From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- third_party/heimdal/lib/Makefile.am | 50 + third_party/heimdal/lib/NTMakefile | 79 + third_party/heimdal/lib/asn1/ChangeLog | 1665 + third_party/heimdal/lib/asn1/MANUAL.md | 1287 + third_party/heimdal/lib/asn1/Makefile.am | 567 + third_party/heimdal/lib/asn1/NTMakefile | 548 + third_party/heimdal/lib/asn1/README-X681.md | 1124 + third_party/heimdal/lib/asn1/README-template.md | 278 + third_party/heimdal/lib/asn1/README.md | 1327 + third_party/heimdal/lib/asn1/asn1-common.h | 90 + third_party/heimdal/lib/asn1/asn1-template.h | 305 + .../heimdal/lib/asn1/asn1_compile-version.rc | 36 + third_party/heimdal/lib/asn1/asn1_compile.1 | 355 + third_party/heimdal/lib/asn1/asn1_err.et | 29 + third_party/heimdal/lib/asn1/asn1_gen.c | 187 + third_party/heimdal/lib/asn1/asn1_print.1 | 135 + third_party/heimdal/lib/asn1/asn1_print.c | 692 + third_party/heimdal/lib/asn1/asn1parse.y | 2036 + third_party/heimdal/lib/asn1/canthandle.asn1 | 15 + third_party/heimdal/lib/asn1/check-ber.c | 280 + third_party/heimdal/lib/asn1/check-common.c | 422 + third_party/heimdal/lib/asn1/check-common.h | 92 + third_party/heimdal/lib/asn1/check-der.c | 1215 + third_party/heimdal/lib/asn1/check-gen.c | 2758 + third_party/heimdal/lib/asn1/check-gen.h | 9 + third_party/heimdal/lib/asn1/check-template.c | 532 + third_party/heimdal/lib/asn1/check-timegm.c | 81 + third_party/heimdal/lib/asn1/cms.asn1 | 149 + third_party/heimdal/lib/asn1/cms.opt | 2 + third_party/heimdal/lib/asn1/crmf.asn1 | 110 + third_party/heimdal/lib/asn1/crmf.opt | 0 third_party/heimdal/lib/asn1/der.c | 142 + third_party/heimdal/lib/asn1/der.h | 107 + third_party/heimdal/lib/asn1/der_cmp.c | 247 + third_party/heimdal/lib/asn1/der_copy.c | 249 + third_party/heimdal/lib/asn1/der_format.c | 170 + third_party/heimdal/lib/asn1/der_free.c | 156 + third_party/heimdal/lib/asn1/der_get.c | 842 + third_party/heimdal/lib/asn1/der_length.c | 307 + third_party/heimdal/lib/asn1/der_locl.h | 63 + third_party/heimdal/lib/asn1/der_print.c | 229 + third_party/heimdal/lib/asn1/der_put.c | 717 + third_party/heimdal/lib/asn1/digest.asn1 | 179 + third_party/heimdal/lib/asn1/extra.c | 285 + .../heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq | Bin 0 -> 55 bytes .../heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt | Bin 0 -> 643 bytes .../heimdal/lib/asn1/fuzz-inputs/x690sample.der | 5 + third_party/heimdal/lib/asn1/fuzzer.c | 742 + third_party/heimdal/lib/asn1/gen.c | 2090 + third_party/heimdal/lib/asn1/gen_copy.c | 290 + third_party/heimdal/lib/asn1/gen_decode.c | 841 + third_party/heimdal/lib/asn1/gen_encode.c | 747 + third_party/heimdal/lib/asn1/gen_free.c | 239 + third_party/heimdal/lib/asn1/gen_glue.c | 162 + third_party/heimdal/lib/asn1/gen_length.c | 309 + third_party/heimdal/lib/asn1/gen_locl.h | 192 + third_party/heimdal/lib/asn1/gen_print.c | 43 + third_party/heimdal/lib/asn1/gen_seq.c | 127 + third_party/heimdal/lib/asn1/gen_template.c | 1675 + third_party/heimdal/lib/asn1/hash.c | 206 + third_party/heimdal/lib/asn1/hash.h | 87 + third_party/heimdal/lib/asn1/heim_asn1.h | 71 + third_party/heimdal/lib/asn1/krb5.asn1 | 1066 + third_party/heimdal/lib/asn1/krb5.opt | 9 + third_party/heimdal/lib/asn1/kx509.asn1 | 204 + third_party/heimdal/lib/asn1/lex.h | 42 + third_party/heimdal/lib/asn1/lex.l | 310 + third_party/heimdal/lib/asn1/libasn1-exports.def | 2655 + third_party/heimdal/lib/asn1/main.c | 495 + third_party/heimdal/lib/asn1/ocsp.asn1 | 113 + third_party/heimdal/lib/asn1/ocsp.opt | 2 + third_party/heimdal/lib/asn1/oid_resolution.c | 341 + third_party/heimdal/lib/asn1/pkcs10.asn1 | 64 + third_party/heimdal/lib/asn1/pkcs10.opt | 1 + third_party/heimdal/lib/asn1/pkcs12.asn1 | 81 + third_party/heimdal/lib/asn1/pkcs8.asn1 | 29 + third_party/heimdal/lib/asn1/pkcs9.asn1 | 29 + third_party/heimdal/lib/asn1/pkinit.asn1 | 201 + third_party/heimdal/lib/asn1/pku2u.asn1 | 30 + third_party/heimdal/lib/asn1/rfc2459.asn1 | 1210 + third_party/heimdal/lib/asn1/rfc2459.opt | 12 + third_party/heimdal/lib/asn1/rfc4108.asn1 | 207 + third_party/heimdal/lib/asn1/roken_rename.h | 46 + third_party/heimdal/lib/asn1/setchgpw2.asn1 | 193 + third_party/heimdal/lib/asn1/symbol.c | 179 + third_party/heimdal/lib/asn1/symbol.h | 268 + third_party/heimdal/lib/asn1/tcg.asn1 | 42 + third_party/heimdal/lib/asn1/template.c | 3104 + third_party/heimdal/lib/asn1/test.asn1 | 309 + third_party/heimdal/lib/asn1/test.gen | 14 + third_party/heimdal/lib/asn1/test.opt | 7 + third_party/heimdal/lib/asn1/timegm.c | 136 + third_party/heimdal/lib/asn1/version-script.map | 6 + third_party/heimdal/lib/asn1/x690sample.asn1 | 181 + third_party/heimdal/lib/base/Makefile.am | 97 + third_party/heimdal/lib/base/NTMakefile | 134 + third_party/heimdal/lib/base/array.c | 478 + third_party/heimdal/lib/base/baselocl.h | 98 + third_party/heimdal/lib/base/bool.c | 59 + third_party/heimdal/lib/base/bsearch.c | 888 + third_party/heimdal/lib/base/common_plugin.h | 106 + third_party/heimdal/lib/base/config_file.c | 1472 + third_party/heimdal/lib/base/config_reg.c | 658 + third_party/heimdal/lib/base/context.c | 394 + third_party/heimdal/lib/base/data.c | 166 + third_party/heimdal/lib/base/db.c | 1724 + third_party/heimdal/lib/base/dict.c | 305 + third_party/heimdal/lib/base/dll.c | 325 + third_party/heimdal/lib/base/error.c | 181 + third_party/heimdal/lib/base/error_string.c | 177 + third_party/heimdal/lib/base/expand_path.c | 725 + third_party/heimdal/lib/base/heim_err.et | 57 + third_party/heimdal/lib/base/heimbase-atomics.h | 386 + third_party/heimdal/lib/base/heimbase-svc.h | 84 + third_party/heimdal/lib/base/heimbase.c | 1104 + third_party/heimdal/lib/base/heimbase.h | 374 + third_party/heimdal/lib/base/heimbasepriv.h | 93 + third_party/heimdal/lib/base/json.c | 1471 + third_party/heimdal/lib/base/log.c | 1079 + third_party/heimdal/lib/base/null.c | 53 + third_party/heimdal/lib/base/number.c | 136 + third_party/heimdal/lib/base/plugin.c | 785 + third_party/heimdal/lib/base/roken_rename.h | 61 + third_party/heimdal/lib/base/string.c | 261 + third_party/heimdal/lib/base/test_base.c | 1380 + third_party/heimdal/lib/base/version-script.map | 211 + third_party/heimdal/lib/base/warn.c | 169 + third_party/heimdal/lib/com_err/ChangeLog | 235 + third_party/heimdal/lib/com_err/Makefile.am | 50 + third_party/heimdal/lib/com_err/NTMakefile | 91 + third_party/heimdal/lib/com_err/com_err.3 | 246 + third_party/heimdal/lib/com_err/com_err.c | 172 + third_party/heimdal/lib/com_err/com_err.h | 76 + third_party/heimdal/lib/com_err/com_right.h | 87 + .../heimdal/lib/com_err/compile_et-version.rc | 36 + third_party/heimdal/lib/com_err/compile_et.c | 243 + third_party/heimdal/lib/com_err/compile_et.h | 78 + third_party/heimdal/lib/com_err/error.c | 114 + third_party/heimdal/lib/com_err/lex.h | 39 + third_party/heimdal/lib/com_err/lex.l | 123 + .../heimdal/lib/com_err/libcom_err-exports.def | 14 + .../heimdal/lib/com_err/libcom_err-version.rc | 36 + third_party/heimdal/lib/com_err/parse.y | 175 + third_party/heimdal/lib/com_err/roken_rename.h | 62 + third_party/heimdal/lib/com_err/version-script.map | 20 + third_party/heimdal/lib/gss_preauth/Makefile.am | 25 + third_party/heimdal/lib/gss_preauth/NTMakefile | 70 + third_party/heimdal/lib/gss_preauth/README.md | 110 + third_party/heimdal/lib/gss_preauth/pa_client.c | 252 + third_party/heimdal/lib/gss_preauth/pa_common.c | 255 + third_party/heimdal/lib/gssapi/ChangeLog | 2970 + third_party/heimdal/lib/gssapi/Makefile.am | 470 + third_party/heimdal/lib/gssapi/NTMakefile | 747 + third_party/heimdal/lib/gssapi/gen-oid.pl | 149 + third_party/heimdal/lib/gssapi/gss-commands.in | 61 + third_party/heimdal/lib/gssapi/gss-token.1 | 108 + third_party/heimdal/lib/gssapi/gss-token.c | 684 + third_party/heimdal/lib/gssapi/gss_acquire_cred.3 | 688 + third_party/heimdal/lib/gssapi/gssapi.3 | 172 + third_party/heimdal/lib/gssapi/gssapi.h | 41 + third_party/heimdal/lib/gssapi/gssapi/gssapi.h | 1281 + .../heimdal/lib/gssapi/gssapi/gssapi_krb5.h | 225 + .../heimdal/lib/gssapi/gssapi/gssapi_netlogon.h | 50 + .../heimdal/lib/gssapi/gssapi/gssapi_ntlm.h | 41 + third_party/heimdal/lib/gssapi/gssapi/gssapi_oid.h | 262 + .../heimdal/lib/gssapi/gssapi/gssapi_spnego.h | 87 + third_party/heimdal/lib/gssapi/gssapi_mech.h | 725 + third_party/heimdal/lib/gssapi/gsstool.c | 264 + third_party/heimdal/lib/gssapi/krb5/8003.c | 271 + .../heimdal/lib/gssapi/krb5/accept_sec_context.c | 978 + third_party/heimdal/lib/gssapi/krb5/acquire_cred.c | 686 + third_party/heimdal/lib/gssapi/krb5/add_cred.c | 254 + .../heimdal/lib/gssapi/krb5/address_to_krb5addr.c | 77 + third_party/heimdal/lib/gssapi/krb5/aeap.c | 178 + third_party/heimdal/lib/gssapi/krb5/arcfour.c | 1391 + .../heimdal/lib/gssapi/krb5/authorize_localname.c | 66 + .../heimdal/lib/gssapi/krb5/canonicalize_name.c | 58 + third_party/heimdal/lib/gssapi/krb5/ccache_name.c | 78 + third_party/heimdal/lib/gssapi/krb5/cfx.c | 1797 + third_party/heimdal/lib/gssapi/krb5/cfx.h | 65 + third_party/heimdal/lib/gssapi/krb5/compare_name.c | 53 + third_party/heimdal/lib/gssapi/krb5/compat.c | 125 + third_party/heimdal/lib/gssapi/krb5/context_time.c | 94 + third_party/heimdal/lib/gssapi/krb5/copy_ccache.c | 200 + third_party/heimdal/lib/gssapi/krb5/creds.c | 281 + third_party/heimdal/lib/gssapi/krb5/decapsulate.c | 216 + .../heimdal/lib/gssapi/krb5/delete_sec_context.c | 86 + third_party/heimdal/lib/gssapi/krb5/display_name.c | 72 + .../heimdal/lib/gssapi/krb5/display_status.c | 198 + .../heimdal/lib/gssapi/krb5/duplicate_cred.c | 167 + .../heimdal/lib/gssapi/krb5/duplicate_name.c | 58 + third_party/heimdal/lib/gssapi/krb5/encapsulate.c | 153 + third_party/heimdal/lib/gssapi/krb5/export_name.c | 92 + .../heimdal/lib/gssapi/krb5/export_sec_context.c | 257 + third_party/heimdal/lib/gssapi/krb5/external.c | 413 + third_party/heimdal/lib/gssapi/krb5/get_mic.c | 330 + third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et | 33 + third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h | 153 + third_party/heimdal/lib/gssapi/krb5/import_name.c | 294 + .../heimdal/lib/gssapi/krb5/import_sec_context.c | 221 + .../heimdal/lib/gssapi/krb5/indicate_mechs.c | 55 + third_party/heimdal/lib/gssapi/krb5/init.c | 82 + .../heimdal/lib/gssapi/krb5/init_sec_context.c | 1024 + .../heimdal/lib/gssapi/krb5/inquire_context.c | 110 + third_party/heimdal/lib/gssapi/krb5/inquire_cred.c | 225 + .../heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c | 78 + .../heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c | 81 + .../lib/gssapi/krb5/inquire_mechs_for_name.c | 55 + .../lib/gssapi/krb5/inquire_names_for_mech.c | 77 + .../lib/gssapi/krb5/inquire_sec_context_by_oid.c | 604 + third_party/heimdal/lib/gssapi/krb5/name_attrs.c | 1171 + third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c | 70 + third_party/heimdal/lib/gssapi/krb5/prf.c | 148 + .../lib/gssapi/krb5/process_context_token.c | 66 + .../heimdal/lib/gssapi/krb5/release_buffer.c | 46 + third_party/heimdal/lib/gssapi/krb5/release_cred.c | 77 + third_party/heimdal/lib/gssapi/krb5/release_name.c | 53 + third_party/heimdal/lib/gssapi/krb5/sequence.c | 292 + .../heimdal/lib/gssapi/krb5/set_cred_option.c | 249 + .../lib/gssapi/krb5/set_sec_context_option.c | 353 + third_party/heimdal/lib/gssapi/krb5/store_cred.c | 372 + .../heimdal/lib/gssapi/krb5/test_acquire_cred.c | 187 + third_party/heimdal/lib/gssapi/krb5/test_cfx.c | 173 + third_party/heimdal/lib/gssapi/krb5/test_cred.c | 277 + third_party/heimdal/lib/gssapi/krb5/test_kcred.c | 155 + third_party/heimdal/lib/gssapi/krb5/test_oid.c | 51 + .../heimdal/lib/gssapi/krb5/test_sequence.c | 367 + third_party/heimdal/lib/gssapi/krb5/ticket_flags.c | 58 + third_party/heimdal/lib/gssapi/krb5/unwrap.c | 468 + third_party/heimdal/lib/gssapi/krb5/verify_mic.c | 360 + third_party/heimdal/lib/gssapi/krb5/wrap.c | 592 + .../heimdal/lib/gssapi/libgssapi-exports.def | 203 + .../heimdal/lib/gssapi/libgssapi-version.rc | 36 + third_party/heimdal/lib/gssapi/mech/compat.h | 94 + third_party/heimdal/lib/gssapi/mech/context.c | 361 + third_party/heimdal/lib/gssapi/mech/context.h | 51 + third_party/heimdal/lib/gssapi/mech/cred.c | 81 + third_party/heimdal/lib/gssapi/mech/cred.h | 65 + third_party/heimdal/lib/gssapi/mech/doxygen.c | 133 + .../lib/gssapi/mech/gss_accept_sec_context.c | 517 + .../heimdal/lib/gssapi/mech/gss_acquire_cred.c | 50 + .../lib/gssapi/mech/gss_acquire_cred_from.c | 302 + .../mech/gss_acquire_cred_impersonate_name.c | 51 + .../gssapi/mech/gss_acquire_cred_with_password.c | 85 + third_party/heimdal/lib/gssapi/mech/gss_add_cred.c | 58 + .../heimdal/lib/gssapi/mech/gss_add_cred_from.c | 292 + .../lib/gssapi/mech/gss_add_cred_with_password.c | 88 + .../lib/gssapi/mech/gss_add_oid_set_member.c | 87 + third_party/heimdal/lib/gssapi/mech/gss_aeap.c | 334 + .../lib/gssapi/mech/gss_authorize_localname.c | 187 + .../heimdal/lib/gssapi/mech/gss_buffer_set.c | 124 + .../lib/gssapi/mech/gss_canonicalize_name.c | 104 + .../heimdal/lib/gssapi/mech/gss_compare_name.c | 102 + .../heimdal/lib/gssapi/mech/gss_context_time.c | 40 + .../lib/gssapi/mech/gss_create_empty_oid_set.c | 51 + third_party/heimdal/lib/gssapi/mech/gss_cred.c | 326 + .../lib/gssapi/mech/gss_decapsulate_token.c | 72 + .../lib/gssapi/mech/gss_delete_name_attribute.c | 65 + .../lib/gssapi/mech/gss_delete_sec_context.c | 62 + .../heimdal/lib/gssapi/mech/gss_destroy_cred.c | 74 + .../heimdal/lib/gssapi/mech/gss_display_name.c | 82 + .../heimdal/lib/gssapi/mech/gss_display_name_ext.c | 68 + .../heimdal/lib/gssapi/mech/gss_display_status.c | 227 + .../heimdal/lib/gssapi/mech/gss_duplicate_cred.c | 153 + .../heimdal/lib/gssapi/mech/gss_duplicate_name.c | 93 + .../heimdal/lib/gssapi/mech/gss_duplicate_oid.c | 51 + .../lib/gssapi/mech/gss_duplicate_oid_set.c | 57 + .../lib/gssapi/mech/gss_encapsulate_token.c | 66 + .../heimdal/lib/gssapi/mech/gss_export_name.c | 113 + .../lib/gssapi/mech/gss_export_name_composite.c | 66 + .../lib/gssapi/mech/gss_export_sec_context.c | 147 + third_party/heimdal/lib/gssapi/mech/gss_get_mic.c | 51 + .../lib/gssapi/mech/gss_get_name_attribute.c | 83 + .../heimdal/lib/gssapi/mech/gss_get_neg_mechs.c | 54 + .../heimdal/lib/gssapi/mech/gss_import_name.c | 323 + .../lib/gssapi/mech/gss_import_sec_context.c | 147 + .../heimdal/lib/gssapi/mech/gss_indicate_mechs.c | 74 + .../heimdal/lib/gssapi/mech/gss_init_sec_context.c | 281 + .../heimdal/lib/gssapi/mech/gss_inquire_context.c | 120 + .../heimdal/lib/gssapi/mech/gss_inquire_cred.c | 218 + .../lib/gssapi/mech/gss_inquire_cred_by_mech.c | 92 + .../lib/gssapi/mech/gss_inquire_cred_by_oid.c | 90 + .../lib/gssapi/mech/gss_inquire_mechs_for_name.c | 76 + .../heimdal/lib/gssapi/mech/gss_inquire_name.c | 79 + .../lib/gssapi/mech/gss_inquire_names_for_mech.c | 73 + .../gssapi/mech/gss_inquire_sec_context_by_oid.c | 70 + third_party/heimdal/lib/gssapi/mech/gss_krb5.c | 926 + .../heimdal/lib/gssapi/mech/gss_mech_switch.c | 586 + third_party/heimdal/lib/gssapi/mech/gss_mo.c | 638 + third_party/heimdal/lib/gssapi/mech/gss_names.c | 262 + third_party/heimdal/lib/gssapi/mech/gss_oid.c | 370 + .../heimdal/lib/gssapi/mech/gss_oid_equal.c | 58 + .../heimdal/lib/gssapi/mech/gss_oid_to_str.c | 67 + .../heimdal/lib/gssapi/mech/gss_pname_to_uid.c | 197 + .../lib/gssapi/mech/gss_process_context_token.c | 41 + .../heimdal/lib/gssapi/mech/gss_pseudo_random.c | 70 + .../heimdal/lib/gssapi/mech/gss_release_buffer.c | 42 + .../heimdal/lib/gssapi/mech/gss_release_cred.c | 66 + .../heimdal/lib/gssapi/mech/gss_release_name.c | 63 + .../heimdal/lib/gssapi/mech/gss_release_oid.c | 46 + .../heimdal/lib/gssapi/mech/gss_release_oid_set.c | 44 + third_party/heimdal/lib/gssapi/mech/gss_rfc4121.c | 111 + third_party/heimdal/lib/gssapi/mech/gss_seal.c | 45 + .../heimdal/lib/gssapi/mech/gss_set_cred_option.c | 118 + .../lib/gssapi/mech/gss_set_name_attribute.c | 69 + .../heimdal/lib/gssapi/mech/gss_set_neg_mechs.c | 60 + .../lib/gssapi/mech/gss_set_sec_context_option.c | 102 + third_party/heimdal/lib/gssapi/mech/gss_sign.c | 41 + .../heimdal/lib/gssapi/mech/gss_store_cred.c | 57 + .../heimdal/lib/gssapi/mech/gss_store_cred_into.c | 181 + .../lib/gssapi/mech/gss_test_oid_set_member.c | 46 + third_party/heimdal/lib/gssapi/mech/gss_unseal.c | 43 + third_party/heimdal/lib/gssapi/mech/gss_unwrap.c | 56 + third_party/heimdal/lib/gssapi/mech/gss_utils.c | 381 + third_party/heimdal/lib/gssapi/mech/gss_verify.c | 42 + .../heimdal/lib/gssapi/mech/gss_verify_mic.c | 52 + third_party/heimdal/lib/gssapi/mech/gss_wrap.c | 71 + .../heimdal/lib/gssapi/mech/gss_wrap_size_limit.c | 52 + third_party/heimdal/lib/gssapi/mech/gssapi.asn1 | 12 + .../lib/gssapi/mech/gssspi_exchange_meta_data.c | 115 + .../lib/gssapi/mech/gssspi_query_mechanism_info.c | 55 + .../lib/gssapi/mech/gssspi_query_meta_data.c | 117 + third_party/heimdal/lib/gssapi/mech/mech.5 | 94 + third_party/heimdal/lib/gssapi/mech/mech_locl.h | 78 + third_party/heimdal/lib/gssapi/mech/mech_switch.h | 43 + third_party/heimdal/lib/gssapi/mech/name.h | 77 + third_party/heimdal/lib/gssapi/mech/utils.h | 87 + .../lib/gssapi/netlogon/accept_sec_context.c | 89 + .../heimdal/lib/gssapi/netlogon/acquire_cred.c | 186 + third_party/heimdal/lib/gssapi/netlogon/add_cred.c | 89 + .../lib/gssapi/netlogon/canonicalize_name.c | 46 + .../heimdal/lib/gssapi/netlogon/compare_name.c | 61 + .../heimdal/lib/gssapi/netlogon/context_time.c | 47 + third_party/heimdal/lib/gssapi/netlogon/crypto.c | 733 + .../lib/gssapi/netlogon/delete_sec_context.c | 62 + .../heimdal/lib/gssapi/netlogon/display_name.c | 67 + .../heimdal/lib/gssapi/netlogon/display_status.c | 55 + .../heimdal/lib/gssapi/netlogon/duplicate_cred.c | 54 + .../heimdal/lib/gssapi/netlogon/duplicate_name.c | 77 + .../heimdal/lib/gssapi/netlogon/export_name.c | 45 + .../lib/gssapi/netlogon/export_sec_context.c | 50 + third_party/heimdal/lib/gssapi/netlogon/external.c | 111 + .../heimdal/lib/gssapi/netlogon/import_name.c | 94 + .../lib/gssapi/netlogon/import_sec_context.c | 50 + .../heimdal/lib/gssapi/netlogon/indicate_mechs.c | 48 + .../heimdal/lib/gssapi/netlogon/init_sec_context.c | 289 + .../heimdal/lib/gssapi/netlogon/inquire_context.c | 76 + .../heimdal/lib/gssapi/netlogon/inquire_cred.c | 68 + .../lib/gssapi/netlogon/inquire_cred_by_mech.c | 66 + .../lib/gssapi/netlogon/inquire_mechs_for_name.c | 48 + .../lib/gssapi/netlogon/inquire_names_for_mech.c | 58 + .../heimdal/lib/gssapi/netlogon/iter_cred.c | 44 + third_party/heimdal/lib/gssapi/netlogon/netlogon.h | 150 + .../lib/gssapi/netlogon/process_context_token.c | 46 + third_party/heimdal/lib/gssapi/netlogon/regen.sh | 3 + .../heimdal/lib/gssapi/netlogon/release_cred.c | 54 + .../heimdal/lib/gssapi/netlogon/release_name.c | 54 + .../heimdal/lib/gssapi/ntlm/accept_sec_context.c | 256 + third_party/heimdal/lib/gssapi/ntlm/acquire_cred.c | 88 + third_party/heimdal/lib/gssapi/ntlm/add_cred.c | 60 + .../heimdal/lib/gssapi/ntlm/canonicalize_name.c | 45 + third_party/heimdal/lib/gssapi/ntlm/compare_name.c | 45 + third_party/heimdal/lib/gssapi/ntlm/context_time.c | 45 + third_party/heimdal/lib/gssapi/ntlm/creds.c | 159 + third_party/heimdal/lib/gssapi/ntlm/crypto.c | 615 + .../heimdal/lib/gssapi/ntlm/delete_sec_context.c | 69 + third_party/heimdal/lib/gssapi/ntlm/display_name.c | 71 + .../heimdal/lib/gssapi/ntlm/display_status.c | 54 + .../heimdal/lib/gssapi/ntlm/duplicate_cred.c | 57 + .../heimdal/lib/gssapi/ntlm/duplicate_name.c | 48 + third_party/heimdal/lib/gssapi/ntlm/export_name.c | 50 + .../heimdal/lib/gssapi/ntlm/export_sec_context.c | 50 + third_party/heimdal/lib/gssapi/ntlm/external.c | 140 + third_party/heimdal/lib/gssapi/ntlm/import_name.c | 112 + .../heimdal/lib/gssapi/ntlm/import_sec_context.c | 48 + .../heimdal/lib/gssapi/ntlm/indicate_mechs.c | 46 + .../heimdal/lib/gssapi/ntlm/init_sec_context.c | 536 + .../heimdal/lib/gssapi/ntlm/inquire_context.c | 68 + .../heimdal/lib/gssapi/ntlm/inquire_cred_by_mech.c | 58 + .../lib/gssapi/ntlm/inquire_mechs_for_name.c | 48 + .../lib/gssapi/ntlm/inquire_names_for_mech.c | 51 + .../lib/gssapi/ntlm/inquire_sec_context_by_oid.c | 90 + third_party/heimdal/lib/gssapi/ntlm/iter_cred.c | 99 + third_party/heimdal/lib/gssapi/ntlm/kdc.c | 435 + third_party/heimdal/lib/gssapi/ntlm/ntlm.h | 147 + .../lib/gssapi/ntlm/process_context_token.c | 44 + third_party/heimdal/lib/gssapi/ntlm/release_cred.c | 66 + third_party/heimdal/lib/gssapi/ntlm/release_name.c | 52 + .../lib/gssapi/ntlm/set_sec_context_option.c | 60 + third_party/heimdal/lib/gssapi/oid.txt | 173 + .../heimdal/lib/gssapi/sanon/accept_sec_context.c | 169 + .../heimdal/lib/gssapi/sanon/acquire_cred.c | 59 + third_party/heimdal/lib/gssapi/sanon/add_cred.c | 65 + .../heimdal/lib/gssapi/sanon/canonicalize_name.c | 48 + .../heimdal/lib/gssapi/sanon/compare_name.c | 54 + .../heimdal/lib/gssapi/sanon/context_time.c | 50 + third_party/heimdal/lib/gssapi/sanon/crypto.c | 333 + .../heimdal/lib/gssapi/sanon/delete_sec_context.c | 62 + .../heimdal/lib/gssapi/sanon/display_name.c | 50 + .../heimdal/lib/gssapi/sanon/display_status.c | 60 + .../heimdal/lib/gssapi/sanon/duplicate_cred.c | 43 + .../heimdal/lib/gssapi/sanon/duplicate_name.c | 43 + third_party/heimdal/lib/gssapi/sanon/export_cred.c | 78 + third_party/heimdal/lib/gssapi/sanon/export_name.c | 52 + .../heimdal/lib/gssapi/sanon/export_sec_context.c | 52 + third_party/heimdal/lib/gssapi/sanon/external.c | 270 + third_party/heimdal/lib/gssapi/sanon/import_cred.c | 42 + third_party/heimdal/lib/gssapi/sanon/import_name.c | 163 + .../heimdal/lib/gssapi/sanon/import_sec_context.c | 55 + .../heimdal/lib/gssapi/sanon/init_sec_context.c | 205 + .../heimdal/lib/gssapi/sanon/inquire_context.c | 75 + .../heimdal/lib/gssapi/sanon/inquire_cred.c | 58 + .../lib/gssapi/sanon/inquire_cred_by_mech.c | 74 + .../lib/gssapi/sanon/inquire_mechs_for_name.c | 54 + .../lib/gssapi/sanon/inquire_names_for_mech.c | 77 + .../lib/gssapi/sanon/inquire_sec_context_by_oid.c | 61 + third_party/heimdal/lib/gssapi/sanon/negoex.c | 131 + .../lib/gssapi/sanon/process_context_token.c | 42 + .../heimdal/lib/gssapi/sanon/release_cred.c | 42 + .../heimdal/lib/gssapi/sanon/release_name.c | 42 + third_party/heimdal/lib/gssapi/sanon/sanon_locl.h | 84 + .../heimdal/lib/gssapi/spnego/accept_sec_context.c | 1024 + third_party/heimdal/lib/gssapi/spnego/compat.c | 684 + .../heimdal/lib/gssapi/spnego/context_storage.c | 498 + .../heimdal/lib/gssapi/spnego/context_stubs.c | 578 + third_party/heimdal/lib/gssapi/spnego/external.c | 165 + .../heimdal/lib/gssapi/spnego/init_sec_context.c | 841 + third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c | 1041 + .../heimdal/lib/gssapi/spnego/negoex_err.et | 25 + .../heimdal/lib/gssapi/spnego/negoex_locl.h | 127 + .../heimdal/lib/gssapi/spnego/negoex_util.c | 1047 + third_party/heimdal/lib/gssapi/spnego/spnego.asn1 | 66 + third_party/heimdal/lib/gssapi/spnego/spnego.opt | 1 + .../heimdal/lib/gssapi/spnego/spnego_locl.h | 159 + third_party/heimdal/lib/gssapi/test_acquire_cred.c | 344 + .../heimdal/lib/gssapi/test_add_store_cred.c | 219 + third_party/heimdal/lib/gssapi/test_common.c | 71 + third_party/heimdal/lib/gssapi/test_common.h | 36 + third_party/heimdal/lib/gssapi/test_context.c | 1622 + third_party/heimdal/lib/gssapi/test_cred.c | 236 + third_party/heimdal/lib/gssapi/test_kcred.c | 198 + third_party/heimdal/lib/gssapi/test_names.c | 675 + third_party/heimdal/lib/gssapi/test_negoex_mech.c | 592 + third_party/heimdal/lib/gssapi/test_ntlm.c | 337 + third_party/heimdal/lib/gssapi/test_oid.c | 71 + third_party/heimdal/lib/gssapi/version-script.map | 210 + third_party/heimdal/lib/hcrypto/ChangeLog | 1227 + third_party/heimdal/lib/hcrypto/DESperate.txt | 108 + third_party/heimdal/lib/hcrypto/Makefile.am | 424 + third_party/heimdal/lib/hcrypto/NTMakefile | 272 + third_party/heimdal/lib/hcrypto/aes.c | 142 + third_party/heimdal/lib/hcrypto/aes.h | 83 + third_party/heimdal/lib/hcrypto/bn.c | 529 + third_party/heimdal/lib/hcrypto/bn.h | 139 + third_party/heimdal/lib/hcrypto/camellia-ntt.c | 1458 + third_party/heimdal/lib/hcrypto/camellia-ntt.h | 63 + third_party/heimdal/lib/hcrypto/camellia.c | 113 + third_party/heimdal/lib/hcrypto/camellia.h | 72 + third_party/heimdal/lib/hcrypto/common.c | 65 + third_party/heimdal/lib/hcrypto/common.h | 45 + third_party/heimdal/lib/hcrypto/des-tables.h | 196 + third_party/heimdal/lib/hcrypto/des.c | 1186 + third_party/heimdal/lib/hcrypto/des.h | 146 + third_party/heimdal/lib/hcrypto/destest.c | 621 + third_party/heimdal/lib/hcrypto/dh-ltm.c | 264 + third_party/heimdal/lib/hcrypto/dh-tfm.c | 248 + third_party/heimdal/lib/hcrypto/dh.c | 551 + third_party/heimdal/lib/hcrypto/dh.h | 148 + third_party/heimdal/lib/hcrypto/doxygen.c | 102 + third_party/heimdal/lib/hcrypto/dsa.c | 127 + third_party/heimdal/lib/hcrypto/dsa.h | 142 + third_party/heimdal/lib/hcrypto/ec.c | 178 + third_party/heimdal/lib/hcrypto/ec.h | 97 + third_party/heimdal/lib/hcrypto/ecdh.h | 47 + third_party/heimdal/lib/hcrypto/ecdsa.h | 52 + third_party/heimdal/lib/hcrypto/engine.c | 396 + third_party/heimdal/lib/hcrypto/engine.h | 120 + third_party/heimdal/lib/hcrypto/evp-cc.c | 917 + third_party/heimdal/lib/hcrypto/evp-cc.h | 100 + third_party/heimdal/lib/hcrypto/evp-crypt.c | 217 + third_party/heimdal/lib/hcrypto/evp-hcrypto.c | 831 + third_party/heimdal/lib/hcrypto/evp-hcrypto.h | 101 + third_party/heimdal/lib/hcrypto/evp-openssl.c | 659 + third_party/heimdal/lib/hcrypto/evp-openssl.h | 100 + third_party/heimdal/lib/hcrypto/evp-pkcs11.c | 831 + third_party/heimdal/lib/hcrypto/evp-pkcs11.h | 153 + third_party/heimdal/lib/hcrypto/evp-w32.c | 139 + third_party/heimdal/lib/hcrypto/evp-w32.h | 98 + third_party/heimdal/lib/hcrypto/evp-wincng.c | 725 + third_party/heimdal/lib/hcrypto/evp-wincng.h | 95 + third_party/heimdal/lib/hcrypto/evp.c | 1562 + third_party/heimdal/lib/hcrypto/evp.h | 359 + .../heimdal/lib/hcrypto/example_evp_cipher.c | 165 + third_party/heimdal/lib/hcrypto/gen-des.pl | 217 + third_party/heimdal/lib/hcrypto/hash.h | 74 + third_party/heimdal/lib/hcrypto/hmac.c | 179 + third_party/heimdal/lib/hcrypto/hmac.h | 86 + .../heimdal/lib/hcrypto/libhcrypto-exports.def | 345 + third_party/heimdal/lib/hcrypto/libtommath/LICENSE | 26 + .../heimdal/lib/hcrypto/libtommath/NTMakefile | 203 + .../heimdal/lib/hcrypto/libtommath/README.md | 44 + .../heimdal/lib/hcrypto/libtommath/appveyor.yml | 20 + .../heimdal/lib/hcrypto/libtommath/astylerc | 30 + .../heimdal/lib/hcrypto/libtommath/bn_cutoffs.c | 14 + .../heimdal/lib/hcrypto/libtommath/bn_deprecated.c | 321 + .../heimdal/lib/hcrypto/libtommath/bn_mp_2expt.c | 31 + .../heimdal/lib/hcrypto/libtommath/bn_mp_abs.c | 26 + .../heimdal/lib/hcrypto/libtommath/bn_mp_add.c | 38 + .../heimdal/lib/hcrypto/libtommath/bn_mp_add_d.c | 89 + .../heimdal/lib/hcrypto/libtommath/bn_mp_addmod.c | 25 + .../heimdal/lib/hcrypto/libtommath/bn_mp_and.c | 56 + .../heimdal/lib/hcrypto/libtommath/bn_mp_clamp.c | 27 + .../heimdal/lib/hcrypto/libtommath/bn_mp_clear.c | 20 + .../lib/hcrypto/libtommath/bn_mp_clear_multi.c | 19 + .../heimdal/lib/hcrypto/libtommath/bn_mp_cmp.c | 26 + .../heimdal/lib/hcrypto/libtommath/bn_mp_cmp_d.c | 28 + .../heimdal/lib/hcrypto/libtommath/bn_mp_cmp_mag.c | 39 + .../heimdal/lib/hcrypto/libtommath/bn_mp_cnt_lsb.c | 37 + .../lib/hcrypto/libtommath/bn_mp_complement.c | 12 + .../heimdal/lib/hcrypto/libtommath/bn_mp_copy.c | 47 + .../lib/hcrypto/libtommath/bn_mp_count_bits.c | 28 + .../heimdal/lib/hcrypto/libtommath/bn_mp_decr.c | 34 + .../heimdal/lib/hcrypto/libtommath/bn_mp_div.c | 250 + .../heimdal/lib/hcrypto/libtommath/bn_mp_div_2.c | 49 + .../heimdal/lib/hcrypto/libtommath/bn_mp_div_2d.c | 71 + .../heimdal/lib/hcrypto/libtommath/bn_mp_div_3.c | 63 + .../heimdal/lib/hcrypto/libtommath/bn_mp_div_d.c | 84 + .../lib/hcrypto/libtommath/bn_mp_dr_is_modulus.c | 27 + .../lib/hcrypto/libtommath/bn_mp_dr_reduce.c | 78 + .../lib/hcrypto/libtommath/bn_mp_dr_setup.c | 15 + .../lib/hcrypto/libtommath/bn_mp_error_to_string.c | 27 + .../heimdal/lib/hcrypto/libtommath/bn_mp_exch.c | 17 + .../lib/hcrypto/libtommath/bn_mp_expt_u32.c | 46 + .../heimdal/lib/hcrypto/libtommath/bn_mp_exptmod.c | 76 + .../lib/hcrypto/libtommath/bn_mp_exteuclid.c | 73 + .../heimdal/lib/hcrypto/libtommath/bn_mp_fread.c | 60 + .../lib/hcrypto/libtommath/bn_mp_from_sbin.c | 25 + .../lib/hcrypto/libtommath/bn_mp_from_ubin.c | 39 + .../heimdal/lib/hcrypto/libtommath/bn_mp_fwrite.c | 45 + .../heimdal/lib/hcrypto/libtommath/bn_mp_gcd.c | 92 + .../lib/hcrypto/libtommath/bn_mp_get_double.c | 18 + .../heimdal/lib/hcrypto/libtommath/bn_mp_get_i32.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_get_i64.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_get_l.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_get_ll.c | 7 + .../lib/hcrypto/libtommath/bn_mp_get_mag_u32.c | 7 + .../lib/hcrypto/libtommath/bn_mp_get_mag_u64.c | 7 + .../lib/hcrypto/libtommath/bn_mp_get_mag_ul.c | 7 + .../lib/hcrypto/libtommath/bn_mp_get_mag_ull.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_grow.c | 38 + .../heimdal/lib/hcrypto/libtommath/bn_mp_incr.c | 30 + .../heimdal/lib/hcrypto/libtommath/bn_mp_init.c | 23 + .../lib/hcrypto/libtommath/bn_mp_init_copy.c | 21 + .../lib/hcrypto/libtommath/bn_mp_init_i32.c | 7 + .../lib/hcrypto/libtommath/bn_mp_init_i64.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_init_l.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_init_ll.c | 7 + .../lib/hcrypto/libtommath/bn_mp_init_multi.c | 41 + .../lib/hcrypto/libtommath/bn_mp_init_set.c | 16 + .../lib/hcrypto/libtommath/bn_mp_init_size.c | 24 + .../lib/hcrypto/libtommath/bn_mp_init_u32.c | 7 + .../lib/hcrypto/libtommath/bn_mp_init_u64.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_init_ul.c | 7 + .../lib/hcrypto/libtommath/bn_mp_init_ull.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_invmod.c | 23 + .../lib/hcrypto/libtommath/bn_mp_is_square.c | 93 + .../heimdal/lib/hcrypto/libtommath/bn_mp_iseven.c | 10 + .../heimdal/lib/hcrypto/libtommath/bn_mp_isodd.c | 10 + .../lib/hcrypto/libtommath/bn_mp_kronecker.c | 129 + .../heimdal/lib/hcrypto/libtommath/bn_mp_lcm.c | 44 + .../heimdal/lib/hcrypto/libtommath/bn_mp_log_u32.c | 191 + .../heimdal/lib/hcrypto/libtommath/bn_mp_lshd.c | 51 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mod.c | 31 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mod_2d.c | 38 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mod_d.c | 10 + .../bn_mp_montgomery_calc_normalization.c | 44 + .../hcrypto/libtommath/bn_mp_montgomery_reduce.c | 102 + .../hcrypto/libtommath/bn_mp_montgomery_setup.c | 42 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mul.c | 52 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mul_2.c | 64 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mul_2d.c | 69 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mul_d.c | 61 + .../heimdal/lib/hcrypto/libtommath/bn_mp_mulmod.c | 25 + .../heimdal/lib/hcrypto/libtommath/bn_mp_neg.c | 24 + .../heimdal/lib/hcrypto/libtommath/bn_mp_or.c | 56 + .../heimdal/lib/hcrypto/libtommath/bn_mp_pack.c | 69 + .../lib/hcrypto/libtommath/bn_mp_pack_count.c | 12 + .../lib/hcrypto/libtommath/bn_mp_prime_fermat.c | 47 + .../libtommath/bn_mp_prime_frobenius_underwood.c | 132 + .../lib/hcrypto/libtommath/bn_mp_prime_is_prime.c | 314 + .../hcrypto/libtommath/bn_mp_prime_miller_rabin.c | 91 + .../hcrypto/libtommath/bn_mp_prime_next_prime.c | 132 + .../libtommath/bn_mp_prime_rabin_miller_trials.c | 47 + .../lib/hcrypto/libtommath/bn_mp_prime_rand.c | 141 + .../bn_mp_prime_strong_lucas_selfridge.c | 289 + .../lib/hcrypto/libtommath/bn_mp_radix_size.c | 65 + .../lib/hcrypto/libtommath/bn_mp_radix_smap.c | 22 + .../heimdal/lib/hcrypto/libtommath/bn_mp_rand.c | 46 + .../lib/hcrypto/libtommath/bn_mp_read_radix.c | 79 + .../heimdal/lib/hcrypto/libtommath/bn_mp_reduce.c | 83 + .../lib/hcrypto/libtommath/bn_mp_reduce_2k.c | 48 + .../lib/hcrypto/libtommath/bn_mp_reduce_2k_l.c | 49 + .../lib/hcrypto/libtommath/bn_mp_reduce_2k_setup.c | 32 + .../hcrypto/libtommath/bn_mp_reduce_2k_setup_l.c | 28 + .../lib/hcrypto/libtommath/bn_mp_reduce_is_2k.c | 38 + .../lib/hcrypto/libtommath/bn_mp_reduce_is_2k_l.c | 28 + .../lib/hcrypto/libtommath/bn_mp_reduce_setup.c | 17 + .../lib/hcrypto/libtommath/bn_mp_root_u32.c | 142 + .../heimdal/lib/hcrypto/libtommath/bn_mp_rshd.c | 51 + .../lib/hcrypto/libtommath/bn_mp_sbin_size.c | 11 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set.c | 14 + .../lib/hcrypto/libtommath/bn_mp_set_double.c | 47 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_i32.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_i64.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_l.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_ll.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_u32.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_u64.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_ul.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_set_ull.c | 7 + .../heimdal/lib/hcrypto/libtommath/bn_mp_shrink.c | 22 + .../lib/hcrypto/libtommath/bn_mp_signed_rsh.c | 22 + .../heimdal/lib/hcrypto/libtommath/bn_mp_sqr.c | 28 + .../heimdal/lib/hcrypto/libtommath/bn_mp_sqrmod.c | 25 + .../heimdal/lib/hcrypto/libtommath/bn_mp_sqrt.c | 67 + .../lib/hcrypto/libtommath/bn_mp_sqrtmod_prime.c | 118 + .../heimdal/lib/hcrypto/libtommath/bn_mp_sub.c | 40 + .../heimdal/lib/hcrypto/libtommath/bn_mp_sub_d.c | 74 + .../heimdal/lib/hcrypto/libtommath/bn_mp_submod.c | 25 + .../lib/hcrypto/libtommath/bn_mp_to_radix.c | 84 + .../heimdal/lib/hcrypto/libtommath/bn_mp_to_sbin.c | 22 + .../heimdal/lib/hcrypto/libtommath/bn_mp_to_ubin.c | 41 + .../lib/hcrypto/libtommath/bn_mp_ubin_size.c | 12 + .../heimdal/lib/hcrypto/libtommath/bn_mp_unpack.c | 49 + .../heimdal/lib/hcrypto/libtommath/bn_mp_xor.c | 56 + .../heimdal/lib/hcrypto/libtommath/bn_mp_zero.c | 13 + .../heimdal/lib/hcrypto/libtommath/bn_prime_tab.c | 61 + .../heimdal/lib/hcrypto/libtommath/bn_s_mp_add.c | 91 + .../lib/hcrypto/libtommath/bn_s_mp_balance_mul.c | 81 + .../lib/hcrypto/libtommath/bn_s_mp_exptmod.c | 198 + .../lib/hcrypto/libtommath/bn_s_mp_exptmod_fast.c | 254 + .../lib/hcrypto/libtommath/bn_s_mp_get_bit.c | 21 + .../lib/hcrypto/libtommath/bn_s_mp_invmod_fast.c | 118 + .../lib/hcrypto/libtommath/bn_s_mp_invmod_slow.c | 119 + .../lib/hcrypto/libtommath/bn_s_mp_karatsuba_mul.c | 174 + .../lib/hcrypto/libtommath/bn_s_mp_karatsuba_sqr.c | 110 + .../libtommath/bn_s_mp_montgomery_reduce_fast.c | 159 + .../lib/hcrypto/libtommath/bn_s_mp_mul_digs.c | 74 + .../lib/hcrypto/libtommath/bn_s_mp_mul_digs_fast.c | 90 + .../lib/hcrypto/libtommath/bn_s_mp_mul_high_digs.c | 64 + .../libtommath/bn_s_mp_mul_high_digs_fast.c | 81 + .../libtommath/bn_s_mp_prime_is_divisible.c | 35 + .../lib/hcrypto/libtommath/bn_s_mp_rand_jenkins.c | 52 + .../lib/hcrypto/libtommath/bn_s_mp_rand_platform.c | 168 + .../lib/hcrypto/libtommath/bn_s_mp_reverse.c | 22 + .../heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr.c | 69 + .../lib/hcrypto/libtommath/bn_s_mp_sqr_fast.c | 97 + .../heimdal/lib/hcrypto/libtommath/bn_s_mp_sub.c | 71 + .../lib/hcrypto/libtommath/bn_s_mp_toom_mul.c | 215 + .../lib/hcrypto/libtommath/bn_s_mp_toom_sqr.c | 147 + .../heimdal/lib/hcrypto/libtommath/changes.txt | 497 + .../lib/hcrypto/libtommath/demo/mtest_opponent.c | 402 + .../heimdal/lib/hcrypto/libtommath/demo/shared.c | 42 + .../heimdal/lib/hcrypto/libtommath/demo/shared.h | 21 + .../heimdal/lib/hcrypto/libtommath/demo/test.c | 2522 + .../heimdal/lib/hcrypto/libtommath/demo/timing.c | 406 + .../heimdal/lib/hcrypto/libtommath/doc/bn.pdf | Bin 0 -> 430812 bytes .../heimdal/lib/hcrypto/libtommath/doc/bn.tex | 2507 + .../heimdal/lib/hcrypto/libtommath/etc/2kprime.1 | 2 + .../heimdal/lib/hcrypto/libtommath/etc/2kprime.c | 81 + .../heimdal/lib/hcrypto/libtommath/etc/drprime.c | 67 + .../heimdal/lib/hcrypto/libtommath/etc/drprimes.28 | 25 + .../lib/hcrypto/libtommath/etc/drprimes.txt | 9 + .../heimdal/lib/hcrypto/libtommath/etc/makefile | 44 + .../lib/hcrypto/libtommath/etc/makefile.icc | 67 + .../lib/hcrypto/libtommath/etc/makefile.msvc | 24 + .../heimdal/lib/hcrypto/libtommath/etc/mersenne.c | 138 + .../heimdal/lib/hcrypto/libtommath/etc/mont.c | 44 + .../heimdal/lib/hcrypto/libtommath/etc/pprime.c | 411 + .../heimdal/lib/hcrypto/libtommath/etc/prime.1024 | 414 + .../heimdal/lib/hcrypto/libtommath/etc/prime.512 | 205 + .../heimdal/lib/hcrypto/libtommath/etc/timer.asm | 37 + .../heimdal/lib/hcrypto/libtommath/etc/tune.c | 542 + .../heimdal/lib/hcrypto/libtommath/etc/tune_it.sh | 107 + third_party/heimdal/lib/hcrypto/libtommath/gen.pl | 20 + .../heimdal/lib/hcrypto/libtommath/helper.pl | 482 + .../lib/hcrypto/libtommath/libtommath.pc.in | 10 + .../lib/hcrypto/libtommath/libtommath_VS2008.sln | 29 + .../hcrypto/libtommath/libtommath_VS2008.vcproj | 966 + .../heimdal/lib/hcrypto/libtommath/logs/README | 13 + .../heimdal/lib/hcrypto/libtommath/logs/add.log | 16 + .../heimdal/lib/hcrypto/libtommath/logs/addsub.png | Bin 0 -> 5921 bytes .../heimdal/lib/hcrypto/libtommath/logs/expt.log | 7 + .../heimdal/lib/hcrypto/libtommath/logs/expt.png | Bin 0 -> 7290 bytes .../lib/hcrypto/libtommath/logs/expt_2k.log | 6 + .../lib/hcrypto/libtommath/logs/expt_2kl.log | 3 + .../lib/hcrypto/libtommath/logs/expt_dr.log | 7 + .../heimdal/lib/hcrypto/libtommath/logs/graphs.dem | 16 + .../heimdal/lib/hcrypto/libtommath/logs/index.html | 27 + .../heimdal/lib/hcrypto/libtommath/logs/invmod.log | 8 + .../heimdal/lib/hcrypto/libtommath/logs/invmod.png | Bin 0 -> 6294 bytes .../heimdal/lib/hcrypto/libtommath/logs/mult.log | 84 + .../heimdal/lib/hcrypto/libtommath/logs/mult.png | Bin 0 -> 8308 bytes .../lib/hcrypto/libtommath/logs/mult_kara.log | 84 + .../heimdal/lib/hcrypto/libtommath/logs/sqr.log | 84 + .../lib/hcrypto/libtommath/logs/sqr_kara.log | 84 + .../heimdal/lib/hcrypto/libtommath/logs/sub.log | 16 + .../heimdal/lib/hcrypto/libtommath/makefile | 165 + .../heimdal/lib/hcrypto/libtommath/makefile.mingw | 109 + .../heimdal/lib/hcrypto/libtommath/makefile.msvc | 93 + .../heimdal/lib/hcrypto/libtommath/makefile.shared | 99 + .../heimdal/lib/hcrypto/libtommath/makefile.unix | 106 + .../lib/hcrypto/libtommath/makefile_include.mk | 166 + .../heimdal/lib/hcrypto/libtommath/mtest/logtab.h | 24 + .../lib/hcrypto/libtommath/mtest/mpi-config.h | 90 + .../lib/hcrypto/libtommath/mtest/mpi-types.h | 20 + .../heimdal/lib/hcrypto/libtommath/mtest/mpi.c | 3987 + .../heimdal/lib/hcrypto/libtommath/mtest/mpi.h | 233 + .../heimdal/lib/hcrypto/libtommath/mtest/mtest.c | 374 + .../heimdal/lib/hcrypto/libtommath/pre_gen/mpi.c | 9541 + .../heimdal/lib/hcrypto/libtommath/testme.sh | 394 + .../heimdal/lib/hcrypto/libtommath/tommath.def | 145 + .../heimdal/lib/hcrypto/libtommath/tommath.h | 781 + .../heimdal/lib/hcrypto/libtommath/tommath_class.h | 1319 + .../lib/hcrypto/libtommath/tommath_cutoffs.h | 13 + .../lib/hcrypto/libtommath/tommath_private.h | 303 + .../lib/hcrypto/libtommath/tommath_superclass.h | 110 + third_party/heimdal/lib/hcrypto/md4.c | 250 + third_party/heimdal/lib/hcrypto/md4.h | 62 + third_party/heimdal/lib/hcrypto/md5.c | 274 + third_party/heimdal/lib/hcrypto/md5.h | 62 + third_party/heimdal/lib/hcrypto/md5crypt_test.c | 75 + third_party/heimdal/lib/hcrypto/mdtest.c | 320 + third_party/heimdal/lib/hcrypto/passwd_dialog.aps | Bin 0 -> 30428 bytes third_party/heimdal/lib/hcrypto/passwd_dialog.clw | 34 + third_party/heimdal/lib/hcrypto/passwd_dialog.rc | 143 + third_party/heimdal/lib/hcrypto/passwd_dialog.res | Bin 0 -> 320 bytes third_party/heimdal/lib/hcrypto/passwd_dlg.c | 89 + third_party/heimdal/lib/hcrypto/passwd_dlg.h | 47 + third_party/heimdal/lib/hcrypto/pkcs12.c | 158 + third_party/heimdal/lib/hcrypto/pkcs12.h | 57 + third_party/heimdal/lib/hcrypto/pkcs5.c | 153 + third_party/heimdal/lib/hcrypto/rand-fortuna.c | 648 + third_party/heimdal/lib/hcrypto/rand-timer.c | 210 + third_party/heimdal/lib/hcrypto/rand-unix.c | 175 + third_party/heimdal/lib/hcrypto/rand-w32.c | 150 + third_party/heimdal/lib/hcrypto/rand.c | 402 + third_party/heimdal/lib/hcrypto/rand.h | 106 + third_party/heimdal/lib/hcrypto/randi.h | 49 + third_party/heimdal/lib/hcrypto/rc2.c | 240 + third_party/heimdal/lib/hcrypto/rc2.h | 71 + third_party/heimdal/lib/hcrypto/rc2test.c | 167 + third_party/heimdal/lib/hcrypto/rc4.c | 79 + third_party/heimdal/lib/hcrypto/rc4.h | 46 + third_party/heimdal/lib/hcrypto/rctest.c | 161 + third_party/heimdal/lib/hcrypto/resource.h | 18 + third_party/heimdal/lib/hcrypto/rijndael-alg-fst.c | 1223 + third_party/heimdal/lib/hcrypto/rijndael-alg-fst.h | 46 + third_party/heimdal/lib/hcrypto/rnd_keys.c | 138 + third_party/heimdal/lib/hcrypto/rsa-gmp.c | 584 + third_party/heimdal/lib/hcrypto/rsa-ltm.c | 637 + third_party/heimdal/lib/hcrypto/rsa-tfm.c | 573 + third_party/heimdal/lib/hcrypto/rsa.c | 706 + third_party/heimdal/lib/hcrypto/rsa.h | 184 + third_party/heimdal/lib/hcrypto/rsakey.der | Bin 0 -> 609 bytes third_party/heimdal/lib/hcrypto/rsakey2048.der | Bin 0 -> 1192 bytes third_party/heimdal/lib/hcrypto/rsakey4096.der | Bin 0 -> 2349 bytes third_party/heimdal/lib/hcrypto/sha.c | 300 + third_party/heimdal/lib/hcrypto/sha.h | 115 + third_party/heimdal/lib/hcrypto/sha256.c | 233 + third_party/heimdal/lib/hcrypto/sha512.c | 301 + third_party/heimdal/lib/hcrypto/test_bn.c | 392 + third_party/heimdal/lib/hcrypto/test_bulk.c | 311 + third_party/heimdal/lib/hcrypto/test_cipher.c | 430 + third_party/heimdal/lib/hcrypto/test_crypto.in | 120 + third_party/heimdal/lib/hcrypto/test_dh.c | 472 + third_party/heimdal/lib/hcrypto/test_engine_dso.c | 329 + third_party/heimdal/lib/hcrypto/test_hmac.c | 74 + third_party/heimdal/lib/hcrypto/test_pkcs12.c | 138 + third_party/heimdal/lib/hcrypto/test_pkcs5.c | 147 + third_party/heimdal/lib/hcrypto/test_rand.c | 219 + third_party/heimdal/lib/hcrypto/test_rsa.c | 397 + third_party/heimdal/lib/hcrypto/ui.c | 218 + third_party/heimdal/lib/hcrypto/ui.h | 49 + third_party/heimdal/lib/hcrypto/undef.h | 167 + third_party/heimdal/lib/hcrypto/validate.c | 307 + third_party/heimdal/lib/hcrypto/version-script.map | 333 + third_party/heimdal/lib/hcrypto/x25519/NTMakefile | 46 + third_party/heimdal/lib/hcrypto/x25519/align.h | 7 + .../heimdal/lib/hcrypto/x25519/ed25519_ref10.c | 2886 + .../heimdal/lib/hcrypto/x25519/ed25519_ref10.h | 174 + .../lib/hcrypto/x25519/ed25519_ref10_fe_25_5.h | 1067 + .../lib/hcrypto/x25519/ed25519_ref10_fe_51.h | 539 + .../heimdal/lib/hcrypto/x25519/fe_25_5/base.h | 1344 + .../heimdal/lib/hcrypto/x25519/fe_25_5/base2.h | 40 + .../heimdal/lib/hcrypto/x25519/fe_25_5/constants.h | 40 + .../heimdal/lib/hcrypto/x25519/fe_25_5/fe.h | 220 + .../heimdal/lib/hcrypto/x25519/fe_51/base.h | 1344 + .../heimdal/lib/hcrypto/x25519/fe_51/base2.h | 40 + .../heimdal/lib/hcrypto/x25519/fe_51/constants.h | 41 + third_party/heimdal/lib/hcrypto/x25519/fe_51/fe.h | 116 + .../heimdal/lib/hcrypto/x25519/x25519_ref10.c | 209 + third_party/heimdal/lib/hcrypto/x25519_ref10.h | 55 + third_party/heimdal/lib/hdb/Makefile.am | 170 + third_party/heimdal/lib/hdb/NTMakefile | 189 + third_party/heimdal/lib/hdb/common.c | 1906 + third_party/heimdal/lib/hdb/data-mkey.mit.des3.be | Bin 0 -> 46 bytes third_party/heimdal/lib/hdb/data-mkey.mit.des3.le | Bin 0 -> 30 bytes third_party/heimdal/lib/hdb/db.c | 391 + third_party/heimdal/lib/hdb/db3.c | 495 + third_party/heimdal/lib/hdb/dbinfo.c | 291 + third_party/heimdal/lib/hdb/ext.c | 786 + third_party/heimdal/lib/hdb/hdb-keytab.c | 232 + third_party/heimdal/lib/hdb/hdb-ldap.c | 2118 + third_party/heimdal/lib/hdb/hdb-mdb.c | 692 + third_party/heimdal/lib/hdb/hdb-mitdb.c | 1498 + third_party/heimdal/lib/hdb/hdb-sqlite.c | 1075 + third_party/heimdal/lib/hdb/hdb.asn1 | 254 + third_party/heimdal/lib/hdb/hdb.c | 848 + third_party/heimdal/lib/hdb/hdb.h | 344 + third_party/heimdal/lib/hdb/hdb.opt | 9 + third_party/heimdal/lib/hdb/hdb.schema | 144 + third_party/heimdal/lib/hdb/hdb_err.et | 33 + third_party/heimdal/lib/hdb/hdb_locl.h | 73 + third_party/heimdal/lib/hdb/keys.c | 855 + third_party/heimdal/lib/hdb/keytab.c | 448 + third_party/heimdal/lib/hdb/libhdb-exports.def | 180 + third_party/heimdal/lib/hdb/libhdb-version.rc | 36 + third_party/heimdal/lib/hdb/mkey.c | 769 + third_party/heimdal/lib/hdb/ndbm.c | 406 + third_party/heimdal/lib/hdb/print.c | 597 + third_party/heimdal/lib/hdb/test_concurrency.c | 506 + third_party/heimdal/lib/hdb/test_dbinfo.c | 156 + third_party/heimdal/lib/hdb/test_hdbkeys.c | 124 + third_party/heimdal/lib/hdb/test_mkey.c | 55 + third_party/heimdal/lib/hdb/test_namespace.c | 941 + third_party/heimdal/lib/hdb/version-script.map | 189 + third_party/heimdal/lib/heimdal/NTMakefile | 98 + third_party/heimdal/lib/heimdal/heimdal-version.rc | 36 + third_party/heimdal/lib/hx509/ChangeLog | 2749 + third_party/heimdal/lib/hx509/Makefile.am | 398 + third_party/heimdal/lib/hx509/NTMakefile | 180 + third_party/heimdal/lib/hx509/TODO | 61 + third_party/heimdal/lib/hx509/ca.c | 3099 + third_party/heimdal/lib/hx509/cert.c | 3951 + third_party/heimdal/lib/hx509/char_map.h | 45 + third_party/heimdal/lib/hx509/cms.c | 1719 + third_party/heimdal/lib/hx509/collector.c | 341 + third_party/heimdal/lib/hx509/crypto-ec.c | 838 + third_party/heimdal/lib/hx509/crypto.c | 2800 + third_party/heimdal/lib/hx509/data/PKITS.pdf | Bin 0 -> 754584 bytes third_party/heimdal/lib/hx509/data/PKITS_data.zip | Bin 0 -> 2149008 bytes .../heimdal/lib/hx509/data/bleichenbacher-bad.pem | 12 + .../heimdal/lib/hx509/data/bleichenbacher-good.pem | 12 + .../hx509/data/bleichenbacher-sf-pad-correct.pem | 16 + third_party/heimdal/lib/hx509/data/ca.crt | 32 + third_party/heimdal/lib/hx509/data/ca.key | 52 + third_party/heimdal/lib/hx509/data/crl1.crl | 16 + third_party/heimdal/lib/hx509/data/crl1.der | Bin 0 -> 649 bytes third_party/heimdal/lib/hx509/data/eccurve.pem | 3 + third_party/heimdal/lib/hx509/data/gen-req.sh | 360 + third_party/heimdal/lib/hx509/data/https.crt | 116 + third_party/heimdal/lib/hx509/data/https.key | 52 + third_party/heimdal/lib/hx509/data/j.pem | 26 + third_party/heimdal/lib/hx509/data/kdc.crt | 122 + third_party/heimdal/lib/hx509/data/kdc.key | 52 + third_party/heimdal/lib/hx509/data/key.der | Bin 0 -> 609 bytes third_party/heimdal/lib/hx509/data/key2.der | Bin 0 -> 610 bytes third_party/heimdal/lib/hx509/data/mkcert.sh | 83 + third_party/heimdal/lib/hx509/data/n0ll.pem | 47 + third_party/heimdal/lib/hx509/data/nist-data | 91 + third_party/heimdal/lib/hx509/data/nist-data2 | 291 + third_party/heimdal/lib/hx509/data/nist-result2 | 31 + .../heimdal/lib/hx509/data/no-proxy-test.crt | 30 + .../heimdal/lib/hx509/data/no-proxy-test.key | 52 + third_party/heimdal/lib/hx509/data/ocsp-req1.der | Bin 0 -> 105 bytes third_party/heimdal/lib/hx509/data/ocsp-req2.der | Bin 0 -> 105 bytes .../heimdal/lib/hx509/data/ocsp-resp1-2.der | Bin 0 -> 999 bytes .../heimdal/lib/hx509/data/ocsp-resp1-3.der | Bin 0 -> 363 bytes .../heimdal/lib/hx509/data/ocsp-resp1-ca.der | Bin 0 -> 2159 bytes .../heimdal/lib/hx509/data/ocsp-resp1-keyhash.der | Bin 0 -> 2060 bytes .../lib/hx509/data/ocsp-resp1-ocsp-no-cert.der | Bin 0 -> 748 bytes .../heimdal/lib/hx509/data/ocsp-resp1-ocsp.der | Bin 0 -> 2078 bytes third_party/heimdal/lib/hx509/data/ocsp-resp1.der | Bin 0 -> 918 bytes third_party/heimdal/lib/hx509/data/ocsp-resp2.der | Bin 0 -> 2095 bytes .../heimdal/lib/hx509/data/ocsp-responder.crt | 119 + .../heimdal/lib/hx509/data/ocsp-responder.key | 52 + third_party/heimdal/lib/hx509/data/openssl.1.0.cnf | 190 + third_party/heimdal/lib/hx509/data/openssl.1.1.cnf | 185 + third_party/heimdal/lib/hx509/data/pkinit-ec.crt | 81 + third_party/heimdal/lib/hx509/data/pkinit-ec.key | 5 + .../heimdal/lib/hx509/data/pkinit-proxy-chain.crt | 149 + .../heimdal/lib/hx509/data/pkinit-proxy.crt | 30 + .../heimdal/lib/hx509/data/pkinit-proxy.key | 52 + third_party/heimdal/lib/hx509/data/pkinit-pw.key | 54 + third_party/heimdal/lib/hx509/data/pkinit.crt | 119 + third_party/heimdal/lib/hx509/data/pkinit.key | 52 + .../heimdal/lib/hx509/data/proxy-level-test.crt | 31 + .../heimdal/lib/hx509/data/proxy-level-test.key | 52 + third_party/heimdal/lib/hx509/data/proxy-test.crt | 30 + third_party/heimdal/lib/hx509/data/proxy-test.key | 52 + .../lib/hx509/data/proxy10-child-child-test.crt | 32 + .../lib/hx509/data/proxy10-child-child-test.key | 52 + .../heimdal/lib/hx509/data/proxy10-child-test.crt | 31 + .../heimdal/lib/hx509/data/proxy10-child-test.key | 52 + .../heimdal/lib/hx509/data/proxy10-test.crt | 30 + .../heimdal/lib/hx509/data/proxy10-test.key | 52 + third_party/heimdal/lib/hx509/data/revoke.crt | 116 + third_party/heimdal/lib/hx509/data/revoke.key | 52 + .../lib/hx509/data/secp256r1TestCA.cert.pem | 12 + .../heimdal/lib/hx509/data/secp256r1TestCA.key.pem | 5 + .../heimdal/lib/hx509/data/secp256r1TestCA.pem | 17 + .../lib/hx509/data/secp256r2TestClient.cert.pem | 12 + .../lib/hx509/data/secp256r2TestClient.key.pem | 5 + .../heimdal/lib/hx509/data/secp256r2TestClient.pem | 17 + .../lib/hx509/data/secp256r2TestServer.cert.pem | 12 + .../lib/hx509/data/secp256r2TestServer.key.pem | 5 + .../heimdal/lib/hx509/data/secp256r2TestServer.pem | 17 + .../heimdal/lib/hx509/data/sf-class2-root.pem | 24 + third_party/heimdal/lib/hx509/data/static-file | 84 + third_party/heimdal/lib/hx509/data/sub-ca.crt | 123 + third_party/heimdal/lib/hx509/data/sub-ca.key | 52 + third_party/heimdal/lib/hx509/data/sub-cert.crt | 116 + third_party/heimdal/lib/hx509/data/sub-cert.key | 52 + third_party/heimdal/lib/hx509/data/sub-cert.p12 | Bin 0 -> 7072 bytes third_party/heimdal/lib/hx509/data/tcg-devid.pem | 24 + third_party/heimdal/lib/hx509/data/tcg-ek-cp.pem | 24 + .../heimdal/lib/hx509/data/test-ds-only.crt | 117 + .../heimdal/lib/hx509/data/test-ds-only.key | 52 + .../heimdal/lib/hx509/data/test-enveloped-aes-128 | Bin 0 -> 3547 bytes .../heimdal/lib/hx509/data/test-enveloped-aes-256 | Bin 0 -> 3547 bytes .../heimdal/lib/hx509/data/test-enveloped-des | Bin 0 -> 3527 bytes .../heimdal/lib/hx509/data/test-enveloped-des-ede3 | Bin 0 -> 3530 bytes .../heimdal/lib/hx509/data/test-enveloped-rc2-128 | Bin 0 -> 3535 bytes .../heimdal/lib/hx509/data/test-enveloped-rc2-40 | Bin 0 -> 3536 bytes .../heimdal/lib/hx509/data/test-enveloped-rc2-64 | Bin 0 -> 3535 bytes .../heimdal/lib/hx509/data/test-ke-only.crt | 117 + .../heimdal/lib/hx509/data/test-ke-only.key | 52 + third_party/heimdal/lib/hx509/data/test-nopw.p12 | Bin 0 -> 5510 bytes third_party/heimdal/lib/hx509/data/test-pw.key | 54 + .../heimdal/lib/hx509/data/test-signed-data | Bin 0 -> 5057 bytes .../heimdal/lib/hx509/data/test-signed-data-noattr | Bin 0 -> 4826 bytes .../lib/hx509/data/test-signed-data-noattr-nocerts | Bin 0 -> 3537 bytes .../heimdal/lib/hx509/data/test-signed-sha-1 | Bin 0 -> 5037 bytes .../heimdal/lib/hx509/data/test-signed-sha-256 | Bin 0 -> 5057 bytes .../heimdal/lib/hx509/data/test-signed-sha-512 | Bin 0 -> 5090 bytes .../heimdal/lib/hx509/data/test.combined.crt | 168 + third_party/heimdal/lib/hx509/data/test.crt | 116 + third_party/heimdal/lib/hx509/data/test.key | 52 + third_party/heimdal/lib/hx509/data/test.p12 | Bin 0 -> 5608 bytes .../lib/hx509/data/win-u16-in-printablestring.der | Bin 0 -> 772 bytes .../lib/hx509/data/yutaka-pad-broken-ca.pem | 16 + .../lib/hx509/data/yutaka-pad-broken-cert.pem | 18 + .../heimdal/lib/hx509/data/yutaka-pad-ok-ca.pem | 16 + .../heimdal/lib/hx509/data/yutaka-pad-ok-cert.pem | 18 + third_party/heimdal/lib/hx509/data/yutaka-pad.key | 15 + third_party/heimdal/lib/hx509/doxygen.c | 85 + third_party/heimdal/lib/hx509/env.c | 245 + third_party/heimdal/lib/hx509/error.c | 220 + third_party/heimdal/lib/hx509/file.c | 387 + third_party/heimdal/lib/hx509/hx509.h | 222 + third_party/heimdal/lib/hx509/hx509_err.et | 110 + third_party/heimdal/lib/hx509/hx_locl.h | 330 + third_party/heimdal/lib/hx509/hxtool-commands.in | 1088 + third_party/heimdal/lib/hx509/hxtool-version.rc | 36 + third_party/heimdal/lib/hx509/hxtool.1 | 380 + third_party/heimdal/lib/hx509/hxtool.c | 3249 + third_party/heimdal/lib/hx509/keyset.c | 846 + third_party/heimdal/lib/hx509/ks_dir.c | 231 + third_party/heimdal/lib/hx509/ks_file.c | 808 + third_party/heimdal/lib/hx509/ks_keychain.c | 627 + third_party/heimdal/lib/hx509/ks_mem.c | 224 + third_party/heimdal/lib/hx509/ks_null.c | 101 + third_party/heimdal/lib/hx509/ks_p11.c | 1230 + third_party/heimdal/lib/hx509/ks_p12.c | 764 + third_party/heimdal/lib/hx509/libhx509-exports.def | 305 + third_party/heimdal/lib/hx509/lock.c | 252 + third_party/heimdal/lib/hx509/name.c | 1529 + third_party/heimdal/lib/hx509/peer.c | 237 + third_party/heimdal/lib/hx509/print.c | 1144 + third_party/heimdal/lib/hx509/quote.py | 101 + third_party/heimdal/lib/hx509/ref/pkcs11.h | 1722 + third_party/heimdal/lib/hx509/req.c | 1681 + third_party/heimdal/lib/hx509/revoke.c | 1647 + third_party/heimdal/lib/hx509/sel-gram.y | 130 + third_party/heimdal/lib/hx509/sel-lex.l | 148 + third_party/heimdal/lib/hx509/sel.c | 240 + third_party/heimdal/lib/hx509/sel.h | 100 + third_party/heimdal/lib/hx509/softp11.c | 1777 + third_party/heimdal/lib/hx509/test_ca.in | 480 + third_party/heimdal/lib/hx509/test_cert.in | 84 + third_party/heimdal/lib/hx509/test_chain.in | 256 + third_party/heimdal/lib/hx509/test_cms.in | 514 + third_party/heimdal/lib/hx509/test_crypto.in | 192 + third_party/heimdal/lib/hx509/test_expr.c | 87 + third_party/heimdal/lib/hx509/test_java_pkcs11.in | 73 + third_party/heimdal/lib/hx509/test_name.c | 468 + third_party/heimdal/lib/hx509/test_nist.in | 117 + third_party/heimdal/lib/hx509/test_nist2.in | 136 + third_party/heimdal/lib/hx509/test_nist_cert.in | 68 + third_party/heimdal/lib/hx509/test_nist_pkcs12.in | 77 + third_party/heimdal/lib/hx509/test_pkcs11.in | 62 + third_party/heimdal/lib/hx509/test_query.in | 203 + third_party/heimdal/lib/hx509/test_req.in | 211 + third_party/heimdal/lib/hx509/test_soft_pkcs11.c | 228 + third_party/heimdal/lib/hx509/test_windows.in | 89 + .../heimdal/lib/hx509/tst-crypto-available1 | 13 + .../heimdal/lib/hx509/tst-crypto-available2 | 5 + .../heimdal/lib/hx509/tst-crypto-available3 | 6 + third_party/heimdal/lib/hx509/tst-crypto-select | 1 + third_party/heimdal/lib/hx509/tst-crypto-select1 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select2 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select3 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select4 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select5 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select6 | 1 + third_party/heimdal/lib/hx509/tst-crypto-select7 | 1 + third_party/heimdal/lib/hx509/version-script.map | 315 + third_party/heimdal/lib/ipc/Makefile.am | 76 + third_party/heimdal/lib/ipc/client.c | 610 + third_party/heimdal/lib/ipc/common.c | 206 + third_party/heimdal/lib/ipc/heim-ipc.h | 133 + third_party/heimdal/lib/ipc/heim_ipc.defs | 66 + third_party/heimdal/lib/ipc/heim_ipc_async.defs | 56 + third_party/heimdal/lib/ipc/heim_ipc_reply.defs | 51 + third_party/heimdal/lib/ipc/heim_ipc_types.h | 44 + third_party/heimdal/lib/ipc/hi_locl.h | 83 + third_party/heimdal/lib/ipc/server.c | 1372 + third_party/heimdal/lib/ipc/tc.c | 138 + third_party/heimdal/lib/ipc/ts-http.c | 136 + third_party/heimdal/lib/ipc/ts.c | 116 + third_party/heimdal/lib/kadm5/ChangeLog | 1389 + third_party/heimdal/lib/kadm5/Makefile.am | 233 + third_party/heimdal/lib/kadm5/NTMakefile | 296 + third_party/heimdal/lib/kadm5/acl.c | 242 + third_party/heimdal/lib/kadm5/ad.c | 1525 + third_party/heimdal/lib/kadm5/admin.h | 272 + third_party/heimdal/lib/kadm5/bump_pw_expire.c | 64 + third_party/heimdal/lib/kadm5/check-cracklib.pl | 112 + third_party/heimdal/lib/kadm5/chpass_c.c | 175 + third_party/heimdal/lib/kadm5/chpass_s.c | 466 + third_party/heimdal/lib/kadm5/client_glue.c | 150 + third_party/heimdal/lib/kadm5/common_glue.c | 452 + third_party/heimdal/lib/kadm5/context_s.c | 316 + third_party/heimdal/lib/kadm5/create_c.c | 114 + third_party/heimdal/lib/kadm5/create_s.c | 363 + third_party/heimdal/lib/kadm5/default_keys.c | 121 + third_party/heimdal/lib/kadm5/delete_c.c | 88 + third_party/heimdal/lib/kadm5/delete_s.c | 145 + third_party/heimdal/lib/kadm5/destroy_c.c | 58 + third_party/heimdal/lib/kadm5/destroy_s.c | 95 + third_party/heimdal/lib/kadm5/ent_setup.c | 276 + third_party/heimdal/lib/kadm5/error.c | 48 + third_party/heimdal/lib/kadm5/flush.c | 48 + third_party/heimdal/lib/kadm5/flush_c.c | 41 + third_party/heimdal/lib/kadm5/flush_s.c | 41 + third_party/heimdal/lib/kadm5/free.c | 92 + .../kadm5/fuzz-inputs-bin/test_marshall-ent0.bin | Bin 0 -> 191 bytes .../kadm5/fuzz-inputs-bin/test_marshall-ent1.bin | Bin 0 -> 139 bytes .../fuzz-inputs-packed/test_marshall-ent0.bin | Bin 0 -> 65 bytes .../fuzz-inputs-packed/test_marshall-ent1.bin | Bin 0 -> 46 bytes .../kadm5/fuzz-inputs-txt/test_marshall-ent0.txt | 101 + .../kadm5/fuzz-inputs-txt/test_marshall-ent1.txt | 54 + third_party/heimdal/lib/kadm5/get_c.c | 96 + third_party/heimdal/lib/kadm5/get_princs_c.c | 299 + third_party/heimdal/lib/kadm5/get_princs_s.c | 207 + third_party/heimdal/lib/kadm5/get_s.c | 412 + third_party/heimdal/lib/kadm5/init_c.c | 920 + third_party/heimdal/lib/kadm5/init_s.c | 280 + third_party/heimdal/lib/kadm5/iprop-commands.in | 187 + third_party/heimdal/lib/kadm5/iprop-log-version.rc | 36 + third_party/heimdal/lib/kadm5/iprop-log.8 | 254 + third_party/heimdal/lib/kadm5/iprop-log.c | 653 + third_party/heimdal/lib/kadm5/iprop.8 | 246 + third_party/heimdal/lib/kadm5/iprop.h | 80 + .../heimdal/lib/kadm5/ipropd-master-version.rc | 36 + .../heimdal/lib/kadm5/ipropd-slave-version.rc | 36 + third_party/heimdal/lib/kadm5/ipropd_common.c | 266 + third_party/heimdal/lib/kadm5/ipropd_master.c | 1890 + third_party/heimdal/lib/kadm5/ipropd_slave.c | 1186 + third_party/heimdal/lib/kadm5/kadm5-hook.h | 151 + third_party/heimdal/lib/kadm5/kadm5-pwcheck.h | 73 + third_party/heimdal/lib/kadm5/kadm5_err.et | 114 + third_party/heimdal/lib/kadm5/kadm5_locl.h | 91 + third_party/heimdal/lib/kadm5/kadm5_pwcheck.3 | 159 + third_party/heimdal/lib/kadm5/keys.c | 132 + .../heimdal/lib/kadm5/libkadm5srv-exports.def | 93 + .../heimdal/lib/kadm5/libkadm5srv-version.rc | 36 + third_party/heimdal/lib/kadm5/log.c | 2756 + third_party/heimdal/lib/kadm5/marshall.c | 962 + third_party/heimdal/lib/kadm5/modify_c.c | 93 + third_party/heimdal/lib/kadm5/modify_s.c | 215 + third_party/heimdal/lib/kadm5/password_quality.c | 508 + third_party/heimdal/lib/kadm5/private.h | 210 + third_party/heimdal/lib/kadm5/privs_c.c | 89 + third_party/heimdal/lib/kadm5/privs_s.c | 44 + third_party/heimdal/lib/kadm5/prune_c.c | 73 + third_party/heimdal/lib/kadm5/prune_s.c | 149 + third_party/heimdal/lib/kadm5/randkey_c.c | 154 + third_party/heimdal/lib/kadm5/randkey_s.c | 204 + third_party/heimdal/lib/kadm5/rename_c.c | 94 + third_party/heimdal/lib/kadm5/rename_s.c | 188 + third_party/heimdal/lib/kadm5/sample_hook.c | 286 + .../heimdal/lib/kadm5/sample_passwd_check.c | 87 + third_party/heimdal/lib/kadm5/send_recv.c | 99 + third_party/heimdal/lib/kadm5/server_glue.c | 150 + third_party/heimdal/lib/kadm5/server_hooks.c | 97 + third_party/heimdal/lib/kadm5/set_keys.c | 420 + third_party/heimdal/lib/kadm5/set_modifier.c | 54 + third_party/heimdal/lib/kadm5/setkey3_s.c | 220 + third_party/heimdal/lib/kadm5/test_pw_quality.c | 99 + .../heimdal/lib/kadm5/version-script-client.map | 69 + third_party/heimdal/lib/kadm5/version-script.map | 98 + third_party/heimdal/lib/kafs/ChangeLog | 572 + third_party/heimdal/lib/kafs/Makefile.am | 96 + third_party/heimdal/lib/kafs/NTMakefile | 35 + third_party/heimdal/lib/kafs/afskrb5.c | 353 + third_party/heimdal/lib/kafs/afsl.exp | 6 + third_party/heimdal/lib/kafs/afslib.c | 53 + third_party/heimdal/lib/kafs/afslib.exp | 3 + third_party/heimdal/lib/kafs/afssys.c | 630 + third_party/heimdal/lib/kafs/afssysdefs.h | 109 + third_party/heimdal/lib/kafs/common.c | 469 + third_party/heimdal/lib/kafs/kafs.3 | 296 + third_party/heimdal/lib/kafs/kafs.h | 216 + third_party/heimdal/lib/kafs/kafs_locl.h | 162 + third_party/heimdal/lib/kafs/roken_rename.h | 64 + third_party/heimdal/lib/kafs/rxkad_kdf.c | 221 + third_party/heimdal/lib/kdfs/ChangeLog | 28 + third_party/heimdal/lib/kdfs/Makefile.am | 12 + third_party/heimdal/lib/kdfs/NTMakefile | 35 + third_party/heimdal/lib/kdfs/k5dfspag.c | 368 + third_party/heimdal/lib/krb5/Makefile.am | 454 + third_party/heimdal/lib/krb5/NTMakefile | 542 + third_party/heimdal/lib/krb5/acache.c | 1129 + third_party/heimdal/lib/krb5/acl.c | 293 + third_party/heimdal/lib/krb5/add_et_list.c | 54 + third_party/heimdal/lib/krb5/addr_families.c | 1574 + third_party/heimdal/lib/krb5/aes-test.c | 1058 + third_party/heimdal/lib/krb5/an2ln_plugin.h | 91 + third_party/heimdal/lib/krb5/aname_to_localname.c | 471 + third_party/heimdal/lib/krb5/appdefault.c | 140 + third_party/heimdal/lib/krb5/asn1_glue.c | 162 + third_party/heimdal/lib/krb5/auth_context.c | 621 + third_party/heimdal/lib/krb5/authdata.c | 124 + third_party/heimdal/lib/krb5/build_ap_req.c | 68 + third_party/heimdal/lib/krb5/build_auth.c | 267 + third_party/heimdal/lib/krb5/cache.c | 2300 + third_party/heimdal/lib/krb5/ccache_plugin.h | 46 + third_party/heimdal/lib/krb5/changepw.c | 860 + third_party/heimdal/lib/krb5/codec.c | 214 + third_party/heimdal/lib/krb5/config_file.c | 758 + third_party/heimdal/lib/krb5/constants.c | 67 + third_party/heimdal/lib/krb5/context.c | 1506 + third_party/heimdal/lib/krb5/convert_creds.c | 92 + third_party/heimdal/lib/krb5/copy_host_realm.c | 72 + third_party/heimdal/lib/krb5/crc.c | 69 + third_party/heimdal/lib/krb5/creds.c | 282 + third_party/heimdal/lib/krb5/crypto-aes-sha1.c | 177 + third_party/heimdal/lib/krb5/crypto-aes-sha2.c | 199 + third_party/heimdal/lib/krb5/crypto-algs.c | 94 + third_party/heimdal/lib/krb5/crypto-arcfour.c | 368 + third_party/heimdal/lib/krb5/crypto-des-common.c | 158 + third_party/heimdal/lib/krb5/crypto-des.c | 403 + third_party/heimdal/lib/krb5/crypto-des3.c | 292 + third_party/heimdal/lib/krb5/crypto-evp.c | 674 + third_party/heimdal/lib/krb5/crypto-null.c | 103 + third_party/heimdal/lib/krb5/crypto-pk.c | 295 + third_party/heimdal/lib/krb5/crypto-rand.c | 152 + third_party/heimdal/lib/krb5/crypto-stubs.c | 102 + third_party/heimdal/lib/krb5/crypto.c | 3248 + third_party/heimdal/lib/krb5/crypto.h | 231 + third_party/heimdal/lib/krb5/data.c | 228 + third_party/heimdal/lib/krb5/db_plugin.c | 41 + third_party/heimdal/lib/krb5/db_plugin.h | 68 + third_party/heimdal/lib/krb5/dcache.c | 854 + third_party/heimdal/lib/krb5/deprecated.c | 725 + third_party/heimdal/lib/krb5/derived-key-test.c | 145 + third_party/heimdal/lib/krb5/digest.c | 1165 + third_party/heimdal/lib/krb5/dll.c | 76 + third_party/heimdal/lib/krb5/doxygen.c | 700 + third_party/heimdal/lib/krb5/eai_to_heim_errno.c | 118 + third_party/heimdal/lib/krb5/enomem.c | 42 + third_party/heimdal/lib/krb5/error_string.c | 236 + third_party/heimdal/lib/krb5/expand_hostname.c | 177 + third_party/heimdal/lib/krb5/expand_path.c | 94 + third_party/heimdal/lib/krb5/fast.c | 963 + third_party/heimdal/lib/krb5/fcache.c | 1693 + third_party/heimdal/lib/krb5/free.c | 51 + third_party/heimdal/lib/krb5/free_host_realm.c | 59 + third_party/heimdal/lib/krb5/generate_seq_number.c | 48 + third_party/heimdal/lib/krb5/generate_subkey.c | 73 + third_party/heimdal/lib/krb5/get_addrs.c | 283 + third_party/heimdal/lib/krb5/get_cred.c | 2044 + .../heimdal/lib/krb5/get_default_principal.c | 95 + third_party/heimdal/lib/krb5/get_default_realm.c | 80 + third_party/heimdal/lib/krb5/get_for_creds.c | 367 + third_party/heimdal/lib/krb5/get_host_realm.c | 308 + third_party/heimdal/lib/krb5/get_in_tkt.c | 557 + third_party/heimdal/lib/krb5/get_port.c | 52 + third_party/heimdal/lib/krb5/init_creds.c | 482 + third_party/heimdal/lib/krb5/init_creds_pw.c | 4052 + third_party/heimdal/lib/krb5/k524_err.et | 20 + third_party/heimdal/lib/krb5/k5e1_err.et | 13 + third_party/heimdal/lib/krb5/kcm.c | 1505 + third_party/heimdal/lib/krb5/kcm.h | 87 + third_party/heimdal/lib/krb5/kerberos.8 | 115 + third_party/heimdal/lib/krb5/keyblock.c | 203 + third_party/heimdal/lib/krb5/keytab.c | 976 + third_party/heimdal/lib/krb5/keytab_any.c | 260 + third_party/heimdal/lib/krb5/keytab_file.c | 856 + third_party/heimdal/lib/krb5/keytab_keyfile.c | 456 + third_party/heimdal/lib/krb5/keytab_memory.c | 231 + third_party/heimdal/lib/krb5/krb5-plugin.7 | 359 + third_party/heimdal/lib/krb5/krb5.conf.5 | 1475 + third_party/heimdal/lib/krb5/krb5.h | 1073 + third_party/heimdal/lib/krb5/krb5.moduli | 3 + .../heimdal/lib/krb5/krb524_convert_creds_kdc.3 | 86 + .../heimdal/lib/krb5/krb5_425_conv_principal.3 | 224 + third_party/heimdal/lib/krb5/krb5_acl_match_file.3 | 111 + .../heimdal/lib/krb5/krb5_aname_to_localname.3 | 80 + third_party/heimdal/lib/krb5/krb5_appdefault.3 | 88 + third_party/heimdal/lib/krb5/krb5_auth_context.3 | 395 + .../heimdal/lib/krb5/krb5_c_make_checksum.3 | 297 + third_party/heimdal/lib/krb5/krb5_ccapi.h | 239 + .../heimdal/lib/krb5/krb5_check_transited.3 | 106 + .../heimdal/lib/krb5/krb5_create_checksum.3 | 226 + third_party/heimdal/lib/krb5/krb5_creds.3 | 119 + third_party/heimdal/lib/krb5/krb5_digest.3 | 260 + .../heimdal/lib/krb5/krb5_eai_to_heim_errno.3 | 68 + third_party/heimdal/lib/krb5/krb5_encrypt.3 | 278 + third_party/heimdal/lib/krb5/krb5_err.et | 317 + third_party/heimdal/lib/krb5/krb5_find_padata.3 | 87 + .../heimdal/lib/krb5/krb5_generate_random_block.3 | 57 + .../heimdal/lib/krb5/krb5_get_all_client_addrs.3 | 74 + .../heimdal/lib/krb5/krb5_get_credentials.3 | 181 + third_party/heimdal/lib/krb5/krb5_get_creds.3 | 173 + .../heimdal/lib/krb5/krb5_get_forwarded_creds.3 | 79 + third_party/heimdal/lib/krb5/krb5_get_in_cred.3 | 274 + third_party/heimdal/lib/krb5/krb5_get_init_creds.3 | 403 + third_party/heimdal/lib/krb5/krb5_get_krbhst.3 | 86 + third_party/heimdal/lib/krb5/krb5_getportbyname.3 | 67 + third_party/heimdal/lib/krb5/krb5_init_context.3 | 308 + third_party/heimdal/lib/krb5/krb5_is_thread_safe.3 | 58 + third_party/heimdal/lib/krb5/krb5_krbhst_init.3 | 174 + third_party/heimdal/lib/krb5/krb5_locl.h | 491 + third_party/heimdal/lib/krb5/krb5_mk_req.3 | 187 + third_party/heimdal/lib/krb5/krb5_mk_safe.3 | 82 + third_party/heimdal/lib/krb5/krb5_openlog.3 | 305 + third_party/heimdal/lib/krb5/krb5_parse_name.3 | 67 + third_party/heimdal/lib/krb5/krb5_principal.3 | 371 + third_party/heimdal/lib/krb5/krb5_rcache.3 | 163 + third_party/heimdal/lib/krb5/krb5_rd_error.3 | 98 + third_party/heimdal/lib/krb5/krb5_rd_safe.3 | 81 + .../heimdal/lib/krb5/krb5_set_default_realm.3 | 164 + third_party/heimdal/lib/krb5/krb5_set_password.3 | 143 + third_party/heimdal/lib/krb5/krb5_string_to_key.3 | 156 + third_party/heimdal/lib/krb5/krb5_timeofday.3 | 118 + .../heimdal/lib/krb5/krb5_verify_init_creds.3 | 103 + third_party/heimdal/lib/krb5/krb5_verify_user.3 | 241 + third_party/heimdal/lib/krb5/krb_err.et | 63 + third_party/heimdal/lib/krb5/krbhst-test.c | 109 + third_party/heimdal/lib/krb5/krbhst.c | 1282 + third_party/heimdal/lib/krb5/krcache.c | 2075 + third_party/heimdal/lib/krb5/kuserok.c | 753 + third_party/heimdal/lib/krb5/kuserok_plugin.h | 91 + third_party/heimdal/lib/krb5/kx509.c | 1323 + third_party/heimdal/lib/krb5/kx509_err.et | 39 + .../heimdal/lib/krb5/libkrb5-exports.def.in | 901 + third_party/heimdal/lib/krb5/locate_plugin.h | 81 + third_party/heimdal/lib/krb5/log.c | 252 + third_party/heimdal/lib/krb5/mcache.c | 623 + third_party/heimdal/lib/krb5/misc.c | 111 + third_party/heimdal/lib/krb5/mit_glue.c | 434 + third_party/heimdal/lib/krb5/mk_cred.c | 324 + third_party/heimdal/lib/krb5/mk_error.c | 117 + third_party/heimdal/lib/krb5/mk_priv.c | 151 + third_party/heimdal/lib/krb5/mk_rep.c | 119 + third_party/heimdal/lib/krb5/mk_req.c | 114 + third_party/heimdal/lib/krb5/mk_req_ext.c | 151 + third_party/heimdal/lib/krb5/mk_safe.c | 139 + third_party/heimdal/lib/krb5/n-fold-test.c | 119 + third_party/heimdal/lib/krb5/n-fold.c | 150 + third_party/heimdal/lib/krb5/net_read.c | 53 + third_party/heimdal/lib/krb5/net_write.c | 118 + third_party/heimdal/lib/krb5/pac.c | 2159 + third_party/heimdal/lib/krb5/padata.c | 62 + third_party/heimdal/lib/krb5/parse-name-test.c | 192 + third_party/heimdal/lib/krb5/pcache.c | 81 + third_party/heimdal/lib/krb5/pkinit-ec.c | 314 + third_party/heimdal/lib/krb5/pkinit.c | 2670 + third_party/heimdal/lib/krb5/plugin.c | 208 + third_party/heimdal/lib/krb5/principal.c | 2220 + third_party/heimdal/lib/krb5/prog_setup.c | 64 + third_party/heimdal/lib/krb5/prompter_posix.c | 72 + third_party/heimdal/lib/krb5/pseudo-random-test.c | 112 + third_party/heimdal/lib/krb5/rd_cred.c | 348 + third_party/heimdal/lib/krb5/rd_error.c | 125 + third_party/heimdal/lib/krb5/rd_priv.c | 184 + third_party/heimdal/lib/krb5/rd_rep.c | 121 + third_party/heimdal/lib/krb5/rd_req.c | 1107 + third_party/heimdal/lib/krb5/rd_safe.c | 214 + third_party/heimdal/lib/krb5/read_message.c | 104 + third_party/heimdal/lib/krb5/recvauth.c | 269 + third_party/heimdal/lib/krb5/replay.c | 328 + third_party/heimdal/lib/krb5/salt-aes-sha1.c | 102 + third_party/heimdal/lib/krb5/salt-aes-sha2.c | 136 + third_party/heimdal/lib/krb5/salt-arcfour.c | 107 + third_party/heimdal/lib/krb5/salt-des.c | 223 + third_party/heimdal/lib/krb5/salt-des3.c | 147 + third_party/heimdal/lib/krb5/salt.c | 362 + third_party/heimdal/lib/krb5/scache.c | 1602 + third_party/heimdal/lib/krb5/send_to_kdc.c | 1357 + third_party/heimdal/lib/krb5/send_to_kdc_plugin.h | 70 + third_party/heimdal/lib/krb5/sendauth.c | 257 + third_party/heimdal/lib/krb5/set_default_realm.c | 85 + third_party/heimdal/lib/krb5/sock_principal.c | 68 + third_party/heimdal/lib/krb5/sp800-108-kdf.c | 100 + third_party/heimdal/lib/krb5/store-int.c | 67 + third_party/heimdal/lib/krb5/store-int.h | 50 + third_party/heimdal/lib/krb5/store-test.c | 117 + third_party/heimdal/lib/krb5/store.c | 2058 + third_party/heimdal/lib/krb5/store_emem.c | 222 + third_party/heimdal/lib/krb5/store_fd.c | 200 + third_party/heimdal/lib/krb5/store_mem.c | 212 + third_party/heimdal/lib/krb5/store_sock.c | 163 + third_party/heimdal/lib/krb5/store_stdio.c | 271 + third_party/heimdal/lib/krb5/string-to-key-test.c | 140 + third_party/heimdal/lib/krb5/test_acl.c | 118 + third_party/heimdal/lib/krb5/test_addr.c | 239 + third_party/heimdal/lib/krb5/test_alname.c | 219 + third_party/heimdal/lib/krb5/test_ap-req.c | 228 + third_party/heimdal/lib/krb5/test_canon.c | 177 + third_party/heimdal/lib/krb5/test_cc.c | 1218 + third_party/heimdal/lib/krb5/test_config.c | 246 + .../heimdal/lib/krb5/test_config_strings.cfg | 12 + third_party/heimdal/lib/krb5/test_crypto.c | 216 + .../heimdal/lib/krb5/test_crypto_wrapping.c | 168 + third_party/heimdal/lib/krb5/test_expand_toks.c | 104 + third_party/heimdal/lib/krb5/test_forward.c | 134 + third_party/heimdal/lib/krb5/test_fx.c | 253 + third_party/heimdal/lib/krb5/test_get_addrs.c | 111 + third_party/heimdal/lib/krb5/test_gic.c | 148 + third_party/heimdal/lib/krb5/test_hostname.c | 150 + third_party/heimdal/lib/krb5/test_keytab.c | 291 + third_party/heimdal/lib/krb5/test_kuserok.c | 109 + third_party/heimdal/lib/krb5/test_mem.c | 71 + third_party/heimdal/lib/krb5/test_mkforwardable.c | 191 + third_party/heimdal/lib/krb5/test_pac.c | 1270 + third_party/heimdal/lib/krb5/test_pkinit_dh2key.c | 216 + third_party/heimdal/lib/krb5/test_pknistkdf.c | 373 + third_party/heimdal/lib/krb5/test_plugin.c | 131 + third_party/heimdal/lib/krb5/test_prf.c | 100 + third_party/heimdal/lib/krb5/test_princ.c | 365 + third_party/heimdal/lib/krb5/test_renew.c | 119 + third_party/heimdal/lib/krb5/test_rfc3961.c | 522 + third_party/heimdal/lib/krb5/test_set_kvno0.c | 182 + third_party/heimdal/lib/krb5/test_store.c | 364 + third_party/heimdal/lib/krb5/test_time.c | 85 + third_party/heimdal/lib/krb5/test_x500.c | 110 + third_party/heimdal/lib/krb5/ticket.c | 967 + third_party/heimdal/lib/krb5/time.c | 138 + third_party/heimdal/lib/krb5/transited.c | 699 + third_party/heimdal/lib/krb5/verify_init.c | 246 + .../heimdal/lib/krb5/verify_krb5_conf-version.rc | 36 + third_party/heimdal/lib/krb5/verify_krb5_conf.8 | 95 + third_party/heimdal/lib/krb5/verify_krb5_conf.c | 795 + third_party/heimdal/lib/krb5/verify_user.c | 258 + third_party/heimdal/lib/krb5/version-script.map | 892 + third_party/heimdal/lib/krb5/version.c | 39 + third_party/heimdal/lib/krb5/warn.c | 330 + third_party/heimdal/lib/krb5/write_message.c | 87 + third_party/heimdal/lib/libedit/COPYING | 30 + third_party/heimdal/lib/libedit/ChangeLog | 300 + third_party/heimdal/lib/libedit/INSTALL | 229 + third_party/heimdal/lib/libedit/Makefile.am | 9 + third_party/heimdal/lib/libedit/THANKS | 1 + third_party/heimdal/lib/libedit/acinclude.m4 | 66 + third_party/heimdal/lib/libedit/config.h.in | 282 + third_party/heimdal/lib/libedit/configure.ac | 111 + third_party/heimdal/lib/libedit/doc/Makefile.am | 33 + .../heimdal/lib/libedit/doc/editline.3.roff | 883 + third_party/heimdal/lib/libedit/doc/editrc.5.roff | 490 + third_party/heimdal/lib/libedit/doc/mdoc2man.awk | 459 + .../heimdal/lib/libedit/examples/Makefile.am | 14 + third_party/heimdal/lib/libedit/examples/fileman.c | 496 + third_party/heimdal/lib/libedit/examples/tc1.c | 309 + third_party/heimdal/lib/libedit/examples/wtc1.c | 269 + third_party/heimdal/lib/libedit/libedit.pc.in | 12 + third_party/heimdal/lib/libedit/src/Makefile.am | 43 + third_party/heimdal/lib/libedit/src/chared.c | 753 + third_party/heimdal/lib/libedit/src/chared.h | 155 + third_party/heimdal/lib/libedit/src/chartype.c | 340 + third_party/heimdal/lib/libedit/src/chartype.h | 114 + third_party/heimdal/lib/libedit/src/common.c | 835 + third_party/heimdal/lib/libedit/src/editline.3 | 997 + third_party/heimdal/lib/libedit/src/editline.7 | 935 + third_party/heimdal/lib/libedit/src/editrc.5 | 317 + third_party/heimdal/lib/libedit/src/el.c | 640 + third_party/heimdal/lib/libedit/src/el.h | 153 + third_party/heimdal/lib/libedit/src/eln.c | 388 + third_party/heimdal/lib/libedit/src/emacs.c | 512 + third_party/heimdal/lib/libedit/src/filecomplete.c | 573 + third_party/heimdal/lib/libedit/src/filecomplete.h | 44 + third_party/heimdal/lib/libedit/src/getline.c | 128 + third_party/heimdal/lib/libedit/src/hist.c | 245 + third_party/heimdal/lib/libedit/src/hist.h | 79 + third_party/heimdal/lib/libedit/src/histedit.h | 313 + third_party/heimdal/lib/libedit/src/history.c | 1157 + third_party/heimdal/lib/libedit/src/historyn.c | 3 + third_party/heimdal/lib/libedit/src/keymacro.c | 669 + third_party/heimdal/lib/libedit/src/keymacro.h | 76 + third_party/heimdal/lib/libedit/src/makelist | 177 + third_party/heimdal/lib/libedit/src/map.c | 1427 + third_party/heimdal/lib/libedit/src/map.h | 79 + third_party/heimdal/lib/libedit/src/parse.c | 289 + third_party/heimdal/lib/libedit/src/parse.h | 48 + third_party/heimdal/lib/libedit/src/prompt.c | 199 + third_party/heimdal/lib/libedit/src/prompt.h | 58 + third_party/heimdal/lib/libedit/src/read.c | 628 + third_party/heimdal/lib/libedit/src/read.h | 45 + third_party/heimdal/lib/libedit/src/readline.c | 2367 + .../heimdal/lib/libedit/src/readline/readline.h | 227 + third_party/heimdal/lib/libedit/src/refresh.c | 1187 + third_party/heimdal/lib/libedit/src/refresh.h | 57 + third_party/heimdal/lib/libedit/src/search.c | 641 + third_party/heimdal/lib/libedit/src/search.h | 64 + third_party/heimdal/lib/libedit/src/shlib_version | 5 + third_party/heimdal/lib/libedit/src/sig.c | 205 + third_party/heimdal/lib/libedit/src/sig.h | 70 + third_party/heimdal/lib/libedit/src/sys.h | 112 + third_party/heimdal/lib/libedit/src/terminal.c | 1691 + third_party/heimdal/lib/libedit/src/terminal.h | 125 + third_party/heimdal/lib/libedit/src/tokenizer.c | 466 + third_party/heimdal/lib/libedit/src/tokenizern.c | 3 + third_party/heimdal/lib/libedit/src/tty.c | 1342 + third_party/heimdal/lib/libedit/src/tty.h | 481 + third_party/heimdal/lib/libedit/src/unvis.c | 553 + third_party/heimdal/lib/libedit/src/vi.c | 1157 + third_party/heimdal/lib/libedit/src/vis.c | 728 + third_party/heimdal/lib/libedit/src/vis.h | 120 + third_party/heimdal/lib/libedit/src/wcsdup.c | 43 + third_party/heimdal/lib/ntlm/ChangeLog | 120 + third_party/heimdal/lib/ntlm/Makefile.am | 49 + third_party/heimdal/lib/ntlm/NTMakefile | 90 + third_party/heimdal/lib/ntlm/apop.c | 263 + third_party/heimdal/lib/ntlm/digest.c | 994 + third_party/heimdal/lib/ntlm/heim-auth.h | 135 + third_party/heimdal/lib/ntlm/heimntlm.h | 166 + .../heimdal/lib/ntlm/libheimntlm-exports.def | 24 + .../heimdal/lib/ntlm/libheimntlm-version.rc | 36 + third_party/heimdal/lib/ntlm/ntlm.c | 2030 + third_party/heimdal/lib/ntlm/ntlm_err.et | 60 + third_party/heimdal/lib/ntlm/test_commonauth.c | 425 + third_party/heimdal/lib/ntlm/test_ntlm.c | 617 + third_party/heimdal/lib/ntlm/version-script.map | 30 + third_party/heimdal/lib/otp/ChangeLog | 128 + third_party/heimdal/lib/otp/Makefile.am | 90 + third_party/heimdal/lib/otp/NTMakefile | 35 + third_party/heimdal/lib/otp/otp.c | 63 + third_party/heimdal/lib/otp/otp.h | 101 + third_party/heimdal/lib/otp/otp_challenge.c | 68 + third_party/heimdal/lib/otp/otp_db.c | 233 + third_party/heimdal/lib/otp/otp_locl.h | 70 + third_party/heimdal/lib/otp/otp_md.c | 231 + third_party/heimdal/lib/otp/otp_md.h | 46 + third_party/heimdal/lib/otp/otp_parse.c | 2522 + third_party/heimdal/lib/otp/otp_print.c | 99 + third_party/heimdal/lib/otp/otp_verify.c | 78 + third_party/heimdal/lib/otp/otptest.c | 142 + third_party/heimdal/lib/otp/roken_rename.h | 73 + third_party/heimdal/lib/otp/version-script.map | 25 + third_party/heimdal/lib/roken/ChangeLog | 2229 + third_party/heimdal/lib/roken/Makefile.am | 293 + third_party/heimdal/lib/roken/NTMakefile | 312 + third_party/heimdal/lib/roken/base32-test.c | 106 + third_party/heimdal/lib/roken/base32.c | 313 + third_party/heimdal/lib/roken/base32.h | 61 + third_party/heimdal/lib/roken/base64-test.c | 97 + third_party/heimdal/lib/roken/base64.c | 270 + third_party/heimdal/lib/roken/base64.h | 55 + third_party/heimdal/lib/roken/bswap.c | 74 + third_party/heimdal/lib/roken/chown.c | 42 + third_party/heimdal/lib/roken/cloexec.c | 75 + third_party/heimdal/lib/roken/closefrom.c | 57 + third_party/heimdal/lib/roken/clz.c | 69 + third_party/heimdal/lib/roken/concat.c | 110 + third_party/heimdal/lib/roken/copyhostent.c | 98 + third_party/heimdal/lib/roken/ct.c | 82 + third_party/heimdal/lib/roken/daemon.c | 80 + third_party/heimdal/lib/roken/detach.c | 226 + third_party/heimdal/lib/roken/dirent-test.c | 278 + third_party/heimdal/lib/roken/dirent.c | 235 + third_party/heimdal/lib/roken/dirent.hin | 66 + third_party/heimdal/lib/roken/dlfcn.hin | 109 + third_party/heimdal/lib/roken/dlfcn_w32.c | 700 + third_party/heimdal/lib/roken/doxygen.c | 44 + third_party/heimdal/lib/roken/dumpdata.c | 249 + third_party/heimdal/lib/roken/ecalloc.3 | 84 + third_party/heimdal/lib/roken/ecalloc.c | 53 + third_party/heimdal/lib/roken/emalloc.c | 53 + third_party/heimdal/lib/roken/environment.c | 162 + third_party/heimdal/lib/roken/eread.c | 51 + third_party/heimdal/lib/roken/erealloc.c | 53 + third_party/heimdal/lib/roken/err.c | 46 + third_party/heimdal/lib/roken/err.hin | 99 + third_party/heimdal/lib/roken/errx.c | 45 + third_party/heimdal/lib/roken/esetenv.c | 45 + third_party/heimdal/lib/roken/estrdup.c | 53 + third_party/heimdal/lib/roken/ewrite.c | 51 + third_party/heimdal/lib/roken/fchown.c | 42 + third_party/heimdal/lib/roken/flock.c | 154 + third_party/heimdal/lib/roken/fnmatch.c | 175 + third_party/heimdal/lib/roken/fnmatch.hin | 66 + third_party/heimdal/lib/roken/freeaddrinfo.c | 54 + third_party/heimdal/lib/roken/freehostent.c | 59 + third_party/heimdal/lib/roken/fseeko.c | 48 + third_party/heimdal/lib/roken/ftello.c | 48 + third_party/heimdal/lib/roken/gai_strerror.c | 74 + third_party/heimdal/lib/roken/get_window_size.c | 132 + third_party/heimdal/lib/roken/getaddrinfo-test.c | 151 + third_party/heimdal/lib/roken/getaddrinfo.c | 414 + .../heimdal/lib/roken/getaddrinfo_hostspec.c | 101 + third_party/heimdal/lib/roken/getarg.3 | 341 + third_party/heimdal/lib/roken/getarg.c | 607 + third_party/heimdal/lib/roken/getarg.h | 112 + third_party/heimdal/lib/roken/getauxval.c | 263 + third_party/heimdal/lib/roken/getauxval.h | 176 + third_party/heimdal/lib/roken/getcwd.c | 54 + third_party/heimdal/lib/roken/getdtablesize.c | 99 + third_party/heimdal/lib/roken/getegid.c | 46 + third_party/heimdal/lib/roken/geteuid.c | 46 + third_party/heimdal/lib/roken/getgid.c | 45 + third_party/heimdal/lib/roken/gethostname.c | 70 + third_party/heimdal/lib/roken/getifaddrs-test.c | 137 + third_party/heimdal/lib/roken/getifaddrs.c | 1314 + third_party/heimdal/lib/roken/getifaddrs_w32.c | 161 + third_party/heimdal/lib/roken/getipnodebyaddr.c | 71 + third_party/heimdal/lib/roken/getipnodebyname.c | 83 + third_party/heimdal/lib/roken/getnameinfo.c | 124 + .../heimdal/lib/roken/getnameinfo_verified.c | 94 + third_party/heimdal/lib/roken/getopt.c | 124 + third_party/heimdal/lib/roken/getprogname.c | 48 + third_party/heimdal/lib/roken/gettimeofday.c | 94 + third_party/heimdal/lib/roken/getuid.c | 45 + third_party/heimdal/lib/roken/getuserinfo.c | 334 + third_party/heimdal/lib/roken/getusershell.c | 185 + third_party/heimdal/lib/roken/h_errno.c | 38 + third_party/heimdal/lib/roken/hex-test.c | 115 + third_party/heimdal/lib/roken/hex.c | 108 + third_party/heimdal/lib/roken/hex.h | 57 + third_party/heimdal/lib/roken/hostent_find_fqdn.c | 56 + third_party/heimdal/lib/roken/hstrerror.c | 78 + third_party/heimdal/lib/roken/ifaddrs.hin | 79 + third_party/heimdal/lib/roken/inet_aton.c | 46 + third_party/heimdal/lib/roken/inet_ntop.c | 151 + third_party/heimdal/lib/roken/inet_pton.c | 116 + third_party/heimdal/lib/roken/initgroups.c | 42 + third_party/heimdal/lib/roken/innetgr.c | 45 + third_party/heimdal/lib/roken/install-sh | 251 + third_party/heimdal/lib/roken/issuid.c | 278 + third_party/heimdal/lib/roken/localtime_r.c | 60 + third_party/heimdal/lib/roken/lstat.c | 42 + third_party/heimdal/lib/roken/memmem.c | 72 + third_party/heimdal/lib/roken/memmove.c | 62 + third_party/heimdal/lib/roken/memset_s.c | 51 + third_party/heimdal/lib/roken/mergesort.c | 50 + third_party/heimdal/lib/roken/mergesort_r.c | 338 + third_party/heimdal/lib/roken/mini_inetd.c | 197 + third_party/heimdal/lib/roken/missing | 190 + third_party/heimdal/lib/roken/mkdir.c | 53 + third_party/heimdal/lib/roken/mkdtemp.c | 86 + third_party/heimdal/lib/roken/mkinstalldirs | 40 + third_party/heimdal/lib/roken/mkostemp.c | 87 + third_party/heimdal/lib/roken/mkstemp.c | 82 + third_party/heimdal/lib/roken/ndbm_wrap.c | 227 + third_party/heimdal/lib/roken/ndbm_wrap.h | 93 + third_party/heimdal/lib/roken/net_read.c | 118 + third_party/heimdal/lib/roken/net_write.c | 134 + third_party/heimdal/lib/roken/parse_bytes-test.c | 89 + third_party/heimdal/lib/roken/parse_bytes.c | 81 + third_party/heimdal/lib/roken/parse_bytes.h | 50 + third_party/heimdal/lib/roken/parse_reply-test.c | 126 + third_party/heimdal/lib/roken/parse_time-test.c | 119 + third_party/heimdal/lib/roken/parse_time.3 | 173 + third_party/heimdal/lib/roken/parse_time.c | 104 + third_party/heimdal/lib/roken/parse_time.h | 72 + third_party/heimdal/lib/roken/parse_units.c | 524 + third_party/heimdal/lib/roken/parse_units.h | 116 + third_party/heimdal/lib/roken/putenv.c | 79 + third_party/heimdal/lib/roken/qsort.c | 201 + third_party/heimdal/lib/roken/rand.c | 74 + third_party/heimdal/lib/roken/rcmd.c | 49 + third_party/heimdal/lib/roken/readv.c | 64 + third_party/heimdal/lib/roken/realloc.c | 47 + third_party/heimdal/lib/roken/recvmsg.c | 66 + third_party/heimdal/lib/roken/rename.c | 49 + third_party/heimdal/lib/roken/resolve-test.c | 309 + third_party/heimdal/lib/roken/resolve.c | 956 + third_party/heimdal/lib/roken/resolve.h | 251 + third_party/heimdal/lib/roken/rkpty.c | 392 + third_party/heimdal/lib/roken/roken-common.h | 569 + third_party/heimdal/lib/roken/roken.awk | 54 + third_party/heimdal/lib/roken/roken.h.in | 1394 + third_party/heimdal/lib/roken/roken_gethostby.c | 292 + third_party/heimdal/lib/roken/rtbl.3 | 201 + third_party/heimdal/lib/roken/rtbl.c | 558 + third_party/heimdal/lib/roken/rtbl.h | 124 + third_party/heimdal/lib/roken/search.hin | 44 + third_party/heimdal/lib/roken/secure_getenv.c | 47 + third_party/heimdal/lib/roken/secure_getenv.h | 42 + third_party/heimdal/lib/roken/sendmsg.c | 148 + third_party/heimdal/lib/roken/setegid.c | 54 + third_party/heimdal/lib/roken/setenv.c | 74 + third_party/heimdal/lib/roken/seteuid.c | 54 + third_party/heimdal/lib/roken/setprogname.c | 91 + third_party/heimdal/lib/roken/signal.c | 77 + third_party/heimdal/lib/roken/simple_exec.c | 325 + third_party/heimdal/lib/roken/simple_exec_w32.c | 431 + third_party/heimdal/lib/roken/sleep.c | 55 + third_party/heimdal/lib/roken/snprintf-test.c | 268 + third_party/heimdal/lib/roken/snprintf.c | 729 + third_party/heimdal/lib/roken/socket.c | 372 + third_party/heimdal/lib/roken/socket_wrapper.c | 1911 + third_party/heimdal/lib/roken/socket_wrapper.h | 146 + third_party/heimdal/lib/roken/sockstartup_w32.c | 75 + third_party/heimdal/lib/roken/stdbool.hin | 13 + third_party/heimdal/lib/roken/stdint.hin | 43 + third_party/heimdal/lib/roken/strcasecmp.c | 55 + third_party/heimdal/lib/roken/strcollect.c | 93 + third_party/heimdal/lib/roken/strdup.c | 47 + third_party/heimdal/lib/roken/strerror.c | 54 + third_party/heimdal/lib/roken/strerror_r.c | 84 + third_party/heimdal/lib/roken/strftime.c | 402 + third_party/heimdal/lib/roken/strlcat.c | 60 + third_party/heimdal/lib/roken/strlcpy.c | 73 + third_party/heimdal/lib/roken/strlwr.c | 50 + third_party/heimdal/lib/roken/strncasecmp.c | 59 + third_party/heimdal/lib/roken/strndup.c | 53 + third_party/heimdal/lib/roken/strnlen.c | 46 + third_party/heimdal/lib/roken/strpftime-test.c | 295 + third_party/heimdal/lib/roken/strpftime-test.h | 61 + third_party/heimdal/lib/roken/strpool.c | 114 + third_party/heimdal/lib/roken/strptime.c | 449 + third_party/heimdal/lib/roken/strsep.c | 58 + third_party/heimdal/lib/roken/strsep_copy.c | 66 + third_party/heimdal/lib/roken/strtok_r.c | 62 + third_party/heimdal/lib/roken/strtoll.c | 155 + third_party/heimdal/lib/roken/strtoull.c | 129 + third_party/heimdal/lib/roken/strupr.c | 50 + third_party/heimdal/lib/roken/swab.c | 50 + third_party/heimdal/lib/roken/syslog.hin | 248 + third_party/heimdal/lib/roken/syslogc.c | 339 + third_party/heimdal/lib/roken/test-auxval.c | 235 + third_party/heimdal/lib/roken/test-detach.c | 100 + third_party/heimdal/lib/roken/test-getuserinfo.c | 136 + third_party/heimdal/lib/roken/test-mem.c | 215 + third_party/heimdal/lib/roken/test-mem.h | 39 + third_party/heimdal/lib/roken/test-mini_inetd.c | 371 + third_party/heimdal/lib/roken/test-readenv.c | 115 + third_party/heimdal/lib/roken/timegm.c | 85 + third_party/heimdal/lib/roken/timeval.c | 286 + third_party/heimdal/lib/roken/tm2time.c | 58 + third_party/heimdal/lib/roken/tsearch-test.c | 125 + third_party/heimdal/lib/roken/tsearch.c | 175 + third_party/heimdal/lib/roken/unsetenv.c | 69 + third_party/heimdal/lib/roken/unvis.c | 283 + third_party/heimdal/lib/roken/verr.c | 44 + third_party/heimdal/lib/roken/verrx.c | 44 + third_party/heimdal/lib/roken/version-script.map | 241 + third_party/heimdal/lib/roken/versionsupport.h | 139 + third_party/heimdal/lib/roken/vis-extras.h | 27 + third_party/heimdal/lib/roken/vis.c | 649 + third_party/heimdal/lib/roken/vis.hin | 170 + third_party/heimdal/lib/roken/vsyslog.c | 113 + third_party/heimdal/lib/roken/vwarn.c | 43 + third_party/heimdal/lib/roken/vwarnx.c | 44 + third_party/heimdal/lib/roken/warn.c | 46 + third_party/heimdal/lib/roken/warnerr.c | 58 + third_party/heimdal/lib/roken/warnx.c | 45 + third_party/heimdal/lib/roken/win32_alloc.c | 76 + third_party/heimdal/lib/roken/win32_version.c | 128 + third_party/heimdal/lib/roken/write_pid.c | 129 + third_party/heimdal/lib/roken/writev.c | 61 + third_party/heimdal/lib/roken/xdbm.h | 52 + third_party/heimdal/lib/roken/xfree.c | 42 + third_party/heimdal/lib/sl/ChangeLog | 329 + third_party/heimdal/lib/sl/Makefile.am | 50 + third_party/heimdal/lib/sl/NTMakefile | 74 + third_party/heimdal/lib/sl/roken_rename.h | 67 + third_party/heimdal/lib/sl/sl.c | 528 + third_party/heimdal/lib/sl/sl.h | 71 + third_party/heimdal/lib/sl/sl_locl.h | 45 + third_party/heimdal/lib/sl/slc-gram.y | 791 + third_party/heimdal/lib/sl/slc-lex.l | 158 + third_party/heimdal/lib/sl/slc.h | 56 + third_party/heimdal/lib/sl/test_sl.c | 98 + third_party/heimdal/lib/sqlite/Makefile.am | 20 + third_party/heimdal/lib/sqlite/NTMakefile | 52 + third_party/heimdal/lib/sqlite/README | 25 + third_party/heimdal/lib/sqlite/sqlite3.c | 231382 ++++++++++++++++++ third_party/heimdal/lib/sqlite/sqlite3.h | 12229 + third_party/heimdal/lib/sqlite/sqlite3ext.h | 659 + third_party/heimdal/lib/vers/ChangeLog | 74 + third_party/heimdal/lib/vers/Makefile.am | 13 + third_party/heimdal/lib/vers/NTMakefile | 56 + third_party/heimdal/lib/vers/make-print-version.c | 66 + third_party/heimdal/lib/vers/print_version.c | 59 + third_party/heimdal/lib/vers/vers.h | 41 + third_party/heimdal/lib/wind/ChangeLog | 136 + .../lib/wind/CompositionExclusions-3.2.0.txt | 176 + .../heimdal/lib/wind/DerivedNormalizationProps.txt | 2574 + third_party/heimdal/lib/wind/Makefile.am | 147 + third_party/heimdal/lib/wind/NTMakefile | 159 + .../heimdal/lib/wind/NormalizationCorrections.txt | 43 + third_party/heimdal/lib/wind/NormalizationTest.txt | 17166 ++ third_party/heimdal/lib/wind/UnicodeData.py | 57 + third_party/heimdal/lib/wind/UnicodeData.txt | 15100 ++ third_party/heimdal/lib/wind/bidi.c | 92 + third_party/heimdal/lib/wind/combining.c | 62 + third_party/heimdal/lib/wind/doxygen.c | 47 + third_party/heimdal/lib/wind/errorlist.c | 77 + third_party/heimdal/lib/wind/gen-bidi.py | 102 + third_party/heimdal/lib/wind/gen-combining.py | 104 + third_party/heimdal/lib/wind/gen-errorlist.py | 121 + third_party/heimdal/lib/wind/gen-map.py | 158 + third_party/heimdal/lib/wind/gen-normalize.py | 211 + .../heimdal/lib/wind/gen-punycode-examples.py | 130 + third_party/heimdal/lib/wind/generate.py | 86 + third_party/heimdal/lib/wind/idn-lookup.c | 167 + third_party/heimdal/lib/wind/ldap.c | 91 + third_party/heimdal/lib/wind/libwind-exports.def | 27 + third_party/heimdal/lib/wind/map.c | 85 + third_party/heimdal/lib/wind/normalize.c | 325 + third_party/heimdal/lib/wind/punycode.c | 168 + third_party/heimdal/lib/wind/rfc3454.py | 60 + third_party/heimdal/lib/wind/rfc4518.py | 150 + third_party/heimdal/lib/wind/stringprep.c | 145 + third_party/heimdal/lib/wind/stringprep.py | 92 + third_party/heimdal/lib/wind/test-bidi.c | 81 + third_party/heimdal/lib/wind/test-ldap.c | 128 + third_party/heimdal/lib/wind/test-map.c | 98 + third_party/heimdal/lib/wind/test-normalize.c | 179 + third_party/heimdal/lib/wind/test-prohibited.c | 138 + third_party/heimdal/lib/wind/test-punycode.c | 83 + third_party/heimdal/lib/wind/test-rw.c | 186 + third_party/heimdal/lib/wind/test-utf8.c | 174 + third_party/heimdal/lib/wind/utf8.c | 591 + third_party/heimdal/lib/wind/util.py | 48 + third_party/heimdal/lib/wind/version-script.map | 29 + third_party/heimdal/lib/wind/wind.h | 86 + third_party/heimdal/lib/wind/wind_err.et | 23 + third_party/heimdal/lib/wind/windlocl.h | 67 + 1753 files changed, 740505 insertions(+) create mode 100644 third_party/heimdal/lib/Makefile.am create mode 100644 third_party/heimdal/lib/NTMakefile create mode 100644 third_party/heimdal/lib/asn1/ChangeLog create mode 100644 third_party/heimdal/lib/asn1/MANUAL.md create mode 100644 third_party/heimdal/lib/asn1/Makefile.am create mode 100644 third_party/heimdal/lib/asn1/NTMakefile create mode 100644 third_party/heimdal/lib/asn1/README-X681.md create mode 100644 third_party/heimdal/lib/asn1/README-template.md create mode 100644 third_party/heimdal/lib/asn1/README.md create mode 100644 third_party/heimdal/lib/asn1/asn1-common.h create mode 100644 third_party/heimdal/lib/asn1/asn1-template.h create mode 100644 third_party/heimdal/lib/asn1/asn1_compile-version.rc create mode 100644 third_party/heimdal/lib/asn1/asn1_compile.1 create mode 100644 third_party/heimdal/lib/asn1/asn1_err.et create mode 100644 third_party/heimdal/lib/asn1/asn1_gen.c create mode 100644 third_party/heimdal/lib/asn1/asn1_print.1 create mode 100644 third_party/heimdal/lib/asn1/asn1_print.c create mode 100644 third_party/heimdal/lib/asn1/asn1parse.y create mode 100644 third_party/heimdal/lib/asn1/canthandle.asn1 create mode 100644 third_party/heimdal/lib/asn1/check-ber.c create mode 100644 third_party/heimdal/lib/asn1/check-common.c create mode 100644 third_party/heimdal/lib/asn1/check-common.h create mode 100644 third_party/heimdal/lib/asn1/check-der.c create mode 100644 third_party/heimdal/lib/asn1/check-gen.c create mode 100644 third_party/heimdal/lib/asn1/check-gen.h create mode 100644 third_party/heimdal/lib/asn1/check-template.c create mode 100644 third_party/heimdal/lib/asn1/check-timegm.c create mode 100644 third_party/heimdal/lib/asn1/cms.asn1 create mode 100644 third_party/heimdal/lib/asn1/cms.opt create mode 100644 third_party/heimdal/lib/asn1/crmf.asn1 create mode 100644 third_party/heimdal/lib/asn1/crmf.opt create mode 100644 third_party/heimdal/lib/asn1/der.c create mode 100644 third_party/heimdal/lib/asn1/der.h create mode 100644 third_party/heimdal/lib/asn1/der_cmp.c create mode 100644 third_party/heimdal/lib/asn1/der_copy.c create mode 100644 third_party/heimdal/lib/asn1/der_format.c create mode 100644 third_party/heimdal/lib/asn1/der_free.c create mode 100644 third_party/heimdal/lib/asn1/der_get.c create mode 100644 third_party/heimdal/lib/asn1/der_length.c create mode 100644 third_party/heimdal/lib/asn1/der_locl.h create mode 100644 third_party/heimdal/lib/asn1/der_print.c create mode 100644 third_party/heimdal/lib/asn1/der_put.c create mode 100644 third_party/heimdal/lib/asn1/digest.asn1 create mode 100644 third_party/heimdal/lib/asn1/extra.c create mode 100644 third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq create mode 100644 third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt create mode 100644 third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der create mode 100644 third_party/heimdal/lib/asn1/fuzzer.c create mode 100644 third_party/heimdal/lib/asn1/gen.c create mode 100644 third_party/heimdal/lib/asn1/gen_copy.c create mode 100644 third_party/heimdal/lib/asn1/gen_decode.c create mode 100644 third_party/heimdal/lib/asn1/gen_encode.c create mode 100644 third_party/heimdal/lib/asn1/gen_free.c create mode 100644 third_party/heimdal/lib/asn1/gen_glue.c create mode 100644 third_party/heimdal/lib/asn1/gen_length.c create mode 100644 third_party/heimdal/lib/asn1/gen_locl.h create mode 100644 third_party/heimdal/lib/asn1/gen_print.c create mode 100644 third_party/heimdal/lib/asn1/gen_seq.c create mode 100644 third_party/heimdal/lib/asn1/gen_template.c create mode 100644 third_party/heimdal/lib/asn1/hash.c create mode 100644 third_party/heimdal/lib/asn1/hash.h create mode 100644 third_party/heimdal/lib/asn1/heim_asn1.h create mode 100644 third_party/heimdal/lib/asn1/krb5.asn1 create mode 100644 third_party/heimdal/lib/asn1/krb5.opt create mode 100644 third_party/heimdal/lib/asn1/kx509.asn1 create mode 100644 third_party/heimdal/lib/asn1/lex.h create mode 100644 third_party/heimdal/lib/asn1/lex.l create mode 100644 third_party/heimdal/lib/asn1/libasn1-exports.def create mode 100644 third_party/heimdal/lib/asn1/main.c create mode 100644 third_party/heimdal/lib/asn1/ocsp.asn1 create mode 100644 third_party/heimdal/lib/asn1/ocsp.opt create mode 100644 third_party/heimdal/lib/asn1/oid_resolution.c create mode 100644 third_party/heimdal/lib/asn1/pkcs10.asn1 create mode 100644 third_party/heimdal/lib/asn1/pkcs10.opt create mode 100644 third_party/heimdal/lib/asn1/pkcs12.asn1 create mode 100644 third_party/heimdal/lib/asn1/pkcs8.asn1 create mode 100644 third_party/heimdal/lib/asn1/pkcs9.asn1 create mode 100644 third_party/heimdal/lib/asn1/pkinit.asn1 create mode 100644 third_party/heimdal/lib/asn1/pku2u.asn1 create mode 100644 third_party/heimdal/lib/asn1/rfc2459.asn1 create mode 100644 third_party/heimdal/lib/asn1/rfc2459.opt create mode 100644 third_party/heimdal/lib/asn1/rfc4108.asn1 create mode 100644 third_party/heimdal/lib/asn1/roken_rename.h create mode 100644 third_party/heimdal/lib/asn1/setchgpw2.asn1 create mode 100644 third_party/heimdal/lib/asn1/symbol.c create mode 100644 third_party/heimdal/lib/asn1/symbol.h create mode 100644 third_party/heimdal/lib/asn1/tcg.asn1 create mode 100644 third_party/heimdal/lib/asn1/template.c create mode 100644 third_party/heimdal/lib/asn1/test.asn1 create mode 100644 third_party/heimdal/lib/asn1/test.gen create mode 100644 third_party/heimdal/lib/asn1/test.opt create mode 100644 third_party/heimdal/lib/asn1/timegm.c create mode 100644 third_party/heimdal/lib/asn1/version-script.map create mode 100644 third_party/heimdal/lib/asn1/x690sample.asn1 create mode 100644 third_party/heimdal/lib/base/Makefile.am create mode 100644 third_party/heimdal/lib/base/NTMakefile create mode 100644 third_party/heimdal/lib/base/array.c create mode 100644 third_party/heimdal/lib/base/baselocl.h create mode 100644 third_party/heimdal/lib/base/bool.c create mode 100644 third_party/heimdal/lib/base/bsearch.c create mode 100644 third_party/heimdal/lib/base/common_plugin.h create mode 100644 third_party/heimdal/lib/base/config_file.c create mode 100644 third_party/heimdal/lib/base/config_reg.c create mode 100644 third_party/heimdal/lib/base/context.c create mode 100644 third_party/heimdal/lib/base/data.c create mode 100644 third_party/heimdal/lib/base/db.c create mode 100644 third_party/heimdal/lib/base/dict.c create mode 100644 third_party/heimdal/lib/base/dll.c create mode 100644 third_party/heimdal/lib/base/error.c create mode 100644 third_party/heimdal/lib/base/error_string.c create mode 100644 third_party/heimdal/lib/base/expand_path.c create mode 100644 third_party/heimdal/lib/base/heim_err.et create mode 100644 third_party/heimdal/lib/base/heimbase-atomics.h create mode 100644 third_party/heimdal/lib/base/heimbase-svc.h create mode 100644 third_party/heimdal/lib/base/heimbase.c create mode 100644 third_party/heimdal/lib/base/heimbase.h create mode 100644 third_party/heimdal/lib/base/heimbasepriv.h create mode 100644 third_party/heimdal/lib/base/json.c create mode 100644 third_party/heimdal/lib/base/log.c create mode 100644 third_party/heimdal/lib/base/null.c create mode 100644 third_party/heimdal/lib/base/number.c create mode 100644 third_party/heimdal/lib/base/plugin.c create mode 100644 third_party/heimdal/lib/base/roken_rename.h create mode 100644 third_party/heimdal/lib/base/string.c create mode 100644 third_party/heimdal/lib/base/test_base.c create mode 100644 third_party/heimdal/lib/base/version-script.map create mode 100644 third_party/heimdal/lib/base/warn.c create mode 100644 third_party/heimdal/lib/com_err/ChangeLog create mode 100644 third_party/heimdal/lib/com_err/Makefile.am create mode 100644 third_party/heimdal/lib/com_err/NTMakefile create mode 100644 third_party/heimdal/lib/com_err/com_err.3 create mode 100644 third_party/heimdal/lib/com_err/com_err.c create mode 100644 third_party/heimdal/lib/com_err/com_err.h create mode 100644 third_party/heimdal/lib/com_err/com_right.h create mode 100644 third_party/heimdal/lib/com_err/compile_et-version.rc create mode 100644 third_party/heimdal/lib/com_err/compile_et.c create mode 100644 third_party/heimdal/lib/com_err/compile_et.h create mode 100644 third_party/heimdal/lib/com_err/error.c create mode 100644 third_party/heimdal/lib/com_err/lex.h create mode 100644 third_party/heimdal/lib/com_err/lex.l create mode 100644 third_party/heimdal/lib/com_err/libcom_err-exports.def create mode 100644 third_party/heimdal/lib/com_err/libcom_err-version.rc create mode 100644 third_party/heimdal/lib/com_err/parse.y create mode 100644 third_party/heimdal/lib/com_err/roken_rename.h create mode 100644 third_party/heimdal/lib/com_err/version-script.map create mode 100644 third_party/heimdal/lib/gss_preauth/Makefile.am create mode 100644 third_party/heimdal/lib/gss_preauth/NTMakefile create mode 100644 third_party/heimdal/lib/gss_preauth/README.md create mode 100644 third_party/heimdal/lib/gss_preauth/pa_client.c create mode 100644 third_party/heimdal/lib/gss_preauth/pa_common.c create mode 100644 third_party/heimdal/lib/gssapi/ChangeLog create mode 100644 third_party/heimdal/lib/gssapi/Makefile.am create mode 100644 third_party/heimdal/lib/gssapi/NTMakefile create mode 100644 third_party/heimdal/lib/gssapi/gen-oid.pl create mode 100644 third_party/heimdal/lib/gssapi/gss-commands.in create mode 100644 third_party/heimdal/lib/gssapi/gss-token.1 create mode 100644 third_party/heimdal/lib/gssapi/gss-token.c create mode 100644 third_party/heimdal/lib/gssapi/gss_acquire_cred.3 create mode 100644 third_party/heimdal/lib/gssapi/gssapi.3 create mode 100644 third_party/heimdal/lib/gssapi/gssapi.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi_netlogon.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi_ntlm.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi_oid.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi/gssapi_spnego.h create mode 100644 third_party/heimdal/lib/gssapi/gssapi_mech.h create mode 100644 third_party/heimdal/lib/gssapi/gsstool.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/8003.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/add_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/aeap.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/arcfour.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/authorize_localname.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/ccache_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/cfx.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/cfx.h create mode 100644 third_party/heimdal/lib/gssapi/krb5/compare_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/compat.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/context_time.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/copy_ccache.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/creds.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/decapsulate.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/display_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/display_status.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/duplicate_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/encapsulate.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/export_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/export_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/external.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/get_mic.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et create mode 100644 third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h create mode 100644 third_party/heimdal/lib/gssapi/krb5/import_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/import_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/init.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_context.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/name_attrs.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/prf.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/process_context_token.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/release_buffer.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/release_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/release_name.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/sequence.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/set_cred_option.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/store_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_cfx.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_cred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_kcred.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_oid.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/test_sequence.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/ticket_flags.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/unwrap.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/verify_mic.c create mode 100644 third_party/heimdal/lib/gssapi/krb5/wrap.c create mode 100644 third_party/heimdal/lib/gssapi/libgssapi-exports.def create mode 100644 third_party/heimdal/lib/gssapi/libgssapi-version.rc create mode 100644 third_party/heimdal/lib/gssapi/mech/compat.h create mode 100644 third_party/heimdal/lib/gssapi/mech/context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/context.h create mode 100644 third_party/heimdal/lib/gssapi/mech/cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/cred.h create mode 100644 third_party/heimdal/lib/gssapi/mech/doxygen.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_with_password.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_add_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_add_cred_from.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_add_cred_with_password.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_add_oid_set_member.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_aeap.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_authorize_localname.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_buffer_set.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_canonicalize_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_compare_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_context_time.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_create_empty_oid_set.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_decapsulate_token.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_delete_name_attribute.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_delete_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_destroy_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_display_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_display_name_ext.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_display_status.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_duplicate_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_duplicate_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid_set.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_encapsulate_token.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_export_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_export_name_composite.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_get_mic.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_get_name_attribute.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_get_neg_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_import_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_indicate_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_context.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_mechs_for_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_names_for_mech.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_krb5.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_mo.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_names.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_oid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_oid_equal.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_oid_to_str.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_process_context_token.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_pseudo_random.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_release_buffer.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_release_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_release_name.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_release_oid.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_release_oid_set.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_rfc4121.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_seal.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_set_cred_option.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_set_name_attribute.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_set_neg_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_set_sec_context_option.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_sign.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_store_cred.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_store_cred_into.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_test_oid_set_member.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_unseal.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_unwrap.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_utils.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_verify.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_verify_mic.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_wrap.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gssapi.asn1 create mode 100644 third_party/heimdal/lib/gssapi/mech/gssspi_exchange_meta_data.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gssspi_query_mechanism_info.c create mode 100644 third_party/heimdal/lib/gssapi/mech/gssspi_query_meta_data.c create mode 100644 third_party/heimdal/lib/gssapi/mech/mech.5 create mode 100644 third_party/heimdal/lib/gssapi/mech/mech_locl.h create mode 100644 third_party/heimdal/lib/gssapi/mech/mech_switch.h create mode 100644 third_party/heimdal/lib/gssapi/mech/name.h create mode 100644 third_party/heimdal/lib/gssapi/mech/utils.h create mode 100644 third_party/heimdal/lib/gssapi/netlogon/accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/add_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/canonicalize_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/compare_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/context_time.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/crypto.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/delete_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/display_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/display_status.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/duplicate_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/duplicate_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/export_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/export_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/external.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/import_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/import_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/indicate_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/inquire_context.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/inquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/inquire_cred_by_mech.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/inquire_mechs_for_name.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/inquire_names_for_mech.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/iter_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/netlogon.h create mode 100644 third_party/heimdal/lib/gssapi/netlogon/process_context_token.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/regen.sh create mode 100644 third_party/heimdal/lib/gssapi/netlogon/release_cred.c create mode 100644 third_party/heimdal/lib/gssapi/netlogon/release_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/add_cred.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/canonicalize_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/compare_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/context_time.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/creds.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/crypto.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/display_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/display_status.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/duplicate_cred.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/duplicate_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/export_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/export_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/external.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/import_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/import_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/indicate_mechs.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/inquire_context.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/inquire_cred_by_mech.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/inquire_mechs_for_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/inquire_names_for_mech.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/inquire_sec_context_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/iter_cred.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/kdc.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/ntlm.h create mode 100644 third_party/heimdal/lib/gssapi/ntlm/process_context_token.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/release_cred.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/release_name.c create mode 100644 third_party/heimdal/lib/gssapi/ntlm/set_sec_context_option.c create mode 100644 third_party/heimdal/lib/gssapi/oid.txt create mode 100644 third_party/heimdal/lib/gssapi/sanon/accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/add_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/canonicalize_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/compare_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/context_time.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/crypto.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/delete_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/display_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/display_status.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/duplicate_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/duplicate_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/export_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/export_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/export_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/external.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/import_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/import_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/import_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_context.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_cred_by_mech.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_mechs_for_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_names_for_mech.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/inquire_sec_context_by_oid.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/negoex.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/process_context_token.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/release_cred.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/release_name.c create mode 100644 third_party/heimdal/lib/gssapi/sanon/sanon_locl.h create mode 100644 third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/compat.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/context_storage.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/context_stubs.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/external.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/init_sec_context.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/negoex_err.et create mode 100644 third_party/heimdal/lib/gssapi/spnego/negoex_locl.h create mode 100644 third_party/heimdal/lib/gssapi/spnego/negoex_util.c create mode 100644 third_party/heimdal/lib/gssapi/spnego/spnego.asn1 create mode 100644 third_party/heimdal/lib/gssapi/spnego/spnego.opt create mode 100644 third_party/heimdal/lib/gssapi/spnego/spnego_locl.h create mode 100644 third_party/heimdal/lib/gssapi/test_acquire_cred.c create mode 100644 third_party/heimdal/lib/gssapi/test_add_store_cred.c create mode 100644 third_party/heimdal/lib/gssapi/test_common.c create mode 100644 third_party/heimdal/lib/gssapi/test_common.h create mode 100644 third_party/heimdal/lib/gssapi/test_context.c create mode 100644 third_party/heimdal/lib/gssapi/test_cred.c create mode 100644 third_party/heimdal/lib/gssapi/test_kcred.c create mode 100644 third_party/heimdal/lib/gssapi/test_names.c create mode 100644 third_party/heimdal/lib/gssapi/test_negoex_mech.c create mode 100644 third_party/heimdal/lib/gssapi/test_ntlm.c create mode 100644 third_party/heimdal/lib/gssapi/test_oid.c create mode 100644 third_party/heimdal/lib/gssapi/version-script.map create mode 100644 third_party/heimdal/lib/hcrypto/ChangeLog create mode 100644 third_party/heimdal/lib/hcrypto/DESperate.txt create mode 100644 third_party/heimdal/lib/hcrypto/Makefile.am create mode 100644 third_party/heimdal/lib/hcrypto/NTMakefile create mode 100644 third_party/heimdal/lib/hcrypto/aes.c create mode 100644 third_party/heimdal/lib/hcrypto/aes.h create mode 100644 third_party/heimdal/lib/hcrypto/bn.c create mode 100644 third_party/heimdal/lib/hcrypto/bn.h create mode 100644 third_party/heimdal/lib/hcrypto/camellia-ntt.c create mode 100644 third_party/heimdal/lib/hcrypto/camellia-ntt.h create mode 100644 third_party/heimdal/lib/hcrypto/camellia.c create mode 100644 third_party/heimdal/lib/hcrypto/camellia.h create mode 100644 third_party/heimdal/lib/hcrypto/common.c create mode 100644 third_party/heimdal/lib/hcrypto/common.h create mode 100644 third_party/heimdal/lib/hcrypto/des-tables.h create mode 100644 third_party/heimdal/lib/hcrypto/des.c create mode 100644 third_party/heimdal/lib/hcrypto/des.h create mode 100644 third_party/heimdal/lib/hcrypto/destest.c create mode 100644 third_party/heimdal/lib/hcrypto/dh-ltm.c create mode 100644 third_party/heimdal/lib/hcrypto/dh-tfm.c create mode 100644 third_party/heimdal/lib/hcrypto/dh.c create mode 100644 third_party/heimdal/lib/hcrypto/dh.h create mode 100644 third_party/heimdal/lib/hcrypto/doxygen.c create mode 100644 third_party/heimdal/lib/hcrypto/dsa.c create mode 100644 third_party/heimdal/lib/hcrypto/dsa.h create mode 100644 third_party/heimdal/lib/hcrypto/ec.c create mode 100644 third_party/heimdal/lib/hcrypto/ec.h create mode 100644 third_party/heimdal/lib/hcrypto/ecdh.h create mode 100644 third_party/heimdal/lib/hcrypto/ecdsa.h create mode 100644 third_party/heimdal/lib/hcrypto/engine.c create mode 100644 third_party/heimdal/lib/hcrypto/engine.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-cc.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-cc.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-crypt.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-hcrypto.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-hcrypto.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-openssl.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-openssl.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-pkcs11.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-pkcs11.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-w32.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-w32.h create mode 100644 third_party/heimdal/lib/hcrypto/evp-wincng.c create mode 100644 third_party/heimdal/lib/hcrypto/evp-wincng.h create mode 100644 third_party/heimdal/lib/hcrypto/evp.c create mode 100644 third_party/heimdal/lib/hcrypto/evp.h create mode 100644 third_party/heimdal/lib/hcrypto/example_evp_cipher.c create mode 100644 third_party/heimdal/lib/hcrypto/gen-des.pl create mode 100644 third_party/heimdal/lib/hcrypto/hash.h create mode 100644 third_party/heimdal/lib/hcrypto/hmac.c create mode 100644 third_party/heimdal/lib/hcrypto/hmac.h create mode 100644 third_party/heimdal/lib/hcrypto/libhcrypto-exports.def create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/LICENSE create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/NTMakefile create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/README.md create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/appveyor.yml create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/astylerc create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_cutoffs.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_deprecated.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_2expt.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_abs.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_addmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_and.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clamp.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear_multi.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_mag.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cnt_lsb.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_complement.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_copy.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_count_bits.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_decr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_3.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_is_modulus.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_reduce.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_setup.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_error_to_string.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exch.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_expt_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exptmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exteuclid.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fread.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_sbin.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_ubin.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fwrite.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_gcd.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_double.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_ll.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ull.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_grow.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_incr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_copy.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ll.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_multi.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_set.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_size.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ull.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_invmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_is_square.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_iseven.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_isodd.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_kronecker.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lcm.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_log_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lshd.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_2d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_calc_normalization.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_reduce.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_setup.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mulmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_neg.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_or.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack_count.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_fermat.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_frobenius_underwood.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_is_prime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_miller_rabin.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_next_prime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rabin_miller_trials.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rand.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_strong_lucas_selfridge.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_size.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_smap.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rand.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_read_radix.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_setup.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_root_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rshd.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sbin_size.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_l.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ll.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u32.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u64.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ull.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_shrink.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_signed_rsh.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrt.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrtmod_prime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub_d.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_submod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_radix.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_sbin.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_ubin.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_ubin_size.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_unpack.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_xor.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_mp_zero.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_prime_tab.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_add.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_balance_mul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_get_bit.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_slow.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_karatsuba_mul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_karatsuba_sqr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_montgomery_reduce_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_prime_is_divisible.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_jenkins.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_reverse.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr_fast.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sub.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_mul.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_sqr.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/changes.txt create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/demo/mtest_opponent.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/demo/shared.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/demo/shared.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/demo/test.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/demo/timing.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/doc/bn.pdf create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/doc/bn.tex create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.1 create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/drprime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.28 create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.txt create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/makefile create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.icc create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.msvc create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/mersenne.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/mont.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/pprime.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/prime.1024 create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/prime.512 create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/timer.asm create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c create mode 100755 third_party/heimdal/lib/hcrypto/libtommath/etc/tune_it.sh create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/gen.pl create mode 100755 third_party/heimdal/lib/hcrypto/libtommath/helper.pl create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/libtommath.pc.in create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.sln create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.vcproj create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/README create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/add.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/addsub.png create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/expt.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/expt.png create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2k.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2kl.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/expt_dr.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/graphs.dem create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/index.html create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.png create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/mult.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/mult.png create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/mult_kara.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/sqr.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/sqr_kara.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/logs/sub.log create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile.mingw create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile.msvc create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile.shared create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile.unix create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/makefile_include.mk create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/logtab.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-config.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-types.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/mtest/mtest.c create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/pre_gen/mpi.c create mode 100755 third_party/heimdal/lib/hcrypto/libtommath/testme.sh create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath.def create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath_class.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath_cutoffs.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath_private.h create mode 100644 third_party/heimdal/lib/hcrypto/libtommath/tommath_superclass.h create mode 100644 third_party/heimdal/lib/hcrypto/md4.c create mode 100644 third_party/heimdal/lib/hcrypto/md4.h create mode 100644 third_party/heimdal/lib/hcrypto/md5.c create mode 100644 third_party/heimdal/lib/hcrypto/md5.h create mode 100644 third_party/heimdal/lib/hcrypto/md5crypt_test.c create mode 100644 third_party/heimdal/lib/hcrypto/mdtest.c create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dialog.aps create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dialog.clw create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dialog.rc create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dialog.res create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dlg.c create mode 100644 third_party/heimdal/lib/hcrypto/passwd_dlg.h create mode 100644 third_party/heimdal/lib/hcrypto/pkcs12.c create mode 100644 third_party/heimdal/lib/hcrypto/pkcs12.h create mode 100644 third_party/heimdal/lib/hcrypto/pkcs5.c create mode 100644 third_party/heimdal/lib/hcrypto/rand-fortuna.c create mode 100644 third_party/heimdal/lib/hcrypto/rand-timer.c create mode 100644 third_party/heimdal/lib/hcrypto/rand-unix.c create mode 100644 third_party/heimdal/lib/hcrypto/rand-w32.c create mode 100644 third_party/heimdal/lib/hcrypto/rand.c create mode 100644 third_party/heimdal/lib/hcrypto/rand.h create mode 100644 third_party/heimdal/lib/hcrypto/randi.h create mode 100644 third_party/heimdal/lib/hcrypto/rc2.c create mode 100644 third_party/heimdal/lib/hcrypto/rc2.h create mode 100644 third_party/heimdal/lib/hcrypto/rc2test.c create mode 100644 third_party/heimdal/lib/hcrypto/rc4.c create mode 100644 third_party/heimdal/lib/hcrypto/rc4.h create mode 100644 third_party/heimdal/lib/hcrypto/rctest.c create mode 100644 third_party/heimdal/lib/hcrypto/resource.h create mode 100644 third_party/heimdal/lib/hcrypto/rijndael-alg-fst.c create mode 100644 third_party/heimdal/lib/hcrypto/rijndael-alg-fst.h create mode 100644 third_party/heimdal/lib/hcrypto/rnd_keys.c create mode 100644 third_party/heimdal/lib/hcrypto/rsa-gmp.c create mode 100644 third_party/heimdal/lib/hcrypto/rsa-ltm.c create mode 100644 third_party/heimdal/lib/hcrypto/rsa-tfm.c create mode 100644 third_party/heimdal/lib/hcrypto/rsa.c create mode 100644 third_party/heimdal/lib/hcrypto/rsa.h create mode 100644 third_party/heimdal/lib/hcrypto/rsakey.der create mode 100644 third_party/heimdal/lib/hcrypto/rsakey2048.der create mode 100644 third_party/heimdal/lib/hcrypto/rsakey4096.der create mode 100644 third_party/heimdal/lib/hcrypto/sha.c create mode 100644 third_party/heimdal/lib/hcrypto/sha.h create mode 100644 third_party/heimdal/lib/hcrypto/sha256.c create mode 100644 third_party/heimdal/lib/hcrypto/sha512.c create mode 100644 third_party/heimdal/lib/hcrypto/test_bn.c create mode 100644 third_party/heimdal/lib/hcrypto/test_bulk.c create mode 100644 third_party/heimdal/lib/hcrypto/test_cipher.c create mode 100644 third_party/heimdal/lib/hcrypto/test_crypto.in create mode 100644 third_party/heimdal/lib/hcrypto/test_dh.c create mode 100644 third_party/heimdal/lib/hcrypto/test_engine_dso.c create mode 100644 third_party/heimdal/lib/hcrypto/test_hmac.c create mode 100644 third_party/heimdal/lib/hcrypto/test_pkcs12.c create mode 100644 third_party/heimdal/lib/hcrypto/test_pkcs5.c create mode 100644 third_party/heimdal/lib/hcrypto/test_rand.c create mode 100644 third_party/heimdal/lib/hcrypto/test_rsa.c create mode 100644 third_party/heimdal/lib/hcrypto/ui.c create mode 100644 third_party/heimdal/lib/hcrypto/ui.h create mode 100644 third_party/heimdal/lib/hcrypto/undef.h create mode 100644 third_party/heimdal/lib/hcrypto/validate.c create mode 100644 third_party/heimdal/lib/hcrypto/version-script.map create mode 100644 third_party/heimdal/lib/hcrypto/x25519/NTMakefile create mode 100644 third_party/heimdal/lib/hcrypto/x25519/align.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.c create mode 100644 third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_25_5.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_51.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base2.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_25_5/constants.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_25_5/fe.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_51/base.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_51/base2.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_51/constants.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/fe_51/fe.h create mode 100644 third_party/heimdal/lib/hcrypto/x25519/x25519_ref10.c create mode 100644 third_party/heimdal/lib/hcrypto/x25519_ref10.h create mode 100644 third_party/heimdal/lib/hdb/Makefile.am create mode 100644 third_party/heimdal/lib/hdb/NTMakefile create mode 100644 third_party/heimdal/lib/hdb/common.c create mode 100644 third_party/heimdal/lib/hdb/data-mkey.mit.des3.be create mode 100644 third_party/heimdal/lib/hdb/data-mkey.mit.des3.le create mode 100644 third_party/heimdal/lib/hdb/db.c create mode 100644 third_party/heimdal/lib/hdb/db3.c create mode 100644 third_party/heimdal/lib/hdb/dbinfo.c create mode 100644 third_party/heimdal/lib/hdb/ext.c create mode 100644 third_party/heimdal/lib/hdb/hdb-keytab.c create mode 100644 third_party/heimdal/lib/hdb/hdb-ldap.c create mode 100644 third_party/heimdal/lib/hdb/hdb-mdb.c create mode 100644 third_party/heimdal/lib/hdb/hdb-mitdb.c create mode 100644 third_party/heimdal/lib/hdb/hdb-sqlite.c create mode 100644 third_party/heimdal/lib/hdb/hdb.asn1 create mode 100644 third_party/heimdal/lib/hdb/hdb.c create mode 100644 third_party/heimdal/lib/hdb/hdb.h create mode 100644 third_party/heimdal/lib/hdb/hdb.opt create mode 100644 third_party/heimdal/lib/hdb/hdb.schema create mode 100644 third_party/heimdal/lib/hdb/hdb_err.et create mode 100644 third_party/heimdal/lib/hdb/hdb_locl.h create mode 100644 third_party/heimdal/lib/hdb/keys.c create mode 100644 third_party/heimdal/lib/hdb/keytab.c create mode 100644 third_party/heimdal/lib/hdb/libhdb-exports.def create mode 100644 third_party/heimdal/lib/hdb/libhdb-version.rc create mode 100644 third_party/heimdal/lib/hdb/mkey.c create mode 100644 third_party/heimdal/lib/hdb/ndbm.c create mode 100644 third_party/heimdal/lib/hdb/print.c create mode 100644 third_party/heimdal/lib/hdb/test_concurrency.c create mode 100644 third_party/heimdal/lib/hdb/test_dbinfo.c create mode 100644 third_party/heimdal/lib/hdb/test_hdbkeys.c create mode 100644 third_party/heimdal/lib/hdb/test_mkey.c create mode 100644 third_party/heimdal/lib/hdb/test_namespace.c create mode 100644 third_party/heimdal/lib/hdb/version-script.map create mode 100644 third_party/heimdal/lib/heimdal/NTMakefile create mode 100644 third_party/heimdal/lib/heimdal/heimdal-version.rc create mode 100644 third_party/heimdal/lib/hx509/ChangeLog create mode 100644 third_party/heimdal/lib/hx509/Makefile.am create mode 100644 third_party/heimdal/lib/hx509/NTMakefile create mode 100644 third_party/heimdal/lib/hx509/TODO create mode 100644 third_party/heimdal/lib/hx509/ca.c create mode 100644 third_party/heimdal/lib/hx509/cert.c create mode 100644 third_party/heimdal/lib/hx509/char_map.h create mode 100644 third_party/heimdal/lib/hx509/cms.c create mode 100644 third_party/heimdal/lib/hx509/collector.c create mode 100644 third_party/heimdal/lib/hx509/crypto-ec.c create mode 100644 third_party/heimdal/lib/hx509/crypto.c create mode 100644 third_party/heimdal/lib/hx509/data/PKITS.pdf create mode 100644 third_party/heimdal/lib/hx509/data/PKITS_data.zip create mode 100644 third_party/heimdal/lib/hx509/data/bleichenbacher-bad.pem create mode 100644 third_party/heimdal/lib/hx509/data/bleichenbacher-good.pem create mode 100644 third_party/heimdal/lib/hx509/data/bleichenbacher-sf-pad-correct.pem create mode 100644 third_party/heimdal/lib/hx509/data/ca.crt create mode 100644 third_party/heimdal/lib/hx509/data/ca.key create mode 100644 third_party/heimdal/lib/hx509/data/crl1.crl create mode 100644 third_party/heimdal/lib/hx509/data/crl1.der create mode 100644 third_party/heimdal/lib/hx509/data/eccurve.pem create mode 100755 third_party/heimdal/lib/hx509/data/gen-req.sh create mode 100644 third_party/heimdal/lib/hx509/data/https.crt create mode 100644 third_party/heimdal/lib/hx509/data/https.key create mode 100644 third_party/heimdal/lib/hx509/data/j.pem create mode 100644 third_party/heimdal/lib/hx509/data/kdc.crt create mode 100644 third_party/heimdal/lib/hx509/data/kdc.key create mode 100644 third_party/heimdal/lib/hx509/data/key.der create mode 100644 third_party/heimdal/lib/hx509/data/key2.der create mode 100755 third_party/heimdal/lib/hx509/data/mkcert.sh create mode 100644 third_party/heimdal/lib/hx509/data/n0ll.pem create mode 100644 third_party/heimdal/lib/hx509/data/nist-data create mode 100644 third_party/heimdal/lib/hx509/data/nist-data2 create mode 100644 third_party/heimdal/lib/hx509/data/nist-result2 create mode 100644 third_party/heimdal/lib/hx509/data/no-proxy-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/no-proxy-test.key create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-req1.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-req2.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-2.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-3.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-ca.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-keyhash.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp-no-cert.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp1.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-resp2.der create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-responder.crt create mode 100644 third_party/heimdal/lib/hx509/data/ocsp-responder.key create mode 100644 third_party/heimdal/lib/hx509/data/openssl.1.0.cnf create mode 100644 third_party/heimdal/lib/hx509/data/openssl.1.1.cnf create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-ec.crt create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-ec.key create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-proxy-chain.crt create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-proxy.crt create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-proxy.key create mode 100644 third_party/heimdal/lib/hx509/data/pkinit-pw.key create mode 100644 third_party/heimdal/lib/hx509/data/pkinit.crt create mode 100644 third_party/heimdal/lib/hx509/data/pkinit.key create mode 100644 third_party/heimdal/lib/hx509/data/proxy-level-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/proxy-level-test.key create mode 100644 third_party/heimdal/lib/hx509/data/proxy-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/proxy-test.key create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-child-child-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-child-child-test.key create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-child-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-child-test.key create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-test.crt create mode 100644 third_party/heimdal/lib/hx509/data/proxy10-test.key create mode 100644 third_party/heimdal/lib/hx509/data/revoke.crt create mode 100644 third_party/heimdal/lib/hx509/data/revoke.key create mode 100644 third_party/heimdal/lib/hx509/data/secp256r1TestCA.cert.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r1TestCA.key.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r1TestCA.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestClient.cert.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestClient.key.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestClient.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestServer.cert.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestServer.key.pem create mode 100644 third_party/heimdal/lib/hx509/data/secp256r2TestServer.pem create mode 100644 third_party/heimdal/lib/hx509/data/sf-class2-root.pem create mode 100644 third_party/heimdal/lib/hx509/data/static-file create mode 100644 third_party/heimdal/lib/hx509/data/sub-ca.crt create mode 100644 third_party/heimdal/lib/hx509/data/sub-ca.key create mode 100644 third_party/heimdal/lib/hx509/data/sub-cert.crt create mode 100644 third_party/heimdal/lib/hx509/data/sub-cert.key create mode 100644 third_party/heimdal/lib/hx509/data/sub-cert.p12 create mode 100644 third_party/heimdal/lib/hx509/data/tcg-devid.pem create mode 100644 third_party/heimdal/lib/hx509/data/tcg-ek-cp.pem create mode 100644 third_party/heimdal/lib/hx509/data/test-ds-only.crt create mode 100644 third_party/heimdal/lib/hx509/data/test-ds-only.key create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-aes-128 create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-aes-256 create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-des create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-des-ede3 create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-rc2-128 create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-rc2-40 create mode 100644 third_party/heimdal/lib/hx509/data/test-enveloped-rc2-64 create mode 100644 third_party/heimdal/lib/hx509/data/test-ke-only.crt create mode 100644 third_party/heimdal/lib/hx509/data/test-ke-only.key create mode 100644 third_party/heimdal/lib/hx509/data/test-nopw.p12 create mode 100644 third_party/heimdal/lib/hx509/data/test-pw.key create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-data create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-data-noattr create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-data-noattr-nocerts create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-sha-1 create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-sha-256 create mode 100644 third_party/heimdal/lib/hx509/data/test-signed-sha-512 create mode 100644 third_party/heimdal/lib/hx509/data/test.combined.crt create mode 100644 third_party/heimdal/lib/hx509/data/test.crt create mode 100644 third_party/heimdal/lib/hx509/data/test.key create mode 100644 third_party/heimdal/lib/hx509/data/test.p12 create mode 100644 third_party/heimdal/lib/hx509/data/win-u16-in-printablestring.der create mode 100644 third_party/heimdal/lib/hx509/data/yutaka-pad-broken-ca.pem create mode 100644 third_party/heimdal/lib/hx509/data/yutaka-pad-broken-cert.pem create mode 100644 third_party/heimdal/lib/hx509/data/yutaka-pad-ok-ca.pem create mode 100644 third_party/heimdal/lib/hx509/data/yutaka-pad-ok-cert.pem create mode 100644 third_party/heimdal/lib/hx509/data/yutaka-pad.key create mode 100644 third_party/heimdal/lib/hx509/doxygen.c create mode 100644 third_party/heimdal/lib/hx509/env.c create mode 100644 third_party/heimdal/lib/hx509/error.c create mode 100644 third_party/heimdal/lib/hx509/file.c create mode 100644 third_party/heimdal/lib/hx509/hx509.h create mode 100644 third_party/heimdal/lib/hx509/hx509_err.et create mode 100644 third_party/heimdal/lib/hx509/hx_locl.h create mode 100644 third_party/heimdal/lib/hx509/hxtool-commands.in create mode 100644 third_party/heimdal/lib/hx509/hxtool-version.rc create mode 100644 third_party/heimdal/lib/hx509/hxtool.1 create mode 100644 third_party/heimdal/lib/hx509/hxtool.c create mode 100644 third_party/heimdal/lib/hx509/keyset.c create mode 100644 third_party/heimdal/lib/hx509/ks_dir.c create mode 100644 third_party/heimdal/lib/hx509/ks_file.c create mode 100644 third_party/heimdal/lib/hx509/ks_keychain.c create mode 100644 third_party/heimdal/lib/hx509/ks_mem.c create mode 100644 third_party/heimdal/lib/hx509/ks_null.c create mode 100644 third_party/heimdal/lib/hx509/ks_p11.c create mode 100644 third_party/heimdal/lib/hx509/ks_p12.c create mode 100644 third_party/heimdal/lib/hx509/libhx509-exports.def create mode 100644 third_party/heimdal/lib/hx509/lock.c create mode 100644 third_party/heimdal/lib/hx509/name.c create mode 100644 third_party/heimdal/lib/hx509/peer.c create mode 100644 third_party/heimdal/lib/hx509/print.c create mode 100644 third_party/heimdal/lib/hx509/quote.py create mode 100644 third_party/heimdal/lib/hx509/ref/pkcs11.h create mode 100644 third_party/heimdal/lib/hx509/req.c create mode 100644 third_party/heimdal/lib/hx509/revoke.c create mode 100644 third_party/heimdal/lib/hx509/sel-gram.y create mode 100644 third_party/heimdal/lib/hx509/sel-lex.l create mode 100644 third_party/heimdal/lib/hx509/sel.c create mode 100644 third_party/heimdal/lib/hx509/sel.h create mode 100644 third_party/heimdal/lib/hx509/softp11.c create mode 100644 third_party/heimdal/lib/hx509/test_ca.in create mode 100644 third_party/heimdal/lib/hx509/test_cert.in create mode 100644 third_party/heimdal/lib/hx509/test_chain.in create mode 100644 third_party/heimdal/lib/hx509/test_cms.in create mode 100644 third_party/heimdal/lib/hx509/test_crypto.in create mode 100644 third_party/heimdal/lib/hx509/test_expr.c create mode 100644 third_party/heimdal/lib/hx509/test_java_pkcs11.in create mode 100644 third_party/heimdal/lib/hx509/test_name.c create mode 100644 third_party/heimdal/lib/hx509/test_nist.in create mode 100644 third_party/heimdal/lib/hx509/test_nist2.in create mode 100644 third_party/heimdal/lib/hx509/test_nist_cert.in create mode 100644 third_party/heimdal/lib/hx509/test_nist_pkcs12.in create mode 100644 third_party/heimdal/lib/hx509/test_pkcs11.in create mode 100644 third_party/heimdal/lib/hx509/test_query.in create mode 100644 third_party/heimdal/lib/hx509/test_req.in create mode 100644 third_party/heimdal/lib/hx509/test_soft_pkcs11.c create mode 100644 third_party/heimdal/lib/hx509/test_windows.in create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-available1 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-available2 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-available3 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select1 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select2 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select3 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select4 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select5 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select6 create mode 100644 third_party/heimdal/lib/hx509/tst-crypto-select7 create mode 100644 third_party/heimdal/lib/hx509/version-script.map create mode 100644 third_party/heimdal/lib/ipc/Makefile.am create mode 100644 third_party/heimdal/lib/ipc/client.c create mode 100644 third_party/heimdal/lib/ipc/common.c create mode 100644 third_party/heimdal/lib/ipc/heim-ipc.h create mode 100644 third_party/heimdal/lib/ipc/heim_ipc.defs create mode 100644 third_party/heimdal/lib/ipc/heim_ipc_async.defs create mode 100644 third_party/heimdal/lib/ipc/heim_ipc_reply.defs create mode 100644 third_party/heimdal/lib/ipc/heim_ipc_types.h create mode 100644 third_party/heimdal/lib/ipc/hi_locl.h create mode 100644 third_party/heimdal/lib/ipc/server.c create mode 100644 third_party/heimdal/lib/ipc/tc.c create mode 100644 third_party/heimdal/lib/ipc/ts-http.c create mode 100644 third_party/heimdal/lib/ipc/ts.c create mode 100644 third_party/heimdal/lib/kadm5/ChangeLog create mode 100644 third_party/heimdal/lib/kadm5/Makefile.am create mode 100644 third_party/heimdal/lib/kadm5/NTMakefile create mode 100644 third_party/heimdal/lib/kadm5/acl.c create mode 100644 third_party/heimdal/lib/kadm5/ad.c create mode 100644 third_party/heimdal/lib/kadm5/admin.h create mode 100644 third_party/heimdal/lib/kadm5/bump_pw_expire.c create mode 100644 third_party/heimdal/lib/kadm5/check-cracklib.pl create mode 100644 third_party/heimdal/lib/kadm5/chpass_c.c create mode 100644 third_party/heimdal/lib/kadm5/chpass_s.c create mode 100644 third_party/heimdal/lib/kadm5/client_glue.c create mode 100644 third_party/heimdal/lib/kadm5/common_glue.c create mode 100644 third_party/heimdal/lib/kadm5/context_s.c create mode 100644 third_party/heimdal/lib/kadm5/create_c.c create mode 100644 third_party/heimdal/lib/kadm5/create_s.c create mode 100644 third_party/heimdal/lib/kadm5/default_keys.c create mode 100644 third_party/heimdal/lib/kadm5/delete_c.c create mode 100644 third_party/heimdal/lib/kadm5/delete_s.c create mode 100644 third_party/heimdal/lib/kadm5/destroy_c.c create mode 100644 third_party/heimdal/lib/kadm5/destroy_s.c create mode 100644 third_party/heimdal/lib/kadm5/ent_setup.c create mode 100644 third_party/heimdal/lib/kadm5/error.c create mode 100644 third_party/heimdal/lib/kadm5/flush.c create mode 100644 third_party/heimdal/lib/kadm5/flush_c.c create mode 100644 third_party/heimdal/lib/kadm5/flush_s.c create mode 100644 third_party/heimdal/lib/kadm5/free.c create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent0.bin create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent1.bin create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent0.bin create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent1.bin create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt create mode 100644 third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent1.txt create mode 100644 third_party/heimdal/lib/kadm5/get_c.c create mode 100644 third_party/heimdal/lib/kadm5/get_princs_c.c create mode 100644 third_party/heimdal/lib/kadm5/get_princs_s.c create mode 100644 third_party/heimdal/lib/kadm5/get_s.c create mode 100644 third_party/heimdal/lib/kadm5/init_c.c create mode 100644 third_party/heimdal/lib/kadm5/init_s.c create mode 100644 third_party/heimdal/lib/kadm5/iprop-commands.in create mode 100644 third_party/heimdal/lib/kadm5/iprop-log-version.rc create mode 100644 third_party/heimdal/lib/kadm5/iprop-log.8 create mode 100644 third_party/heimdal/lib/kadm5/iprop-log.c create mode 100644 third_party/heimdal/lib/kadm5/iprop.8 create mode 100644 third_party/heimdal/lib/kadm5/iprop.h create mode 100644 third_party/heimdal/lib/kadm5/ipropd-master-version.rc create mode 100644 third_party/heimdal/lib/kadm5/ipropd-slave-version.rc create mode 100644 third_party/heimdal/lib/kadm5/ipropd_common.c create mode 100644 third_party/heimdal/lib/kadm5/ipropd_master.c create mode 100644 third_party/heimdal/lib/kadm5/ipropd_slave.c create mode 100644 third_party/heimdal/lib/kadm5/kadm5-hook.h create mode 100644 third_party/heimdal/lib/kadm5/kadm5-pwcheck.h create mode 100644 third_party/heimdal/lib/kadm5/kadm5_err.et create mode 100644 third_party/heimdal/lib/kadm5/kadm5_locl.h create mode 100644 third_party/heimdal/lib/kadm5/kadm5_pwcheck.3 create mode 100644 third_party/heimdal/lib/kadm5/keys.c create mode 100644 third_party/heimdal/lib/kadm5/libkadm5srv-exports.def create mode 100644 third_party/heimdal/lib/kadm5/libkadm5srv-version.rc create mode 100644 third_party/heimdal/lib/kadm5/log.c create mode 100644 third_party/heimdal/lib/kadm5/marshall.c create mode 100644 third_party/heimdal/lib/kadm5/modify_c.c create mode 100644 third_party/heimdal/lib/kadm5/modify_s.c create mode 100644 third_party/heimdal/lib/kadm5/password_quality.c create mode 100644 third_party/heimdal/lib/kadm5/private.h create mode 100644 third_party/heimdal/lib/kadm5/privs_c.c create mode 100644 third_party/heimdal/lib/kadm5/privs_s.c create mode 100644 third_party/heimdal/lib/kadm5/prune_c.c create mode 100644 third_party/heimdal/lib/kadm5/prune_s.c create mode 100644 third_party/heimdal/lib/kadm5/randkey_c.c create mode 100644 third_party/heimdal/lib/kadm5/randkey_s.c create mode 100644 third_party/heimdal/lib/kadm5/rename_c.c create mode 100644 third_party/heimdal/lib/kadm5/rename_s.c create mode 100644 third_party/heimdal/lib/kadm5/sample_hook.c create mode 100644 third_party/heimdal/lib/kadm5/sample_passwd_check.c create mode 100644 third_party/heimdal/lib/kadm5/send_recv.c create mode 100644 third_party/heimdal/lib/kadm5/server_glue.c create mode 100644 third_party/heimdal/lib/kadm5/server_hooks.c create mode 100644 third_party/heimdal/lib/kadm5/set_keys.c create mode 100644 third_party/heimdal/lib/kadm5/set_modifier.c create mode 100644 third_party/heimdal/lib/kadm5/setkey3_s.c create mode 100644 third_party/heimdal/lib/kadm5/test_pw_quality.c create mode 100644 third_party/heimdal/lib/kadm5/version-script-client.map create mode 100644 third_party/heimdal/lib/kadm5/version-script.map create mode 100644 third_party/heimdal/lib/kafs/ChangeLog create mode 100644 third_party/heimdal/lib/kafs/Makefile.am create mode 100644 third_party/heimdal/lib/kafs/NTMakefile create mode 100644 third_party/heimdal/lib/kafs/afskrb5.c create mode 100644 third_party/heimdal/lib/kafs/afsl.exp create mode 100644 third_party/heimdal/lib/kafs/afslib.c create mode 100644 third_party/heimdal/lib/kafs/afslib.exp create mode 100644 third_party/heimdal/lib/kafs/afssys.c create mode 100644 third_party/heimdal/lib/kafs/afssysdefs.h create mode 100644 third_party/heimdal/lib/kafs/common.c create mode 100644 third_party/heimdal/lib/kafs/kafs.3 create mode 100644 third_party/heimdal/lib/kafs/kafs.h create mode 100644 third_party/heimdal/lib/kafs/kafs_locl.h create mode 100644 third_party/heimdal/lib/kafs/roken_rename.h create mode 100644 third_party/heimdal/lib/kafs/rxkad_kdf.c create mode 100644 third_party/heimdal/lib/kdfs/ChangeLog create mode 100644 third_party/heimdal/lib/kdfs/Makefile.am create mode 100644 third_party/heimdal/lib/kdfs/NTMakefile create mode 100644 third_party/heimdal/lib/kdfs/k5dfspag.c create mode 100644 third_party/heimdal/lib/krb5/Makefile.am create mode 100644 third_party/heimdal/lib/krb5/NTMakefile create mode 100644 third_party/heimdal/lib/krb5/acache.c create mode 100644 third_party/heimdal/lib/krb5/acl.c create mode 100644 third_party/heimdal/lib/krb5/add_et_list.c create mode 100644 third_party/heimdal/lib/krb5/addr_families.c create mode 100644 third_party/heimdal/lib/krb5/aes-test.c create mode 100644 third_party/heimdal/lib/krb5/an2ln_plugin.h create mode 100644 third_party/heimdal/lib/krb5/aname_to_localname.c create mode 100644 third_party/heimdal/lib/krb5/appdefault.c create mode 100644 third_party/heimdal/lib/krb5/asn1_glue.c create mode 100644 third_party/heimdal/lib/krb5/auth_context.c create mode 100644 third_party/heimdal/lib/krb5/authdata.c create mode 100644 third_party/heimdal/lib/krb5/build_ap_req.c create mode 100644 third_party/heimdal/lib/krb5/build_auth.c create mode 100644 third_party/heimdal/lib/krb5/cache.c create mode 100644 third_party/heimdal/lib/krb5/ccache_plugin.h create mode 100644 third_party/heimdal/lib/krb5/changepw.c create mode 100644 third_party/heimdal/lib/krb5/codec.c create mode 100644 third_party/heimdal/lib/krb5/config_file.c create mode 100644 third_party/heimdal/lib/krb5/constants.c create mode 100644 third_party/heimdal/lib/krb5/context.c create mode 100644 third_party/heimdal/lib/krb5/convert_creds.c create mode 100644 third_party/heimdal/lib/krb5/copy_host_realm.c create mode 100644 third_party/heimdal/lib/krb5/crc.c create mode 100644 third_party/heimdal/lib/krb5/creds.c create mode 100644 third_party/heimdal/lib/krb5/crypto-aes-sha1.c create mode 100644 third_party/heimdal/lib/krb5/crypto-aes-sha2.c create mode 100644 third_party/heimdal/lib/krb5/crypto-algs.c create mode 100644 third_party/heimdal/lib/krb5/crypto-arcfour.c create mode 100644 third_party/heimdal/lib/krb5/crypto-des-common.c create mode 100644 third_party/heimdal/lib/krb5/crypto-des.c create mode 100644 third_party/heimdal/lib/krb5/crypto-des3.c create mode 100644 third_party/heimdal/lib/krb5/crypto-evp.c create mode 100644 third_party/heimdal/lib/krb5/crypto-null.c create mode 100644 third_party/heimdal/lib/krb5/crypto-pk.c create mode 100644 third_party/heimdal/lib/krb5/crypto-rand.c create mode 100644 third_party/heimdal/lib/krb5/crypto-stubs.c create mode 100644 third_party/heimdal/lib/krb5/crypto.c create mode 100644 third_party/heimdal/lib/krb5/crypto.h create mode 100644 third_party/heimdal/lib/krb5/data.c create mode 100644 third_party/heimdal/lib/krb5/db_plugin.c create mode 100644 third_party/heimdal/lib/krb5/db_plugin.h create mode 100644 third_party/heimdal/lib/krb5/dcache.c create mode 100644 third_party/heimdal/lib/krb5/deprecated.c create mode 100644 third_party/heimdal/lib/krb5/derived-key-test.c create mode 100644 third_party/heimdal/lib/krb5/digest.c create mode 100644 third_party/heimdal/lib/krb5/dll.c create mode 100644 third_party/heimdal/lib/krb5/doxygen.c create mode 100644 third_party/heimdal/lib/krb5/eai_to_heim_errno.c create mode 100644 third_party/heimdal/lib/krb5/enomem.c create mode 100644 third_party/heimdal/lib/krb5/error_string.c create mode 100644 third_party/heimdal/lib/krb5/expand_hostname.c create mode 100644 third_party/heimdal/lib/krb5/expand_path.c create mode 100644 third_party/heimdal/lib/krb5/fast.c create mode 100644 third_party/heimdal/lib/krb5/fcache.c create mode 100644 third_party/heimdal/lib/krb5/free.c create mode 100644 third_party/heimdal/lib/krb5/free_host_realm.c create mode 100644 third_party/heimdal/lib/krb5/generate_seq_number.c create mode 100644 third_party/heimdal/lib/krb5/generate_subkey.c create mode 100644 third_party/heimdal/lib/krb5/get_addrs.c create mode 100644 third_party/heimdal/lib/krb5/get_cred.c create mode 100644 third_party/heimdal/lib/krb5/get_default_principal.c create mode 100644 third_party/heimdal/lib/krb5/get_default_realm.c create mode 100644 third_party/heimdal/lib/krb5/get_for_creds.c create mode 100644 third_party/heimdal/lib/krb5/get_host_realm.c create mode 100644 third_party/heimdal/lib/krb5/get_in_tkt.c create mode 100644 third_party/heimdal/lib/krb5/get_port.c create mode 100644 third_party/heimdal/lib/krb5/init_creds.c create mode 100644 third_party/heimdal/lib/krb5/init_creds_pw.c create mode 100644 third_party/heimdal/lib/krb5/k524_err.et create mode 100644 third_party/heimdal/lib/krb5/k5e1_err.et create mode 100644 third_party/heimdal/lib/krb5/kcm.c create mode 100644 third_party/heimdal/lib/krb5/kcm.h create mode 100644 third_party/heimdal/lib/krb5/kerberos.8 create mode 100644 third_party/heimdal/lib/krb5/keyblock.c create mode 100644 third_party/heimdal/lib/krb5/keytab.c create mode 100644 third_party/heimdal/lib/krb5/keytab_any.c create mode 100644 third_party/heimdal/lib/krb5/keytab_file.c create mode 100644 third_party/heimdal/lib/krb5/keytab_keyfile.c create mode 100644 third_party/heimdal/lib/krb5/keytab_memory.c create mode 100644 third_party/heimdal/lib/krb5/krb5-plugin.7 create mode 100644 third_party/heimdal/lib/krb5/krb5.conf.5 create mode 100644 third_party/heimdal/lib/krb5/krb5.h create mode 100644 third_party/heimdal/lib/krb5/krb5.moduli create mode 100644 third_party/heimdal/lib/krb5/krb524_convert_creds_kdc.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_425_conv_principal.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_acl_match_file.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_aname_to_localname.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_appdefault.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_auth_context.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_c_make_checksum.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_ccapi.h create mode 100644 third_party/heimdal/lib/krb5/krb5_check_transited.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_create_checksum.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_creds.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_digest.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_eai_to_heim_errno.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_encrypt.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_err.et create mode 100644 third_party/heimdal/lib/krb5/krb5_find_padata.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_generate_random_block.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_all_client_addrs.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_credentials.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_creds.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_forwarded_creds.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_in_cred.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_init_creds.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_get_krbhst.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_getportbyname.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_init_context.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_is_thread_safe.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_krbhst_init.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_locl.h create mode 100644 third_party/heimdal/lib/krb5/krb5_mk_req.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_mk_safe.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_openlog.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_parse_name.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_principal.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_rcache.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_rd_error.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_rd_safe.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_set_default_realm.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_set_password.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_string_to_key.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_timeofday.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_verify_init_creds.3 create mode 100644 third_party/heimdal/lib/krb5/krb5_verify_user.3 create mode 100644 third_party/heimdal/lib/krb5/krb_err.et create mode 100644 third_party/heimdal/lib/krb5/krbhst-test.c create mode 100644 third_party/heimdal/lib/krb5/krbhst.c create mode 100644 third_party/heimdal/lib/krb5/krcache.c create mode 100644 third_party/heimdal/lib/krb5/kuserok.c create mode 100644 third_party/heimdal/lib/krb5/kuserok_plugin.h create mode 100644 third_party/heimdal/lib/krb5/kx509.c create mode 100644 third_party/heimdal/lib/krb5/kx509_err.et create mode 100644 third_party/heimdal/lib/krb5/libkrb5-exports.def.in create mode 100644 third_party/heimdal/lib/krb5/locate_plugin.h create mode 100644 third_party/heimdal/lib/krb5/log.c create mode 100644 third_party/heimdal/lib/krb5/mcache.c create mode 100644 third_party/heimdal/lib/krb5/misc.c create mode 100644 third_party/heimdal/lib/krb5/mit_glue.c create mode 100644 third_party/heimdal/lib/krb5/mk_cred.c create mode 100644 third_party/heimdal/lib/krb5/mk_error.c create mode 100644 third_party/heimdal/lib/krb5/mk_priv.c create mode 100644 third_party/heimdal/lib/krb5/mk_rep.c create mode 100644 third_party/heimdal/lib/krb5/mk_req.c create mode 100644 third_party/heimdal/lib/krb5/mk_req_ext.c create mode 100644 third_party/heimdal/lib/krb5/mk_safe.c create mode 100644 third_party/heimdal/lib/krb5/n-fold-test.c create mode 100644 third_party/heimdal/lib/krb5/n-fold.c create mode 100644 third_party/heimdal/lib/krb5/net_read.c create mode 100644 third_party/heimdal/lib/krb5/net_write.c create mode 100644 third_party/heimdal/lib/krb5/pac.c create mode 100644 third_party/heimdal/lib/krb5/padata.c create mode 100644 third_party/heimdal/lib/krb5/parse-name-test.c create mode 100644 third_party/heimdal/lib/krb5/pcache.c create mode 100644 third_party/heimdal/lib/krb5/pkinit-ec.c create mode 100644 third_party/heimdal/lib/krb5/pkinit.c create mode 100644 third_party/heimdal/lib/krb5/plugin.c create mode 100644 third_party/heimdal/lib/krb5/principal.c create mode 100644 third_party/heimdal/lib/krb5/prog_setup.c create mode 100644 third_party/heimdal/lib/krb5/prompter_posix.c create mode 100644 third_party/heimdal/lib/krb5/pseudo-random-test.c create mode 100644 third_party/heimdal/lib/krb5/rd_cred.c create mode 100644 third_party/heimdal/lib/krb5/rd_error.c create mode 100644 third_party/heimdal/lib/krb5/rd_priv.c create mode 100644 third_party/heimdal/lib/krb5/rd_rep.c create mode 100644 third_party/heimdal/lib/krb5/rd_req.c create mode 100644 third_party/heimdal/lib/krb5/rd_safe.c create mode 100644 third_party/heimdal/lib/krb5/read_message.c create mode 100644 third_party/heimdal/lib/krb5/recvauth.c create mode 100644 third_party/heimdal/lib/krb5/replay.c create mode 100644 third_party/heimdal/lib/krb5/salt-aes-sha1.c create mode 100644 third_party/heimdal/lib/krb5/salt-aes-sha2.c create mode 100644 third_party/heimdal/lib/krb5/salt-arcfour.c create mode 100644 third_party/heimdal/lib/krb5/salt-des.c create mode 100644 third_party/heimdal/lib/krb5/salt-des3.c create mode 100644 third_party/heimdal/lib/krb5/salt.c create mode 100644 third_party/heimdal/lib/krb5/scache.c create mode 100644 third_party/heimdal/lib/krb5/send_to_kdc.c create mode 100644 third_party/heimdal/lib/krb5/send_to_kdc_plugin.h create mode 100644 third_party/heimdal/lib/krb5/sendauth.c create mode 100644 third_party/heimdal/lib/krb5/set_default_realm.c create mode 100644 third_party/heimdal/lib/krb5/sock_principal.c create mode 100755 third_party/heimdal/lib/krb5/sp800-108-kdf.c create mode 100644 third_party/heimdal/lib/krb5/store-int.c create mode 100644 third_party/heimdal/lib/krb5/store-int.h create mode 100644 third_party/heimdal/lib/krb5/store-test.c create mode 100644 third_party/heimdal/lib/krb5/store.c create mode 100644 third_party/heimdal/lib/krb5/store_emem.c create mode 100644 third_party/heimdal/lib/krb5/store_fd.c create mode 100644 third_party/heimdal/lib/krb5/store_mem.c create mode 100644 third_party/heimdal/lib/krb5/store_sock.c create mode 100644 third_party/heimdal/lib/krb5/store_stdio.c create mode 100644 third_party/heimdal/lib/krb5/string-to-key-test.c create mode 100644 third_party/heimdal/lib/krb5/test_acl.c create mode 100644 third_party/heimdal/lib/krb5/test_addr.c create mode 100644 third_party/heimdal/lib/krb5/test_alname.c create mode 100644 third_party/heimdal/lib/krb5/test_ap-req.c create mode 100755 third_party/heimdal/lib/krb5/test_canon.c create mode 100644 third_party/heimdal/lib/krb5/test_cc.c create mode 100644 third_party/heimdal/lib/krb5/test_config.c create mode 100644 third_party/heimdal/lib/krb5/test_config_strings.cfg create mode 100644 third_party/heimdal/lib/krb5/test_crypto.c create mode 100644 third_party/heimdal/lib/krb5/test_crypto_wrapping.c create mode 100644 third_party/heimdal/lib/krb5/test_expand_toks.c create mode 100644 third_party/heimdal/lib/krb5/test_forward.c create mode 100644 third_party/heimdal/lib/krb5/test_fx.c create mode 100644 third_party/heimdal/lib/krb5/test_get_addrs.c create mode 100644 third_party/heimdal/lib/krb5/test_gic.c create mode 100644 third_party/heimdal/lib/krb5/test_hostname.c create mode 100644 third_party/heimdal/lib/krb5/test_keytab.c create mode 100644 third_party/heimdal/lib/krb5/test_kuserok.c create mode 100644 third_party/heimdal/lib/krb5/test_mem.c create mode 100644 third_party/heimdal/lib/krb5/test_mkforwardable.c create mode 100644 third_party/heimdal/lib/krb5/test_pac.c create mode 100644 third_party/heimdal/lib/krb5/test_pkinit_dh2key.c create mode 100644 third_party/heimdal/lib/krb5/test_pknistkdf.c create mode 100644 third_party/heimdal/lib/krb5/test_plugin.c create mode 100644 third_party/heimdal/lib/krb5/test_prf.c create mode 100644 third_party/heimdal/lib/krb5/test_princ.c create mode 100644 third_party/heimdal/lib/krb5/test_renew.c create mode 100644 third_party/heimdal/lib/krb5/test_rfc3961.c create mode 100644 third_party/heimdal/lib/krb5/test_set_kvno0.c create mode 100644 third_party/heimdal/lib/krb5/test_store.c create mode 100644 third_party/heimdal/lib/krb5/test_time.c create mode 100644 third_party/heimdal/lib/krb5/test_x500.c create mode 100644 third_party/heimdal/lib/krb5/ticket.c create mode 100644 third_party/heimdal/lib/krb5/time.c create mode 100644 third_party/heimdal/lib/krb5/transited.c create mode 100644 third_party/heimdal/lib/krb5/verify_init.c create mode 100644 third_party/heimdal/lib/krb5/verify_krb5_conf-version.rc create mode 100644 third_party/heimdal/lib/krb5/verify_krb5_conf.8 create mode 100644 third_party/heimdal/lib/krb5/verify_krb5_conf.c create mode 100644 third_party/heimdal/lib/krb5/verify_user.c create mode 100644 third_party/heimdal/lib/krb5/version-script.map create mode 100644 third_party/heimdal/lib/krb5/version.c create mode 100644 third_party/heimdal/lib/krb5/warn.c create mode 100644 third_party/heimdal/lib/krb5/write_message.c create mode 100644 third_party/heimdal/lib/libedit/COPYING create mode 100644 third_party/heimdal/lib/libedit/ChangeLog create mode 100644 third_party/heimdal/lib/libedit/INSTALL create mode 100644 third_party/heimdal/lib/libedit/Makefile.am create mode 100644 third_party/heimdal/lib/libedit/THANKS create mode 100644 third_party/heimdal/lib/libedit/acinclude.m4 create mode 100644 third_party/heimdal/lib/libedit/config.h.in create mode 100644 third_party/heimdal/lib/libedit/configure.ac create mode 100644 third_party/heimdal/lib/libedit/doc/Makefile.am create mode 100644 third_party/heimdal/lib/libedit/doc/editline.3.roff create mode 100644 third_party/heimdal/lib/libedit/doc/editrc.5.roff create mode 100644 third_party/heimdal/lib/libedit/doc/mdoc2man.awk create mode 100644 third_party/heimdal/lib/libedit/examples/Makefile.am create mode 100644 third_party/heimdal/lib/libedit/examples/fileman.c create mode 100644 third_party/heimdal/lib/libedit/examples/tc1.c create mode 100644 third_party/heimdal/lib/libedit/examples/wtc1.c create mode 100644 third_party/heimdal/lib/libedit/libedit.pc.in create mode 100644 third_party/heimdal/lib/libedit/src/Makefile.am create mode 100644 third_party/heimdal/lib/libedit/src/chared.c create mode 100644 third_party/heimdal/lib/libedit/src/chared.h create mode 100644 third_party/heimdal/lib/libedit/src/chartype.c create mode 100644 third_party/heimdal/lib/libedit/src/chartype.h create mode 100644 third_party/heimdal/lib/libedit/src/common.c create mode 100644 third_party/heimdal/lib/libedit/src/editline.3 create mode 100644 third_party/heimdal/lib/libedit/src/editline.7 create mode 100644 third_party/heimdal/lib/libedit/src/editrc.5 create mode 100644 third_party/heimdal/lib/libedit/src/el.c create mode 100644 third_party/heimdal/lib/libedit/src/el.h create mode 100644 third_party/heimdal/lib/libedit/src/eln.c create mode 100644 third_party/heimdal/lib/libedit/src/emacs.c create mode 100644 third_party/heimdal/lib/libedit/src/filecomplete.c create mode 100644 third_party/heimdal/lib/libedit/src/filecomplete.h create mode 100644 third_party/heimdal/lib/libedit/src/getline.c create mode 100644 third_party/heimdal/lib/libedit/src/hist.c create mode 100644 third_party/heimdal/lib/libedit/src/hist.h create mode 100644 third_party/heimdal/lib/libedit/src/histedit.h create mode 100644 third_party/heimdal/lib/libedit/src/history.c create mode 100644 third_party/heimdal/lib/libedit/src/historyn.c create mode 100644 third_party/heimdal/lib/libedit/src/keymacro.c create mode 100644 third_party/heimdal/lib/libedit/src/keymacro.h create mode 100644 third_party/heimdal/lib/libedit/src/makelist create mode 100644 third_party/heimdal/lib/libedit/src/map.c create mode 100644 third_party/heimdal/lib/libedit/src/map.h create mode 100644 third_party/heimdal/lib/libedit/src/parse.c create mode 100644 third_party/heimdal/lib/libedit/src/parse.h create mode 100644 third_party/heimdal/lib/libedit/src/prompt.c create mode 100644 third_party/heimdal/lib/libedit/src/prompt.h create mode 100644 third_party/heimdal/lib/libedit/src/read.c create mode 100644 third_party/heimdal/lib/libedit/src/read.h create mode 100644 third_party/heimdal/lib/libedit/src/readline.c create mode 100644 third_party/heimdal/lib/libedit/src/readline/readline.h create mode 100644 third_party/heimdal/lib/libedit/src/refresh.c create mode 100644 third_party/heimdal/lib/libedit/src/refresh.h create mode 100644 third_party/heimdal/lib/libedit/src/search.c create mode 100644 third_party/heimdal/lib/libedit/src/search.h create mode 100644 third_party/heimdal/lib/libedit/src/shlib_version create mode 100644 third_party/heimdal/lib/libedit/src/sig.c create mode 100644 third_party/heimdal/lib/libedit/src/sig.h create mode 100644 third_party/heimdal/lib/libedit/src/sys.h create mode 100644 third_party/heimdal/lib/libedit/src/terminal.c create mode 100644 third_party/heimdal/lib/libedit/src/terminal.h create mode 100644 third_party/heimdal/lib/libedit/src/tokenizer.c create mode 100644 third_party/heimdal/lib/libedit/src/tokenizern.c create mode 100644 third_party/heimdal/lib/libedit/src/tty.c create mode 100644 third_party/heimdal/lib/libedit/src/tty.h create mode 100644 third_party/heimdal/lib/libedit/src/unvis.c create mode 100644 third_party/heimdal/lib/libedit/src/vi.c create mode 100644 third_party/heimdal/lib/libedit/src/vis.c create mode 100644 third_party/heimdal/lib/libedit/src/vis.h create mode 100644 third_party/heimdal/lib/libedit/src/wcsdup.c create mode 100644 third_party/heimdal/lib/ntlm/ChangeLog create mode 100644 third_party/heimdal/lib/ntlm/Makefile.am create mode 100644 third_party/heimdal/lib/ntlm/NTMakefile create mode 100644 third_party/heimdal/lib/ntlm/apop.c create mode 100644 third_party/heimdal/lib/ntlm/digest.c create mode 100644 third_party/heimdal/lib/ntlm/heim-auth.h create mode 100644 third_party/heimdal/lib/ntlm/heimntlm.h create mode 100644 third_party/heimdal/lib/ntlm/libheimntlm-exports.def create mode 100644 third_party/heimdal/lib/ntlm/libheimntlm-version.rc create mode 100644 third_party/heimdal/lib/ntlm/ntlm.c create mode 100644 third_party/heimdal/lib/ntlm/ntlm_err.et create mode 100644 third_party/heimdal/lib/ntlm/test_commonauth.c create mode 100644 third_party/heimdal/lib/ntlm/test_ntlm.c create mode 100644 third_party/heimdal/lib/ntlm/version-script.map create mode 100644 third_party/heimdal/lib/otp/ChangeLog create mode 100644 third_party/heimdal/lib/otp/Makefile.am create mode 100644 third_party/heimdal/lib/otp/NTMakefile create mode 100644 third_party/heimdal/lib/otp/otp.c create mode 100644 third_party/heimdal/lib/otp/otp.h create mode 100644 third_party/heimdal/lib/otp/otp_challenge.c create mode 100644 third_party/heimdal/lib/otp/otp_db.c create mode 100644 third_party/heimdal/lib/otp/otp_locl.h create mode 100644 third_party/heimdal/lib/otp/otp_md.c create mode 100644 third_party/heimdal/lib/otp/otp_md.h create mode 100644 third_party/heimdal/lib/otp/otp_parse.c create mode 100644 third_party/heimdal/lib/otp/otp_print.c create mode 100644 third_party/heimdal/lib/otp/otp_verify.c create mode 100644 third_party/heimdal/lib/otp/otptest.c create mode 100644 third_party/heimdal/lib/otp/roken_rename.h create mode 100644 third_party/heimdal/lib/otp/version-script.map create mode 100644 third_party/heimdal/lib/roken/ChangeLog create mode 100644 third_party/heimdal/lib/roken/Makefile.am create mode 100644 third_party/heimdal/lib/roken/NTMakefile create mode 100644 third_party/heimdal/lib/roken/base32-test.c create mode 100644 third_party/heimdal/lib/roken/base32.c create mode 100644 third_party/heimdal/lib/roken/base32.h create mode 100644 third_party/heimdal/lib/roken/base64-test.c create mode 100644 third_party/heimdal/lib/roken/base64.c create mode 100644 third_party/heimdal/lib/roken/base64.h create mode 100644 third_party/heimdal/lib/roken/bswap.c create mode 100644 third_party/heimdal/lib/roken/chown.c create mode 100644 third_party/heimdal/lib/roken/cloexec.c create mode 100644 third_party/heimdal/lib/roken/closefrom.c create mode 100644 third_party/heimdal/lib/roken/clz.c create mode 100644 third_party/heimdal/lib/roken/concat.c create mode 100644 third_party/heimdal/lib/roken/copyhostent.c create mode 100644 third_party/heimdal/lib/roken/ct.c create mode 100644 third_party/heimdal/lib/roken/daemon.c create mode 100644 third_party/heimdal/lib/roken/detach.c create mode 100644 third_party/heimdal/lib/roken/dirent-test.c create mode 100644 third_party/heimdal/lib/roken/dirent.c create mode 100644 third_party/heimdal/lib/roken/dirent.hin create mode 100644 third_party/heimdal/lib/roken/dlfcn.hin create mode 100644 third_party/heimdal/lib/roken/dlfcn_w32.c create mode 100644 third_party/heimdal/lib/roken/doxygen.c create mode 100644 third_party/heimdal/lib/roken/dumpdata.c create mode 100644 third_party/heimdal/lib/roken/ecalloc.3 create mode 100644 third_party/heimdal/lib/roken/ecalloc.c create mode 100644 third_party/heimdal/lib/roken/emalloc.c create mode 100644 third_party/heimdal/lib/roken/environment.c create mode 100644 third_party/heimdal/lib/roken/eread.c create mode 100644 third_party/heimdal/lib/roken/erealloc.c create mode 100644 third_party/heimdal/lib/roken/err.c create mode 100644 third_party/heimdal/lib/roken/err.hin create mode 100644 third_party/heimdal/lib/roken/errx.c create mode 100644 third_party/heimdal/lib/roken/esetenv.c create mode 100644 third_party/heimdal/lib/roken/estrdup.c create mode 100644 third_party/heimdal/lib/roken/ewrite.c create mode 100644 third_party/heimdal/lib/roken/fchown.c create mode 100644 third_party/heimdal/lib/roken/flock.c create mode 100644 third_party/heimdal/lib/roken/fnmatch.c create mode 100644 third_party/heimdal/lib/roken/fnmatch.hin create mode 100644 third_party/heimdal/lib/roken/freeaddrinfo.c create mode 100644 third_party/heimdal/lib/roken/freehostent.c create mode 100644 third_party/heimdal/lib/roken/fseeko.c create mode 100644 third_party/heimdal/lib/roken/ftello.c create mode 100644 third_party/heimdal/lib/roken/gai_strerror.c create mode 100644 third_party/heimdal/lib/roken/get_window_size.c create mode 100644 third_party/heimdal/lib/roken/getaddrinfo-test.c create mode 100644 third_party/heimdal/lib/roken/getaddrinfo.c create mode 100644 third_party/heimdal/lib/roken/getaddrinfo_hostspec.c create mode 100644 third_party/heimdal/lib/roken/getarg.3 create mode 100644 third_party/heimdal/lib/roken/getarg.c create mode 100644 third_party/heimdal/lib/roken/getarg.h create mode 100644 third_party/heimdal/lib/roken/getauxval.c create mode 100644 third_party/heimdal/lib/roken/getauxval.h create mode 100644 third_party/heimdal/lib/roken/getcwd.c create mode 100644 third_party/heimdal/lib/roken/getdtablesize.c create mode 100644 third_party/heimdal/lib/roken/getegid.c create mode 100644 third_party/heimdal/lib/roken/geteuid.c create mode 100644 third_party/heimdal/lib/roken/getgid.c create mode 100644 third_party/heimdal/lib/roken/gethostname.c create mode 100644 third_party/heimdal/lib/roken/getifaddrs-test.c create mode 100644 third_party/heimdal/lib/roken/getifaddrs.c create mode 100644 third_party/heimdal/lib/roken/getifaddrs_w32.c create mode 100644 third_party/heimdal/lib/roken/getipnodebyaddr.c create mode 100644 third_party/heimdal/lib/roken/getipnodebyname.c create mode 100644 third_party/heimdal/lib/roken/getnameinfo.c create mode 100644 third_party/heimdal/lib/roken/getnameinfo_verified.c create mode 100644 third_party/heimdal/lib/roken/getopt.c create mode 100644 third_party/heimdal/lib/roken/getprogname.c create mode 100644 third_party/heimdal/lib/roken/gettimeofday.c create mode 100644 third_party/heimdal/lib/roken/getuid.c create mode 100644 third_party/heimdal/lib/roken/getuserinfo.c create mode 100644 third_party/heimdal/lib/roken/getusershell.c create mode 100644 third_party/heimdal/lib/roken/h_errno.c create mode 100644 third_party/heimdal/lib/roken/hex-test.c create mode 100644 third_party/heimdal/lib/roken/hex.c create mode 100644 third_party/heimdal/lib/roken/hex.h create mode 100644 third_party/heimdal/lib/roken/hostent_find_fqdn.c create mode 100644 third_party/heimdal/lib/roken/hstrerror.c create mode 100644 third_party/heimdal/lib/roken/ifaddrs.hin create mode 100644 third_party/heimdal/lib/roken/inet_aton.c create mode 100644 third_party/heimdal/lib/roken/inet_ntop.c create mode 100644 third_party/heimdal/lib/roken/inet_pton.c create mode 100644 third_party/heimdal/lib/roken/initgroups.c create mode 100644 third_party/heimdal/lib/roken/innetgr.c create mode 100644 third_party/heimdal/lib/roken/install-sh create mode 100644 third_party/heimdal/lib/roken/issuid.c create mode 100644 third_party/heimdal/lib/roken/localtime_r.c create mode 100644 third_party/heimdal/lib/roken/lstat.c create mode 100644 third_party/heimdal/lib/roken/memmem.c create mode 100644 third_party/heimdal/lib/roken/memmove.c create mode 100644 third_party/heimdal/lib/roken/memset_s.c create mode 100644 third_party/heimdal/lib/roken/mergesort.c create mode 100644 third_party/heimdal/lib/roken/mergesort_r.c create mode 100644 third_party/heimdal/lib/roken/mini_inetd.c create mode 100644 third_party/heimdal/lib/roken/missing create mode 100644 third_party/heimdal/lib/roken/mkdir.c create mode 100644 third_party/heimdal/lib/roken/mkdtemp.c create mode 100644 third_party/heimdal/lib/roken/mkinstalldirs create mode 100644 third_party/heimdal/lib/roken/mkostemp.c create mode 100644 third_party/heimdal/lib/roken/mkstemp.c create mode 100644 third_party/heimdal/lib/roken/ndbm_wrap.c create mode 100644 third_party/heimdal/lib/roken/ndbm_wrap.h create mode 100644 third_party/heimdal/lib/roken/net_read.c create mode 100644 third_party/heimdal/lib/roken/net_write.c create mode 100644 third_party/heimdal/lib/roken/parse_bytes-test.c create mode 100644 third_party/heimdal/lib/roken/parse_bytes.c create mode 100644 third_party/heimdal/lib/roken/parse_bytes.h create mode 100644 third_party/heimdal/lib/roken/parse_reply-test.c create mode 100644 third_party/heimdal/lib/roken/parse_time-test.c create mode 100644 third_party/heimdal/lib/roken/parse_time.3 create mode 100644 third_party/heimdal/lib/roken/parse_time.c create mode 100644 third_party/heimdal/lib/roken/parse_time.h create mode 100644 third_party/heimdal/lib/roken/parse_units.c create mode 100644 third_party/heimdal/lib/roken/parse_units.h create mode 100644 third_party/heimdal/lib/roken/putenv.c create mode 100644 third_party/heimdal/lib/roken/qsort.c create mode 100644 third_party/heimdal/lib/roken/rand.c create mode 100644 third_party/heimdal/lib/roken/rcmd.c create mode 100644 third_party/heimdal/lib/roken/readv.c create mode 100644 third_party/heimdal/lib/roken/realloc.c create mode 100644 third_party/heimdal/lib/roken/recvmsg.c create mode 100644 third_party/heimdal/lib/roken/rename.c create mode 100644 third_party/heimdal/lib/roken/resolve-test.c create mode 100644 third_party/heimdal/lib/roken/resolve.c create mode 100644 third_party/heimdal/lib/roken/resolve.h create mode 100644 third_party/heimdal/lib/roken/rkpty.c create mode 100644 third_party/heimdal/lib/roken/roken-common.h create mode 100644 third_party/heimdal/lib/roken/roken.awk create mode 100644 third_party/heimdal/lib/roken/roken.h.in create mode 100644 third_party/heimdal/lib/roken/roken_gethostby.c create mode 100644 third_party/heimdal/lib/roken/rtbl.3 create mode 100644 third_party/heimdal/lib/roken/rtbl.c create mode 100644 third_party/heimdal/lib/roken/rtbl.h create mode 100644 third_party/heimdal/lib/roken/search.hin create mode 100644 third_party/heimdal/lib/roken/secure_getenv.c create mode 100644 third_party/heimdal/lib/roken/secure_getenv.h create mode 100644 third_party/heimdal/lib/roken/sendmsg.c create mode 100644 third_party/heimdal/lib/roken/setegid.c create mode 100644 third_party/heimdal/lib/roken/setenv.c create mode 100644 third_party/heimdal/lib/roken/seteuid.c create mode 100644 third_party/heimdal/lib/roken/setprogname.c create mode 100644 third_party/heimdal/lib/roken/signal.c create mode 100644 third_party/heimdal/lib/roken/simple_exec.c create mode 100644 third_party/heimdal/lib/roken/simple_exec_w32.c create mode 100644 third_party/heimdal/lib/roken/sleep.c create mode 100644 third_party/heimdal/lib/roken/snprintf-test.c create mode 100644 third_party/heimdal/lib/roken/snprintf.c create mode 100644 third_party/heimdal/lib/roken/socket.c create mode 100644 third_party/heimdal/lib/roken/socket_wrapper.c create mode 100644 third_party/heimdal/lib/roken/socket_wrapper.h create mode 100644 third_party/heimdal/lib/roken/sockstartup_w32.c create mode 100644 third_party/heimdal/lib/roken/stdbool.hin create mode 100644 third_party/heimdal/lib/roken/stdint.hin create mode 100644 third_party/heimdal/lib/roken/strcasecmp.c create mode 100644 third_party/heimdal/lib/roken/strcollect.c create mode 100644 third_party/heimdal/lib/roken/strdup.c create mode 100644 third_party/heimdal/lib/roken/strerror.c create mode 100644 third_party/heimdal/lib/roken/strerror_r.c create mode 100644 third_party/heimdal/lib/roken/strftime.c create mode 100644 third_party/heimdal/lib/roken/strlcat.c create mode 100644 third_party/heimdal/lib/roken/strlcpy.c create mode 100644 third_party/heimdal/lib/roken/strlwr.c create mode 100644 third_party/heimdal/lib/roken/strncasecmp.c create mode 100644 third_party/heimdal/lib/roken/strndup.c create mode 100644 third_party/heimdal/lib/roken/strnlen.c create mode 100644 third_party/heimdal/lib/roken/strpftime-test.c create mode 100644 third_party/heimdal/lib/roken/strpftime-test.h create mode 100644 third_party/heimdal/lib/roken/strpool.c create mode 100644 third_party/heimdal/lib/roken/strptime.c create mode 100644 third_party/heimdal/lib/roken/strsep.c create mode 100644 third_party/heimdal/lib/roken/strsep_copy.c create mode 100644 third_party/heimdal/lib/roken/strtok_r.c create mode 100644 third_party/heimdal/lib/roken/strtoll.c create mode 100644 third_party/heimdal/lib/roken/strtoull.c create mode 100644 third_party/heimdal/lib/roken/strupr.c create mode 100644 third_party/heimdal/lib/roken/swab.c create mode 100644 third_party/heimdal/lib/roken/syslog.hin create mode 100644 third_party/heimdal/lib/roken/syslogc.c create mode 100644 third_party/heimdal/lib/roken/test-auxval.c create mode 100644 third_party/heimdal/lib/roken/test-detach.c create mode 100644 third_party/heimdal/lib/roken/test-getuserinfo.c create mode 100644 third_party/heimdal/lib/roken/test-mem.c create mode 100644 third_party/heimdal/lib/roken/test-mem.h create mode 100644 third_party/heimdal/lib/roken/test-mini_inetd.c create mode 100644 third_party/heimdal/lib/roken/test-readenv.c create mode 100644 third_party/heimdal/lib/roken/timegm.c create mode 100644 third_party/heimdal/lib/roken/timeval.c create mode 100644 third_party/heimdal/lib/roken/tm2time.c create mode 100644 third_party/heimdal/lib/roken/tsearch-test.c create mode 100644 third_party/heimdal/lib/roken/tsearch.c create mode 100644 third_party/heimdal/lib/roken/unsetenv.c create mode 100644 third_party/heimdal/lib/roken/unvis.c create mode 100644 third_party/heimdal/lib/roken/verr.c create mode 100644 third_party/heimdal/lib/roken/verrx.c create mode 100644 third_party/heimdal/lib/roken/version-script.map create mode 100644 third_party/heimdal/lib/roken/versionsupport.h create mode 100644 third_party/heimdal/lib/roken/vis-extras.h create mode 100644 third_party/heimdal/lib/roken/vis.c create mode 100644 third_party/heimdal/lib/roken/vis.hin create mode 100644 third_party/heimdal/lib/roken/vsyslog.c create mode 100644 third_party/heimdal/lib/roken/vwarn.c create mode 100644 third_party/heimdal/lib/roken/vwarnx.c create mode 100644 third_party/heimdal/lib/roken/warn.c create mode 100644 third_party/heimdal/lib/roken/warnerr.c create mode 100644 third_party/heimdal/lib/roken/warnx.c create mode 100644 third_party/heimdal/lib/roken/win32_alloc.c create mode 100644 third_party/heimdal/lib/roken/win32_version.c create mode 100644 third_party/heimdal/lib/roken/write_pid.c create mode 100644 third_party/heimdal/lib/roken/writev.c create mode 100644 third_party/heimdal/lib/roken/xdbm.h create mode 100644 third_party/heimdal/lib/roken/xfree.c create mode 100644 third_party/heimdal/lib/sl/ChangeLog create mode 100644 third_party/heimdal/lib/sl/Makefile.am create mode 100644 third_party/heimdal/lib/sl/NTMakefile create mode 100644 third_party/heimdal/lib/sl/roken_rename.h create mode 100644 third_party/heimdal/lib/sl/sl.c create mode 100644 third_party/heimdal/lib/sl/sl.h create mode 100644 third_party/heimdal/lib/sl/sl_locl.h create mode 100644 third_party/heimdal/lib/sl/slc-gram.y create mode 100644 third_party/heimdal/lib/sl/slc-lex.l create mode 100644 third_party/heimdal/lib/sl/slc.h create mode 100644 third_party/heimdal/lib/sl/test_sl.c create mode 100644 third_party/heimdal/lib/sqlite/Makefile.am create mode 100644 third_party/heimdal/lib/sqlite/NTMakefile create mode 100644 third_party/heimdal/lib/sqlite/README create mode 100644 third_party/heimdal/lib/sqlite/sqlite3.c create mode 100644 third_party/heimdal/lib/sqlite/sqlite3.h create mode 100644 third_party/heimdal/lib/sqlite/sqlite3ext.h create mode 100644 third_party/heimdal/lib/vers/ChangeLog create mode 100644 third_party/heimdal/lib/vers/Makefile.am create mode 100644 third_party/heimdal/lib/vers/NTMakefile create mode 100644 third_party/heimdal/lib/vers/make-print-version.c create mode 100644 third_party/heimdal/lib/vers/print_version.c create mode 100644 third_party/heimdal/lib/vers/vers.h create mode 100644 third_party/heimdal/lib/wind/ChangeLog create mode 100644 third_party/heimdal/lib/wind/CompositionExclusions-3.2.0.txt create mode 100644 third_party/heimdal/lib/wind/DerivedNormalizationProps.txt create mode 100644 third_party/heimdal/lib/wind/Makefile.am create mode 100644 third_party/heimdal/lib/wind/NTMakefile create mode 100644 third_party/heimdal/lib/wind/NormalizationCorrections.txt create mode 100644 third_party/heimdal/lib/wind/NormalizationTest.txt create mode 100644 third_party/heimdal/lib/wind/UnicodeData.py create mode 100644 third_party/heimdal/lib/wind/UnicodeData.txt create mode 100644 third_party/heimdal/lib/wind/bidi.c create mode 100644 third_party/heimdal/lib/wind/combining.c create mode 100644 third_party/heimdal/lib/wind/doxygen.c create mode 100644 third_party/heimdal/lib/wind/errorlist.c create mode 100644 third_party/heimdal/lib/wind/gen-bidi.py create mode 100644 third_party/heimdal/lib/wind/gen-combining.py create mode 100644 third_party/heimdal/lib/wind/gen-errorlist.py create mode 100644 third_party/heimdal/lib/wind/gen-map.py create mode 100644 third_party/heimdal/lib/wind/gen-normalize.py create mode 100644 third_party/heimdal/lib/wind/gen-punycode-examples.py create mode 100644 third_party/heimdal/lib/wind/generate.py create mode 100644 third_party/heimdal/lib/wind/idn-lookup.c create mode 100644 third_party/heimdal/lib/wind/ldap.c create mode 100644 third_party/heimdal/lib/wind/libwind-exports.def create mode 100644 third_party/heimdal/lib/wind/map.c create mode 100644 third_party/heimdal/lib/wind/normalize.c create mode 100644 third_party/heimdal/lib/wind/punycode.c create mode 100644 third_party/heimdal/lib/wind/rfc3454.py create mode 100644 third_party/heimdal/lib/wind/rfc4518.py create mode 100644 third_party/heimdal/lib/wind/stringprep.c create mode 100644 third_party/heimdal/lib/wind/stringprep.py create mode 100644 third_party/heimdal/lib/wind/test-bidi.c create mode 100644 third_party/heimdal/lib/wind/test-ldap.c create mode 100644 third_party/heimdal/lib/wind/test-map.c create mode 100644 third_party/heimdal/lib/wind/test-normalize.c create mode 100644 third_party/heimdal/lib/wind/test-prohibited.c create mode 100644 third_party/heimdal/lib/wind/test-punycode.c create mode 100644 third_party/heimdal/lib/wind/test-rw.c create mode 100644 third_party/heimdal/lib/wind/test-utf8.c create mode 100644 third_party/heimdal/lib/wind/utf8.c create mode 100644 third_party/heimdal/lib/wind/util.py create mode 100644 third_party/heimdal/lib/wind/version-script.map create mode 100644 third_party/heimdal/lib/wind/wind.h create mode 100644 third_party/heimdal/lib/wind/wind_err.et create mode 100644 third_party/heimdal/lib/wind/windlocl.h (limited to 'third_party/heimdal/lib') diff --git a/third_party/heimdal/lib/Makefile.am b/third_party/heimdal/lib/Makefile.am new file mode 100644 index 0000000..dc70116 --- /dev/null +++ b/third_party/heimdal/lib/Makefile.am @@ -0,0 +1,50 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +if LIBEDIT +dir_editline = libedit +endif +if OTP +dir_otp = otp +endif +if DCE +dir_dce = kdfs +endif +if COM_ERR +dir_com_err = com_err +endif +if !SQLITE3 +dir_sqlite = sqlite +endif +if MAINTAINER_MODE +dir_sqlite = sqlite +endif +if !NO_AFS +dir_afs = kafs +endif + +SUBDIRS = \ + roken \ + vers \ + $(dir_com_err) \ + base \ + $(dir_editline) \ + sl \ + wind \ + asn1 \ + $(dir_sqlite) \ + hcrypto \ + ipc \ + hx509 \ + krb5 \ + ntlm \ + $(dir_afs) \ + gssapi \ + gss_preauth \ + hdb \ + kadm5 \ + $(dir_otp) \ + $(dir_dce) + +EXTRA_DIST = NTMakefile heimdal diff --git a/third_party/heimdal/lib/NTMakefile b/third_party/heimdal/lib/NTMakefile new file mode 100644 index 0000000..39a0db5 --- /dev/null +++ b/third_party/heimdal/lib/NTMakefile @@ -0,0 +1,79 @@ +######################################################################## +# +# Copyright (c) 2009-2016, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + + +!ifdef OTP +dir_otp = otp +!endif +!ifdef DCE +dir_dce = kdfs +!endif + +# Third party plugins must be added to the assembly +# Permit third party assembly scripts + +!if exist(..\thirdparty\plugin\NTMakefile) +plugin=..\thirdparty\plugin +!endif + +!if exist(..\thirdparty\assembly\NTMakefile) +assembly=..\thirdparty\assembly +!else +assembly=..\packages\windows\assembly +!endif + +SUBDIRS = roken vers com_err base sl wind asn1 sqlite \ + hcrypto hx509 krb5 heimdal ntlm kafs gssapi gss_preauth \ + hdb kadm5 $(dir_otp) $(dir_dce) $(plugin) $(assembly) + +!include ../windows/NTMakefile.w32 + +# We can't build some of the lib tools until after we have LIBHEIMDAL. +# So we build tools in a separate build step: + +all:: all-tools + +all-tools:: asn1-tools hx509-tools krb5-tools kadm5-tools gss-tools + +asn1-tools: + @( cd asn1 && $(RMAKE) all-tools && cd .. ) || exit /b 1 + +hx509-tools: + @( cd hx509 && $(RMAKE) all-tools && cd .. ) || exit /b 1 + +krb5-tools: + @( cd krb5 && $(RMAKE) all-tools && cd .. ) || exit /b 1 + +kadm5-tools: + @( cd kadm5 && $(RMAKE) all-tools && cd .. ) || exit /b 1 + +gss-tools: + @( cd gssapi && $(RMAKE) all-tools && cd ..) || exit /b 1 diff --git a/third_party/heimdal/lib/asn1/ChangeLog b/third_party/heimdal/lib/asn1/ChangeLog new file mode 100644 index 0000000..523e24b --- /dev/null +++ b/third_party/heimdal/lib/asn1/ChangeLog @@ -0,0 +1,1665 @@ +2008-04-09 Love Hörnquist Åstrand + + * pkinit.asn1: add id-pkinit-kdf + + * pkinit.asn1: add PkinitSP80056AOtherInfo + +2008-04-07 Love Hörnquist Åstrand + + * gen.c: Use unsigned where appropriate. + +2008-03-22 Love Hörnquist Åstrand + + * k5.asn1: Match name in ClientCanonicalizedNames with -10 + + * k5.asn1: add referral-valid-until + +2008-01-13 Love Hörnquist Åstrand + + * asn1-common.h gen.c der.c gen_encode.c: add and use der_{malloc,free} + +2007-12-13 Love Hörnquist Åstrand + + * libasn1.h: remove, not used. + +2007-12-04 Love Hörnquist Åstrand + + * Makefile.am: Add DigestTypes, add --seq to antoher type. + + * digest.asn1: Add supportedMechs request. + +2007-10-18 Love Hörnquist Åstrand + + * k5.asn1: Some "old" windows enctypes. From Andy Polyakov. + +2007-07-23 Love Hörnquist Åstrand + + * Makefile.am: Fold in pk-init-alg-agilty. + + * pkinit.asn1: Fold in pk-init-alg-agilty. + +2007-07-16 Love Hörnquist Åstrand + + * parse.y: Passe object id is its part of the module defintion + statement. + +2007-07-14 Love Hörnquist Åstrand + + * check-gen.c: test SEQ OF SIZE (...) + + * Makefile.am: Include more sizeof tests. + +2007-07-12 Love Hörnquist Åstrand + + * try to avoid aliasing of pointers enum {} vs int + +2007-07-10 Love Hörnquist Åstrand + + * test.asn1: Test SIZE attribute for SEQ and OCTET STRING + + * parse.y (OctetStringType): add SIZE to OCTET STRING. + + * Makefile.am: New library version. + +2007-07-02 Love Hörnquist Åstrand + + * rfc2459.asn1: Re-add size limits. + + * k5.asn1: Add size limits from RFC 4120. + + * gen_decode.c: Check range on SEQ OF and OCTET STRING. + + * asn1_err.et (min|max|exact) constraints. + + * parse.y: Parse size limitations to SEQ OF. + +2007-06-28 Love Hörnquist Åstrand + + * Makefile.am: Add AuthorityInfoAccessSyntax. + + * rfc2459.asn1: Add AuthorityInfoAccessSyntax. + + * rfc2459.asn1: Add authorityInfoAccess, rename proxyCertInfo. + + * Makefile.am: Add authorityInfoAccess, rename proxyCertInfo. + +2007-06-27 Love Hörnquist Åstrand + + * der_get.c (der_get_time): avoid using wrapping of octet_string + and realloc. + + * der_get.c: No need to undef timetm, we don't use it any more. + + * timegm.c: Fix spelling caused by too much query-replace. + + * gen.c: Include for UINT_MAX. + + * gen_decode.c: Check for multipication overrun. + + * gen_encode.c: Paranoia check in buffer overun in output + function. + + * check-der.c: Test boolean. + + * check-der.c: test universal strings. + + * check-der.c: Test failure cases for der_get_tag. + + * check-der.c: test dates from last century. + + * check-der.c: Move zero length integercheck to a better place. + + * check-der.c: Test zero length integer. + +2007-06-18 Love Hörnquist Åstrand + + * check-der.c: Init data to something. + +2007-06-15 Love Hörnquist Åstrand + + * k5.asn1: Add KRB5-AUTHDATA-INITIAL-VERIFIED-CAS. + +2007-06-13 Love Hörnquist Åstrand + + * pkinit.asn1: Make the pkinit nonce signed (like the kerberos + nonce). + +2007-06-03 Love Hörnquist Åstrand + + * check-der.c: Free more memory. + + * der_format.c: Don't accect zero length hex numbers. + + * check-der.c: Also free right memory. + + * main.c: Close asn1 file when done. + + * check-der.c: more check for der_parse_hex_heim_integer + + * der_format.c (der_parse_hex_heim_integer): check length before + reading data. + + * check-gen.c (test_authenticator): free memory + +2007-05-31 Love Hörnquist Åstrand + + * Makefile.am: add MS-UPN-SAN + + * pkinit.asn1: add MS-UPN-SAN + + * rfc2459.asn1: Do evil things to handle IMPLICIT encoded + structures. Add id-ms-client-authentication. + +2007-05-30 Love Hörnquist Åstrand + + * Makefile.am: Add asn1_id_ms_cert_enroll_domaincontroller.x + +2007-05-10 Love Hörnquist Åstrand + + * gen.c: Add struct units; as a forward declaration. Pointed out + by Marcus Watts. + + * rfc2459.asn1: Netscape extentions + + * Makefile.am: add U.S. Federal PKI Common Policy Framework + + * rfc2459.asn1: add U.S. Federal PKI Common Policy Framework + +2007-04-24 Love Hörnquist Åstrand + + * gen_seq.c: Handle the case of resize to 0 and realloc that + returns NULL. + + * check-gen.c (check_seq): free seq. + +2007-04-19 Love Hörnquist Åstrand + + * check-der.c (test_heim_oid_format_same): avoid leaking memory in + the non failure case too + +2007-04-16 Love Hörnquist Åstrand + + * Makefile.am: remove extra ^Q + +2007-04-11 Love Hörnquist Åstrand + + * der_get.c: Allow trailing NULs. We allow this since MIT Kerberos + sends an strings in the NEED_PREAUTH case that includes a trailing + NUL. + +2007-02-17 Love Hörnquist Åstrand + + + * Makefile.am: Add PA-ClientCanonicalized and friends. + + * k5.asn1: Add PA-ClientCanonicalized and friends. + +2007-02-08 Love Hörnquist Åstrand + + * check-der.c: Drop one over INT_MAX test-case. + +2007-02-05 Love Hörnquist Åstrand + + * pkinit.asn1: add id-pkinit-ms-eku + + * pkinit.asn1: fill in more bits of id-pkinit-ms-san + +2007-02-02 Love Hörnquist Åstrand + + * digest.asn1: rename hash-a1 to session key + +2007-02-01 Love Hörnquist Åstrand + + * digest.asn1: Add elements to send in requestResponse to KDC and + get status of the request. + +2007-01-31 Love Hörnquist Åstrand + + * Makefile.am: seq rules for CRLDistributionPoints + +2007-01-30 Love Hörnquist Åstrand + + * Makefile.am: add CRLDistributionPoints and friends + +2007-01-20 Love Hörnquist Åstrand + + * check-der.c: check BMPstring oddlength more + + * check-der.c: Test for NUL char in string in GENERAL STRING. + + * der_get.c: Check for NUL characters in string and return + ASN1_BAD_CHARACTER error-code if we find them. + + * asn1_err.et: Add BAD_CHARACTER error. + +2007-01-16 Love Hörnquist Åstrand + + * Makefile.am: Add id-at-streetAddress. + + * rfc2459.asn1: Add id-at-streetAddress. + +2007-01-12 Love Hörnquist Åstrand + + * rfc2459.asn1: Add PKIXXmppAddr and id-pkix-on-xmppAddr. + +2006-12-30 Love Hörnquist Åstrand + + * Makefile.am: Add id-pkix-kp oids. + + * rfc2459.asn1: Add id-pkix-kp oids. + +2006-12-29 Love Hörnquist Åstrand + + * gen_encode.c: Named bit strings have this horrible, disgusting, + compress bits until they are no longer really there but stuff in + an initial octet anyway encoding scheme. Try to get it right and + calculate the initial octet runtime instead of compiletime. + + * check-gen.c: Check all other silly bitstring combinations. + + * Makefile.am: Add --sequence=Extensions to rfc2459. + +2006-12-28 Love Hörnquist Åstrand + + * kx509.asn1: Add kx509. + + * Makefile.am: Add kx509. + + * Add VisibleString parsing + +2006-12-15 Love Hörnquist Åstrand + + * Makefile.am: Add ntlm files. + + * digest.asn1: Add bits for handling NTLM. + +2006-12-08 Love Hörnquist Åstrand + + * Makefile.am: add pkix proxy cert policy lang oids + + * rfc2459.asn1: add pkix proxy cert policy lang oids + +2006-12-07 Love Hörnquist Åstrand + + * rfc2459.asn1: unbreak id-pe-proxyCertInfo + + * rfc2459.asn1: Add id-pkix-on-dnsSRV and related oids + +2006-11-28 Love Hörnquist Åstrand + + * Makefile.am: Add explicit depenency to LIB_roken for libasn1.la, + make AIX happy. + +2006-11-27 Love Hörnquist Åstrand + + * der_format.c (der_print_heim_oid): oid with zero length is + invalid, fail to print. + +2006-11-24 Love Hörnquist Åstrand + + * der_format.c (der_print_heim_oid): use delim when printing. + +2006-11-21 Love Hörnquist Åstrand + + * k5.asn1: Make KRB5-PADATA-S4U2SELF pa type 129. + +2006-10-24 Love Hörnquist Åstrand + + * asn1_err.et: add EXTRA_DATA + +2006-10-21 Love Hörnquist Åstrand + + * check-gen.c: avoid leaking memory + + * check-der.c: avoid leaking memory + + * der_format.c (der_parse_heim_oid): avoid leaking memory + + * check-common.c: Print size_t as (unsigned long) and cast. + + * check-common.c: Try to align data, IA64's gets upset if its + unaligned. + + * lex.l: add missing */ + + * lex.c: need %e for hpux lex + +2006-10-20 Love Hörnquist Åstrand + + * Makefile.am: remove dups from gen_files_test, add check-timegm. + + * Makefile.am: include more test.asn1 built files + + * Makefile.am: More files, now for make check. + +2006-10-19 Love Hörnquist Åstrand + + * Makefile.am: Add missing files + + * Makefile.am (asn1_compile_SOURCES): add gen_locl.h + + * check-timegm.c: Add check for _der_timegm. + + * der_get.c (generalizedtime2time): always use _der_timegm. + + * timegm.c: make more strict + + * der_locl.h: Rename timegm to _der_timegm. + +2006-10-17 Love Hörnquist Åstrand + + * timegm.c: vJust fail if tm_mon is out of range for now XXXX this + is wrong. + +2006-10-16 Love Hörnquist Åstrand + + * Makefile.am: extra depencies on der-protos.h + +2006-10-14 Love Hörnquist Åstrand + + * check-der.c: Prefix primitive types with der_. + + * timegm.c: rename the buildin timegm to _der_timegm + + * heim_asn1.h: move prototype away from here. + + * der_format.c: Add der_parse_heim_oid + + * gen_free.c: prefix primitive types with der_ + + * der_copy.c: prefix primitive types with der_ + + * gen_length.c: prefix primitive types with der_ + + * der_length.c: prefix primitive types with der_ + + * der_cmp.c: prefix primitive types with der_ + + * gen_free.c: prefix primitive types with der_ + + * der_free.c: prefix primitive types with der_ + + * gen_copy.c: prefix primitive types with der_ + + * der_copy.c: rename copy_ to der_copy_ + + * Makefile.am: Add der-protos.h to nodist_include_HEADERS. + + * der.h: use newly built + + * Makefile.am: Generate der prototypes. + + * gen.c: move any definitions here. + + * asn1-common.h: move any definitions here. + + * der.h: remove der_parse_oid prototype, it was never implemented. + + * der.h: New der_print_heim_oid signature. Test + der_parse_heim_oid + + * check-der.c: New der_print_heim_oid signature. Test + der_parse_heim_oid + +2006-10-07 Love Hörnquist Åstrand + + * lex.l: Grow an even larger output table size. + + * Makefile.am: split build files into dist_ and noinst_ SOURCES + +2006-10-04 Love Hörnquist Åstrand + + * gen_seq.c: In generation of remove_TYPE: if you just removed the + last element, you must not memmove memory beyond the array. From + Andrew Bartlett + +2006-10-01 Love Hörnquist Åstrand + + * lex.l: Grow (%p, %a, %n) tables for Solaris 10 lex. From Harald + Barth. + +2006-09-24 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): drop unused variable realtype. + +2006-09-11 Love Hörnquist Åstrand + + * Makefile.am: Add KRB5SignedPath and friends. + + * k5.asn1: Add KRB5SignedPath and friends. + + * Makefile.am: Add new sequence generation for GeneralNames. + +2006-09-07 Love Hörnquist Åstrand + + * CMS.asn1 (CMSVersion): rename versions from v0 to CMSVersion_v0, + ... + +2006-09-05 Love Hörnquist Åstrand + + * Makefile.am: Add TESTSeqOf for testing sequence generation code. + + * check-gen.c: Add sequence tests. + + * test.asn1: Add TESTSeqOf for testing sequence generation code. + + * gen_seq.c: fix warning. + + * gen_seq.c: make generated data work + + * setchgpw2.asn1: enctype is part of the krb5 module now, use that + instead of locally defining it. + + * Makefile.am: asn1_compile += gen_seq.c + + * gen_locl.h: add new prototypes, remove unused ones. + + * gen.c: Generate sequence function. + + * main.c: add --sequence + + * gen_seq.c: Add generated add_ and remove_ for "SEQUENCE OF + TType". I'm tried of writing realloc(foo->data, + sizeof(foo->data[0]) + (foo->len + 1)); Only generated for those + type that is enabled by the command flag --sequence. + +2006-08-25 Love Hörnquist Åstrand + + * digest.asn1 (DigestRequest): add authid + + * digest.asn1: Comment describing on how to communicate the sasl + int/conf mode. + +2006-08-23 Love Hörnquist Åstrand + + * digest.asn1: Add some missing fields needed for digest. + +2006-08-21 Love Hörnquist Åstrand + + * digest.asn1: Tweak to make consisten and more easier to use. + +2006-07-20 Love Hörnquist Åstrand + + * Makefile.am: Remove CMS symmetric encryption support. Add + DigestProtocol. + + * digest.asn1: DigestProtocol + + * k5.asn1: Remove CMS symmetric encryption support. + +2006-06-22 Love Hörnquist Åstrand + + * check-der.c (check_fail_heim_integer): disable test + + * der_get.c (der_get_heim_integer): revert part of previous + + * der_get.c (der_get_heim_integer): Add more checks + + * asn1_print.c: Add printing of bignums and use der_print_heim_oid + + * check-der.c (test_heim_oid_format_same): add printing on failure + + * check-der.c: Add one check for heim_int, add checking for oid + printing + +2006-06-06 Love Hörnquist Åstrand + + * Makefile.am: Impersonation support bits (and sort) + + * k5.asn1: Impersonation support bits. + +2006-05-13 Love Hörnquist Åstrand + + * der_format.c (der_parse_hex_heim_integer): avoid shadowing. + +2006-04-29 Love Hörnquist Åstrand + + * Makefile.am: Add ExternalPrincipalIdentifiers, shared between + several elements. + + * pkinit.asn1: Add ExternalPrincipalIdentifiers, shared between + several elements. + +2006-04-28 Love Hörnquist Åstrand + + * parse.y: Add missing ;'s, found by bison on a SuSE 8.2 machine. + +2006-04-26 Love Hörnquist Åstrand + + * Makefile.am: Add definitions from RFC 3820, Proxy Certificate + Profile. + + * rfc2459.asn1: Add definitions from RFC 3820, Proxy Certificate + Profile. + +2006-04-24 Love Hörnquist Åstrand + + * rfc2459.asn1: Add id-Userid + + * Makefile.am: Add UID and email + + * pkcs9.asn1: Add id-pkcs9-emailAddress + + * Makefile.am: Add attribute type oids from X520 and RFC 2247 DC + oid + + * rfc2459.asn1: Add attribute type oids from X520 and RFC 2247 DC + oid + +2006-04-21 Love Hörnquist Åstrand + + * Makefile.am: add sha-1 and sha-2 + + * rfc2459.asn1: add sha-1 and sha-2 + +2006-04-15 Love Hörnquist Åstrand + + * Makefile.am: Add id-pkcs1-sha256WithRSAEncryption and friends + + * rfc2459.asn1: Add id-pkcs1-sha256WithRSAEncryption and friends + + * CMS.asn1: Turn CMSRC2CBCParameter.rc2ParameterVersion into a + constrained integer + +2006-04-08 Love Hörnquist Åstrand + + * hash.c (hashtabnew): check for NULL before setting structure. + Coverity, NetBSD CID#4 + +2006-03-31 Love Hörnquist Åstrand + + * Makefile.am: gen_files_rfc2459 += asn1_ExtKeyUsage.x + + * rfc2459.asn1: Add ExtKeyUsage. + + * gen.c (generate_header_of_codefile): remove unused variable. + +2006-03-30 Love Hörnquist Åstrand + + * gen.c: Put all the IMPORTed headers into the headerfile to avoid + hidden depencies. + +2006-03-27 Love Hörnquist Åstrand + + * Makefile.am: Add id-pkinit-ms-san. + + * pkinit.asn1: Add id-pkinit-ms-san. + + * k5.asn1 (PADATA-TYPE): Add KRB5-PADATA-PA-PK-OCSP-RESPONSE + +2006-03-26 Love Hörnquist Åstrand + + * Makefile.am: Add pkinit-san. + + * pkinit.asn1: Rename id-pksan to id-pkinit-san + +2006-03-08 Love Hörnquist Åstrand + + * gen.c (init_generate): Nothing in the generated files needs + timegm(), so no need to provide a prototype for it. + +2006-02-13 Love Hörnquist Åstrand + + * pkinit.asn1: paChecksum is now OPTIONAL so it can be upgraded to + something better then SHA1 + +2006-01-31 Love Hörnquist Åstrand + + * extra.c: Stub-generator now generates alloc statements for + tagless ANY OPTIONAL, remove workaround. + + * check-gen.c: check for "tagless ANY OPTIONAL" + + * test.asn1: check for "tagless ANY OPTIONAL" + +2006-01-30 Love Hörnquist Åstrand + + * der.h: UniversalString and BMPString are both implemented. + + * der.h: Remove , after the last element of enum. + + * asn1_gen.c: Spelling. + +2006-01-20 Love Hörnquist Åstrand + + * der_length.c (length_heim_integer): Try handle negative length + of integers better. + + * der_get.c (der_get_heim_integer): handle negative integers. + + * check-der.c: check heim_integer. + +2006-01-18 Love Hörnquist Åstrand + + * Makefile.am: Its cRLReason, not cRLReasons + + * canthandle.asn1: "Allocation is done on CONTEXT tags" works just + fine. + + * rfc2459.asn1: Add CRL structures and OIDs. + + * Makefile.am: Add CRL and TESTAlloc structures and OIDs. + + * check-gen.c: Check OPTIONAL context-tagless elements. + + * test.asn1: Check OPTIONAL context-tagless elements. + + * der_cmp.c (heim_integer_cmp): make it work with negative + numbers. + +2006-01-17 Love Hörnquist Åstrand + + * check-der.c: check that der_parse_hex_heim_integer() handles odd + length numbers. + + * der_format.c (der_parse_hex_heim_integer): make more resiliant + to errors, handle odd length numbers. + +2006-01-13 Love Hörnquist Åstrand + + * Makefile.am: Add RSAPrivateKey + + * rfc2459.asn1: Add RSAPrivateKey. + +2006-01-05 Love Hörnquist Åstrand + + * der_copy.c (copy_heim_integer): copy the negative flag + +2005-12-14 Love Hörnquist Åstrand + + * parse.y: Drop ExceptionSpec for now, its not used. + +2005-12-06 Love Hörnquist Åstrand + + * test.asn1: Add test string for constraints. + + * symbol.h: Add support for part of the Constraint-s + + * gen.c: Set new constraints pointer in Type to NULL for inline + constructed types. + + * parse.y: Add support for parsing part of the Constraint-s + +2005-10-29 Love Hörnquist Åstrand + + * Makefile.am: Add some X9.57 (DSA) oids, sort lines + + * rfc2459.asn1: Add some X9.57 (DSA) oids. + +2005-10-07 Love Hörnquist Åstrand + + * Makefile.am: Remove pk-init-19 support. + + * pkinit.asn1: Fix comment + + * check-der.c: Add tests for parse and print functions for + heim_integer. + + * Makefile.am: Add parse and print functions for heim_integer. + + * der_format.c: Add parse and print functions for heim_integer. + + * der.h: Add parse and print functions for heim_integer. + +2005-09-22 Love Hörnquist Åstrand + + * Makefile.am (gen_files_rfc2459) += asn1_DHPublicKey.x + + * rfc2459.asn1: Add DHPublicKey, and INTEGER to for storing the DH + public key in the SubjectPublicKeyInfo.subjectPublicKey BIT + STRING. + +2005-09-20 Love Hörnquist Åstrand + + * gen_decode.c: TSequenceOf/TSetOf: Increase the length of the + array after successful decoding the next element, so that the + array don't contain heap-data. + +2005-09-13 Love Hörnquist Åstrand + + * check-der.c: Avoid empty array initiators. + + * pkcs8.asn1 (PKCS8PrivateKeyInfo): Inline SET OF to avoid + compiler "feature" + + * check-common.c: Avoid signedness warnings. + + * check-common.h: Makes bytes native platform signed to avoid + casting everywhere + + * check-der.c: Don't depend on malloc(very-very-larger-value) will + fail. Cast to unsigned long before printing size_t. + + * check-gen.c: Don't depend on malloc(very-very-larger-value) will + fail. + + * check-gen.c: Fix signedness warnings. + + * lex.l: unput() have to hanppen in actions for flex 2.5.31, can + do them in user code sesction, so move up handle_comment and + handle_string into action, not much sharing was done anyway. + +2005-09-09 Love Hörnquist Åstrand + + * check-der.c (test_one_int): len and len_len is size_t + +2005-08-23 Love Hörnquist Åstrand + + * gen_encode.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + . + + * gen_length.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + . + + * gen_decode.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + . + + * parse.y: Const poision yyerror. + + * gen.c: Const poision. + +2005-08-22 Love Hörnquist Åstrand + + * k5.asn1: Add KRB5-PADATA-PK-AS-09-BINDING, client send + this (with an empty pa-data.padata-value) to tell the KDC that the + client support the binding the PA-REP to the AS-REQ packet. This + is to fix the problem lack of binding the AS-REQ to the PK-AS-REP + in pre PK-INIT-27. The nonce is replaced with a asCheckSum. + +2005-08-11 Love Hörnquist Åstrand + + * canthandle.asn1: Allocation is done on CONTEXT tags. + + * asn1_gen.c: rename optind to optidx to avoid shadow warnings + +2005-07-28 Love Hörnquist Åstrand + + * rfc2459.asn1: add id-rsadsi-rc2-cbc + + * Makefile.am: add another oid for rc2 + +2005-07-27 Love Hörnquist Åstrand + + * check-der.c: Make variable initiation constant by moving them to + global context + + * check-gen.c: change to c89 comment + +2005-07-27 Love Hörnquist Åstrand + + * Makefile.am: remove duplicate asn1_CMSAttributes.x + +2005-07-26 Love Hörnquist Åstrand + + * asn1_print.c: rename optind to optidx + + * Makefile.am: Update to pkinit-27 + + * pkinit.asn1: Update to pkinit-27 + +2005-07-25 Love Hörnquist Åstrand + + * check-der.c: make it work for non c99 compilers too + + * check-der.c: start testing BIT STRING + + * der_cmp.c (heim_bit_string_cmp): try handle corner cases better + + * gen_free.c (free_type): free bignum integers + +2005-07-23 Love Hörnquist Åstrand + + * Makefile.am: add PKCS12-OctetString + + * pkcs12.asn1: add PKCS12-OctetString + + * Makefile.am: add new files + + * rfc2459.asn1: include SET OF in Attribute to make the type more + useful + + * CMS.asn1: handle IMPLICIT and share some common structures + +2005-07-21 Love Hörnquist Åstrand + + * rfc2459.asn1: Include enough workarounds that this even might + work. + + * check-gen.c: Two implicit tests, one with all structures inlined + + * test.asn1: fix workaround for IMPLICIT CONS case + + * canthandle.asn1: fix workaround for IMPLICIT CONS case + + * asn1_print.c: hint that there are IMPLICIT content when we find + it + + * check-gen.c: Added #ifdef out test for IMPLICIT tagging. + + * Makefile.am: test several IMPLICIT tag level deep + + * test.asn1: test several IMPLICIT tag level deep + + * test.asn1: tests for IMPLICIT + + * Makefile.am: tests for IMPLICIT + + * canthandle.asn1: Expand on what is wrong with the IMPLICIT + tagging + + * rfc2459.asn1: some of the structure are in the IMPLICIT TAGS + module + +2005-07-19 Love Hörnquist Åstrand + + * asn1_print.c: print size_t by casting to unsigned long and use + right printf format tags are unsigned integers + + * gen.c (generate_constant): oid elements are unsigned + + * gen_decode.c (decode_type): tagdatalen should be an size_t. + + * extra.c (decode_heim_any): tag is unsigned int. + + * der_get.c (der_match_tag): tag is unsigned int. + + * gen_length.c (length_type): cast size_t argument to unsigned + long and use appropriate printf format + + * check-der.c (check_fail_bitstring): check for length overflow + + * der_get.c: rewrite integer overflow tests w/o SIZE_T_MAX + + * check-common.c (generic_decode_fail): only copy in if checklen + its less then 0xffffff and larger than 0. + + * gen_decode.c (find_tag): find external references, we can't + handle those, so tell user that instead of crashing + +2005-07-18 Dave Love + + * extra.c (free_heim_any_set): Fix return. + + * gen_decode.c (find_tag): Fix return in TType case. + +2005-07-13 Love Hörnquist Åstrand + + * gen_encode.c (TChoice): add () to make sure variable expression + is evaluated correctly + + * gen_length.c (TChoice): add () to make sure variable expression + is evaluated correctly + + * k5.asn1: reapply 1.43 that got lost in the merge: rename pvno to + krb5-pvno + +2005-07-12 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): TChoice: set the label + + * check-gen.c (cmp_Name): do at least some checking + + * gen_locl.h: rename function filename() to get_filename() to + avoid shadowing + + * lex.l: rename function filename() to get_filename() to avoid + shadowing + + * gen.c: rename function filename() to get_filename() to avoid + shadowing + + * check-der.c: add failure checks for large oid elements + + * check-gen.c: add failure checks for tag (and large tags) + + * der_get.c: Check for integer overflows in tags and oid elements. + +2005-07-10 Assar Westerlund + + * gen_decode.c: Fix decoding of choices to select which branch to + try based on the tag and return an error if that branch fails. + + * check-gen.c: Fix short choice test cases. + +2005-07-09 Assar Westerlund + + * symbol.c: + * parse.y: + * main.c: + * lex.l: + * gen_length.c: + * gen_free.c: + * gen_encode.c: + * gen_decode.c: + * gen_copy.c: + * gen.c: + * extra.c: + * check-gen.c: + * check-der.c: + * check-common.c: + * asn1_print.c: + * asn1_gen.c: + Use emalloc, ecalloc, and estrdup. + Check return value from asprintf. + Make sure that malloc(0) returning NULL is not treated as an + error. + +2005-07-10 Love Hörnquist Åstrand + + * check-gen.c: test cases for CHOICE, its too liberal right now, + it don't fail hard on failure on after it successfully decoded the + first tag in a choice branch + + * asn1_gen.c: calculate the basename for the output file, + pretty-print tag number + + * test.gen: sample for asn1_gen + + * check-gen.c: check errors in SEQUENCE + + * Makefile.am: build asn1_gen, TESTSeq and new, and class/type/tag + string<->num converter. + + * test.asn1: TESTSeq, for testing SEQUENCE + + * asn1_gen.c: generator for asn1 data + + * asn1_print.c: use class/type/tag string<->num converter. + + * der.c: Add class/type/tag string<->num converter. + + * der.h: Add class/type/tag string<->num converter. + Prototypes/structures for new time bits. + +2005-07-09 Love Hörnquist Åstrand + + * der_get.c (der_get_unsigned) check for length overflow + (der_get_integer) ditto + (der_get_general_string) ditto + + * der_get.c: check for overruns using SIZE_T_MAX + + * check-der.c: check BIT STRING and OBJECT IDENTIFIER error cases + + * check-common.c (generic_decode_fail): allocate 4K for the over + sized memory test + + * der_get.c (der_get_oid): check for integer overruns and + unterminated oid correctly + + * check-common.h (map_alloc, generic_decode_fail): prototypes + + * check-common.c (map_alloc): make input buffer const + (generic_decode_fail): verify decoding failures + +2005-07-05 Love Hörnquist Åstrand + + * gen_encode.c: split up the printf for SET OF, also use the + generate name for the symbol in the SET OF, if not, the name might + contain non valid variable name characters (like -) + +2005-07-04 Love Hörnquist Åstrand + + * Makefile.am: move pkcs12 defines into their own namespace + + * pkcs12.asn1: move pkcs12 defines into their own namespace + + * pkcs9.asn1: add PKCS9-friendlyName with workaround for SET OF + bug + + * heim_asn1.h: reuse heim_octet_string for heim_any types + + * main.c: use optidx, handle the case where name is missing and + use base of filename then + + * asn1-common.h: include ASN1_MALLOC_ENCODE + + * gen_decode.c: use less context so lower indentention level, add + missing {} where needed + +2005-07-02 Love Hörnquist Åstrand + + * gen_copy.c: Use a global variable to keep track of if the 'goto + fail' was used, and use that to only generate the label if needed. + + * asn1_print.c: do indefinite form loop detection and stop after + 10000 recursive indefinite forms, stops crashing due to running + out of stack + + * asn1_print.c: catch badly formated indefinite length data + (missing EndOfContent tag) add (negative) indent flag to speed up + testing + +2005-07-01 Love Hörnquist Åstrand + + * canthandle.asn1: Can't handle primitives in CHOICE + + * gen_decode.c: Check if malloc failes + + * gen_copy.c: Make sure to free memory on failure + + * gen_decode.c: Check if malloc failes, rename "reallen" to + tagdatalen since that is what it is. + +2005-05-29 Love Hörnquist Åstrand + + * prefix Der_class with ASN1_C_ to avoid problems with system + headerfiles that pollute the name space + +2005-05-20 Love Hörnquist Åstrand + + * pkcs12.asn1: add PKCS12CertBag + + * pkcs9.asn1: add pkcs9 certtype x509 certificate + + * Makefile.am: add pkcs12 certbag and pkcs9 certtype x509 + certificate + + * pkcs12.asn1: split off PKCS12Attributes from SafeBag so it can + be reused + + * Makefile.am: add PKCS12Attributes + +2005-05-10 Love Hörnquist Åstrand + + * canthandle.asn1: fix tags in example + +2005-05-02 Love Hörnquist Åstrand + + * pkinit.asn1: Let the Windows nonce be an int32 (signed), if not + it will fail when using Windows PK-INIT. + +2005-05-01 Love Hörnquist Åstrand + + * Makefile.am: add pkcs12-PBEParams + + * pkcs12.asn1: add pkcs12-PBEParams + + * parse.y: objid_element: exit when the condition fails + +2005-04-26 Love Hörnquist Åstrand + + * gen_glue.c: 1.8: switch the units variable to a + function. gcc-4.1 needs the size of the structure if its defined + as extern struct units foo_units[] an we don't want to include + in the generate headerfile + +2005-03-20 Love Hörnquist Åstrand + + * Makefile.am: add the des-ede3-cbc oid that ansi x9.52 uses + + * rfc2459.asn1: add the des-ede3-cbc oid that ansi x9.52 uses + + * Makefile.am: add oids for x509 + + * rfc2459.asn1: add oids now when the compiler can handle them + +2005-03-19 Love Hörnquist Åstrand + + * Makefile.am: add pkcs9 files + + * pkcs9.asn1: add small number of oids from pkcs9 + +2005-03-14 Love Hörnquist Åstrand + + * Makefile.am: add a bunch of pkcs1/pkcs2/pkcs3/aes oids + + * rfc2459.asn1: add a bunch of pkcs1/pkcs2/pkcs3/aes oids + +2005-03-10 Love Hörnquist Åstrand + + * k5.asn1: merge pa-numbers + +2005-03-09 Love Hörnquist Åstrand + + * Makefile.am: add oid's + + * rfc2459.asn1: add encryption oids + + * CMS.asn1: add signedAndEnvelopedData oid + + * pkcs12.asn1: add pkcs12 oids + + * CMS.asn1: add pkcs7 oids + +2005-03-08 Love Hörnquist Åstrand + + * gen.c (generate_header_of_codefile): break out the header + section generation + (generate_constant): generate a function that return the oid + inside a heim_oid + + * parse.y: fix the ordering of the oid's + + * parse.y: handle OBJECT IDENTIFIER as value construct + +2005-02-24 Love Hörnquist Åstrand + + * Preserve content of CHOICE element that is unknown if ellipsis + was used when defining the structure + +2005-02-13 Love Hörnquist Åstrand + + * parse.y: use ANS1_TAILQ macros + + * *.[ch]: use ASN1_TAILQ macros + + * asn1_queue.h: inline bsd sys/queue.h and rename TAILQ to + ASN1_TAILQ to avoid problems with name polluting headerfiles + +2005-01-19 Love Hörnquist Åstrand + + * gen.c: pull in + +2005-01-10 Love Hörnquist Åstrand + + * Add BMPString and UniversalString + + * k5.asn1 (EtypeList): make INTEGER constrained (use krb5int32) + +2005-01-07 Love Hörnquist Åstrand + + * rfc2459.asn1: add GeneralNames + +2004-11-21 Love Hörnquist Åstrand + + * gen.c: use unsigned integer for len of SequenceOf/SetOf and + bitstring names + +2004-11-10 Love Hörnquist Åstrand + + * Makefile.am: switch to krb5int32 and krb5uint32 + + * Unify that three integer types TInteger TUInteger and TBigInteger. + Start to use constrained integers where appropriate. + +2004-10-13 Love Hörnquist Åstrand + + * CMS.asn1: remove no longer used commented out elements + + * gen_glue.c: make units structures const + +2004-10-12 Love Hörnquist Åstrand + + * lex.l: handle hex number with [a-fA-F] in them + +2004-10-07 Love Hörnquist Åstrand + + * gen_free.c: free _save for CHOICE too + + * rfc2459.asn1: use Name and not heim_any + + * gen_decode.c: if malloc for _save failes, goto fail so we free + the structure + + * gen_copy.c: copy _save for CHOICE too + + * gen.c: add _save for CHOICE too + + * CMS.asn1: RecipientIdentifier and SignerIdentifier is the same + name is CMSIdentifier and add glue for that so we can share code + use Name and not heim_any + +2004-10-03 Love Hörnquist Åstrand + + * Makefile.am: drop AlgorithmIdentifierNonOpt add + {RC2CBC,}CBCParameter here where they belong + + * CMS.asn1: add {RC2CBC,}CBCParameter here where they belong + + * rfc2459.asn1: drop AlgorithmIdentifierNonOpt + + * rfc2459.asn1: stop using AlgorithmIdentifierNonOpt hint that we + really want to use Name and some MS stuff + +2004-09-05 Love Hörnquist Åstrand + + * asn1_print.c: handle end of content, this is part BER support, + however, OCTET STRING need some tweeking too. + + * der.h: add UT_EndOfContent + + * test.asn1: test asn1 spec file + + * check-gen.c: check larget tags + + * Makefile.am: add test asn1 spec file that we can use for testing + constructs that doesn't exists in already existing spec (like + large tags) + + * der_put.c (der_put_tag): make sure there are space for the head + tag when we are dealing with large tags (>30) + + * check-gen.c: add test for tag length + + * check-common.c: export the map_ functions for OVERRUN/UNDERRUN + detection restore the SIGSEGV handler when test is done + + * check-common.h: export the map_ functions for OVERRUN/UNDERRUN + detection + + * gen_decode.c: check that the tag-length is not longer the length + use forwstr on some more places + + * parse.y: revert part of 1.14.2.21, multiple IMPORT isn't allowed + + * pkinit.asn1: correct usage of IMPORT + + * CMS.asn1: correct usage of IMPORT + + * pkcs8.asn1: pkcs8, encrypting private key + + * pkcs12.asn1: pkcs12, key/crl/certificate file transport PDU + + * Makefile.am: add pkcs8 and pkcs12 + + * der_free.c: reset length when freing primitives + + * CMS.asn1: add EncryptedData + +2004-08-26 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): if the entry is already optional + when parsing a tag and we allocate the structure, not pass down + optional since that will case the subtype's decode_type also to + allocate an entry. and we'll leak an entry. Bug from Luke Howard + . While here, use calloc. + +2004-04-29 Love Hörnquist Åstrand + + * k5.asn1: shift the last added etypes one step so rc2 doesn't + stomp on cram-md5 + +2004-04-26 Love Hörnquist Åstrand + + * k5.asn1: add ETYPE_AESNNN_CBC_NONE + + * CMS.asn1: add CMS symmetrical parameters moved to k5.asn1 + + * k5.asn1: add CMS symmetrical parameters here, more nametypes + enctype rc2-cbc + +2004-04-25 Love Hörnquist Åstrand + + * gen_decode.c: free data on decode failure + +2004-04-24 Love Hörnquist Åstrand + + * Makefile.am: add CBCParameter and RC2CBCParameter + + * CMS.asn1: add CBCParameter and RC2CBCParameter + +2004-04-20 Love Hörnquist Åstrand + + * check-der.c: add simple test for oid's, used to trigger malloc + bugs in you have picky malloc (like valgrind/purify/third) + + * der_get.c (der_get_oid): handle all oid components being smaller + then 127 and allocate one extra element since first byte is split + to to elements. + +2004-04-16 Love Hörnquist Åstrand + + * canthandle.asn1: one thing handled + + * gen_decode.c: handle OPTIONAL CONS-tag-less elements + + * der_length.c (length_len): since length is no longer the same as + an unsigned, do the length counting here. ("unsigned" is zero + padded when most significate bit is set, length is not) + +2004-04-12 Love Hörnquist Åstrand + + * canthandle.asn1: document by example what the encoder can't + handle right now + + * Makefile.am: add more stuff needed whem implementing x509 + preserve TBSCertificate + + * rfc2459.asn1: add more stuff needed whem implementing x509 + + * CMS.asn1: move some type to rfc2459.asn1 where they belong (and + import them) + + * gen.c: preserve the raw data when asked too + + * gen_decode.c: preserve the raw data when asked too + + * gen_copy.c: preserve the raw data when asked too + + * gen_free.c: preserve the raw data when asked too + + * gen_locl.h: add preserve_type + + * heim_asn1.h: add heim_any_cmp + + * main.c: add flag --preserve-binary=Symbol1,Symbol2,... that make + the compiler generate stubs to save the raw data, its not used + right now when generating the stat + + * k5.asn1: Windows uses PADATA 15 for the request too + + * extra.c: add heim_any_cmp + + * der_put.c: implement UTCtime correctly + + * der_locl.h: remove #ifdef HAVE_TIMEGM\ntimegm\n#endif here from + der.h so one day der.h can get installed + + * der_length.c: implement UTCtime correctly + + * der_get.c: implement UTCtime correctly, prefix dce_fix with + _heim_fix + + * der_copy.c: make copy_bit_string work again + + * der_cmp.c: add octet_string, integer, bit_string cmp functions + + * der.h: hide away more symbols, add more _cmp functions + +2004-03-06 Love Hörnquist Åstrand + + * Makefile.am: add more pkix types make k5 use rfc150 bitstrings, + everything else use der bitstrings + + * main.c: as a compile time option, handle no rfc1510 bitstrings + + * gen_locl.h: rfc1510 bitstrings flag + + * gen_length.c: as a compile time option, handle no rfc1510 + bitstrings + + * gen_encode.c: as a compile time option, handle no rfc1510 + bitstrings + + * gen_decode.c: handle no rfc1510 bitstrings + + * check-gen.c: test for bitstrings + + * rfc2459.asn1: add Certificates and KeyUsage + +2004-02-22 Love Hörnquist Åstrand + + * pkinit.asn1: use Name from PKIX + + * rfc2459.asn1: add more silly string types to DirectoryString + + * gen_encode.c: add checks for data overflow when encoding + TBitString with members encode SET OF correctly by bytewise + sorting the members + + * gen_decode.c: add checks for data overrun when encoding + TBitString with members + + * der_put.c: add _heim_der_set_sort + + * der_cmp.c: rename oid_cmp to heim_oid_cmp + + * der.h: rename oid_cmp to heim_oid_cmp, add _heim_der_set_sort + + * check-gen.c: add check for Name and (commented out) heim_integer + + * check-der.c: test for "der_length.c: Fix len_unsigned for + certain negative integers, it got the length wrong" , from + Panasas, Inc. + + * der_length.c: Fix len_unsigned for certain negative integers, it + got the length wrong, fix from Panasas, Inc. + + rename len_int and len_unsigned to _heim_\& + + * gen_length.c: 1.14: (length_type): TSequenceOf: add up the size + of all the elements, don't use just the size of the last element. + +2004-02-20 Love Hörnquist Åstrand + + * rfc2459.asn1: include defintion of Name + + * pkinit.asn1: no need for ContentType, its cms internal + + * CMS.asn1: move ContentInfo to CMS + + * pkinit.asn1: update to pk-init-18, move ContentInfo to CMS + + * Makefile.am: align with pk-init-18, move contentinfo to cms + +2004-02-17 Love Hörnquist Åstrand + + * der_get.c: rewrite previous commit + + * der_get.c (der_get_heim_integer): handle positive integer + starting with 0 + + * der_length.c (der_put_heim_integer): try handle negative + integers better (?) + + * der_put.c (der_put_heim_integer): try handle negative integers + better + + * der_get.c (der_get_heim_integer): dont abort on negative integer just + return ASN1_OVERRUN for now + + * parse.y: add ia5string, and printablestring + + * gen_length.c: add ia5string, and printablestring + + * gen_free.c: add ia5string, and printablestring + + * gen_decode.c: add ia5string, and printablestring + + * gen_copy.c: add ia5string, and printablestring + + * gen.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_put.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_length.c: add ia5string, printablestring, and utf8string + change implemetation of heim_integer and store the data as + bigendian byte array with a external flag for signedness + + * der_get.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_free.c: add ia5string, printablestring, and utf8string + + * der_copy.c: add ia5string, printablestring, and utf8string + + * der.h: add ia5string, printablestring, and utf8string + + * asn1-common.h: add signedness flag to heim_integer, add + ia5string and printablestring + +2004-02-13 Love Hörnquist Åstrand + + * rfc2459.asn1: use BIGINTEGER where appropriate + + * setchgpw2.asn1: spelling and add op-req again + +2004-02-12 Love Hörnquist Åstrand + + * Makefile.am: clean up better + +2004-02-11 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): TTag, don't overshare the reallen + variable + + * Makefile.am: adapt to log file name change + + * gen.c: genereate log file name based on base name + +2003-11-26 Love Hörnquist Åstrand + + * Makefile.am: += asn1_AlgorithmIdentifierNonOpt.x + + * rfc2459.asn1: add AlgorithmIdentifierNonOpt and use it where + it's needed, make DomainParameters.validationParms heim_any as a + hack. Both are workarounds for the problem with heimdal's asn1 + compiler have with decoing context tagless OPTIONALs. + + * pkinit.asn1: don't import AlgorithmIdentifier + +2003-11-25 Love Hörnquist Åstrand + + * der_put.c (der_put_bit_string): make it work somewhat better + (should really prune off all trailing zeros) + + * gen_encode.c (encode_type): bit string is not a constructed type + + * der_length.c (length_bit_string): calculate right length for + bitstrings + +2003-11-24 Love Hörnquist Åstrand + + * der_cmp.c (oid_cmp): compare the whole array, not just + length/sizeof(component) + + * check-common.c: mmap the scratch areas, mprotect before and + after, align data to the edge of the mprotect()ed area to provoke + bugs + + * Makefile.am: add DomainParameters, ValidationParms + + * rfc2459.asn1: add DomainParameters, ValidationParms + + * check-der.c: add free function + + * check-common.h: add free function + + * check-common.c: add free function + + * check-gen.c: check KRB-ERROR + + * asn1_print.c: check end of tag_names loop into APPL class tags + +2003-11-23 Love Hörnquist Åstrand + + * der_put.c (der_put_generalized_time): check size, not *size + +2003-11-11 Love Hörnquist Åstrand + + * gen_decode.c (decode_type/TBitString): skip over + skipped-bits-in-last-octet octet + + * gen_glue.c (generate_units): generate units in reverse order to + keep unparse_units happy + +2003-11-08 Love Hörnquist Åstrand + + * Makefile.am: generate all silly pkinit files + + * pkinit.asn1: make it work again, add strange ms structures + + * k5.asn1: PROV-SRV-LOCATION, PacketCable provisioning server + location, PKT-SP-SEC-I09-030728 + + * asn1-common.h: add bit string + + * der_put.c: add bit string and utctime + + * gen.c: add bit string and utctime + + * gen_copy.c: add bit string and utctime + + * der_copy.c: add bit string + + * gen_decode.c: add utctime and bitstring + + * gen_encode.c: add utctime and bitstring + + * gen_free.c: add utctime and bitstring + + * gen_glue.c: don't generate glue for member-less bit strings + + * der_cmp.c: compare function for oids + + * gen_length.c: add utc time, make bit string work for bits + strings w/o any members + + * der_cmp.c: compare function for oids + + * der.h: update boolean prototypes add utctime and bit_string + + * der_free.c: add free_bit_string + + * der_get.c: add bit string and utctime + + * der_length.c: add bit string and utctime, fix memory leak in + length_generalized_time + + * CMS.asn1: make EncryptedContentInfo.encryptedContent a OCTET + STRING to make the generator do the right thing with IMPLICIT + mumble OPTIONAL, make CertificateSet a heim_any_set + + * extra.c, heim_asn1.h: add any_set, instead of just consuming one + der object, its consumes the rest of the data avaible + + * extra.c, heim_asn1.h: extern implementation of ANY, decoder + needs to have hack removed when generator handles tagless optional + data + + * pkinit.asn1: add KdcDHKeyInfo-Win2k + +2003-11-07 Love Hörnquist Åstrand + + * der_copy.c (copy_oid): copy all components + + * parse.y: parse UTCTime, allow multiple IMPORT + + * symbol.h: add TUTCTime + + * rfc2459.asn1: update + + * x509.asn1: update + + * pkinit.asn1: update + + * CMS.asn1: new file + + * asn1_print.c: print some more lengths, check length before + steping out in the void, parse SET, only go down CONTEXT of type + CONS (not PRIM) + +2003-09-17 Love Hörnquist Åstrand + + * gen_encode.c (TChoice, TSequence): code element in reverse + order... + +2003-09-16 Love Hörnquist Åstrand + + * gen.c: store NULL's as int's for now + + * parse.y: remove dup of type def of UsefulType + +2003-09-11 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): if malloc failes, return ENOMEM + +2003-09-10 Love Hörnquist Åstrand + + * parse.y: kw_UTF8String is a token put tag around the OID + + * asn1_print.c (UT_Integer): when the integer is larger then int + can handle, just print BIG INT and its size + +2003-09-10 Love Hörnquist Åstrand + + * gen_decode.c (decode_type): TTag, try to generate prettier code + in the non optional case, also remember to update length + +2003-01-22 Johan Danielsson + + * gen_decode.c: add flag to decode broken DCE BER encoding + + * gen_locl.h: add flag to decode broken DCE BER encoding + + * main.c: add flag to decode broken DCE BER encoding + diff --git a/third_party/heimdal/lib/asn1/MANUAL.md b/third_party/heimdal/lib/asn1/MANUAL.md new file mode 100644 index 0000000..89c452a --- /dev/null +++ b/third_party/heimdal/lib/asn1/MANUAL.md @@ -0,0 +1,1287 @@ +# Introduction + +Heimdal is an implementation of PKIX and Kerberos. As such it must handle the +use of [Abstract Syntax Notation One (ASN.1)](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en) +by those protocols. ASN.1 is a language for describing the schemata of network +protocol messages. Associated with ASN.1 are the ASN.1 Encoding Rules (ERs) +that specify how to encode such messages. + +In short: + + - ASN.1 is just a _schema description language_ + + - ASN.1 Encoding Rules are specifications for encoding formats for values of + types described by ASN.1 schemas ("modules") + +Similar languages include: + + - [DCE RPC's Interface Description Language (IDL)](https://pubs.opengroup.org/onlinepubs/9629399/chap4.htm#tagcjh_08) + - [Microsoft Interface Description Language (IDL)](https://docs.microsoft.com/en-us/windows/win32/midl/midl-start-page) + (MIDL is derived from the DCE RPC IDL) + - ONC RPC's eXternal Data Representation (XDR) [RFC4506](https://datatracker.ietf.org/doc/html/rfc4506) + - [XML Schema](https://en.wikipedia.org/wiki/XML_schema) + - Various JSON schema languages + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Similar encoding rules include: + + - DCE RPC's [NDR](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm) + - ONC RPC's [XDR](https://datatracker.ietf.org/doc/html/rfc4506) + - XML + - FastInfoSet + - JSON + - CBOR + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - [Flat Buffers](https://google.github.io/flatbuffers/) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Many such languages are quite old. ASN.1 itself dates to the early 1980s, with +the first specification published in 1984. XDR was first published in 1987. +IDL's lineage dates back to sometime during the 1980s, via the Apollo Domain +operating system. + +ASN.1 is standardized by the International Telecommunications Union (ITU-T), +and has continued evolving over the years, with frequent updates. + +The two most useful and transcending features of ASN.1 are: + + - the ability to formally express what some know as "open types", "typed + holes", or "references"; + + - the ability to add encoding rules over type, which for ASN.1 includes: + + - binary, tag-length-value (TLV) encoding rules + - binary, non-TLV encoding rules + - textual encoding rules using XML and JSON + - an ad-hoc generic text-based ER called GSER + + In principle ASN.1 can add encoding rules that would allow it to + interoperate with many others, such as: CBOR, protocol buffers, flat + buffers, NDR, and others. + + Readers may recognize that some alternatives to ASN.1 have followed a + similar arc. For example, Protocol Buffers was originally a syntax and + encoding, and has become a syntax and set of various encodings (e.g., Flat + Buffers was added later). And XML has FastInfoSet as a binary encoding + alternative to XML's textual encoding. + +As well, ASN.1 has [high-quality, freely-available specifications](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en). + +## ASN.1 Example + +For example, this is a `Certificate` as used in TLS and other protocols, taken +from [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280): + + ```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } + ``` + +and the same `Certificate` taken from a more modern version -from +[RFC5912](https://datatracker.ietf.org/doc/html/rfc5912)- using newer features +of ASN.1: + + ```ASN.1 + Certificate ::= SIGNED{TBSCertificate} + + TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, + {SignatureAlgorithms}}, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + ... , + [[2: + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + ]], + [[3: + extensions [3] Extensions{{CertExtensions}} OPTIONAL + ]], ... + } + ``` + +As you can see, a `Certificate` is a structure containing a to-be-signed +sub-structure, and a signature of that sub-structure, and the sub-structure +has: a version number, a serial number, a signature algorithm, an issuer name, +a validity period, a subject name, a public key for the subject name, "unique +identifiers" for the issuer and subject entities, and "extensions". + +To understand more we'd have to look at the types of those fields of +`TBSCertificate`, but for now we won't do that. The point here is to show that +ASN.1 allows us to describe "types" of data in a way that resembles +"structures", "records", or "classes" in various programming languages. + +To be sure, there are some "noisy" artifacts in the definition of +`TBSCertificate` which mostly have to do with the original encoding rules for +ASN.1. The original encoding rules for ASN.1 were tag-length-value (TLV) +binary encodings, meaning that for every type, the encoding of a value of that +type consisted of a _tag_, a _length_ of the value's encoding, and the _actual +value's encoding_. Over time other encoding rules were added that do not +require tags, such as the octet encoding rules (OER), but also JSON encoding +rules (JER), XML encoding rules (XER), and others. There is almost no need for +tagging directives like `[1] IMPLICIT` when using OER. But in existing +protocols like PKIX and Kerberos that date back to the days when DER was king, +tagging directives are unfortunately commonplace. + +## ASN.1 Crash Course + +This is not a specification. Readers should refer to the ITU-T's X.680 base +specification for ASN.1's syntax. + +A schema is called a "module". + +A module looks like: + +```ASN.1 +-- This is a comment + +-- Here's the name of the module, here given as an "object identifier" or +-- OID: +PKIXAlgs-2009 { iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-pkix1-algorithms2008-02(56) } + + +-- `DEFINITIONS` is a required keyword +-- `EXPLICIT TAGS` will be explained later +DEFINITIONS EXPLICIT TAGS ::= +BEGIN +-- list exported types, or `ALL`: +EXPORTS ALL; +-- import some types: +IMPORTS PUBLIC-KEY, SIGNATURE-ALGORITHM, ... FROM AlgorithmInformation-2009 + mda-sha224, mda-sha256, ... FROM PKIX1-PSS-OAEP-Algorithms-2009; + +-- type definitions follow: +... + +END +``` + +Type names start with capital upper-case letters. Value names start with +lower-case letters. + +Type definitions are of the form `TypeName ::= TypeDefinition`. + +Value (constant) definitions are of the form `valueName ::= TypeName `. + +There are some "universal" primitive types (e.g., string types, numeric types), +and several "constructed" types (arrays, structures. + +Some useful primitive types include `BOOLEAN`, `INTEGER` and `UTF8String`. + +Structures are either `SEQUENCE { ... }` or `SET { ... }`. The "fields" of +these are known as "members". + +Arrays are either `SEQUENCE OF SomeType` or `SET OF SomeType`. + +A `SEQUENCE`'s elements or members are ordered, while a `SET`'s are not. In +practice this means that for _canonical_ encoding rules a `SET OF` type's +values must be sorted, while a `SET { ... }` type's members need not be sorted +at run-time, but are sorted by _tag_ at compile-time. + +Anonymous types are supported, such as `SET OF SET { a A, b B }` (which is a +set of structures with an `a` field (member) of type `A` and a `b` member of +type `B`). + +The members of structures can be `OPTIONAL` or have a `DEFAULT` value. + +There are also discriminated union types known as `CHOICE`s: `U ::= CHOICE { a +A, b B, c C }` (in this case `U` is either an `A`, a `B`, or a `C`. + +Extensibility is supported. "Extensibility" means: the ability to add new +members to structures, new alternatives to discriminated unions, etc. For +example, `A ::= SEQUENCE { a0 A0, a1 A1, ... }` means that type `A` is a +structure that has two fields and which may have more fields added in future +revisions, therefore decoders _must_ be able to receive and decode encodings of +extended versions of `A`, even encoders produced prior to the extensions being +specified! (Normally a decoder "skips" extensions it doesn't know about, and +the encoding rules need only make it possible to do so.) + +## TLV Encoding Rules + +The TLV encoding rules for ASN.1 are: + + - Basic Encoding Rules (BER) + - Distinguished Encoding Rules (DER), a canonical subset of BER + - Canonical Encoding Rules (CER), another canonical subset of BER + +"Canonical" encoding rules yield just one way to encode any value of any type, +while non-canonical rules possibly yield many ways to encode values of certain +types. For example, JSON is not a canonical data encoding. A canonical form +of JSON would have to specify what interstitial whitespace is allowed, a +canonical representation of strings (which Unicode codepoints must be escaped +and in what way, and which must not), and a canonical representation of decimal +numbers. + +It is important to understand that originally ASN.1 came with TLV encoding +rules, and some considerations around TLV encoding rules leaked into the +language. For example, `A ::= SET { a0 [0] A0, a1 [1] A1 }` is a structure +that has two members `a0` and `a1`, and when encoded those members will be +tagged with a "context-specific" tags `0` and `1`, respectively. + +Tags only have to be specified when needed to disambiguate encodings. +Ambiguities arise only in `CHOICE` types and sometimes in `SEQUENCE`/`SET` +types that have `OPTIONAL`/`DEFAULT`ed members. + +In modern ASN.1 it is possible to specify that a module uses `AUTOMATIC` +tagging so that one need never specify tags explicitly in order to fix +ambiguities. + +Also, there are two types of tags: `IMPLICIT` and `EXPLICIT`. Implicit tags +replace the tags that the tagged type would have otherwise. Explicit tags +treat the encoding of a type's value (including its tag and length) as the +value of the tagged type, thus yielding a tag-length-tag-length-value encoding +-- a TLTLV encoding! + +Thus explicit tagging is more redundant and wasteful than implicit tagging. +But implicit tagging loses metadata that is useful for tools that can decode +TLV encodings without reference to the schema (module) corresponding to the +types of values encoded. + +TLV encodings were probably never justified except by lack of tooling and +belief that codecs for TLV ERs can be hand-coded. But TLV RTs exist, and +because they are widely used, cannot be removed. + +## Other Encoding Rules + +The Packed Encoding Rules (PER) and Octet Encoding Rules (OER) are rules that +resemble XDR, but with a 1-byte word size instead of 4-byte word size, and also +with a 1-byte alignment instead of 4-byte alignment, yielding space-efficient +encodings. + +Hand-coding XDR codecs is quite common and fairly easy. Hand-coding PER and +OER is widely considered difficult because PER and OER try to be quite +space-efficient. + +Hand-coding TLV codecs used to be considered easy, but really, never was. + +But no one should hand-code codecs for any encoding rules. + +Instead, one should use a compiler. This is true for ASN.1, and for all schema +languages. + +## Encoding Rule Specific Syntactic Forms + +Some encoding rules require specific syntactic forms for some aspects of them. + +For example, the JER (JSON Encoding Rules) provide for syntax to select the use +of JSON arrays vs. JSON objects for encoding structure types. + +For example, the TLV encoding rules provide for syntax for specifying +alternative tags for disambiguation. + +## ASN.1 Syntax Specifications + + - The base specification is ITU-T + [X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en). + + - Additional syntax extensions include: + + - [X.681 ASN.1 Information object specification](https://www.itu.int/rec/T-REC-X.681/en) + - [X.682 ASN.1 Constraint specification](https://www.itu.int/rec/T-REC-X.682/en) + - [X.682 ASN.1 Parameterization of ASN.1 specifications](https://www.itu.int/rec/T-REC-X.683/en) + + Together these three specifications make the formal specification of open + types possible. + +## ASN.1 Encoding Rules Specifications + + - The TLV Basic, Distinguished, and Canonical Encoding Rules (BER, DER, CER) + are described in ITU-T [X.690](https://www.itu.int/rec/T-REC-X.690/en). + + - The more flat-buffers/XDR-like Packed Encoding Rules (PER) are described in + ITU-T [X.691](https://www.itu.int/rec/T-REC-X.691/en), and its successor, + the Octet Encoding Rules (OER) are described in + [X.696](https://www.itu.int/rec/T-REC-X.692/en). + + - The XML Encoding Rules (XER) are described in ITU-T + [X.693](https://www.itu.int/rec/T-REC-X.693/en). + + Related is the [X.694 Mapping W3C XML schema definitions into ASN.1](https://www.itu.int/rec/T-REC-X.694/en) + + - The JSON Encoding Rules (JER) are described in ITU-T + [X.697](https://www.itu.int/rec/T-REC-X.697/en). + + - The Generic String Encoding Rules are specified by IETF RFCs + [RFC3641](https://datatracker.ietf.org/doc/html/rfc3641), + [RFC3642](https://datatracker.ietf.org/doc/html/rfc3642), + [RFC4792](https://datatracker.ietf.org/doc/html/rfc4792). + +Additional ERs can be added. + +For example, XDR can clearly encode a very large subset of ASN.1, and with a +few additional conventions, all of ASN.1. + +NDR too can clearly encode a very large subset of ASN.1, and with a few +additional conventions, all of ASN. However, ASN.1 is not sufficiently rich a +_syntax_ to express all of what NDR can express (think of NDR conformant and/or +varying arrays), though with some extensions it could. + +## Commentary + +The text in this section is the personal opinion of the author(s). + + - ASN.1 gets a bad rap because BER/DER/CER are terrible encoding rules, as are + all TLV encoding rules. + + The BER family of encoding rules is a disaster, yes, but ASN.1 itself is + not. On the contrary, ASN.1 is quite rich in features and semantics -as + rich as any competitor- while also being very easy to write and understand + _as a syntax_. + + - ASN.1 also gets a bad rap because its full syntax is not context-free, and + so parsing it can be tricky. + + And yet the Heimdal ASN.1 compiler manages, using LALR(1) `yacc`/`bison`/`byacc` + parser-generators. For the subset of ASN.1 that this compiler handles, + there are no ambiguities. However, we understand that eventually we will + need run into ambiguities. + + For example, `ValueSet` and `ObjectSet` are ambiguous. X.680 says: + + ``` + ValueSet ::= "{" ElementSetSpecs "}" + ``` + + while X.681 says: + + ``` + ObjectSet ::= "{" ObjectSetSpec "}" + ``` + + and the set members can be just the symbolic names of members, in which case + there's no grammatical difference between those two productions. These then + cause a conflict in the `FieldSetting` production, which is used in the + `ObjectDefn` production, which is used in defining an object (which is to be + referenced from some `ObjectSet` or `FieldSetting`). + + This particular conflict can be resolved by one of: + + - limiting the power of object sets by disallowing recursion (object sets + containing objects that have field settings that are object sets ...), + + - or by introducing additional required and disambiguating syntactic + elements that preclude full compliance with ASN.1, + + - or by simply using the same production and type internally to handle + both, the `ValueSet` and `ObjectSet` productions and then internally + resolving the actual type as late as possible by either inspecting the + types of the set members or by inspecting the expected kind of field that + the `ValueSet`-or-`ObjectSet` is setting. + + Clearly, only the last of these is satisfying, but it is more work for the + compiler developer. + + - TLV encodings are bad because they yield unnecessary redundance in + encodings. This is space-inefficient, but also a source of bugs in + hand-coded codecs for TLV encodings. + + EXPLICIT tagging makes this worse by making the encoding a TLTLV encoding + (tag length tag length value). (The inner TLV is the V for the outer TL.) + + - TLV encodings are often described as "self-describing" because one can + usually write a `dumpasn1` style of tool that attempts to decode a TLV + encoding of a value without reference to the value's type definition. + + The use of `IMPLICIT` tagging with BER/DER/CER makes schema-less `dumpasn1` + style tools harder to use, as some type information is lost. E.g., a + primitive type implicitly tagged with a context tag results in a TLV + encoding where -without reference to the schema- the tag denotes no + information about the type of the value encoded. The user is left to figure + out what kind of data that is and to then decode it by hand. For + constructed types (arrays and structures), implicit tagging does not really + lose any metadata about the type that wasn't already lost by BER/DER/CER, so + there is no great loss there. + + However, Heimdal's ASN.1 compiler includes an `asn1_print(1)` utility that + can print DER-encoded values in much more detail than a schema-less + `dumpasn1` style of tool can. This is because `asn1_print(1)` includes + a number of compiled ASN.1 modules, and it can be extended to include more. + + - There is some merit to BER, however. Specifically, an appropriate use of + indeterminate length encoding with BER can yield on-line encoding. Think of + encoding streams of indeterminate size -- this cannot be done with DER or + Flat Buffers, or most encodings, though it can be done with some encodings, + such as BER and NDR (NDR has "pipes" for this). + + Some clues are needed in order to produce an codec that can handle such + on-line behavior. In IDL/NDR that clue comes from the "pipe" type. In + ASN.1 there is no such clue and it would have to be provided separately to + the ASN.1 compiler (e.g., as a command-line option). + + - Protocol Buffers is a TLV encoding. There was no need to make it a TLV + encoding. + + Public opinion seems to prefer Flat Buffers now, which is not a TLV encoding + and which is more comparable to XDR/NDR/PER/OER. + +# Heimdal ASN.1 Compiler + +The Heimdal ASN.1 compiler and library implement a very large subset of the +ASN.1 syntax, meanign large parts of X.680, X.681, X.682, and X.683. + +The compiler currently emits: + + - a JSON representation of ASN.1 modules + - C types corresponding to ASN.1 modules' types + - C functions for DER (and some BER) codecs for ASN.1 modules' types + +We vaguely hope to eventually move to using the JSON representation of ASN.1 +modules to do code generation in a programming language like `jq` rather than +in C. The idea there is to make it much easier to target other programming +languages than C, especially Rust, so that we can start moving Heimdal to Rust +(first after this would be `lib/hx509`, then `lib/krb5`, then `lib/hdb`, then +`lib/gssapi`, then `kdc/`). + +The compiler has two "backends": + + - C code generation + - "template" (byte-code) generation and interpretation + +## Features and Limitations + +Supported encoding rules: + + - DER + - BER decoding (but not encoding) + +As well, the Heimdal ASN.1 compiler can render values as JSON using an ad-hoc +metaschema that is not quite JER-compliant. A sample rendering of a complex +PKIX `Certificate` with all typed holes automatically decoded is shown in +[README.md#features](README.md#features). + +The Heimdal ASN.1 compiler supports open types via X.681/X.682/X.683 syntax. +Specifically: (when using the template backend) the generated codecs can +automatically and recursively decode and encode through "typed holes". + +An "open type", also known as "typed holes" or "references", is a part of a +structure that can contain the encoding of a value of some arbitrary data type, +with a hint of that value's type expressed in some way such as: via an "object +identifier", or an integer, or even a string (e.g., like a URN). + +Open types are widely used as a form of extensibility. + +Historically, open types were never documented formally, but with natural +language (e.g., English) meant only for humans to understand. Documenting open +types with formal syntax allows compilers to support them specially. + +See the the [`asn1_compile(1)` manual page](#Manual-Page-for-asn1_compile) +below and [README.md#features](README.md#features), for more details on +limitations. Excerpt from the manual page: + +``` +The Information Object System support includes automatic codec support +for encoding and decoding through “open types” which are also known as +“typed holes”. See RFC5912 for examples of how to use the ASN.1 Infor- +mation Object System via X.681/X.682/X.683 annotations. See the com- +piler's README files for more information on ASN.1 Information Object +System support. + +Extensions specific to Heimdal are generally not syntactic in nature but +rather command-line options to this program. For example, one can use +command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei- + ther encoded nor decoded; +etc. + +ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + +Size and range constraints on the ‘INTEGER’ type cause the compiler to +generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, +‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which +represents an integer of arbitrary size. + +Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. +``` + +## Easy-to-Use C Types + +The Heimdal ASN.1 compiler generates easy-to-use C types for ASN.1 types. + +Unconstrained `INTEGER` becomes `heim_integer` -- a large integer type. + +Constrained `INTEGER` types become `int`, `unsigned int`, `int64_t`, or +`uint64_t`. + +String types generally become `char *` (C strings, i.e., NUL-terminated) or +`heim_octet_string` (a counted byte string type). + +`SET` and `SEQUENCE` types become `struct` types. + +`SET OF SomeType` and `SEQUENCE OF SomeType` types become `struct` types with a +`size_t len` field counting the number of elements of the array, and a pointer +to `len` consecutive elements of the `SomeType` type. + +`CHOICE` types become a `struct` type with an `enum` discriminant and a +`union`. + +Type names have hyphens turned to underscores. + +Every ASN.1 gets a `typedef`. + +`OPTIONAL` members of `SET`s and `SEQUENCE`s become pointer types (`NULL` +values mean "absent", while non-`NULL` values mean "present"). + +Tags are of no consequence to the C types generated. + +Types definitions to be topographically sorted because of the need to have +forward declarations. + +Forward `typedef` declarations are emmitted. + +Circular type dependencies are allowed provided that `OPTIONAL` members are +used for enough circular references so as to avoid creating types whose values +have infinite size! (Circular type dependencies can be used to build linked +lists, though that is a bit of a silly trick when one can use arrays instead, +though in principle this could be used to do on-line encoding and decoding of +arbitrarily large streams of objects. See the [commentary](#Commentary) +section.) + +Thus `Certificate` becomes: + +```C +typedef struct TBSCertificate { + heim_octet_string _save; /* see below! */ + Version *version; + CertificateSerialNumber serialNumber; + AlgorithmIdentifier signature; + Name issuer; + Validity validity; + Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + heim_bit_string *issuerUniqueID; + heim_bit_string *subjectUniqueID; + Extensions *extensions; +} TBSCertificate; + +typedef struct Certificate { + TBSCertificate tbsCertificate; + AlgorithmIdentifier signatureAlgorithm; + heim_bit_string signatureValue; +} Certificate; +``` + +The `_save` field in `TBSCertificate` is generated when the compiler is invoked +with `--preserve-binary=TBSCertificate`, and the decoder will place the +original encoding of the value of a `TBSCertificate` in the decoded +`TBSCertificate`'s `_save` field. This is very useful for signature +validation: the application need not attempt to re-encode a `TBSCertificate` in +order to validate its signature from the containing `Certificate`! + +Let's compare to the `Certificate` as defined in ASN.1: + +```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } +``` + +The conversion from ASN.1 to C is quite mechanical and natural. That's what +code-generators do, of course, so it's not surprising. But you can see that +`Certificate` in ASN.1 and C differs only in: + + - in C `SEQUENCE { }` becomes `struct { }` + - in C the type name comes first + - in C we drop the tagging directives (e.g., `[0] EXPLICIT`) + - `DEFAULT` and `OPTIONAL` become pointers + - in C we use `typedef`s to make the type names usable without having to add + `struct` + +## Circular Type Dependencies + +As noted above, circular type dependencies are supported. + +Here's a toy example from [XDR](https://datatracker.ietf.org/doc/html/rfc4506) +-- a linked list: + +```XDR +struct stringentry { + string item<>; + stringentry *next; +}; + +typedef stringentry *stringlist; +``` + +Here is the same example in ASN.1: + +```ASN.1 +Stringentry ::= SEQUENCE { + item UTF8String, + next Stringentry OPTIONAL +} +``` + +which compiles to: + +```C +typedef struct Stringentry Stringentry; +struct Stringentry { + char *item; + Stringentry *next; +}; +``` + +This illustrates that `OPTIONAL` members in ASN.1 are like pointers in XDR. + +Making the `next` member not `OPTIONAL` would cause `Stringentry` to be +infinitely large, and there is no way to declare the equivalent in C anyways +(`struct foo { int a; struct foo b; };` will not compile in C). + +Mutual circular references are allowed too. In the following example `A` +refers to `B` and `B` refers to `A`, but as long as one (or both) of those +references is `OPTIONAL`, then it will be allowed: + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B } +B ::= SEQUENCE { name UTF8String, a A OPTIONAL } +``` + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B OPTIONAL } +B ::= SEQUENCE { name UTF8String, a A } +``` + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B OPTIONAL } +B ::= SEQUENCE { name UTF8String, a A OPTIONAL } +``` + +In the above example values of types `A` and `B` together form a linked list. + +Whereas this is broken and will not compile: + +```ASN1 +A ::= SEQUENCE { name UTF8String, b B } +B ::= SEQUENCE { name UTF8String, a A } -- infinite size! +``` + +## Generated APIs For Any Given Type T + +The C functions generated for ASN.1 types are all of the same form, for any +type `T`: + +```C +int decode_T(const unsigned char *, size_t, TBSCertificate *, size_t *); +int encode_T(unsigned char *, size_t, const TBSCertificate *, size_t *); +size_t length_T(const TBSCertificate *); +int copy_T(const TBSCertificate *, TBSCertificate *); +void free_T(TBSCertificate *); +char * print_T(const TBSCertificate *, int); +``` + +The `decode_T()` functions take a pointer to the encoded data, its length in +bytes, a pointer to a C object of type `T` to decode into, and a pointer into +which the number of bytes consumed will be written. + +The `length_T()` functions take a pointer to a C object of type `T` and return +the number of bytes its encoding would need. + +The `encode_T()` functions take a pointer to enough bytes to encode the value, +the number of bytes found there, a pointer to a C object of type `T` whose +value to encode, and a pointer into which the number of bytes output will be +written. + +> NOTE WELL: The first argument to `encode_T()` functions must point to the +> last byte in the buffer into which the encoder will encode the value. This +> is because the encoder encodes from the end towards the beginning. + +The `print_T()` functions encode the value of a C object of type `T` in JSON +(though not in JER-compliant JSON). A sample printing of a complex PKIX +`Certificate` can be seen in [README.md#features](README.md#features). + +The `copy_T()` functions take a pointer to a source C object of type `T` whose +value they then copy to the destination C object of the same type. The copy +constructor is equivalent to encoding the source value and decoding it onto the +destination. + +The `free_T()` functions take a pointer to a C object of type `T` whose value's +memory resources will be released. Note that the C object _itself_ is not +freed, only its _content_. + +See [sample usage](#Using-the-Generated-APIs). + +These functions are all recursive. + +> NOTE WELL: These functions use the standard C memory allocator. +> When using the Windows statically-linked C run-time, you must link with +> `LIBASN1.LIB` to avoid possibly freeing memory allocated by a different +> allocator. + +## Error Handling + +All codec functions that return errors return them as `int`. + +Error values are: + + - system error codes (use `strerror()` to display them) + +or + + - `ASN1_BAD_TIMEFORMAT` + - `ASN1_MISSING_FIELD` + - `ASN1_MISPLACED_FIELD` + - `ASN1_TYPE_MISMATCH` + - `ASN1_OVERFLOW` + - `ASN1_OVERRUN` + - `ASN1_BAD_ID` + - `ASN1_BAD_LENGTH` + - `ASN1_BAD_FORMAT` + - `ASN1_PARSE_ERROR` + - `ASN1_EXTRA_DATA` + - `ASN1_BAD_CHARACTER` + - `ASN1_MIN_CONSTRAINT` + - `ASN1_MAX_CONSTRAINT` + - `ASN1_EXACT_CONSTRAINT` + - `ASN1_INDEF_OVERRUN` + - `ASN1_INDEF_UNDERRUN` + - `ASN1_GOT_BER` + - `ASN1_INDEF_EXTRA_DATA` + +You can use the `com_err` library to display these errors as strings: + +```C + struct et_list *etl = NULL; + initialize_asn1_error_table_r(&etl); + int ret; + + ... + + ret = decode_T(...); + if (ret) { + const char *error_message; + + if ((error_message = com_right(etl, ret)) == NULL) + error_message = strerror(ret); + + fprintf(stderr, "Failed to decode T: %s\n", + error_message ? error_message : ""); + } +``` + +## Using the Generated APIs + +Value construction is as usual in C. Use the standard C allocator for +allocating values of `OPTIONAL` fields. + +Value destruction is done with the `free_T()` destructors. + +Decoding is just: + +```C + Certificate c; + size_t sz; + int ret; + + ret = decode_Certificate(pointer_to_encoded_bytes, + number_of_encoded_bytes, + &c, &sz); + if (ret == 0) { + if (sz != number_of_encoded_bytes) + warnx("Extra bytes after Certificate!"); + } else { + warnx("Failed to decode certificate!"); + return ret; + } + + /* Now do stuff with the Certificate */ + ... + + /* Now release the memory */ + free_Certificate(&c); +``` + +Encoding involves calling the `length_T()` function to compute the number of +bytes needed for the encoding, then allocating that many bytes, then calling +`encode_T()` to encode into that memory. A convenience macro, +`ASN1_MALLOC_ENCODE()`, does all three operations: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + ASN1_MALLOC_ENCODE(Certificate, bytes, num_bytes, &c, sz, ret); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +or, the same code w/o the `ASN1_MALLOC_ENCODE()` macro: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + num_bytes = length_Certificate(&c); + bytes = malloc(num_bytes); + if (bytes == NULL) + errx(1, "Out of memory"); + + /* + * Note that the memory to encode into, passed to encode_Certificate() + * must be a pointer to the _last_ byte of that memory, not the first! + */ + ret = encode_Certificate(bytes + num_bytes - 1, num_bytes, + &c, &sz); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +## Open Types + +The handling of X.681/X.682/X.683 syntax for open types is described at length +in [README-X681.md](README-X681.md). + +## Command-line Usage + +The compiler takes an ASN.1 module file name and outputs a C header and C +source files, as well as various other metadata files: + + - `_asn1.h` + + This file defines all the exported types from the given ASN.1 module as C + types. + + - `_asn1-priv.h` + + This file defines all the non-exported types from the given ASN.1 module as + C types. + + - `_asn1_files` + + This file is needed because the default is to place the code for each type + in a separate C source file, which can help improve the performance of + builds by making it easier to parallelize the building of the ASN.1 module. + + - `asn1_.c` or `asn1__asn1.c` + + If `--one-code-file` is used, then the implementation of the module will be + in a file named `asn1__asn1.c`, otherwise the implementation of each + type in the module will be in `asn1_.c`. + + - `_asn1.json` + + This file contains a JSON description of the module (the schema for this + file is ad-hoc and subject to change w/o notice). + + - `_asn1_oids.c` + + This file is meant to be `#include`d, and contains just calls to a + `DEFINE_OID_WITH_NAME(sym)` macro that the user must define, where `sym` is + the suffix of the name of a variable of type `heim_oid`. The full name of + the variable is `asn1_oid_ ## sym`. + + - `_asn1_syms.c` + + This file is meant to be `#include`d, and contains just calls to these + macros that the user must define: + + - `ASN1_SYM_INTVAL(name, genname, sym, num)` + - `ASN1_SYM_OID(name, genname, sym)` + - `ASN1_SYM_TYPE(name, genname, sym)` + + where `name` is the C string literal name of the value or type as it appears + in the ASN.1 module, `genname` is the C string literal name of the value or + type as generated (e.g., with hyphens replaced by underscores), `sym` is the + symbol or symbol suffix (see above0, and `num` is the numeric value of the + integer value. + +Control over the C types used for ASN.1 `INTEGER` types is done by ASN.1 usage +convention: + + - unconstrained `INTEGER` types, or `INTEGER` types where only the minimum, or + only the maximum value is specified generate `heim_integer` + + - constrained `INTEGER` types whose minimum and maximum fit in `unsigned`'s + range generate `unsigned` + + - constrained `INTEGER` types whose minimum and maximum fit in `int`'s + range generate `int` + + - constrained `INTEGER` types whose minimum and maximum fit in `uin64_t`'s + range generate `uin64_t` + + - constrained `INTEGER` types whose minimum and maximum fit in `in64_t`'s + range generate `in64_t` + + - `INTEGER` types with named members generate a C `struct` with `unsigned int` + bit-field members + + - all other `INTEGER` types generate `heim_integer` + +Various code generation options are provided as command-line options or as +ASN.1 usage conventions: + + - `--type-file=C-HEADER-FILE` -- generate an `#include` directive to include + that header for some useful base types (within Heimdal we use `krb5-types.h` + as that header) + + - `--template` -- use the "template" (byte-coded) backend + + - `--one-code-file` -- causes all the code generated to be placed in one C + source file (mutually exclusive with `--template`) + + - `--support-ber` -- accept non-DER BER when decoding + + - `--preserve-binary=TYPE` -- add a `_save` field to the C struct type for the + ASN.1 `TYPE` where the decoder will save the original encoding of the value + of `TYPE` it decodes (useful for cryptographic signature verification!) + + - `--sequence=TYPE` -- generate `add_TYPE()` and `remove_TYPE()` utility + functions (`TYPE` must be a `SET OF` or `SEQUENCE OF` type) + + - `--decorate=DECORATION` -- add fields to generated C struct types as + described in the `DECORATION` (see the + [manual page](#Manual-Page-for-asn1_compile) below) + + Decoration fields are never encoded or decoded. They are meant to be used + for, e.g., application state keeping. + + - `--no-parse-units` -- normally the compiler generates code to use the + Heimdal `libroken` "units" utility for displaying bit fields; this option + disables this + +See the [manual page for `asn1_compile(1)`](#Manual-Page-for-asn1_compile) for +a full listing of command-line options. + +### Manual Page for `asn1_compile(1)` + +``` +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) + +NAME + asn1_compile — compile ASN.1 modules + +SYNOPSIS + asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] + +DESCRIPTION + asn1_compile compiles an ASN.1 module into C source code and header + files. + + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + + Options supported: + + --template + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. + + --prefix-enum + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --encode-rfc1510-bit-string + Use RFC1510, non-standard handling of “BIT STRING” types. + + --decode-dce-ber + + --support-ber + + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. + + --one-code-file + Generate a single source code file. Otherwise a separate code + file will be generated for every type. + + --gen-name=NAME + Use NAME to form the names of the files generated. + + --option-file=FILE + Take additional command-line options from FILE. + + --original-order + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. + + --no-parse-units + Do not generate to-int / from-int functions for enumeration + types. + + --type-file=C-HEADER-FILE + Generate an include of the named header file that might be needed + for common type defintions. + + --version + + --help + +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. + +HEIMDAL February 22, 2021 HEIMDAL +``` + +# Future Directions + +The Heimdal ASN.1 compiler is focused on PKIX and Kerberos, and is almost +feature-complete for dealing with those. It could use additional support for +X.681/X.682/X.683 elements that would allow the compiler to understand +`Certificate ::= SIGNED{TBSCertificate}`, particularly the ability to +automatically validate cryptographic algorithm parameters. However, this is +not that important. + +Another feature that might be nice is the ability of callers to specify smaller +information object sets when decoding values of types like `Certificate`, +mainly to avoid spending CPU cycles and memory allocations on decoding types in +typed holes that are not of interest to the application. + +For testing purposes, a JSON reader to go with the JSON printer might be nice, +and anyways, would make for a generally useful tool. + +Another feature that would be nice would to automatically generate SQL and LDAP +code for HDB based on `lib/hdb/hdb.asn1` (with certain usage conventions and/or +compiler command-line options to make it possible to map schemas usefully). + +For the `hxtool` command, it would be nice if the user could input arbitrary +certificate extensions and `subjectAlternativeName` (SAN) values in JSON + an +ASN.1 module and type reference that `hxtool` could then parse and encode using +the ASN.1 compiler and library. Currently the `hx509` library and its `hxtool` +command must be taught about every SAN type. diff --git a/third_party/heimdal/lib/asn1/Makefile.am b/third_party/heimdal/lib/asn1/Makefile.am new file mode 100644 index 0000000..e5af4ba --- /dev/null +++ b/third_party/heimdal/lib/asn1/Makefile.am @@ -0,0 +1,567 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_YFLAGS = -d -o asn1parse.c -t + +AM_CPPFLAGS += $(ROKEN_RENAME) -I$(top_builddir)/include -I$(top_srcdir)/lib/base + +man_MANS = asn1_print.1 asn1_compile.1 + +lib_LTLIBRARIES = libasn1.la libasn1template.la +libasn1_la_LDFLAGS = -version-info 8:0:0 +libasn1template_la_LDFLAGS = -version-info 8:0:0 + +noinst_LTLIBRARIES = libasn1base.la + +if versionscript +libasn1_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +libasn1template_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + + +libasn1_la_LIBADD = \ + libasn1base.la \ + @LIB_com_err@ \ + $(LIBADD_roken) + +libasn1template_la_LIBADD = \ + libasn1base.la \ + @LIB_com_err@ \ + $(LIBADD_roken) + +BUILT_SOURCES = \ + $(gen_files_rfc2459) \ + $(gen_files_rfc4108) \ + $(gen_files_cms) \ + $(gen_files_krb5) \ + $(gen_files_ocsp) \ + $(gen_files_pkinit) \ + $(gen_files_pkcs8) \ + $(gen_files_pkcs9) \ + $(gen_files_pkcs10) \ + $(gen_files_pkcs12) \ + $(gen_files_digest) \ + $(gen_files_kx509) + +BUILT_TEMPLATE_SOURCES = \ + $(gen_files_rfc2459_template) \ + $(gen_files_rfc4108_template) \ + $(gen_files_cms_template) \ + $(gen_files_krb5_template) \ + $(gen_files_ocsp_template) \ + $(gen_files_pkinit_template) \ + $(gen_files_pkcs8_template) \ + $(gen_files_pkcs9_template) \ + $(gen_files_pkcs10_template) \ + $(gen_files_pkcs12_template) \ + $(gen_files_digest_template) \ + $(gen_files_kx509_template) + +gen_files_krb5 = asn1_krb5_asn1.c +gen_files_krb5_template = asn1_krb5_template_asn1.c +gen_files_cms = asn1_cms_asn1.c +gen_files_cms_template = asn1_cms_template_asn1.c +gen_files_crmf = asn1_crmf_asn1.c +gen_files_crmf_template = asn1_crmf_template_asn1.c +gen_files_rfc2459 = asn1_rfc2459_asn1.c +gen_files_rfc2459_template = asn1_rfc2459_template_asn1.c +gen_files_rfc4108 = asn1_rfc4108_asn1.c +gen_files_rfc4108_template = asn1_rfc4108_template_asn1.c +gen_files_ocsp = asn1_ocsp_asn1.c +gen_files_ocsp_template = asn1_ocsp_template_asn1.c +gen_files_pkinit = asn1_pkinit_asn1.c +gen_files_pkinit_template = asn1_pkinit_template_asn1.c +gen_files_pkcs10 = asn1_pkcs10_asn1.c +gen_files_pkcs10_template = asn1_pkcs10_template_asn1.c +gen_files_pkcs12 = asn1_pkcs12_asn1.c +gen_files_pkcs12_template = asn1_pkcs12_template_asn1.c +gen_files_pkcs8 = asn1_pkcs8_asn1.c +gen_files_pkcs8_template = asn1_pkcs8_template_asn1.c +gen_files_pkcs9 = asn1_pkcs9_asn1.c +gen_files_pkcs9_template = asn1_pkcs9_template_asn1.c +gen_files_test = asn1_test_asn1.c +gen_files_test_template = asn1_test_template_asn1.c +gen_files_digest = asn1_digest_asn1.c +gen_files_digest_template = asn1_digest_template_asn1.c +gen_files_kx509 = asn1_kx509_asn1.c +gen_files_kx509_template = asn1_kx509_template_asn1.c +gen_files_x690sample = asn1_x690sample_asn1.c +gen_files_x690sample_template = asn1_x690sample_template_asn1.c + +oid_resolution.lo: $(BUILT_SOURCES) + +noinst_PROGRAMS = asn1_gen + +bin_PROGRAMS = asn1_compile asn1_print + +TESTS = check-der check-gen check-gen-template check-timegm check-ber check-template +check_PROGRAMS = $(TESTS) + +asn1_gen_SOURCES = asn1_gen.c +asn1_print_SOURCES = asn1_print.c +asn1_print_SOURCES += $(gen_files_x690sample_template) +asn1_print_CPPFLAGS = -DASN1_PRINT_SUPPORTED +check_der_SOURCES = check-der.c check-common.c check-common.h + +check_template_SOURCES = check-template.c check-common.c check-common.h +nodist_check_template_SOURCES = $(gen_files_test_template) + +check_gen_template_CPPFLAGS = -DASN1_IOS_SUPPORTED +dist_check_gen_template_SOURCES = check-gen.c check-common.c check-common.h +nodist_check_gen_template_SOURCES = $(gen_files_test_template) \ + $(gen_files_x690sample_template) + +dist_check_gen_SOURCES = check-gen.c check-common.c check-common.h +nodist_check_gen_SOURCES = $(gen_files_test) $(gen_files_x690sample) + +build_HEADERZ = asn1-template.h + +asn1_compile_SOURCES = \ + asn1parse.y \ + der.h \ + gen.c \ + gen_copy.c \ + gen_decode.c \ + gen_encode.c \ + gen_print.c \ + gen_free.c \ + gen_glue.c \ + gen_length.c \ + gen_locl.h \ + gen_seq.c \ + gen_template.c \ + hash.c \ + hash.h \ + lex.l \ + lex.h \ + main.c \ + asn1-template.h \ + symbol.c \ + symbol.h + +dist_libasn1base_la_SOURCES = \ + der_locl.h \ + der.c \ + der.h \ + der_get.c \ + der_put.c \ + der_free.c \ + der_print.c \ + der_length.c \ + der_copy.c \ + der_cmp.c \ + der_format.c \ + fuzzer.c \ + heim_asn1.h \ + extra.c \ + roken_rename.h \ + template.c \ + timegm.c + +dist_libasn1_la_SOURCES = oid_resolution.c +dist_libasn1template_la_SOURCES = oid_resolution.c + +nodist_libasn1base_la_SOURCES = \ + asn1_err.h \ + asn1_err.c + +nodist_libasn1_la_SOURCES = $(BUILT_SOURCES) + +if !ASN1_TEMPLATING +nodist_libasn1template_la_SOURCES = $(BUILT_TEMPLATE_SOURCES) +else +nodist_libasn1template_la_SOURCES = $(BUILT_SOURCES) +endif + +asn1_compile_LDADD = \ + $(LIB_roken) $(LEXLIB) + +check_der_LDADD = \ + libasn1.la \ + $(LIB_roken) + +check_template_LDADD = $(check_der_LDADD) +asn1_print_LDADD = libasn1template.la $(LIB_roken) $(LIB_com_err) +asn1_gen_LDADD = $(check_der_LDADD) +check_timegm_LDADD = $(check_der_LDADD) + +check_gen_template_LDADD = \ + libasn1template.la \ + $(LIB_roken) + +check_gen_LDADD = \ + libasn1template.la \ + $(LIB_roken) + +check_ber_LDADD = $(check_gen_LDADD) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(gen_files_rfc2459) \ + $(gen_files_rfc2459_template) \ + $(gen_files_rfc4108) \ + $(gen_files_rfc4108_template) \ + $(gen_files_cms) \ + $(gen_files_cms_template) \ + $(gen_files_krb5) \ + $(gen_files_krb5_template) \ + $(gen_files_ocsp) \ + $(gen_files_ocsp_template) \ + $(gen_files_pkinit) \ + $(gen_files_pkinit_template) \ + $(gen_files_pkcs8) \ + $(gen_files_pkcs8_template) \ + $(gen_files_pkcs9) \ + $(gen_files_pkcs9_template) \ + $(gen_files_pkcs10) \ + $(gen_files_pkcs10_template) \ + $(gen_files_pkcs12) \ + $(gen_files_pkcs12_template) \ + $(gen_files_digest) \ + $(gen_files_digest_template) \ + $(gen_files_kx509) \ + $(gen_files_kx509_template) \ + $(gen_files_x690sample) \ + $(gen_files_x690sample_template) \ + $(gen_files_test) \ + $(gen_files_test_template) \ + $(nodist_check_gen_SOURCES) \ + asn1parse.c asn1parse.h lex.c \ + asn1_err.c asn1_err.h \ + rfc2459_asn1_files rfc2459_asn1*.h \ + rfc2459_template_asn1_files rfc2459_template_asn1*.h \ + rfc4108_asn1_files rfc4108_asn1*.h \ + rfc4108_template_asn1_files rfc4108_template_asn1*.h \ + cms_asn1_files cms_asn1*.h \ + cms_template_asn1_files cms_template_asn1* \ + crmf_asn1_files crmf_asn1* \ + crmf_template_asn1_files crmf_template_asn1* \ + krb5_asn1_files krb5_asn1* \ + krb5_template_asn1_files krb5_template_asn1* \ + ocsp_asn1_files ocsp_asn1* \ + ocsp_template_asn1_files ocsp_template_asn1* \ + pkinit_asn1_files pkinit_asn1* \ + pkinit_template_asn1_files pkinit_template_asn1* \ + pkcs8_asn1_files pkcs8_asn1* \ + pkcs8_template_asn1_files pkcs8_template_asn1* \ + pkcs9_asn1_files pkcs9_asn1* \ + pkcs9_template_asn1_files pkcs9_template_asn1* \ + pkcs10_asn1_files pkcs10_asn1* \ + pkcs10_template_asn1_files pkcs10_template_asn1* \ + pkcs12_asn1_files pkcs12_asn1* \ + pkcs12_template_asn1_files pkcs12_template_asn1* \ + digest_asn1_files digest_asn1* \ + digest_template_asn1_files digest_template_asn1* \ + kx509_asn1_files kx509_asn1* \ + kx509_template_asn1_files kx509_template_asn1* \ + x690sample_asn1_files x690sample_asn1* \ + x690sample_template_asn1_files x690sample_template_asn1* \ + test_asn1_files test_asn1* \ + test_template_asn1_files test_template_asn1* \ + asn1_*_asn1.c *_asn1.json *_asn1_syms.c *_asn1_oids.c + +dist_include_HEADERS = der.h heim_asn1.h +dist_include_HEADERS += $(srcdir)/der-protos.h $(srcdir)/der-private.h +dist_include_HEADERS += asn1-common.h + +nodist_include_HEADERS = asn1_err.h +nodist_include_HEADERS += krb5_asn1.h +nodist_include_HEADERS += krb5_template_asn1.h +nodist_include_HEADERS += pkinit_asn1.h +nodist_include_HEADERS += pkinit_template_asn1.h +nodist_include_HEADERS += cms_asn1.h +nodist_include_HEADERS += cms_template_asn1.h +nodist_include_HEADERS += crmf_asn1.h +nodist_include_HEADERS += crmf_template_asn1.h +nodist_include_HEADERS += rfc2459_asn1.h +nodist_include_HEADERS += rfc2459_template_asn1.h +nodist_include_HEADERS += rfc4108_asn1.h +nodist_include_HEADERS += rfc4108_template_asn1.h +nodist_include_HEADERS += ocsp_asn1.h +nodist_include_HEADERS += ocsp_template_asn1.h +nodist_include_HEADERS += pkcs8_asn1.h +nodist_include_HEADERS += pkcs8_template_asn1.h +nodist_include_HEADERS += pkcs9_asn1.h +nodist_include_HEADERS += pkcs9_template_asn1.h +nodist_include_HEADERS += pkcs10_asn1.h +nodist_include_HEADERS += pkcs10_template_asn1.h +nodist_include_HEADERS += pkcs12_asn1.h +nodist_include_HEADERS += pkcs12_template_asn1.h +nodist_include_HEADERS += digest_asn1.h +nodist_include_HEADERS += digest_template_asn1.h +nodist_include_HEADERS += kx509_asn1.h +nodist_include_HEADERS += kx509_template_asn1.h +nodist_include_HEADERS += x690sample_asn1.h +nodist_include_HEADERS += x690sample_template_asn1.h + +priv_headers = krb5_asn1-priv.h +priv_headers += krb5_template_asn1-priv.h +priv_headers += pkinit_asn1-priv.h +priv_headers += pkinit_template_asn1-priv.h +priv_headers += cms_asn1-priv.h +priv_headers += cms_template_asn1-priv.h +priv_headers += crmf_asn1-priv.h +priv_headers += crmf_template_asn1-priv.h +priv_headers += rfc2459_asn1-priv.h +priv_headers += rfc2459_template_asn1-priv.h +priv_headers += rfc4108_asn1-priv.h +priv_headers += rfc4108_template_asn1-priv.h +priv_headers += ocsp_asn1-priv.h +priv_headers += ocsp_template_asn1-priv.h +priv_headers += pkcs8_asn1-priv.h +priv_headers += pkcs8_template_asn1-priv.h +priv_headers += pkcs9_asn1-priv.h +priv_headers += pkcs9_template_asn1-priv.h +priv_headers += pkcs10_asn1-priv.h +priv_headers += pkcs10_template_asn1-priv.h +priv_headers += pkcs12_asn1-priv.h +priv_headers += pkcs12_template_asn1-priv.h +priv_headers += digest_asn1-priv.h +priv_headers += digest_template_asn1-priv.h +priv_headers += kx509_asn1-priv.h +priv_headers += kx509_template_asn1-priv.h +priv_headers += x690sample_asn1-priv.h +priv_headers += x690sample_template_asn1-priv.h +priv_headers += test_asn1.h test_asn1-priv.h +priv_headers += test_template_asn1.h test_template_asn1-priv.h + + + +$(asn1_compile_OBJECTS): asn1parse.h asn1parse.c $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1_la_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1template_la_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1base_la_OBJECTS): asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(check_gen_OBJECTS): test_asn1.h +$(check_template_OBJECTS): test_asn1_files +$(asn1_print_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) + +asn1parse.h: asn1parse.c + +$(gen_files_krb5) krb5_asn1.h krb5_asn1-priv.h: krb5_asn1_files +$(gen_files_krb5_template) krb5_template_asn1.h krb5_template_asn1-priv.h: krb5_template_asn1_files +$(gen_files_ocsp) ocsp_asn1.h ocsp_asn1-priv.h: ocsp_asn1_files +$(gen_files_ocsp_template) ocsp_template_asn1.h ocsp_template_asn1-priv.h: ocsp_template_asn1_files +$(gen_files_pkinit) pkinit_asn1.h pkinit_asn1-priv.h: pkinit_asn1_files +$(gen_files_pkinit_template) pkinit_template_asn1.h pkinit_template_asn1-priv.h: pkinit_template_asn1_files +$(gen_files_pkcs8) pkcs8_asn1.h pkcs8_asn1-priv.h: pkcs8_asn1_files +$(gen_files_pkcs8_template) pkcs8_template_asn1.h pkcs8_template_asn1-priv.h: pkcs8_template_asn1_files +$(gen_files_pkcs9) pkcs9_asn1.h pkcs9_asn1-priv.h: pkcs9_asn1_files +$(gen_files_pkcs9_template) pkcs9_template_asn1.h pkcs9_template_asn1-priv.h: pkcs9_template_asn1_files +$(gen_files_pkcs10) pkcs10_asn1.h pkcs10_asn1-priv.h: pkcs10_asn1_files +$(gen_files_pkcs10_template) pkcs10_template_asn1.h pkcs10_template_asn1-priv.h: pkcs10_template_asn1_files +$(gen_files_pkcs12) pkcs12_asn1.h pkcs12_asn1-priv.h: pkcs12_asn1_files +$(gen_files_pkcs12_template) pkcs12_template_asn1.h pkcs12_template_asn1-priv.h: pkcs12_template_asn1_files +$(gen_files_digest) digest_asn1.h digest_asn1-priv.h: digest_asn1_files +$(gen_files_digest_template) digest_template_asn1.h digest_template_asn1-priv.h: digest_template_asn1_files +$(gen_files_kx509) kx509_asn1.h kx509_asn1-priv.h: kx509_asn1_files +$(gen_files_kx509_template) kx509_template_asn1.h kx509_template_asn1-priv.h: kx509_template_asn1_files +$(gen_files_rfc2459) rfc2459_asn1.h rfc2459_asn1-priv.h: rfc2459_asn1_files +$(gen_files_rfc2459_template) rfc2459_template_asn1.h rfc2459_template_asn1-priv.h: rfc2459_template_asn1_files +$(gen_files_rfc4108) rfc4108_asn1.h rfc4108_asn1-priv.h: rfc4108_asn1_files +$(gen_files_rfc4108_template) rfc4108_template_asn1.h rfc4108_template_asn1-priv.h: rfc4108_template_asn1_files +$(gen_files_cms) cms_asn1.h cms_asn1-priv.h: cms_asn1_files +$(gen_files_cms_template) cms_template_asn1.h cms_template_asn1-priv.h: cms_template_asn1_files +$(gen_files_crmf) crmf_asn1.h crmf_asn1-priv.h: crmf_asn1_files +$(gen_files_crmf_template) crmf_template_asn1.h crmf_template_asn1-priv.h: crmf_template_asn1_files +$(gen_files_x690sample) x690sample_asn1.h x690sample_asn1-priv.h: x690sample_asn1_files +$(gen_files_x690sample_template) x690sample_template_asn1.h x690sample_template_asn1-priv.h: x690sample_template_asn1_files +$(gen_files_test) test_asn1.h test_asn1-priv.h: test_asn1_files +$(gen_files_test_template) test_template_asn1.h test_template_asn1-priv.h: test_template_asn1_files + +if ASN1_TEMPLATING +TEMPLATE_OPTION=--template +else +TEMPLATE_OPTION= +endif + +# If the default is not templating, then we build a variant of libasn1 that is +# templated anyways. +rfc2459_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_template_asn1 || (rm -f rfc2459_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_template_asn1.c + +rfc4108_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/rfc4108.asn1 rfc4108_template_asn1 || (rm -f rfc4108_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_template_asn1.c + +cms_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_template_asn1 || (rm -f cms_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_template_asn1.c + +crmf_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_template_asn1 || (rm -f crmf_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_template_asn1.c + +krb5_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt + $(ASN1_COMPILE) --one-code-file --template \ + --option-file=$(srcdir)/krb5.opt \ + $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_template_asn1.c + +ocsp_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_template_asn1 || (rm -f ocsp_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_template_asn1.c + +pkinit_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkinit.asn1 pkinit_template_asn1 || (rm -f pkinit_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_template_asn1.c + +pkcs8_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs8.asn1 pkcs8_template_asn1 || (rm -f pkcs8_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_template_asn1.c + +pkcs9_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs9.asn1 pkcs9_template_asn1 || (rm -f pkcs9_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_template_asn1.c + +pkcs10_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_template_asn1 || (rm -f pkcs10_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_template_asn1.c + +pkcs12_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs12.asn1 pkcs12_template_asn1 || (rm -f pkcs12_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_template_asn1.c + +digest_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/digest.asn1 digest_template_asn1 || (rm -f digest_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_template_asn1.c + +kx509_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/kx509.asn1 kx509_template_asn1 || (rm -f kx509_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_template_asn1.c + +rfc2459_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_asn1 || (rm -f rfc2459_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_asn1.c + +rfc4108_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/rfc4108.asn1 rfc4108_asn1 || (rm -f rfc4108_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_asn1.c + +cms_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_asn1 || (rm -f cms_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_asn1.c + +crmf_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_asn1 || (rm -f crmf_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_asn1.c + +krb5_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) \ + --option-file=$(srcdir)/krb5.opt \ + $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_asn1.c + +ocsp_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_asn1 || (rm -f ocsp_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_asn1.c + +pkinit_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkinit.asn1 pkinit_asn1 || (rm -f pkinit_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_asn1.c + +pkcs8_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs8.asn1 pkcs8_asn1 || (rm -f pkcs8_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_asn1.c + +pkcs9_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs9.asn1 pkcs9_asn1 || (rm -f pkcs9_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_asn1.c + +pkcs10_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_asn1 || (rm -f pkcs10_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_asn1.c + +pkcs12_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs12.asn1 pkcs12_asn1 || (rm -f pkcs12_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_asn1.c + +digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/digest.asn1 digest_asn1 || (rm -f digest_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_asn1.c + +kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/kx509.asn1 kx509_asn1 || (rm -f kx509_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_asn1.c + +x690sample_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/x690sample.asn1 x690sample_template_asn1 || (rm -f x690sample_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_template_asn1.c + +x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 + $(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_asn1.c + +test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 + $(ASN1_COMPILE) --one-code-file \ + --template \ + --option-file=$(srcdir)/test.opt \ + $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_template_asn1.c + +test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 + $(ASN1_COMPILE) --one-code-file \ + --option-file=$(srcdir)/test.opt \ + $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_asn1.c + + +EXTRA_DIST = \ + NTMakefile \ + README-template.md \ + asn1_compile-version.rc \ + libasn1-exports.def \ + canthandle.asn1 \ + cms.asn1 \ + cms.opt \ + crmf.asn1 \ + crmf.opt \ + digest.asn1 \ + krb5.asn1 \ + krb5.opt \ + kx509.asn1 \ + ocsp.asn1 \ + ocsp.opt \ + pkcs10.asn1 \ + pkcs10.opt \ + pkcs12.asn1 \ + pkcs8.asn1 \ + pkcs9.asn1 \ + pkinit.asn1 \ + pku2u.asn1 \ + rfc2459.asn1 \ + rfc2459.opt \ + rfc4108.asn1 \ + setchgpw2.asn1 \ + tcg.asn1 \ + test.asn1 \ + test.opt \ + x690sample.asn1 \ + test.gen \ + asn1_err.et \ + asn1_err.c \ + asn1_err.h \ + asn1_print.1 \ + asn1_compile.1 \ + version-script.map + +DER_PROTOS = $(srcdir)/der-protos.h $(srcdir)/der-private.h + +ALL_OBJECTS = $(libasn1_la_OBJECTS) +ALL_OBJECTS += $(libasn1template_la_OBJECTS) +ALL_OBJECTS += $(libasn1base_la_OBJECTS) +ALL_OBJECTS += $(asn1_print_OBJECTS) +ALL_OBJECTS += $(asn1_compile_OBJECTS) +ALL_OBJECTS += $(asn1_gen_OBJECTS) +ALL_OBJECTS += $(check_template_OBJECTS) + +$(ALL_OBJECTS): $(DER_PROTOS) asn1_err.h + +$(srcdir)/der-protos.h: $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -o der-protos.h $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) || rm -f der-protos.h + +$(srcdir)/der-private.h: $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p der-private.h $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) || rm -f der-private.h diff --git a/third_party/heimdal/lib/asn1/NTMakefile b/third_party/heimdal/lib/asn1/NTMakefile new file mode 100644 index 0000000..19255c6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/NTMakefile @@ -0,0 +1,548 @@ +######################################################################## +# +# Copyright (c) 2009-2022, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\asn1 + +intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME -DASN1_IOS_SUPPORTED -DASN1_LIB + +!include ../../windows/NTMakefile.w32 + +ASN1_BINARIES = \ + $(LIBEXECDIR)\asn1_compile.exe + +$(BINDIR)\asn1_compile.exe: \ + $(OBJ)\asn1parse.obj \ + $(OBJ)\gen.obj \ + $(OBJ)\gen_copy.obj \ + $(OBJ)\gen_decode.obj \ + $(OBJ)\gen_encode.obj \ + $(OBJ)\gen_print.obj \ + $(OBJ)\gen_free.obj \ + $(OBJ)\gen_glue.obj \ + $(OBJ)\gen_length.obj \ + $(OBJ)\gen_seq.obj \ + $(OBJ)\gen_template.obj \ + $(OBJ)\hash.obj \ + $(OBJ)\lex.obj \ + $(OBJ)\main.obj \ + $(OBJ)\symbol.obj \ + $(OBJ)\asn1_compile-version.res + $(EXECONLINK) $(LIBROKEN) $(LIBVERS) + $(EXEPREP_NOHEIM) + +$(OBJ)\lex.c: lex.l $(OBJ)\asn1parse.h + $(LEX) -o$@ lex.l + +$(OBJ)\lex.obj: $(OBJ)\lex.c + $(C2OBJ) -DYY_NO_UNISTD_H + +$(OBJ)\asn1parse.c $(OBJ)\asn1parse.h: asn1parse.y + $(YACC) -o $(OBJ)\asn1parse.c --defines=$(OBJ)\asn1parse.h $** + +$(OBJ)\asn1_err.c $(OBJ)\asn1_err.h: asn1_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\asn1_err.et + cd $(SRCDIR) + +$(BINDIR)\asn1_print.exe: $(OBJ)\asn1_print.obj $(LIBHEIMDAL) + $(EXECONLINK) $(LIBVERS) $(LIBROKEN) $(LIBCOMERR) + $(EXEPREP) + +$(BINDIR)\asn1_gen.exe: $(OBJ)\asn1_gen.obj $(LIBHEIMDAL) + $(EXECONLINK) $(LIBVERS) $(LIBROKEN) + $(EXEPREP) + +LIBASN1_X= \ + $(OBJ)\asn1_rfc2459_asn1.c \ + $(OBJ)\asn1_rfc4108_asn1.c \ + $(OBJ)\asn1_cms_asn1.c \ + $(OBJ)\asn1_krb5_asn1.c \ + $(OBJ)\asn1_ocsp_asn1.c \ + $(OBJ)\asn1_pkinit_asn1.c \ + $(OBJ)\asn1_pkcs8_asn1.c \ + $(OBJ)\asn1_pkcs9_asn1.c \ + $(OBJ)\asn1_pkcs10_asn1.c \ + $(OBJ)\asn1_pkcs12_asn1.c \ + $(OBJ)\asn1_digest_asn1.c \ + $(OBJ)\asn1_kx509_asn1.c \ + $(OBJ)\asn1_x690sample_asn1.c + +LIBASN1_OBJS= \ + $(OBJ)\der.obj \ + $(OBJ)\der_get.obj \ + $(OBJ)\der_put.obj \ + $(OBJ)\der_free.obj \ + $(OBJ)\der_print.obj \ + $(OBJ)\der_length.obj \ + $(OBJ)\der_copy.obj \ + $(OBJ)\der_cmp.obj \ + $(OBJ)\der_format.obj \ + $(OBJ)\template.obj \ + $(OBJ)\extra.obj \ + $(OBJ)\oid_resolution.obj \ + $(OBJ)\timegm.obj \ + $(OBJ)\asn1_rfc2459_asn1.obj \ + $(OBJ)\asn1_rfc4108_asn1.obj \ + $(OBJ)\asn1_cms_asn1.obj \ + $(OBJ)\asn1_krb5_asn1.obj \ + $(OBJ)\asn1_ocsp_asn1.obj \ + $(OBJ)\asn1_pkinit_asn1.obj \ + $(OBJ)\asn1_pkcs8_asn1.obj \ + $(OBJ)\asn1_pkcs9_asn1.obj \ + $(OBJ)\asn1_pkcs10_asn1.obj \ + $(OBJ)\asn1_pkcs12_asn1.obj \ + $(OBJ)\asn1_digest_asn1.obj \ + $(OBJ)\asn1_kx509_asn1.obj \ + $(OBJ)\asn1_x690sample_asn1.obj \ + $(OBJ)\asn1_err.obj + +$(OBJ)\oid_resolution.obj: $(LIBASN1_X) + +$(LIBASN1): $(LIBASN1_OBJS) + $(LIBCON_C) -out:$@ @<< +$(**: = +) +<< + +clean:: + -$(RM) $(LIBASN1) + +# +# The static runtime version LIBASN1_S is for use by thirdparty +# components. It is not used in the construction of the Heimdal +# DLLs. + +LIBASN1_S_OBJS= \ + $(OBJ)\der.s.obj \ + $(OBJ)\der_get.s.obj \ + $(OBJ)\der_put.s.obj \ + $(OBJ)\der_free.s.obj \ + $(OBJ)\der_print.s.obj \ + $(OBJ)\der_length.s.obj \ + $(OBJ)\der_copy.s.obj \ + $(OBJ)\der_cmp.s.obj \ + $(OBJ)\der_format.s.obj \ + $(OBJ)\template.s.obj \ + $(OBJ)\extra.s.obj \ + $(OBJ)\oid_resolution.s.obj \ + $(OBJ)\timegm.s.obj \ + $(OBJ)\asn1_rfc2459_asn1.s.obj \ + $(OBJ)\asn1_rfc4108_asn1.s.obj \ + $(OBJ)\asn1_cms_asn1.s.obj \ + $(OBJ)\asn1_krb5_asn1.s.obj \ + $(OBJ)\asn1_ocsp_asn1.s.obj \ + $(OBJ)\asn1_pkinit_asn1.s.obj \ + $(OBJ)\asn1_pkcs8_asn1.s.obj \ + $(OBJ)\asn1_pkcs9_asn1.s.obj \ + $(OBJ)\asn1_pkcs10_asn1.s.obj \ + $(OBJ)\asn1_pkcs12_asn1.s.obj \ + $(OBJ)\asn1_digest_asn1.s.obj \ + $(OBJ)\asn1_kx509_asn1.s.obj \ + $(OBJ)\asn1_x690sample_asn1.s.obj \ + $(OBJ)\asn1_err.s.obj + +$(OBJ)\oid_resolution.s.obj: oid_resolution.c $(LIBASN1_X) + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ oid_resolution.c + +$(OBJ)\der.s.obj: der.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_get.s.obj: der_get.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_put.s.obj: der_put.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_free.s.obj: der_free.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_print.s.obj: der_print.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_length.s.obj: der_length.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_copy.s.obj: der_copy.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_cmp.s.obj: der_cmp.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_format.s.obj: der_format.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\template.s.obj: template.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\extra.s.obj: extra.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\timegm.s.obj: timegm.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_rfc2459_asn1.s.obj: $(OBJ)\asn1_rfc2459_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_rfc4108_asn1.s.obj: $(OBJ)\asn1_rfc4108_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_cms_asn1.s.obj: $(OBJ)\asn1_cms_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_krb5_asn1.s.obj: $(OBJ)\asn1_krb5_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_ocsp_asn1.s.obj: $(OBJ)\asn1_ocsp_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkinit_asn1.s.obj: $(OBJ)\asn1_pkinit_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs8_asn1.s.obj: $(OBJ)\asn1_pkcs8_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs9_asn1.s.obj: $(OBJ)\asn1_pkcs9_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs10_asn1.s.obj: $(OBJ)\asn1_pkcs10_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs12_asn1.s.obj: $(OBJ)\asn1_pkcs12_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_digest_asn1.s.obj: $(OBJ)\asn1_digest_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_kx509_asn1.s.obj: $(OBJ)\asn1_kx509_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_x690sample_asn1.s.obj: $(OBJ)\asn1_x690sample_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_asn1.s.obj: $(OBJ)\asn1_test_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_template_asn1.s.obj: $(OBJ)\asn1_test_template_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_err.s.obj: $(OBJ)\asn1_err.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(LIBASN1_S): $(LIBASN1_S_OBJS) + $(LIBCON_C) -out:$@ @<< +$(**: = +) +<< + +clean:: + -$(RM) $(LIBASN1_S) + + +# +# Generate list of exports +# +# This target is only used during development to generate a list of +# symbols that are exported from all the object files in LIBASN1_OBJS. +# +exports-list.txt: $(LIBASN1_OBJS) + $(PERL) ..\..\cf\w32-list-externs-from-objs.pl -q -u @<< > $@ +$(**: = +) +<< + +$(OBJ)\asn1_krb5_asn1.c $(OBJ)\krb5_asn1.h: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\krb5.opt \ + $(SRCDIR)\krb5.asn1 krb5_asn1 \ + || ($(RM) $(OBJ)\krb5_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_ocsp_asn1.c $(OBJ)\ocsp_asn1.h: $(BINDIR)\asn1_compile.exe ocsp.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\ocsp.opt \ + $(SRCDIR)\ocsp.asn1 \ + ocsp_asn1 \ + || ($(RM) $(OBJ)\ocsp_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkinit_asn1.c $(OBJ)\pkinit_asn1.h: $(BINDIR)\asn1_compile.exe pkinit.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkinit.asn1 pkinit_asn1 \ + || ($(RM) $(OBJ)\pkinit_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs8_asn1.c $(OBJ)\pkcs8_asn1.h: $(BINDIR)\asn1_compile.exe pkcs8.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs8.asn1 pkcs8_asn1 \ + || ($(RM) $(OBJ)\pkcs8_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs9_asn1.c $(OBJ)\pkcs9_asn1.h: $(BINDIR)\asn1_compile.exe pkcs9.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs9.asn1 pkcs9_asn1 \ + || ($(RM) $(OBJ)\pkcs9_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs10_asn1.c $(OBJ)\pkcs10_asn1.h: $(BINDIR)\asn1_compile.exe pkcs10.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\pkcs10.opt \ + $(SRCDIR)\pkcs10.asn1 \ + pkcs10_asn1 \ + || ($(RM) $(OBJ)\pkcs10_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs12_asn1.c $(OBJ)\pkcs12_asn1.h: $(BINDIR)\asn1_compile.exe pkcs12.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs12.asn1 pkcs12_asn1 \ + || ($(RM) $(OBJ)\pkcs12_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_digest_asn1.c $(OBJ)\digest_asn1.h: $(BINDIR)\asn1_compile.exe digest.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\digest.asn1 digest_asn1 \ + || ($(RM) $(OBJ)\digest_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_kx509_asn1.c $(OBJ)\kx509_asn1.h: $(BINDIR)\asn1_compile.exe kx509.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\kx509.asn1 kx509_asn1 \ + || ($(RM) $(OBJ)\kx509_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_rfc2459_asn1.c $(OBJ)\rfc2459_asn1.h: $(BINDIR)\asn1_compile.exe rfc2459.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\rfc2459.opt \ + $(SRCDIR)\rfc2459.asn1 rfc2459_asn1 \ + || ($(RM) $(OBJ)\rfc2459_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_rfc4108_asn1.c $(OBJ)\rfc4108_asn1.h: $(BINDIR)\asn1_compile.exe rfc4108.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + $(SRCDIR)\rfc4108.asn1 rfc4108_asn1 \ + || ($(RM) $(OBJ)\rfc4108_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_cms_asn1.c $(OBJ)\cms_asn1.h: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file --option-file=$(SRCDIR)\cms.opt \ + $(SRCDIR)\cms.asn1 cms_asn1 \ + || ($(RM) $(OBJ)\cms_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(gen_files_crmf) $(OBJ)\crmf_asn1.h: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file --option-file=$(SRCDIR)\crmf.opt \ + $(SRCDIR)\crmf.asn1 crmf_asn1 \ + || ($(RM) $(OBJ)\crmf_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_x690sample_asn1.c $(OBJ)\x690sample_asn1.h: $(BINDIR)\asn1_compile.exe x690sample.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + $(SRCDIR)\x690sample.asn1 x690sample_asn1 \ + || ($(RM) $(OBJ)\x690sample_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_test_asn1.c $(OBJ)\test_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --option-file=$(SRCDIR)/test.opt \ + --one-code-file \ + $(SRCDIR)\test.asn1 test_asn1 \ + || ($(RM) $(OBJ)\test_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_test_template_asn1.c $(OBJ)\test_template_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --option-file=$(SRCDIR)/test.opt \ + --one-code-file \ + $(SRCDIR)\test.asn1 test_template_asn1 \ + || ($(RM) $(OBJ)\test_template_asn1.h ; exit /b 1) + cd $(SRCDIR) + +INCFILES= \ + $(INCDIR)\der.h \ + $(INCDIR)\heim_asn1.h \ + $(INCDIR)\der-protos.h \ + $(INCDIR)\der-private.h \ + $(INCDIR)\asn1-common.h \ + $(INCDIR)\asn1-template.h \ + $(OBJ)\asn1_err.h + +$(INCDIR)\der-protos.h: $(OBJ)\der-protos.h + +GENINCFILES= \ + $(INCDIR)\asn1_err.h \ + $(INCDIR)\cms_asn1.h \ + $(INCDIR)\crmf_asn1.h \ + $(INCDIR)\digest_asn1.h \ + $(INCDIR)\krb5_asn1.h \ + $(INCDIR)\kx509_asn1.h \ + $(INCDIR)\ocsp_asn1.h \ + $(INCDIR)\pkcs12_asn1.h \ + $(INCDIR)\pkcs8_asn1.h \ + $(INCDIR)\pkcs9_asn1.h \ + $(INCDIR)\pkcs10_asn1.h \ + $(INCDIR)\pkinit_asn1.h \ + $(INCDIR)\rfc2459_asn1.h \ + $(INCDIR)\rfc4108_asn1.h \ + $(INCDIR)\x690sample_asn1.h \ + $(OBJ)\krb5_asn1-priv.h \ + $(OBJ)\ocsp_asn1-priv.h \ + $(OBJ)\pkinit_asn1-priv.h \ + $(OBJ)\cms_asn1-priv.h \ + $(OBJ)\crmf_asn1-priv.h \ + $(OBJ)\rfc2459_asn1-priv.h \ + $(OBJ)\rfc4108_asn1-priv.h \ + $(OBJ)\x690sample_asn1-priv.h \ + $(OBJ)\pkcs8_asn1-priv.h \ + $(OBJ)\pkcs9_asn1-priv.h \ + $(OBJ)\pkcs10_asn1-priv.h \ + $(OBJ)\pkcs12_asn1-priv.h \ + $(OBJ)\digest_asn1-priv.h \ + $(OBJ)\kx509_asn1-priv.h \ + $(OBJ)\test_template_asn1.h \ + $(OBJ)\test_template_asn1-priv.h \ + $(OBJ)\test_asn1.h \ + $(OBJ)\test_asn1-priv.h + +libasn1_base_SOURCES= \ + der_locl.h \ + der.c \ + der.h \ + der_get.c \ + der_put.c \ + der_free.c \ + der_print.c \ + der_length.c \ + der_copy.c \ + der_cmp.c \ + der_format.c \ + template.c \ + heim_asn1.h \ + extra.c \ + timegm.c + +libasn1_SOURCES= \ + oid_resolution.c + +$(OBJ)\der-protos.h: $(libasn1_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -o $(OBJ)\der-protos.h $(libasn1_base_SOURCES) $(libasn1_SOURCES) || $(RM) $(OBJ)\der-protos.h + +$(OBJ)\der-private.h: $(libasn1_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\der-private.h $(libasn1_base_SOURCES) $(libasn1_SOURCES) || $(RM) $(OBJ)\der-private.h + +clean:: + -$(RM) $(INCDIR)\der-protos.h + +all:: $(INCFILES) $(GENINCFILES) $(ASN1_BINARIES) $(LIBASN1) $(LIBASN1_S) + +all-tools:: $(LIBEXECDIR)\asn1_print.exe $(BINDIR)\asn1_gen.exe + +clean:: + -$(RM) $(INCFILES) + -$(RM) $(GENINCFILES) + -$(RM) $(ASN1_BINARIES:.exe=.*) + -$(RM) $(LIBASN1) + -$(RM) $(LIBEXECDIR)\asn1_print.* + -$(RM) $(LIBEXECDIR)\asn1_gen.* + +TEST_BINARIES=\ + $(OBJ)\check-der.exe \ + $(OBJ)\check-gen-template.exe \ + $(OBJ)\check-timegm.exe \ + $(OBJ)\check-ber.exe \ + $(OBJ)\check-template.exe + +test-binaries: $(TEST_BINARIES) + +test-run: + cd $(OBJ) + -check-der.exe + -check-gen-template.exe + -check-timegm.exe + -check-ber.exe + -check-template.exe + cd $(SRC) + +test:: test-binaries test-run + +clean:: + -$(RM) $(TEST_BINARIES:.exe=*) + +$(OBJ)\check-ber.exe: $(OBJ)\check-ber.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-der.exe: $(OBJ)\check-der.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-gen-template.exe: $(OBJ)\check-gen.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_template_asn1.obj + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-timegm.exe: $(OBJ)\check-timegm.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-template.exe: $(OBJ)\check-template.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_asn1.obj + $(EXECONLINK) + $(EXEPREP_NODIST) diff --git a/third_party/heimdal/lib/asn1/README-X681.md b/third_party/heimdal/lib/asn1/README-X681.md new file mode 100644 index 0000000..e0d270b --- /dev/null +++ b/third_party/heimdal/lib/asn1/README-X681.md @@ -0,0 +1,1124 @@ +# Automatic Open Type Handling via X.68x Support in Heimdal's ASN.1 Compiler + +## Table of Contents + + 1. [Introduction](#Introduction) + 2. [Typed Holes / Open Types](#typed-holes--open-types) + 3. [ASN.1 IOS, Constraint, and Parameterization](#asn1-ios-constraint-and-parameterization) + - [IOS Crash Course](#ios-crash-course) + 4. [Usage](#Usage) + 5. [Limitations](#Limitations) + 6. [Implementation Design](#implementation-design) + 7. [Moving From C](#moving-from-c) + +## Introduction + +ASN.1 is a set of specifications for "syntax" for defining data schemas, and +"encoding rules" for encoding values of data of types defined in those schemas. +There are many encoding rules, but one syntax. + +The base of ASN.1 _syntax_ is specified by X.680, an ITU-T standard. The +encoding rules are specified by the X.69x series (X.690 through X.697). + +This README is concerned primarily with the X.68x series. + +While X.680 is essential for implementing many Internet (and other) protocols, +and sufficient for implementing all of those, there are extensions in the +remainder of the X.68x series that can make life a lot easier for developers +who have to use ASN.1 for interoperability reasons. + +Various syntax extensions are specified in X.68x series documents: + + - X.681: Information Object specification + - X.682: Constraint specification + - X.683: Parameterization of ASN.1 specifications + +The intent of X.681, X.682, and X.683 is to add ways to formally express +constraints that would otherwise require natural language to express. Give a +compiler more formally-expressed constraints and it can do more labor-saving +than it could otherwise. + +A subset of these three extensions, X.681, X.682, and X.683, can enable some +rather magical features. These magical features are generally not the focus of +those ITU-T specifications nor of many RFCs that make use of them, but +nonetheless they are of interest to us. + +This README covers some ideas for what this magic is, and implementation of it. + +RFC 6025 does an excellent job of elucidating X.681, which otherwise most +readers unfamiliar with it will no doubt find inscrutable. Hopefully this +README improves that further. + +The magic that we're after is simply the *automatic and recursive handling of +open types by an ASN.1 compiler*. + +Combined with eventual support for the ASN.1 JSON Encoding Rules (JER) [X.697], +this feature could give us unprecendented visibility into really complex data +structures, such as Endorsement Key Certificates (EKcerts) for Trusted Platform +Module (TPM) applications. + +Support for JER and automatic handling of open types should allow us to +trivially implement a command-line tool that can parse any DER or JER (JSON) +encoding of any value whose type is known and compiled, and which could +transcode to the other encoding rules. I.e., dump DER to JSON, and parse JSON +to output DER. + +Indeed, Heimdal's `asn1_print` program currently supports transcoding of DER to +JSON, though it's not quite X.697-compliant JSON! Heimdal does not currently +support parsing JSON-encoded values of ASN.1 types. + +Combined with transcoders for JSON/CBOR and other binary-JSON formats, we could +support those encodings too. + +We could really see how much space OER/JER/CBOR save over DER for Kerberos +tickets, PKIX certificates, and much else. + +We especially want this for PKIX, and more than anything for certificates, as +the TBSCertificate type is full of deeply nested open types: DNs and +subjectDirectory attributes, otherName SAN types, and certificate extensions. + +Besides a magical ASN.1 DER/JER dumper/transcoder utility, we want to replace +DN attribute and subject alternative name (SAN) `otherName` tables and much +hand-coded handling of certificate extensions in `lib/hx509/`. + +The reader should already be familiar with ASN.1, which anyways is a set of two +things: + + - an abstract syntax for specifying schemas for data interchange + + - a set of encoding rules + +A very common thing to see in projects that use ASN.1, as well as projects that +use alternatives to ASN.1, is a pattern known as the "typed hole" or "open +type". + +The ASN.1 Information Object System (IOS) [X.681] is all about automating the +otherwise very annoying task of dealing with "typed holes" / "open types". + +The ASN.1 IOS is not sufficient to implement the magic we're after. Also +needed is constraint specification and parameterization of types. + +ITU-T references: + +https://www.itu.int/rec/T-REC-X.680-201508-I/en +https://www.itu.int/rec/T-REC-X.681-201508-I/en +https://www.itu.int/rec/T-REC-X.682-201508-I/en +https://www.itu.int/rec/T-REC-X.683-201508-I/en + + +## Typed Holes / Open Types + +A typed hole or open type is a pattern of data structure that generally looks +like: + +``` + { type_id, bytes_encoding_a_value_of_a_type_identified_by_type_id } +``` + +I.e., an opaque datum and an identifier of what kind of datum that is. This +happens because the structure with the typed hole is used in contexts where it +can't know all possible things that can go in it. In many cases we do know +what all possible things are that can go in a typed hole, but many years ago +didn't, say, or anyways, had a reason to use a typed hole. + +These are used not only in protocols that use ASN.1, but in many protocols that +use syntaxes and encodings unrelated to ASN.1. I.e., these concepts are *not* +ASN.1-specific. + +Many Internet protocols use typed holes, and many use typed holes in ASN.1 +types. For example, PKIX, Kerberos, LDAP, and others, use ASN.1 and typed +holes. + +For examples of an Internet protocol that does not use ASN.1 but which still +has typed holes, see IP, MIME, SSHv2, IKEv2, and others. Most quintessentilly, +IP itself, since IP packet payloads are for some upper layer protocol +identified in the IP packet header. + +In ASN.1 these generally look like: + +```ASN.1 + TypedHole ::= SEQUENCE { + typeId INTEGER, + opaque OCTET STRING + } +``` + +or + +```ASN.1 + -- Old ASN.1 style + TypedHole ::= SEQUENCE { + typeId OBJECT IDENTIFIER, + opaque ANY DEFINED BY typeID + } +``` + +or + +```ASN.1 + -- Old ASN.1 style + TypedHole ::= SEQUENCE { + typeId OBJECT IDENTIFIER, + opaque ANY -- DEFINED BY typeID + } +``` + +or any number of variations. + + Note: the `ANY` variations are no longer conformant to X.680 (the base + ASN.1 specification). + +The pattern is `{ id, hole }` where the `hole` is ultimately an opaque sequence +of bytes whose content's schema is identified by the `id` in the same data +structure. The pattern does not require just two fields, and it does not +require any particular type for the hole, nor for the type ID. Sometimes the +"hole" is an `OCTET STRING`, sometimes it's a `BIT STRING`, sometimes it's an +`ANY` or `ANY DEFINED BY`. Sometimes the hole is even an array of (`SET OF` or +`SEQUENCE OF`, in ASN.1) values of the type identified by the id field. + +An example from PKIX: + +```ASN.1 +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, -- <- type ID + critical BOOLEAN OPTIONAL, + extnValue OCTET STRING, -- <- hole +} +``` + +which shows that typed holes don't always have just three fields, and the type +identifier isn't always an integer. + +Now, Heimdal's ASN.1 compiler generates the obvious C data structure for PKIX's +`Extension` type: + +```C + typedef struct Extension { + heim_oid extnID; + int *critical; + heim_octet_string extnValue; + } Extension; +``` + +and applications using this compiler have to inspect the `extnID` field, +comparing it to any number of OIDs, to determine the type of `extnValue`, then +must call `decode_ThatType()` to decode whatever that octet string has. + +This is very inconvenient. + +Compare this to the handling of discriminated unions (what ASN.1 calls a +`CHOICE`): + +```C + /* + * ASN.1 definition: + * + * DistributionPointName ::= CHOICE { + * fullName [0] IMPLICIT SEQUENCE OF GeneralName, + * nameRelativeToCRLIssuer [1] RelativeDistinguishedName, + * } + */ + + /* C equivalent */ + typedef struct DistributionPointName { + enum DistributionPointName_enum { + choice_DistributionPointName_fullName = 1, + choice_DistributionPointName_nameRelativeToCRLIssuer + } element; + union { + struct DistributionPointName_fullName { + unsigned int len; + GeneralName *val; + } fullName; + RelativeDistinguishedName nameRelativeToCRLIssuer; + } u; + } DistributionPointName; +``` + +The ASN.1 encoding on the wire of a `CHOICE` value, almost no matter the +encoding rules, looks... remarkably like the encoding of a typed hole. Though +generally the alternatives of a discriminated union have to all be encoded with +the same encoding rules, whereas with typed holes the encoded data could be +encoded in radically different encoding rules than the structure containing it +in a typed hole. + +In fact, extensible `CHOICE`s are handled by our compiler as a discriminated +union one of whose alternatives is a typed hole when the `CHOICE` is +extensible: + +```C + typedef struct DigestRepInner { + enum DigestRepInner_enum { + choice_DigestRepInner_asn1_ellipsis = 0, /* <--- unknown CHOICE arm */ + choice_DigestRepInner_error, + choice_DigestRepInner_initReply, + choice_DigestRepInner_response, + choice_DigestRepInner_ntlmInitReply, + choice_DigestRepInner_ntlmResponse, + choice_DigestRepInner_supportedMechs + /* ... */ + } element; + union { + DigestError error; + DigestInitReply initReply; + DigestResponse response; + NTLMInitReply ntlmInitReply; + NTLMResponse ntlmResponse; + DigestTypes supportedMechs; + heim_octet_string asn1_ellipsis; /* <--- unknown CHOICE arm */ + } u; + } DigestRepInner; +``` + +The critical thing to understand is that our compiler automatically decodes +(and encodes) `CHOICE`s' alternatives, but it used to NOT do that for typed +holes because it knows nothing about them. Now, however, our compiler can +do this for typed holes provided the module specifies what the alternatives +are. + +It would be nice if we could treat *all* typed holes like `CHOICE`s whenever +the compiler knows the alternatives! + +And that's exactly what the ASN.1 IOS system makes possible. With ASN.1 IOS +support, our compiler can automatically decode all the `Certificate` +extensions, and all the distinguished name extensions it knows about. + +There is a fair bit of code in `lib/hx509/` that deals with encoding and +decoding things in typed holes where the compiler could just handle that +automatically for us, allowing us to delete a lot of code. + +Even more importantly, if we ever add support for visual encoding rules of +ASN.1, such as JSON Encoding Rules (JER) [X.697] or Generic String Encoding +Rules (GSER) [RFC2641], we could have a utility program to automatically +display or compile DER (and other encodings) of certifcates and many other +interesting data structures. + +Indeed, we do now have such a utility (`asn1_print`), able to transcode DER to +JSON. + +## ASN.1 IOS, Constraint, and Parameterization + +The ASN.1 IOS is additional syntax that allows ASN.1 module authors to express +all the details about typed holes that ASN.1 compilers need to make developers' +lives much easier. + +RFC5912 has lots of examples, such as this `CLASS` corresponding to the +`Extension` type from PKIX: + +```ASN.1 + -- A class that provides some of the details of the PKIX Extension typed + -- hole: + EXTENSION ::= CLASS { + -- The following are fields of a class (as opposed to "members" of + -- SEQUENCE or SET types): + &id OBJECT IDENTIFIER UNIQUE, -- This is a fixed-type value field. + -- UNIQUE -> There can be only one + -- object with this OID + -- in any object set of + -- this class. + -- I.e., this is like a + -- PRIMARY KEY in a SQL + -- TABLE spec. + &ExtnType, -- This is a type field (the hole). + &Critical BOOLEAN DEFAULT {TRUE | FALSE } -- fixed-type value set field. + } WITH SYNTAX { + -- This is a specification of easy to use (but hard-to-parse) syntax for + -- specifying instances of this CLASS: + SYNTAX &ExtnType IDENTIFIED BY &id + [CRITICALITY &Critical] + } + + -- Here's a parameterized Extension type. The formal parameter is an as-yet + -- unspecified set of valid things this hole can carry for some particular + -- instance of this type. The actual parameter will be specified later (see + -- below). + Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + -- The type ID has to be the &id field of the EXTENSION CLASS of the + -- ExtensionSet object set parameter. + extnID EXTENSION.&id({ExtensionSet}), + -- This is the critical field, whose DEFAULT value should be that of + -- the &Critical field of the EXTENSION CLASS of the ExtensionSet object + -- set parameter. + critical BOOLEAN + -- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + -- Finally, the hole is an OCTET STRING constrained to hold the encoding + -- of the type named by the &ExtnType field of the EXTENSION CLASS of the + -- ExtensionSet object set parameter. + -- + -- Note that for all members of this SEQUENCE, the fields of the object + -- referenced must be of the same object in the ExtensionSet object set + -- parameter. That's how we get to say that some OID implies some type + -- for the hole. + extnValue OCTET STRING (CONTAINING + EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + -- contains the DER encoding of the ASN.1 value + -- corresponding to the extension type identified + -- by extnID + } + + -- This is just a SEQUENCE of Extensions, the parameterized version. + Extensions{EXTENSION:ExtensionSet} ::= + SEQUENCE SIZE (1..MAX) OF Extension{{ExtensionSet}} +``` + +and these uses of it in RFC5280 (PKIX base) where the actual parameter is +given: + +```ASN.1 + -- Here we have an individual "object" specifying that the OID + -- id-ce-authorityKeyIdentifier implies AuthorityKeyIdentifier as the hole + -- type: + ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX + AuthorityKeyIdentifier IDENTIFIED BY + id-ce-authorityKeyIdentifier } + + -- And here's the OID, for completeness: + id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + ... + + -- And Here's an object set for the EXTENSION CLASS collecting a bunch of + -- related extensions (here they are the extensions that certificates can + -- carry in their extensions member): + CertExtensions EXTENSION ::= { + ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | + ext-KeyUsage | ext-PrivateKeyUsagePeriod | + ext-CertificatePolicies | ext-PolicyMappings | + ext-SubjectAltName | ext-IssuerAltName | + ext-SubjectDirectoryAttributes | + ext-BasicConstraints | ext-NameConstraints | + ext-PolicyConstraints | ext-ExtKeyUsage | + ext-CRLDistributionPoints | ext-InhibitAnyPolicy | + ext-FreshestCRL | ext-AuthorityInfoAccess | + ext-SubjectInfoAccessSyntax, ... } + ... + + -- Lastly, we have a Certificate, and the place where the Extensions type's + -- actual parameter is specified. + -- + -- This is where the rubber meets the road: + + Certificate ::= SIGNED{TBSCertificate} + + TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, + {SignatureAlgorithms}}, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + ... , + [[2: -- If present, version MUST be v2 + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + ]], + [[3: -- If present, version MUST be v3 -- + extensions [3] Extensions{{CertExtensions}} OPTIONAL + -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + -- The rubber meets the road *here*. + -- + -- This says that the set of *known* certificate + -- extensions are those for which there are "objects" + -- in the "object set" named CertExtensions. + ]], ... } +``` + +Notice that the `extensions` field of `TBSCertificate` is of type `Extensions` +parametrized by the `CertExtensions` "information object set". + +This allows the compiler to know that if any of the OIDs listed in the +`CertExtensions` object set appear as the actual value of the `extnID` member +of an `Extension` value, then the `extnValue` member of the same `Extension` +value must be an instance of the type associated with that OID. For example, +an `Extension` with `extnID` value of `id-ce-authorityKeyIdentifier` must have +an `extnValue` of type `AuthorityKeyIdentifier`. + + +### IOS Crash Course + +The ASN.1 IOS may be... a bit difficult to understand -- the syntax isn't +pretty. And X.681 has a lot of strange terminology, like "variable type value +set field". + +An IOS "class" has fields, and those fields are of kind +`[Fixed]Type[Value[Set]]` or `Object[Set]`. Then there's "objects" and "object +sets". Hopefully this section will make all of that comprehensible. + +_Classes_ have fields of various kinds. More on this below. + +_Classes_ can also have zero, one, or more _object sets_ associated with them, +and each object set has zero, one, or more _objects_ that are also themselves +associated with classes. Each object has a setting for each required field of +a class, and possibly also for optional/defaulted fields as well. + +As X.681 explains, IOS object sets really are akin to relational database +tables, while objects are akin to rows of the same, with columns specified by +classes. + +Or one can think of _classes_ as relational tables with one predefined column +naming object sets, and rows being objects grouped into object sets by that +column. IOS supports complex path expressions across these objects (but we +won't need to support that yet). + +These relational entities are immutable in that they are defined in ASN.1 +modules that are compiled and there is no way to change them at run-time, only +query them (although perhaps object sets marked as extensible are intended to +be extensible at run-time?). To mutate them one must edit the ASN.1 module +that defines them and recompile it. IOS entities also have no on-the-wire +representation. + +So far, the IOS seems just so useless to us: we have some, but non-urgent need +to specify immutable relational data. For example, cryptosystem parameters, +which PKIX does define using IOS, but again: not urgent. + +The magic for us lies in being able to document and constrain actual datatypes +using the IOS [X.681], constraint specification [X.682], and type +parameterization [X.683]. We can express the following things: + + - that some _member_ of a `SET` or `SEQUENCE` is of open type + + - that some _member_ of a `SET` or `SEQUENCE` identifies a type encoded into + an open type member of the same (or related) `SET` or `SEQUENCE` + + - what pairs of `{type ID value, type}` are allowed for some `SET`'s or + `SEQUENCE`'s open type members + +With this our ASN.1 compiler has the metadata it needs in order to +auto-generate decoding and encoding of values of open types. + +A termnology point: `CHOICE`, `SET`, and `SEQUENCE` types have "members", but +_classes_ and _objects_ have "fields", and _object sets_ have "elements". + +Objects must have "_settings_" for all the required fields of the object's +class and none, some, or all of the `OPTIONAL` or `DEFAULT` fields of the +class. This is very similar to `SET`/`SEQUENCE` members, which can be +`OPTIONAL` or `DEFAULT`ed. + +The _members_ (we call them fields in C, instance variables in C++, Java, ...) +of a `SET` or `SEQUENCE` type are typed, just as in C, C++, Java, etc. for +struct or object types. + +There are several kinds of fields of classes. These can be confusing, so it is +useful that we explain them by reference to how they relate to the members of +`SEQUENCE` types constrained by object sets: + + - A `type field` of a class is one that specifies a `SET` or `SEQUENCE` member + of unknown (i.e., open) type. + + The type of that `SET` or `SEQUENCE` member will not be not truly unknown, + but determined by some other member of the SET or SEQUENCE, and that will be + specified in a "value field" (or "value set" field) an "object" in an + "object set" of that class. + + This is essentially a "type variable", akin to those seen in high-level + languages like Haskell. + + - A `fixed type value field` of a class is one that specifies a SET or + SEQUENCE member of fixed type. Being of fixed-type, this is not a type + variable, naturally. + + - A `fixed type value set field` of a class is like a `fixed type value + field`, but where object sets should provide a set of values with which to + constrain `SET`/`SEQUENCE` members corresponding to the field. + + - A `variable type value [set] field` is one where the type of the `SET` or + `SEQUENCE` member corresponding to the field will vary according to some + specified `type field` of the same class. + + - An `object field` will be a field that names another class (possibly the + same class), which can be used to provide rich hierarchical type semantics + that... we mostly don't need for now. + + These define relations between classes, much like `FOREIGN KEY`s in SQL. + + These are also known as `link fields`. + + - Similarly for `object set field`s. + +As usual for ASN.1, the case of the first letter of a field name is meaningful: + + - value and object field names start with a lower case letter; + - type, value set, and object set fields start with an upper-case letter. + +The form of a `fixed type value` field and a `fixed type value set` field is +the same, differing only the case of the first letter of the field name. +Similarly for `variable type value` and `variable type value set` fields. +Similarly, again, for `object` and `object set` fields. + +Here's a simple example from PKIX: + +```ASN.1 + -- An IOS class used to impose constraints on the PKIX Extension type: + EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType, + &Critical BOOLEAN DEFAULT {TRUE | FALSE } + } WITH SYNTAX { + SYNTAX &ExtnType IDENTIFIED BY &id + [CRITICALITY &Critical] + } +``` + + - The `&id` field of `EXTENSION` is a fixed-type value field. It's not a + fixed-type value _set_ field because its identifier (`id`) starts with a + lower-case letter. + + The `&id` field is intended to make the `extnId` member of the `Extension` + `SEQUENCE` type name identify the actual type of the `extnValue` member of + the same `SEQUENCE` type. + + Note that `UNIQUE` keyword tells us there can be only one object with any + given value of this field in any object set of this class. (There is no way + to specify the equivalent of a multi-column `PRIMARY KEY` from SQL, only + single-column primary/unique keys. Note that the `&id` field is not marked + `OPTIONAL` or `DEFAULT`, which is like saying it's `NOT NULL` in SQL.) + + - The `&ExtnType` field is a type field. We can tell because no type is named + in its declaration! + + - The `&Critical` field is a fixed-type value set field. We can tell because + it specifies a type (`BOOLEAN`) and starts with an upper-case letter. + + In-tree we could avoid having to implement fixed-type value set fields by + renaming this one to `&critical` and eliding its `DEFAULT ` given + that we know there are only two possible values for a `BOOLEAN` field. + + - Ignore the `WITH SYNTAX` clause for now. All it does is specify a + user-friendly but implementor-hostile syntax for specifying objects. + +Note that none of the `Extension` extensions in PKIX actually specify +`CRITICALITY`/`&Critical`, so... we just don't need fixed-type value set +fields. We could elide the `&Critical` field of the `EXTENSION` class +altogether. + +Here's another, much more complex example from PKIX: + +```ASN.1 + ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + &equality-match MATCHING-RULE OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL + } + MATCHING-RULE ::= CLASS { + &ParentMatchingRules MATCHING-RULE OPTIONAL, + &AssertionType OPTIONAL, + &uniqueMatchIndicator ATTRIBUTE OPTIONAL, + &id OBJECT IDENTIFIER UNIQUE + } +``` + + - For `ATTRIBUTE` the fields are: + - The `&id` field is a fixed-type value field (intended to name the type of + members linked to the `&Type` field). + - The `&Type` field is a type field (open type). + - The `&equality-match` is an object field linking to object sets of the + `MATCHING-RULE` class. + - The `minCount` and `maxCount` fields are fixed-type value fields. + - For `MATCHING-RULE` the fields are: + - The `&ParentMatchingRules` is an object set field linking to more + `MATCHING-RULE`s. + - The `&AssertionType` field is a type field (open type). + - The `&uniqueMatchIndicator` field is an object field linking back to some + object of the `ATTRIBUTE` class that indicates whether the match is + unique (presumably). + - The `&id` field is a fixed-type value field (intended to name the type of + members linked to the `&AssertionType` field). + +No `Attribute`s in PKIX (at least RFC 5912) specify matching rules, so we +really don't need support for object nor object set fields. + +Because + - no objects in object sets of `EXTENSION` in PKIX specify "criticality", + - and no objects in object sets of `ATTRIBUTE` in PKIX specify matching rules, + - and no matching rules are specified in PKIX (or maybe just one), +we can drop `MATCHING-RULE` and simplify `ATTRIBUTE` and `EXTENSION` as: + +```ASN.1 + EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType + } + ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL + } +``` + +X.681 has an example in appendix D.2 that has at least one field of every kind. + +Again, the rubber that are IOS classes and object sets meet the road when +defining types: + +```ASN.1 + -- Define the Extension type but link it to the EXTENSION class so that + -- an object set for that class can constrain it: + Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + extnID EXTENSION.&id({ExtensionSet}), + critical BOOLEAN + (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + extnValue OCTET STRING (CONTAINING + EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + } + -- Most members of TBSCertificate elided for brevity: + TBSCertificate ::= SEQUENCE { + ..., + extensions [3] Extensions{{CertExtensions}} OPTIONAL + -- ^^^^^^^^^^^^^^^^ + -- the rubber meets the road here!! + ... + } + + OTHER-NAME ::= TYPE-IDENTIFIER + -- Most members of GeneralName elided for brevity: + GeneralName ::= CHOICE { + otherName [0] INSTANCE OF OTHER-NAME({KnownOtherNames}), + -- ^^^^^^^^^^^^^^^^^ + -- rubber & road meet! + ... + } +``` + +(The `CertExtensions` and `KnownOtherNames` object sets are not shown here for +brevity. PKIX doesn't even define an `KnownOtherNames` object set, though it +well could.) + +The above demonstrates two ways to create `SEQUENCE` types that are constrained +by IOS classes. One is by defining the types of the members of a `SEQUENCE` +type by reference to class fields. The other is by using `INSTANCE OF` to say +that the class defines the type directly. The first lets us do things like +have a mix members of a `SEQUENCE` type where some are defined by relation to a +class and others are not, or where multiple classes are used. + +In the case of `INSTANCE OF`, what shall the names of the members of the +derived type be? Well, such types can _only_ be instances of `TYPE-IDENTIFIER` +or classes copied from and isomorphic to it (as `OTHER-NAME` is in the above +exammle), and so the names of their two members are just baked in by X.681 +annex C.1 as: + +```ASN.1 + SEQUENCE { + type-id .&id, + value[0] .&Type + } + -- where is the name of the class, which has to be + -- `TYPE-IDENTIFIER` or exactly like it. +``` + +(This means we can't use `INSTANCE OF` with `EXTENSION`, though we can for +`OTHER-NAME`.) + +PKIX has much more complex classes for relating and constraining cryptographic +algorithms and their parameters: + + - `DIGEST-ALGORITHM`, + - `SIGNATURE-ALGORITHM`, + - `PUBLIC-KEY`, + - `KEY-TRANSPORT`, + - `KEY-AGREE`, + - `KEY-WRAP`, + - `KEY-DERIVATION`, + - `MAC-ALGORITHM`, + - `CONTENT-ENCRYPTION`, + - `ALGORITHM`, + - `SMIME-CAPS`, + - and `CURVE`. + +These show the value of just the relational data aspect of IOS. They can not +only be used by the codecs at run-time to perform validation of, e.g., +cryptographic algorithm parameters, but also to provide those rules to other +code in the application so that the programmer doesn't have to manually write +the same in C, C++, Java, etc, and can refer to them when applying those +cryptographic algorithms. And, of course, the object sets for the above +classes can be and are specified in standards documents, making it very easy to +import them into projects that have an IOS-capable ASN.1 compiler. + +Still, for Heimdal we won't bother with the full power of X.681/X.682/X.683 for +now. + +## Usage + +To use this feature you must use the `--template` and `--one-code-file` +arguments to `asn1_compile`. C types are generated from ASN.1 types as +described above. + +Note that failure to decode open type values does not cause decoding to fail +altogether. It is important that applications check for undecoded open types. +Open type decoding failures manifest as `NULL` values for the `u` field of the +decoded open type structures (see above). + +For examples of X.681/X.682/X.683 usage, look at `lib/asn1/rfc2459.asn1`. + +## Limitations + + - `AtNotation` supported is very limited. + + - Object set extensibility is not supported. + + - Only one formal (and actual) type parameter is supported at this time. + + - `TYPE-IDENTIFIER` is not built-in at this time. (But users can define it as + specified.) + + - `CLASS` "copying" is not supported at this time. + + - Link fields are not supported. + + - `Information from objects` constructs are not supported. + + - `IMPORTS` of IOS entities are not supported at this time. + + - ... + +## Implementation Design + +NOTE: This has already be implemented in the `master` branch of Heimdal. + + - The required specifications, X.681, X.682, and X.683, are fairly large and + non-trivial. We can implement just the subset of those three that we need + to implement PKIX, just as we already implement just the subset of X.680 + that we need to implement PKIX and Kerberos. + + For dealing with PKIX, the bare minimum of IOS classes we want are: + + - `ATTRIBUTE` (used for `DN` attributes in RFC5280, specifically for the + `SingleAttribute` and `AttributeSet` types, RDNs, and the + `subjectDirectoryAttributes` extension) + - `EXTENSION` (used for `Extension`, i.e., certificate extensions in + RFC5280) + - `TYPE-IDENTIFIER` (used for `OtherName` and for CMS' `Content-Type`) + + The minimal subset of X.681, X.682, and X.683 needed to implement those + three is all we need. + + _Eventually_ we may want to increase that subset so as to implement other + IOS classes from PKIX, such as `DIGEST-ALGORITHM`, and to provide object + sets and query functionality for them to applications so that we can use + standard modules to encode information about cryptosystems. But not right + now. + + Note that there's no object set specified for OTHER-NAME instances, but we + can and have creates our own. We want magic open type decoding to recurse + all the way down and handle DN attributes, extensions, SANs, policy + qualifiers, the works. + + - We'll really want to do this mainly for the template compiler and begin + abandoning the original compiler. The codegen backend generates the same C + types, but no code for automatic, recursive handling of open types. + + Maintaining two compiler backends is difficult enough; adding complex + features beyond X.680 to both is too much work. The template compiler is + simply superior just on account of its output size scaling as `O(N)` instead + of `O(M * N)` where `M` is the number of encoding rules supported and `N` is + the size of an ASN.1 module (or all modules). + + - Also, to make the transition to using IOS in-tree, we'll want to keep + existing fields of C structures as generated by the compiler today, only + adding new ones, that way code that hasn't been updated to use the automatic + encoding/decoding can still work and we can then update Heimdal in-tree + slowly to take advantage of the new magic. + + Below are the C types for the ASN.1 PKIX types we care about, as generated + by the current prototype. + + `Extension` compiles to: + +```C +typedef struct Extension { + heim_oid extnID; + int critical; + heim_octet_string extnValue; + /* NEW: */ + struct { + enum { + choice_Extension_iosnumunknown = 0, + choice_Extension_iosnum_id_x509_ce_authorityKeyIdentifier, + choice_Extension_iosnum_id_x509_ce_subjectKeyIdentifier, + choice_Extension_iosnum_id_x509_ce_keyUsage, + choice_Extension_iosnum_id_x509_ce_privateKeyUsagePeriod, + choice_Extension_iosnum_id_x509_ce_certificatePolicies, + choice_Extension_iosnum_id_x509_ce_policyMappings, + choice_Extension_iosnum_id_x509_ce_subjectAltName, + choice_Extension_iosnum_id_x509_ce_issuerAltName, + choice_Extension_iosnum_id_x509_ce_basicConstraints, + choice_Extension_iosnum_id_x509_ce_nameConstraints, + choice_Extension_iosnum_id_x509_ce_policyConstraints, + choice_Extension_iosnum_id_x509_ce_extKeyUsage, + choice_Extension_iosnum_id_x509_ce_cRLDistributionPoints, + choice_Extension_iosnum_id_x509_ce_inhibitAnyPolicy, + choice_Extension_iosnum_id_x509_ce_freshestCRL, + choice_Extension_iosnum_id_pkix_pe_authorityInfoAccess, + choice_Extension_iosnum_id_pkix_pe_subjectInfoAccess, + } element; + union { + void *_any; + AuthorityKeyIdentifier* ext_AuthorityKeyIdentifier; + SubjectKeyIdentifier* ext_SubjectKeyIdentifier; + KeyUsage* ext_KeyUsage; + PrivateKeyUsagePeriod* ext_PrivateKeyUsagePeriod; + CertificatePolicies* ext_CertificatePolicies; + PolicyMappings* ext_PolicyMappings; + GeneralNames* ext_SubjectAltName; + GeneralNames* ext_IssuerAltName; + BasicConstraints* ext_BasicConstraints; + NameConstraints* ext_NameConstraints; + PolicyConstraints* ext_PolicyConstraints; + ExtKeyUsage* ext_ExtKeyUsage; + CRLDistributionPoints* ext_CRLDistributionPoints; + SkipCerts* ext_InhibitAnyPolicy; + CRLDistributionPoints* ext_FreshestCRL; + AuthorityInfoAccessSyntax* ext_AuthorityInfoAccess; + SubjectInfoAccessSyntax* ext_SubjectInfoAccessSyntax; + } u; + } _ioschoice_extnValue; +} Extension; +``` + + The `SingleAttribute` and `AttributeSet` types compile to: + +```C +typedef struct SingleAttribute { + heim_oid type; + HEIM_ANY value; + struct { + enum { + choice_SingleAttribute_iosnumunknown = 0, + choice_SingleAttribute_iosnum_id_at_name, + choice_SingleAttribute_iosnum_id_at_surname, + choice_SingleAttribute_iosnum_id_at_givenName, + choice_SingleAttribute_iosnum_id_at_initials, + choice_SingleAttribute_iosnum_id_at_generationQualifier, + choice_SingleAttribute_iosnum_id_at_commonName, + choice_SingleAttribute_iosnum_id_at_localityName, + choice_SingleAttribute_iosnum_id_at_stateOrProvinceName, + choice_SingleAttribute_iosnum_id_at_organizationName, + choice_SingleAttribute_iosnum_id_at_organizationalUnitName, + choice_SingleAttribute_iosnum_id_at_title, + choice_SingleAttribute_iosnum_id_at_dnQualifier, + choice_SingleAttribute_iosnum_id_at_countryName, + choice_SingleAttribute_iosnum_id_at_serialNumber, + choice_SingleAttribute_iosnum_id_at_pseudonym, + choice_SingleAttribute_iosnum_id_domainComponent, + choice_SingleAttribute_iosnum_id_at_emailAddress, + } element; + union { + void *_any; + X520name* at_name; + X520name* at_surname; + X520name* at_givenName; + X520name* at_initials; + X520name* at_generationQualifier; + X520CommonName* at_x520CommonName; + X520LocalityName* at_x520LocalityName; + DirectoryString* at_x520StateOrProvinceName; + DirectoryString* at_x520OrganizationName; + DirectoryString* at_x520OrganizationalUnitName; + DirectoryString* at_x520Title; + heim_printable_string* at_x520dnQualifier; + heim_printable_string* at_x520countryName; + heim_printable_string* at_x520SerialNumber; + DirectoryString* at_x520Pseudonym; + heim_ia5_string* at_domainComponent; + heim_ia5_string* at_emailAddress; + } u; + } _ioschoice_value; +} SingleAttribute; +``` + + and + +```C +typedef struct AttributeSet { + heim_oid type; + struct AttributeSet_values + { + unsigned int len; + HEIM_ANY* val; + } values; + struct { + enum { + choice_AttributeSet_iosnumunknown = 0, + choice_AttributeSet_iosnum_id_at_name, + choice_AttributeSet_iosnum_id_at_surname, + choice_AttributeSet_iosnum_id_at_givenName, + choice_AttributeSet_iosnum_id_at_initials, + choice_AttributeSet_iosnum_id_at_generationQualifier, + choice_AttributeSet_iosnum_id_at_commonName, + choice_AttributeSet_iosnum_id_at_localityName, + choice_AttributeSet_iosnum_id_at_stateOrProvinceName, + choice_AttributeSet_iosnum_id_at_organizationName, + choice_AttributeSet_iosnum_id_at_organizationalUnitName, + choice_AttributeSet_iosnum_id_at_title, + choice_AttributeSet_iosnum_id_at_dnQualifier, + choice_AttributeSet_iosnum_id_at_countryName, + choice_AttributeSet_iosnum_id_at_serialNumber, + choice_AttributeSet_iosnum_id_at_pseudonym, + choice_AttributeSet_iosnum_id_domainComponent, + choice_AttributeSet_iosnum_id_at_emailAddress, + } element; + unsigned int len; + union { + void *_any; + X520name* at_name; + X520name* at_surname; + X520name* at_givenName; + X520name* at_initials; + X520name* at_generationQualifier; + X520CommonName* at_x520CommonName; + X520LocalityName* at_x520LocalityName; + DirectoryString* at_x520StateOrProvinceName; + DirectoryString* at_x520OrganizationName; + DirectoryString* at_x520OrganizationalUnitName; + DirectoryString* at_x520Title; + heim_printable_string* at_x520dnQualifier; + heim_printable_string* at_x520countryName; + heim_printable_string* at_x520SerialNumber; + DirectoryString* at_x520Pseudonym; + heim_ia5_string* at_domainComponent; + heim_ia5_string* at_emailAddress; + } *val; + } _ioschoice_values; +} AttributeSet; +``` + + The `OtherName` type compiles to: + +```C +typedef struct OtherName { + heim_oid type_id; + HEIM_ANY value; + struct { + enum { + choice_OtherName_iosnumunknown = 0, + choice_OtherName_iosnum_id_pkix_on_xmppAddr, + choice_OtherName_iosnum_id_pkix_on_dnsSRV, + choice_OtherName_iosnum_id_pkix_on_hardwareModuleName, + choice_OtherName_iosnum_id_pkix_on_permanentIdentifier, + choice_OtherName_iosnum_id_pkix_on_pkinit_san, + choice_OtherName_iosnum_id_pkix_on_pkinit_ms_san, + } element; + union { + void *_any; + heim_utf8_string* on_xmppAddr; + heim_ia5_string* on_dnsSRV; + HardwareModuleName* on_hardwareModuleName; + PermanentIdentifier* on_permanentIdentifier; + KRB5PrincipalName* on_krb5PrincipalName; + heim_utf8_string* on_pkinit_ms_san; + } u; + } _ioschoice_value; +} OtherName; +``` + + If a caller to `encode_Certificate()` passes a certificate object with + extensions with `_ioselement == choice_Extension_iosnumunknown` (or + whatever, for each open type), then the encoder will use the `extnID` and + `extnValue` fields, otherwise it will use the new `_ioschoice_extnValue` + field and leave `extnID` and `extnValue` cleared. If both are set, the + `extnID` and `extnValue` fields, and also the new `_ioschoice_extnValue` + field, then the encoder will ignore the latter. + + In both cases, the `critical` field gets used as-is. The rule is be that we + support *two* special C struct fields for open types: a hole type ID enum + field, and a decoded hole value union. All other fields will map to either + normal (possibly constrained) members of the SET/SEQUENCE. + + - Type ID values get mapped to discrete enum values. Object sets get sorted + by object type IDs so that for decoding they can be and are binary-searched. + For encoding and other cases (destructors and copy constructors) we directly + index the object set by the mapped type ID enum. + + - The C header generator remains shared between the two backends. + + - SET and SEQUENCE types containing an open type are represented as follows in + their templates. + +```C + extern const struct asn1_template asn1_CertExtensions[]; + /*...*/ + const struct asn1_template asn1_Extension_tag__22[] = { + /* 0 */ { 0, sizeof(struct Extension), ((void*)5) }, + /* 1 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_OID), + offsetof(struct Extension, extnID), + asn1_AttributeType_tag__1 }, + /* 2 */ { A1_OP_DEFVAL | A1_DV_BOOLEAN, ~0, (void*)0 }, + /* 3 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Boolean) | A1_FLAG_DEFAULT, + offsetof(struct Extension, critical), + asn1_Extension_tag_critical_24 }, + /* 4 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_OctetString), + offsetof(struct Extension, extnValue), + asn1_Extension_tag_extnValue_25 }, + /* NEW: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ + /* 5 */ { A1_OP_OPENTYPE_OBJSET | 0 | (2 << 10) | 0, + offsetof(Extension, _ioschoice_extnValue), + asn1_CertExtensions } + }; + const struct asn1_template asn1_Extension[] = { + /* 0 */ { 0, sizeof(Extension), ((void*)1) }, + /* 1 */ { A1_TAG_T(ASN1_C_UNIV, CONS, UT_Sequence), + 0, asn1_Extension_tag__22 } + }; + + /* NEW: */ + const struct asn1_template asn1_CertExtensions[] = { + /* + * Header template entry bearing the count of objects in + * this object set: + */ + /* 0 */ { 0, 0, ((void*)18) }, + + /* + * Value of object #0 in this set: two entries, one naming + * a type ID field value, and the other naming the type + * that corresponds to that value. + * + * In this case, the first object is for the + * AuthorityKeyIdentifier type as a certificate extension. + */ + /* 1 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_x509_ce_authorityKeyIdentifier }, + /* 2 */ { A1_OP_OPENTYPE, sizeof(AuthorityKeyIdentifier), + (const void*)&asn1_AuthorityKeyIdentifier }, + + /* Value of object #1 (SubjectKeyIdentifier): */ + + /* 3 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_x509_ce_subjectKeyIdentifier }, + /* 4 */ { A1_OP_OPENTYPE, sizeof(SubjectKeyIdentifier), + (const void*)&asn1_SubjectKeyIdentifier }, + /* 5 */ + + /* And so on...*/ + + /* Value of object #17 */ + /* 35 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_pkix_pe_subjectInfoAccess }, + /* 36 */ { A1_OP_OPENTYPE, sizeof(SubjectInfoAccessSyntax), + (const void*)&asn1_SubjectInfoAccessSyntax } + }; +``` + + After the template entries for all the normal fields of a struct there will + be an object set reference entry identifying the type ID and open type + fields's entries' indices in the same template. The object set has a header + entry followed by pairs of entries each representing a single object and all + of them representing the object set. + + This allows the encoder and decoder to both find the object set quickly, + especially since the objects are sorted by type ID value. + +## Moving From C + + - Generate and output a JSON representation of the compiled ASN.1 module. + + - Code codegen/templategen backends in jq or Haskell or whatever. + + - Code template interpreters in <host> language. + + - Eventually rewrite the compiler itself in Rust or whatever. diff --git a/third_party/heimdal/lib/asn1/README-template.md b/third_party/heimdal/lib/asn1/README-template.md new file mode 100644 index 0000000..9f1b60f --- /dev/null +++ b/third_party/heimdal/lib/asn1/README-template.md @@ -0,0 +1,278 @@ + +#Notes on Heimdal's ASN.1 compiler's "template" backend + +```bash +size .libs/libasn1.dylib +size .libs/libasn1base.a | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT baselib: /' +size .libs/asn1_*.o | awk '{sum += $1} END {print sum}' | sed 's/^/generated code stubs: /' +size *_asn1-template.o | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT stubs: /' +``` + +Notes about the template parser: + + - assumption: code is large, tables smaller + + - size scales better as features as added: + + - adding encoding rules, textual value parsers, comparators, and so on, are + just new template interpreter, and generally that means no change to + templates. + + - so template sizing scales like `O(M + N)` where `M` is the size of the + modules and `N` is the size of the interpreters + + - but codegen sizing scales like `O(M * N)` + + - as we add interpreters the size advantage of templates increases + + - smaller tables and code, more memory sharing, smaller cache footprint, + should lead to better performance + + - templates are shared for encode/decode/free/copy/print interpreters, + whereas none of those operations as generated by the codegen backend + share any code + + - very compressible -- we waste a lot of space in `struct asn1_template` on + 64-bit systems, and still it's smaller than the code generated by the + codegen backend + + Note that the template backend does currently dedup templates, though that + is a quadratic operation that we may eventually have to make optional (right + now it's not a problem). + + If we made the `ptr` field a `uint32_t` instead of a pointer, and wrote a + linker for templates, and squeezed out some bits of `tt` and `offset` (we'll + never need even 8 bits for tags, let alone 20!, and we'll never need 32 bits + for struct sizes and field offsets either, maybe not even 16-bits), we could + cut the size of `struct asn1_template` in half. + + Also, once we add OER/JER we could have an option to not support TLV ERs and + then drop a lot of the tag-related parts of the minified AST that templates + are, further shrinking the templates. + + The smaller the templates, the faster interpreting will be. + + - use explicit stack instead of recursion in template interpreter to reduce + stack use and increase speed + + The code generated by the codegen backend is also recursive, though the + compiler could inline some calls. Using an explicit stack in an iterative + interpreter would likely be a big win. + + - how to generate template based stubs + + (Note: it's now the default for Heimdal itself.) + + Use the `--template` option to `asn1_compile` to use the template backend, + or leave it off to use the codegen backend. + + - the template backend now has more functionality than the codegen backend + + - much easier to extend! adding new encoding rules is just adding a few + functions to template.c, one set of length/encode/decode functions per ER, + so we could add OER/PER/XDR/GSER/JER with very little work outside that one + file and `gen_template.c` (to generate stub functions and possibly slight + alterations to templates) and gen.c (to generate declarations of those stub + functions). + + - template decoding has been fuzzed extensively with American Fuzzy Lop (AFL) + +TODO: + + - Generate templates for enumerations, with their names and values, so that + values of enumerated types can be printed. + + - Remove old fuzzer. Rely on AFL only. + + - Fuzzing tests, always more fuzzing: + + - Instructions: + +``` + $ git clone https://github.com/heimdal/heimdal + $ cd heimdal + $ srcdir=$PWD + $ autoreconf -fi + $ + $ mkdir build + $ cd build + $ + $ ../configure --srcdir=$srcdir ... + $ make -j4 + $ + $ cd lib/asn1 + $ make clean + $ AFL_HARDEN=1 make -j4 asn1_print check CC=afl-gcc # or CC=afl-clang + $ + $ # $srcdir/lib/asn1/fuzz-inputs/ has at least one minimized DER value + $ # produced by taking an EK certificate and truncating the signatureValue + $ # and tbsCertificate.subjectPublicKeyInfo fields then re-encoding, thus + $ # cutting down the size of the certificate by 45%. AFL finds interesting + $ # code paths much faster if the input corpus is minimized. + $ + $ mkdir f + $ ../../libtool --mode=execute afl-fuzz -i $srcdir/lib/asn1/fuzz-inputs -o $PWD/f ./asn1_print '@@' Certificate + $ + $ # Or + $ ../../libtool --mode=execute afl-fuzz -i $srcdir/lib/asn1/fuzz-inputs -o $PWD/f ./asn1_print -A '@@' + $ + $ # Examine crash reports, if any. Each crash report consists of an input + $ # that caused a crash, so run valgrind on each such input: + $ + $ for i in f/crashes/id*; do + > echo $i + > ../../libtool --mode=execute valgrind --num-callers=64 ./asn1_print $i \ + > Certificate IOSCertificationRequest >/dev/null 2> f/crashes/vg-${i##*/} + > done + $ + $ # then review the valgrind output: + $ $PAGER f/crashes/vg-* +``` + + - Here's a screenshot of AFL running on the previous commit: + +``` + american fuzzy lop 2.52b (asn1_print) + +┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐ +│ run time : 1 days, 22 hrs, 39 min, 51 sec │ cycles done : 18 │ +│ last new path : 0 days, 0 hrs, 38 min, 5 sec │ total paths : 2310 │ +│ last uniq crash : none seen yet │ uniq crashes : 0 │ +│ last uniq hang : none seen yet │ uniq hangs : 0 │ +├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤ +│ now processing : 997* (43.16%) │ map density : 2.19% / 8.74% │ +│ paths timed out : 0 (0.00%) │ count coverage : 3.25 bits/tuple │ +├─ stage progress ────────────────────┼─ findings in depth ────────────────────┤ +│ now trying : interest 16/8 │ favored paths : 319 (13.81%) │ +│ stage execs : 13.1k/13.4k (98.18%) │ new edges on : 506 (21.90%) │ +│ total execs : 91.9M │ total crashes : 0 (0 unique) │ +│ exec speed : 576.2/sec │ total tmouts : 2158 (180 unique) │ +├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤ +│ bit flips : 565/5.60M, 124/5.60M, 74/5.59M │ levels : 19 │ +│ byte flips : 4/699k, 17/375k, 15/385k │ pending : 552 │ +│ arithmetics : 323/20.7M, 8/10.6M, 1/517k │ pend fav : 0 │ +│ known ints : 85/1.76M, 148/9.98M, 175/16.8M │ own finds : 2308 │ +│ dictionary : 0/0, 0/0, 12/6.62M │ imported : n/a │ +│ havoc : 757/6.35M, 0/0 │ stability : 100.00% │ +│ trim : 14.30%/336k, 46.60% ├────────────────────────┘ +└─────────────────────────────────────────────────────┘ [cpu000:196%] +``` + + - TODO: Make building with AFL a ./cofigure option. + + - TODO: Make fuzzing with AFL a make target. + + - Fuzz decode round-tripping (don't just decode, but also encoded the + decoded). + + - Performance testing + + - `ASN1_MALLOC_ENCODE()` as a function, replaces `encode_` and `length_` + + - Fix SIZE constraits + + - Proper implementation of `SET { ... }` + + - Compact types that only contain on entry to not having a header. + + +SIZE - Futher down is later generations of the template parser + +``` + code: + ================== + __TEXT __DATA __OBJC others dec hex + 462848 12288 0 323584 798720 c3000 (O2) + + trivial types: + ================== + __TEXT __DATA __OBJC others dec hex + 446464 12288 0 323584 782336 bf000 (O2) + + OPTIONAL + ================== + __TEXT __DATA __OBJC others dec hex + 425984 16384 0 323584 765952 bb000 (O2) + + SEQ OF + ================== + __TEXT __DATA __OBJC others dec hex + 368640 32768 0 327680 729088 b2000 (O2) + 348160 32768 0 327680 708608 ad000 (Os) + + BOOLEAN + ================== + 339968 32768 0 327680 700416 ab000 (Os) + + TYPE_EXTERNAL: + ================== + 331776 32768 0 327680 692224 a9000 (Os) + + SET OF + ================== + 327680 32768 0 327680 688128 a8000 (Os) + + TYPE_EXTERNAL everywhere + ================== + __TEXT __DATA __OBJC others dec hex + 167936 69632 0 327680 565248 8a000 (Os) + + TAG uses ->ptr (header and trailer) + ================== + 229376 102400 0 421888 753664 b8000 (O0) + + TAG uses ->ptr (header only) + ================== + 221184 77824 0 421888 720896 b0000 (O0) + + BER support for octet string (not working) + ================== + 180224 73728 0 417792 671744 a4000 (O2) + + CHOICE and BIT STRING missign + ================== + __TEXT __DATA __OBJC others dec hex + 172032 73728 0 417792 663552 a2000 (Os) + + No accessor functions to global variable + ================== + __TEXT __DATA __OBJC others dec hex + 159744 73728 0 393216 626688 99000 (Os) + + All types tables (except choice) (id still objects) + ================== + __TEXT __DATA __OBJC others dec hex + 167936 77824 0 421888 667648 a3000 + base lib: 22820 + + __TEXT __DATA __OBJC others dec hex + ================== + 167936 77824 0 421888 667648 a3000 (Os) + baselib: 22820 + generated code stubs: 41472 + TEXT stubs: 112560 + + All types, id still objects + ================== + __TEXT __DATA __OBJC others dec hex + 155648 81920 0 430080 667648 a3000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 119891 + + All types, id still objects, dup compression + ================== + __TEXT __DATA __OBJC others dec hex + 143360 65536 0 376832 585728 8f000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 107147 + + All types, dup compression, id vars + ================== + __TEXT __DATA __OBJC others dec hex + 131072 65536 0 352256 548864 86000 + TEXT baselib: 23166 + generated code stubs: 7536 + TEXT stubs: 107147 +``` diff --git a/third_party/heimdal/lib/asn1/README.md b/third_party/heimdal/lib/asn1/README.md new file mode 100644 index 0000000..9c4e697 --- /dev/null +++ b/third_party/heimdal/lib/asn1/README.md @@ -0,0 +1,1327 @@ +# Heimdal's ASN.1 Compiler + +This is a new README, and it's not very rich in contents yet. Be sure to check +out the [README on the template backend](/lib/asn1/README-template.md) and the [README +on automatic open type decoding via X.681/X.682/X.683 +annotations](/lib/asn1/README-X681.md). + +## Table of Contents + + 1. [Introduction](#Introduction) + 2. [ASN.1 Support in Heimdal](#asn1-support-in-heimdal) + 3. [News](#News) + 4. [Features](#Features) + 5. [Limitations](#Limitations) + 6. [Compiler Usage](#Compiler-usage) + 7. [APIs Generated by the Compiler](#APIs-generated-by-the-compiler) + 8. [`asn1_print` Usage](#asn1_print-usage) + 9. [Implementation](#implementation) + 10. [Moving From C](#moving-from-c) + +## Introduction + +ASN.1 is a... some would say baroque, perhaps obsolete, archaic even, "syntax" +for expressing data type schemas, and also a set of "encoding rules" (ERs) that +specify many ways to encode values of those types for interchange. + +Some ERs are binary, others are textual. Some binary ERs are tag-length-value +(TLV), others have no need for tagging. Some of the ERs are roundly and +rightly disliked, but then there are XER (XML Encoding Rules) and JER (JSON +Encoding Rules) that really illustrate how the syntax and the encoding rules +really are separate and distinct things. + +ASN.1 is a wheel that everyone loves to reinvent, and often badly. It's worth +knowing a bit about it before reinventing this wheel badly yet again. + +It's also worth pondering that there appears to be ways to map most data +exchange metaschemas and schemas onto others, and therefore too, transliterate +most encodings onto others. + +First, an example of the syntax: + +```ASN.1 +-- This is what a certificate looks like (as in TLS server certificates, or +-- "SSL certs): +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +-- The main body of a certificate is here though: +TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT 1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL, + subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL +} +``` + +Here we see something akin to a "structure" or "record" with various named +fields of various types. Some of these are optional, which means they can have +no value given in encodings. One is defaulted, which means that if no values +is given in encodings then the default value is intended. + +Those `[0]` things are called tags and are decidedly obsolete, along with all +"tag-length-value" (TLV) or "self-describing" encoding rules. Tags appear as +lexical tokens in ASN.1 only because a) in the early 80s TLV encodings were +thought fantastic, and b) automatic tagging wasn't invented and implemented +until it was too late. New ASN.1 modules should never need to have those tags +appear in the syntax. + +ASN.1 has a lot of competition, and may even be obsolete. Obsolete +technologies take decades to die out because of the need to interoperate with +the installed base. So even if ASN.1 is obsolete, we find ourselves needing to +implement a large subset of it in order to implement certain important network +protocols. + +Encoding rules? There are many: + + - JSON Encoding Rules (JER) ([X.697](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.697)) + + Use JSON instead of some binary scheme like DER (see below). + + - XML Encoding Rules (XER) ([X.693](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.693)) + + - Generic String Encoding Rules (GSER) ([RFC3641](https://tools.ietf.org/html/rfc3641)) + + - Basic, Distinguished, and Canonical Encoding Rules (BER, DER, CER) ([X.690](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.690) + + These are the dreaded tag-length-value encoding rules. They are redundant, + wasteful, and inefficient in spite of being non-textual (i.e., binary)! + + The descriptor "tag-length-value" is due to all values being encoded as some + bytes for a "tag", then some bytes for the length of the encoded value, then + the encoded value itself. The body of a structured type (e.g., + `Certificate`) is itself a concatenation of the TLV encodings of the fields + of that structured type, in order. + + DER and CER are alternative canonical forms of BER. + + - Packed Encoding Rules (PER) ([X.691](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.691)) and Octet Encoding Rules (OER) ([X.696](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.696)) + + These are a lot like eXternal Data Representation + ([XDR](https://tools.ietf.org/html/rfc4506.html)), but with 1-octet + alignment instead of 4-octet alignment. + +There is also a meta encoding rule system, the Encoding Control Notation (ECN) +([X.692](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.692)) +intended to be able to express all sorts of kinds of encodings. + +Heimdal currently only supports DER for encoding, and DER and BER for decoding, +but soon may support JER as well, and can print values as JSON, though not +compliant with JER. + +The syntax itself is specified by +[X.680](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.680), +with extensions via +[X.681](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.681), +[X.682](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.682), +and +[X.683](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.683),. + +## ASN.1 Support in Heimdal + +Heimdal contains an implementation of: + + - ASN.1 + - PKIX + - Kerberos + - misc. Heimdal-specific protocols related to PKIX and Kerberos, such as: + + - Online certification authority protocols + - Kerberos KDC replication protocols + - Kerberos administration protocols + +PKIX and Kerberos both require ASN.1 and DER support. + +For historical reasons many ASN.1-using projects have used hand-rolled codecs +that have proven difficult to implement, maintain, and extend, and, of course, +buggy. Heimdal has its own ASN.1 module compiler and library in order to avoid +the pitfalls of hand-rolled codecs, and to satisfy Heimdal's internal needs. + +There are other ASN.1 compilers and libraries out there, of course, but it +would prove difficult to switch compilers as generally ASN.1 compilers lack +sufficient control over generated types and APIs for programming languages. + +Heimdal's ASN.1 compiler supports a large subset of X.680, X.681, X.682, and +X.683, as well as a large subset of X.690, with an architecture that should +make it easy to add support for encoding rules other than X.690. + +## News + +In recent times the following features have been added: + + - Feature parity for the "template" backend, even superiority, as the codegen + backend does not yet support automatic open type decoding/encoding. + + - IMPLICIT tagging support is finally complete. + + - Automatic open type traversal, using a subset of X.681/X.682/X.683 for + expressing the requisite metadata. + + - Decoration of ASN.1 types with "hidden" fields (ones that don't get encoded + or decoded) of ASN.1 or C types. + +## Futures + + - JER support? + + - XDR/NDR/OER support? + + - Generate comparators? (lib/hx509 has a half-baked Certificate comparator) + +## Features + + - Most of X.680 is supported. + + - Most of X.690 is supported for decoding, with only DER supported for + encoding. + + - For cryptographic applications there is a `--preserve-binary=TYPE` compiler + option that causes the `TYPE`'s C `struct` to gain a `_save` field where the + original encoding of the `TYPE` is preserved by the decoder. This allows + cryptographic applications to validate signatures, MACs, authenticated + decryption tags, checksums, etc., without having to re-encode the `TYPE` + (which wouldn't even work if the encoding received were BER and BER were + permitted for that `TYPE`). + + - Unconstrained integer types have a large integer representation in C that is + not terribly useful in common cases. Range and member constraints on + integer types cause the compiler to use `int`, `int64_t`, `unsigned int`, + and/or `uint64_t` as appropriate. + + - The Heimdal ASN.1 compiler currently handles a large subset of X.680, and + (in a branch) a small subset of X.681, X.682, and X.683, which manifests as + automatic handling of all open types contained in `SET`/`SEQUENCE` types + that are parameterized with information object sets. This allows all open + types in PKIX certificates, for example, to get decoded automatically no + matter how deeply nested. We use a TCG EK certificate that has eight + certificate extensions, including subject alternative names and subject + directory attributes where the attribute values are not string types, and + all of these things get decoded automatically. + + - The template backend dedups templates to save space. This is an O(N^2) kind + of feature that we need to make optional, but it works. (When we implement + JER this will have the side-effect of printing the wrong type names in some + cases because two or more types have the same templates and get deduped.) + + - There is an _experimental_ ASN.1 module -> JSON feature in the compiler. It + currently dumps type and value definitions, but not class, or object set + definitions. Even for types, it is not complete, and the JSON schema used + is subject to change *WITHOUT NOTICE*. + + Perhaps eventually we can re-write the compiler as a C-coded ASN.1 -> JSON + stage followed by a jq-coded code and template generator state, which would + make it much easier to extend the compiler. + + - We have an `asn1_print` program that can decode DER from any exported types + from any ASN.1 modules committed in Heimdal: + + ```bash + $ ./asn1_print ek.crt Certificate | + jq '.tbsCertificate.extensions[3]._extnValue[]._values' + ``` + + ```JSON + [ + { + "_type": "TPMSpecification", + "family": "2.0", + "level": 0, + "revision": 138 + } + ] + [ + { + "_type": "TPMSecurityAssertions", + "version": 0, + "fieldUpgradable": true, + "ekGenerationType": "ekgt-injected", + "ekGenerationLocation": "tpmManufacturer", + "ekCertificateGenerationLocation": "tpmManufacturer", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "ealevel4", + "evaluationStatus": "evaluationCompleted", + "plus": true, + "strengthOfFunction": null, + "profileOid": null, + "profileUri": null, + "targetOid": null, + "targetUri": null + }, + "fipsLevel": { + "_type": "FIPSLevel", + "version": "140-2", + "level": "sllevel2", + "plus": false + }, + "iso9000Certified": false, + "iso9000Uri": null + } + ] + ``` + + A complete dump of such a certificate: + + ```bash + $ ./asn1_print ek.crt Certificate | jq . + ``` + + ```JSON + { + "_type": "Certificate", + "tbsCertificate": { + "_type": "TBSCertificate", + "_save": "30820376A00302010202146A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A300D06092A864886F70D01010B05003055310B3009060355040613024348311E301C060355040A131553544D6963726F656C656374726F6E696373204E56312630240603550403131D53544D2054504D20454B20496E7465726D656469617465204341203035301E170D3138313231343030303030305A170D3238313231343030303030305A300030820122300D06092A864886F70D01010105000382010F003082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001A38201A9308201A5301F0603551D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C0866030420603551D20043B303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F30590603551D110101FF044F304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A303034393030303830670603551D090460305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100300E0603551D0F0101FF040403020520300C0603551D130101FF0402300030100603551D250409300706056781050801304A06082B06010505070101043E303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "version": "rfc3280_version_3", + "serialNumber": "6A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A", + "signature": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "issuer": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.6", + "components": [ + 2, + 5, + 4, + 6 + ], + "name": "id-at-countryName" + }, + "value": { + "_choice": "printableString", + "value": "CH" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.10", + "components": [ + 2, + 5, + 4, + 10 + ], + "name": "id-at-organizationName" + }, + "value": { + "_choice": "printableString", + "value": "STMicroelectronics NV" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.3", + "components": [ + 2, + 5, + 4, + 3 + ], + "name": "id-at-commonName" + }, + "value": { + "_choice": "printableString", + "value": "STM TPM EK Intermediate CA 05" + } + } + ] + ] + }, + "validity": { + "_type": "Validity", + "notBefore": { + "_choice": "utcTime", + "value": "2018-12-14T00:00:00Z" + }, + "notAfter": { + "_choice": "utcTime", + "value": "2028-12-14T00:00:00Z" + } + }, + "subject": { + "_choice": "rdnSequence", + "value": [] + }, + "subjectPublicKeyInfo": { + "_type": "SubjectPublicKeyInfo", + "algorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.1", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 1 + ], + "name": "id-pkcs1-rsaEncryption" + }, + "parameters": "0500" + }, + "subjectPublicKey": "2160:3082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001" + }, + "issuerUniqueID": null, + "subjectUniqueID": null, + "extensions": [ + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.35", + "components": [ + 2, + 5, + 29, + 35 + ], + "name": "id-x509-ce-authorityKeyIdentifier" + }, + "critical": false, + "extnValue": "301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "_extnValue_choice": "ext-AuthorityKeyIdentifier", + "_extnValue": { + "_type": "AuthorityKeyIdentifier", + "keyIdentifier": "1ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "authorityCertIssuer": null, + "authorityCertSerialNumber": null + } + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32", + "components": [ + 2, + 5, + 29, + 32 + ], + "name": "id-x509-ce-certificatePolicies" + }, + "critical": false, + "extnValue": "303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F", + "_extnValue_choice": "ext-CertificatePolicies", + "_extnValue": [ + { + "_type": "PolicyInformation", + "policyIdentifier": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32.0", + "components": [ + 2, + 5, + 29, + 32, + 0 + ], + "name": "id-x509-ce-certificatePolicies-anyPolicy" + }, + "policyQualifiers": [ + { + "_type": "PolicyQualifierInfo", + "policyQualifierId": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.2.1", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 2, + 1 + ], + "name": "id-pkix-qt-cps" + }, + "qualifier": "1621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F" + } + ] + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.17", + "components": [ + 2, + 5, + 29, + 17 + ], + "name": "id-x509-ce-subjectAltName" + }, + "critical": true, + "extnValue": "304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A3030343930303038", + "_extnValue_choice": "ext-SubjectAltName", + "_extnValue": [ + { + "_choice": "directoryName", + "value": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.1", + "components": [ + 2, + 23, + 133, + 2, + 1 + ], + "name": "tcg-at-tpmManufacturer" + }, + "value": { + "_choice": "utf8String", + "value": "id:53544D20" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.2", + "components": [ + 2, + 23, + 133, + 2, + 2 + ], + "name": "tcg-at-tpmModel" + }, + "value": { + "_choice": "utf8String", + "value": "ST33HTPHAHC0" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.3", + "components": [ + 2, + 23, + 133, + 2, + 3 + ], + "name": "tcg-at-tpmVersion" + }, + "value": { + "_choice": "utf8String", + "value": "id:00490008" + } + } + ] + ] + } + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.9", + "components": [ + 2, + 5, + 29, + 9 + ], + "name": "id-x509-ce-subjectDirectoryAttributes" + }, + "critical": false, + "extnValue": "305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100", + "_extnValue_choice": "ext-SubjectDirectoryAttributes", + "_extnValue": [ + { + "_type": "AttributeSet", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.16", + "components": [ + 2, + 23, + 133, + 2, + 16 + ], + "name": "tcg-at-tpmSpecification" + }, + "values": [ + "300C0C03322E300201000202008A" + ], + "_values_choice": "at-TPMSpecification", + "_values": [ + { + "_type": "TPMSpecification", + "family": "2.0", + "level": 0, + "revision": 138 + } + ] + }, + { + "_type": "AttributeSet", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.18", + "components": [ + 2, + 23, + 133, + 2, + 18 + ], + "name": "tcg-at-tpmSecurityAssertions" + }, + "values": [ + "30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100" + ], + "_values_choice": "at-TPMSecurityAssertions", + "_values": [ + { + "_type": "TPMSecurityAssertions", + "version": 0, + "fieldUpgradable": true, + "ekGenerationType": "ekgt-injected", + "ekGenerationLocation": "tpmManufacturer", + "ekCertificateGenerationLocation": "tpmManufacturer", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "ealevel4", + "evaluationStatus": "evaluationCompleted", + "plus": true, + "strengthOfFunction": null, + "profileOid": null, + "profileUri": null, + "targetOid": null, + "targetUri": null + }, + "fipsLevel": { + "_type": "FIPSLevel", + "version": "140-2", + "level": "sllevel2", + "plus": false + }, + "iso9000Certified": false, + "iso9000Uri": null + } + ] + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.15", + "components": [ + 2, + 5, + 29, + 15 + ], + "name": "id-x509-ce-keyUsage" + }, + "critical": true, + "extnValue": "03020520", + "_extnValue_choice": "ext-KeyUsage", + "_extnValue": [ + "keyEncipherment" + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.19", + "components": [ + 2, + 5, + 29, + 19 + ], + "name": "id-x509-ce-basicConstraints" + }, + "critical": true, + "extnValue": "3000", + "_extnValue_choice": "ext-BasicConstraints", + "_extnValue": { + "_type": "BasicConstraints", + "cA": false, + "pathLenConstraint": null + } + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.37", + "components": [ + 2, + 5, + 29, + 37 + ], + "name": "id-x509-ce-extKeyUsage" + }, + "critical": false, + "extnValue": "300706056781050801", + "_extnValue_choice": "ext-ExtKeyUsage", + "_extnValue": [ + { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.8.1", + "components": [ + 2, + 23, + 133, + 8, + 1 + ], + "name": "tcg-kp-EKCertificate" + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.1.1", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "name": "id-pkix-pe-authorityInfoAccess" + }, + "critical": false, + "extnValue": "303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "_extnValue_choice": "ext-AuthorityInfoAccess", + "_extnValue": [ + { + "_type": "AccessDescription", + "accessMethod": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.48.2", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 48, + 2 + ], + "name": "id-pkix-ad-caIssuers" + }, + "accessLocation": { + "_choice": "uniformResourceIdentifier", + "value": "http://secure.globalsign.com/stmtpmekint05.crt" + } + } + ] + } + ] + }, + "signatureAlgorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "signatureValue": "2048:3D4C381E5B4F1BCBE09C63D52F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF8869013041E92CDD3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAFF9E7E908480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252A4C18A4F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20EB3DBD763F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63BE0E516D00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B38F7EE56CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755BBC2806FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506" + } + ``` + + (Notice that OID names look a bit weird. For reasons that may have been + lost to time and may no longer be relevant, these OIDs are defined with + slightly different names in the ASN.1 modules in Heimdal's source tree. + We'll fix this eventually.) + +... + +## Limitations + + - `libasn1`'s and, therefore, `asn1_print`'s JSON support is not X.697 (JER) + compatible. + + - Control over C types generated is very limited, mainly only for integer + types. + + - When using the template backend, `SET { .. }` types are currently not sorted + by tag as they should be, but if the module author sorts them by hand then + DER will be produced. + + - `REAL` is not supported. + + - `EmbeddedPDV` is not supported. + + - `BMPString` is not supported. + + - IA5String is not properly supported -- it's essentially treated as a + `UTF8String` with a different tag. This is true of all the string types. + + - Only types can be imported at this time. Without some rototilling we likely + will not be able to import anything other than types, values, and object + sets. + + - Only simple value syntax is supported. Constructed value syntax (i.e., + values of `SET`, `SEQUENCE`, `SET OF`, and `SEQUENCE OF`), is not supported. + Values of `CHOICE` types are also not supported. + + - There is no way to substitute object sets at run-time. This means that + automatic decoding through open types will spend more CPU cycles than the + application might want, by decoding more types than the application might + care about. The ability to substitute object sets at run-time would require + a change to the APIs generated. + + - ... + +## Compiler Usage + +The various options for the Heimdal ASN.1 compiler are described in its manual +page, which is included below. + +The `--option-file=FILE` option is particularly useful, as it allows additional +compiler options to be read from a file. + +The `--preserve-binary=TYPE-NAME` option is critical for signature validation +as it causes the decoder to save the encoding of the given type so that +signature validation code can easily find the original encoding and thus avoid +having to re-encode or resort to other hacks. E.g., we use this for preserving +the original encoding of the `tbsCertificate` field of `Certificate`. + +The `--sequence=TYPE-NAME` causes the compiler to generate additional utility +functions for adding or removing items from the named type when it is a +`SEQUENCE OF` or `SET OF` type. + +See the manual page `asn1_compile.1`: + +```text +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) + +NAME + asn1_compile — compile ASN.1 modules + +SYNOPSIS + asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] + +DESCRIPTION + asn1_compile compiles an ASN.1 module into C source code and header + files. + + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + + Options supported: + + --template + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. + + --prefix-enum + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --encode-rfc1510-bit-string + Use RFC1510, non-standard handling of “BIT STRING” types. + + --decode-dce-ber + + --support-ber + + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. + + --one-code-file + Generate a single source code file. Otherwise a separate code + file will be generated for every type. + + --gen-name=NAME + Use NAME to form the names of the files generated. + + --option-file=FILE + Take additional command-line options from FILE. + + --original-order + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. + + --no-parse-units + Do not generate to-int / from-int functions for enumeration + types. + + --type-file=C-HEADER-FILE + Generate an include of the named header file that might be needed + for common type defintions. + + --version + + --help + +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. + +HEIMDAL February 22, 2021 HEIMDAL +``` + +## APIs Generated by the Compiler + +Every named type in an ASN.1 module gets a corresponding type in C. +Em-dashes in symbols become underscores. + +Every named type in an ASN.1 module also gets several functions generated +associated with it: + + - `int decode_TypeName(const unsigned char *, size_t, TypeName *, size_t *);` + + Decodes a value of `TypeName` in the given byte array of the given size, + into the given `TypeName` object, and outputs the number of bytes parsed. + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library. + + - `int encode_TypeName(unsigned char *, size_t, const TypeName *, size_t *);` + + Encodes the given object of `TypeName` type into the given byte array of the + given size, outputting the number of bytes used. + + NOTE WELL: the `unsigned char *` pointer must point to the _last_ byte of + the buffer! + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library, including system errors such as `ENOMEM`. + + - `int length_TypeName(const TypeName *);` + + Returns the number of bytes needed to encode the given object. + + - `void free_TypeName(TypeName *);` + + Releases the memory associated with the content of the given object, but + note that the object itself is _not_ released. + + - `int copy_TypeName(const TypeName *, TypeName *);` + + Copies the content of the given `const` object to the destination, + non-`const` object. + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library, including system errors such as `ENOMEM`. + + - `char *print_TypeName(const TypeName *, int);` + + Returns a string (JSON) representation of the given object. The `int` + argument is a bitset of flags: + + - `ASN1_PRINT_INDENT` + + Indent the JSON. If not given the the JSON will have no interstitial + whitespace, including newlines. + +You will want to review the data structures generated. They look like: + +```C + typedef struct TBSCertificate TBSCertificate; + typedef struct AlgorithmIdentifier AlgorithmIdentifier; + typedef struct ... ...; + + /* + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING { + }, + } + */ + + typedef struct Certificate { + TBSCertificate tbsCertificate; + AlgorithmIdentifier signatureAlgorithm; + heim_bit_string signatureValue; + } Certificate; + + /* + TBSCertificate ::= SEQUENCE { + version [0] Version OPTIONAL, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING { + } OPTIONAL, + subjectUniqueID [2] IMPLICIT BIT STRING { + } OPTIONAL, + extensions [3] Extensions OPTIONAL, + } + */ + + typedef struct TBSCertificate { + heim_octet_string _save; + Version *version; + CertificateSerialNumber serialNumber; + AlgorithmIdentifier signature; + Name issuer; + Validity validity; + Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + heim_bit_string *issuerUniqueID; + heim_bit_string *subjectUniqueID; + Extensions *extensions; + } TBSCertificate; +``` + +Note how trivial the mapping onto C is. + +`OPTIONAL` fields become pointer fields, with `NULL` indicating +absence and non-NULL indicating presence. + +And so on. + +## `asn1_print` Usage + +```text +ASN1_PRINT(1) BSD General Commands Manual ASN1_PRINT(1) + +NAME + asn1_print — dump ASN.1 DER encoded values + +SYNOPSIS + asn1_print [-i | --no-indent] [-I | --inner] [-l | --list-types] + [-A | --try-all-types] [-S | --raw-sequence] [-n | --no-print] + [-q | --quiet] [--test-encode] [--test-copy] + [-l -v | --version] [-l -h | --help] [FILE [TypeName...]] + +DESCRIPTION + asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu- + ments are given, then asn1_print will print the value in a JSON-like for- + mat using its knowledge of the ASN.1 modules defining those types, stop- + ping at the first type for which it can successfully decode the value. + If TypeNames are given, they must be the names of ASN.1 types exported by + an ASN.1 modules that are compiled into asn1_print. Use the + --try-all-types option to attempt decoding as all ASN.1 types known to + asn1_print. If neither any TypeName nor --try-all-types are given, then + the value will be parsed and displayed using just the self-describing + nature of DER. + + Options supported: + + -i, --no-indent + Do not indent dump. + + -I, --inner + Try to parse inner structures of OCTET STRING and constructed + values. + + -l, --list-types + List all types known to asn1_print. + + -A, --try-all-types + Attempt to decode the value as any of all types known to + asn1_print. + + -S, --raw-sequence + If a value parses as a given TypeName but any bytes are left + over, try to parse those separately as well until all bytes are + consumed or an error occurs. + + -n, --no-print + For the case where -A or --try-all-types or where a TypeName is + given, do not output a JSON representation of the value, just + attempt to decode it. This is useful for fuzzing. + + -q, --quiet + Similar to -n, --no-print but JSON output will be formatted, just + not output. As with -n, --no-print, this option requires -A -/ + --try-all-types or that a TypeName be given. This is useful for + fuzzing. + + --test-encode + Check that encoding produces the same value as decoding. Useful + for fuzzing. + + --test-copy + Test copy functions. Useful for fuzzing. + + -v, --version + + -h, --help + +HEIMDAL February 22, 2021 HEIMDAL +``` + +## Implementation + +See: + + - `lib/asn1/main.c` for the `main()` function of the compiler + - `lib/asn1/asn1parse.y` for the grammar and most of the parsing into an AST + - `lib/asn1/symbol.h` for the types making up the AST + - `lib/asn1/{hash,symbol}.c` for compiler AST supporting functionality + - `lib/asn1/gen.c` for the C header file generator + - `lib/asn1/gen_template.c` for the template generator + - `lib/asn1/gen_{decode,encode,length,copy,free}.c` for the C code generator + - `lib/asn1/gen_{glue,seq}.c` for misc code generator + - `lib/asn1/template.c` for the template interpreter + - `lib/asn1/der*.c` for primitive type primitives + - `lib/asn1/extra.c` for primitives related to `ANY` + +... + +## Futures + + - Add JER support so we can convert between JER and DER? + + - Add XDR support? There are no ASN.1 Encoding Rules based on XDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + XDR syntax has equivalent semantics. + + - Add OER support? + + - Add NDR support? There are no ASN.1 Encoding Rules based on NDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + IDL syntax has equivalent semantics. + + - Perhaps third parties will contribute more control over generated types? + This may require separate publication of the Heimdal ASN.1 compiler from the + rest of Heimdal. + +## Moving From C + + - Generate and output a JSON representation of the compiled ASN.1 module. + + - Code codegen/templategen backends in jq or Haskell or whatever. + + - Code template interpreters in some host language. + + - Eventually rewrite the compiler itself in Rust or whatever. diff --git a/third_party/heimdal/lib/asn1/asn1-common.h b/third_party/heimdal/lib/asn1/asn1-common.h new file mode 100644 index 0000000..7797eed --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1-common.h @@ -0,0 +1,90 @@ +/* $Id$ */ + +#include +#include +#include + +#ifndef __asn1_common_definitions__ +#define __asn1_common_definitions__ + +#ifndef __HEIM_BASE_DATA__ +#define __HEIM_BASE_DATA__ 1 +struct heim_base_data { + size_t length; + void *data; +}; +#endif + +typedef struct heim_integer { + size_t length; + void *data; + int negative; +} heim_integer; + +typedef struct heim_base_data heim_octet_string; + +typedef char *heim_general_string; +typedef char *heim_utf8_string; +typedef struct heim_base_data heim_printable_string; +typedef struct heim_base_data heim_ia5_string; + +typedef struct heim_bmp_string { + size_t length; + uint16_t *data; +} heim_bmp_string; + +typedef struct heim_universal_string { + size_t length; + uint32_t *data; +} heim_universal_string; + +typedef char *heim_visible_string; + +typedef struct heim_oid { + size_t length; + unsigned *components; +} heim_oid; + +typedef struct heim_bit_string { + size_t length; + void *data; +} heim_bit_string; + +typedef struct heim_base_data heim_any; +typedef struct heim_base_data heim_any_set; +typedef struct heim_base_data HEIM_ANY; +typedef struct heim_base_data HEIM_ANY_SET; + +enum asn1_print_flags { + ASN1_PRINT_INDENT = 1, +}; + +#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ + do { \ + (BL) = length_##T((S)); \ + (B) = malloc((BL)); \ + if((B) == NULL) { \ + (R) = ENOMEM; \ + } else { \ + (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \ + (S), (L)); \ + if((R) != 0) { \ + free((B)); \ + (B) = NULL; \ + } \ + } \ + } while (0) + +#ifdef _WIN32 +#ifndef ASN1_LIB +#define ASN1EXP __declspec(dllimport) +#else +#define ASN1EXP +#endif +#define ASN1CALL __stdcall +#else +#define ASN1EXP +#define ASN1CALL +#endif + +#endif diff --git a/third_party/heimdal/lib/asn1/asn1-template.h b/third_party/heimdal/lib/asn1/asn1-template.h new file mode 100644 index 0000000..07c4461 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1-template.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* asn1 templates */ + +#ifndef __TEMPLATE_H__ +#define __TEMPLATE_H__ + +/* + * TBD: + * + * - For OER also encode number of optional/default/extension elements into + * header entry's ptr field, not just the number of entries that follow it. + * + * - For JER we'll need to encode encoding options (encode as array, encode as + * object, etc.) + * + * - For open types we'll need to be able to indicate what encoding rules the + * type uses. + * + * - We have too many bits for tags (20) and probably not enough for ops (4 + * bits, and we've used all but one). + */ + +/* header: + * HF flags if not a BIT STRING type + * HBF flags if a BIT STRING type + * + * ptr is count of elements + * offset is size of struct + */ + +/* tag: + * 0..20 tag + * 21 type + * 22..23 class + * 24..27 flags + * 28..31 op + * + * ptr points to template for tagged type + * offset is offset of struct field + */ + +/* parse: + * 0..11 type + * 12..23 unused + * 24..27 flags + * 28..31 op + * + * ptr is NULL + * offset is ... + */ + +/* defval: (next template entry is defaulted) + * + * DV flags (ptr is or points to defval) + * + * ptr is default value or pointer to default value + * offset is all ones + */ + +/* name: first one is the name of the SET/SEQUENCE/CHOICE type + * subsequent ones are the name of the nth field + * + * 0..23 unused + * 24..27 flags A1_NM_* + * 28..31 op + * + * ptr is const char * pointer to the name as C string + * offset is all zeros + */ + +/* objset: + * 0..9 open type ID entry index + * 10..19 open type entry index + * 20..23 unused + * 24..27 flags A1_OS_* + * 28..31 op + * + * ptr points to object set template + * offset is the offset of the choice struct + */ + +/* opentypeid: offset is zero + * ptr points to value if it is not an integer + * ptr is the value if it is an integer + * 0..23 unused + * 24..27 flags A1_OTI_* + * 28..31 op + */ + +/* opentype: offset is sizeof C type for this open type choice + * ptr points to template for type choice + * 0..23 unused + * 24..27 flags + * 28..31 op + */ + +#define A1_OP_MASK (0xf0000000) +#define A1_OP_TYPE (0x10000000) /* templated type */ +#define A1_OP_TYPE_EXTERN (0x20000000) /* templated type (imported) */ +#define A1_OP_TAG (0x30000000) /* a tag */ +#define A1_OP_PARSE (0x40000000) /* primitive type */ +#define A1_OP_SEQOF (0x50000000) /* sequence of */ +#define A1_OP_SETOF (0x60000000) /* set of */ +#define A1_OP_BMEMBER (0x70000000) /* BIT STRING member */ +#define A1_OP_CHOICE (0x80000000) /* CHOICE */ +#define A1_OP_DEFVAL (0x90000000) /* def. value */ +#define A1_OP_OPENTYPE_OBJSET (0xa0000000) /* object set for open type */ +#define A1_OP_OPENTYPE_ID (0xb0000000) /* open type id field */ +#define A1_OP_OPENTYPE (0xc0000000) /* open type field */ +#define A1_OP_NAME (0xd0000000) /* symbol */ +#define A1_OP_TYPE_DECORATE (0xe0000000) /* decoration w/ templated type */ +#define A1_OP_TYPE_DECORATE_EXTERN (0xf0000000) /* decoration w/ some C type */ + /* 0x00.. is still free */ + +#define A1_FLAG_MASK (0x0f000000) +#define A1_FLAG_OPTIONAL (0x01000000) +#define A1_FLAG_IMPLICIT (0x02000000) +#define A1_FLAG_DEFAULT (0x04000000) + +#define A1_TAG_T(CLASS,TYPE,TAG) ((A1_OP_TAG) | (((CLASS) << 22) | ((TYPE) << 21) | (TAG))) +#define A1_TAG_CLASS(x) (((x) >> 22) & 0x3) +#define A1_TAG_TYPE(x) (((x) >> 21) & 0x1) +#define A1_TAG_TAG(x) ((x) & 0x1fffff) + +#define A1_TAG_LEN(t) ((uintptr_t)(t)->ptr) +#define A1_HEADER_LEN(t) ((uintptr_t)(t)->ptr) + +#define A1_PARSE_T(type) ((A1_OP_PARSE) | (type)) +#define A1_PARSE_TYPE_MASK 0xfff +#define A1_PARSE_TYPE(x) (A1_PARSE_TYPE_MASK & (x)) + +#define A1_PF_INDEFINTE 0x1 +#define A1_PF_ALLOW_BER 0x2 + +#define A1_HF_PRESERVE 0x1 +#define A1_HF_ELLIPSIS 0x2 + +#define A1_HBF_RFC1510 0x1 + +#define A1_DV_BOOLEAN 0x01 +#define A1_DV_INTEGER 0x02 +#define A1_DV_INTEGER32 0x04 +#define A1_DV_INTEGER64 0x08 +#define A1_DV_UTF8STRING 0x10 + +#define A1_OS_IS_SORTED (0x01000000) +#define A1_OS_OT_IS_ARRAY (0x02000000) +#define A1_OTI_IS_INTEGER (0x04000000) + + +struct asn1_template { + uint32_t tt; + uint32_t offset; + const void *ptr; +}; + +typedef int (ASN1CALL *asn1_type_decode)(const unsigned char *, size_t, void *, size_t *); +typedef int (ASN1CALL *asn1_type_encode)(unsigned char *, size_t, const void *, size_t *); +typedef size_t (ASN1CALL *asn1_type_length)(const void *); +typedef void (ASN1CALL *asn1_type_release)(void *); +typedef int (ASN1CALL *asn1_type_copy)(const void *, void *); +typedef char * (ASN1CALL *asn1_type_print)(const void *, int); + +struct asn1_type_func { + asn1_type_encode encode; + asn1_type_decode decode; + asn1_type_length length; + asn1_type_copy copy; + asn1_type_release release; + asn1_type_print print; + size_t size; +}; + +struct template_of { + unsigned int len; + void *val; +}; + +enum template_types { + A1T_IMEMBER = 0, + A1T_HEIM_INTEGER, + A1T_INTEGER, + A1T_INTEGER64, + A1T_UNSIGNED, + A1T_UNSIGNED64, + A1T_GENERAL_STRING, + A1T_OCTET_STRING, + A1T_OCTET_STRING_BER, + A1T_IA5_STRING, + A1T_BMP_STRING, + A1T_UNIVERSAL_STRING, + A1T_PRINTABLE_STRING, + A1T_VISIBLE_STRING, + A1T_UTF8_STRING, + A1T_GENERALIZED_TIME, + A1T_UTC_TIME, + A1T_HEIM_BIT_STRING, + A1T_BOOLEAN, + A1T_OID, + A1T_TELETEX_STRING, + A1T_NUM_ENTRY +}; + +extern struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY]; + +#define ABORT_ON_ERROR() abort() + +#define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset)) +#define DPO(data,offset) ((void *)(((unsigned char *)data) + offset)) + +/* + * These functions are needed by the generated template stubs and are + * really internal functions. Since they are part of der-private.h + * that contains extra prototypes that really a private we included a + * copy here. + */ + +int +_asn1_copy_top ( + const struct asn1_template * /*t*/, + const void * /*from*/, + void * /*to*/); + +void +_asn1_free_top(const struct asn1_template *, void *); + +char * +_asn1_print_top(const struct asn1_template *, int, const void *); + +int +_asn1_decode_top ( + const struct asn1_template * /*t*/, + unsigned /*flags*/, + const unsigned char * /*p*/, + size_t /*len*/, + void * /*data*/, + size_t * /*size*/); + +int +_asn1_encode ( + const struct asn1_template * /*t*/, + unsigned char * /*p*/, + size_t /*len*/, + const void * /*data*/, + size_t * /*size*/); + +int +_asn1_encode_fuzzer ( + const struct asn1_template * /*t*/, + unsigned char * /*p*/, + size_t /*len*/, + const void * /*data*/, + size_t * /*size*/); + +void +_asn1_free ( + const struct asn1_template * /*t*/, + void * /*data*/); + +size_t +_asn1_length ( + const struct asn1_template * /*t*/, + const void * /*data*/); + +size_t +_asn1_length_fuzzer ( + const struct asn1_template * /*t*/, + const void * /*data*/); + + +#endif diff --git a/third_party/heimdal/lib/asn1/asn1_compile-version.rc b/third_party/heimdal/lib/asn1/asn1_compile-version.rc new file mode 100644 index 0000000..120fb85 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_compile-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "ASN.1 Compiler" +#define RC_FILE_ORIG_0409 "asn1_compile.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/asn1/asn1_compile.1 b/third_party/heimdal/lib/asn1/asn1_compile.1 new file mode 100644 index 0000000..9af2767 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_compile.1 @@ -0,0 +1,355 @@ +.\" Copyright (c) 2019 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2021 +.Dt ASN1_COMPILE 1 +.Os HEIMDAL +.Sh NAME +.Nm asn1_compile +.Nd compile ASN.1 modules +.Sh SYNOPSIS +.Nm +.Bk -words +.Op Fl Fl template +.Op Fl Fl prefix-enum +.Op Fl Fl enum-prefix=PREFIX +.Op Fl Fl encode-rfc1510-bit-string +.Op Fl Fl decode-dce-ber +.Op Fl Fl support-ber +.Op Fl Fl preserve-binary=TYPE +.Op Fl Fl sequence=TYPE +.Op Fl Fl decorate=DECORATION +.Op Fl Fl one-code-file +.Op Fl Fl gen-name=NAME +.Op Fl Fl option-file=FILE +.Op Fl Fl original-order +.Op Fl Fl no-parse-units +.Op Fl Fl type-file=C-HEADER-FILE +.Op Fl Fl version +.Op Fl Fl help +.Op Ar FILE.asn1 Op Ar NAME +.Ek +.Sh DESCRIPTION +.Nm +compiles an ASN.1 module into C source code and header files. +.Pp +A fairly large subset of ASN.1 as specified in X.680, and the +ASN.1 Information Object System as specified in X.681, X.682, and +X.683 is supported, with support for the Distinguished Encoding +Rules (DER), partial Basic Encoding Rules (BER) support, and +experimental JSON support (encoding only at this time). +.Pp +See the compiler's README files for details about the C code and +interfaces it generates. +.Pp +The Information Object System support includes automatic codec +support for encoding and decoding through +.Dq open types +which are also known as +.Dq typed holes . +See RFC 5912 for examples of how to use the ASN.1 +Information Object System via X.681/X.682/X.683 annotations. See +the compiler's README files for more information on ASN.1 +Information Object System support. +.Pp +Extensions specific to Heimdal are generally not syntactic in +nature but rather command-line options to this program. +For example, one can use command-line options to: +.Bl -bullet -compact -width Ds -offset indent +.It +enable decoding of BER-encoded values; +.It +enable RFC1510-style handling of +.Sq BIT STRING +types; +.It +enable saving of as-received encodings of specific types for the +purpose of signature validation; +.It +generate add/remove utility functions for array types; +.It +decorate generated +.Sq struct +types with fields that are neither encoded nor decoded; +.El +etc. +.Pp +ASN.1 x.680 features supported: +.Bl -bullet -compact -width Ds -offset indent +.It +most primitive types (except BMPString and REAL); +.It +all constructed types, including SET and SET OF; +.It +explicit and implicit tagging. +.El +.Pp +Size and range constraints on the +.Sq INTEGER +type cause the compiler to generate appropriate C types such as +.Sq int , +.Sq unsigned int , +.Sq int64_t , +.Sq uint64_t . +Unconstrained +.Sq INTEGER +is treated as +.Sq heim_integer , +which represents an integer of arbitrary size. +.Pp +Caveats and ASN.1 x.680 features not supported: +.Bl -bullet -compact -width Ds -offset indent +.It +JSON encoding support is not quite X.697 (JER) compatible. +Its JSON schema is subject to change without notice. +.It +Control over C types generated is very limited, mainly only for +integer types. +.It +When using the template backend, `SET { .. }` types are currently +not sorted by tag as they should be, but if the module author +sorts them by hand then correct DER will be produced. +.It +.Sq AUTOMATIC TAGS +is not supported. +.It +The +.Va REAL +type is not supported. +.It +The +.Va EmbeddedPDV +type is not supported. +.It +The +.Va BMPString +type is not supported. +.It +The +.Va IA5String +is not properly supported, as it's essentially treated as a +.Va UTF8String +with a different tag. +.It +All supported non-octet strings are treated as like the +.Va UTF8String +type. +.It +Only types can be imported into ASN.1 modules at this time. +.It +Only simple value syntax is supported. +Constructed value syntax (i.e., values of SET, SEQUENCE, SET OF, +and SEQUENCE OF types), is not supported. +Values of `CHOICE` types are also not supported. +.El +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl Fl template +Use the +.Dq template +backend instead of the +.Dq codegen +backend (which is the default backend). +.Pp +The template backend generates +.Dq templates +which are akin to bytecode, and which are interpreted at +run-time. +.Pp +The codegen backend generates C code for all functions directly, +with no template interpretation. +.Pp +The template backend scales better than the codegen backend +because as we add support for more encoding rules and more +operations (we may add value comparators) the templates stay +mostly the same, thus scaling linearly with size of module. +Whereas the codegen backend scales linear with the product of +module size and number of encoding rules supported. +.It Fl Fl prefix-enum +This option should be removed because ENUMERATED types should +always have their labels prefixed. +.It Fl Fl enum-prefix=PREFIX +This option should be removed because ENUMERATED types should +always have their labels prefixed. +.It Fl Fl encode-rfc1510-bit-string +Use RFC1510, non-standard handling of +.Dq BIT STRING +types. +.It Fl Fl decode-dce-ber +.It Fl Fl support-ber +.It Fl Fl preserve-binary=TYPE +Generate a field named +.Sq _save +in the C struct generated for the named +.Ar TYPE . +This field is used to preserve the original encoding of the value +of the +.Ar TYPE . +.Pp +This is useful for cryptographic applications so that they can +check signatures of encoded values as-received without having to +re-encode those values. +.Pp +For example, the TBSCertificate type should have values preserved +so that Certificate validation can check the signatureValue over +the tbsCertificate's value as-received. +.Pp +The alternative of encoding a value to check a signature of it is +brittle. +For types where non-canonical encodings (such as BER) are +allowed, this alternative is bound to fail. +Thus the point of this option. +.It Fl Fl sequence=TYPE +Generate add/remove functions for the named ASN.1 +.Ar TYPE +which must be a +.Sq SET OF +or +.Sq SEQUENCE OF +type. +.It Fl Fl decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given ASN.1 type +.Ar FIELD-ASN1-TYPE , +but do not encode or decode it. +If the +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +This is useful for adding fields to existing types that can be +used for internal bookkeeping but which do not affect +interoperability because they are neither encoded nor decoded. +For example, one might decorate a request type with state needed +during processing of the request. +.It Fl Fl decorate=ASN1-TYPE:void*:fname +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of type +.Sq void * +(but do not encode or decode it. +.Pp +The destructor and copy constructor functions generated by this +compiler for +.Ar ASN1-TYPE +will set this field to the +.Sq NULL +pointer. +.It Fl Fl decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given external C type +.Ar FIELD-C-TYPE , +declared in the given +.Ar header +but do not encode or decode this field. +If the +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +The +.Ar header +must include double quotes or angle brackets. +The +.Ar copyfn +must be the name of a copy constructor function that takes a +pointer to a source value of the type, and a pointer to a +destination value of the type, in that order, and which returns +zero on success or else a system error code on failure. +The +.Ar freefn +must be the name of a destructor function that takes a pointer to +a value of the type and which releases resources referenced by +that value, but does not free the value itself (the run-time +allocates this value as needed from the C heap). +The +.Ar freefn +should also reset the value to a pristine state (such as all +zeros). +.Pp +If the +.Ar copyfn +and +.Ar freefn +are empty strings, then the decoration field will neither be +copied nor freed by the functions generated for the +.Ar TYPE . +.It Fl Fl one-code-file +Generate a single source code file. +Otherwise a separate code file will be generated for every type. +.It Fl Fl gen-name=NAME +Use +.Ar NAME +to form the names of the files generated. +.It Fl Fl option-file=FILE +Take additional command-line options from +.Ar FILE . +The options file must have one command-line option per-line, but +leading whitespace is ignored, and lines that start with a hash +symbol +.Sq ( # ) +are comments and are ignored. +.It Fl Fl original-order +Attempt to preserve the original order of type definition in the +ASN.1 module. +By default the compiler generates types in a topological sort +order. +.It Fl Fl no-parse-units +Do not generate to-int / from-int functions for enumeration +types. +.It Fl Fl type-file=C-HEADER-FILE +Generate an include of the named header file that might be needed +for common type defintions. +.It Fl Fl version +.It Fl Fl help +.El +.Sh NOTES +Currently only the template backend supports automatic encoding +and decoding of open types via the ASN.1 Information Object +System and X.681/X.682/X.683 annotations. diff --git a/third_party/heimdal/lib/asn1/asn1_err.et b/third_party/heimdal/lib/asn1/asn1_err.et new file mode 100644 index 0000000..ac7a9eb --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_err.et @@ -0,0 +1,29 @@ +# +# Error messages for the asn.1 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table asn1 +prefix ASN1 +error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library" +error_code MISSING_FIELD, "ASN.1 structure is missing a required field" +error_code MISPLACED_FIELD, "ASN.1 unexpected field number" +error_code TYPE_MISMATCH, "ASN.1 type numbers are inconsistent" +error_code OVERFLOW, "ASN.1 value too large" +error_code OVERRUN, "ASN.1 encoding ended unexpectedly" +error_code BAD_ID, "ASN.1 identifier doesn't match expected value" +error_code BAD_LENGTH, "ASN.1 length doesn't match expected value" +error_code BAD_FORMAT, "ASN.1 badly-formatted encoding" +error_code PARSE_ERROR, "ASN.1 parse error" +error_code EXTRA_DATA, "ASN.1 extra data past end of end structure" +error_code BAD_CHARACTER, "ASN.1 invalid character in string" +error_code MIN_CONSTRAINT, "ASN.1 too few elements" +error_code MAX_CONSTRAINT, "ASN.1 too many elements" +error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements" +error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun" +error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun" +error_code GOT_BER, "ASN.1 got BER encoded when expected DER" +error_code INDEF_EXTRA_DATA, "ASN.1 EoC tag contained data" +end diff --git a/third_party/heimdal/lib/asn1/asn1_gen.c b/third_party/heimdal/lib/asn1/asn1_gen.c new file mode 100644 index 0000000..6a0244f --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_gen.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include +#include +#include +#include +#include +#include +#include + +RCSID("$Id$"); + +static int +doit(const char *fn) +{ + char buf[2048]; + char *fnout = NULL; + const char *bname; + unsigned long line = 0; + FILE *f, *fout; + size_t offset = 0; + + f = fopen(fn, "r"); + if (f == NULL) + err(1, "fopen"); + + bname = strrchr(fn, '/'); + if (bname) + bname++; + else + bname = fn; + + if (asprintf(&fnout, "%s.out", bname) < 0 || fnout == NULL) + errx(1, "malloc"); + + fout = fopen(fnout, "w"); + if (fout == NULL) + err(1, "fopen: output file"); + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *ptr, *class, *type, *tag, *length, *data, *foo; + int ret, l, c, ty, ta; + unsigned char p[6], *pdata; + size_t sz; + + line++; + + buf[strcspn(buf, "\r\n")] = '\0'; + if (buf[0] == '#' || buf[0] == '\0') + continue; + + ptr = buf; + while (isspace((unsigned char)*ptr)) + ptr++; + + class = strtok_r(ptr, " \t\n", &foo); + if (class == NULL) errx(1, "class missing on line %lu", line); + type = strtok_r(NULL, " \t\n", &foo); + if (type == NULL) errx(1, "type missing on line %lu", line); + tag = strtok_r(NULL, " \t\n", &foo); + if (tag == NULL) errx(1, "tag missing on line %lu", line); + length = strtok_r(NULL, " \t\n", &foo); + if (length == NULL) errx(1, "length missing on line %lu", line); + data = strtok_r(NULL, " \t\n", &foo); + + c = der_get_class_num(class); + if (c == -1) errx(1, "no valid class on line %lu", line); + ty = der_get_type_num(type); + if (ty == -1) errx(1, "no valid type on line %lu", line); + ta = der_get_tag_num(tag); + if (ta == -1) + ta = atoi(tag); + + l = atoi(length); + + printf("line: %3lu offset: %3lu class: %d type: %d " + "tag: %3d length: %3d %s\n", + line, (unsigned long)offset, c, ty, ta, l, + data ? "" : ""); + + ret = der_put_length_and_tag(p + sizeof(p) - 1, sizeof(p), + l, + c, + ty, + ta, + &sz); + if (ret) + errx(1, "der_put_length_and_tag: %d", ret); + + if (fwrite(p + sizeof(p) - sz , sz, 1, fout) != 1) + err(1, "fwrite length/tag failed"); + offset += sz; + + if (data) { + size_t datalen; + + datalen = strlen(data) / 2; + pdata = emalloc(sz); + + if (hex_decode(data, pdata, datalen) != datalen) + errx(1, "failed to decode data"); + + if (fwrite(pdata, datalen, 1, fout) != 1) + err(1, "fwrite data failed"); + offset += datalen; + + free(pdata); + } + } + printf("line: eof offset: %lu\n", (unsigned long)offset); + + if (fclose(fout) == EOF) + err(1, "writes to file %s failed", fnout); + fclose(f); + return 0; +} + + +static int version_flag; +static int help_flag; +struct getargs args[] = { + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "parse-file"); + exit(code); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname (argv[0]); + + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + if (argc != 1) + usage (1); + + return doit (argv[0]); +} diff --git a/third_party/heimdal/lib/asn1/asn1_print.1 b/third_party/heimdal/lib/asn1/asn1_print.1 new file mode 100644 index 0000000..8066b0b --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_print.1 @@ -0,0 +1,135 @@ +.\" Copyright (c) 2021 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2021 +.Dt ASN1_PRINT 1 +.Os HEIMDAL +.Sh NAME +.Nm asn1_print +.Nd dump ASN.1 DER encoded values +.Sh SYNOPSIS +.Nm +.Bk -words +.Oo Fl i \*(Ba Xo Fl Fl no-indent Xc Oc +.Oo Fl I \*(Ba Xo Fl Fl inner Xc Oc +.Oo Fl l \*(Ba Xo Fl Fl list-types Xc Oc +.Oo Fl A \*(Ba Xo Fl Fl try-all-types Xc Oc +.Oo Fl S \*(Ba Xo Fl Fl raw-sequence Xc Oc +.Oo Fl n \*(Ba Xo Fl Fl no-print Xc Oc +.Oo Fl q \*(Ba Xo Fl Fl quiet Xc Oc +.Oo Xo Fl Fl test-encode Xc Oc +.Oo Xo Fl Fl test-copy Xc Oc +.Oo Fl l v \*(Ba Xo +.Fl Fl version +.Xc +.Oc +.Oo Fl l h \*(Ba Xo +.Fl Fl help +.Xc +.Oc +.Op Ar FILE Op Ar TypeName... +.Ek +.Sh DESCRIPTION +.Nm +Dumps ASN.1 DER-encoded values. +If one or more +.Ar TypeName +arguments are given, then +.Nm +will print the value in a JSON-like format using its knowledge of +the ASN.1 modules defining those types, stopping at the first type +for which it can successfully decode the value. +If +.Ar TypeNames +are given, they must be the names of ASN.1 types exported by an +ASN.1 modules that are compiled into +.Nm . +Use the +.Fl Fl try-all-types +option to attempt decoding as all ASN.1 types known to +.Nm . +If neither any +.Ar TypeName +nor +.Fl Fl try-all-types +are given, then the value will be parsed and displayed using just +the self-describing nature of DER. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl i, Fl Fl no-indent +Do not indent dump. +.It Fl I, Fl Fl inner +Try to parse inner structures of OCTET STRING and constructed values. +.It Fl l, Fl Fl list-types +List all types known to +.Nm . +.It Fl A, Fl Fl try-all-types +Attempt to decode the value as any of all types known to +.Nm . +.It Fl S, Fl Fl raw-sequence +If a value parses as a given +.Ar TypeName +but any bytes are left over, try to parse those separately as +well until all bytes are consumed or an error occurs. +.It Fl n, Fl Fl no-print +For the case where +.Fl A +or +.Fl Fl try-all-types +or where a +.Ar TypeName +is given, do not output a JSON representation of the value, just +attempt to decode it. +This is useful for fuzzing. +.It Fl q, Fl Fl quiet +Similar to +.Fl n, Fl Fl no-print +but JSON output will be formatted, just not output. +As with +.Fl n, Fl Fl no-print, +this option requires +.Fl A / Fl Fl try-all-types +or that a +.Ar TypeName +be given. +This is useful for fuzzing. +.It Fl Fl test-encode +Check that encoding produces the same value as decoding. +Useful for fuzzing. +.It Fl Fl test-copy +Test copy functions. +Useful for fuzzing. +.It Fl v, Fl Fl version +.It Fl h, Fl Fl help +.El diff --git a/third_party/heimdal/lib/asn1/asn1_print.c b/third_party/heimdal/lib/asn1/asn1_print.c new file mode 100644 index 0000000..9ef6ffd --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_print.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include +#include +#include +#include +#include +#include +#include +#include "cms_asn1.h" +#include "digest_asn1.h" +#include "krb5_asn1.h" +#include "kx509_asn1.h" +#include "ocsp_asn1.h" +#include "pkcs10_asn1.h" +#include "pkcs12_asn1.h" +#include "pkcs8_asn1.h" +#include "pkcs9_asn1.h" +#include "pkinit_asn1.h" +#include "rfc2459_asn1.h" +#include "rfc4108_asn1.h" +#ifdef ASN1_PRINT_SUPPORTED +#include "x690sample_template_asn1.h" +#else +#include "x690sample_asn1.h" +#endif + +static int quiet_flag = 0; +static int print_flag = 1; +static int test_copy_flag; +static int test_encode_flag; +static int sequence_flag; +static int try_all_flag; +static int indent_flag = 1; +static int inner_flag; + +static unsigned long indefinite_form_loop; +static unsigned long indefinite_form_loop_max = 10000; + +typedef size_t (*lengther)(void *); +typedef int (*copyer)(const void *, void *); +typedef int (*encoder)(unsigned char *, size_t, void *, size_t *); +typedef int (*decoder)(const unsigned char *, size_t, void *, size_t *); +typedef char *(*printer)(const void *, int); +typedef void (*releaser)(void *); +const struct types { + const char *name; + size_t sz; + copyer cpy; + lengther len; + decoder decode; + encoder encode; + printer print; + releaser release; +} types[] = { +#define ASN1_SYM_INTVAL(n, gn, gns, i) +#define ASN1_SYM_OID(n, gn, gns) +#ifdef ASN1_PRINT_SUPPORTED +#define ASN1_SYM_TYPE(n, gn, gns) \ + { \ + n, \ + sizeof(gns), \ + (copyer)copy_ ## gns, \ + (lengther)length_ ## gns, \ + (decoder)decode_ ## gns, \ + (encoder)encode_ ## gns, \ + (printer)print_ ## gns, \ + (releaser)free_ ## gns, \ + }, +#else +#define ASN1_SYM_TYPE(n, gn, gns) \ + { \ + n, \ + sizeof(gns), \ + (copyer)copy_ ## gns, \ + (lengther)length_ ## gns, \ + (decoder)decode_ ## gns, \ + (encoder)encode_ ## gns, \ + 0, \ + (releaser)free_ ## gns, \ + }, +#endif +#include "cms_asn1_syms.c" +#include "digest_asn1_syms.c" +#include "krb5_asn1_syms.c" +#include "kx509_asn1_syms.c" +#include "ocsp_asn1_syms.c" +#include "pkcs10_asn1_syms.c" +#include "pkcs12_asn1_syms.c" +#include "pkcs8_asn1_syms.c" +#include "pkcs9_asn1_syms.c" +#include "pkinit_asn1_syms.c" +#include "rfc2459_asn1_syms.c" +#include "rfc4108_asn1_syms.c" +#ifdef ASN1_PRINT_SUPPORTED +#include "x690sample_template_asn1_syms.c" +#else +#include "x690sample_asn1_syms.c" +#endif +}; + +struct types sorted_types[sizeof(types)/sizeof(types[0])]; + +static size_t +loop (unsigned char *buf, size_t len, int indent) +{ + unsigned char *start_buf = buf; + + while (len > 0) { + int ret; + Der_class class; + Der_type type; + unsigned int tag; + size_t sz; + size_t length; + size_t loop_length = 0; + int end_tag = 0; + const char *tagname; + + ret = der_get_tag (buf, len, &class, &type, &tag, &sz); + if (ret) + errx (1, "der_get_tag: %s", error_message (ret)); + if (sz > len) + errx (1, "unreasonable length (%u) > %u", + (unsigned)sz, (unsigned)len); + buf += sz; + len -= sz; + if (indent_flag) { + int i; + for (i = 0; i < indent; ++i) + printf (" "); + } + printf ("%s %s ", der_get_class_name(class), der_get_type_name(type)); + tagname = der_get_tag_name(tag); + if (class == ASN1_C_UNIV && tagname != NULL) + printf ("%s = ", tagname); + else + printf ("tag %d = ", tag); + ret = der_get_length (buf, len, &length, &sz); + if (ret) + errx (1, "der_get_tag: %s", error_message (ret)); + if (sz > len) + errx (1, "unreasonable tag length (%u) > %u", + (unsigned)sz, (unsigned)len); + buf += sz; + len -= sz; + if (length == ASN1_INDEFINITE) { + if ((class == ASN1_C_UNIV && type == PRIM && tag == UT_OctetString) || + (class == ASN1_C_CONTEXT && type == CONS) || + (class == ASN1_C_UNIV && type == CONS && tag == UT_Sequence) || + (class == ASN1_C_UNIV && type == CONS && tag == UT_Set)) { + printf("*INDEFINITE FORM*"); + } else { + fflush(stdout); + errx(1, "indef form used on unsupported object"); + } + end_tag = 1; + if (indefinite_form_loop > indefinite_form_loop_max) + errx(1, "indefinite form used recursively more then %lu " + "times, aborting", indefinite_form_loop_max); + indefinite_form_loop++; + length = len; + } else if (length > len) { + printf("\n"); + fflush(stdout); + errx (1, "unreasonable inner length (%u) > %u", + (unsigned)length, (unsigned)len); + } + if (class == ASN1_C_CONTEXT || class == ASN1_C_APPL) { + printf ("%lu bytes [%u]", (unsigned long)length, tag); + if (type == CONS) { + printf("\n"); + loop_length = loop (buf, length, indent + 2); + } else { + printf(" IMPLICIT content\n"); + } + } else if (class == ASN1_C_UNIV) { + switch (tag) { + case UT_EndOfContent: + printf (" INDEFINITE length was %lu\n", + (unsigned long)(buf - start_buf)); + break; + case UT_Set : + case UT_Sequence : + printf ("%lu bytes {\n", (unsigned long)length); + loop_length = loop (buf, length, indent + 2); + if (indent_flag) { + int i; + for (i = 0; i < indent; ++i) + printf (" "); + printf ("}\n"); + } else + printf ("} indent = %d\n", indent / 2); + break; + case UT_Integer : { + int val; + + if (length <= sizeof(val)) { + ret = der_get_integer (buf, length, &val, NULL); + if (ret) + errx (1, "der_get_integer: %s", error_message (ret)); + printf ("integer %d\n", val); + } else { + heim_integer vali; + char *p; + + ret = der_get_heim_integer(buf, length, &vali, NULL); + if (ret) + errx (1, "der_get_heim_integer: %s", + error_message (ret)); + ret = der_print_hex_heim_integer(&vali, &p); + if (ret) + errx (1, "der_print_hex_heim_integer: %s", + error_message (ret)); + printf ("BIG NUM integer: length %lu %s\n", + (unsigned long)length, p); + free(p); + } + break; + } + case UT_OctetString : { + heim_octet_string str; + size_t i; + + ret = der_get_octet_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_octet_string: %s", error_message (ret)); + printf ("(length %lu), ", (unsigned long)length); + + if (inner_flag) { + Der_class class2; + Der_type type2; + unsigned int tag2; + + ret = der_get_tag(str.data, str.length, + &class2, &type2, &tag2, &sz); + if (ret || sz > str.length || + type2 != CONS || tag2 != UT_Sequence) + goto just_an_octet_string; + + printf("{\n"); + loop (str.data, str.length, indent + 2); + for (i = 0; i < indent; ++i) + printf (" "); + printf ("}\n"); + + } else { + unsigned char *uc; + + just_an_octet_string: + uc = (unsigned char *)str.data; + for (i = 0; i < min(16,length); ++i) + printf ("%02x", uc[i]); + printf ("\n"); + } + free (str.data); + break; + } + case UT_IA5String : + case UT_PrintableString : { + heim_printable_string str; + unsigned char *s; + size_t n; + + memset(&str, 0, sizeof(str)); + + ret = der_get_printable_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_general_string: %s", + error_message (ret)); + s = str.data; + printf("\""); + for (n = 0; n < str.length; n++) { + if (isprint(s[n])) + printf ("%c", s[n]); + else + printf ("#%02x", s[n]); + } + printf("\"\n"); + der_free_printable_string(&str); + break; + } + case UT_GeneralizedTime : + case UT_GeneralString : + case UT_VisibleString : + case UT_UTF8String : { + heim_general_string str; + + ret = der_get_general_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_general_string: %s", + error_message (ret)); + printf ("\"%s\"\n", str); + free (str); + break; + } + case UT_OID: { + heim_oid o; + char *p; + + ret = der_get_oid(buf, length, &o, NULL); + if (ret) + errx (1, "der_get_oid: %s", error_message (ret)); + ret = der_print_heim_oid_sym(&o, '.', &p); + der_free_oid(&o); + if (ret) + errx (1, "der_print_heim_oid_sym: %s", error_message (ret)); + printf("%s\n", p); + free(p); + + break; + } + case UT_Enumerated: { + int num; + + ret = der_get_integer (buf, length, &num, NULL); + if (ret) + errx (1, "der_get_enum: %s", error_message (ret)); + + printf("%u\n", num); + break; + } + default : + printf ("%lu bytes\n", (unsigned long)length); + break; + } + } + if (end_tag) { + if (loop_length == 0) + errx(1, "zero length INDEFINITE data ? indent = %d\n", + indent / 2); + if (loop_length < length) + length = loop_length; + if (indefinite_form_loop == 0) + errx(1, "internal error in indefinite form loop detection"); + indefinite_form_loop--; + } else if (loop_length) + errx(1, "internal error for INDEFINITE form"); + buf += length; + len -= length; + } + return 0; +} + +static int +type_cmp(const void *va, const void *vb) +{ + const struct types *ta = (const struct types *)va; + const struct types *tb = (const struct types *)vb; + + return strcmp(ta->name, tb->name); +} + +static int +dotype(unsigned char *buf, size_t len, char **argv, size_t *size) +{ + const char *typename = ""; + size_t matches = 0; + size_t sz; + size_t tried = 0; + size_t i = 0; + void *v; + int ret = 0; + + *size = len; + + memcpy(sorted_types, types, sizeof(types)); + qsort(sorted_types, + sizeof(types)/sizeof(types[0]), + sizeof(types[0]), + type_cmp); + + while ((try_all_flag && i < sizeof(types)/sizeof(types[0])) || + (typename = (argv++)[0])) { + + if (try_all_flag) { + typename = sorted_types[i].name; + } else { + size_t right = sizeof(types)/sizeof(types[0]) - 1; + size_t left = 0; + size_t mid = (left + right) >> 1; + int c = -1; + + while (left <= right) { + mid = (left + right) >> 1; + c = strcmp(sorted_types[mid].name, typename); + if (c < 0) + left = mid + 1; + else if (c > 0) + right = mid - 1; + else + break; + } + if (c != 0) + errx(1, "Type %s not found", typename); + i = mid; + } + v = ecalloc(1, sorted_types[i].sz); + ret = sorted_types[i].decode(buf, len, v, &sz); + if (ret == 0) { + matches++; + if (!quiet_flag && sz == len) { + fprintf(stderr, "Match: %s\n", typename); + } else if (sequence_flag) { + *size = sz; + } else if (!quiet_flag) { + fprintf(stderr, "Prefix match: %s\n", typename); + } + if (print_flag) { + static int warned = 0; + + if (!sorted_types[i].print) { + if (!warned) + warnx("Missing print support; try enabling / not " + "disabling ASN.1 templating in build " + "configuration"); + warned = 1; + } else { + char *s; + + s = sorted_types[i].print(v, indent_flag ? ASN1_PRINT_INDENT : 0); + if (!s) + err(1, "Could not print %s\n", typename); + if (!quiet_flag) + printf("%s\n", s); + free(s); + } + } + if (test_encode_flag) { + unsigned char *der = emalloc(sz); + size_t wants = sorted_types[i].len(v); + + if (wants != sz) + errx(1, "Encoding will not round trip"); + ret = sorted_types[i].encode(der + (sz - 1), sz, v, &sz); + if (ret != 0) + errx(1, "Encoding failed"); + if (memcmp(buf, der, sz) != 0) + errx(1, "Encoding did not round trip"); + free(der); + } + if (test_copy_flag) { + void *vcpy = ecalloc(1, sorted_types[i].sz); + + ret = sorted_types[i].cpy(v, vcpy); + if (ret != 0) + errx(1, "Copy function failed"); + if (test_encode_flag) { + unsigned char *der = emalloc(sz); + size_t wants = sorted_types[i].len(vcpy); + + if (wants != sz) + errx(1, "Encoding of copy will not round trip"); + ret = sorted_types[i].encode(der + (sz - 1), sz, vcpy, &sz); + if (ret != 0) + errx(1, "Encoding of copy failed"); + if (memcmp(buf, der, sz) != 0) + errx(1, "Encoding of copy did not round trip"); + free(der); + } + sorted_types[i].release(vcpy); + free(vcpy); + } + } + sorted_types[i].release(v); + free(v); + tried++; + i++; + + if (ret == 0 && !try_all_flag && !argv[0]) + return 0; + + if (!try_all_flag && argv[0]) + continue; + + if (try_all_flag) { + if (i < sizeof(types)/sizeof(types[0])) + continue; + if (matches) + break; + } + if (tried > 1) + errx(1, "No type matched the input value"); + + /* XXX Use com_err */ + switch (ret) { + case ASN1_BAD_TIMEFORMAT: + errx(1, "Could not decode and print data as type %s: " + "Bad time format", typename); + case ASN1_MISSING_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Missing required field", typename); + case ASN1_MISPLACED_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Fields out of order", typename); + case ASN1_TYPE_MISMATCH: + errx(1, "Could not decode and print data as type %s: " + "Type mismatch", typename); + case ASN1_OVERFLOW: + errx(1, "Could not decode and print data as type %s: " + "DER value too large", typename); + case ASN1_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "DER value too short", typename); + case ASN1_BAD_ID: + errx(1, "Could not decode and print data as type %s: " + "DER tag is unexpected", typename); + case ASN1_BAD_LENGTH: + errx(1, "Could not decode and print data as type %s: " + "DER length does not match value", typename); + case ASN1_BAD_FORMAT: + case ASN1_PARSE_ERROR: + errx(1, "Could not decode and print data as type %s: " + "DER badly formatted", typename); + case ASN1_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "Extra data past end of end structure", typename); + case ASN1_BAD_CHARACTER: + errx(1, "Could not decode and print data as type %s: " + "Invalid character encoding in string", typename); + case ASN1_MIN_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too few elements", typename); + case ASN1_MAX_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too many elements", typename); + case ASN1_EXACT_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Wrong count of elements", typename); + case ASN1_INDEF_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding overun", typename); + case ASN1_INDEF_UNDERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding underun", typename); + case ASN1_GOT_BER: + errx(1, "Could not decode and print data as type %s: " + "BER encoding when DER expected", typename); + case ASN1_INDEF_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "End-of-contents tag contains data", typename); + default: + errx(1, "Could not decode and print data as type %s", typename); + } + } + return 0; +} + +static int +doit(char **argv) +{ + int fd = open(argv[0], O_RDONLY); + struct stat sb; + unsigned char *buf; + size_t len; + int ret; + + if(fd < 0) + err(1, "opening %s for read", argv[0]); + if (fstat (fd, &sb) < 0) + err(1, "stat %s", argv[0]); + len = sb.st_size; + buf = emalloc(len); + if (read(fd, buf, len) != len) + errx(1, "read failed"); + close(fd); + + argv++; + if (argv[0] || try_all_flag) { + size_t off = 0; + size_t sz = 0; + + do { + ret = dotype(buf + off, len - off, argv, &sz); + off += sz; + } while (ret == 0 && sequence_flag && off < len); + } else { + ret = loop(buf, len, 0); + } + free(buf); + return ret; +} + + +static int list_types_flag; +static int version_flag; +static int help_flag; +struct getargs args[] = { + { "indent", 'i', arg_negative_flag, &indent_flag, + "\tdo not indent dump", NULL }, + { "inner", 'I', arg_flag, &inner_flag, + "\ttry to parse inner structures of OCTET STRING", NULL }, + { "list-types", 'l', arg_flag, &list_types_flag, + "\tlist ASN.1 types known to this program", NULL }, + { "try-all-types", 'A', arg_flag, &try_all_flag, + "\ttry all known types", NULL }, + { "raw-sequence", 'S', arg_flag, &sequence_flag, + "\ttry parsing leftover data", NULL }, + { "test-encode", 0, arg_flag, &test_encode_flag, + "\ttest encode round trip (for memory debugging and fuzzing)", NULL }, + { "test-copy", 0, arg_flag, &test_copy_flag, + "\ttest copy operation (for memory debugging and fuzzing)", NULL }, + { "print", 'n', arg_negative_flag, &print_flag, + "\ttest copy operation (for memory debugging and fuzzing)", NULL }, + { "quiet", 'q', arg_flag, &quiet_flag, + "\tOutput nothing (exit status 0 means type matched)", NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "dump-file [TypeName [TypeName ...]]"); + exit(code); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + initialize_asn1_error_table(); + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if (help_flag) + usage(0); + if (version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + + if (sequence_flag && try_all_flag) + errx(1, "--raw-sequence and --try-all-types are mutually exclusive"); + if (quiet_flag && !try_all_flag && argc < 2) + errx(1, "--quiet requires --try-all-types or that a TypeName be given"); + if (!print_flag && !try_all_flag && argc < 2) + errx(1, "--no-print requires --try-all-types or that a TypeName be given"); + + if (list_types_flag) { + size_t i; + + if (argc) + errx(1, "--list-types is exclusive of other options or arguments"); + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) + printf("%s\n", types[i].name); + exit(0); + } + + if (argc < 1) + usage(1); + return doit(argv); +} diff --git a/third_party/heimdal/lib/asn1/asn1parse.y b/third_party/heimdal/lib/asn1/asn1parse.y new file mode 100644 index 0000000..d9e3fba --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1parse.y @@ -0,0 +1,2036 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +%{ + +#include + +#include +#include +#include +#include +#include "symbol.h" +#include "lex.h" +#include "gen_locl.h" +#include "der.h" + +static Type *new_type (Typetype t); +/*static IOSClass *new_class(struct fieldhead *);*/ +/*static IOSObject *new_object(struct objfieldhead *);*/ +/*IOSObjectSet *new_object_set(struct objectshead *);*/ +static struct objectshead *add_object_set_spec(struct objectshead *, IOSObject *); +static ObjectField *new_field_setting(char *, Type *, struct value *); +static struct objfieldhead *add_field_setting(struct objfieldhead *, ObjectField *); +static struct fieldhead *add_field_spec(struct fieldhead *, Field *); +static Field *new_type_field(char *, int, Type *); +static Field *new_fixed_type_value_field(char *, Type *, int, int, struct value *); +static Type *parametrize_type(Type *, IOSClass *); +static Type *type_from_class_field(IOSClass *, const char *); +static void validate_object_set(IOSObjectSet *); +/*static Type *type_from_object(const char *, const char *);*/ +static struct constraint_spec *new_constraint_spec(enum ctype); +static Type *new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype); +void yyerror (const char *); +#define yyerror yyerror +static struct objid *new_objid(const char *label, int value); +static void add_oid_to_tail(struct objid *, struct objid *); +static void fix_labels(Symbol *s); + +struct string_list { + char *string; + struct string_list *next; +}; + +static int default_tag_env = TE_EXPLICIT; +static unsigned long idcounter; + +/* Declarations for Bison */ +#define YYMALLOC malloc +#define YYFREE free + +%} + +%union { + int64_t constant; + struct value *value; + struct range *range; + char *name; + Type *type; + IOSClass *class; + IOSObjectSet *objectset; + IOSObject *object; + Field *field; + ObjectField *objfield; + Member *member; + IOSClass *formalparam; + struct objid *objid; + char *defval; + struct string_list *sl; + struct tagtype tag; + struct memhead *members; + struct fieldhead *fields; + struct objectshead *objects; + struct objfieldhead *objfields; + struct constraint_spec *constraint_spec; +} + +%token kw_ABSENT +%token kw_ABSTRACT_SYNTAX +%token kw_ALL +%token kw_APPLICATION +%token kw_AUTOMATIC +%token kw_BEGIN +%token kw_BIT +%token kw_BMPString +%token kw_BOOLEAN +%token kw_BY +%token kw_CHARACTER +%token kw_CHOICE +%token kw_CLASS +%token kw_COMPONENT +%token kw_COMPONENTS +%token kw_CONSTRAINED +%token kw_CONTAINING +%token kw_DEFAULT +%token kw_DEFINITIONS +%token kw_EMBEDDED +%token kw_ENCODED +%token kw_END +%token kw_ENUMERATED +%token kw_EXCEPT +%token kw_EXPLICIT +%token kw_EXPORTS +%token kw_EXTENSIBILITY +%token kw_EXTERNAL +%token kw_FALSE +%token kw_FROM +%token kw_GeneralString +%token kw_GeneralizedTime +%token kw_GraphicString +%token kw_IA5String +%token kw_IDENTIFIER +%token kw_IMPLICIT +%token kw_IMPLIED +%token kw_IMPORTS +%token kw_INCLUDES +%token kw_INSTANCE +%token kw_INTEGER +%token kw_INTERSECTION +%token kw_ISO646String +%token kw_MAX +%token kw_MIN +%token kw_MINUS_INFINITY +%token kw_NULL +%token kw_NumericString +%token kw_OBJECT +%token kw_OCTET +%token kw_OF +%token kw_OPTIONAL +%token kw_ObjectDescriptor +%token kw_PATTERN +%token kw_PDV +%token kw_PLUS_INFINITY +%token kw_PRESENT +%token kw_PRIVATE +%token kw_PrintableString +%token kw_REAL +%token kw_RELATIVE_OID +%token kw_SEQUENCE +%token kw_SET +%token kw_SIZE +%token kw_STRING +%token kw_SYNTAX +%token kw_T61String +%token kw_TAGS +%token kw_TRUE +%token kw_TYPE_IDENTIFIER +%token kw_TeletexString +%token kw_UNION +%token kw_UNIQUE +%token kw_UNIVERSAL +%token kw_UTCTime +%token kw_UTF8String +%token kw_UniversalString +%token kw_VideotexString +%token kw_VisibleString +%token kw_WITH + +%token RANGE +%token EEQUAL +%token ELLIPSIS + +%token TYPE_IDENTIFIER referencename +%token CLASS_IDENTIFIER +%token VALUE_IDENTIFIER +%token STRING + +%token NUMBER +%type SignedNumber +%type Class tagenv +%type DummyReference + +%type Identifier + +/* + * The NULL keyword being both a value and a type causes a reduce/reduce + * conflict in the FieldSetting production since its alternatives are + * + * '&' Identifier Type + * + * and + * + * '&' Identifier Value + * + * and NULL is both a type and a value. + * + * For now we work around this by having a ValueExNull production that excludes + * the NULL value. To really get past this will require unifying the type and + * value types (e.g., via type punning). + */ +%type Value ValueExNull +%type BuiltinValue BuiltinValueExNull +%type IntegerValue +%type BooleanValue +%type ObjectIdentifierValue +%type CharacterStringValue +%type NullValue +%type DefinedValue +%type ReferencedValue +%type Valuereference + +%type DefinedObjectClass ParamGovernor +%type ObjectClassDefn +%type Parameter + +%type Type +%type BuiltinType +%type BitStringType +%type BooleanType +%type ChoiceType +%type ConstrainedType +%type UnconstrainedType +%type EnumeratedType +%type IntegerType +%type NullType +%type OctetStringType +%type SequenceType +%type SequenceOfType +%type SetType +%type SetOfType +%type TaggedType +%type ReferencedType +%type DefinedType +%type UsefulType +%type ObjectIdentifierType +%type CharacterStringType +%type RestrictedCharactedStringType +%type ObjectClassFieldType +%type ParameterizedType +/*%type TypeFromObject*/ + +%type ObjectSet DefinedObjectSet +%type ActualParameter +%type Object DefinedObject ObjectDefn +%type FieldSetting + +%type Tag + +%type FieldSpec TypeFieldSpec FixedTypeValueFieldSpec +%type FieldSpecList +%type ComponentType +%type NamedBit +%type NamedNumber +%type NamedType +%type ComponentTypeList +%type Enumerations +%type NamedBitList +%type NamedNumberList +%type ObjectSetSpec +%type FieldSettings + +%type objid objid_list objid_element objid_opt +%type range size + +%type referencenames + +%type Constraint +%type ConstraintSpec +%type SubtypeConstraint +%type GeneralConstraint +%type ContentsConstraint +%type UserDefinedConstraint +%type SimpleTableConstraint TableConstraint +%type ComponentRelationConstraint + + +%start ModuleDefinition + +%% + +/* + * We have sinned by allowing types to have names that start with lower-case, + * and values that have names that start with upper-case. + * + * UPDATE: We sin no more. However, parts of this block comment are still + * relevant. + * + * That worked when we only supported basic X.680 because the rules for + * TypeAssignment and ValueAssignment are clearly unambiguous in spite of the + * case issue. + * + * We now pay the price because X.681 adds productions where the only thing we + * have to help us distinguish certain rules is the form of an identifier: the + * case of its first letter. + * + * We have cleansed our sin by not allowing wrong-case identifiers any more. + * + * Some historical instances of this sin in-tree: + * + * - DOMAIN-X500-COMPRESS (value (enum) but name starts with upper-case) + * - krb5int32 (type but name starts with lower-case) + * - krb5uint32 (type but name starts with lower-case) + * - hdb_keyset (type but name starts with lower-case) + * - hdb_entry (type but name starts with lower-case) + * - hdb_entry_alias (type but name starts with lower-case) + * - HDB_DB_FORMAT INTEGER (value (int) but name starts with upper-case) + * + * We have fixed all of these and others, in some cases leaving behind aliases + * in header files as needed. + * + * We have one shift/reduce conflict (shift ObjectClassAssignment, reduce + * TypeAssignment) and one reduce/reduce conflict (ObjectAssignment vs + * ValueAssignment) that we avoid by requiring CLASS names to start with an + * underscore. + * + * In the FieldSetting rule, also, we get a reduce/reduce conflict if we use + * `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and + * `VALUE_IDENTIFIER' for value field settings, and then we can't make + * progress. + * + * Looking forward, we may not (will not) be able to distinguish ValueSet and + * ObjectSet field settings from each other either, and we may not (will not) + * be able distinguish Object and Value field settings from each other as well. + * To deal with those we will have to run-time type-tag and type-pun the C + * structures for valueset/objectset and value/object, and have one rule for + * each of those that inspects the type of the item to decide what kind of + * setting it is. + * + * Sadly, the extended syntax for ASN.1 (x.680 + x.681/2/3) appears to have + * ambiguities that cannot be resolved with bison/yacc. + */ +Identifier : TYPE_IDENTIFIER { $$ = $1; } + | VALUE_IDENTIFIER { $$ = $1; }; + +ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefault + EEQUAL kw_BEGIN ModuleBody kw_END + { + struct objid **o = objid2list($2); + size_t i; + + fprintf(jsonfile, + "{\"module\":\"%s\",\"tagging\":\"%s\",\"objid\":[", $1, + default_tag_env == TE_EXPLICIT ? "explicit" : "implicit"); + + for (i = 0; o && o[i]; i++) { + fprintf(jsonfile, "%s{\"value\":%d", i ? "," : "", o[i]->value); + if (o[i]->label) + fprintf(jsonfile, ",\"label\":\"%s\"", o[i]->label); + fprintf(jsonfile, "}"); + } + fprintf(jsonfile, "]}\n"); + free(o); + } + ; + +TagDefault : kw_EXPLICIT kw_TAGS + { default_tag_env = TE_EXPLICIT; } + | kw_IMPLICIT kw_TAGS + { default_tag_env = TE_IMPLICIT; } + | kw_AUTOMATIC kw_TAGS + { lex_error_message("automatic tagging is not supported"); } + | /* empty */ + ; + +ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED + { lex_error_message("no extensibility options supported"); } + | /* empty */ + ; + +ModuleBody : Exports Imports AssignmentList + | /* empty */ + ; + +Imports : kw_IMPORTS SymbolsImported ';' + | /* empty */ + ; + +SymbolsImported : SymbolsFromModuleList + | /* empty */ + ; + +SymbolsFromModuleList: SymbolsFromModule + | SymbolsFromModuleList SymbolsFromModule + ; + +SymbolsFromModule: referencenames kw_FROM Identifier objid_opt + { + /* + * FIXME We really could use knowing what kind of thing the + * identifier identifies -- a type, a value, what? + * + * Our sin of allowing type names to start with lower-case + * and values with upper-case means we can't tell. So we + * assume it's types only, but that means we can't import + * OID values, but we really want to! + * + * One thing we could do is not force `s->stype = Stype' + * here, instead set it to a new `Sunknown' value so that + * the first place that refers to this symbol with enough + * context to imply a symbol type can set it. + */ + struct string_list *sl; + for(sl = $1; sl != NULL; sl = sl->next) { + Symbol *s = addsym(sl->string); + s->stype = Stype; + gen_template_import(s); + } + add_import($3); + } + ; + +Exports : kw_EXPORTS referencenames ';' + { + struct string_list *sl; + for(sl = $2; sl != NULL; sl = sl->next) + add_export(sl->string); + } + | kw_EXPORTS kw_ALL + | /* empty */ + ; + +AssignmentList : Assignment + | Assignment AssignmentList + ; + +Assignment : TypeAssignment + | ValueAssignment + | ParameterizedTypeAssignment + | ObjectClassAssignment + | ObjectAssignment + | ObjectSetAssignment + /* | ParameterizedAssignment // from X.683 */ + ; + +referencenames : Identifier ',' referencenames + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = $3; + } + | Identifier + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = NULL; + } + ; + +DefinedObjectClass + : CLASS_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sclass) + lex_error_message ("%s is not a class\n", $1); + $$ = s->iosclass; + }; + +ObjectClassAssignment + : CLASS_IDENTIFIER EEQUAL ObjectClassDefn + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + s->iosclass->symbol = s; + fix_labels(s); + } + | CLASS_IDENTIFIER EEQUAL DefinedObjectClass + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + } + /* | ParameterizedObjectClass */ + ; + +ObjectClassDefn : kw_CLASS '{' FieldSpecList '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->fields = $3; + $$->id = idcounter++; + }; + +ObjectAssignment: VALUE_IDENTIFIER DefinedObjectClass EEQUAL Object + { + Symbol *s = addsym($1); + s->stype = Sobj; + s->object = $4; + s->object->iosclass = $2; + if (!s->object->symbol) + s->object->symbol = s; + fix_labels(s); + } + ; + +ObjectSetAssignment + : TYPE_IDENTIFIER DefinedObjectClass EEQUAL ObjectSet + { + Symbol *s = addsym($1); + s->stype = Sobjset; + s->iosclass = $2; + s->objectset = $4; + s->objectset->symbol = s->objectset->symbol ? s->objectset->symbol : s; + s->objectset->iosclass = $2; + validate_object_set($4); + generate_template_objectset_forwards(s); + } + ; + +ObjectSet : '{' ObjectSetSpec '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objects = $2; + $$->id = idcounter++; + } + ; + +ObjectSetSpec : DefinedObject + { $$ = add_object_set_spec(NULL, $1); } + | ObjectSetSpec '|' DefinedObject + { $$ = add_object_set_spec($1, $3); } + ; + +Object : DefinedObject + | ObjectDefn + /* | ObjectFromObject */ + /* | ParameterizedObject */ + ; + +DefinedObject : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobj) + lex_error_message ("%s is not an object\n", $1); + $$ = s->object; + } + ; + +DefinedObjectSet: TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobjset && s->stype != SUndefined) + lex_error_message ("%s is not an object set\n", $1); + $$ = s->objectset; + } + ; + + +ObjectDefn : '{' FieldSettings '}' /* DefaultSyntax */ + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objfields = $2; + $$->id = idcounter++; + } + /* | DefinedSyntax */ + ; + +FieldSettings : FieldSetting + { + $$ = add_field_setting(NULL, $1); + } + | FieldSettings ',' FieldSetting + { + $$ = add_field_setting($1, $3); + } + ; + +/* See note on `Identifier' */ +FieldSetting : '&' Identifier Type + { $$ = new_field_setting($2, $3, NULL); } + | '&' Identifier ValueExNull + { $$ = new_field_setting($2, NULL, $3); } + /* | '&' TYPE_IDENTIFIER ValueSet */ + /* | '&' VALUE_IDENTIFIER Object */ + /* | '&' TYPE_IDENTIFIER ObjectSet */ + ; + +/* Fields of a class */ +FieldSpecList : FieldSpec + { $$ = add_field_spec(NULL, $1); } + | FieldSpecList ',' FieldSpec + { $$ = add_field_spec($1, $3); }; + +/* + * Fields of a CLASS + * + * There are seven kinds of class/object fields: + * + * - type fields, + * - fixed-type value fields, + * - fixed-type value set fields, + * - variable-type value fields + * - variable-type value set fields + * - object fields + * - object set fields + * + * We care only to support the bare minimum to treat open types as a CHOICE of + * sorts and automatically encode/decode values in open types. That's: type + * fields and fixed-type value fields. + */ +FieldSpec : TypeFieldSpec + | FixedTypeValueFieldSpec + /* | VariableTypeValueFieldSpec */ + /* | VariableTypeValueSetFieldSpec */ + /* | FixedTypeValueSetFieldSpec */ + /* | ObjectFieldSpec */ + /* | ObjectSetFieldSpec */ + ; +TypeFieldSpec : '&' Identifier + { $$ = new_type_field($2, 0, NULL); } + | '&' Identifier kw_OPTIONAL + { $$ = new_type_field($2, 1, NULL); } + | '&' Identifier kw_DEFAULT Type + { $$ = new_type_field($2, 1, $4); } + ; + +FixedTypeValueFieldSpec + : '&' Identifier Type + { $$ = new_fixed_type_value_field($2, $3, 0, 0, NULL); } + | '&' Identifier Type kw_UNIQUE + { $$ = new_fixed_type_value_field($2, $3, 1, 0, NULL); } + | '&' Identifier Type kw_UNIQUE kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 1, 1, NULL); } + | '&' Identifier Type kw_UNIQUE kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 1, 0, $6); } + | '&' Identifier Type kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 0, 1, NULL); } + | '&' Identifier Type kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 0, 0, $5); }; + +/* + * Now we need a bit of X.683, just enough to parse PKIX. + * + * E.g., we need to parse this sort of type definition, which isn't quite the + * final type definition because the ExtensionSet will be provided later. + * + *-- <- ObjectClassDefn -> + * EXTENSION ::= CLASS { + * &id OBJECT IDENTIFIER UNIQUE, + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * + * &ExtnType, + * -- ^^^^^^^^^ + * -- TypeFieldSpec + * + * &Critical BOOLEAN DEFAULT {TRUE | FALSE } + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * } WITH SYNTAX { + * SYNTAX &ExtnType IDENTIFIED BY &id + * [CRITICALITY &Critical] + * } + * + *-- <--------- ParameterizedTypeAssignment --------> + * -- NOTE: The name of this type has to be Extension, really. + * -- But the name of the Extension type with the actual + * -- parameter provided also has to be Extension. + * -- We could disallow that and require that the various + * -- Extension types all have different names, then we'd + * -- let the one with the actual parameter in PKIX be the + * -- one named Extension. Or we could find a way to let + * -- them all share one symbol name, or at least two: + * -- the one with the formal parameter, and just one with + * -- an actual parameter. + * -- + * -- Also, IMPORTing types that have formal parameters is + * -- almost certainly going to require parsing the IMPORTed + * -- module. Until we do that, users will be able to work + * -- around that by just copying CLASSes and pameterized + * -- type definitions around. But when we do start parsing + * -- IMPORTed modules we might need to do something about + * -- many types possibly having the same names, though we + * -- might do nothing and simply say "don't do that!". + * Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + * -- ^^^^^^^^^^^^ + * -- is a DummyReference, which is a Reference, basically + * -- it is an object set variable which will have an object + * -- set value supplied where constrained types are defined + * -- from this one, possibly anonymous types where + * -- SEQUENCE/SET members of this type are defined. + * -- ^^^^^^^^^ + * -- is a ParamGovernor, really, just Governor, either a Type or + * -- DefinedObjectClass (we only need DefinedObjectClass) + * -- ^^^^^^^^^^^^^^^^^^^^^^ + * -- is a Parameter + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- is a ParameterList (we need only support one param though) + * extnID EXTENSION.&id({ExtensionSet}), + * -- ^^^^^^^^^^^^^^^^ + * -- simple table constraint limiting id to OIDs + * -- from ExtensionSet + * -- ^^^^^^^^^^^^^ + * -- a reference to the id field of the EXTENSION CLASS + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING (CONTAINING + * -- ObjectClassFieldType + * -- vvvvvvvvvvvvvvvvvvv + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * -- ^^^^^^^^^ + * -- AtNotation + * -- ^^^^^^^^^^^^^^ + * -- DefinedObjectSet + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ComponentRelationConstraint + * -- says that extnValue will contain + * -- a value of a type identified by + * -- the OID in extnID in the object + * -- set ExtensionSet (which is a set + * -- of {OID, type} objects) + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ConstraintSpec + * -- ^^^^^^^^^^^^^^^^^^^ + * -- another type ref + * } + * + * Then later we'll see (ParameterizedType, a part of DefinedType): + * + * TBSCertificate ::= SEQUENCE { + * ... + * -- Here is where the object set is linked into the + * -- whole thing, making *magic* possible. This is + * -- where the real Extensions type is defined. Sadly + * -- this might mean we can't have a C type named + * -- Extensions. Hmmm. We might need an ASN.1 + * -- extension that lets use do this: + * -- + * -- Extension ::= Extension{{CertExtensions}} + * -- + * -- or + * -- + * -- Extension ::= ParameterizedExtension{{CertExtensions}} + * -- + * -- and then rename the Extension type above to this. + * -- Then we can define Extensions as a SEQUENCE OF + * -- that. + * -- + * -- <- ParameterizedType -> + * extensions [3] Extensions{{CertExtensions}} OPTIONAL + * -- ^^^^^^^^^^^^^^ + * -- ObjectSetSpec + * -- ^^^^^^^^^^^^^^^^ + * -- ObjectSet + * -- ^^^^^^^^^^^^^^^^^^ + * -- ActualParameterList + * -- ^^^^^^^^^^ + * -- Type + * } + * + * Then: + * + * -- Object set, limits what Extensions can be in TBSCertificate. + *-- <- ObjectSetAssignment -> + * CertExtensions EXTENSION ::= { + * -- ^^^^^^^^^ + * -- DefinedObjectClass + *-- ^^^^^^^^^^^^^^ + *-- objectsetreference, for us, IDENTIFIER + * ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | ... + * } + * + * and: + * + * -- ObjectAssignment (with defined syntax, which we're not going to support): + * -- + * -- Defines one particular object in the CertExtensions object set. + * -- We don't need th SYNTAX bits though -- ETOOMUCHWORK. + * -- This says that the OID id-ce-authorityKeyIdentifier means the extnValue + * -- is a DER-encoded AuthorityKeyIdentifier. + * ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX + * AuthorityKeyIdentifier IDENTIFIED BY + * id-ce-authorityKeyIdentifier } + * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + * + * -- ObjectAssignment (with default syntax): + * ext-AuthorityKeyIdentifier EXTENSION ::= { + * -- fields don't have to be in order since we have the field names + * &extnId id-ce-authorityKeyIdentifier, + * &extnValue AuthorityKeyIdentifier + * } + * + * -- Plain old type def using only X.680 + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * In terms of compilation, we'll want to support only the template backend, + * though we'll generate the same C types for both, the template backend and + * the codegen backend. + * + * The generators should see a type for Extension that includes a) the + * parametrization (relating members in the SEQUENCE to fields in the CLASS), + * and b) the object set CertExtensions for the _same_ class. + * + * - The C types for ASN.1 parametrized types with object set parameters + * should be laid out just as before, but with additional fields: + * + * typedef struct Extension { + * heim_oid extnID; + * int *critical; + * heim_octet_string extnValue; + * // NEW FIELDS BELOW + * enum { + * opentypechoice_unknown_Extension = 0 + * opentypechoice_Extension_id_ce_authorityKeyIdentifier, + * ... + * } _element; + * union { + * // er, what should this be named?! we have no name information + * // and naming it after its object value name is probably not a good + * // idea or not easy. We do have the OID value and possible name + * // though, so we should use that: + * AuthorityKeyIdentifier id_ce_authorityKeyIdentifier; + * ... + * } _u; + * } Extension; + * + * - The template for this should consist of new struct asn1_template entries + * following the ones for the normal fields of Extension. The first of these + * should have an OP that indicates that the following N entries correspond + * to the object set that specifies this open type, then the following N + * entries should each point to an object in the object set. Or maybe the + * object set should be a separate template -- either way. We'll also want a + * flag to indicate whether the object set is sorted (none of the type IDs + * are IMPORTed) or not (some of the type IDs are IMPORTed) so we can binary + * search the object set at encode/decode time. + * + * Hmm, we can assume the object sets are already sorted when there's + * IMPORTed IDs -- the author can do it. Yes, they're sets, but lexically + * they must be in some order. + * + * I like that, actually, requiring that the module author manually sort the + * object sets, at least when they refer to type IDs that are IMPORTed. Or + * maybe forbid object sets that use IMPORTed type IDs -- the module author + * can always copy their definitions anyways. + */ + +TypeAssignment : Identifier EEQUAL Type + { + Symbol *s = addsym($1); + s->stype = Stype; + s->type = $3; + fix_labels(s); + + /* + * Hack: make sure that non-anonymous enumeration types get + * a symbol tacked on so we can generate a template for + * their members for value printing. + */ + if (s->type->type == TTag && $3->symbol == NULL && + $3->subtype != NULL && $3->subtype->type == TInteger && + $3->subtype->symbol == NULL) { + $3->subtype->symbol = s; + } + if (original_order) + generate_type(s); + else + generate_type_header_forwards(s); + } + ; + +ParameterizedTypeAssignment + /* For now we'll only support one parameter -- enough for PKIX */ + : Identifier '{' Parameter '}' EEQUAL Type + { + char *pname = NULL; + Symbol *s; + + if (asprintf(&pname, "%s{%s:x}", $1, $3->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + s = addsym(pname); + free($1); + s->stype = Sparamtype; + s->type = parametrize_type($6, $3); + s->type->symbol = s; + fix_labels(s); + } + ; + +/* + * We're not going to support governor variables for now. We don't need to. + * + * Also, we're not going to support more than one formal parameter. + * Correspondingly we'll only support a single actual parameter (the count of + * formal and actual parameters has to match, naturally). + */ + +Parameter : ParamGovernor ':' DummyReference + { $$ = $1; }; + /* | DummyReference */ + ; + +DummyReference : TYPE_IDENTIFIER { $$ = idcounter++; }; + +ParamGovernor : DefinedObjectClass + { $$ = $1; } + /* | DummyGovernor */ + /* | Type */ + ; + +UnconstrainedType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SetType + | ObjectClassFieldType; /* X.681 */ + +Type : BuiltinType | ReferencedType | ConstrainedType ; + +BuiltinType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SequenceOfType + | SetType + | SetOfType + | TaggedType + | ObjectClassFieldType /* X.681 */ + /* | InstanceOfType // X.681 */ + ; + +ObjectClassFieldType + : DefinedObjectClass '.' '&' Identifier + { $$ = type_from_class_field($1, $4); }; + +BooleanType : kw_BOOLEAN + { + $$ = new_tag(ASN1_C_UNIV, UT_Boolean, + TE_EXPLICIT, new_type(TBoolean)); + } + ; + + /* + * The spec says the values in a ValueRange are Values, but a) all + * the various value ranges do not involve OBJECT IDENTIFIER, b) + * we only support integer value ranges at this time (as opposed + * to, e.g., time ranges, and we don't even support time values at + * this time), c) allowing OBJECT IDENTIFIER here causes a + * shift-reduce conflict, so we limit ourselves to integer values + * in ranges. We could always define IntegerValueRange, + * TimeValueRange, etc. when we add support for more value types. + */ +range : IntegerValue RANGE IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in first part of range"); + if($1->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $3->u.integervalue; + } + | IntegerValue RANGE kw_MAX + { + if($1->type != integervalue) + lex_error_message("Non-integer in first part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = INT_MAX; + } + | kw_MIN RANGE IntegerValue + { + if($3->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = INT_MIN; + $$->max = $3->u.integervalue; + } + | IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in limit"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $1->u.integervalue; + } + ; + + +IntegerType : kw_INTEGER + { + $$ = new_tag(ASN1_C_UNIV, UT_Integer, + TE_EXPLICIT, new_type(TInteger)); + } + | kw_INTEGER '{' NamedNumberList '}' + { + $$ = new_type(TInteger); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); + } + ; + +NamedNumberList : NamedNumber + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedNumberList ',' NamedNumber + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + | NamedNumberList ',' ELLIPSIS + { $$ = $1; } /* XXX used for Enumerations */ + ; + +NamedNumber : Identifier '(' SignedNumber ')' + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + | Identifier '(' DefinedValue ')' + { + if ($3->type != integervalue) + lex_error_message("Named number %s not a numeric value", + $3->s->name); + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3->u.integervalue; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + ; + +EnumeratedType : kw_ENUMERATED '{' Enumerations '}' + { + $$ = new_type(TInteger); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Enumerated, TE_EXPLICIT, $$); + } + ; + +Enumerations : NamedNumberList /* XXX */ + ; + +BitStringType : kw_BIT kw_STRING + { + $$ = new_type(TBitString); + $$->members = emalloc(sizeof(*$$->members)); + HEIM_TAILQ_INIT($$->members); + $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); + } + | kw_BIT kw_STRING '{' NamedBitList '}' + { + $$ = new_type(TBitString); + $$->members = $4; + $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); + } + ; + +ObjectIdentifierType: kw_OBJECT kw_IDENTIFIER + { + $$ = new_tag(ASN1_C_UNIV, UT_OID, + TE_EXPLICIT, new_type(TOID)); + } + ; +OctetStringType : kw_OCTET kw_STRING size + { + Type *t = new_type(TOctetString); + t->range = $3; + if (t->range) { + if (t->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for OCTET STRING"); + } + $$ = new_tag(ASN1_C_UNIV, UT_OctetString, + TE_EXPLICIT, t); + } + ; + +NullType : kw_NULL + { + $$ = new_tag(ASN1_C_UNIV, UT_Null, + TE_EXPLICIT, new_type(TNull)); + } + ; + +size : + { $$ = NULL; } + | kw_SIZE '(' range ')' + { $$ = $3; } + ; + + +SequenceType : kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSequence); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + | kw_SEQUENCE '{' '}' + { + $$ = new_type(TSequence); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SequenceOfType : kw_SEQUENCE size kw_OF Type + { + $$ = new_type(TSequenceOf); + $$->range = $2; + if ($$->range) { + if ($$->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for SEQUENCE OF"); + } + + $$->subtype = $4; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SetType : kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSet); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + | kw_SET '{' '}' + { + $$ = new_type(TSet); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +SetOfType : kw_SET kw_OF Type + { + $$ = new_type(TSetOf); + $$->subtype = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TChoice); + $$->members = $3; + } + ; + +ReferencedType : DefinedType + | UsefulType + /* | TypeFromObject // X.681 */ + /* | ValueSetFromObjects // X.681 */ + ; + +/* +TypeFromObject : VALUE_IDENTIFIER '.' '&' TYPE_IDENTIFIER + { $$ = type_from_object($1, $4); }; + */ + +DefinedType : TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + $$ = new_type(TType); + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + } + | ParameterizedType + { $$ = $1; } + ; + + /* + * Should be ActualParameterList, but we'll do just one for now + * as that's enough for PKIX. + */ +ParameterizedType + : Identifier '{' ActualParameter '}' /* XXX ActualParameterList */ + { + Symbol *s, *ps; + char *pname = NULL; + + if ($3 == NULL) { + lex_error_message("Unknown ActualParameter object set parametrizing %s\n", $1); + exit(1); + } + + /* Lookup the type from a ParameterizedTypeAssignment */ + if (asprintf(&pname, "%s{%s:x}", $1, + $3->iosclass->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + ps = addsym(pname); + if (ps->stype != Sparamtype) + lex_error_message ("%s is not a parameterized type\n", $1); + + s = addsym($1); + $$ = ps->type; /* XXX copy, probably */ + if (!ps->type) + errx(1, "Wrong class (%s) parameter for parameterized " + "type %s", $3->iosclass->symbol->name, $1); + s->stype = Stype; + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + $$->actual_parameter = $3; + if ($$->type == TTag) + $$->subtype->actual_parameter = $3; + } + +/* + * Per X.683 $1 for ActualParameter should be any of: a Type, a Value, a + * ValueSet, a DefinedObjectClass, an Object, or an ObjectSet. For PKIX we + * need nothing more than an ObjectSet here. + * + * Also, we can't lexically or syntactically tell the difference between all + * these things, though fortunately we can for ObjectSet. + */ +ActualParameter : DefinedObjectSet + { $$ = $1; }; + +UsefulType : kw_GeneralizedTime + { + $$ = new_tag(ASN1_C_UNIV, UT_GeneralizedTime, + TE_EXPLICIT, new_type(TGeneralizedTime)); + } + | kw_UTCTime + { + $$ = new_tag(ASN1_C_UNIV, UT_UTCTime, + TE_EXPLICIT, new_type(TUTCTime)); + } + ; + +ConstrainedType : UnconstrainedType Constraint + { + $$ = $1; + if ($2->ctype == CT_RANGE) { + if ($1->type != TTag || $1->subtype->type != TInteger) + lex_error_message("RANGE constraints apply only to INTEGER types"); + $$->subtype->range = $2->u.range; + free($2); + } else { + $$->constraint = $2; + } + /* if (Constraint.type == contentConstraint) { + assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too + if (Constraint.u.constraint.type) { + assert((Constraint.u.constraint.type.length % 8) == 0); + } + } + if (Constraint.u.constraint.encoding) { + type == der-oid|ber-oid + } + */ + } + ; + + +Constraint : '(' ConstraintSpec ')' + { + $$ = $2; + } + ; + +ConstraintSpec : SubtypeConstraint | GeneralConstraint + ; + +SubtypeConstraint: range + { + $$ = new_constraint_spec(CT_RANGE); + $$->u.range = $1; + } + +GeneralConstraint: ContentsConstraint + | UserDefinedConstraint + | TableConstraint + ; + +ContentsConstraint: kw_CONTAINING Type + { + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = $2; + $$->u.content.encoding = NULL; + } + | kw_ENCODED kw_BY Value + { + if ($3->type != objectidentifiervalue) + lex_error_message("Non-OID used in ENCODED BY constraint"); + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = NULL; + $$->u.content.encoding = $3; + } + | kw_CONTAINING Type kw_ENCODED kw_BY Value + { + if ($5->type != objectidentifiervalue) + lex_error_message("Non-OID used in ENCODED BY constraint"); + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = $2; + $$->u.content.encoding = $5; + } + ; + +UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}' + { + $$ = new_constraint_spec(CT_USER); + } + ; + +TableConstraint : SimpleTableConstraint + { $$ = $1; } + | ComponentRelationConstraint + { $$ = $1; }; + +SimpleTableConstraint + : '{' TYPE_IDENTIFIER '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = 0; + }; + +/* + * In X.682, ComponentRelationConstraint is a fantastically more complicated + * production. The stuff in the second set of braces is a list of AtNotation, + * and AtNotation is '@' followed by some number of '.'s, followed by a + * ComponentIdList, which is a non-empty set of identifiers separated by '.'s. + * The number of '.'s is a "level" used to identify a SET, SEQUENCE, or CHOICE + * where the path of member identifiers is rooted that ultimately identifies + * the field providing the constraint. + * + * So in + * + * extnValue OCTET STRING + * (CONTAINING + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * ^^^^^^^^^^^^^^^^^^^ + * ObjectClassFieldType + * meaning the open type field + * &ExtnType of EXTENSION + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * GeneralConstraint + * ^^^^^^^^^^^^^^^^^^^^^^^ + * ComponentRelationConstraint + * ^^^^^^^^^^^^^^ + * DefinedObjectSet + * ^^^^^^^^ + * '{' AtNotation ',' + '}' + * + * we have EXTENSION.&ExtnType is the ObjectClassFieldType, and + * ({ExtensionSet}{@extnID}) is the ComponentRelationConstraint on the + * extnValue member, where {ExtensionSet} is the DummyReference from the formal + * parameter of the enclosing parameterized type, and {@extnID} is the + * AtNotation list identifying the field of the class/objects-in-the-object-set + * that will be identifying the type of the extnValue field. + * + * We need just the one AtNotation component. + */ +ComponentRelationConstraint + : '{' TYPE_IDENTIFIER '}' '{' '@' Identifier '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = $6; + }; + +TaggedType : Tag tagenv Type + { + $$ = new_type(TTag); + $$->tag = $1; + $$->tag.tagenv = $2; + if (template_flag) { + $$->subtype = $3; + } else if ($2 == TE_IMPLICIT) { + Type *t = $3; + + /* + * FIXME We shouldn't do this... The logic for + * dealing with IMPLICIT tags belongs elsewhere. + */ + while (t->type == TType) { + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + break; + } + /* + * IMPLICIT tags of CHOICE types are EXPLICIT + * instead. + */ + if (t->type == TChoice) { + $$->implicit_choice = 1; + $$->tag.tagenv = TE_EXPLICIT; + } + if($3->type == TTag && $2 == TE_IMPLICIT) { + $$->subtype = $3->subtype; + free($3); + } else { + $$->subtype = $3; + } + } else { + $$->subtype = $3; + } + } + ; + +Tag : '[' Class NUMBER ']' + { + $$.tagclass = $2; + $$.tagvalue = $3; + $$.tagenv = default_tag_env; + } + ; + +Class : /* */ + { + $$ = ASN1_C_CONTEXT; + } + | kw_UNIVERSAL + { + $$ = ASN1_C_UNIV; + } + | kw_APPLICATION + { + $$ = ASN1_C_APPL; + } + | kw_PRIVATE + { + $$ = ASN1_C_PRIVATE; + } + ; + +tagenv : /* */ + { + $$ = default_tag_env; + } + | kw_EXPLICIT + { + $$ = default_tag_env; + } + | kw_IMPLICIT + { + $$ = TE_IMPLICIT; + } + ; + + +ValueAssignment : VALUE_IDENTIFIER Type EEQUAL Value + { + Symbol *s; + s = addsym ($1); + + s->stype = SValue; + s->value = $4; + generate_constant (s); + /* + * Save this value's name so we can know some name for + * this value wherever _a_ name may be needed for it. + * + * This is useful for OIDs used as type IDs in objects + * sets of classes with open types. We'll generate + * enum labels from those OIDs' names. + */ + s->value->s = s; + } + ; + +CharacterStringType: RestrictedCharactedStringType + ; + +RestrictedCharactedStringType: kw_GeneralString + { + $$ = new_tag(ASN1_C_UNIV, UT_GeneralString, + TE_EXPLICIT, new_type(TGeneralString)); + } + | kw_TeletexString + { + $$ = new_tag(ASN1_C_UNIV, UT_TeletexString, + TE_EXPLICIT, new_type(TTeletexString)); + } + | kw_UTF8String + { + $$ = new_tag(ASN1_C_UNIV, UT_UTF8String, + TE_EXPLICIT, new_type(TUTF8String)); + } + | kw_PrintableString + { + $$ = new_tag(ASN1_C_UNIV, UT_PrintableString, + TE_EXPLICIT, new_type(TPrintableString)); + } + | kw_VisibleString + { + $$ = new_tag(ASN1_C_UNIV, UT_VisibleString, + TE_EXPLICIT, new_type(TVisibleString)); + } + | kw_IA5String + { + $$ = new_tag(ASN1_C_UNIV, UT_IA5String, + TE_EXPLICIT, new_type(TIA5String)); + } + | kw_BMPString + { + $$ = new_tag(ASN1_C_UNIV, UT_BMPString, + TE_EXPLICIT, new_type(TBMPString)); + } + | kw_UniversalString + { + $$ = new_tag(ASN1_C_UNIV, UT_UniversalString, + TE_EXPLICIT, new_type(TUniversalString)); + } + + ; + +ComponentTypeList: ComponentType + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | ComponentTypeList ',' ComponentType + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + | ComponentTypeList ',' ELLIPSIS + { + struct member *m = ecalloc(1, sizeof(*m)); + m->name = estrdup("..."); + m->gen_name = estrdup("asn1_ellipsis"); + m->ellipsis = 1; + HEIM_TAILQ_INSERT_TAIL($1, m, members); + $$ = $1; + } + ; + +NamedType : Identifier Type + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->type = $2; + $$->ellipsis = 0; + } + ; + +ComponentType : NamedType + { + $$ = $1; + $$->optional = 0; + $$->defval = NULL; + } + | NamedType kw_OPTIONAL + { + $$ = $1; + $$->optional = 1; + $$->defval = NULL; + } + | NamedType kw_DEFAULT Value + { + $$ = $1; + $$->optional = 0; + $$->defval = $3; + } + ; + +NamedBitList : NamedBit + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedBitList ',' NamedBit + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + ; + +NamedBit : Identifier '(' NUMBER ')' + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + ; + +objid_opt : objid + | /* empty */ { $$ = NULL; } + ; + +objid : '{' objid_list '}' + { + $$ = $2; + } + ; + +objid_list : /* empty */ + { + $$ = NULL; + } + | objid_element objid_list + { + if ($2) { + $$ = $2; + add_oid_to_tail($2, $1); + } else { + $$ = $1; + } + } + ; + +objid_element : Identifier '(' NUMBER ')' + { + $$ = new_objid($1, $3); + } + | Identifier + { + Symbol *s = addsym($1); + if(s->stype != SValue || + s->value->type != objectidentifiervalue) { + lex_error_message("%s is not an object identifier\n", + s->name); + exit(1); + } + $$ = s->value->u.objectidentifiervalue; + } + | NUMBER + { + $$ = new_objid(NULL, $1); + } + ; + +Value : BuiltinValue + | ReferencedValue + ; + +ValueExNull : BuiltinValueExNull + | ReferencedValue + ; + +BuiltinValue : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + | NullValue + ; + +BuiltinValueExNull + : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + ; + +ReferencedValue : DefinedValue + ; + +DefinedValue : Valuereference + ; + +Valuereference : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != SValue) + lex_error_message ("%s is not a value\n", + s->name); + else + $$ = s->value; + } + ; + +CharacterStringValue: STRING + { + $$ = emalloc(sizeof(*$$)); + $$->type = stringvalue; + $$->u.stringvalue = $1; + } + ; + +BooleanValue : kw_TRUE + { + $$ = emalloc(sizeof(*$$)); + $$->type = booleanvalue; + $$->u.booleanvalue = 1; + } + | kw_FALSE + { + $$ = emalloc(sizeof(*$$)); + $$->type = booleanvalue; + $$->u.booleanvalue = 0; + } + ; + +IntegerValue : SignedNumber + { + $$ = emalloc(sizeof(*$$)); + $$->type = integervalue; + $$->u.integervalue = $1; + } + ; + +SignedNumber : NUMBER + ; + +NullValue : kw_NULL + { + } + ; + +ObjectIdentifierValue: objid + { + $$ = emalloc(sizeof(*$$)); + $$->type = objectidentifiervalue; + $$->u.objectidentifiervalue = $1; + } + ; + +%% + +void +yyerror (const char *s) +{ + lex_error_message ("%s\n", s); +} + +static Type * +new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype) +{ + Type *t; + if(oldtype->type == TTag && oldtype->tag.tagenv == TE_IMPLICIT) { + t = oldtype; + oldtype = oldtype->subtype; /* XXX */ + } else + t = new_type (TTag); + + t->tag.tagclass = tagclass; + t->tag.tagvalue = tagvalue; + t->tag.tagenv = tagenv; + t->subtype = oldtype; + return t; +} + +static struct objid * +new_objid(const char *label, int value) +{ + struct objid *s; + s = emalloc(sizeof(*s)); + s->label = label; + s->value = value; + s->next = NULL; + return s; +} + +static void +add_oid_to_tail(struct objid *head, struct objid *tail) +{ + struct objid *o; + o = head; + while (o->next) + o = o->next; + o->next = tail; +} + +static Type * +new_type (Typetype tt) +{ + Type *t = ecalloc(1, sizeof(*t)); + t->type = tt; + t->id = idcounter++; + return t; +} + +static struct constraint_spec * +new_constraint_spec(enum ctype ct) +{ + struct constraint_spec *c = ecalloc(1, sizeof(*c)); + c->ctype = ct; + return c; +} + +static void fix_labels2(Type *t, const char *prefix); +static void fix_labels1(struct memhead *members, const char *prefix) +{ + Member *m; + + if(members == NULL) + return; + HEIM_TAILQ_FOREACH(m, members, members) { + if (asprintf(&m->label, "%s_%s", prefix, m->gen_name) < 0) + errx(1, "malloc"); + if (m->label == NULL) + errx(1, "malloc"); + if(m->type != NULL) + fix_labels2(m->type, m->label); + } +} + +static void fix_labels2(Type *t, const char *prefix) +{ + for(; t; t = t->subtype) + fix_labels1(t->members, prefix); +} + +static void +fix_labels(Symbol *s) +{ + char *p = NULL; + if (asprintf(&p, "choice_%s", s->gen_name) < 0 || p == NULL) + errx(1, "malloc"); + if (s->type) + fix_labels2(s->type, p); + free(p); +} + +static struct objectshead * +add_object_set_spec(struct objectshead *lst, IOSObject *o) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, o, objects); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, o, objects); + } + return lst; +} + +static struct objfieldhead * +add_field_setting(struct objfieldhead *lst, ObjectField *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, objfields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, objfields); + } + return lst; +} + +static struct fieldhead * +add_field_spec(struct fieldhead *lst, Field *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, fields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, fields); + } + return lst; +} + +static ObjectField * +new_field_setting(char *n, Type *t, struct value *v) +{ + ObjectField *of; + + of = ecalloc(1, sizeof(*of)); + of->value = v; + of->type = t; + of->name = n; + return of; +} + +static Field * +new_type_field(char *n, int optional, Type *t) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = 0; + f->defval = 0; + f->type = t; + f->name = n; + return f; +} + +static Field * +new_fixed_type_value_field(char *n, Type *t, int unique, int optional, struct value *defval) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = unique; + f->defval = defval; + f->type = t; + f->name = n; + return f; +} + +static Type * +parametrize_type(Type *t, IOSClass *c) +{ + Type *type; + + type = new_type(TType); + *type = *t; /* XXX Copy, or use subtype; this only works as long as we don't cleanup! */ + type->formal_parameter = c; + return type; +} + +static Type * +type_from_class_field(IOSClass *c, const char *n) +{ + Field *f; + Type *t; + + HEIM_TAILQ_FOREACH(f, c->fields, fields) { + if (strcmp(f->name, n) == 0) { + t = new_type(TType); + if (f->type) { + *t = *f->type; + } else { + Symbol *s = addsym("HEIM_ANY"); + if(s->stype != Stype && s->stype != SUndefined) + errx(1, "Do not define HEIM_ANY, only import it\n"); + s->stype = Stype; + t->symbol = s; + } + t->typeref.iosclass = c; + t->typeref.field = f; + return t; + } + } + return NULL; +} + +static void +validate_object_set(IOSObjectSet *os) +{ + IOSObject **objects; + ObjectField *of; + IOSObject *o; + Field *cf; + size_t nobjs, i; + + /* Check unique fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (!cf->unique) + continue; + if (!cf->type) + errx(1, "Type fields of classes can't be UNIQUE (%s)", + os->iosclass->symbol->name); + sort_object_set(os, cf, &objects, &nobjs); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(cf->name, of->name) != 0) + continue; + if (!of->value) + errx(1, "Value not specified for required UNIQUE field %s of object %s", + cf->name, objects[i]->symbol->name); + break; + } + if (i == 0) + continue; + if (object_cmp(&objects[i - 1], &objects[i]) == 0) + errx(1, "Duplicate values of UNIQUE field %s of objects %s and %s", + cf->name, objects[i - 1]->symbol->name, + objects[i]->symbol->name); + } + free(objects); + } + + /* Check required fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (cf->optional || cf->defval || !cf->type) + continue; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + int specified = 0; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, cf->name) != 0) + continue; + if (of->value) + specified = 1; + break; + } + if (!specified) + errx(1, "Value not specified for required non-UNIQUE field %s of object %s", + cf->name, o->symbol->name); + } + } +} diff --git a/third_party/heimdal/lib/asn1/canthandle.asn1 b/third_party/heimdal/lib/asn1/canthandle.asn1 new file mode 100644 index 0000000..4378428 --- /dev/null +++ b/third_party/heimdal/lib/asn1/canthandle.asn1 @@ -0,0 +1,15 @@ +-- $Id$ -- + +CANTHANDLE DEFINITIONS ::= BEGIN + +-- Currently the compiler handles SET { ... } types, but does NOT sort +-- their members as should be done in the case of conforming DER encoders. +-- The workaround is to sort the members of such types manually in their +-- definitions. See X.690, section 10.3, and X.680, section 8.6 for details. + +-- Can't handle primitives in SET OF, causing the compiler to crash +-- Workaround is to define a type that is only an integer and use that + +Baz ::= SET OF INTEGER + +END diff --git a/third_party/heimdal/lib/asn1/check-ber.c b/third_party/heimdal/lib/asn1/check-ber.c new file mode 100644 index 0000000..57450f4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-ber.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + + +RCSID("$Id$"); + +static const unsigned char *contentdata = (unsigned char *) + "\x30\x80\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0\x80\x30" + "\x80\x02\x01\x03\x31\x0b\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05" + "\x00\x30\x80\x06\x07\x2b\x06\x01\x05\x02\x03\x01\xa0\x80\x24\x80" + "\x04\x40\x30\x3e\xa0\x3c\x30\x3a\xa0\x05\x02\x03\x0e\x03\x86\xa1" + "\x11\x18\x0f\x32\x30\x30\x38\x31\x32\x31\x33\x31\x39\x34\x35\x34" + "\x32\x5a\xa2\x06\x02\x04\xba\xbd\x97\x8a\xa3\x16\x04\x14\x41\x28" + "\x79\xa8\xd0\xe4\xb1\x0f\xb1\xfc\xa6\x0b\x4d\x2b\x85\x3d\xd9\x17" + "\x3f\xdc\x00\x00\x00\x00\x00\x00\xa0\x82\x0b\x6c\x30\x82\x05\x57" + "\x30\x82\x04\x3f\xa0\x03\x02\x01\x02\x02\x03\x47\x3d\x05\x30\x0d" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x81\x86" + "\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1d\x30" + "\x1b\x06\x03\x55\x04\x0a\x13\x14\x41\x70\x70\x6c\x65\x20\x43\x6f" + "\x6d\x70\x75\x74\x65\x72\x2c\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b" + "\x06\x03\x55\x04\x0b\x13\x24\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d" + "\x70\x75\x74\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74" + "\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x31\x29\x30\x27\x06" + "\x03\x55\x04\x03\x13\x20\x41\x70\x70\x6c\x65\x20\x2e\x4d\x61\x63" + "\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74" + "\x68\x6f\x72\x69\x74\x79\x30\x1e\x17\x0d\x30\x38\x31\x30\x30\x31" + "\x30\x38\x30\x36\x33\x33\x5a\x17\x0d\x30\x39\x31\x30\x30\x32\x30" + "\x38\x30\x36\x33\x33\x5a\x30\x71\x31\x0b\x30\x09\x06\x03\x55\x04" + "\x06\x13\x02\x55\x53\x31\x13\x30\x11\x06\x03\x55\x04\x0a\x13\x0a" + "\x41\x70\x70\x6c\x65\x20\x49\x6e\x63\x2e\x31\x0f\x30\x0d\x06\x03" + "\x55\x04\x0b\x13\x06\x6d\x65\x2e\x63\x6f\x6d\x31\x15\x30\x13\x06" + "\x03\x55\x04\x03\x13\x0c\x62\x69\x74\x63\x6f\x6c\x6c\x65\x63\x74" + "\x6f\x72\x31\x25\x30\x23\x06\x03\x55\x04\x0d\x13\x1c\x4d\x6f\x62" + "\x69\x6c\x65\x4d\x65\x20\x53\x68\x61\x72\x69\x6e\x67\x20\x43\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x30\x81\xa3\x30\x0d\x06\x09" + "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x91\x00\x30" + "\x81\x8d\x02\x81\x81\x00\xe1\x15\xd8\xfa\xe9\xc2\xb7\x2e\xf0\xd9" + "\xbe\xdb\x0c\xd8\xcb\xf3\x88\x13\xd7\x22\xf8\x4d\xf4\xb6\x31\x17" + "\xe5\x92\x42\xef\x15\xe4\x5f\x12\x58\x3d\x8d\x0b\xa4\x03\x76\xe0" + "\xd0\xf2\x46\xb4\x4b\x14\x78\x23\x1c\x38\xb0\x99\xff\x36\x6f\x0e" + "\x26\xdf\x76\xd0\x01\x03\x7a\xd9\xcd\x1c\x92\xa6\x10\x5e\xed\x8a" + "\xb0\xfe\x9b\x8c\x96\xb0\x91\x9f\x97\xd0\xf4\x9c\x81\x8e\xbf\xb5" + "\x41\x24\x81\xb0\x1b\xb3\x8c\xd3\x92\x5c\xfd\x2b\x04\x61\xc3\x21" + "\x6c\xa9\xe4\xa0\xfe\xa5\x1c\x76\xfd\xda\x3b\x81\x7c\xa0\x5c\x2c" + "\xf6\x8f\x6e\x74\x52\x35\x02\x07\x01\x00\x01\x00\x01\x00\x01\xa3" + "\x82\x02\x60\x30\x82\x02\x5c\x30\x0c\x06\x03\x55\x1d\x13\x01\x01" + "\xff\x04\x02\x30\x00\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04" + "\x04\x03\x02\x03\x88\x30\x28\x06\x03\x55\x1d\x25\x04\x21\x30\x1f" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x02\x06\x0a\x2a\x86\x48\x86" + "\xf7\x63\x64\x03\x02\x01\x06\x07\x2b\x06\x01\x05\x02\x03\x04\x30" + "\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x11\xb3\x15\xb5\xab\x31" + "\xbb\xa5\x48\xee\xd6\x33\xd2\x86\xc3\x0b\x2a\x4c\x5e\x94\x30\x1f" + "\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x7a\x7d\x90\xb1\x30" + "\x59\x08\x92\x91\xf9\x53\xb9\x71\x1d\x35\x33\x67\x34\x8b\xd5\x30" + "\x81\xa5\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x81\x98\x30" + "\x81\x95\x30\x27\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x01\x86\x1b" + "\x68\x74\x74\x70\x3a\x2f\x2f\x63\x65\x72\x74\x69\x6e\x66\x6f\x2e" + "\x6d\x65\x2e\x63\x6f\x6d\x2f\x6f\x63\x73\x70\x30\x44\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x30\x02\x86\x38\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x63\x61\x73\x69\x67\x6e\x65\x72\x73\x2e\x68\x74\x6d" + "\x6c\x30\x24\x06\x03\x55\x1d\x12\x86\x1d\x68\x74\x74\x70\x3a\x2f" + "\x2f\x63\x65\x72\x74\x69\x6e\x66\x6f\x2e\x6d\x65\x2e\x63\x6f\x6d" + "\x2f\x43\x41\x2e\x63\x65\x72\x30\x82\x01\x28\x06\x03\x55\x1d\x20" + "\x04\x82\x01\x1f\x30\x82\x01\x1b\x30\x82\x01\x17\x06\x09\x2a\x86" + "\x48\x86\xf7\x63\x64\x05\x02\x30\x82\x01\x08\x30\x40\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x02\x01\x16\x34\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x74\x65\x72\x6d\x73\x2e\x68\x74\x6d\x6c\x30\x81\xc3" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x02\x30\x81\xb6\x1a\x81\xb3" + "\x52\x65\x6c\x69\x61\x6e\x63\x65\x20\x6f\x6e\x20\x74\x68\x69\x73" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x62\x79\x20" + "\x61\x6e\x79\x20\x70\x61\x72\x74\x79\x20\x61\x73\x73\x75\x6d\x65" + "\x73\x20\x61\x63\x63\x65\x70\x74\x61\x6e\x63\x65\x20\x6f\x66\x20" + "\x74\x68\x65\x20\x74\x68\x65\x6e\x20\x61\x70\x70\x6c\x69\x63\x61" + "\x62\x6c\x65\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x20\x74\x65\x72" + "\x6d\x73\x20\x61\x6e\x64\x20\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e" + "\x73\x20\x6f\x66\x20\x75\x73\x65\x2c\x20\x63\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x70\x6f\x6c\x69\x63\x79\x20\x61\x6e\x64" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\x70" + "\x72\x61\x63\x74\x69\x63\x65\x20\x73\x74\x61\x74\x65\x6d\x65\x6e" + "\x74\x73\x2e\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05" + "\x05\x00\x03\x82\x01\x01\x00\x39\xb1\x81\xbe\x55\xf1\xb1\xe4\x16" + "\x5d\x7c\x5b\x6a\xe8\xcf\xee\xaa\x87\x91\x81\xf2\x57\x0d\x32\x6c" + "\xc6\x47\xdc\x71\x70\xfa\x7c\x47\x84\x7f\xa5\x69\x1b\x4c\x52\x98" + "\x7f\xc8\x1f\x62\x06\x83\xae\x0a\xef\x55\x29\x35\xb3\xa0\x04\x88" + "\xa6\x45\x0a\xd0\xd7\x4e\x5c\x63\x3e\xe7\xb2\x28\x85\xd3\x01\x56" + "\x2b\x89\xb5\x60\x9a\xa5\x9d\x85\x0d\x76\x9e\xe1\x4a\x54\x8b\x6f" + "\xad\xc4\xc2\x43\x2f\x18\xaa\x18\x1a\x64\x2f\x2e\xe3\xc9\xb8\xa8" + "\xdd\xba\x53\xc4\x18\xcf\x4e\x30\xbf\x06\xa7\xdb\x12\x34\x24\x5c" + "\x71\x60\x2a\xd2\x93\xef\x54\x83\x4e\x5d\xc5\x5f\x00\x8d\x02\x85" + "\xe5\x17\x68\x46\xfa\xd4\x45\x96\x71\xf7\x93\x58\x4d\x83\x6b\x01" + "\xcb\xdb\x7d\x61\x67\x69\xbe\xf1\x4c\x4b\xe2\x3e\xf6\x4e\x62\x77" + "\x26\x86\xc4\x3b\x96\x38\x27\x0b\x02\x0d\x07\xc9\x95\x53\x6d\x03" + "\xff\x61\xfb\x67\x7f\x8a\x2e\x2f\xc5\xff\x5a\xf9\x53\xd8\xb3\xae" + "\xf1\x05\x27\x92\x79\x22\xd5\x55\x6e\xd6\xbf\xdb\x9d\xad\xbf\xbf" + "\x7d\x15\xd8\x1c\x3d\x63\x86\xf1\xf1\x78\xfe\xfb\x62\x06\x8c\xf4" + "\x0f\xa8\x91\xa8\x7c\xef\x51\x96\x09\x52\x68\xec\x09\xdd\xb9\x9a" + "\x62\x49\xac\xbe\x20\x20\x9b\x30\x82\x06\x0d\x30\x82\x04\xf5\xa0" + "\x03\x02\x01\x02\x02\x01\x0f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7" + "\x0d\x01\x01\x05\x05\x00\x30\x81\x86\x31\x0b\x30\x09\x06\x03\x55" + "\x04\x06\x13\x02\x55\x53\x31\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13" + "\x14\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c" + "\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24" + "\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x20\x43" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f" + "\x72\x69\x74\x79\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x41" + "\x70\x70\x6c\x65\x20\x52\x6f\x6f\x74\x20\x43\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x30" + "\x1e\x17\x0d\x30\x35\x30\x32\x31\x30\x32\x30\x33\x38\x32\x37\x5a" + "\x17\x0d\x31\x31\x31\x31\x31\x30\x32\x30\x33\x38\x32\x37\x5a\x30" + "\x81\x86\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31" + "\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13\x14\x41\x70\x70\x6c\x65\x20" + "\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c\x20\x49\x6e\x63\x2e\x31\x2d" + "\x30\x2b\x06\x03\x55\x04\x0b\x13\x24\x41\x70\x70\x6c\x65\x20\x43" + "\x6f\x6d\x70\x75\x74\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63" + "\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x31\x29\x30" + "\x27\x06\x03\x55\x04\x03\x13\x20\x41\x70\x70\x6c\x65\x20\x2e\x4d" + "\x61\x63\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41" + "\x75\x74\x68\x6f\x72\x69\x74\x79\x30\x82\x01\x22\x30\x0d\x06\x09" + "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00" + "\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xbb\x73\x84\xb0\x48\x36\x64" + "\xf8\x1f\xa2\x57\x89\xb6\xe2\x71\x3c\x36\x5e\x56\xeb\xdb\x96\x16" + "\x23\x1c\x81\xd0\x14\x2d\xd6\xf0\x4b\x22\x9b\x3f\xb7\x7a\x2c\xa2" + "\xf0\x69\x48\x33\xb7\x9e\xef\x68\xe7\xbc\x30\x07\x73\xbc\x61\xb0" + "\x01\x51\xef\x44\xdf\xdb\x45\x04\x96\x80\x2c\x7b\xe8\x93\x1f\x89" + "\x92\x60\x21\xcd\x34\x55\x00\x66\x31\x03\x01\x01\x44\x25\x94\x0b" + "\x42\x78\xca\x5a\x05\x1e\x77\x73\x24\x75\x6a\xc8\x45\x9c\xef\x2b" + "\x2a\x51\x29\x8f\xeb\x7e\x62\xd7\xfa\xcd\x32\xfd\x31\xe8\xcd\xde" + "\xab\x0d\xb5\xb4\x56\xc2\x68\x51\x09\x0c\x29\xe5\x38\x7b\x50\x68" + "\xbe\x00\x87\x8c\x56\xef\xd3\x1b\xa3\xc9\x6e\xa6\x74\x43\xeb\x83" + "\xd4\x63\x5f\x13\x79\x1e\xf8\x85\xbf\xbf\x73\x69\x36\xc5\x56\x12" + "\x6c\xe4\xee\xaf\x86\xab\x65\xb6\x04\xf0\x5a\x63\x2d\xa3\x31\x6c" + "\xe8\x48\x10\x65\xc0\x74\x45\x0d\x97\x58\x90\x3d\x91\x83\x14\xf2" + "\x6f\xba\xad\x2f\x6c\x41\x6e\x3c\xb7\x8f\x72\x4a\x1d\xf0\xb7\x1a" + "\xc0\xf0\x72\x0b\x3d\x9d\x7a\x8b\x4d\xb0\x33\xb7\x5f\x83\xef\x08" + "\x5b\x5f\x35\x35\x3b\x52\xdf\x30\xb1\x00\x6c\xa6\x3a\x86\xc4\xf4" + "\x7c\xe1\x79\x74\x5f\x0b\x35\xb8\xe1\x02\x03\x01\x00\x01\xa3\x82" + "\x02\x82\x30\x82\x02\x7e\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff" + "\x04\x04\x03\x02\x01\x86\x30\x0f\x06\x03\x55\x1d\x13\x01\x01\xff" + "\x04\x05\x30\x03\x01\x01\xff\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" + "\x04\x14\x7a\x7d\x90\xb1\x30\x59\x08\x92\x91\xf9\x53\xb9\x71\x1d" + "\x35\x33\x67\x34\x8b\xd5\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30" + "\x16\x80\x14\x2b\xd0\x69\x47\x94\x76\x09\xfe\xf4\x6b\x8d\x2e\x40" + "\xa6\xf7\x47\x4d\x7f\x08\x5e\x30\x82\x01\x28\x06\x03\x55\x1d\x20" + "\x04\x82\x01\x1f\x30\x82\x01\x1b\x30\x82\x01\x17\x06\x09\x2a\x86" + "\x48\x86\xf7\x63\x64\x05\x02\x30\x82\x01\x08\x30\x40\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x02\x01\x16\x34\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x74\x65\x72\x6d\x73\x2e\x68\x74\x6d\x6c\x30\x81\xc3" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x02\x30\x81\xb6\x1a\x81\xb3" + "\x52\x65\x6c\x69\x61\x6e\x63\x65\x20\x6f\x6e\x20\x74\x68\x69\x73" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x62\x79\x20" + "\x61\x6e\x79\x20\x70\x61\x72\x74\x79\x20\x61\x73\x73\x75\x6d\x65" + "\x73\x20\x61\x63\x63\x65\x70\x74\x61\x6e\x63\x65\x20\x6f\x66\x20" + "\x74\x68\x65\x20\x74\x68\x65\x6e\x20\x61\x70\x70\x6c\x69\x63\x61" + "\x62\x6c\x65\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x20\x74\x65\x72" + "\x6d\x73\x20\x61\x6e\x64\x20\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e" + "\x73\x20\x6f\x66\x20\x75\x73\x65\x2c\x20\x63\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x70\x6f\x6c\x69\x63\x79\x20\x61\x6e\x64" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\x70" + "\x72\x61\x63\x74\x69\x63\x65\x20\x73\x74\x61\x74\x65\x6d\x65\x6e" + "\x74\x73\x2e\x30\x43\x06\x03\x55\x1d\x1f\x04\x3c\x30\x3a\x30\x38" + "\xa0\x36\xa0\x34\x86\x32\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77" + "\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65\x72\x74\x69" + "\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69\x74\x79\x2f" + "\x72\x6f\x6f\x74\x2e\x63\x72\x6c\x30\x81\xa9\x06\x08\x2b\x06\x01" + "\x05\x05\x07\x01\x01\x04\x81\x9c\x30\x81\x99\x30\x44\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x30\x02\x86\x38\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x63\x61\x73\x69\x67\x6e\x65\x72\x73\x2e\x68\x74\x6d" + "\x6c\x30\x51\x06\x03\x55\x1d\x12\x86\x4a\x68\x74\x74\x70\x3a\x2f" + "\x2f\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72" + "\x69\x74\x79\x2f\x41\x70\x70\x6c\x65\x43\x6f\x6d\x70\x75\x74\x65" + "\x72\x52\x6f\x6f\x74\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65" + "\x2e\x63\x65\x72\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01" + "\x05\x05\x00\x03\x82\x01\x01\x00\x16\x06\xe5\x56\x65\x44\x7d\xd0" + "\xaa\x99\x29\xe5\xc6\x97\x0b\x02\x43\x25\x88\x8c\x42\xba\xfb\xd6" + "\x5b\xb7\x20\x10\x69\x04\x4e\x91\x81\x08\xec\xf5\x23\x1f\xd2\x6d" + "\x3f\x35\xae\xdb\xff\xb8\xc9\x2b\x4b\x28\x73\xc4\x26\x03\xe1\x92" + "\x5e\xb2\x84\x0d\xa7\x13\xc6\x34\x54\xf1\x49\x1f\xa9\x47\x88\xb1" + "\x40\x9b\xd3\x61\x93\x5b\xcf\xc7\x53\xe7\x9f\x54\x7b\x30\xc6\xb8" + "\x3a\x89\x6f\x06\x09\x45\xa1\x94\x98\xbe\x8b\xea\x25\x7d\x91\x89" + "\xf9\x27\x62\xb9\x5f\x2d\xea\xa9\xe7\x96\x5c\xbe\xe5\x84\x6d\xe8" + "\x50\x27\xb4\xb1\xea\x9f\xf7\x92\x0d\x54\x86\xf0\x37\x31\x47\x0d" + "\x54\xde\x91\xe8\x78\xe8\x61\x27\x7c\xc3\xea\xd0\xfc\x21\xa1\x08" + "\xc8\xe5\x01\x0e\x15\xf5\x61\x60\xce\xff\xbd\x44\xd6\x8a\x1b\x67" + "\xf8\x1f\x82\xe2\xa6\xb3\xfc\x3a\xc7\x30\xae\x93\x89\x29\x2e\x81" + "\x43\x0c\x9b\xd5\x18\xa6\x74\x66\x7d\x1c\x79\xe6\x22\xef\xba\xf8" + "\x23\xb3\xd3\x50\x76\x20\xde\x7a\x93\x91\x40\xcd\x16\xad\x82\x6a" + "\xe6\xe7\x25\xf5\xb3\xbb\x36\x61\x38\x8f\xaf\x36\x5f\x4b\xae\xc1" + "\xc6\x89\x99\xb1\xb1\xd9\xf1\xa3\x51\x50\xa1\x00\x3d\xdd\x16\x89" + "\xcf\x35\x05\x62\xa0\x8b\x48\x0a\x31\x82\x01\x35\x30\x82\x01\x31" + "\x02\x01\x01\x30\x81\x8e\x30\x81\x86\x31\x0b\x30\x09\x06\x03\x55" + "\x04\x06\x13\x02\x55\x53\x31\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13" + "\x14\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c" + "\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24" + "\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x20\x43" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f" + "\x72\x69\x74\x79\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x41" + "\x70\x70\x6c\x65\x20\x2e\x4d\x61\x63\x20\x43\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x02" + "\x03\x47\x3d\x05\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x30" + "\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x04\x81" + "\x80\x6d\xba\xa5\x44\x89\x98\x2d\x5e\xc4\xf6\xc0\x1e\x36\x70\x63" + "\x43\xf6\x61\x3c\x0b\x43\x32\x50\x54\x95\x1e\x51\x41\x17\xd2\x7f" + "\x47\x00\x21\x92\x61\xbf\x42\x63\xa4\xc8\x3a\x7f\x8d\x36\xea\xf1" + "\x2d\x9f\x0c\x30\xbc\xe1\x5e\x16\xea\xcc\x01\xdf\xbd\x6b\xc8\xc3" + "\xad\x12\x0e\x6a\x4d\xd5\xad\x15\x41\xcd\xde\xb9\xf9\xf5\xf2\xdc" + "\x65\xaf\x61\x28\x68\x40\x52\x59\xf8\xb8\xa6\xec\xce\xed\x5e\x16" + "\x7b\xbd\x72\x5e\x6a\x6e\x8b\x29\xb2\x97\x22\xe9\x99\xa3\xd6\xa9" + "\x0e\xb3\x5e\xd3\x18\x24\x06\x20\x78\xc8\xa7\xa8\xe7\x76\x3a\x8a" + "\x19\x00\x00\x00\x00\x00\x00"; + +static size_t contentlen = 3367; + + +static int +test_ber(void) +{ + ContentInfo ci; + size_t size; + int ret; + + ret = decode_ContentInfo(contentdata, contentlen, &ci, &size); + if (ret) + return 1; + + free_ContentInfo(&ci); + return 0; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_ber(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-common.c b/third_party/heimdal/lib/asn1/check-common.c new file mode 100644 index 0000000..8a6b5da --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-common.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1999 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#include +#include +#include +#include + +#include "asn1-common.h" +#include "check-common.h" + +struct map_page { + void *start; + size_t size; + void *data_start; + size_t data_size; + enum map_type type; +}; + +/* #undef HAVE_MMAP */ + +void * +map_alloc(enum map_type type, const void *buf, + size_t size, struct map_page **map) +{ +#ifndef HAVE_MMAP + unsigned char *p; + size_t len = size + sizeof(long) * 2; + int i; + + *map = ecalloc(1, sizeof(**map)); + + p = emalloc(len); + (*map)->type = type; + (*map)->start = p; + (*map)->size = len; + (*map)->data_start = p + sizeof(long); + for (i = sizeof(long); i > 0; i--) + p[sizeof(long) - i] = 0xff - i; + for (i = sizeof(long); i > 0; i--) + p[len - i] = 0xff - i; +#else + unsigned char *p; + int flags, ret, fd; + size_t pagesize = getpagesize(); + + *map = ecalloc(1, sizeof(**map)); + + (*map)->type = type; + +#ifdef MAP_ANON + flags = MAP_ANON; + fd = -1; +#else + flags = 0; + fd = open ("/dev/zero", O_RDONLY); + if(fd < 0) + err (1, "open /dev/zero"); +#endif + flags |= MAP_PRIVATE; + + (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; + + p = (unsigned char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, + flags, fd, 0); + if (p == (unsigned char *)MAP_FAILED) + err (1, "mmap"); + + (*map)->start = p; + + ret = mprotect (p, pagesize, 0); + if (ret < 0) + err (1, "mprotect"); + + ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); + if (ret < 0) + err (1, "mprotect"); + + switch (type) { + case OVERRUN: + (*map)->data_start = p + (*map)->size - pagesize - size; + break; + case UNDERRUN: + (*map)->data_start = p + pagesize; + break; + default: + abort(); + } +#endif + (*map)->data_size = size; + if (buf) + memcpy((*map)->data_start, buf, size); + return (*map)->data_start; +} + +void +map_free(struct map_page *map, const char *test_name, const char *map_name) +{ +#ifndef HAVE_MMAP + unsigned char *p = map->start; + int i; + + for (i = sizeof(long); i > 0; i--) + if (p[sizeof(long) - i] != 0xff - i) + errx(1, "%s: %s underrun %d\n", test_name, map_name, i); + for (i = sizeof(long); i > 0; i--) + if (p[map->size - i] != 0xff - i) + errx(1, "%s: %s overrun %lu\n", test_name, map_name, + (unsigned long)map->size - i); + free(map->start); +#else + int ret; + + ret = munmap (map->start, map->size); + if (ret < 0) + err (1, "munmap"); +#endif + free(map); +} + +static void +print_bytes (unsigned const char *buf, size_t len) +{ + int i; + + for (i = 0; i < len; ++i) + printf ("%02x ", buf[i]); +} + +#ifndef MAP_FAILED +#define MAP_FAILED (-1) +#endif + +static char *current_test = ""; +static char *current_state = ""; + +static RETSIGTYPE +segv_handler(int sig) +{ + int fd; + char msg[] = "SIGSEGV i current test: "; + /* For compilers that insist we check write(2)'s result here */ + int e = 1; + + fd = open("/dev/stdout", O_WRONLY, 0600); + if (fd >= 0) { + + if (write(fd, msg, sizeof(msg)) == -1 || + write(fd, current_test, strlen(current_test)) == -1 || + write(fd, " ", 1) == -1 || + write(fd, current_state, strlen(current_state)) == -1 || + write(fd, "\n", 1) == -1) + e = 2; + (void) close(fd); + } + _exit(e); +} + +int +generic_test (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), + size_t (ASN1CALL *length)(void *), + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), + void (ASN1CALL *free_data)(void *), + int (*cmp)(void *a, void *b), + int (ASN1CALL *copy)(const void *from, void *to)) +{ + unsigned char *buf, *buf2; + int i; + int failures = 0; + void *data; + struct map_page *data_map, *buf_map, *buf2_map; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; +#endif + + for (i = 0; i < ntests; ++i) { + int ret; + size_t sz, consumed_sz, length_sz, buf_sz; + void *to = NULL; + + current_test = tests[i].name; + + current_state = "init"; + +#ifdef HAVE_SIGACTION + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_RESETHAND + sa.sa_flags |= SA_RESETHAND; +#endif + sa.sa_handler = segv_handler; + sigaction (SIGSEGV, &sa, &osa); +#endif + + data = map_alloc(OVERRUN, NULL, data_size, &data_map); + + buf_sz = tests[i].byte_len; + buf = map_alloc(UNDERRUN, NULL, buf_sz, &buf_map); + + current_state = "encode"; + ret = (*encode) (buf + buf_sz - 1, buf_sz, + tests[i].val, &sz); + if (ret != 0) { + printf ("encoding of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + if (sz != tests[i].byte_len) { + printf ("encoding of %s has wrong len (%lu != %lu)\n", + tests[i].name, + (unsigned long)sz, (unsigned long)tests[i].byte_len); + ++failures; + continue; + } + + current_state = "length"; + length_sz = (*length) (tests[i].val); + if (sz != length_sz) { + printf ("length for %s is bad (%lu != %lu)\n", + tests[i].name, (unsigned long)length_sz, (unsigned long)sz); + ++failures; + continue; + } + + current_state = "memcmp"; + if (memcmp (buf, tests[i].bytes, tests[i].byte_len) != 0) { + printf ("encoding of %s has bad bytes:\n" + "correct: ", tests[i].name); + print_bytes ((unsigned char *)tests[i].bytes, tests[i].byte_len); + printf ("\nactual: "); + print_bytes (buf, sz); + printf ("\n"); +#if 0 + rk_dumpdata("correct", tests[i].bytes, tests[i].byte_len); + rk_dumpdata("actual", buf, sz); + exit (1); +#endif + ++failures; + continue; + } + + buf2 = map_alloc(OVERRUN, buf, sz, &buf2_map); + + current_state = "decode"; + ret = (*decode) (buf2, sz, data, &consumed_sz); + if (ret != 0) { + printf ("decoding of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + if (sz != consumed_sz) { + printf ("different length decoding %s (%ld != %ld)\n", + tests[i].name, + (unsigned long)sz, (unsigned long)consumed_sz); + ++failures; + continue; + } + current_state = "cmp"; + if ((*cmp)(data, tests[i].val) != 0) { + printf ("%s: comparison failed\n", tests[i].name); + ++failures; + continue; + } + + current_state = "copy"; + if (copy) { + to = emalloc(data_size); + ret = (*copy)(data, to); + if (ret != 0) { + printf ("copy of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + + current_state = "cmp-copy"; + if ((*cmp)(data, to) != 0) { + printf ("%s: copy comparison failed\n", tests[i].name); + ++failures; + continue; + } + } + + current_state = "free"; + if (free_data) { + (*free_data)(data); + if (to) { + (*free_data)(to); + free(to); + } + } + + current_state = "free"; + map_free(buf_map, tests[i].name, "encode"); + map_free(buf2_map, tests[i].name, "decode"); + map_free(data_map, tests[i].name, "data"); + +#ifdef HAVE_SIGACTION + sigaction (SIGSEGV, &osa, NULL); +#endif + } + current_state = "done"; + return failures; +} + +/* + * check for failures + * + * a test size (byte_len) of -1 means that the test tries to trigger a + * integer overflow (and later a malloc of to little memory), just + * allocate some memory and hope that is enough for that test. + */ + +int +generic_decode_fail (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)) +{ + unsigned char *buf; + int i; + int failures = 0; + void *data; + struct map_page *data_map, *buf_map; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; +#endif + + for (i = 0; i < ntests; ++i) { + int ret; + size_t sz; + const void *bytes; + + current_test = tests[i].name; + + current_state = "init"; + +#ifdef HAVE_SIGACTION + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_RESETHAND + sa.sa_flags |= SA_RESETHAND; +#endif + sa.sa_handler = segv_handler; + sigaction (SIGSEGV, &sa, &osa); +#endif + + data = map_alloc(OVERRUN, NULL, data_size, &data_map); + + if (tests[i].byte_len < 0xffffff && tests[i].byte_len >= 0) { + sz = tests[i].byte_len; + bytes = tests[i].bytes; + } else { + sz = 4096; + bytes = NULL; + } + + buf = map_alloc(OVERRUN, bytes, sz, &buf_map); + + if (tests[i].byte_len == -1) + memset(buf, 0, sz); + + current_state = "decode"; + ret = (*decode) (buf, tests[i].byte_len, data, &sz); + if (ret == 0) { + printf ("sucessfully decoded %s\n", tests[i].name); + ++failures; + continue; + } + + current_state = "free"; + if (buf) + map_free(buf_map, tests[i].name, "encode"); + map_free(data_map, tests[i].name, "data"); + +#ifdef HAVE_SIGACTION + sigaction (SIGSEGV, &osa, NULL); +#endif + } + current_state = "done"; + return failures; +} diff --git a/third_party/heimdal/lib/asn1/check-common.h b/third_party/heimdal/lib/asn1/check-common.h new file mode 100644 index 0000000..6ea1f81 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-common.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define IF_OPT_COMPARE(ac,bc,e) \ + if (((ac)->e == NULL && (bc)->e != NULL) || (((ac)->e != NULL && (bc)->e == NULL))) return 1; \ + if ((ac)->e) +#define COMPARE_OPT_STRING(ac,bc,e) \ + do { if (strcmp(*(ac)->e, *(bc)->e) != 0) return 1; } while(0) +#define COMPARE_OPT_OCTET_STRING(ac,bc,e) \ + do { if ((ac)->e->length != (bc)->e->length || memcmp((ac)->e->data, (bc)->e->data, (ac)->e->length) != 0) return 1; } while(0) +#define COMPARE_STRING(ac,bc,e) \ + do { if (strcmp((ac)->e, (bc)->e) != 0) return 1; } while(0) +#define COMPARE_INTEGER(ac,bc,e) \ + do { if ((ac)->e != (bc)->e) return 1; } while(0) +#define COMPARE_OPT_INTEGER(ac,bc,e) \ + do { if (*(ac)->e != *(bc)->e) return 1; } while(0) +#define COMPARE_MEM(ac,bc,e,len) \ + do { if (memcmp((ac)->e, (bc)->e,len) != 0) return 1; } while(0) +#define COMPARE_OCTET_STRING(ac,bc,e) \ + do { if ((ac)->e.length != (bc)->e.length || memcmp((ac)->e.data, (bc)->e.data, (ac)->e.length) != 0) return 1; } while(0) + +struct test_case { + void *val; + ssize_t byte_len; + const char *bytes; + char *name; +}; + +typedef int (ASN1CALL *generic_encode)(unsigned char *, size_t, void *, size_t *); +typedef size_t (ASN1CALL *generic_length)(void *); +typedef int (ASN1CALL *generic_decode)(unsigned char *, size_t, void *, size_t *); +typedef void (ASN1CALL *generic_free)(void *); +typedef int (ASN1CALL *generic_copy)(const void *, void *); + +int +generic_test (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), + size_t (ASN1CALL *length)(void *), + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), + void (ASN1CALL *free_data)(void *), + int (*cmp)(void *a, void *b), + int (ASN1CALL *copy)(const void *a, void *b)); + +int +generic_decode_fail(const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)); + + +struct map_page; + +enum map_type { OVERRUN, UNDERRUN }; + +struct map_page; + +void * map_alloc(enum map_type, const void *, size_t, struct map_page **); +void map_free(struct map_page *, const char *, const char *); diff --git a/third_party/heimdal/lib/asn1/check-der.c b/third_party/heimdal/lib/asn1/check-der.c new file mode 100644 index 0000000..58c1446 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-der.c @@ -0,0 +1,1215 @@ +/* + * Copyright (c) 1999 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include +#include + +#include +#include +#include + +#include "check-common.h" + +RCSID("$Id$"); + +static int +cmp_integer (void *a, void *b) +{ + int *ia = (int *)a; + int *ib = (int *)b; + + return *ib - *ia; +} + +static int +test_integer (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x7f", NULL }, + {NULL, 2, "\x00\x80", NULL }, + {NULL, 2, "\x01\x00", NULL }, + {NULL, 1, "\x80", NULL }, + {NULL, 2, "\xff\x7f", NULL }, + {NULL, 1, "\xff", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 2, "\x00\xff", NULL }, + {NULL, 2, "\xfe\x01", NULL }, + {NULL, 4, "\x7f\xff\xff\xff", NULL } + }; + + int values[] = {0, 127, 128, 256, -128, -129, -1, -255, 255, + -511, 0x7fffffff}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "integer %d", values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_integer, + (generic_length) der_length_integer, + (generic_decode)der_get_integer, + (generic_free)NULL, + cmp_integer, + NULL); + + for (i = 0; i < ntests; ++i) + free (tests[i].name); + return ret; +} + +static int +test_one_int(int val) +{ + int ret, dval; + unsigned char *buf; + size_t len_len, len; + + len = _heim_len_int(val); + + buf = emalloc(len + 2); + + buf[0] = '\xff'; + buf[len + 1] = '\xff'; + memset(buf + 1, 0, len); + + ret = der_put_integer(buf + 1 + len - 1, len, &val, &len_len); + if (ret) { + printf("integer %d encode failed %d\n", val, ret); + return 1; + } + if (len != len_len) { + printf("integer %d encode fail with %d len %lu, result len %lu\n", + val, ret, (unsigned long)len, (unsigned long)len_len); + return 1; + } + + ret = der_get_integer(buf + 1, len, &dval, &len_len); + if (ret) { + printf("integer %d decode failed %d\n", val, ret); + return 1; + } + if (len != len_len) { + printf("integer %d decoded diffrent len %lu != %lu", + val, (unsigned long)len, (unsigned long)len_len); + return 1; + } + if (val != dval) { + printf("decode decoded to diffrent value %d != %d", + val, dval); + return 1; + } + + if (buf[0] != (unsigned char)'\xff') { + printf("precanary dead %d\n", val); + return 1; + } + if (buf[len + 1] != (unsigned char)'\xff') { + printf("postecanary dead %d\n", val); + return 1; + } + free(buf); + return 0; +} + +static int +test_integer_more (void) +{ + int64_t i, n1, n2, n3, n4, n5, n6; + + n2 = 0; + for (i = 0; i < (sizeof(int) * 8); i++) { + n1 = 0x01 << i; + n2 = n2 | n1; + n3 = ~n1; + n4 = ~n2; + n5 = (-1) & ~(0x3f << i); + n6 = (-1) & ~(0x7f << i); + + test_one_int(n1); + test_one_int(n2); + test_one_int(n3); + test_one_int(n4); + test_one_int(n5); + test_one_int(n6); + } + return 0; +} + +static int +cmp_unsigned (void *a, void *b) +{ + return *(unsigned int*)b - *(unsigned int*)a; +} + +static int +test_unsigned (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x7f", NULL }, + {NULL, 2, "\x00\x80", NULL }, + {NULL, 2, "\x01\x00", NULL }, + {NULL, 2, "\x02\x00", NULL }, + {NULL, 3, "\x00\x80\x00", NULL }, + {NULL, 5, "\x00\x80\x00\x00\x00", NULL }, + {NULL, 4, "\x7f\xff\xff\xff", NULL } + }; + + unsigned int values[] = {0, 127, 128, 256, 512, 32768, + 0x80000000, 0x7fffffff}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "unsigned %u", values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_unsigned, + (generic_length)der_length_unsigned, + (generic_decode)der_get_unsigned, + (generic_free)NULL, + cmp_unsigned, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + return ret; +} + +static int +cmp_octet_string (void *a, void *b) +{ + return der_heim_octet_string_cmp(a, b); +} + +static int +test_octet_string (void) +{ + heim_octet_string s1 = {8, "\x01\x23\x45\x67\x89\xab\xcd\xef"}; + + struct test_case tests[] = { + {NULL, 8, "\x01\x23\x45\x67\x89\xab\xcd\xef", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a octet string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_octet_string), + (generic_encode)der_put_octet_string, + (generic_length)der_length_octet_string, + (generic_decode)der_get_octet_string, + (generic_free)der_free_octet_string, + cmp_octet_string, + NULL); + free(tests[0].name); + return ret; +} + +static int +cmp_bmp_string (void *a, void *b) +{ + heim_bmp_string *oa = (heim_bmp_string *)a; + heim_bmp_string *ob = (heim_bmp_string *)b; + + return der_heim_bmp_string_cmp(oa, ob); +} + +static uint16_t bmp_d1[] = { 32 }; +static uint16_t bmp_d2[] = { 32, 32 }; + +static int +test_bmp_string (void) +{ + heim_bmp_string s1 = { 1, bmp_d1 }; + heim_bmp_string s2 = { 2, bmp_d2 }; + + struct test_case tests[] = { + {NULL, 2, "\x00\x20", NULL }, + {NULL, 4, "\x00\x20\x00\x20", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a bmp string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + tests[1].val = &s2; + if (asprintf (&tests[1].name, "second bmp string") < 0) + errx(1, "malloc"); + if (tests[1].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_bmp_string), + (generic_encode)der_put_bmp_string, + (generic_length)der_length_bmp_string, + (generic_decode)der_get_bmp_string, + (generic_free)der_free_bmp_string, + cmp_bmp_string, + NULL); + free(tests[0].name); + free(tests[1].name); + return ret; +} + +static int +cmp_universal_string (void *a, void *b) +{ + heim_universal_string *oa = (heim_universal_string *)a; + heim_universal_string *ob = (heim_universal_string *)b; + + return der_heim_universal_string_cmp(oa, ob); +} + +static uint32_t universal_d1[] = { 32 }; +static uint32_t universal_d2[] = { 32, 32 }; + +static int +test_universal_string (void) +{ + heim_universal_string s1 = { 1, universal_d1 }; + heim_universal_string s2 = { 2, universal_d2 }; + + struct test_case tests[] = { + {NULL, 4, "\x00\x00\x00\x20", NULL }, + {NULL, 8, "\x00\x00\x00\x20\x00\x00\x00\x20", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a universal string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + tests[1].val = &s2; + if (asprintf (&tests[1].name, "second universal string") < 0) + errx(1, "malloc"); + if (tests[1].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_universal_string), + (generic_encode)der_put_universal_string, + (generic_length)der_length_universal_string, + (generic_decode)der_get_universal_string, + (generic_free)der_free_universal_string, + cmp_universal_string, + NULL); + free(tests[0].name); + free(tests[1].name); + return ret; +} + +static int +cmp_general_string (void *a, void *b) +{ + char **sa = (char **)a; + char **sb = (char **)b; + + return strcmp (*sa, *sb); +} + +static int +test_general_string (void) +{ + char *s1 = "Test User 1"; + + struct test_case tests[] = { + {NULL, 11, "\x54\x65\x73\x74\x20\x55\x73\x65\x72\x20\x31", NULL } + }; + int ret, ntests = sizeof(tests) / sizeof(*tests); + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "the string \"%s\"", s1) < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(unsigned char *), + (generic_encode)der_put_general_string, + (generic_length)der_length_general_string, + (generic_decode)der_get_general_string, + (generic_free)der_free_general_string, + cmp_general_string, + NULL); + free(tests[0].name); + return ret; +} + +static int +cmp_generalized_time (void *a, void *b) +{ + time_t *ta = (time_t *)a; + time_t *tb = (time_t *)b; + + return (int)(*tb - *ta); +} + +static int +test_generalized_time (void) +{ + struct test_case tests[] = { + {NULL, 15, "19700101000000Z", NULL }, + {NULL, 15, "19851106210627Z", NULL } + }; + time_t values[] = {0, 500159187}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "time %d", (int)values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(time_t), + (generic_encode)der_put_generalized_time, + (generic_length)der_length_generalized_time, + (generic_decode)der_get_generalized_time, + (generic_free)NULL, + cmp_generalized_time, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_oid (void *a, void *b) +{ + return der_heim_oid_cmp((heim_oid *)a, (heim_oid *)b); +} + +static unsigned oid_comp1[] = { 1, 1, 1 }; +static unsigned oid_comp2[] = { 1, 1 }; +static unsigned oid_comp3[] = { 6, 15, 1 }; +static unsigned oid_comp4[] = { 6, 15 }; + +static int +test_oid (void) +{ + struct test_case tests[] = { + {NULL, 2, "\x29\x01", NULL }, + {NULL, 1, "\x29", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 1, "\xff", NULL } + }; + heim_oid values[] = { + { 3, oid_comp1 }, + { 2, oid_comp2 }, + { 3, oid_comp3 }, + { 2, oid_comp4 } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "oid %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_oid), + (generic_encode)der_put_oid, + (generic_length)der_length_oid, + (generic_decode)der_get_oid, + (generic_free)der_free_oid, + test_cmp_oid, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_bit_string (void *a, void *b) +{ + return der_heim_bit_string_cmp((heim_bit_string *)a, (heim_bit_string *)b); +} + +static int +test_bit_string (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL } + }; + heim_bit_string values[] = { + { 0, "" } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "bit_string %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_bit_string), + (generic_encode)der_put_bit_string, + (generic_length)der_length_bit_string, + (generic_decode)der_get_bit_string, + (generic_free)der_free_bit_string, + test_cmp_bit_string, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_heim_integer (void *a, void *b) +{ + return der_heim_integer_cmp((heim_integer *)a, (heim_integer *)b); +} + +static int +test_heim_integer (void) +{ + struct test_case tests[] = { + {NULL, 1, "\xff", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 2, "\xfe\x01", NULL }, + {NULL, 2, "\xef\x01", NULL }, + {NULL, 3, "\xff\x00\xff", NULL }, + {NULL, 3, "\xff\x01\x00", NULL }, + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x01", NULL }, + {NULL, 2, "\x00\x80", NULL }, + }; + + heim_integer values[] = { + { 1, "\x01", 1 }, + { 1, "\xff", 1 }, + { 2, "\x01\xff", 1 }, + { 2, "\x10\xff", 1 }, + { 2, "\xff\x01", 1 }, + { 2, "\xff\x00", 1 }, + { 0, "", 0 }, + { 1, "\x01", 0 }, + { 1, "\x80", 0 }, + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(tests[0]); + size_t size; + heim_integer i2; + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "heim_integer %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_integer), + (generic_encode)der_put_heim_integer, + (generic_length)der_length_heim_integer, + (generic_decode)der_get_heim_integer, + (generic_free)der_free_heim_integer, + test_cmp_heim_integer, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + if (ret) + return ret; + + /* test zero length integer (BER format) */ + ret = der_get_heim_integer(NULL, 0, &i2, &size); + if (ret) + errx(1, "der_get_heim_integer"); + if (i2.length != 0) + errx(1, "der_get_heim_integer wrong length"); + der_free_heim_integer(&i2); + + return 0; +} + +static int +test_cmp_boolean (void *a, void *b) +{ + return !!*(int *)a != !!*(int *)b; +} + +static int +test_boolean (void) +{ + struct test_case tests[] = { + {NULL, 1, "\xff", NULL }, + {NULL, 1, "\x00", NULL } + }; + + int values[] = { 1, 0 }; + int i, ret; + int ntests = sizeof(tests) / sizeof(tests[0]); + size_t size; + heim_integer i2; + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "heim_boolean %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_boolean, + (generic_length)der_length_boolean, + (generic_decode)der_get_boolean, + (generic_free)NULL, + test_cmp_boolean, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + if (ret) + return ret; + + /* test zero length integer (BER format) */ + ret = der_get_heim_integer(NULL, 0, &i2, &size); + if (ret) + errx(1, "der_get_heim_integer"); + if (i2.length != 0) + errx(1, "der_get_heim_integer wrong length"); + der_free_heim_integer(&i2); + + return 0; +} + +static int +check_fail_unsigned(void) +{ + struct test_case tests[] = { + {NULL, sizeof(unsigned) + 1, + "\x01\x01\x01\x01\x01\x01\x01\x01\x01", "data overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(unsigned), + (generic_decode)der_get_unsigned); +} + +static int +check_fail_integer(void) +{ + struct test_case tests[] = { + {NULL, sizeof(int) + 1, + "\x01\x01\x01\x01\x01\x01\x01\x01\x01", "data overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(int), + (generic_decode)der_get_integer); +} + +static int +check_fail_length(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 1, "\x82", "internal length overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(size_t), + (generic_decode)der_get_length); +} + +static int +check_fail_boolean(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(int), + (generic_decode)der_get_boolean); +} + +static int +check_fail_general_string(void) +{ + struct test_case tests[] = { + { NULL, 3, "A\x00i", "NUL char in string"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_general_string), + (generic_decode)der_get_general_string); +} + +static int +check_fail_bmp_string(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "odd (1) length bmpstring"}, + {NULL, 3, "\x00\x00\x00", "odd (3) length bmpstring"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_bmp_string), + (generic_decode)der_get_bmp_string); +} + +static int +check_fail_universal_string(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "x & 3 == 1 universal string"}, + {NULL, 2, "\x00\x00", "x & 3 == 2 universal string"}, + {NULL, 3, "\x00\x00\x00", "x & 3 == 3 universal string"}, + {NULL, 5, "\x00\x00\x00\x00\x00", "x & 3 == 1 universal string"}, + {NULL, 6, "\x00\x00\x00\x00\x00\x00", "x & 3 == 2 universal string"}, + {NULL, 7, "\x00\x00\x00\x00\x00\x00\x00", "x & 3 == 3 universal string"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_universal_string), + (generic_decode)der_get_universal_string); +} + +static int +check_fail_heim_integer(void) +{ +#if 0 + struct test_case tests[] = { + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_integer), + (generic_decode)der_get_heim_integer); +#else + return 0; +#endif +} + +static int +check_fail_generalized_time(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "no time"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(time_t), + (generic_decode)der_get_generalized_time); +} + +static int +check_fail_oid(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 2, "\x00\x80", "last byte continuation" }, + {NULL, 11, "\x00\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00", + "oid element overflow" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_oid), + (generic_decode)der_get_oid); +} + +static int +check_fail_bitstring(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 1, "\x08", "larger then 8 bits trailer"}, + {NULL, 1, "\x01", "to few bytes for bits"}, + {NULL, -2, "\x00", "length overrun"}, + {NULL, -1, "", "length to short"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_bit_string), + (generic_decode)der_get_bit_string); +} + +static int +check_heim_integer_same(const char *p, const char *norm_p, heim_integer *i) +{ + heim_integer i2; + char *str; + int ret; + + ret = der_print_hex_heim_integer(i, &str); + if (ret) + errx(1, "der_print_hex_heim_integer: %d", ret); + + if (strcmp(str, norm_p) != 0) + errx(1, "der_print_hex_heim_integer: %s != %s", str, p); + + ret = der_parse_hex_heim_integer(str, &i2); + if (ret) + errx(1, "der_parse_hex_heim_integer: %d", ret); + + if (der_heim_integer_cmp(i, &i2) != 0) + errx(1, "der_heim_integer_cmp: p %s", p); + + der_free_heim_integer(&i2); + free(str); + + ret = der_parse_hex_heim_integer(p, &i2); + if (ret) + errx(1, "der_parse_hex_heim_integer: %d", ret); + + if (der_heim_integer_cmp(i, &i2) != 0) + errx(1, "der_heim_integer_cmp: norm"); + + der_free_heim_integer(&i2); + + return 0; +} + +static int +test_heim_int_format(void) +{ + heim_integer i = { 1, "\x10", 0 }; + heim_integer i2 = { 1, "\x10", 1 }; + heim_integer i3 = { 1, "\01", 0 }; + char *p = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + heim_integer bni = { + 128, + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2" + "\x21\x68\xC2\x34\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1" + "\x29\x02\x4E\x08\x8A\x67\xCC\x74\x02\x0B\xBE\xA6" + "\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD" + "\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D" + "\xF2\x5F\x14\x37\x4F\xE1\x35\x6D\x6D\x51\xC2\x45" + "\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\xF4\x4C\x42\xE9" + "\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED" + "\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11" + "\x7C\x4B\x1F\xE6\x49\x28\x66\x51\xEC\xE6\x53\x81" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", + 0 + }; + heim_integer f; + int ret = 0; + + ret += check_heim_integer_same(p, p, &bni); + ret += check_heim_integer_same("10", "10", &i); + ret += check_heim_integer_same("00000010", "10", &i); + ret += check_heim_integer_same("-10", "-10", &i2); + ret += check_heim_integer_same("-00000010", "-10", &i2); + ret += check_heim_integer_same("01", "01", &i3); + ret += check_heim_integer_same("1", "01", &i3); + + { + int r; + r = der_parse_hex_heim_integer("-", &f); + if (r == 0) { + der_free_heim_integer(&f); + ret++; + } + /* used to cause UMR */ + r = der_parse_hex_heim_integer("00", &f); + if (r == 0) + der_free_heim_integer(&f); + else + ret++; + } + + return ret; +} + +static int +test_heim_oid_format_same(const char *str, const heim_oid *oid) +{ + int ret; + char *p; + heim_oid o2; + + ret = der_print_heim_oid(oid, ' ', &p); + if (ret) { + printf("fail to print oid: %s\n", str); + return 1; + } + + if (strcmp(p, str) != 0) { + printf("oid %s != formated oid %s\n", str, p); + free(p); + return 1; + } + + ret = der_parse_heim_oid(p, " ", &o2); + if (ret) { + printf("failed to parse %s\n", p); + free(p); + return 1; + } + free(p); + ret = der_heim_oid_cmp(&o2, oid); + der_free_oid(&o2); + + if (ret != 0) + return 1; + return 0; +} + +static unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; + +static int +test_heim_oid_format(void) +{ + heim_oid sha1 = { 6, sha1_oid_tree }; + int ret = 0; + + ret += test_heim_oid_format_same("1 3 14 3 2 26", &sha1); + + return ret; +} + +static int +check_trailing_nul(void) +{ + int i, ret; + struct { + int fail; + const unsigned char *p; + size_t len; + const char *s; + size_t size; + } foo[] = { + { 1, (const unsigned char *)"foo\x00o", 5, NULL, 0 }, + { 1, (const unsigned char *)"\x00o", 2, NULL, 0 }, + { 0, (const unsigned char *)"\x00\x00\x00\x00\x00", 5, "", 5 }, + { 0, (const unsigned char *)"\x00", 1, "", 1 }, + { 0, (const unsigned char *)"", 0, "", 0 }, + { 0, (const unsigned char *)"foo\x00\x00", 5, "foo", 5 }, + { 0, (const unsigned char *)"foo\0", 4, "foo", 4 }, + { 0, (const unsigned char *)"foo", 3, "foo", 3 } + }; + + for (i = 0; i < sizeof(foo)/sizeof(foo[0]); i++) { + char *s; + size_t size; + ret = der_get_general_string(foo[i].p, foo[i].len, &s, &size); + if (foo[i].fail) { + if (ret == 0) + errx(1, "check %d NULL didn't fail", i); + continue; + } + if (ret) + errx(1, "NULL check %d der_get_general_string failed", i); + if (foo[i].size != size) + errx(1, "NUL check i = %d size failed", i); + if (strcmp(foo[i].s, s) != 0) + errx(1, "NUL check i = %d content failed", i); + free(s); + } + return 0; +} + +static int +test_misc_cmp(void) +{ + int ret; + + /* diffrent lengths are diffrent */ + { + const heim_octet_string os1 = { 1, "a" } , os2 = { 0, NULL }; + ret = der_heim_octet_string_cmp(&os1, &os2); + if (ret == 0) + return 1; + } + /* diffrent data are diffrent */ + { + const heim_octet_string os1 = { 1, "a" } , os2 = { 1, "b" }; + ret = der_heim_octet_string_cmp(&os1, &os2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + const heim_bit_string bs1 = { 8, "a" } , bs2 = { 7, "a" }; + ret = der_heim_bit_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent data are diffrent */ + { + const heim_bit_string bs1 = { 7, "\x0f" } , bs2 = { 7, "\x02" }; + ret = der_heim_bit_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + uint16_t data = 1; + heim_bmp_string bs1 = { 1, NULL } , bs2 = { 0, NULL }; + bs1.data = &data; + ret = der_heim_bmp_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + uint32_t data; + heim_universal_string us1 = { 1, NULL } , us2 = { 0, NULL }; + us1.data = &data; + ret = der_heim_universal_string_cmp(&us1, &us2); + if (ret == 0) + return 1; + } + /* same */ + { + uint32_t data = (uint32_t)'a'; + heim_universal_string us1 = { 1, NULL } , us2 = { 1, NULL }; + us1.data = &data; + us2.data = &data; + ret = der_heim_universal_string_cmp(&us1, &us2); + if (ret != 0) + return 1; + } + + return 0; +} + +static int +corner_generalized_time(void) +{ + const char *str = "760520140000Z"; + size_t size; + time_t t; + int ret; + + ret = der_get_generalized_time((const unsigned char*)str, strlen(str), + &t, &size); + if (ret) + return 1; + return 0; +} + +static int +corner_tag(void) +{ + struct { + int ok; + const char *ptr; + size_t len; + } tests[] = { + { 1, "\x00", 1 }, + { 0, "\xff", 1 }, + { 0, "\xff\xff\xff\xff\xff\xff\xff\xff", 8 } + }; + int i, ret; + Der_class cl; + Der_type ty; + unsigned int tag; + size_t size; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + ret = der_get_tag((const unsigned char*)tests[i].ptr, + tests[i].len, &cl, &ty, &tag, &size); + if (ret) { + if (tests[i].ok) + errx(1, "failed while shouldn't"); + } else { + if (!tests[i].ok) + errx(1, "passed while shouldn't"); + } + } + return 0; +} + +struct randomcheck { + asn1_type_decode decoder; + asn1_type_release release; + size_t typesize; + size_t inputsize; +} randomcheck[] = { +#define el(name, type, maxlen) { \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type), \ + maxlen \ + } + el(integer, int, 6), + el(heim_integer, heim_integer, 12), + el(integer, int, 6), + el(unsigned, unsigned, 6), + el(general_string, heim_general_string, 12), + el(octet_string, heim_octet_string, 12), + { (asn1_type_decode)der_get_octet_string_ber, + (asn1_type_release)der_free_octet_string, + sizeof(heim_octet_string), 20 }, + el(generalized_time, time_t, 20), + el(utctime, time_t, 20), + el(bit_string, heim_bit_string, 10), + el(oid, heim_oid, 10), + { NULL, NULL, 0, 0 } +#undef el +}; + +static void +asn1rand(uint8_t *randbytes, size_t len) +{ + while (len) { + *randbytes++ = rk_random(); + len--; + } +} + +static int +check_random(void) +{ + struct randomcheck *r = randomcheck; + uint8_t *input; + void *type; + size_t size, insize; + int ret; + + while (r->decoder) { + type = emalloc(r->typesize); + memset(type, 0, r->typesize); + + input = emalloc(r->inputsize); + + /* try all zero first */ + memset(input, 0, r->inputsize); + + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* try all one first */ + memset(input, 0xff, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* try 0x41 too */ + memset(input, 0x41, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* random */ + asn1rand(input, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* let make buffer smaller */ + insize = r->inputsize; + do { + insize--; + asn1rand(input, insize); + + ret = r->decoder(input, insize, type, &size); + if (!ret) + r->release(type); + } while(insize > 0); + + free(type); + + r++; + } + return 0; +} + + + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_integer (); + ret += test_integer_more(); + ret += test_unsigned (); + ret += test_octet_string (); + ret += test_bmp_string (); + ret += test_universal_string (); + ret += test_general_string (); + ret += test_generalized_time (); + ret += test_oid (); + ret += test_bit_string(); + ret += test_heim_integer(); + ret += test_boolean(); + + ret += check_fail_unsigned(); + ret += check_fail_integer(); + ret += check_fail_length(); + ret += check_fail_boolean(); + ret += check_fail_general_string(); + ret += check_fail_bmp_string(); + ret += check_fail_universal_string(); + ret += check_fail_heim_integer(); + ret += check_fail_generalized_time(); + ret += check_fail_oid(); + ret += check_fail_bitstring(); + ret += test_heim_int_format(); + ret += test_heim_oid_format(); + ret += check_trailing_nul(); + ret += test_misc_cmp(); + ret += corner_generalized_time(); + ret += corner_tag(); + ret += check_random(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-gen.c b/third_party/heimdal/lib/asn1/check-gen.c new file mode 100644 index 0000000..4941c74 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-gen.c @@ -0,0 +1,2758 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check-common.h" + +static int my_copy_vers_called; +static int my_free_vers_called; + +#include +#if UINT_MAX == 0xffffffff +// 32 bit +#define DISABLE_TEST_64 +#endif + +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + my_copy_vers_called++; + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + my_free_vers_called++; + v->v = -1; +} + +static char *lha_principal[] = { "lha" }; +static char *lharoot_princ[] = { "lha", "root" }; +static char *datan_princ[] = { "host", "nutcracker.e.kth.se" }; +static char *nada_tgt_principal[] = { "krbtgt", "NADA.KTH.SE" }; + +static int +cmp_principal (void *a, void *b) +{ + Principal *pa = a; + Principal *pb = b; + int i; + + COMPARE_STRING(pa,pb,realm); + COMPARE_INTEGER(pa,pb,name.name_type); + COMPARE_INTEGER(pa,pb,name.name_string.len); + + for (i = 0; i < pa->name.name_string.len; i++) + COMPARE_STRING(pa,pb,name.name_string.val[i]); + + return 0; +} + +static int +test_principal (void) +{ + + struct test_case tests[] = { + { NULL, 29, + "\x30\x1b\xa0\x10\x30\x0e\xa0\x03\x02\x01\x01\xa1\x07\x30\x05\x1b" + "\x03\x6c\x68\x61\xa1\x07\x1b\x05\x53\x55\x2e\x53\x45", + NULL + }, + { NULL, 35, + "\x30\x21\xa0\x16\x30\x14\xa0\x03\x02\x01\x01\xa1\x0d\x30\x0b\x1b" + "\x03\x6c\x68\x61\x1b\x04\x72\x6f\x6f\x74\xa1\x07\x1b\x05\x53\x55" + "\x2e\x53\x45", + NULL + }, + { NULL, 54, + "\x30\x34\xa0\x26\x30\x24\xa0\x03\x02\x01\x03\xa1\x1d\x30\x1b\x1b" + "\x04\x68\x6f\x73\x74\x1b\x13\x6e\x75\x74\x63\x72\x61\x63\x6b\x65" + "\x72\x2e\x65\x2e\x6b\x74\x68\x2e\x73\x65\xa1\x0a\x1b\x08\x45\x2e" + "\x4b\x54\x48\x2e\x53\x45", + NULL + } + }; + + + Principal values[] = { + { { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE", NULL }, + { { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE", NULL }, + { { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE", NULL } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "Principal %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(Principal), + (generic_encode)encode_Principal, + (generic_length)length_Principal, + (generic_decode)decode_Principal, + (generic_free)free_Principal, + cmp_principal, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + + return ret; +} + +static int +cmp_authenticator (void *a, void *b) +{ + Authenticator *aa = a; + Authenticator *ab = b; + int i; + + COMPARE_INTEGER(aa,ab,authenticator_vno); + COMPARE_STRING(aa,ab,crealm); + + COMPARE_INTEGER(aa,ab,cname.name_type); + COMPARE_INTEGER(aa,ab,cname.name_string.len); + + for (i = 0; i < aa->cname.name_string.len; i++) + COMPARE_STRING(aa,ab,cname.name_string.val[i]); + + return 0; +} + +static int +test_authenticator (void) +{ + struct test_case tests[] = { + { NULL, 63, + "\x62\x3d\x30\x3b\xa0\x03\x02\x01\x05\xa1\x0a\x1b\x08" + "\x45\x2e\x4b\x54\x48\x2e\x53\x45\xa2\x10\x30\x0e\xa0" + "\x03\x02\x01\x01\xa1\x07\x30\x05\x1b\x03\x6c\x68\x61" + "\xa4\x03\x02\x01\x0a\xa5\x11\x18\x0f\x31\x39\x37\x30" + "\x30\x31\x30\x31\x30\x30\x30\x31\x33\x39\x5a", + NULL + }, + { NULL, 67, + "\x62\x41\x30\x3f\xa0\x03\x02\x01\x05\xa1\x07\x1b\x05" + "\x53\x55\x2e\x53\x45\xa2\x16\x30\x14\xa0\x03\x02\x01" + "\x01\xa1\x0d\x30\x0b\x1b\x03\x6c\x68\x61\x1b\x04\x72" + "\x6f\x6f\x74\xa4\x04\x02\x02\x01\x24\xa5\x11\x18\x0f" + "\x31\x39\x37\x30\x30\x31\x30\x31\x30\x30\x31\x36\x33" + "\x39\x5a", + NULL + } + }; + + Authenticator values[] = { + { 5, "E.KTH.SE", { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, + NULL, 10, 99, NULL, NULL, NULL }, + { 5, "SU.SE", { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, + NULL, 292, 999, NULL, NULL, NULL } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "Authenticator %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(Authenticator), + (generic_encode)encode_Authenticator, + (generic_length)length_Authenticator, + (generic_decode)decode_Authenticator, + (generic_free)free_Authenticator, + cmp_authenticator, + (generic_copy)copy_Authenticator); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + + return ret; +} + +static int +cmp_KRB_ERROR (void *a, void *b) +{ + KRB_ERROR *aa = a; + KRB_ERROR *ab = b; + int i; + + COMPARE_INTEGER(aa,ab,pvno); + COMPARE_INTEGER(aa,ab,msg_type); + + IF_OPT_COMPARE(aa,ab,ctime) { + COMPARE_INTEGER(aa,ab,ctime); + } + IF_OPT_COMPARE(aa,ab,cusec) { + COMPARE_INTEGER(aa,ab,cusec); + } + COMPARE_INTEGER(aa,ab,stime); + COMPARE_INTEGER(aa,ab,susec); + COMPARE_INTEGER(aa,ab,error_code); + + IF_OPT_COMPARE(aa,ab,crealm) { + COMPARE_OPT_STRING(aa,ab,crealm); + } +#if 0 + IF_OPT_COMPARE(aa,ab,cname) { + COMPARE_OPT_STRING(aa,ab,cname); + } +#endif + COMPARE_STRING(aa,ab,realm); + + COMPARE_INTEGER(aa,ab,sname.name_string.len); + for (i = 0; i < aa->sname.name_string.len; i++) + COMPARE_STRING(aa,ab,sname.name_string.val[i]); + + IF_OPT_COMPARE(aa,ab,e_text) { + COMPARE_OPT_STRING(aa,ab,e_text); + } + IF_OPT_COMPARE(aa,ab,e_data) { + /* COMPARE_OPT_OCTET_STRING(aa,ab,e_data); */ + } + + return 0; +} + +static int +test_krb_error (void) +{ + struct test_case tests[] = { + { NULL, 127, + "\x7e\x7d\x30\x7b\xa0\x03\x02\x01\x05\xa1\x03\x02\x01\x1e\xa4\x11" + "\x18\x0f\x32\x30\x30\x33\x31\x31\x32\x34\x30\x30\x31\x31\x31\x39" + "\x5a\xa5\x05\x02\x03\x04\xed\xa5\xa6\x03\x02\x01\x1f\xa7\x0d\x1b" + "\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45\xa8\x10\x30\x0e" + "\xa0\x03\x02\x01\x01\xa1\x07\x30\x05\x1b\x03\x6c\x68\x61\xa9\x0d" + "\x1b\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45\xaa\x20\x30" + "\x1e\xa0\x03\x02\x01\x01\xa1\x17\x30\x15\x1b\x06\x6b\x72\x62\x74" + "\x67\x74\x1b\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45", + "KRB-ERROR Test 1" + } + }; + int ntests = sizeof(tests) / sizeof(*tests); + KRB_ERROR e1; + PrincipalName lhaprincipalname = { 1, { 1, lha_principal } }; + PrincipalName tgtprincipalname = { 1, { 2, nada_tgt_principal } }; + char *realm = "NADA.KTH.SE"; + + e1.pvno = 5; + e1.msg_type = 30; + e1.ctime = NULL; + e1.cusec = NULL; + e1.stime = 1069632679; + e1.susec = 322981; + e1.error_code = 31; + e1.crealm = &realm; + e1.cname = &lhaprincipalname; + e1.realm = "NADA.KTH.SE"; + e1.sname = tgtprincipalname; + e1.e_text = NULL; + e1.e_data = NULL; + + tests[0].val = &e1; + + return generic_test (tests, ntests, sizeof(KRB_ERROR), + (generic_encode)encode_KRB_ERROR, + (generic_length)length_KRB_ERROR, + (generic_decode)decode_KRB_ERROR, + (generic_free)free_KRB_ERROR, + cmp_KRB_ERROR, + (generic_copy)copy_KRB_ERROR); +} + +static int +cmp_Name (void *a, void *b) +{ + Name *aa = a; + Name *ab = b; + + COMPARE_INTEGER(aa,ab,element); + + return 0; +} + +static int +test_Name (void) +{ + struct test_case tests[] = { + { NULL, 35, + "\x30\x21\x31\x1f\x30\x0b\x06\x03\x55\x04\x03\x13\x04\x4c\x6f\x76" + "\x65\x30\x10\x06\x03\x55\x04\x07\x13\x09\x53\x54\x4f\x43\x4b\x48" + "\x4f\x4c\x4d", + "Name CN=Love+L=STOCKHOLM" + }, + { NULL, 35, + "\x30\x21\x31\x1f\x30\x0b\x06\x03\x55\x04\x03\x13\x04\x4c\x6f\x76" + "\x65\x30\x10\x06\x03\x55\x04\x07\x13\x09\x53\x54\x4f\x43\x4b\x48" + "\x4f\x4c\x4d", + "Name L=STOCKHOLM+CN=Love" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + Name n1, n2; + RelativeDistinguishedName rdn1[1]; + RelativeDistinguishedName rdn2[1]; + AttributeTypeAndValue atv1[2]; + AttributeTypeAndValue atv2[2]; + unsigned cmp_CN[] = { 2, 5, 4, 3 }; + unsigned cmp_L[] = { 2, 5, 4, 7 }; + + /* n1 */ + n1.element = choice_Name_rdnSequence; + n1.u.rdnSequence.val = rdn1; + n1.u.rdnSequence.len = sizeof(rdn1)/sizeof(rdn1[0]); + rdn1[0].val = atv1; + rdn1[0].len = sizeof(atv1)/sizeof(atv1[0]); + + atv1[0].type.length = sizeof(cmp_CN)/sizeof(cmp_CN[0]); + atv1[0].type.components = cmp_CN; + atv1[0].value.element = choice_DirectoryString_printableString; + atv1[0].value.u.printableString.data = "Love"; + atv1[0].value.u.printableString.length = 4; + + atv1[1].type.length = sizeof(cmp_L)/sizeof(cmp_L[0]); + atv1[1].type.components = cmp_L; + atv1[1].value.element = choice_DirectoryString_printableString; + atv1[1].value.u.printableString.data = "STOCKHOLM"; + atv1[1].value.u.printableString.length = 9; + + /* n2 */ + n2.element = choice_Name_rdnSequence; + n2.u.rdnSequence.val = rdn2; + n2.u.rdnSequence.len = sizeof(rdn2)/sizeof(rdn2[0]); + rdn2[0].val = atv2; + rdn2[0].len = sizeof(atv2)/sizeof(atv2[0]); + + atv2[0].type.length = sizeof(cmp_L)/sizeof(cmp_L[0]); + atv2[0].type.components = cmp_L; + atv2[0].value.element = choice_DirectoryString_printableString; + atv2[0].value.u.printableString.data = "STOCKHOLM"; + atv2[0].value.u.printableString.length = 9; + + atv2[1].type.length = sizeof(cmp_CN)/sizeof(cmp_CN[0]); + atv2[1].type.components = cmp_CN; + atv2[1].value.element = choice_DirectoryString_printableString; + atv2[1].value.u.printableString.data = "Love"; + atv2[1].value.u.printableString.length = 4; + + /* */ + tests[0].val = &n1; + tests[1].val = &n2; + + return generic_test (tests, ntests, sizeof(Name), + (generic_encode)encode_Name, + (generic_length)length_Name, + (generic_decode)decode_Name, + (generic_free)free_Name, + cmp_Name, + (generic_copy)copy_Name); +} + +static int +cmp_KeyUsage (void *a, void *b) +{ + KeyUsage *aa = a; + KeyUsage *ab = b; + + return KeyUsage2int(*aa) != KeyUsage2int(*ab); +} + +static int +test_bit_string (void) +{ + struct test_case tests[] = { + { NULL, 4, + "\x03\x02\x07\x80", + "bitstring 1" + }, + { NULL, 4, + "\x03\x02\x05\xa0", + "bitstring 2" + }, + { NULL, 5, + "\x03\x03\x07\x00\x80", + "bitstring 3" + }, + { NULL, 3, + "\x03\x01\x00", + "bitstring 4" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + KeyUsage ku1, ku2, ku3, ku4; + + memset(&ku1, 0, sizeof(ku1)); + ku1.digitalSignature = 1; + tests[0].val = &ku1; + + memset(&ku2, 0, sizeof(ku2)); + ku2.digitalSignature = 1; + ku2.keyEncipherment = 1; + tests[1].val = &ku2; + + memset(&ku3, 0, sizeof(ku3)); + ku3.decipherOnly = 1; + tests[2].val = &ku3; + + memset(&ku4, 0, sizeof(ku4)); + tests[3].val = &ku4; + + + return generic_test (tests, ntests, sizeof(KeyUsage), + (generic_encode)encode_KeyUsage, + (generic_length)length_KeyUsage, + (generic_decode)decode_KeyUsage, + (generic_free)free_KeyUsage, + cmp_KeyUsage, + (generic_copy)copy_KeyUsage); +} + +static int +cmp_TicketFlags (void *a, void *b) +{ + TicketFlags *aa = a; + TicketFlags *ab = b; + + return TicketFlags2int(*aa) != TicketFlags2int(*ab); +} + +static int +test_bit_string_rfc1510 (void) +{ + struct test_case tests[] = { + { NULL, 7, + "\x03\x05\x00\x80\x00\x00\x00", + "TF bitstring 1" + }, + { NULL, 7, + "\x03\x05\x00\x40\x20\x00\x00", + "TF bitstring 2" + }, + { NULL, 7, + "\x03\x05\x00\x00\x20\x00\x00", + "TF bitstring 3" + }, + { NULL, 7, + "\x03\x05\x00\x00\x00\x00\x00", + "TF bitstring 4" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TicketFlags tf1, tf2, tf3, tf4; + + memset(&tf1, 0, sizeof(tf1)); + tf1.reserved = 1; + tests[0].val = &tf1; + + memset(&tf2, 0, sizeof(tf2)); + tf2.forwardable = 1; + tf2.pre_authent = 1; + tests[1].val = &tf2; + + memset(&tf3, 0, sizeof(tf3)); + tf3.pre_authent = 1; + tests[2].val = &tf3; + + memset(&tf4, 0, sizeof(tf4)); + tests[3].val = &tf4; + + + return generic_test (tests, ntests, sizeof(TicketFlags), + (generic_encode)encode_TicketFlags, + (generic_length)length_TicketFlags, + (generic_decode)decode_TicketFlags, + (generic_free)free_TicketFlags, + cmp_TicketFlags, + (generic_copy)copy_TicketFlags); +} + +static int +cmp_KerberosTime (void *a, void *b) +{ + KerberosTime *aa = a; + KerberosTime *ab = b; + + return *aa != *ab; +} + +static int +test_time (void) +{ + struct test_case tests[] = { + { NULL, 17, + "\x18\x0f\x31\x39\x37\x30\x30\x31\x30\x31\x30\x31\x31\x38\x33\x31" + "\x5a", + "time 1" }, + { NULL, 17, + "\x18\x0f\x32\x30\x30\x39\x30\x35\x32\x34\x30\x32\x30\x32\x34\x30" + "\x5a", + "time 2" } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + KerberosTime times[] = { + 4711, + 1243130560 + }; + + tests[0].val = ×[0]; + tests[1].val = ×[1]; + + return generic_test (tests, ntests, sizeof(KerberosTime), + (generic_encode)encode_KerberosTime, + (generic_length)length_KerberosTime, + (generic_decode)decode_KerberosTime, + (generic_free)free_KerberosTime, + cmp_KerberosTime, + (generic_copy)copy_KerberosTime); +} + +struct { + const char *cert; + size_t len; +} certs[] = { + { + "\x30\x82\x02\x6c\x30\x82\x01\xd5\xa0\x03\x02\x01\x02\x02\x09\x00" + "\x99\x32\xde\x61\x0e\x40\x19\x8a\x30\x0d\x06\x09\x2a\x86\x48\x86" + "\xf7\x0d\x01\x01\x05\x05\x00\x30\x2a\x31\x1b\x30\x19\x06\x03\x55" + "\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52" + "\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" + "\x02\x53\x45\x30\x1e\x17\x0d\x30\x39\x30\x34\x32\x36\x32\x30\x32" + "\x39\x34\x30\x5a\x17\x0d\x31\x39\x30\x34\x32\x34\x32\x30\x32\x39" + "\x34\x30\x5a\x30\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12" + "\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20" + "\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30" + "\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05" + "\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xb9\xd3\x1b\x67" + "\x1c\xf7\x5e\x26\x81\x3b\x82\xff\x03\xa4\x43\xb5\xb2\x63\x0b\x89" + "\x58\x43\xfe\x3d\xe0\x38\x7d\x93\x74\xbb\xad\x21\xa4\x29\xd9\x34" + "\x79\xf3\x1c\x8c\x5a\xd6\xb0\xd7\x19\xea\xcc\xaf\xe0\xa8\x40\x02" + "\x1d\x91\xf1\xac\x36\xb0\xfb\x08\xbd\xcc\x9a\xe1\xb7\x6e\xee\x0a" + "\x69\xbf\x6d\x2b\xee\x20\x82\x61\x06\xf2\x18\xcc\x89\x11\x64\x7e" + "\xb2\xff\x47\xd1\x3b\x52\x73\xeb\x5a\xc0\x03\xa6\x4b\xc7\x40\x7e" + "\xbc\xe1\x0e\x65\x44\x3f\x40\x8b\x02\x82\x54\x04\xd9\xcc\x2c\x67" + "\x01\xb6\x16\x82\xd8\x33\x53\x17\xd7\xde\x8d\x5d\x02\x03\x01\x00" + "\x01\xa3\x81\x99\x30\x81\x96\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" + "\x04\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30\xdd" + "\x27\x96\x59\x9b\x0e\x68\x30\x5a\x06\x03\x55\x1d\x23\x04\x53\x30" + "\x51\x80\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30" + "\xdd\x27\x96\x59\x9b\x0e\x68\xa1\x2e\xa4\x2c\x30\x2a\x31\x1b\x30" + "\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65" + "\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03" + "\x55\x04\x06\x13\x02\x53\x45\x82\x09\x00\x99\x32\xde\x61\x0e\x40" + "\x19\x8a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff" + "\x30\x0b\x06\x03\x55\x1d\x0f\x04\x04\x03\x02\x01\xe6\x30\x0d\x06" + "\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00" + "\x52\x9b\xe4\x0e\xee\xc2\x5d\xb7\xf1\xba\x47\xe3\xfe\xaf\x3d\x51" + "\x10\xfd\xe8\x0d\x14\x58\x05\x36\xa7\xeb\xd8\x05\xe5\x27\x6f\x51" + "\xb8\xec\x90\xd9\x03\xe1\xbc\x9c\x93\x38\x21\x5c\xaf\x4e\x6c\x7b" + "\x6c\x65\xa9\x92\xcd\x94\xef\xa8\xae\x90\x12\x14\x78\x2d\xa3\x15" + "\xaa\x42\xf1\xd9\x44\x64\x2c\x3c\xc0\xbd\x3a\x48\xd8\x80\x45\x8b" + "\xd1\x79\x82\xe0\x0f\xdf\x08\x3c\x60\x21\x6f\x31\x47\x98\xae\x2f" + "\xcb\xb1\xa1\xb9\xc1\xa3\x71\x5e\x4a\xc2\x67\xdf\x66\x0a\x51\xb5" + "\xad\x60\x05\xdb\x02\xd4\x1a\xd2\xb9\x4e\x01\x08\x2b\xc3\x57\xaf", + 624 }, + { + "\x30\x82\x02\x54\x30\x82\x01\xbd\xa0\x03\x02\x01\x02\x02\x01\x08" + "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30" + "\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30" + "\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b" + "\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30\x1e\x17\x0d\x30" + "\x39\x30\x34\x32\x36\x32\x30\x32\x39\x34\x30\x5a\x17\x0d\x31\x39" + "\x30\x34\x32\x34\x32\x30\x32\x39\x34\x30\x5a\x30\x1b\x31\x0b\x30" + "\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x31\x0c\x30\x0a\x06\x03" + "\x55\x04\x03\x0c\x03\x6b\x64\x63\x30\x81\x9f\x30\x0d\x06\x09\x2a" + "\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81" + "\x89\x02\x81\x81\x00\xd2\x41\x7a\xf8\x4b\x55\xb2\xaf\x11\xf9\x43" + "\x9b\x43\x81\x09\x3b\x9a\x94\xcf\x00\xf4\x85\x75\x92\xd7\x2a\xa5" + "\x11\xf1\xa8\x50\x6e\xc6\x84\x74\x24\x17\xda\x84\xc8\x03\x37\xb2" + "\x20\xf3\xba\xb5\x59\x36\x21\x4d\xab\x70\xe2\xc3\x09\x93\x68\x14" + "\x12\x79\xc5\xbb\x9e\x1b\x4a\xf0\xc6\x24\x59\x25\xc3\x1c\xa8\x70" + "\x66\x5b\x3e\x41\x8e\xe3\x25\x71\x9a\x94\xa0\x5b\x46\x91\x6f\xdd" + "\x58\x14\xec\x89\xe5\x8c\x96\xc5\x38\x60\xe4\xab\xf2\x75\xee\x6e" + "\x62\xfc\xe1\xbd\x03\x47\xff\xc4\xbe\x0f\xca\x70\x73\xe3\x74\x58" + "\x3a\x2f\x04\x2d\x39\x02\x03\x01\x00\x01\xa3\x81\x98\x30\x81\x95" + "\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55" + "\x1d\x0f\x04\x04\x03\x02\x05\xe0\x30\x12\x06\x03\x55\x1d\x25\x04" + "\x0b\x30\x09\x06\x07\x2b\x06\x01\x05\x02\x03\x05\x30\x1d\x06\x03" + "\x55\x1d\x0e\x04\x16\x04\x14\x3a\xd3\x73\xff\xab\xdb\x7d\x8d\xc6" + "\x3a\xa2\x26\x3e\xae\x78\x95\x80\xc9\xe6\x31\x30\x48\x06\x03\x55" + "\x1d\x11\x04\x41\x30\x3f\xa0\x3d\x06\x06\x2b\x06\x01\x05\x02\x02" + "\xa0\x33\x30\x31\xa0\x0d\x1b\x0b\x54\x45\x53\x54\x2e\x48\x35\x4c" + "\x2e\x53\x45\xa1\x20\x30\x1e\xa0\x03\x02\x01\x01\xa1\x17\x30\x15" + "\x1b\x06\x6b\x72\x62\x74\x67\x74\x1b\x0b\x54\x45\x53\x54\x2e\x48" + "\x35\x4c\x2e\x53\x45\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01" + "\x01\x05\x05\x00\x03\x81\x81\x00\x83\xf4\x14\xa7\x6e\x59\xff\x80" + "\x64\xe7\xfa\xcf\x13\x80\x86\xe1\xed\x02\x38\xad\x96\x72\x25\xe5" + "\x06\x7a\x9a\xbc\x24\x74\xa9\x75\x55\xb2\x49\x80\x69\x45\x95\x4a" + "\x4c\x76\xa9\xe3\x4e\x49\xd3\xc2\x69\x5a\x95\x03\xeb\xba\x72\x23" + "\x9c\xfd\x3d\x8b\xc6\x07\x82\x3b\xf4\xf3\xef\x6c\x2e\x9e\x0b\xac" + "\x9e\x6c\xbb\x37\x4a\xa1\x9e\x73\xd1\xdc\x97\x61\xba\xfc\xd3\x49" + "\xa6\xc2\x4c\x55\x2e\x06\x37\x76\xb5\xef\x57\xe7\x57\x58\x8a\x71" + "\x63\xf3\xeb\xe7\x55\x68\x0d\xf6\x46\x4c\xfb\xf9\x43\xbb\x0c\x92" + "\x4f\x4e\x22\x7b\x63\xe8\x4f\x9c", + 600 + } +}; + +static int +test_cert(void) +{ + Certificate c, c2; + size_t size; + size_t i; + int ret; + + memset(&c, 0, sizeof(c)); + ret = copy_Certificate(&c, &c2); + if (ret) + return ret; + free_Certificate(&c2); + + for (i = 0; i < sizeof(certs)/sizeof(certs[0]); i++) { + + ret = decode_Certificate((unsigned char *)certs[i].cert, + certs[i].len, &c, &size); + if (ret) + return ret; + + ret = copy_Certificate(&c, &c2); + free_Certificate(&c); + if (ret) + return ret; + + free_Certificate(&c2); + } + + return 0; +} + +struct { + const char *sd; + size_t len; +} signeddata[] = { + { + "\x30\x80\x02\x01\x03\x31\x0b\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a" + "\x05\x00\x30\x80\x06\x07\x2b\x06\x01\x05\x02\x03\x03\xa0\x80\x24" + "\x80\x04\x50\x30\x4e\xa0\x2b\x30\x29\xa0\x03\x02\x01\x12\xa1\x22" + "\x04\x20\x78\xf4\x86\x31\xc6\xc2\xc9\xcb\xef\x0c\xd7\x3a\x2a\xcd" + "\x8c\x13\x34\x83\xb1\x5c\xa8\xbe\xbf\x2f\xea\xd2\xbb\xd8\x8c\x18" + "\x47\x01\xa1\x1f\x30\x1d\xa0\x03\x02\x01\x0c\xa1\x16\x04\x14\xa6" + "\x2c\x52\xb2\x80\x98\x30\x40\xbc\x5f\xb0\x77\x2d\x8a\xd7\xa1\xda" + "\x3c\xc5\x62\x00\x00\x00\x00\x00\x00\xa0\x82\x02\x09\x30\x82\x02" + "\x05\x30\x82\x01\x6e\xa0\x03\x02\x01\x02\x02\x04\x49\x75\x57\xbf" + "\x30\x0b\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x30\x3b\x31" + "\x1f\x30\x1d\x06\x03\x55\x04\x03\x0c\x16\x63\x6f\x6d\x2e\x61\x70" + "\x70\x6c\x65\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73\x2e\x6b\x64\x63" + "\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53\x79\x73\x74\x65" + "\x6d\x20\x49\x64\x65\x6e\x74\x69\x74\x79\x30\x1e\x17\x0d\x30\x39" + "\x31\x32\x30\x34\x30\x30\x32\x30\x32\x34\x5a\x17\x0d\x32\x39\x31" + "\x31\x32\x39\x30\x30\x32\x30\x32\x34\x5a\x30\x3b\x31\x1f\x30\x1d" + "\x06\x03\x55\x04\x03\x0c\x16\x63\x6f\x6d\x2e\x61\x70\x70\x6c\x65" + "\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73\x2e\x6b\x64\x63\x31\x18\x30" + "\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53\x79\x73\x74\x65\x6d\x20\x49" + "\x64\x65\x6e\x74\x69\x74\x79\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86" + "\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89" + "\x02\x81\x81\x00\xb2\xc5\x4b\x34\xe3\x93\x99\xbb\xaa\xd1\x70\x62" + "\x6c\x9c\xcc\xa6\xbc\x47\xc3\x23\xff\x15\xb9\x11\x27\x0a\xf8\x55" + "\x4c\xb2\x43\x34\x75\xad\x55\xbb\xb9\x8a\xd0\x25\x64\xa4\x8c\x82" + "\x74\x5d\x89\x52\xe2\x76\x75\x08\x67\xb5\x9c\x9c\x69\x86\x0c\x6d" + "\x79\xf7\xa0\xbe\x42\x8f\x90\x46\x0c\x18\xf4\x7a\x56\x17\xa4\x65" + "\x00\x3a\x5e\x3e\xbf\xbc\xf5\xe2\x2c\x26\x03\x52\xdd\xd4\x85\x3f" + "\x03\xd7\x0c\x45\x7f\xff\xdd\x1e\x70\x6c\x9f\xb0\x8c\xd0\x33\xad" + "\x92\x54\x17\x9d\x88\x89\x1a\xee\xef\xf7\x96\x3e\x68\xc3\xd1\x60" + "\x47\x86\x80\x5d\x02\x03\x01\x00\x01\xa3\x18\x30\x16\x30\x14\x06" + "\x03\x55\x1d\x25\x04\x0d\x30\x0b\x06\x09\x2a\x86\x48\x86\xf7\x63" + "\x64\x04\x04\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05" + "\x05\x00\x03\x81\x81\x00\x9b\xbb\xaa\x63\x66\xd8\x70\x84\x3e\xf6" + "\xa1\x3b\xf3\xe6\xd7\x3d\xfc\x4f\xc9\x45\xaa\x31\x43\x8d\xb5\x72" + "\xe4\x34\x95\x7b\x6e\x5f\xe5\xc8\x5e\xaf\x12\x08\x6d\xd7\x25\x76" + "\x40\xd5\xdc\x83\x7f\x2f\x74\xd1\x63\xc0\x7c\x26\x4d\x53\x10\xe7" + "\xfa\xcc\xf2\x60\x41\x63\xdf\x56\xd6\xd9\xc0\xb4\xd0\x73\x99\x54" + "\x40\xad\x90\x79\x2d\xd2\x5e\xcb\x13\x22\x2b\xd0\x76\xef\x8a\x48" + "\xfd\xb2\x6e\xca\x04\x4e\x91\x3f\xb4\x63\xad\x22\x3a\xf7\x20\x9c" + "\x4c\x0e\x47\x78\xe5\x2a\x85\x0e\x90\x7a\xce\x46\xe6\x15\x02\xb0" + "\x83\xe7\xac\xfa\x92\xf8\x31\x81\xe8\x30\x81\xe5\x02\x01\x01\x30" + "\x43\x30\x3b\x31\x1f\x30\x1d\x06\x03\x55\x04\x03\x0c\x16\x63\x6f" + "\x6d\x2e\x61\x70\x70\x6c\x65\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73" + "\x2e\x6b\x64\x63\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53" + "\x79\x73\x74\x65\x6d\x20\x49\x64\x65\x6e\x74\x69\x74\x79\x02\x04" + "\x49\x75\x57\xbf\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x30" + "\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x04\x81" + "\x80\x50\x2c\x69\xe1\xd2\xc4\xd1\xcc\xdc\xe0\xe9\x8a\x6b\x6a\x97" + "\x1b\xb4\xe0\xa8\x20\xbe\x09\x6d\xe1\x55\x5f\x07\x70\x94\x2e\x14" + "\xed\x4e\xb1\x69\x75\x40\xbb\x99\x87\xed\x23\x50\x27\x5f\xaa\xc4" + "\x84\x60\x06\xfe\x45\xfd\x7e\x1b\x18\xe0\x0b\x77\x35\x2a\xb2\xf2" + "\xe0\x88\x31\xad\x82\x31\x4a\xbc\x6d\x71\x62\xe6\x4d\x33\xb4\x09" + "\x6e\x3f\x14\x12\xf2\x89\x29\x31\x84\x60\x2b\xa8\x2d\xe6\xca\x2f" + "\x03\x3d\xd4\x69\x89\xb3\x98\xfd\xac\x63\x14\xaf\x6a\x52\x2a\xac" + "\xe3\x8e\xfa\x21\x41\x8f\xcc\x04\x2d\x52\xee\x49\x54\x0d\x58\x51" + "\x77\x00\x00", + 883 + } +}; + +static int +test_SignedData(void) +{ + SignedData sd; + size_t size, i; + int ret; + + for (i = 0; i < sizeof(signeddata) / sizeof(signeddata[0]); i++) { + + ret = decode_SignedData((unsigned char *)signeddata[i].sd, + signeddata[i].len, &sd, &size); + if (ret) + return ret; + + free_SignedData(&sd); + } + + return 0; +} + + +static int +cmp_TESTLargeTag (void *a, void *b) +{ + TESTLargeTag *aa = a; + TESTLargeTag *ab = b; + + COMPARE_INTEGER(aa,ab,foo); + COMPARE_INTEGER(aa,ab,bar); + return 0; +} + +static int +test_large_tag (void) +{ + struct test_case tests[] = { + { NULL, 15, "\x30\x0d\xbf\x7f\x03\x02\x01\x01\xbf\x81\x00\x03\x02\x01\x02", "large tag 1" } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TESTLargeTag lt1; + + memset(<1, 0, sizeof(lt1)); + lt1.foo = 1; + lt1.bar = 2; + + tests[0].val = <1; + + return generic_test (tests, ntests, sizeof(TESTLargeTag), + (generic_encode)encode_TESTLargeTag, + (generic_length)length_TESTLargeTag, + (generic_decode)decode_TESTLargeTag, + (generic_free)free_TESTLargeTag, + cmp_TESTLargeTag, + (generic_copy)copy_TESTLargeTag); +} + +struct test_data { + int ok; + size_t len; + size_t expected_len; + void *data; +}; + +static int +check_tag_length(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 3, 3, "\x02\x01\x7f"}, + { 1, 4, 4, "\x02\x02\x00\x80"}, + { 1, 4, 4, "\x02\x02\x01\x00"}, + { 1, 4, 4, "\x02\x02\x02\x00"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTuint32 values[] = {0, 127, 128, 256, 512, + 0, 127, 128, 256, 512 }; + TESTuint32 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTuint32(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +check_tag_length64(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\x01\xff\xff\xff\xff"}, + { 1, 7, 7, "\x02\x05\x02\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x7f\xff\xff\xff\xff\xff\xff"}, + { 1, 10, 10, "\x02\x08\x00\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff"}, + { 1, 11, 11, "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTuint64 values[] = {0, 8589934591LL, 8589934592LL, + 36028797018963967LL, 36028797018963968LL, + 9223372036854775807LL, 18446744073709551615ULL, + 0, 127, 128, 256, 512 }; + TESTuint64 u; + int i, ret, failed = 0; + void *buf; + + if (sizeof(TESTuint64) != sizeof(uint64_t)) { + ret += 1; + printf("sizeof(TESTuint64) %d != sizeof(uint64_t) %d\n", + (int)sizeof(TESTuint64), (int)sizeof(uint64_t)); + } + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTuint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %lu\n", (unsigned long)sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %llu\nActual value: %llu\n", + (unsigned long long)values[i], (unsigned long long)u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +check_tag_length64s(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x01"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x80\x00\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTint64 values[] = {0, -8589934591LL, -8589934592LL, + -36028797018963967LL, -36028797018963968LL, + -9223372036854775807LL, -36028797018963967LL, + 0, 127, 128, 256, 512 }; + TESTint64 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %lu\n", (unsigned long)sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %lld\nActual value: %lld\n", + (long long)values[i], (long long)u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +cmp_TESTChoice (void *a, void *b) +{ + return 0; +} + +static int +test_choice (void) +{ + struct test_case tests[] = { + { NULL, 5, "\xa1\x03\x02\x01\x01", "large choice 1" }, + { NULL, 5, "\xa2\x03\x02\x01\x02", "large choice 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTChoice1 c1; + TESTChoice1 c2_1; + TESTChoice2 c2_2; + + memset(&c1, 0, sizeof(c1)); + c1.element = choice_TESTChoice1_i1; + c1.u.i1 = 1; + tests[0].val = &c1; + + memset(&c2_1, 0, sizeof(c2_1)); + c2_1.element = choice_TESTChoice1_i2; + c2_1.u.i2 = 2; + tests[1].val = &c2_1; + + ret += generic_test (tests, ntests, sizeof(TESTChoice1), + (generic_encode)encode_TESTChoice1, + (generic_length)length_TESTChoice1, + (generic_decode)decode_TESTChoice1, + (generic_free)free_TESTChoice1, + cmp_TESTChoice, + (generic_copy)copy_TESTChoice1); + + memset(&c2_2, 0, sizeof(c2_2)); + c2_2.element = choice_TESTChoice2_asn1_ellipsis; + c2_2.u.asn1_ellipsis.data = "\xa2\x03\x02\x01\x02"; + c2_2.u.asn1_ellipsis.length = 5; + tests[1].val = &c2_2; + + ret += generic_test (tests, ntests, sizeof(TESTChoice2), + (generic_encode)encode_TESTChoice2, + (generic_length)length_TESTChoice2, + (generic_decode)decode_TESTChoice2, + (generic_free)free_TESTChoice2, + cmp_TESTChoice, + (generic_copy)copy_TESTChoice2); + + return ret; +} + +/* Test --decorate=TYPE:FIELD-TYPE:field-name[?] */ +static int +test_decorated(void) +{ + TESTNotDecorated tnd; + TESTDecorated td, td_copy; + size_t len, size; + void *ptr; + int ret; + + memset(&td, 0, sizeof(td)); + memset(&tnd, 0, sizeof(tnd)); + + my_copy_vers_called = 0; + my_free_vers_called = 0; + + td.version = 3; + td.version3.v = 5; + td.privthing = &td; + if ((td.version2 = malloc(sizeof(*td.version2))) == NULL) + errx(1, "out of memory"); + *td.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecorated, ptr, len, &td, &size, ret); + if (ret) { + warnx("could not encode a TESTDecorated struct"); + return 1; + } + ret = decode_TESTNotDecorated(ptr, len, &tnd, &size); + if (ret) { + warnx("could not decode a TESTDecorated struct as TESTNotDecorated"); + return 1; + } + free(ptr); + if (size != len) { + warnx("TESTDecorated encoded size mismatch"); + return 1; + } + if (td.version != tnd.version) { + warnx("TESTDecorated did not decode as a TESTNotDecorated correctly"); + return 1; + } + if (copy_TESTDecorated(&td, &td_copy)) { + warnx("copy_TESTDecorated() failed"); + return 1; + } + if (td.version != td_copy.version) { + warnx("copy_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td_copy.version2 == NULL || *td.version2 != *td_copy.version2) { + warnx("copy_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.version3.v != td_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecorated() did not work correctly (3)"); + return 1; + } + if (td_copy.privthing != 0) { + warnx("copy_TESTDecorated() did not work correctly (4)"); + return 1; + } + + free_TESTDecorated(&td_copy); + free_TESTDecorated(&td); + if (td.version2) { + warnx("free_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.privthing != 0) { + warnx("free_TESTDecorated() did not work correctly (3)"); + return 1; + } + return 0; +} + +static int +test_extensible_choice(void) +{ + PA_FX_FAST_REQUEST r, r2; + size_t len, size; + void *ptr; + int ret; + + memset(&r, 0, sizeof(r)); + + ret = copy_PA_FX_FAST_REQUEST(&r, &r2); + if (ret) + return ret; + free_PA_FX_FAST_REQUEST(&r2); + + r.element = 0; + r.u.asn1_ellipsis.data = "hello"; + r.u.asn1_ellipsis.length = sizeof("hello") - 1; + ret = copy_PA_FX_FAST_REQUEST(&r, &r2); + if (ret) + errx(1, "Out of memory"); + if (r2.element != 0) + errx(1, "Extensible CHOICE copy failure to set discriminant to 0"); + if (r2.u.asn1_ellipsis.length != r.u.asn1_ellipsis.length) + errx(1, "Extensible CHOICE copy failure to copy extension"); + if (memcmp(r.u.asn1_ellipsis.data, r2.u.asn1_ellipsis.data, + r.u.asn1_ellipsis.length) != 0) + errx(1, "Extensible CHOICE copy failure to copy extension (2)"); + free_PA_FX_FAST_REQUEST(&r2); + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, ptr, len, &r, &size, ret); + if (ret || len != size) + errx(1, "Extensible CHOICE encoding failure"); + + ret = decode_PA_FX_FAST_REQUEST(ptr, len, &r2, &size); + if (ret || len != size) + errx(1, "Extensible CHOICE decoding failure"); + + if (r2.element != 0) + errx(1, "Extensible CHOICE decode failure to set discriminant to 0"); + if (r2.u.asn1_ellipsis.length != r.u.asn1_ellipsis.length) + errx(1, "Extensible CHOICE decode failure to copy extension"); + if (memcmp(r.u.asn1_ellipsis.data, r2.u.asn1_ellipsis.data, + r.u.asn1_ellipsis.length) != 0) + errx(1, "Extensible CHOICE decode failure to copy extension (2)"); + + free_PA_FX_FAST_REQUEST(&r2); + free(ptr); + return 0; +} + +static int +test_decorated_choice(void) +{ + TESTNotDecoratedChoice tndc; + TESTDecoratedChoice tdc, tdc_copy; + size_t len, size; + void *ptr; + int ret; + + memset(&tdc, 0, sizeof(tdc)); + memset(&tndc, 0, sizeof(tndc)); + + my_copy_vers_called = 0; + my_free_vers_called = 0; + + tdc.element = choice_TESTDecoratedChoice_version; + tdc.u.version = 3; + tdc.version3.v = 5; + tdc.privthing = &tdc; + if ((tdc.version2 = malloc(sizeof(*tdc.version2))) == NULL) + errx(1, "out of memory"); + *tdc.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecoratedChoice, ptr, len, &tdc, &size, ret); + if (ret) { + warnx("could not encode a TESTDecoratedChoice struct"); + return 1; + } + ret = decode_TESTNotDecoratedChoice(ptr, len, &tndc, &size); + if (ret) { + warnx("could not decode a TESTDecoratedChoice struct as TESTNotDecoratedChoice"); + return 1; + } + free(ptr); + if (size != len) { + warnx("TESTDecoratedChoice encoded size mismatch"); + return 1; + } + if ((int)tdc.element != (int)tndc.element || + tdc.u.version != tndc.u.version) { + warnx("TESTDecoratedChoice did not decode as a TESTNotDecoratedChoice correctly"); + return 1; + } + if (copy_TESTDecoratedChoice(&tdc, &tdc_copy)) { + warnx("copy_TESTDecoratedChoice() failed"); + return 1; + } + if ((int)tdc.element != (int)tdc_copy.element || + tdc.u.version != tdc_copy.u.version) { + warnx("copy_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc_copy.version2 == NULL || *tdc.version2 != *tdc_copy.version2) { + warnx("copy_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.version3.v != tdc_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecoratedChoice() did not work correctly (3)"); + return 1; + } + if (tdc_copy.privthing != 0) { + warnx("copy_TESTDecoratedChoice() did not work correctly (4)"); + return 1; + } + + free_TESTDecoratedChoice(&tdc_copy); + free_TESTDecoratedChoice(&tdc); + if (tdc.version2) { + warnx("free_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.privthing != 0) { + warnx("free_TESTDecoratedChoice() did not work correctly (3)"); + return 1; + } + return 0; +} + + +static int +cmp_TESTImplicit (void *a, void *b) +{ + TESTImplicit *aa = a; + TESTImplicit *ab = b; + + COMPARE_INTEGER(aa,ab,ti1); + COMPARE_INTEGER(aa,ab,ti2.foo); + COMPARE_INTEGER(aa,ab,ti3); + return 0; +} + +static int +cmp_TESTImplicit2 (void *a, void *b) +{ + TESTImplicit2 *aa = a; + TESTImplicit2 *ab = b; + + COMPARE_INTEGER(aa,ab,ti1); + COMPARE_INTEGER(aa,ab,ti3); + IF_OPT_COMPARE(aa,ab,ti4) { + COMPARE_INTEGER(aa,ab,ti4[0]); + } + return 0; +} + +static int +cmp_TESTImplicit3 (void *a, void *b) +{ + TESTImplicit3 *aa = a; + TESTImplicit3 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit3_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} + +static int +cmp_TESTImplicit4 (void *a, void *b) +{ + TESTImplicit4 *aa = a; + TESTImplicit4 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit4_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} + +static int +test_implicit (void) +{ + int ret = 0; + /* + * UNIV CONS Sequence = 14 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT CONS tag 1 = 6 bytes [1] + * CONTEXT CONS tag 127 = 3 bytes [127] + * UNIV PRIM Integer = integer 2 + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * } + */ + struct test_case tests[] = { + { NULL, 16, + "\x30\x0e\x80\x01\x00\xa1\x06\xbf\x7f\x03\x02\x01\x02\x82\x01\x03", + "implicit 1" } + }; + /* + * UNIV CONS Sequence = 10 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * CONTEXT PRIM tag 51 = 1 bytes [51] IMPLICIT content + * } + */ + struct test_case tests2[] = { + { NULL, 12, + "\x30\x0a\x80\x01\x01\x82\x01\x03\x9f\x33\x01\x04", + "implicit 2" } + }; + /* + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests3[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 3" } + }; + /* + * Notice: same as tests3[].bytes. + * + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests4[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 4" } + }; + + TESTImplicit c0; + TESTImplicit2 c1; + TESTImplicit3 c2; + TESTImplicit4 c3; + int ti4 = 4; + + memset(&c0, 0, sizeof(c0)); + c0.ti1 = 0; + c0.ti2.foo = 2; + c0.ti3 = 3; + tests[0].val = &c0; + + memset(&c1, 0, sizeof(c1)); + c1.ti1 = 1; + c1.ti3 = 3; + c1.ti4 = &ti4; + tests2[0].val = &c1; + + memset(&c2, 0, sizeof(c2)); + c2.element = choice_TESTImplicit3_ti2; + c2.u.ti2.element = choice_TESTImplicit3_ti2_i1; + c2.u.ti2.u.i1 = 5; + tests3[0].val = &c2; + + memset(&c3, 0, sizeof(c3)); + c3.element = choice_TESTImplicit4_ti2; + c3.u.ti2.element = choice_TESTChoice2_i1; + c3.u.ti2.u.i1 = 5; + tests4[0].val = &c3; + + ret += generic_test(tests, + sizeof(tests) / sizeof(*tests), + sizeof(TESTImplicit), + (generic_encode)encode_TESTImplicit, + (generic_length)length_TESTImplicit, + (generic_decode)decode_TESTImplicit, + (generic_free)free_TESTImplicit, + cmp_TESTImplicit, + (generic_copy)copy_TESTImplicit); + + ret += generic_test(tests2, + sizeof(tests2) / sizeof(*tests2), + sizeof(TESTImplicit2), + (generic_encode)encode_TESTImplicit2, + (generic_length)length_TESTImplicit2, + (generic_decode)decode_TESTImplicit2, + (generic_free)free_TESTImplicit2, + cmp_TESTImplicit2, + NULL); + + ret += generic_test(tests3, + sizeof(tests3) / sizeof(*tests3), + sizeof(TESTImplicit3), + (generic_encode)encode_TESTImplicit3, + (generic_length)length_TESTImplicit3, + (generic_decode)decode_TESTImplicit3, + (generic_free)free_TESTImplicit3, + cmp_TESTImplicit3, + NULL); + + ret += generic_test(tests4, + sizeof(tests4) / sizeof(*tests4), + sizeof(TESTImplicit4), + (generic_encode)encode_TESTImplicit4, + (generic_length)length_TESTImplicit4, + (generic_decode)decode_TESTImplicit4, + (generic_free)free_TESTImplicit4, + cmp_TESTImplicit4, + NULL); + + return ret; +} + +static int +cmp_TESTAlloc (void *a, void *b) +{ + TESTAlloc *aa = a; + TESTAlloc *ab = b; + + IF_OPT_COMPARE(aa,ab,tagless) { + COMPARE_INTEGER(aa,ab,tagless->ai); + } + + COMPARE_INTEGER(aa,ab,three); + + IF_OPT_COMPARE(aa,ab,tagless2) { + COMPARE_OPT_OCTET_STRING(aa, ab, tagless2); + } + + return 0; +} + +/* +UNIV CONS Sequence 12 + UNIV CONS Sequence 5 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 01 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 5 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 8 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 04 + UNIV PRIM Integer 1 05 + +*/ + +static int +test_taglessalloc (void) +{ + struct test_case tests[] = { + { NULL, 14, + "\x30\x0c\x30\x05\xa0\x03\x02\x01\x01\xa1\x03\x02\x01\x03", + "alloc 1" }, + { NULL, 7, + "\x30\x05\xa1\x03\x02\x01\x03", + "alloc 2" }, + { NULL, 10, + "\x30\x08\xa1\x03\x02\x01\x04\x02\x01\x05", + "alloc 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTAlloc c1, c2, c3; + heim_any any3; + + memset(&c1, 0, sizeof(c1)); + c1.tagless = ecalloc(1, sizeof(*c1.tagless)); + c1.tagless->ai = 1; + c1.three = 3; + tests[0].val = &c1; + + memset(&c2, 0, sizeof(c2)); + c2.tagless = NULL; + c2.three = 3; + tests[1].val = &c2; + + memset(&c3, 0, sizeof(c3)); + c3.tagless = NULL; + c3.three = 4; + c3.tagless2 = &any3; + any3.data = "\x02\x01\x05"; + any3.length = 3; + tests[2].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTAlloc), + (generic_encode)encode_TESTAlloc, + (generic_length)length_TESTAlloc, + (generic_decode)decode_TESTAlloc, + (generic_free)free_TESTAlloc, + cmp_TESTAlloc, + (generic_copy)copy_TESTAlloc); + + free(c1.tagless); + + return ret; +} + +static int +cmp_TESTOptional (void *a, void *b) +{ + TESTOptional *aa = a; + TESTOptional *ab = b; + + IF_OPT_COMPARE(aa,ab,zero) { + COMPARE_OPT_INTEGER(aa,ab,zero); + } + IF_OPT_COMPARE(aa,ab,one) { + COMPARE_OPT_INTEGER(aa,ab,one); + } + return 0; +} + +/* +UNIV CONS Sequence 5 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + +UNIV CONS Sequence 5 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 10 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 01 + +*/ + +static int +test_optional (void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "optional 0" }, + { NULL, 7, + "\x30\x05\xa0\x03\x02\x01\x00", + "optional 1" }, + { NULL, 7, + "\x30\x05\xa1\x03\x02\x01\x01", + "optional 2" }, + { NULL, 12, + "\x30\x0a\xa0\x03\x02\x01\x00\xa1\x03\x02\x01\x01", + "optional 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTOptional c0, c1, c2, c3; + int zero = 0; + int one = 1; + + c0.zero = NULL; + c0.one = NULL; + tests[0].val = &c0; + + c1.zero = &zero; + c1.one = NULL; + tests[1].val = &c1; + + c2.zero = NULL; + c2.one = &one; + tests[2].val = &c2; + + c3.zero = &zero; + c3.one = &one; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTOptional), + (generic_encode)encode_TESTOptional, + (generic_length)length_TESTOptional, + (generic_decode)decode_TESTOptional, + (generic_free)free_TESTOptional, + cmp_TESTOptional, + (generic_copy)copy_TESTOptional); + + return ret; +} + +static int +check_fail_largetag(void) +{ + struct test_case tests[] = { + {NULL, 14, "\x30\x0c\xbf\x87\xff\xff\xff\xff\xff\x7f\x03\x02\x01\x01", + "tag overflow"}, + {NULL, 0, "", "empty buffer"}, + {NULL, 7, "\x30\x05\xa1\x03\x02\x02\x01", + "one too short" }, + {NULL, 7, "\x30\x04\xa1\x03\x02\x02\x01", + "two too short" }, + {NULL, 7, "\x30\x03\xa1\x03\x02\x02\x01", + "three too short" }, + {NULL, 7, "\x30\x02\xa1\x03\x02\x02\x01", + "four too short" }, + {NULL, 7, "\x30\x01\xa1\x03\x02\x02\x01", + "five too short" }, + {NULL, 7, "\x30\x00\xa1\x03\x02\x02\x01", + "six too short" }, + {NULL, 7, "\x30\x05\xa1\x04\x02\x02\x01", + "inner one too long" }, + {NULL, 7, "\x30\x00\xa1\x02\x02\x02\x01", + "inner one too short" }, + {NULL, 8, "\x30\x05\xbf\x7f\x03\x02\x02\x01", + "inner one too short"}, + {NULL, 8, "\x30\x06\xbf\x64\x03\x02\x01\x01", + "wrong tag"}, + {NULL, 10, "\x30\x08\xbf\x9a\x9b\x38\x03\x02\x01\x01", + "still wrong tag"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTLargeTag), + (generic_decode)decode_TESTLargeTag); +} + + +static int +check_fail_sequence(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty buffer"}, + {NULL, 24, + "\x30\x16\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01\x01" + "\x02\x01\x01\xa2\x03\x02\x01\x01", + "missing one byte from the end, internal length ok"}, + {NULL, 25, + "\x30\x18\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01\x01" + "\x02\x01\x01\xa2\x03\x02\x01\x01", + "inner length one byte too long"}, + {NULL, 24, + "\x30\x17\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01" + "\x01\x02\x01\x01\xa2\x03\x02\x01\x01", + "correct buffer but missing one too short"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTSeq), + (generic_decode)decode_TESTSeq); +} + +static int +check_fail_choice(void) +{ + struct test_case tests[] = { + {NULL, 6, + "\xa1\x02\x02\x01\x01", + "choice one too short"}, + {NULL, 6, + "\xa1\x03\x02\x02\x01", + "choice one too short inner"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTChoice1), + (generic_decode)decode_TESTChoice1); +} + +static int +check_fail_Ticket(void) +{ + char buf[100]; + size_t i; + int ret; + struct test_case test; + Ticket ticket; + + for (i = 0; i < sizeof(buf); i++) { + memset(buf, 0, sizeof(buf)); + memset(&ticket, 0, sizeof(ticket)); + test.val = &ticket; + test.byte_len = i; + test.bytes = buf; + test.name = "zero life"; + ret = generic_decode_fail(&test, 1, sizeof(Ticket), + (generic_decode)decode_Ticket); + if (ret) + return ret; + } + return 0; +} + +static int +check_seq(void) +{ + TESTSeqOf seq; + TESTInteger i = 0; + int ret; + + seq.val = NULL; + seq.len = 0; + + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + + ret = remove_TESTSeqOf(&seq, seq.len - 1); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 2); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret == 0) { + printf("can remove from empty list"); + return 1; + } + + if (seq.len != 0) { + printf("seq not empty!"); + return 1; + } + free_TESTSeqOf(&seq); + ret = 0; + +out: + + return ret; +} + +#define test_seq_of(type, ok, ptr) \ +{ \ + heim_octet_string os; \ + size_t size; \ + type decode; \ + ASN1_MALLOC_ENCODE(type, os.data, os.length, ptr, &size, ret); \ + if (ret) \ + return ret; \ + if (os.length != size) \ + abort(); \ + ret = decode_##type(os.data, os.length, &decode, &size); \ + free(os.data); \ + if (ret) { \ + if (ok) \ + return 1; \ + } else { \ + free_##type(&decode); \ + if (!ok) \ + return 1; \ + if (size != 0) \ + return 1; \ + } \ + return 0; \ +} + +static int +check_seq_of_size(void) +{ +#if 0 /* template */ + TESTInteger integers[4] = { 1, 2, 3, 4 }; + int ret; + + { + TESTSeqSizeOf1 ssof1f1 = { 1, integers }; + TESTSeqSizeOf1 ssof1ok1 = { 2, integers }; + TESTSeqSizeOf1 ssof1f2 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf1, 0, &ssof1f1); + test_seq_of(TESTSeqSizeOf1, 1, &ssof1ok1); + test_seq_of(TESTSeqSizeOf1, 0, &ssof1f2); + } + { + TESTSeqSizeOf2 ssof2f1 = { 0, NULL }; + TESTSeqSizeOf2 ssof2ok1 = { 1, integers }; + TESTSeqSizeOf2 ssof2ok2 = { 2, integers }; + TESTSeqSizeOf2 ssof2f2 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf2, 0, &ssof2f1); + test_seq_of(TESTSeqSizeOf2, 1, &ssof2ok1); + test_seq_of(TESTSeqSizeOf2, 1, &ssof2ok2); + test_seq_of(TESTSeqSizeOf2, 0, &ssof2f2); + } + { + TESTSeqSizeOf3 ssof3f1 = { 0, NULL }; + TESTSeqSizeOf3 ssof3ok1 = { 1, integers }; + TESTSeqSizeOf3 ssof3ok2 = { 2, integers }; + + test_seq_of(TESTSeqSizeOf3, 0, &ssof3f1); + test_seq_of(TESTSeqSizeOf3, 1, &ssof3ok1); + test_seq_of(TESTSeqSizeOf3, 1, &ssof3ok2); + } + { + TESTSeqSizeOf4 ssof4ok1 = { 0, NULL }; + TESTSeqSizeOf4 ssof4ok2 = { 1, integers }; + TESTSeqSizeOf4 ssof4ok3 = { 2, integers }; + TESTSeqSizeOf4 ssof4f1 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok1); + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok2); + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok3); + test_seq_of(TESTSeqSizeOf4, 0, &ssof4f1); + } +#endif + return 0; +} + +static int +check_TESTMechTypeList(void) +{ + TESTMechTypeList tl; + unsigned oid1[] = { 1, 2, 840, 48018, 1, 2, 2}; + unsigned oid2[] = { 1, 2, 840, 113554, 1, 2, 2}; + unsigned oid3[] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 30}; + unsigned oid4[] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10}; + TESTMechType array[] = {{ 7, oid1 }, + { 7, oid2 }, + { 10, oid3 }, + { 10, oid4 }}; + size_t size, len; + void *ptr; + int ret; + + tl.len = 4; + tl.val = array; + + ASN1_MALLOC_ENCODE(TESTMechTypeList, ptr, len, &tl, &size, ret); + if (ret) + errx(1, "TESTMechTypeList: %d", ret); + if (len != size) + abort(); + free(ptr); + return 0; +} + +static int +cmp_TESTSeqOf4(void *a, void *b) +{ + TESTSeqOf4 *aa = a; + TESTSeqOf4 *ab = b; + int i; + + IF_OPT_COMPARE(aa, ab, b1) { + COMPARE_INTEGER(aa->b1, ab->b1, len); + for (i = 0; i < aa->b1->len; ++i) { + COMPARE_INTEGER(aa->b1->val+i, ab->b1->val+i, u1); + COMPARE_INTEGER(aa->b1->val+i, ab->b1->val+i, u2); + COMPARE_OCTET_STRING(aa->b1->val+i, ab->b1->val+i, s1); + COMPARE_OCTET_STRING(aa->b1->val+i, ab->b1->val+i, s2); + } + } + IF_OPT_COMPARE(aa, ab, b2) { + COMPARE_INTEGER(aa->b2, ab->b2, len); + for (i = 0; i < aa->b2->len; ++i) { + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u1); + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u2); + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u3); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s1); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s2); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s3); + } + } + IF_OPT_COMPARE(aa, ab, b3) { + COMPARE_INTEGER(aa->b3, ab->b3, len); + for (i = 0; i < aa->b3->len; ++i) { + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u1); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u2); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u3); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u4); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s1); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s2); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s3); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s4); + } + } + return 0; +} + +static int +test_seq4 (void) +{ + int ret = 0; + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seq4 0" }, + { NULL, 4, + "\x30\x02" "\xa1\x00", + "seq4 1" }, + { NULL, 8, + "\x30\x06" "\xa0\x02\x30\x00" "\xa1\x00", + "seq4 2" }, + { NULL, 2 + (2 + 0x18) + (2 + 0x27) + (2 + 0x31), + "\x30\x76" /* 2 SEQ */ + "\xa0\x18\x30\x16" /* 4 [0] SEQ */ + "\x30\x14" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\xa1\x27" /* 2 [1] IMPL SEQ */ + "\x30\x25" /* 2 SEQ */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\xa2\x31" /* 2 [2] IMPL SEQ */ + "\x30\x2f" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x01\x00" /* 3 OCTET-STRING */ + "\x02\x05\x01\x00\x00\x00\x00", /* 7 INT */ + "seq4 3" }, + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf4 c[4]; + struct TESTSeqOf4_b1 b1[4]; + struct TESTSeqOf4_b2 b2[4]; + struct TESTSeqOf4_b3 b3[4]; + struct TESTSeqOf4_b1_val b1val[4]; + struct TESTSeqOf4_b2_val b2val[4]; + struct TESTSeqOf4_b3_val b3val[4]; + + c[0].b1 = NULL; + c[0].b2 = NULL; + c[0].b3 = NULL; + tests[0].val = &c[0]; + + b2[1].len = 0; + b2[1].val = NULL; + c[1].b1 = NULL; + c[1].b2 = &b2[1]; + c[1].b3 = NULL; + tests[1].val = &c[1]; + + b1[2].len = 0; + b1[2].val = NULL; + b2[2].len = 0; + b2[2].val = NULL; + c[2].b1 = &b1[2]; + c[2].b2 = &b2[2]; + c[2].b3 = NULL; + tests[2].val = &c[2]; + + b1val[3].s1.data = ""; + b1val[3].s1.length = 0; + b1val[3].u1 = 1LL; + b1val[3].s2.data = "\x01\x02"; + b1val[3].s2.length = 2; + b1val[3].u2 = -1LL; + + b2val[3].s1.data = ""; + b2val[3].s1.length = 0; + b2val[3].u1 = 1LL; + b2val[3].s2.data = "\x01\x02"; + b2val[3].s2.length = 2; + b2val[3].u2 = -1LL; + b2val[3].s3.data = "\x00\x01\x02\x03"; + b2val[3].s3.length = 4; + b2val[3].u3 = 1LL<<63; + + b3val[3].s1.data = ""; + b3val[3].s1.length = 0; + b3val[3].u1 = 1LL; + b3val[3].s2.data = "\x01\x02"; + b3val[3].s2.length = 2; + b3val[3].u2 = -1LL; + b3val[3].s3.data = "\x00\x01\x02\x03"; + b3val[3].s3.length = 4; + b3val[3].u3 = 1LL<<63; + b3val[3].s4.data = "\x00"; + b3val[3].s4.length = 1; + b3val[3].u4 = 1LL<<32; + + b1[3].len = 1; + b1[3].val = &b1val[3]; + b2[3].len = 1; + b2[3].val = &b2val[3]; + b3[3].len = 1; + b3[3].val = &b3val[3]; + c[3].b1 = &b1[3]; + c[3].b2 = &b2[3]; + c[3].b3 = &b3[3]; + tests[3].val = &c[3]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf4), + (generic_encode)encode_TESTSeqOf4, + (generic_length)length_TESTSeqOf4, + (generic_decode)decode_TESTSeqOf4, + (generic_free)free_TESTSeqOf4, + cmp_TESTSeqOf4, + (generic_copy)copy_TESTSeqOf4); + return ret; +} + +static int +cmp_test_seqof5 (void *a, void *b) +{ + TESTSeqOf5 *aval = a; + TESTSeqOf5 *bval = b; + + IF_OPT_COMPARE(aval, bval, outer) { + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u0); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s0); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u1); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s1); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u2); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s2); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u3); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s3); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u4); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s4); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u5); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s5); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u6); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s6); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u7); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s7); + } + return 0; +} + +static int +test_seqof5(void) +{ + struct test_case tests[] = { + { NULL, 2, "\x30\x00", "seq5 0" }, + { NULL, 126, + "\x30\x7c" /* SEQ */ + "\x30\x7a" /* SEQ */ + "\x30\x78" /* SEQ */ + "\x02\x01\x01" /* INT 1 */ + "\x04\x06\x01\x01\x01\x01\x01\x01" /* "\0x1"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfe" /* INT ~1 */ + "\x04\x06\x02\x02\x02\x02\x02\x02" /* "\x02"x6 */ + "\x02\x01\x02" /* INT 2 */ + "\x04\x06\x03\x03\x03\x03\x03\x03" /* "\x03"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfd" /* INT ~2 */ + "\x04\x06\x04\x04\x04\x04\x04\x04" /* ... */ + "\x02\x01\x03" + "\x04\x06\x05\x05\x05\x05\x05\x05" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfc" + "\x04\x06\x06\x06\x06\x06\x06\x06" + "\x02\x01\x04" + "\x04\x06\x07\x07\x07\x07\x07\x07" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfb" + "\x04\x06\x08\x08\x08\x08\x08\x08", + "seq5 1" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf5 c[2]; + struct TESTSeqOf5_outer outer; + struct TESTSeqOf5_outer_inner inner; + TESTuint64 u[8]; + heim_octet_string s[8]; + int i; + + c[0].outer = NULL; + tests[0].val = &c[0]; + + for (i = 0; i < 8; ++i) { + u[i] = (i&1) == 0 ? i/2+1 : ~(i/2+1); + s[i].data = memset(malloc(s[i].length = 6), i+1, 6); + } + + inner.u0 = u[0]; inner.u1 = u[1]; inner.u2 = u[2]; inner.u3 = u[3]; + inner.u4 = u[4]; inner.u5 = u[5]; inner.u6 = u[6]; inner.u7 = u[7]; + inner.s0 = s[0]; inner.s1 = s[1]; inner.s2 = s[2]; inner.s3 = s[3]; + inner.s4 = s[4]; inner.s5 = s[5]; inner.s6 = s[6]; inner.s7 = s[7]; + + outer.inner = inner; + c[1].outer = &outer; + tests[1].val = &c[1]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf5), + (generic_encode)encode_TESTSeqOf5, + (generic_length)length_TESTSeqOf5, + (generic_decode)decode_TESTSeqOf5, + (generic_free)free_TESTSeqOf5, + cmp_test_seqof5, + NULL); + + for (i = 0; i < 8; ++i) + free(s[i].data); + + return ret; +} + +static int +cmp_default(void *a, void *b) +{ + TESTDefault *aa = a; + TESTDefault *ab = b; + + COMPARE_STRING(aa,ab,name); + COMPARE_INTEGER(aa,ab,version); + COMPARE_INTEGER(aa,ab,maxint); + COMPARE_INTEGER(aa,ab,works); + return 0; +} + +static int +test_default(void) +{ + struct test_case tests[] = { +#ifndef DISABLE_TEST_64 + { NULL, 2, "\x30\x00", NULL }, +#endif + { NULL, 25, + "\x30\x17\x0c\x07\x68\x65\x69\x6d\x64\x61" + "\x6c\xa0\x03\x02\x01\x07\x02\x04\x7f\xff" + "\xff\xff\x01\x01\x00", + NULL + }, +#ifndef DISABLE_TEST_64 + { NULL, 10, + "\x30\x08\xa0\x03\x02\x01\x07\x01\x01\x00", + NULL + }, +#endif + { NULL, 17, + "\x30\x0f\x0c\x07\x68\x65\x69\x6d\x64\x61\x6c\x02\x04" + "\x7f\xff\xff\xff", + NULL + } + }; + + TESTDefault values[] = { +#ifndef DISABLE_TEST_64 + { "Heimdal", 8, 9223372036854775807LL, 1 }, +#endif + { "heimdal", 7, 2147483647, 0 }, +#ifndef DISABLE_TEST_64 + { "Heimdal", 7, 9223372036854775807LL, 0 }, +#endif + { "heimdal", 8, 2147483647, 1 }, + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "TESTDefault %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(TESTDefault), + (generic_encode)encode_TESTDefault, + (generic_length)length_TESTDefault, + (generic_decode)decode_TESTDefault, + (generic_free)free_TESTDefault, + cmp_default, + (generic_copy)copy_TESTDefault); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + + return ret; +} + +static int +test_x690sample(void) +{ + /* + * Taken from X.690, Appendix A, though sadly it's not specified whether + * it's in BER, DER, or CER, but it is clearly BER and neither DER nor CER + * because the tags of the members of the X690SamplePersonnelRecord type + * are not canonically sorted in the given sample. + * + * Our compiler does NOT canonically sort the members of SET { ... } types + * so it produces the same encoding after decoding this test vector. That + * is clearly a bug given that we aim to output DER. + * + * The template compiler doesn't even decode SET { ... } values properly + * when their members are not in the same order as defined (but the regular + * compiler does). + */ + X690SamplePersonnelRecord r; + heim_octet_string os; + unsigned char encoded_sample[] = { + 0x60, 0x81, 0x85, 0x61, 0x10, 0x1a, 0x04, 0x4a, 0x6f, 0x68, 0x6e, 0x1a, + 0x01, 0x50, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x1a, + 0x08, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x01, 0x33, + 0xa1, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x37, 0x31, 0x30, 0x39, 0x31, 0x37, + 0xa2, 0x12, 0x61, 0x10, 0x1a, 0x04, 0x4d, 0x61, 0x72, 0x79, 0x1a, 0x01, + 0x54, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa3, 0x42, 0x31, 0x1f, + 0x61, 0x11, 0x1a, 0x05, 0x52, 0x61, 0x6c, 0x70, 0x68, 0x1a, 0x01, 0x54, + 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, + 0x39, 0x35, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x1f, 0x61, 0x11, 0x1a, + 0x05, 0x53, 0x75, 0x73, 0x61, 0x6e, 0x1a, 0x01, 0x42, 0x1a, 0x05, 0x53, + 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x35, 0x39, + 0x30, 0x37, 0x31, 0x37 + }; + size_t sz = 0; + int ret; + + memset(&r, 0, sizeof(r)); + if (decode_X690SamplePersonnelRecord(encoded_sample, sizeof(encoded_sample), &r, &sz)) + return 1; + if (sz != sizeof(encoded_sample)) + return 1; + free_X690SamplePersonnelRecord(&r); + memset(&r, 0, sizeof(r)); + + /* We re-construct the record manually to double-check the spec */ + r.name.givenName = strdup("John"); + r.name.initial = strdup("P"); + r.name.familyName = strdup("Smith"); + r.title = strdup("Director"); + r.dateOfHire = strdup("19710917"); + r.number = 51; + r.nameOfSpouse.givenName = strdup("Mary"); + r.nameOfSpouse.initial = strdup("T"); + r.nameOfSpouse.familyName = strdup("Smith"); + r.children.val = calloc(2, sizeof(r.children.val[0])); + r.children.len = 2; + r.children.val[0].name.givenName = strdup("Ralph"); + r.children.val[0].name.initial = strdup("T"); + r.children.val[0].name.familyName = strdup("Smith"); + r.children.val[0].dateOfBirth = strdup("19571111"); + r.children.val[1].name.givenName = strdup("Susan"); + r.children.val[1].name.initial = strdup("B"); + r.children.val[1].name.familyName = strdup("Smith"); + r.children.val[1].dateOfBirth = strdup("19590717"); + os.length = 0; + os.data = 0; + ASN1_MALLOC_ENCODE(X690SamplePersonnelRecord, os.data, os.length, &r, &sz, + ret); + if (ret || sz != sizeof(encoded_sample) || sz != os.length || + memcmp(encoded_sample, os.data, sz) != 0) + return 1; + free_X690SamplePersonnelRecord(&r); + free(os.data); + return 0; +} + +#if ASN1_IOS_SUPPORTED +static int +test_ios(void) +{ + unsigned char encoded_sample[] = { + 0x30, 0x82, 0x04, 0x8e, 0x30, 0x82, 0x03, 0x76, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x6a, + 0x05, 0x97, 0xba, 0x71, 0xd7, 0xe6, 0xd3, 0xac, + 0x0e, 0xdc, 0x9e, 0xdc, 0x95, 0xa1, 0x5b, 0x99, + 0x8d, 0xe4, 0x0a, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x30, 0x55, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, + 0x48, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x15, 0x53, 0x54, 0x4d, 0x69, + 0x63, 0x72, 0x6f, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x73, 0x20, 0x4e, + 0x56, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1d, 0x53, 0x54, 0x4d, 0x20, + 0x54, 0x50, 0x4d, 0x20, 0x45, 0x4b, 0x20, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x20, 0x30, + 0x35, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, + 0x32, 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x32, + 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xcc, 0x14, 0xeb, 0x27, + 0xa7, 0x8c, 0xeb, 0x0e, 0xa4, 0x86, 0xfa, 0x2d, + 0xf7, 0x83, 0x5f, 0x5f, 0xa8, 0xe9, 0x05, 0xb0, + 0x97, 0x01, 0x2b, 0x5b, 0xde, 0x50, 0x38, 0x0c, + 0x35, 0x5b, 0x1a, 0x2a, 0x72, 0x1b, 0xbc, 0x3d, + 0x08, 0xdd, 0x21, 0x79, 0x6c, 0xdb, 0x23, 0x9f, + 0xa9, 0x53, 0x10, 0x65, 0x1b, 0x1b, 0x56, 0xfd, + 0x2c, 0xfe, 0x53, 0xc8, 0x73, 0x52, 0xeb, 0xd9, + 0x96, 0xe3, 0x32, 0x56, 0x16, 0x04, 0x04, 0xce, + 0x93, 0x02, 0xa0, 0x80, 0x66, 0x80, 0x1e, 0x78, + 0x6a, 0x2f, 0x86, 0xe1, 0x81, 0xf9, 0x49, 0x96, + 0x6f, 0x49, 0x2a, 0x85, 0xb5, 0x8e, 0xaa, 0x4a, + 0x6a, 0x8c, 0xb3, 0x69, 0x75, 0x51, 0xbb, 0x23, + 0x6e, 0x87, 0xcc, 0x7b, 0xf8, 0xec, 0x13, 0x47, + 0x87, 0x1c, 0x91, 0xe1, 0x54, 0x37, 0xe8, 0xf2, + 0x66, 0xbf, 0x1e, 0xa5, 0xeb, 0x27, 0x1f, 0xdc, + 0xf3, 0x74, 0xd8, 0xb4, 0x7d, 0xf8, 0xbc, 0xe8, + 0x9e, 0x1f, 0xad, 0x61, 0xc2, 0xa0, 0x88, 0xcb, + 0x40, 0x36, 0xb3, 0x59, 0xcb, 0x72, 0xa2, 0x94, + 0x97, 0x3f, 0xed, 0xcc, 0xf0, 0xc3, 0x40, 0xaf, + 0xfd, 0x14, 0xb6, 0x4f, 0x04, 0x11, 0x65, 0x58, + 0x1a, 0xca, 0x34, 0x14, 0x7c, 0x1c, 0x75, 0x61, + 0x70, 0x47, 0x05, 0x8f, 0x7e, 0xd7, 0xd6, 0x03, + 0xe0, 0x32, 0x50, 0x80, 0x94, 0xfa, 0x73, 0xe8, + 0xb9, 0x15, 0x3d, 0xa3, 0xbf, 0x25, 0x5d, 0x2c, + 0xbb, 0xc5, 0xdf, 0x30, 0x1b, 0xa8, 0xf7, 0x4d, + 0x19, 0x8b, 0xeb, 0xce, 0x86, 0x04, 0x0f, 0xc1, + 0xd2, 0x92, 0x7c, 0x76, 0x57, 0x41, 0x44, 0x90, + 0xd8, 0x02, 0xf4, 0x82, 0xf3, 0xeb, 0xf2, 0xde, + 0x35, 0xee, 0x14, 0x9a, 0x1a, 0x6d, 0xe8, 0xd1, + 0x68, 0x91, 0xfb, 0xfb, 0xa0, 0x2a, 0x18, 0xaf, + 0xe5, 0x9f, 0x9d, 0x6f, 0x14, 0x97, 0x44, 0xe5, + 0xf0, 0xd5, 0x59, 0xb1, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0xa9, 0x30, 0x82, 0x01, + 0xa5, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x1a, 0xdb, + 0x99, 0x4a, 0xb5, 0x8b, 0xe5, 0x7a, 0x0c, 0xc9, + 0xb9, 0x00, 0xe7, 0x85, 0x1e, 0x1a, 0x43, 0xc0, + 0x86, 0x60, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2f, 0x30, + 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x21, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, + 0x50, 0x4d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x59, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, + 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30, 0x49, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, 0x81, + 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64, 0x3a, + 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32, 0x30, + 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67, 0x81, + 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54, 0x33, + 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48, 0x43, + 0x30, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, + 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69, 0x64, + 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30, 0x30, + 0x38, 0x30, 0x67, 0x06, 0x03, 0x55, 0x1d, 0x09, + 0x04, 0x60, 0x30, 0x5e, 0x30, 0x17, 0x06, 0x05, + 0x67, 0x81, 0x05, 0x02, 0x10, 0x31, 0x0e, 0x30, + 0x0c, 0x0c, 0x03, 0x32, 0x2e, 0x30, 0x02, 0x01, + 0x00, 0x02, 0x02, 0x00, 0x8a, 0x30, 0x43, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x12, 0x31, 0x3a, + 0x30, 0x38, 0x02, 0x01, 0x00, 0x01, 0x01, 0xff, + 0xa0, 0x03, 0x0a, 0x01, 0x01, 0xa1, 0x03, 0x0a, + 0x01, 0x00, 0xa2, 0x03, 0x0a, 0x01, 0x00, 0xa3, + 0x10, 0x30, 0x0e, 0x16, 0x03, 0x33, 0x2e, 0x31, + 0x0a, 0x01, 0x04, 0x0a, 0x01, 0x02, 0x01, 0x01, + 0xff, 0xa4, 0x0f, 0x30, 0x0d, 0x16, 0x05, 0x31, + 0x34, 0x30, 0x2d, 0x32, 0x0a, 0x01, 0x02, 0x01, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x05, 0x20, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x09, 0x30, 0x07, 0x06, 0x05, 0x67, 0x81, 0x05, + 0x08, 0x01, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x3e, + 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2e, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x74, 0x6d, + 0x74, 0x70, 0x6d, 0x65, 0x6b, 0x69, 0x6e, 0x74, + 0x30, 0x35, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x3d, 0x4c, 0x38, 0x1e, 0x5b, 0x4f, + 0x1b, 0xcb, 0xe0, 0x9c, 0x63, 0xd5, 0x2f, 0x1f, + 0x04, 0x57, 0x0c, 0xae, 0xa1, 0x42, 0xfd, 0x9c, + 0xd9, 0x42, 0x04, 0x3b, 0x11, 0xf8, 0xe3, 0xbd, + 0xcf, 0x50, 0x00, 0x7a, 0xe1, 0x6c, 0xf8, 0x86, + 0x90, 0x13, 0x04, 0x1e, 0x92, 0xcd, 0xd3, 0x28, + 0x0b, 0xa4, 0xb5, 0x1f, 0xbb, 0xd4, 0x05, 0x82, + 0xed, 0x75, 0x02, 0x19, 0xe2, 0x61, 0xa6, 0x95, + 0x09, 0x56, 0x74, 0x85, 0x5a, 0xac, 0xeb, 0x52, + 0x0a, 0xda, 0xff, 0x9e, 0x7e, 0x90, 0x84, 0x80, + 0xa3, 0x9c, 0xdc, 0xf9, 0x00, 0x46, 0x2d, 0x91, + 0x71, 0x96, 0x0f, 0xfe, 0x55, 0xd3, 0xac, 0x49, + 0xe8, 0xc9, 0x81, 0x34, 0x1b, 0xbd, 0x2e, 0xfb, + 0xcc, 0x25, 0x2a, 0x4c, 0x18, 0xa4, 0xf3, 0xb7, + 0xc8, 0x4c, 0xce, 0x42, 0xce, 0x70, 0xa2, 0x08, + 0xc8, 0x4d, 0x26, 0x30, 0xa7, 0xab, 0xfb, 0xe7, + 0x2d, 0x62, 0x71, 0xe7, 0x5b, 0x9f, 0xf1, 0xc9, + 0x71, 0xd2, 0x0e, 0xb3, 0xdb, 0xd7, 0x63, 0xf1, + 0xe0, 0x4d, 0x83, 0x4e, 0xaa, 0x69, 0x2d, 0x2e, + 0x40, 0x01, 0xbb, 0xf4, 0x73, 0x0a, 0x3e, 0x3f, + 0xda, 0x97, 0x11, 0xae, 0x38, 0x65, 0x24, 0xd9, + 0x1c, 0x63, 0xbe, 0x0e, 0x51, 0x6d, 0x00, 0xd5, + 0xc6, 0x14, 0x1f, 0xcc, 0xf6, 0xc5, 0x39, 0xf3, + 0x51, 0x8e, 0x18, 0x00, 0x49, 0x86, 0x5b, 0xe1, + 0x6b, 0x69, 0xca, 0xe1, 0xf8, 0xcb, 0x7f, 0xdc, + 0x47, 0x4b, 0x38, 0xf7, 0xee, 0x56, 0xcb, 0xe7, + 0xd8, 0xa8, 0x9d, 0x9b, 0xa9, 0x9b, 0x65, 0xd5, + 0x26, 0x5a, 0xef, 0x32, 0xaa, 0x62, 0x42, 0x6b, + 0x10, 0xe6, 0xd7, 0x5b, 0xb8, 0x67, 0x7e, 0xc4, + 0x4f, 0x75, 0x5b, 0xbc, 0x28, 0x06, 0xfd, 0x2b, + 0x4e, 0x04, 0xbd, 0xf5, 0xd4, 0x42, 0x59, 0xdb, + 0xea, 0xa4, 0x2b, 0x6f, 0x56, 0x3d, 0xf7, 0xaa, + 0x75, 0x06, + }; + char cert_json[] = { + "{\"_type\":\"Certificate\",\"tbsCertificate\":{\"_type\":\"TBSCertificate" + "\",\"_save\":\"30820376A00302010202146A0597BA71D7E6D3AC0EDC9EDC95A15" + "B998DE40A300D06092A864886F70D01010B05003055310B30090603550406130" + "24348311E301C060355040A131553544D6963726F656C656374726F6E6963732" + "04E56312630240603550403131D53544D2054504D20454B20496E7465726D656" + "469617465204341203035301E170D3138313231343030303030305A170D32383" + "13231343030303030305A300030820122300D06092A864886F70D01010105000" + "382010F003082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E90" + "5B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B5" + "6FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F94" + "9966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E" + "8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A" + "294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D" + "603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040" + "FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A1" + "8AFE59F9D6F149744E5F0D559B10203010001A38201A9308201A5301F0603551" + "D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660304206035" + "51D20043B303930370604551D2000302F302D06082B060105050702011621687" + "474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F3" + "0590603551D110101FF044F304DA44B304931163014060567810502010C0B696" + "43A353335343444323031173015060567810502020C0C5354333348545048414" + "8433031163014060567810502030C0B69643A303034393030303830670603551" + "D090460305E301706056781050210310E300C0C03322E300201000202008A304" + "306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A010" + "0A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A010" + "2010100300E0603551D0F0101FF040403020520300C0603551D130101FF04023" + "00030100603551D250409300706056781050801304A06082B060105050701010" + "43E303C303A06082B06010505073002862E687474703A2F2F7365637572652E6" + "76C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274\"" + ",\"version\":\"rfc3280_version_3\",\"serialNumber\":\"6A0597BA71D7E6D3A" + "C0EDC9EDC95A15B998DE40A\",\"signature\":{\"_type\":\"AlgorithmIdentifi" + "er\",\"algorithm\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.2.840.1135" + "49.1.1.11\",\"components\":[1,2,840,113549,1,1,11],\"name\":\"id-pkcs1" + "-sha256WithRSAEncryption\"},\"parameters\":\"0500\"},\"issuer\":{\"_choi" + "ce\":\"rdnSequence\",\"value\":[[{\"_type\":\"AttributeTypeAndValue\",\"ty" + "pe\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.6\",\"components\":[2" + ",5,4,6],\"name\":\"id-at-countryName\"},\"value\":{\"_choice\":\"printabl" + "eString\",\"value\":\"CH\"}}],[{\"_type\":\"AttributeTypeAndValue\",\"type" + "\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.10\",\"components\":[2," + "5,4,10],\"name\":\"id-at-organizationName\"},\"value\":{\"_choice\":\"pri" + "ntableString\",\"value\":\"STMicroelectronics NV\"}}],[{\"_type\":\"Attr" + "ibuteTypeAndValue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2." + "5.4.3\",\"components\":[2,5,4,3],\"name\":\"id-at-commonName\"},\"value\"" + ":{\"_choice\":\"printableString\",\"value\":\"STM TPM EK Intermediate C" + "A 05\"}}]]},\"validity\":{\"_type\":\"Validity\",\"notBefore\":{\"_choice\"" + ":\"utcTime\",\"value\":\"2018-12-14T00:00:00Z\"},\"notAfter\":{\"_choice\"" + ":\"utcTime\",\"value\":\"2028-12-14T00:00:00Z\"}},\"subject\":{\"_choice\"" + ":\"rdnSequence\",\"value\":[]},\"subjectPublicKeyInfo\":{\"_type\":\"Subj" + "ectPublicKeyInfo\",\"algorithm\":{\"_type\":\"AlgorithmIdentifier\",\"al" + "gorithm\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.2.840.113549.1.1." + "1\",\"components\":[1,2,840,113549,1,1,1],\"name\":\"id-pkcs1-rsaEncry" + "ption\"},\"parameters\":\"0500\"},\"subjectPublicKey\":\"2160:3082010A02" + "82010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C" + "355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD9" + "96E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A" + "6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDC" + "F374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AF" + "FD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8" + "B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490" + "D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5" + "F0D559B10203010001\"},\"issuerUniqueID\":null,\"subjectUniqueID\":nul" + "l,\"extensions\":[{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT I" + "DENTIFIER\",\"oid\":\"2.5.29.35\",\"components\":[2,5,29,35],\"name\":\"id" + "-x509-ce-authorityKeyIdentifier\"},\"critical\":false,\"extnValue\":\"" + "301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660\",\"_extnValue_ch" + "oice\":\"ext-AuthorityKeyIdentifier\",\"_extnValue\":{\"_type\":\"Author" + "ityKeyIdentifier\",\"keyIdentifier\":\"1ADB994AB58BE57A0CC9B900E7851" + "E1A43C08660\",\"authorityCertIssuer\":null,\"authorityCertSerialNumb" + "er\":null}},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTI" + "FIER\",\"oid\":\"2.5.29.32\",\"components\":[2,5,29,32],\"name\":\"id-x509" + "-ce-certificatePolicies\"},\"critical\":false,\"extnValue\":\"30393037" + "0604551D2000302F302D06082B060105050702011621687474703A2F2F777777" + "2E73742E636F6D2F54504D2F7265706F7369746F72792F\",\"_extnValue_choi" + "ce\":\"ext-CertificatePolicies\",\"_extnValue\":[{\"_type\":\"PolicyInfo" + "rmation\",\"policyIdentifier\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"" + "2.5.29.32.0\",\"components\":[2,5,29,32,0],\"name\":\"id-x509-ce-certi" + "ficatePolicies-anyPolicy\"},\"policyQualifiers\":[{\"_type\":\"PolicyQ" + "ualifierInfo\",\"policyQualifierId\":{\"_type\":\"OBJECT IDENTIFIER\",\"" + "oid\":\"1.3.6.1.5.5.7.2.1\",\"components\":[1,3,6,1,5,5,7,2,1],\"name\"" + ":\"id-pkix-qt-cps\"},\"qualifier\":\"1621687474703A2F2F7777772E73742E" + "636F6D2F54504D2F7265706F7369746F72792F\",\"_qualifier_choice\":\"pq-" + "CPS\"}]}]},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIF" + "IER\",\"oid\":\"2.5.29.17\",\"components\":[2,5,29,17],\"name\":\"id-x509-" + "ce-subjectAltName\"},\"critical\":true,\"extnValue\":\"304DA44B3049311" + "63014060567810502010C0B69643A35333534344432303117301506056781050" + "2020C0C53543333485450484148433031163014060567810502030C0B69643A3" + "030343930303038\",\"_extnValue_choice\":\"ext-SubjectAltName\",\"_extn" + "Value\":[{\"_choice\":\"directoryName\",\"value\":{\"_choice\":\"rdnSequen" + "ce\",\"value\":[[{\"_type\":\"AttributeTypeAndValue\",\"type\":{\"_type\":\"" + "OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.1\",\"components\":[2,23,133,2" + ",1],\"name\":\"tcg-at-tpmManufacturer\"},\"value\":{\"_choice\":\"utf8Str" + "ing\",\"value\":\"id:53544D20\"}}],[{\"_type\":\"AttributeTypeAndValue\"," + "\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.2\",\"compon" + "ents\":[2,23,133,2,2],\"name\":\"tcg-at-tpmModel\"},\"value\":{\"_choice" + "\":\"utf8String\",\"value\":\"ST33HTPHAHC0\"}}],[{\"_type\":\"AttributeTyp" + "eAndValue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2" + ".3\",\"components\":[2,23,133,2,3],\"name\":\"tcg-at-tpmVersion\"},\"val" + "ue\":{\"_choice\":\"utf8String\",\"value\":\"id:00490008\"}}]]}}]},{\"_typ" + "e\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5." + "29.9\",\"components\":[2,5,29,9],\"name\":\"id-x509-ce-subjectDirector" + "yAttributes\"},\"critical\":false,\"extnValue\":\"305E3017060567810502" + "10310E300C0C03322E300201000202008A304306056781050212313A30380201" + "000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A" + "01020101FFA40F300D16053134302D320A0102010100\",\"_extnValue_choice" + "\":\"ext-SubjectDirectoryAttributes\",\"_extnValue\":[{\"_type\":\"Attri" + "buteSet\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.1" + "6\",\"components\":[2,23,133,2,16],\"name\":\"tcg-at-tpmSpecification\"" + "},\"values\":[\"300C0C03322E300201000202008A\"],\"_values_choice\":\"at" + "-TPMSpecification\",\"_values\":[{\"_type\":\"TPMSpecification\",\"famil" + "y\":\"2.0\",\"level\":0,\"revision\":138}]},{\"_type\":\"AttributeSet\",\"ty" + "pe\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.18\",\"componen" + "ts\":[2,23,133,2,18],\"name\":\"tcg-at-tpmSecurityAssertions\"},\"valu" + "es\":[\"30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603" + "332E310A01040A01020101FFA40F300D16053134302D320A0102010100\"],\"_v" + "alues_choice\":\"at-TPMSecurityAssertions\",\"_values\":[{\"_type\":\"TP" + "MSecurityAssertions\",\"version\":0,\"fieldUpgradable\":true,\"ekGener" + "ationType\":\"ekgt-injected\",\"ekGenerationLocation\":\"tpmManufactur" + "er\",\"ekCertificateGenerationLocation\":\"tpmManufacturer\",\"ccInfo\"" + ":{\"_type\":\"CommonCriteriaMeasures\",\"version\":\"3.1\",\"assurancelev" + "el\":\"ealevel4\",\"evaluationStatus\":\"evaluationCompleted\",\"plus\":t" + "rue,\"strengthOfFunction\":null,\"profileOid\":null,\"profileUri\":nul" + "l,\"targetOid\":null,\"targetUri\":null},\"fipsLevel\":{\"_type\":\"FIPSL" + "evel\",\"version\":\"140-2\",\"level\":\"sllevel2\",\"plus\":false},\"iso900" + "0Certified\":false,\"iso9000Uri\":null}]}]},{\"_type\":\"Extension\",\"e" + "xtnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.15\",\"component" + "s\":[2,5,29,15],\"name\":\"id-x509-ce-keyUsage\"},\"critical\":true,\"ex" + "tnValue\":\"03020520\",\"_extnValue_choice\":\"ext-KeyUsage\",\"_extnVal" + "ue\":[\"keyEncipherment\"]},{\"_type\":\"Extension\",\"extnID\":{\"_type\":" + "\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.19\",\"components\":[2,5,29,19],\"" + "name\":\"id-x509-ce-basicConstraints\"},\"critical\":true,\"extnValue\"" + ":\"3000\",\"_extnValue_choice\":\"ext-BasicConstraints\",\"_extnValue\":" + "{\"_type\":\"BasicConstraints\",\"cA\":false,\"pathLenConstraint\":null}" + "},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oi" + "d\":\"2.5.29.37\",\"components\":[2,5,29,37],\"name\":\"id-x509-ce-extKe" + "yUsage\"},\"critical\":false,\"extnValue\":\"300706056781050801\",\"_ext" + "nValue_choice\":\"ext-ExtKeyUsage\",\"_extnValue\":[{\"_type\":\"OBJECT " + "IDENTIFIER\",\"oid\":\"2.23.133.8.1\",\"components\":[2,23,133,8,1],\"na" + "me\":\"tcg-kp-EKCertificate\"}]},{\"_type\":\"Extension\",\"extnID\":{\"_t" + "ype\":\"OBJECT IDENTIFIER\",\"oid\":\"1.3.6.1.5.5.7.1.1\",\"components\":" + "[1,3,6,1,5,5,7,1,1],\"name\":\"id-pkix-pe-authorityInfoAccess\"},\"cr" + "itical\":false,\"extnValue\":\"303C303A06082B06010505073002862E68747" + "4703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706" + "D656B696E7430352E637274\",\"_extnValue_choice\":\"ext-AuthorityInfoA" + "ccess\",\"_extnValue\":[{\"_type\":\"AccessDescription\",\"accessMethod\"" + ":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.3.6.1.5.5.7.48.2\",\"compon" + "ents\":[1,3,6,1,5,5,7,48,2],\"name\":\"id-pkix-ad-caIssuers\"},\"acces" + "sLocation\":{\"_choice\":\"uniformResourceIdentifier\",\"value\":\"http:" + "//secure.globalsign.com/stmtpmekint05.crt\"}}]}]},\"signatureAlgor" + "ithm\":{\"_type\":\"AlgorithmIdentifier\",\"algorithm\":{\"_type\":\"OBJEC" + "T IDENTIFIER\",\"oid\":\"1.2.840.113549.1.1.11\",\"components\":[1,2,84" + "0,113549,1,1,11],\"name\":\"id-pkcs1-sha256WithRSAEncryption\"},\"par" + "ameters\":\"0500\"},\"signatureValue\":\"2048:3D4C381E5B4F1BCBE09C63D5" + "2F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF8869013041E92CD" + "D3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAFF9E7E90" + "8480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252A4C18A4" + "F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20EB3DBD7" + "63F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63BE0E516D" + "00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B38F7EE56" + "CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755BBC2806" + "FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506\"" + "}" + }; + heim_octet_string os; + Certificate c0, c1; + size_t i, nknown, size; + char *s; + int ret; + + /* + * Test automatic decoding of open types. + * + * Decode a value that has plenty of open types with values of known + * alternatives in them, then check that we got what we wanted. + */ + ret = decode_Certificate(encoded_sample, sizeof(encoded_sample), + &c0, &size); + if (ret) + return 1; + if (size != sizeof(encoded_sample)) + return 1; + + s = print_Certificate(&c0, 0); + if (!s) + return 1; + if (strcmp(s, cert_json) != 0) + return 1; + free(s); + + ret = copy_Certificate(&c0, &c1); + if (ret) + return 1; + + if (!c0.tbsCertificate.extensions || !c1.tbsCertificate.extensions) + return 1; + if (!c0.tbsCertificate.extensions->len || + c0.tbsCertificate.extensions->len != c1.tbsCertificate.extensions->len) + return 1; + for (i = nknown = 0; i < c0.tbsCertificate.extensions->len; i++) { + if (c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element != + c1.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element) + return 1; + if (c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element) { +#if 0 + fprintf(stderr, "extension %llu known %u\n", + (unsigned long long)i, + c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue._element); +#endif + nknown++; + } + } + if (!nknown) + return 1; + + + /* + * Check that this round trips. But note that this attempt to encode will + * ignore the automatically decoded open type values from above because + * their encodings are still present. + */ + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c1, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + /* + * Test automatic encoding of open types by clearing the encoding of one + * such open type value, forcing the encoder to encode the value from + * before. + */ + der_free_octet_string(&c0.tbsCertificate.extensions->val[0].extnValue); + der_free_oid(&c0.tbsCertificate.extensions->val[0].extnID); + + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c0, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + /* + * Repeat, but with the copy, as this will test that copying data + * structures with decoded open types in them also copies those. + */ + der_free_octet_string(&c1.tbsCertificate.extensions->val[0].extnValue); + der_free_oid(&c1.tbsCertificate.extensions->val[0].extnID); + + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c1, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + free_Certificate(&c0); + free_Certificate(&c1); + return 0; +} +#endif + +int +main(int argc, char **argv) +{ + int ret = 0; + +#define DO_ONE(t) if (t()) { fprintf(stderr, "%s() failed!\n", #t); ret++; } + DO_ONE(test_principal); + DO_ONE(test_authenticator); + DO_ONE(test_krb_error); + DO_ONE(test_Name); + DO_ONE(test_bit_string); + DO_ONE(test_bit_string_rfc1510); + DO_ONE(test_time); + DO_ONE(test_cert); + + DO_ONE(check_tag_length); + DO_ONE(check_tag_length64); + DO_ONE(check_tag_length64s); + DO_ONE(test_large_tag); + DO_ONE(test_choice); + + DO_ONE(test_implicit); + + DO_ONE(test_taglessalloc); + DO_ONE(test_optional); + + DO_ONE(check_fail_largetag); + DO_ONE(check_fail_sequence); + DO_ONE(check_fail_choice); + DO_ONE(check_fail_Ticket); + + DO_ONE(check_seq); + DO_ONE(check_seq_of_size); + DO_ONE(test_SignedData); + + DO_ONE(check_TESTMechTypeList); + DO_ONE(test_seq4); + DO_ONE(test_seqof5); + + DO_ONE(test_x690sample); + + DO_ONE(test_default); + + DO_ONE(test_extensible_choice); + + DO_ONE(test_decorated_choice); + DO_ONE(test_decorated); + +#if ASN1_IOS_SUPPORTED + DO_ONE(test_ios); +#endif + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-gen.h b/third_party/heimdal/lib/asn1/check-gen.h new file mode 100644 index 0000000..df8c474 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-gen.h @@ -0,0 +1,9 @@ +#ifndef _CHECK_GEN_H +#define _CHECK_GEN_H +typedef struct my_vers_s { + int v; +} my_vers; + +int my_copy_vers(const my_vers *, my_vers *); +void my_free_vers(my_vers *); +#endif /* _CHECK_GEN_H */ diff --git a/third_party/heimdal/lib/asn1/check-template.c b/third_party/heimdal/lib/asn1/check-template.c new file mode 100644 index 0000000..ef5bd69 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-template.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "check-common.h" +#include "der_locl.h" + +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + v->v = -1; +} + +static int +cmp_dummy (void *a, void *b) +{ + return 0; +} + +static int +test_uint64(void) +{ + struct test_case tests[] = { + { NULL, 3, "\x02\x01\x00", "uint64 0" }, + { NULL, 7, "\x02\x05\x01\xff\xff\xff\xff", "uint64 1" }, + { NULL, 7, "\x02\x05\x02\x00\x00\x00\x00", "uint64 2" }, + { NULL, 9, "\x02\x07\x7f\xff\xff\xff\xff\xff\xff", "uint64 3" }, + { NULL, 10, "\x02\x08\x00\x80\x00\x00\x00\x00\x00\x00", "uint64 4" }, + { NULL, 10, "\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff", "uint64 5" }, + { NULL, 11, "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", "uint64 6" } + }; + + size_t i; + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTuint64 values[] = { 0, 8589934591LL, 8589934592LL, + 36028797018963967LL, 36028797018963968LL, + 9223372036854775807LL, 18446744073709551615ULL }; + + for (i = 0; i < ntests; i++) + tests[i].val = &values[i]; + + if (sizeof(TESTuint64) != sizeof(uint64_t)) { + ret += 1; + printf("sizeof(TESTuint64) %d != sizeof(uint64_t) %d\n", + (int)sizeof(TESTuint64), (int)sizeof(uint64_t)); + } + + ret += generic_test (tests, ntests, sizeof(TESTuint64), + (generic_encode)encode_TESTuint64, + (generic_length)length_TESTuint64, + (generic_decode)decode_TESTuint64, + (generic_free)free_TESTuint64, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqofseq(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq 0" }, + { NULL, 9, + "\x30\x07\x30\x05\xa0\x03\x02\x01\x00", + "seqofseq 1" }, + { NULL, 16, + "\x30\x0e\x30\x05\xa0\x03\x02\x01\x00\x30\x05\xa0\x03\x02\x01\x01", + "seqofseq 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq c0, c1, c2; + struct TESTSeqOfSeq_val i[2]; + + i[0].zero = 0; + i[1].zero = 1; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq), + (generic_encode)encode_TESTSeqOfSeq, + (generic_length)length_TESTSeqOfSeq, + (generic_decode)decode_TESTSeqOfSeq, + (generic_free)free_TESTSeqOfSeq, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqofseq2(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq2 0" }, + { NULL, 11, + "\x30\x09\x30\x07\xa0\x05\x1b\x03\x65\x74\x74", + "seqofseq2 1" }, + { NULL, 21, + "\x30\x13\x30\x07\xa0\x05\x1b\x03\x65\x74\x74\x30\x08\xa0" + "\x06\x1b\x04\x74\x76\x61\x61", + "seqofseq2 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq2 c0, c1, c2; + struct TESTSeqOfSeq2_val i[2]; + + i[0].string = "ett"; + i[1].string = "tvaa"; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq2), + (generic_encode)encode_TESTSeqOfSeq2, + (generic_length)length_TESTSeqOfSeq2, + (generic_decode)decode_TESTSeqOfSeq2, + (generic_free)free_TESTSeqOfSeq2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof2(void) +{ + struct test_case tests[] = { + { NULL, 4, + "\x30\x02\x30\x00", + "seqof2 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof2 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof2 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf2 c0, c1, c2; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings.val = NULL; + c0.strings.len = 0; + tests[0].val = &c0; + + c1.strings.len = 1; + c1.strings.val = i; + tests[1].val = &c1; + + c2.strings.len = 2; + c2.strings.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf2), + (generic_encode)encode_TESTSeqOf2, + (generic_length)length_TESTSeqOf2, + (generic_decode)decode_TESTSeqOf2, + (generic_free)free_TESTSeqOf2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof3(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqof3 0" }, + { NULL, 4, + "\x30\x02\x30\x00", + "seqof3 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof3 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof3 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf3 c0, c1, c2, c3; + struct TESTSeqOf3_strings s1, s2, s3; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings = NULL; + tests[0].val = &c0; + + s1.val = NULL; + s1.len = 0; + c1.strings = &s1; + tests[1].val = &c1; + + s2.len = 1; + s2.val = i; + c2.strings = &s2; + tests[2].val = &c2; + + s3.len = 2; + s3.val = i; + c3.strings = &s3; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf3), + (generic_encode)encode_TESTSeqOf3, + (generic_length)length_TESTSeqOf3, + (generic_decode)decode_TESTSeqOf3, + (generic_free)free_TESTSeqOf3, + cmp_dummy, + NULL); + return ret; +} + + +static int +test_seqof4(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seq4 0" }, + { NULL, 4, + "\x30\x02" "\xa1\x00", + "seq4 1" }, + { NULL, 8, + "\x30\x06" "\xa0\x02\x30\x00" "\xa1\x00", + "seq4 2" }, + { NULL, 2 + (2 + 0x18) + (2 + 0x27) + (2 + 0x31), + "\x30\x76" /* 2 SEQ */ + "\xa0\x18\x30\x16" /* 4 [0] SEQ */ + "\x30\x14" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\xa1\x27" /* 2 [1] IMPL SEQ */ + "\x30\x25" /* 2 SEQ */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\xa2\x31" /* 2 [2] IMPL SEQ */ + "\x30\x2f" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x01\x00" /* 3 OCTET-STRING */ + "\x02\x05\x01\x00\x00\x00\x00", /* 7 INT */ + "seq4 3" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf4 c[4]; + struct TESTSeqOf4_b1 b1[4]; + struct TESTSeqOf4_b2 b2[4]; + struct TESTSeqOf4_b3 b3[4]; + struct TESTSeqOf4_b1_val b1val[4]; + struct TESTSeqOf4_b2_val b2val[4]; + struct TESTSeqOf4_b3_val b3val[4]; + + c[0].b1 = NULL; + c[0].b2 = NULL; + c[0].b3 = NULL; + tests[0].val = &c[0]; + + b2[1].len = 0; + b2[1].val = NULL; + c[1].b1 = NULL; + c[1].b2 = &b2[1]; + c[1].b3 = NULL; + tests[1].val = &c[1]; + + b1[2].len = 0; + b1[2].val = NULL; + b2[2].len = 0; + b2[2].val = NULL; + c[2].b1 = &b1[2]; + c[2].b2 = &b2[2]; + c[2].b3 = NULL; + tests[2].val = &c[2]; + + b1val[3].s1.data = ""; + b1val[3].s1.length = 0; + b1val[3].u1 = 1LL; + b1val[3].s2.data = "\x01\x02"; + b1val[3].s2.length = 2; + b1val[3].u2 = (TESTuint64)-1LL; + + b2val[3].s1.data = ""; + b2val[3].s1.length = 0; + b2val[3].u1 = 1LL; + b2val[3].s2.data = "\x01\x02"; + b2val[3].s2.length = 2; + b2val[3].u2 = (TESTuint64)-1LL; + b2val[3].s3.data = "\x00\x01\x02\x03"; + b2val[3].s3.length = 4; + b2val[3].u3 = 1ULL<<63; + + b3val[3].s1.data = ""; + b3val[3].s1.length = 0; + b3val[3].u1 = 1LL; + b3val[3].s2.data = "\x01\x02"; + b3val[3].s2.length = 2; + b3val[3].u2 = (TESTuint64)-1LL; + b3val[3].s3.data = "\x00\x01\x02\x03"; + b3val[3].s3.length = 4; + b3val[3].u3 = 1ULL<<63; + b3val[3].s4.data = "\x00"; + b3val[3].s4.length = 1; + b3val[3].u4 = 1LL<<32; + + b1[3].len = 1; + b1[3].val = &b1val[3]; + b2[3].len = 1; + b2[3].val = &b2val[3]; + b3[3].len = 1; + b3[3].val = &b3val[3]; + c[3].b1 = &b1[3]; + c[3].b2 = &b2[3]; + c[3].b3 = &b3[3]; + tests[3].val = &c[3]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf4), + (generic_encode)encode_TESTSeqOf4, + (generic_length)length_TESTSeqOf4, + (generic_decode)decode_TESTSeqOf4, + (generic_free)free_TESTSeqOf4, + cmp_dummy, + NULL); + return ret; +} + +static int +cmp_test_seqof5 (void *a, void *b) +{ + TESTSeqOf5 *aval = a; + TESTSeqOf5 *bval = b; + + IF_OPT_COMPARE(aval, bval, outer) { + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u0); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s0); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u1); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s1); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u2); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s2); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u3); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s3); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u4); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s4); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u5); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s5); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u6); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s6); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u7); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s7); + } + return 0; +} + +static int +test_seqof5(void) +{ + struct test_case tests[] = { + { NULL, 2, "\x30\x00", "seq5 0" }, + { NULL, 126, + "\x30\x7c" /* SEQ */ + "\x30\x7a" /* SEQ */ + "\x30\x78" /* SEQ */ + "\x02\x01\x01" /* INT 1 */ + "\x04\x06\x01\x01\x01\x01\x01\x01" /* "\0x1"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfe" /* INT ~1 */ + "\x04\x06\x02\x02\x02\x02\x02\x02" /* "\x02"x6 */ + "\x02\x01\x02" /* INT 2 */ + "\x04\x06\x03\x03\x03\x03\x03\x03" /* "\x03"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfd" /* INT ~2 */ + "\x04\x06\x04\x04\x04\x04\x04\x04" /* ... */ + "\x02\x01\x03" + "\x04\x06\x05\x05\x05\x05\x05\x05" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfc" + "\x04\x06\x06\x06\x06\x06\x06\x06" + "\x02\x01\x04" + "\x04\x06\x07\x07\x07\x07\x07\x07" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfb" + "\x04\x06\x08\x08\x08\x08\x08\x08", + "seq5 1" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf5 c[2]; + struct TESTSeqOf5_outer outer; + struct TESTSeqOf5_outer_inner inner; + TESTuint64 u[8]; + heim_octet_string s[8]; + int i; + + c[0].outer = NULL; + tests[0].val = &c[0]; + + for (i = 0; i < 8; ++i) { + u[i] = (i&1) == 0 ? i/2+1 : ~(i/2+1); + s[i].data = memset(malloc(s[i].length = 6), i+1, 6); + } + + inner.u0 = u[0]; inner.u1 = u[1]; inner.u2 = u[2]; inner.u3 = u[3]; + inner.u4 = u[4]; inner.u5 = u[5]; inner.u6 = u[6]; inner.u7 = u[7]; + inner.s0 = s[0]; inner.s1 = s[1]; inner.s2 = s[2]; inner.s3 = s[3]; + inner.s4 = s[4]; inner.s5 = s[5]; inner.s6 = s[6]; inner.s7 = s[7]; + + outer.inner = inner; + c[1].outer = &outer; + tests[1].val = &c[1]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf5), + (generic_encode)encode_TESTSeqOf5, + (generic_length)length_TESTSeqOf5, + (generic_decode)decode_TESTSeqOf5, + (generic_free)free_TESTSeqOf5, + cmp_test_seqof5, + NULL); + + for (i = 0; i < 8; ++i) + free(s[i].data); + + return ret; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_uint64(); + ret += test_seqofseq(); + ret += test_seqofseq2(); + ret += test_seqof2(); + ret += test_seqof3(); + ret += test_seqof4(); + ret += test_seqof5(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-timegm.c b/third_party/heimdal/lib/asn1/check-timegm.c new file mode 100644 index 0000000..13d3abc --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-timegm.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +RCSID("$Id$"); + +static int +test_timegm(void) +{ + int ret = 0; + struct tm tm; + time_t t; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 106; + tm.tm_mon = 9; + tm.tm_mday = 1; + tm.tm_hour = 10; + tm.tm_min = 3; + + t = _der_timegm(&tm); + if (t != 1159696980) + ret += 1; + + tm.tm_mday = 0; + t = _der_timegm(&tm); + if (t != -1) + ret += 1; + + _der_gmtime(1159696980, &tm); + if (tm.tm_year != 106 || + tm.tm_mon != 9 || + tm.tm_mday != 1 || + tm.tm_hour != 10 || + tm.tm_min != 3 || + tm.tm_sec != 0) + errx(1, "tmtime failes"); + + return ret; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_timegm(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/cms.asn1 b/third_party/heimdal/lib/asn1/cms.asn1 new file mode 100644 index 0000000..ae547e5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/cms.asn1 @@ -0,0 +1,149 @@ +-- From RFC 3369 -- +-- $Id$ -- + +CMS DEFINITIONS ::= BEGIN + +IMPORTS CertificateSerialNumber, AlgorithmIdentifier, Name, + Attribute, Certificate, SubjectKeyIdentifier FROM rfc2459 + HEIM_ANY FROM heim; + +id-pkcs7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) } + +id-pkcs7-data OBJECT IDENTIFIER ::= { id-pkcs7 1 } +id-pkcs7-signedData OBJECT IDENTIFIER ::= { id-pkcs7 2 } +id-pkcs7-envelopedData OBJECT IDENTIFIER ::= { id-pkcs7 3 } +id-pkcs7-signedAndEnvelopedData OBJECT IDENTIFIER ::= { id-pkcs7 4 } +id-pkcs7-digestedData OBJECT IDENTIFIER ::= { id-pkcs7 5 } +id-pkcs7-encryptedData OBJECT IDENTIFIER ::= { id-pkcs7 6 } + +CMSVersion ::= INTEGER { + cMSVersion-v0(0), + cMSVersion-v1(1), + cMSVersion-v2(2), + cMSVersion-v3(3), + cMSVersion-v4(4) +} + +DigestAlgorithmIdentifier ::= AlgorithmIdentifier +DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier +SignatureAlgorithmIdentifier ::= AlgorithmIdentifier + +ContentType ::= OBJECT IDENTIFIER +MessageDigest ::= OCTET STRING + +ContentInfo ::= SEQUENCE { + contentType ContentType, + content [0] EXPLICIT HEIM_ANY OPTIONAL -- DEFINED BY contentType +} + +EncapsulatedContentInfo ::= SEQUENCE { + eContentType ContentType, + eContent [0] EXPLICIT OCTET STRING OPTIONAL +} + +CertificateSet ::= SET OF HEIM_ANY + +CertificateList ::= Certificate + +CertificateRevocationLists ::= SET OF CertificateList + +IssuerAndSerialNumber ::= SEQUENCE { + issuer Name, + serialNumber CertificateSerialNumber +} + +-- RecipientIdentifier is same as SignerIdentifier, +-- lets glue them togheter and save some bytes and share code for them + +CMSIdentifier ::= CHOICE { + issuerAndSerialNumber IssuerAndSerialNumber, + subjectKeyIdentifier [0] SubjectKeyIdentifier +} + +SignerIdentifier ::= CMSIdentifier +RecipientIdentifier ::= CMSIdentifier + +--- CMSAttributes are the combined UnsignedAttributes and SignedAttributes +--- to store space and share code + +CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX) + +SignatureValue ::= OCTET STRING + +SignerInfo ::= SEQUENCE { + version CMSVersion, + sid SignerIdentifier, + digestAlgorithm DigestAlgorithmIdentifier, + signedAttrs [0] IMPLICIT CMSAttributes OPTIONAL, + signatureAlgorithm SignatureAlgorithmIdentifier, + signature SignatureValue, + unsignedAttrs [1] IMPLICIT CMSAttributes OPTIONAL +} + +SignerInfos ::= SET OF SignerInfo + +SignedData ::= SEQUENCE { + version CMSVersion, + digestAlgorithms DigestAlgorithmIdentifiers, + encapContentInfo EncapsulatedContentInfo, + certificates [0] IMPLICIT CertificateSet OPTIONAL, + crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + signerInfos SignerInfos +} + +OriginatorInfo ::= SEQUENCE { + certs [0] IMPLICIT CertificateSet OPTIONAL, + crls [1] IMPLICIT CertificateRevocationLists OPTIONAL +} + +KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier +ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + +EncryptedKey ::= OCTET STRING + +KeyTransRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 0 or 2 + rid RecipientIdentifier, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + encryptedKey EncryptedKey +} + +RecipientInfo ::= KeyTransRecipientInfo + +RecipientInfos ::= SET OF RecipientInfo + +EncryptedContent ::= OCTET STRING + +EncryptedContentInfo ::= SEQUENCE { + contentType ContentType, + contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + encryptedContent [0] IMPLICIT OCTET STRING OPTIONAL +} + +UnprotectedAttributes ::= SET OF Attribute -- SIZE (1..MAX) + +CMSEncryptedData ::= SEQUENCE { + version CMSVersion, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL +} + +EnvelopedData ::= SEQUENCE { + version CMSVersion, + originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + recipientInfos RecipientInfos, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL +} + +-- Data ::= OCTET STRING + +CMSRC2CBCParameter ::= SEQUENCE { + rc2ParameterVersion INTEGER (0..4294967295), + iv OCTET STRING -- exactly 8 octets +} + +CMSCBCParameter ::= OCTET STRING + +END diff --git a/third_party/heimdal/lib/asn1/cms.opt b/third_party/heimdal/lib/asn1/cms.opt new file mode 100644 index 0000000..49333e5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/cms.opt @@ -0,0 +1,2 @@ +--decode-dce-ber +--sequence=DigestAlgorithmIdentifiers diff --git a/third_party/heimdal/lib/asn1/crmf.asn1 b/third_party/heimdal/lib/asn1/crmf.asn1 new file mode 100644 index 0000000..696a89b --- /dev/null +++ b/third_party/heimdal/lib/asn1/crmf.asn1 @@ -0,0 +1,110 @@ +-- $Id$ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Time, + GeneralName, + SubjectPublicKeyInfo, + RelativeDistinguishedName, + AttributeTypeAndValue, + Extension, + AlgorithmIdentifier + FROM rfc2459 + HEIM_ANY + FROM heim; + +CRMFRDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +Controls ::= SEQUENCE -- SIZE(1..MAX) -- OF AttributeTypeAndValue + +PKMACValue ::= SEQUENCE { + algId AlgorithmIdentifier, + value BIT STRING +} + +-- XXX IMPLICIT brokenness +POPOSigningKeyInput ::= SEQUENCE { + authInfo CHOICE { + sender [0] IMPLICIT GeneralName, + publicKeyMAC PKMACValue + }, + publicKey SubjectPublicKeyInfo +} -- from CertTemplate + +-- XXX IMPLICIT brokenness +POPOSigningKey ::= SEQUENCE { + poposkInput [0] IMPLICIT POPOSigningKeyInput OPTIONAL, + algorithmIdentifier AlgorithmIdentifier, + signature BIT STRING } + +PBMParameter ::= SEQUENCE { + salt OCTET STRING, + owf AlgorithmIdentifier, + iterationCount INTEGER, + mac AlgorithmIdentifier +} + +SubsequentMessage ::= INTEGER { + encrCert (0), + challengeResp (1) +} + +POPOPrivKey ::= CHOICE { + thisMessage [0] BIT STRING, -- Deprecated + subsequentMessage [1] IMPLICIT SubsequentMessage, + dhMAC [2] BIT STRING, -- Deprecated + agreeMAC [3] IMPLICIT PKMACValue, + encryptedKey [4] HEIM_ANY +} + +ProofOfPossession ::= CHOICE { + raVerified [0] NULL, + signature [1] POPOSigningKey, + keyEncipherment [2] POPOPrivKey, + keyAgreement [3] POPOPrivKey +} + +CertTemplate ::= SEQUENCE { + version [0] INTEGER OPTIONAL, + serialNumber [1] INTEGER OPTIONAL, + signingAlg [2] SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters HEIM_ANY OPTIONAL + } -- AlgorithmIdentifier -- OPTIONAL, + issuer [3] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + validity [4] SEQUENCE { + notBefore [0] Time OPTIONAL, + notAfter [1] Time OPTIONAL + } -- OptionalValidity -- OPTIONAL, + subject [5] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + publicKey [6] IMPLICIT SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING OPTIONAL + } -- SubjectPublicKeyInfo -- OPTIONAL, + issuerUID [7] IMPLICIT BIT STRING OPTIONAL, + subjectUID [8] IMPLICIT BIT STRING OPTIONAL, + extensions [9] IMPLICIT SEQUENCE OF Extension OPTIONAL +} + +CertRequest ::= SEQUENCE { + certReqId INTEGER, + certTemplate CertTemplate, + controls Controls OPTIONAL +} + +CertReqMsg ::= SEQUENCE { + certReq CertRequest, + popo ProofOfPossession OPTIONAL, + regInfo SEQUENCE OF AttributeTypeAndValue OPTIONAL } + +CertReqMessages ::= SEQUENCE OF CertReqMsg + + +END + diff --git a/third_party/heimdal/lib/asn1/crmf.opt b/third_party/heimdal/lib/asn1/crmf.opt new file mode 100644 index 0000000..e69de29 diff --git a/third_party/heimdal/lib/asn1/der.c b/third_party/heimdal/lib/asn1/der.c new file mode 100644 index 0000000..bea4ae5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include +#include +#include +#include +#include + +RCSID("$Id$"); + + +static const char *class_names[] = { + "UNIV", /* 0 */ + "APPL", /* 1 */ + "CONTEXT", /* 2 */ + "PRIVATE" /* 3 */ +}; + +static const char *type_names[] = { + "PRIM", /* 0 */ + "CONS" /* 1 */ +}; + +static const char *tag_names[] = { + "EndOfContent", /* 0 */ + "Boolean", /* 1 */ + "Integer", /* 2 */ + "BitString", /* 3 */ + "OctetString", /* 4 */ + "Null", /* 5 */ + "ObjectID", /* 6 */ + NULL, /* 7 */ + NULL, /* 8 */ + NULL, /* 9 */ + "Enumerated", /* 10 */ + NULL, /* 11 */ + "UTF8String", /* 12 */ + NULL, /* 13 */ + NULL, /* 14 */ + NULL, /* 15 */ + "Sequence", /* 16 */ + "Set", /* 17 */ + NULL, /* 18 */ + "PrintableString", /* 19 */ + NULL, /* 20 */ + NULL, /* 21 */ + "IA5String", /* 22 */ + "UTCTime", /* 23 */ + "GeneralizedTime", /* 24 */ + NULL, /* 25 */ + "VisibleString", /* 26 */ + "GeneralString", /* 27 */ + NULL, /* 28 */ + NULL, /* 29 */ + "BMPString" /* 30 */ +}; + +static int +get_type(const char *name, const char *list[], unsigned len) +{ + unsigned i; + for (i = 0; i < len; i++) + if (list[i] && strcasecmp(list[i], name) == 0) + return i; + return -1; +} + +#define SIZEOF_ARRAY(a) (sizeof((a))/sizeof((a)[0])) + +const char * ASN1CALL +der_get_class_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(class_names)) + return NULL; + return class_names[num]; +} + +int ASN1CALL +der_get_class_num(const char *name) +{ + return get_type(name, class_names, SIZEOF_ARRAY(class_names)); +} + +const char * ASN1CALL +der_get_type_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(type_names)) + return NULL; + return type_names[num]; +} + +int ASN1CALL +der_get_type_num(const char *name) +{ + return get_type(name, type_names, SIZEOF_ARRAY(type_names)); +} + +const char * ASN1CALL +der_get_tag_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(tag_names)) + return NULL; + return tag_names[num]; +} + +int ASN1CALL +der_get_tag_num(const char *name) +{ + return get_type(name, tag_names, SIZEOF_ARRAY(tag_names)); +} diff --git a/third_party/heimdal/lib/asn1/der.h b/third_party/heimdal/lib/asn1/der.h new file mode 100644 index 0000000..ec5603e --- /dev/null +++ b/third_party/heimdal/lib/asn1/der.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_H__ +#define __DER_H__ + +#include + +typedef enum { + ASN1_C_UNIV = 0, + ASN1_C_APPL = 1, + ASN1_C_CONTEXT = 2, + ASN1_C_PRIVATE = 3 +} Der_class; + +typedef enum {PRIM = 0, CONS = 1} Der_type; + +#define MAKE_TAG(CLASS, TYPE, TAG) (((CLASS) << 6) | ((TYPE) << 5) | (TAG)) + +/* Universal tags */ + +enum { + UT_EndOfContent = 0, + UT_Boolean = 1, + UT_Integer = 2, + UT_BitString = 3, + UT_OctetString = 4, + UT_Null = 5, + UT_OID = 6, + UT_Enumerated = 10, + UT_UTF8String = 12, + UT_Sequence = 16, + UT_Set = 17, + UT_PrintableString = 19, + UT_IA5String = 22, + UT_UTCTime = 23, + UT_GeneralizedTime = 24, + UT_VisibleString = 26, + UT_GeneralString = 27, + UT_UniversalString = 28, + UT_BMPString = 30, + /* unsupported types */ + UT_ObjectDescriptor = 7, + UT_External = 8, + UT_Real = 9, + UT_EmbeddedPDV = 11, + UT_RelativeOID = 13, + UT_NumericString = 18, + UT_TeletexString = 20, + UT_VideotexString = 21, + UT_GraphicString = 25 +}; + +#define ASN1_INDEFINITE 0xdce0deed + +typedef struct heim_der_time_t { + time_t dt_sec; + unsigned long dt_nsec; +} heim_der_time_t; + +typedef struct heim_ber_time_t { + time_t bt_sec; + unsigned bt_nsec; + int bt_zone; +} heim_ber_time_t; + +struct asn1_template; + +#include + +int _heim_fix_dce(size_t reallen, size_t *len); +int _heim_der_set_sort(const void *, const void *); +int _heim_time2generalizedtime (time_t, heim_octet_string *, int); + +#endif /* __DER_H__ */ diff --git a/third_party/heimdal/lib/asn1/der_cmp.c b/third_party/heimdal/lib/asn1/der_cmp.c new file mode 100644 index 0000000..f745270 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_cmp.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +int ASN1CALL +der_heim_oid_cmp(const heim_oid *p, const heim_oid *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->components, + q->components, + p->length * sizeof(*p->components)); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->components, + q->components, + p->length * sizeof(*p->components))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->components, + q->components, + q->length * sizeof(*p->components))) == 0) + return 1; + return c; +} + +int ASN1CALL +der_heim_octet_string_cmp(const heim_octet_string *p, + const heim_octet_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length)) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length)) == 0) + return 1; + return c; +} + +int ASN1CALL +der_printable_string_cmp(const heim_printable_string *p, + const heim_printable_string *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +der_ia5_string_cmp(const heim_ia5_string *p, + const heim_ia5_string *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +der_heim_bit_string_cmp(const heim_bit_string *p, + const heim_bit_string *q) +{ + unsigned char pc, qc; + size_t bits; + int c = 0; + + /* Compare prefix */ + if (p->length == 0 && q->length == 0) + return 0; + if (p->length > 7 && q->length > 7) { + if (p->length < q->length) + c = memcmp(p->data, q->data, p->length / 8); + else + c = memcmp(p->data, q->data, q->length / 8); + } + if (c) + return c; + + /* Prefixes are equal, c == 0 */ + + if (p->length == q->length && p->length % 8 == 0) + return 0; + if (p->length == 0 && q->length) + return -1; /* No trailing bits of p to compare to corresponding bits of q */ + if (q->length == 0 && p->length) + return 1; /* No trailing bits of q to compare to corresponding bits of p */ + + /* c == 0, lengths are not equal, both are at least 1 bit */ + pc = ((unsigned char *)p->data)[p->length / 8]; + qc = ((unsigned char *)q->data)[q->length / 8]; + if (p->length < q->length) + bits = p->length % 8; + else + bits = q->length % 8; + + if (bits > 0) { + if ((pc & 0x80) == 0 && (qc & 0x80) != 0) + return -1; + if ((pc & 0x80) != 0 && (qc & 0x80) == 0) + return 1; + } + if (bits > 1) { + if ((pc & 0x40) == 0 && (qc & 0x40) != 0) + return -1; + if ((pc & 0x40) != 0 && (qc & 0x40) == 0) + return 1; + } + if (bits > 2) { + if ((pc & 0x20) == 0 && (qc & 0x20) != 0) + return -1; + if ((pc & 0x20) != 0 && (qc & 0x20) == 0) + return 1; + } + if (bits > 3) { + if ((pc & 0x10) == 0 && (qc & 0x10) != 0) + return -1; + if ((pc & 0x10) != 0 && (qc & 0x10) == 0) + return 1; + } + if (bits > 4) { + if ((pc & 0x08) == 0 && (qc & 0x08) != 0) + return -1; + if ((pc & 0x08) != 0 && (qc & 0x08) == 0) + return 1; + } + if (bits > 5) { + if ((pc & 0x04) == 0 && (qc & 0x04) != 0) + return -1; + if ((pc & 0x04) != 0 && (qc & 0x04) == 0) + return 1; + } + if (bits > 6) { + if ((pc & 0x02) == 0 && (qc & 0x02) != 0) + return -1; + if ((pc & 0x02) != 0 && (qc & 0x02) == 0) + return 1; + } + /* + * `bits' can't be 8. + * + * All leading `bits' bits of the tail of the shorter of `p' or `q' are + * equal. + */ + if (p->length < q->length) + return -1; + if (q->length < p->length) + return 1; + return 0; +} + +int ASN1CALL +der_heim_integer_cmp(const heim_integer *p, + const heim_integer *q) +{ + if (p->negative != q->negative) + return q->negative - p->negative; + if (p->length != q->length) + return (int)(p->length - q->length); + return memcmp(p->data, q->data, p->length); +} + +int ASN1CALL +der_heim_bmp_string_cmp(const heim_bmp_string *p, const heim_bmp_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length * sizeof(q->data[0])); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length * sizeof(q->data[0]))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length * sizeof(q->data[0]))) == 0) + return 1; + return c; +} + +int ASN1CALL +der_heim_universal_string_cmp(const heim_universal_string *p, + const heim_universal_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length * sizeof(q->data[0])); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length * sizeof(q->data[0]))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length * sizeof(q->data[0]))) == 0) + return 1; + return c; +} diff --git a/third_party/heimdal/lib/asn1/der_copy.c b/third_party/heimdal/lib/asn1/der_copy.c new file mode 100644 index 0000000..f67fff6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_copy.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +int ASN1CALL +der_copy_general_string (const heim_general_string *from, + heim_general_string *to) +{ + *to = strdup(*from); + if(*to == NULL) + return ENOMEM; + return 0; +} + +int ASN1CALL +der_copy_integer (const int *from, int *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_integer64 (const int64_t *from, int64_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_unsigned (const unsigned *from, unsigned *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_unsigned64 (const uint64_t *from, uint64_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_generalized_time (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_utctime (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_utf8string (const heim_utf8_string *from, heim_utf8_string *to) +{ + return der_copy_general_string(from, to); +} + +int ASN1CALL +der_copy_printable_string (const heim_printable_string *from, + heim_printable_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + to->data = malloc(from->length + 1); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + ((char *)to->data)[to->length] = '\0'; + return 0; +} + +int ASN1CALL +der_copy_ia5_string (const heim_ia5_string *from, + heim_ia5_string *to) +{ + return der_copy_printable_string(from, to); +} + +int ASN1CALL +der_copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length * sizeof(to->data[0])); + return 0; +} + +int ASN1CALL +der_copy_universal_string (const heim_universal_string *from, + heim_universal_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length * sizeof(to->data[0])); + return 0; +} + +int ASN1CALL +der_copy_visible_string (const heim_visible_string *from, + heim_visible_string *to) +{ + return der_copy_general_string(from, to); +} + +int ASN1CALL +der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) { + if (from->data == NULL) { + *to = *from; + return 0; + } + to->data = calloc(1, 1); + } else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + return 0; +} + +int ASN1CALL +der_copy_heim_integer (const heim_integer *from, heim_integer *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, 1); + else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + to->negative = from->negative; + return 0; +} + +int ASN1CALL +der_copy_oid (const heim_oid *from, heim_oid *to) +{ + if (from->length == 0) { + to->length = 0; + to->components = calloc(1, sizeof(*from->components)); + if (to->components == NULL) + return ENOMEM; + return 0; + } + assert(from->components != NULL); + to->components = malloc(from->length * sizeof(*from->components)); + if (to->components == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + memcpy(to->components, from->components, + to->length * sizeof(*to->components)); + return 0; +} + +int ASN1CALL +der_copy_bit_string (const heim_bit_string *from, heim_bit_string *to) +{ + size_t len; + + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + + len = (from->length + 7) / 8; + if (len == 0) + to->data = calloc(1, 1); + else + to->data = malloc(len); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (len > 0) + memcpy(to->data, from->data, len); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_format.c b/third_party/heimdal/lib/asn1/der_format.c new file mode 100644 index 0000000..bb4a7ce --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_format.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include + +RCSID("$Id$"); + +int ASN1CALL +der_parse_hex_heim_integer (const char *p, heim_integer *data) +{ + ssize_t len; + + data->length = 0; + data->negative = 0; + data->data = NULL; + + if (*p == '-') { + p++; + data->negative = 1; + } + + len = strlen(p); + if (len <= 0) { + data->data = NULL; + data->length = 0; + return EINVAL; + } + + data->length = (len / 2) + 1; + data->data = malloc(data->length); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + + len = hex_decode(p, data->data, data->length); + if (len < 0) { + free(data->data); + data->data = NULL; + data->length = 0; + return EINVAL; + } + + { + unsigned char *q = data->data; + while(len > 0 && *q == 0) { + q++; + len--; + } + data->length = len; + memmove(data->data, q, len); + } + return 0; +} + +int ASN1CALL +der_print_hex_heim_integer (const heim_integer *data, char **p) +{ + ssize_t len; + char *q; + + len = hex_encode(data->data, data->length, p); + if (len < 0) + return ENOMEM; + + if (data->negative) { + len = asprintf(&q, "-%s", *p); + free(*p); + if (len < 0) + return ENOMEM; + *p = q; + } + return 0; +} + +int ASN1CALL +der_print_heim_oid (const heim_oid *oid, char delim, char **str) +{ + struct rk_strpool *p = NULL; + size_t i; + + if (oid->length == 0) + return EINVAL; + + for (i = 0; i < oid->length ; i++) { + p = rk_strpoolprintf(p, "%d", oid->components[i]); + if (p && i < oid->length - 1) + p = rk_strpoolprintf(p, "%c", delim); + if (p == NULL) { + *str = NULL; + return ENOMEM; + } + } + + *str = rk_strpoolcollect(p); + if (*str == NULL) + return ENOMEM; + return 0; +} + +int ASN1CALL +der_parse_heim_oid (const char *str, const char *sep, heim_oid *data) +{ + char *s, *w, *brkt, *endptr; + unsigned int *c; + long l; + + data->length = 0; + data->components = NULL; + + if (sep == NULL) + sep = "."; + + s = strdup(str); + + for (w = strtok_r(s, sep, &brkt); + w != NULL; + w = strtok_r(NULL, sep, &brkt)) { + + c = realloc(data->components, + (data->length + 1) * sizeof(data->components[0])); + if (c == NULL) { + der_free_oid(data); + free(s); + return ENOMEM; + } + data->components = c; + + l = strtol(w, &endptr, 10); + if (*endptr != '\0' || l < 0 || l > INT_MAX) { + der_free_oid(data); + free(s); + return EINVAL; + } + data->components[data->length++] = (unsigned int)l; + } + free(s); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_free.c b/third_party/heimdal/lib/asn1/der_free.c new file mode 100644 index 0000000..d80406f --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_free.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +void ASN1CALL +der_free_general_string (heim_general_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_integer (int *i) +{ + *i = 0; +} + +void ASN1CALL +der_free_integer64 (int64_t *i) +{ + *i = 0; +} + +void ASN1CALL +der_free_unsigned (unsigned *u) +{ + *u = 0; +} + +void ASN1CALL +der_free_unsigned64 (uint64_t *u) +{ + *u = 0; +} + +void ASN1CALL +der_free_generalized_time(time_t *t) +{ + *t = 0; +} + +void ASN1CALL +der_free_utctime(time_t *t) +{ + *t = 0; +} + + +void ASN1CALL +der_free_utf8string (heim_utf8_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_printable_string (heim_printable_string *str) +{ + der_free_octet_string(str); +} + +void ASN1CALL +der_free_ia5_string (heim_ia5_string *str) +{ + der_free_octet_string(str); +} + +void ASN1CALL +der_free_bmp_string (heim_bmp_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_universal_string (heim_universal_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_visible_string (heim_visible_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_octet_string (heim_octet_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_heim_integer (heim_integer *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_oid (heim_oid *k) +{ + free(k->components); + k->components = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_bit_string (heim_bit_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} diff --git a/third_party/heimdal/lib/asn1/der_get.c b/third_party/heimdal/lib/asn1/der_get.c new file mode 100644 index 0000000..06564b7 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_get.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +/* + * All decoding functions take a pointer `p' to first position in + * which to read, from the left, `len' which means the maximum number + * of characters we are able to read, `ret' were the value will be + * returned and `size' where the number of used bytes is stored. + * Either 0 or an error code is returned. + */ + +int ASN1CALL +der_get_unsigned (const unsigned char *p, size_t len, + unsigned *ret, size_t *size) +{ + unsigned val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && p[0] == 0) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_unsigned64 (const unsigned char *p, size_t len, + uint64_t *ret, size_t *size) +{ + uint64_t val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && p[0] == 0) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_integer (const unsigned char *p, size_t len, + int *ret, size_t *size) +{ + int val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && (p[0] == 0 || p[0] == 0xff)) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + /* We assume we're on a twos-complement platform */ + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_integer64 (const unsigned char *p, size_t len, + int64_t *ret, size_t *size) +{ + int64_t val = 0; + size_t oldlen = len; + + if (len > sizeof(val)) + return ASN1_OVERRUN; + + /* We assume we're on a twos-complement platform */ + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + + +int ASN1CALL +der_get_length (const unsigned char *p, size_t len, + size_t *val, size_t *size) +{ + size_t v; + + if (len <= 0) + return ASN1_OVERRUN; + --len; + v = *p++; + if (v < 128) { + *val = v; + if(size) *size = 1; + } else { + int e; + size_t l; + unsigned tmp; + + if(v == 0x80){ + *val = ASN1_INDEFINITE; + if(size) *size = 1; + return 0; + } + v &= 0x7F; + if (len < v) + return ASN1_OVERRUN; + e = der_get_unsigned (p, v, &tmp, &l); + if(e) return e; + *val = tmp; + if(size) *size = l + 1; + } + return 0; +} + +int ASN1CALL +der_get_boolean(const unsigned char *p, size_t len, int *data, size_t *size) +{ + if(len < 1) + return ASN1_OVERRUN; + if(*p != 0) + *data = 1; + else + *data = 0; + *size = 1; + return 0; +} + +int ASN1CALL +der_get_general_string (const unsigned char *p, size_t len, + heim_general_string *str, size_t *size) +{ + const unsigned char *p1; + char *s; + + assert(p != NULL); + + if (size) + *size = 0; + + p1 = memchr(p, 0, len); + if (p1 != NULL) { + /* + * Allow trailing NULs. We allow this since MIT Kerberos sends + * an strings in the NEED_PREAUTH case that includes a + * trailing NUL. + */ + while ((size_t)(p1 - p) < len && *p1 == '\0') + p1++; + if ((size_t)(p1 - p) != len) { + *str = NULL; + return ASN1_BAD_CHARACTER; + } + } + if (len == SIZE_MAX) { + *str = NULL; + return ASN1_BAD_LENGTH; + } + + *str = s = malloc (len + 1); + if (s == NULL) + return ENOMEM; + memcpy (s, p, len); + s[len] = '\0'; + + if(size) *size = len; + return 0; +} + +int ASN1CALL +der_get_utf8string (const unsigned char *p, size_t len, + heim_utf8_string *str, size_t *size) +{ + return der_get_general_string(p, len, str, size); +} + +#define gen_data_zero(_data) \ + do { (_data)->length = 0; (_data)->data = NULL; } while(0) + +int ASN1CALL +der_get_printable_string(const unsigned char *p, size_t len, + heim_printable_string *str, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len == SIZE_MAX) { + gen_data_zero(str); + return ASN1_BAD_LENGTH; + } + str->length = len; + str->data = malloc(len + 1); + if (str->data == NULL) { + gen_data_zero(str); + return ENOMEM; + } + + memcpy(str->data, p, len); + ((char *)str->data)[len] = '\0'; + if(size) *size = len; + return 0; +} + +int ASN1CALL +der_get_ia5_string(const unsigned char *p, size_t len, + heim_ia5_string *str, size_t *size) +{ + return der_get_printable_string(p, len, str, size); +} + +int ASN1CALL +der_get_bmp_string (const unsigned char *p, size_t len, + heim_bmp_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len & 1) { + gen_data_zero(data); + return ASN1_BAD_FORMAT; + } + data->length = len / 2; + if (data->length > UINT_MAX/sizeof(data->data[0])) { + gen_data_zero(data); + return ERANGE; + } + data->data = malloc(data->length * sizeof(data->data[0])); + if (data->data == NULL && data->length != 0) { + gen_data_zero(data); + return ENOMEM; + } + + for (i = 0; i < data->length; i++) { + data->data[i] = (p[0] << 8) | p[1]; + p += 2; + /* check for NUL in the middle of the string */ + if (data->data[i] == 0 && i != (data->length - 1)) { + free(data->data); + gen_data_zero(data); + return ASN1_BAD_CHARACTER; + } + } + if (size) *size = len; + + return 0; +} + +int ASN1CALL +der_get_universal_string (const unsigned char *p, size_t len, + heim_universal_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len & 3) { + gen_data_zero(data); + return ASN1_BAD_FORMAT; + } + data->length = len / 4; + if (data->length > UINT_MAX/sizeof(data->data[0])) { + gen_data_zero(data); + return ERANGE; + } + data->data = malloc(data->length * sizeof(data->data[0])); + if (data->data == NULL && data->length != 0) { + gen_data_zero(data); + return ENOMEM; + } + + for (i = 0; i < data->length; i++) { + data->data[i] = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + /* check for NUL in the middle of the string */ + if (data->data[i] == 0 && i != (data->length - 1)) { + free(data->data); + gen_data_zero(data); + return ASN1_BAD_CHARACTER; + } + } + if (size) *size = len; + return 0; +} + +int ASN1CALL +der_get_visible_string (const unsigned char *p, size_t len, + heim_visible_string *str, size_t *size) +{ + return der_get_general_string(p, len, str, size); +} + +int ASN1CALL +der_get_octet_string (const unsigned char *p, size_t len, + heim_octet_string *data, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len == 0) + data->data = malloc(1); + else + data->data = malloc(len); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + data->length = len; + memcpy (data->data, p, len); + if (size) + *size = len; + return 0; +} + +int ASN1CALL +der_get_octet_string_ber (const unsigned char *p, size_t len, + heim_octet_string *data, size_t *size) +{ + int e; + Der_type type; + Der_class cls; + unsigned int tag, depth = 0; + size_t l, datalen, oldlen = len; + + assert(p != NULL); + + if (size) + *size = 0; + + data->length = 0; + data->data = NULL; + + while (len) { + e = der_get_tag (p, len, &cls, &type, &tag, &l); + if (e) goto out; + if (cls != ASN1_C_UNIV) { + e = ASN1_BAD_ID; + goto out; + } + if (type == PRIM && tag == UT_EndOfContent) { + if (depth == 0) + break; + depth--; + } + if (tag != UT_OctetString) { + e = ASN1_BAD_ID; + goto out; + } + + p += l; + len -= l; + e = der_get_length (p, len, &datalen, &l); + if (e) goto out; + p += l; + len -= l; + + if (datalen > len) + return ASN1_OVERRUN; + + if (type == PRIM && datalen) { + void *ptr; + + ptr = realloc(data->data, data->length + datalen); + if (ptr == NULL) { + e = ENOMEM; + goto out; + } + data->data = ptr; + memcpy(((unsigned char *)data->data) + data->length, p, datalen); + data->length += datalen; + } else if (type != PRIM) + depth++; + + p += datalen; + len -= datalen; + } + if (depth != 0) + return ASN1_INDEF_OVERRUN; + if(size) *size = oldlen - len; + return 0; + out: + free(data->data); + data->data = NULL; + data->length = 0; + return e; +} + + +int ASN1CALL +der_get_heim_integer (const unsigned char *p, size_t len, + heim_integer *data, size_t *size) +{ + data->length = 0; + data->negative = 0; + data->data = NULL; + + if (size) + *size = 0; + + if (len == 0) + return 0; + + assert(p != NULL); + + if (p[0] & 0x80) { + unsigned char *q; + int carry = 1; + + + /* + * A negative number. It's going to be a twos complement byte array. + * We're going to leave the positive value in `data->data', but set the + * `data->negative' flag. That means we need to negate the + * twos-complement integer received. + */ + data->negative = 1; + data->length = len; + + if (p[0] == 0xff) { + if (data->length == 1) { + /* One byte of all ones == -1 */ + q = data->data = malloc(1); + *q = 1; + data->length = 1; + if (size) + *size = 1; + return 0; + } + + p++; + data->length--; + + /* + * We could check if the next byte's high bit is set, which would + * be an error ("illegal padding" in OpenSSL). However, this would + * mean failing to accept certificates made by certain CAs that + * would read 8 bytes of RNG into a buffer, slap on length 8, then + * slap on the tag [UNIVERSAL INTEGER], and make that the + * serialNumber field's encoding, which then fails to parse in + * around 1 in 256 certificates. + * + * So let's not. + * + * if (p[0] & 0x80) + * return ASN1_PARSE_ERROR; // or a new error code + */ + } + data->data = malloc(data->length); + if (data->data == NULL) { + data->length = 0; + if (size) + *size = 0; + return ENOMEM; + } + + /* + * Note that if `data->length' were zero, this would be UB because we + * underflow if data->length is zero even though we wouldn't actually + * dereference the byte before data->data. Thus we check above for + * that. + */ + q = &((unsigned char*)data->data)[data->length - 1]; + p += data->length - 1; + while (q >= (unsigned char*)data->data) { + /* *p XOR 0xff -> ~*p; we're dealing with twos complement */ + *q = *p ^ 0xff; + if (carry) + carry = !++*q; + p--; + q--; + } + } else { + data->negative = 0; + data->length = len; + + if (p[0] == 0) { + p++; + data->length--; + } + data->data = malloc(data->length); + if (data->data == NULL && data->length != 0) { + data->length = 0; + if (size) + *size = 0; + return ENOMEM; + } + memcpy(data->data, p, data->length); + } + if (size) + *size = len; + return 0; +} + +static int +generalizedtime2time (const char *s, time_t *t) +{ + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + if (sscanf (s, "%04d%02d%02d%02d%02d%02dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec) != 6) { + if (sscanf (s, "%02d%02d%02d%02d%02d%02dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec) != 6) + return ASN1_BAD_TIMEFORMAT; + if (tm.tm_year < 50) + tm.tm_year += 2000; + else + tm.tm_year += 1900; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + *t = _der_timegm (&tm); + return 0; +} + +static int ASN1CALL +der_get_time (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + char *times; + int e; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len == SIZE_MAX || len == 0) + return ASN1_BAD_LENGTH; + + times = malloc(len + 1); + if (times == NULL) + return ENOMEM; + memcpy(times, p, len); + times[len] = '\0'; + e = generalizedtime2time(times, data); + free (times); + if(size) *size = len; + return e; +} + +int ASN1CALL +der_get_generalized_time (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + return der_get_time(p, len, data, size); +} + +int ASN1CALL +der_get_utctime (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + return der_get_time(p, len, data, size); +} + +int ASN1CALL +der_get_oid (const unsigned char *p, size_t len, + heim_oid *data, size_t *size) +{ + size_t n; + size_t oldlen = len; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERRUN; + + if (len == SIZE_MAX) + return ASN1_BAD_LENGTH; + + if (len + 1 > UINT_MAX/sizeof(data->components[0])) + return ERANGE; + + data->components = malloc((len + 1) * sizeof(data->components[0])); + if (data->components == NULL) { + data->length = 0; + return ENOMEM; + } + data->components[0] = (*p) / 40; + data->components[1] = (*p) % 40; + --len; + ++p; + for (n = 2; len > 0; ++n) { + unsigned u = 0, u1; + + do { + --len; + u1 = u * 128 + (*p++ % 128); + /* check that we don't overflow the element */ + if (u1 < u) { + der_free_oid(data); + return ASN1_OVERRUN; + } + u = u1; + } while (len > 0 && p[-1] & 0x80); + data->components[n] = u; + } + if (n > 2 && p[-1] & 0x80) { + der_free_oid (data); + return ASN1_OVERRUN; + } + data->length = n; + if (size) + *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_tag (const unsigned char *p, size_t len, + Der_class *cls, Der_type *type, + unsigned int *tag, size_t *size) +{ + size_t ret = 0; + + if (size) + *size = 0; + + if (len < 1) + return ASN1_MISSING_FIELD; + + assert(p != NULL); + + *cls = (Der_class)(((*p) >> 6) & 0x03); + *type = (Der_type)(((*p) >> 5) & 0x01); + *tag = (*p) & 0x1f; + p++; len--; ret++; + if(*tag == 0x1f) { + unsigned int continuation; + unsigned int tag1; + *tag = 0; + do { + if(len < 1) + return ASN1_OVERRUN; + continuation = *p & 128; + tag1 = *tag * 128 + (*p % 128); + /* check that we don't overflow the tag */ + if (tag1 < *tag) + return ASN1_OVERFLOW; + *tag = tag1; + p++; len--; ret++; + } while(continuation); + } + if(size) *size = ret; + return 0; +} + +int ASN1CALL +der_match_tag (const unsigned char *p, size_t len, + Der_class cls, Der_type type, + unsigned int tag, size_t *size) +{ + Der_type thistype; + int e; + + e = der_match_tag2(p, len, cls, &thistype, tag, size); + if (e) return e; + if (thistype != type) return ASN1_BAD_ID; + return 0; +} + +int ASN1CALL +der_match_tag2 (const unsigned char *p, size_t len, + Der_class cls, Der_type *type, + unsigned int tag, size_t *size) +{ + size_t l; + Der_class thisclass; + unsigned int thistag; + int e; + + if (size) + *size = 0; + + e = der_get_tag(p, len, &thisclass, type, &thistag, &l); + if (e) return e; + /* + * We do depend on ASN1_BAD_ID being returned in places where we're + * essentially implementing an application-level CHOICE where we try to + * decode one way then the other. In Heimdal this happens only in lib/hdb/ + * where we try to decode a blob as an hdb_entry, then as an + * hdb_entry_alias. Applications should really not depend on this. + */ + if (cls != thisclass && (cls == ASN1_C_APPL || thisclass == ASN1_C_APPL)) + return ASN1_BAD_ID; + if (cls != thisclass || tag != thistag) + return ASN1_MISSING_FIELD; + if (size) *size = l; + return 0; +} + +/* + * Returns 0 if the encoded data at `p' of length `len' starts with the tag of + * class `cls`, type `type', and tag value `tag', and puts the length of the + * payload (i.e., the length of V in TLV, not the length of TLV) in + * `*length_ret', and the size of the whole thing (the TLV) in `*size' if + * `size' is not NULL. + * + * Else returns an error. + */ +int ASN1CALL +der_match_tag_and_length (const unsigned char *p, size_t len, + Der_class cls, Der_type *type, unsigned int tag, + size_t *length_ret, size_t *size) +{ + size_t l, ret = 0; + int e; + + e = der_match_tag2 (p, len, cls, type, tag, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, length_ret, &l); + if (e) return e; + if(size) *size = ret + l; + return 0; +} + + + +/* + * Old versions of DCE was based on a very early beta of the MIT code, + * which used MAVROS for ASN.1 encoding. MAVROS had the interesting + * feature that it encoded data in the forward direction, which has + * it's problems, since you have no idea how long the data will be + * until after you're done. MAVROS solved this by reserving one byte + * for length, and later, if the actual length was longer, it reverted + * to indefinite, BER style, lengths. The version of MAVROS used by + * the DCE people could apparently generate correct X.509 DER encodings, and + * did this by making space for the length after encoding, but + * unfortunately this feature wasn't used with Kerberos. + */ + +int +_heim_fix_dce(size_t reallen, size_t *len) +{ + if(reallen == ASN1_INDEFINITE) + return 1; + if(*len < reallen) + return -1; + *len = reallen; + return 0; +} + +int ASN1CALL +der_get_bit_string (const unsigned char *p, size_t len, + heim_bit_string *data, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERRUN; + if (p[0] > 7) + return ASN1_BAD_FORMAT; + if (len - 1 == 0 && p[0] != 0) + return ASN1_BAD_FORMAT; + /* check if any of the three upper bits are set + * any of them will cause a interger overrun */ + if ((len - 1) >> (sizeof(len) * 8 - 3)) + return ASN1_OVERRUN; + /* + * If there is data to copy, do that now. + */ + if (len - 1 > 0) { + data->length = (len - 1) * 8; + data->data = malloc(len - 1); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + memcpy (data->data, p + 1, len - 1); + data->length -= p[0]; + } else { + data->data = NULL; + data->length = 0; + } + if(size) *size = len; + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_length.c b/third_party/heimdal/lib/asn1/der_length.c new file mode 100644 index 0000000..cd50df8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_length.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +size_t +_heim_len_unsigned (unsigned val) +{ + size_t ret = 0; + int last_val_gt_128; + + do { + ++ret; + last_val_gt_128 = (val >= 128); + val /= 256; + } while (val); + + if(last_val_gt_128) + ret++; + + return ret; +} + +size_t +_heim_len_unsigned64 (uint64_t val) +{ + size_t ret = 0; + int last_val_gt_128; + + do { + ++ret; + last_val_gt_128 = (val >= 128); + val /= 256; + } while (val); + + if(last_val_gt_128) + ret++; + + return ret; +} + +size_t +_heim_len_int (int val) +{ + unsigned char q; + size_t ret = 0; + + if (val >= 0) { + do { + q = val % 256; + ret++; + val /= 256; + } while(val); + if(q >= 128) + ret++; + } else { + val = ~val; + do { + q = ~(val % 256); + ret++; + val /= 256; + } while(val); + if(q < 128) + ret++; + } + return ret; +} + +size_t +_heim_len_int64 (int64_t val) +{ + unsigned char q; + size_t ret = 0; + + if (val >= 0) { + do { + q = val % 256; + ret++; + val /= 256; + } while(val); + if(q >= 128) + ret++; + } else { + val = ~val; + do { + q = ~(val % 256); + ret++; + val /= 256; + } while(val); + if(q < 128) + ret++; + } + return ret; +} + +static size_t +len_oid (const heim_oid *oid) +{ + size_t ret = 1; + size_t n; + + for (n = 2; n < oid->length; ++n) { + unsigned u = oid->components[n]; + + do { + ++ret; + u /= 128; + } while(u > 0); + } + return ret; +} + +size_t ASN1CALL +der_length_len (size_t len) +{ + if (len < 128) + return 1; + else { + int ret = 0; + do { + ++ret; + len /= 256; + } while (len); + return ret + 1; + } +} + +size_t ASN1CALL +der_length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +size_t ASN1CALL +der_length_integer (const int *data) +{ + return _heim_len_int (*data); +} + +size_t ASN1CALL +der_length_integer64 (const int64_t *data) +{ + return _heim_len_int64 (*data); +} + +size_t ASN1CALL +der_length_unsigned (const unsigned *data) +{ + return _heim_len_unsigned(*data); +} + +size_t ASN1CALL +der_length_unsigned64 (const uint64_t *data) +{ + return _heim_len_unsigned64(*data); +} + +size_t ASN1CALL +der_length_enumerated (const unsigned *data) +{ + return _heim_len_int (*data); +} + +size_t ASN1CALL +der_length_general_string (const heim_general_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_utf8string (const heim_utf8_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_printable_string (const heim_printable_string *data) +{ + return data->length; +} + +size_t ASN1CALL +der_length_ia5_string (const heim_ia5_string *data) +{ + return data->length; +} + +size_t ASN1CALL +der_length_bmp_string (const heim_bmp_string *data) +{ + return data->length * 2; +} + +size_t ASN1CALL +der_length_universal_string (const heim_universal_string *data) +{ + return data->length * 4; +} + +size_t ASN1CALL +der_length_visible_string (const heim_visible_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_octet_string (const heim_octet_string *k) +{ + return k->length; +} + +size_t ASN1CALL +der_length_heim_integer (const heim_integer *k) +{ + if (k->length == 0) + return 1; + if (k->negative && k->length == 1 && ((unsigned char *)k->data)[0] == 1) + return 1; + else if (k->negative) + return k->length + (((~(((unsigned char *)k->data)[0])) & 0x80) ? 0 : 1); + else + return k->length + ((((unsigned char *)k->data)[0] & 0x80) ? 1 : 0); +} + +size_t ASN1CALL +der_length_oid (const heim_oid *k) +{ + return len_oid (k); +} + +size_t ASN1CALL +der_length_generalized_time (const time_t *t) +{ + heim_octet_string k; + size_t ret; + + _heim_time2generalizedtime (*t, &k, 1); + ret = k.length; + free(k.data); + return ret; +} + +size_t ASN1CALL +der_length_utctime (const time_t *t) +{ + heim_octet_string k; + size_t ret; + + _heim_time2generalizedtime (*t, &k, 0); + ret = k.length; + free(k.data); + return ret; +} + +size_t ASN1CALL +der_length_boolean (const int *k) +{ + return 1; +} + +size_t ASN1CALL +der_length_bit_string (const heim_bit_string *k) +{ + return (k->length + 7) / 8 + 1; +} diff --git a/third_party/heimdal/lib/asn1/der_locl.h b/third_party/heimdal/lib/asn1/der_locl.h new file mode 100644 index 0000000..a086e18 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_locl.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1997 - 2002, 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_LOCL_H__ +#define __DER_LOCL_H__ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "asn1-template.h" + +time_t _der_timegm (struct tm *); +struct tm * _der_gmtime(time_t t, struct tm *); +size_t _heim_len_unsigned (unsigned); +size_t _heim_len_int (int); + +#endif /* __DER_LOCL_H__ */ diff --git a/third_party/heimdal/lib/asn1/der_print.c b/third_party/heimdal/lib/asn1/der_print.c new file mode 100644 index 0000000..dada747 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_print.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include "hex.h" + +RCSID("$Id$"); + +char * ASN1CALL +der_print_general_string(const heim_general_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_boolean(const int *i, int flags) +{ + return *i ? strdup("true") : strdup("false"); +} + +char * ASN1CALL +der_print_integer(const int *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%d", *i) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_integer64(const int64_t *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%lld", (long long)*i) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_unsigned(const unsigned *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%u", *u) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_unsigned64(const uint64_t *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%llu", (long long)*u) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_generalized_time(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (gmtime_s(&tms, t) != 0 || + strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", &tms) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + +char * ASN1CALL +der_print_utctime(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (gmtime_s(&tms, t) != 0 || + strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", &tms) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + + +char * ASN1CALL +der_print_utf8string(const heim_utf8_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_printable_string(const heim_printable_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * ASN1CALL +der_print_ia5_string(const heim_ia5_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * ASN1CALL +der_print_bmp_string(const heim_bmp_string *k, int flags) +{ + return strdup(""); +} + +char * ASN1CALL +der_print_universal_string(const heim_universal_string *k, int flags) +{ + return strdup(""); +} + +char * ASN1CALL +der_print_visible_string(const heim_visible_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_octet_string(const heim_octet_string *k, int flags) +{ + char *s = NULL; + + (void) hex_encode(k->data, k->length, &s); + return s; +} + +char * ASN1CALL +der_print_heim_integer(const heim_integer *k, int flags) +{ + char *s = NULL; + + (void) der_print_hex_heim_integer(k, &s); + return s; +} + +char * ASN1CALL +der_print_oid(const heim_oid *k, int flags) +{ + struct rk_strpool *r = NULL; + const char *sym = NULL; + char *s = NULL; + size_t i; + + (void) der_print_heim_oid(k, '.', &s); + + if (!s) + return NULL; + r = rk_strpoolprintf(r, "{\"_type\":\"OBJECT IDENTIFIER\"," + "\"oid\":\"%s\"," + "\"components\":[", + s); + free(s); + for (i = 0; i < k->length; i++) + r = rk_strpoolprintf(r, "%s%u", i ? "," : "", k->components[i]); + if (r) + r = rk_strpoolprintf(r, "]"); + (void) der_find_heim_oid_by_oid(k, &sym); + if (sym && r) { + if ((s = strdup(sym))) { + for (i = 0; s[i]; i++) + if (s[i] == '_') + s[i] = '-'; + } + r = rk_strpoolprintf(r, ",\"name\":\"%s\"", s ? s : sym); + free(s); + } + if (r) + r = rk_strpoolprintf(r, "}"); + return rk_strpoolcollect(r); +} + +char * ASN1CALL +der_print_bit_string(const heim_bit_string *k, int flags) +{ + char *s2 = NULL; + char *s = NULL; + + (void) hex_encode(k->data, k->length / 8, &s); + if (asprintf(&s2, "%llu:%s", (unsigned long long)k->length, s) == -1 || !s2) + s2 = NULL; + free(s); + return s2; +} diff --git a/third_party/heimdal/lib/asn1/der_put.c b/third_party/heimdal/lib/asn1/der_put.c new file mode 100644 index 0000000..106d456 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_put.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +/* + * All encoding functions take a pointer `p' to first position in + * which to write, from the right, `len' which means the maximum + * number of characters we are able to write. The function returns + * the number of characters written in `size' (if non-NULL). + * The return value is 0 or an error. + */ + +int ASN1CALL +der_put_unsigned (unsigned char *p, size_t len, const unsigned *v, size_t *size) +{ + unsigned char *base = p; + unsigned val = *v; + + *size = 0; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + } + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int ASN1CALL +der_put_unsigned64 (unsigned char *p, size_t len, const uint64_t *v, size_t *size) +{ + unsigned char *base = p; + uint64_t val = *v; + + *size = 0; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + } + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int ASN1CALL +der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size) +{ + unsigned char *base = p; + int val = *v; + + *size = 0; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + +int ASN1CALL +der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size) +{ + unsigned char *base = p; + int64_t val = *v; + + *size = 0; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + + +int ASN1CALL +der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERFLOW; + + if (val < 128) { + *p = val; + if (size) + *size = 1; + } else { + size_t l = 0; + + while(val > 0) { + if(len < 2) + return ASN1_OVERFLOW; + *p-- = val % 256; + val /= 256; + len--; + l++; + } + *p = 0x80 | l; + if(size) + *size = l + 1; + } + return 0; +} + +int ASN1CALL +der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size) +{ + *size = 0; + + if(len < 1) + return ASN1_OVERFLOW; + if(*data != 0) + *p = 0xff; + else + *p = 0; + *size = 1; + return 0; +} + +int ASN1CALL +der_put_general_string (unsigned char *p, size_t len, + const heim_general_string *str, size_t *size) +{ + size_t slen; + + assert(p != NULL && str != NULL && *str != NULL && size != NULL); + *size = 0; + slen = strlen(*str); + if (len < slen) + return ASN1_OVERFLOW; + p -= slen; + memcpy (p+1, *str, slen); + *size = slen; + return 0; +} + +int ASN1CALL +der_put_utf8string (unsigned char *p, size_t len, + const heim_utf8_string *str, size_t *size) +{ + return der_put_general_string(p, len, str, size); +} + +int ASN1CALL +der_put_printable_string (unsigned char *p, size_t len, + const heim_printable_string *str, size_t *size) +{ + return der_put_octet_string(p, len, str, size); +} + +int ASN1CALL +der_put_ia5_string (unsigned char *p, size_t len, + const heim_ia5_string *str, size_t *size) +{ + return der_put_octet_string(p, len, str, size); +} + +int ASN1CALL +der_put_bmp_string (unsigned char *p, size_t len, + const heim_bmp_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL && data != NULL); + + if (size) + *size = 0; + + if (len / 2 < data->length) + return ASN1_OVERFLOW; + p -= data->length * 2; + for (i = 0; i < data->length; i++) { + p[1] = (data->data[i] >> 8) & 0xff; + p[2] = data->data[i] & 0xff; + p += 2; + } + if (size) *size = data->length * 2; + return 0; +} + +int ASN1CALL +der_put_universal_string (unsigned char *p, size_t len, + const heim_universal_string *data, size_t *size) +{ + size_t i; + + if (size) + *size = 0; + + if (len / 4 < data->length) + return ASN1_OVERFLOW; + p -= data->length * 4; + for (i = 0; i < data->length; i++) { + p[1] = (data->data[i] >> 24) & 0xff; + p[2] = (data->data[i] >> 16) & 0xff; + p[3] = (data->data[i] >> 8) & 0xff; + p[4] = data->data[i] & 0xff; + p += 4; + } + if (size) *size = data->length * 4; + return 0; +} + +int ASN1CALL +der_put_visible_string (unsigned char *p, size_t len, + const heim_visible_string *str, size_t *size) +{ + return der_put_general_string(p, len, str, size); +} + +int ASN1CALL +der_put_octet_string (unsigned char *p, size_t len, + const heim_octet_string *data, size_t *size) +{ + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; + if (len < data->length) + return ASN1_OVERFLOW; + p -= data->length; + if (data->length) + memcpy(p+1, data->data, data->length); + *size = data->length; + return 0; +} + +int ASN1CALL +der_put_heim_integer (unsigned char *p, size_t len, + const heim_integer *data, size_t *size) +{ + unsigned char *buf; + int hibitset = 0; + + assert(p != NULL); + + if (size) + *size = 0; + + if (data->length == 0) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + if (size) + *size = 1; + return 0; + } + if (len < data->length) + return ASN1_OVERFLOW; + + assert(data->data != NULL); + buf = data->data; + len -= data->length; + + if (data->negative) { + ssize_t i; + int carry; + + /* + * We represent the parsed integer as a positive value with a + * negativity flag. But we need to put it on the wire as the shortest + * twos-complement byte sequence possible. So we're going to negate + * the number as go. + */ + if (data->length == 1 && *(unsigned char *)data->data == 1) { + *(p--) = 0xff; + } else { + for (i = data->length - 1, carry = 1; i >= 0; i--) { + *p = buf[i] ^ 0xff; + if (carry) + carry = !++*p; + p--; + } + if (p[1] < 128) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + hibitset = 1; + } + } + } else { + p -= data->length; + memcpy(p + 1, buf, data->length); + + if (p[1] >= 128) { + if (len < 1) + return ASN1_OVERFLOW; + p[0] = 0; + len--; + hibitset = 1; + } + } + if (size) + *size = data->length + hibitset; + return 0; +} + +int ASN1CALL +der_put_generalized_time (unsigned char *p, size_t len, + const time_t *data, size_t *size) +{ + heim_octet_string k; + size_t l; + int e; + + e = _heim_time2generalizedtime (*data, &k, 1); + if (e) + return e; + e = der_put_octet_string(p, len, &k, &l); + free(k.data); + if(e) + return e; + if(size) + *size = l; + return 0; +} + +int ASN1CALL +der_put_utctime (unsigned char *p, size_t len, + const time_t *data, size_t *size) +{ + heim_octet_string k; + size_t l; + int e; + + e = _heim_time2generalizedtime (*data, &k, 0); + if (e) + return e; + e = der_put_octet_string(p, len, &k, &l); + free(k.data); + if(e) + return e; + if(size) + *size = l; + return 0; +} + +int ASN1CALL +der_put_oid (unsigned char *p, size_t len, + const heim_oid *data, size_t *size) +{ + unsigned char *base = p; + size_t n; + + for (n = data->length - 1; n >= 2; --n) { + unsigned u = data->components[n]; + + if (len < 1) + return ASN1_OVERFLOW; + *p-- = u % 128; + u /= 128; + --len; + while (u > 0) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 128 + u % 128; + u /= 128; + --len; + } + } + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 40 * data->components[0] + data->components[1]; + *size = base - p; + return 0; +} + +/* + * Output a copy of the DER TLV at `p' with a different outermost tag. + * + * This is used in the implementation of IMPLICIT tags in generated decoder + * functions. + */ +int ASN1CALL +der_replace_tag(const unsigned char *p, size_t len, + unsigned char **out, size_t *outlen, + Der_class class, Der_type type, + unsigned int tag) +{ + Der_class found_class; + Der_type found_type; + unsigned int found_tag; + size_t payload_len, l, tag_len, len_len; + int e; + + assert(p != NULL && out != NULL && outlen != NULL); + + e = der_get_tag(p, len, &found_class, &found_type, &found_tag, &l); + if (e) + return e; + if (found_type != type) + return ASN1_TYPE_MISMATCH; + /* We don't care what found_class and found_tag are though */ + tag_len = der_length_tag(tag); + p += l; + len -= l; + e = der_get_length(p, len, &payload_len, &len_len); + if (e) + return e; + if (payload_len > len) + return ASN1_OVERFLOW; + /* + * `p' now points at the payload; `*out' + the length of the tag points at + * where we should copy the DER length and the payload. + */ + if ((*out = malloc(*outlen = tag_len + len_len + payload_len)) == NULL) + return ENOMEM; + memcpy(*out + tag_len, p, len_len + payload_len); + + /* Put the new tag */ + e = der_put_tag(*out + tag_len - 1, tag_len, class, type, tag, &l); + if (e) + return e; + if (l != tag_len) + return ASN1_OVERFLOW; + return 0; +} + +#if 0 +int ASN1CALL +der_encode_implicit(unsigned char *p, size_t len, + asn1_generic_encoder_f encoder, + void *obj, size_t *size, + Der_type type, + unsigned int ttag, Der_class iclass, unsigned int itag) +{ + size_t ttaglen = der_length_tag(ttag); + size_t itaglen = der_length_tag(itag); + size_t l; + unsigned char *p2; + int e; + + assert(p != NULL && size != NULL); + + /* Attempt to encode in place */ + e = encoder(p, len, obj, size); + if (e == 0) { + /* Fits! Rewrite tag, adjust reported size. */ + e = der_put_tag(p + ttaglen - 1, itaglen, iclass, type, itag, &l); + if (e == 0) { + (*size) -= ttaglen; + (*size) += itaglen; + } + return e; + } + if (e != ASN1_OVERFLOW || itaglen <= ttaglen) + return e; + + /* + * Did not fit because ttaglen > itaglen and this was the last / only thing + * being encoded in a buffer of just the right size. + */ + if ((p2 = malloc(len + ttaglen - itaglen)) == NULL) + e = ENOMEM; + if (e == 0) + e = encoder(p2 + len + ttaglen - itaglen - 1, len + ttaglen - itaglen, + obj, size); + if (e == 0) + e = der_put_tag(p2 + ttaglen - 1, itaglen, iclass, type, itag, &l); + if (e == 0) { + (*size) -= ttaglen; + (*size) += itaglen; + memcpy(p - *size, p2 + ttaglen - itaglen, *size); + } + free(p2); + return e; +} +#endif + +int ASN1CALL +der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + if (tag <= 30) { + if (len < 1) + return ASN1_OVERFLOW; + *p = MAKE_TAG(class, type, tag); + *size = 1; + } else { + size_t ret = 0; + unsigned int continuation = 0; + + do { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = tag % 128 | continuation; + len--; + ret++; + tag /= 128; + continuation = 0x80; + } while(tag > 0); + if (len < 1) + return ASN1_OVERFLOW; + *p-- = MAKE_TAG(class, type, 0x1f); + ret++; + *size = ret; + } + return 0; +} + +int ASN1CALL +der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_length (p, len, len_val, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_tag (p, len, class, type, tag, &l); + if(e) + return e; + + ret += l; + *size = ret; + return 0; +} + +int +_heim_time2generalizedtime (time_t t, heim_octet_string *s, int gtimep) +{ + struct tm tm; + const size_t len = gtimep ? 15 : 13; + int bytes; + + s->data = NULL; + s->length = 0; + if (_der_gmtime(t, &tm) == NULL) + return ASN1_BAD_TIMEFORMAT; + s->data = malloc(len + 1); + if (s->data == NULL) + return ENOMEM; + s->length = len; + if (gtimep) + bytes = snprintf(s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + else + bytes = snprintf(s->data, len + 1, "%02d%02d%02d%02d%02d%02dZ", + tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + if (bytes > len) + abort(); + + return 0; +} + +int ASN1CALL +der_put_bit_string (unsigned char *p, size_t len, + const heim_bit_string *data, size_t *size) +{ + size_t data_size; + + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; + data_size = (data->length + 7) / 8; + if (len < data_size + 1) + return ASN1_OVERFLOW; + p -= data_size + 1; + + memcpy (p+2, data->data, data_size); + if (data->length && (data->length % 8) != 0) + p[1] = 8 - (data->length % 8); + else + p[1] = 0; + *size = data_size + 1; + return 0; +} + +int +_heim_der_set_sort(const void *a1, const void *a2) +{ + const heim_octet_string *s1, *s2; + int ret; + + assert(a1 != NULL && a2 != NULL); + s1 = a1; + s2 = a2; + ret = memcmp(s1->data, s2->data, + s1->length < s2->length ? s1->length : s2->length); + if (ret != 0) + return ret; + return (int)(s1->length - s2->length); +} diff --git a/third_party/heimdal/lib/asn1/digest.asn1 b/third_party/heimdal/lib/asn1/digest.asn1 new file mode 100644 index 0000000..7a73993 --- /dev/null +++ b/third_party/heimdal/lib/asn1/digest.asn1 @@ -0,0 +1,179 @@ +-- $Id$ + +DIGEST DEFINITIONS ::= +BEGIN + +IMPORTS EncryptedData, Principal FROM krb5; + +DigestTypes ::= BIT STRING { + ntlm-v1(0), + ntlm-v1-session(1), + ntlm-v2(2), + digest-md5(3), + chap-md5(4), + ms-chap-v2(5) +} + +DigestInit ::= SEQUENCE { + type UTF8String, -- http, sasl, chap, cram-md5 -- + channel [0] SEQUENCE { + cb-type UTF8String, + cb-binding UTF8String + } OPTIONAL, + hostname [1] UTF8String OPTIONAL -- for chap/cram-md5 +} + +DigestInitReply ::= SEQUENCE { + nonce UTF8String, -- service nonce/challenge + opaque UTF8String, -- server state + identifier [0] UTF8String OPTIONAL +} + + +DigestRequest ::= SEQUENCE { + type UTF8String, -- http, sasl-md5, chap, cram-md5 -- + digest UTF8String, -- http:md5/md5-sess sasl:clear/int/conf -- + username UTF8String, -- username user used + responseData UTF8String, -- client response + authid [0] UTF8String OPTIONAL, + authentication-user [1] Principal OPTIONAL, -- principal to get key from + realm [2] UTF8String OPTIONAL, + method [3] UTF8String OPTIONAL, + uri [4] UTF8String OPTIONAL, + serverNonce UTF8String, -- same as "DigestInitReply.nonce" + clientNonce [5] UTF8String OPTIONAL, + nonceCount [6] UTF8String OPTIONAL, + qop [7] UTF8String OPTIONAL, + identifier [8] UTF8String OPTIONAL, + hostname [9] UTF8String OPTIONAL, + opaque UTF8String -- same as "DigestInitReply.opaque" +} +-- opaque = hex(cksum(type|serverNonce|identifier|hostname,digest-key)) +-- serverNonce = hex(time[4bytes]random[12bytes])(-cbType:cbBinding) + + +DigestError ::= SEQUENCE { + reason UTF8String, + code INTEGER (-2147483648..2147483647) +} + +DigestResponse ::= SEQUENCE { + success BOOLEAN, + rsp [0] UTF8String OPTIONAL, + tickets [1] SEQUENCE OF OCTET STRING OPTIONAL, + channel [2] SEQUENCE { + cb-type UTF8String, + cb-binding UTF8String + } OPTIONAL, + session-key [3] OCTET STRING OPTIONAL +} + +NTLMInit ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + hostname [1] UTF8String OPTIONAL, + domain [1] UTF8String OPTIONAL +} + +NTLMInitReply ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + targetname [2] UTF8String, + challenge [3] OCTET STRING, + targetinfo [4] OCTET STRING OPTIONAL +} + +NTLMRequest ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + username [2] UTF8String, + targetname [3] UTF8String, + targetinfo [4] OCTET STRING OPTIONAL, + lm [5] OCTET STRING, + ntlm [6] OCTET STRING, + sessionkey [7] OCTET STRING OPTIONAL +} + +NTLMResponse ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL, + tickets [3] SEQUENCE OF OCTET STRING OPTIONAL +} + +NTLMRequest2 ::= SEQUENCE { + loginUserName [0] UTF8String, + loginDomainName [1] UTF8String, + flags [2] INTEGER (0..4294967295), + lmchallenge [3] OCTET STRING SIZE (8), + ntChallengeResponce [4] OCTET STRING, + lmChallengeResponce [5] OCTET STRING +} + +NTLMReply ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL +} + +DigestReqInner ::= CHOICE { + init [0] DigestInit, + digestRequest [1] DigestRequest, + ntlmInit [2] NTLMInit, + ntlmRequest [3] NTLMRequest, + supportedMechs [4] NULL +} + +DigestREQ ::= [APPLICATION 128] SEQUENCE { + apReq [0] OCTET STRING, + innerReq [1] EncryptedData +} + +DigestRepInner ::= CHOICE { + error [0] DigestError, + initReply [1] DigestInitReply, + response [2] DigestResponse, + ntlmInitReply [3] NTLMInitReply, + ntlmResponse [4] NTLMResponse, + supportedMechs [5] DigestTypes, + ... +} + +DigestREP ::= [APPLICATION 129] SEQUENCE { + apRep [0] OCTET STRING, + innerRep [1] EncryptedData +} + + +-- HTTP + +-- md5 +-- A1 = unq(username-value) ":" unq(realm-value) ":" passwd +-- md5-sess +-- A1 = HEX(H(unq(username-value) ":" unq(realm-value) ":" passwd ) ":" unq(nonce-value) ":" unq(cnonce-value)) + +-- qop == auth +-- A2 = Method ":" digest-uri-value +-- qop == auth-int +-- A2 = Method ":" digest-uri-value ":" H(entity-body) + +-- request-digest = HEX(KD(HEX(H(A1)), +-- unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" HEX(H(A2)))) +-- no "qop" +-- request-digest = HEX(KD(HEX(H(A1)), unq(nonce-value) ":" HEX(H(A2)))) + + +-- SASL: +-- SS = H( { unq(username-value), ":", unq(realm-value), ":", password } ) +-- A1 = { SS, ":", unq(nonce-value), ":", unq(cnonce-value) } +-- A1 = { SS, ":", unq(nonce-value), ":", unq(cnonce-value), ":", unq(authzid-value) } + +-- A2 = "AUTHENTICATE:", ":", digest-uri-value +-- qop == auth-int,auth-conf +-- A2 = "AUTHENTICATE:", ":", digest-uri-value, ":00000000000000000000000000000000" + +-- response-value = HEX( KD ( HEX(H(A1)), +-- { unq(nonce-value), ":" nc-value, ":", +-- unq(cnonce-value), ":", qop-value, ":", +-- HEX(H(A2)) })) + +END diff --git a/third_party/heimdal/lib/asn1/extra.c b/third_party/heimdal/lib/asn1/extra.c new file mode 100644 index 0000000..253ac5a --- /dev/null +++ b/third_party/heimdal/lib/asn1/extra.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include "heim_asn1.h" +#include +#include + +RCSID("$Id$"); + +int ASN1CALL +encode_heim_any(unsigned char *p, size_t len, + const heim_any *data, size_t *size) +{ + return der_put_octet_string (p, len, data, size); +} + +int ASN1CALL +decode_heim_any(const unsigned char *p, size_t len, + heim_any *data, size_t *size) +{ + size_t len_len, length, l; + Der_class thisclass; + Der_type thistype; + unsigned int thistag; + int e; + + memset(data, 0, sizeof(*data)); + + e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l); + if (e) return e; + if (l > len) + return ASN1_OVERFLOW; + e = der_get_length(p + l, len - l, &length, &len_len); + if (e) return e; + if (length == ASN1_INDEFINITE) { + if (len < len_len + l) + return ASN1_OVERFLOW; + length = len - (len_len + l); + } else { + if (len < length + len_len + l) + return ASN1_OVERFLOW; + } + + data->data = malloc(length + len_len + l); + if (data->data == NULL) + return ENOMEM; + data->length = length + len_len + l; + memcpy(data->data, p, length + len_len + l); + + if (size) + *size = length + len_len + l; + + return 0; +} + +void ASN1CALL +free_heim_any(heim_any *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_heim_any(const heim_any *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_heim_any(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_heim_any(const heim_any *from, heim_any *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +encode_HEIM_ANY(unsigned char *p, size_t len, + const heim_any *data, size_t *size) +{ + return encode_heim_any(p, len, data, size); +} + +int ASN1CALL +decode_HEIM_ANY(const unsigned char *p, size_t len, + heim_any *data, size_t *size) +{ + return decode_heim_any(p, len, data, size); +} + +void ASN1CALL +free_HEIM_ANY(heim_any *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_HEIM_ANY(const heim_any *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_HEIM_ANY(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_HEIM_ANY(const heim_any *from, heim_any *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +encode_heim_any_set(unsigned char *p, size_t len, + const heim_any_set *data, size_t *size) +{ + return der_put_octet_string (p, len, data, size); +} + +int ASN1CALL +decode_heim_any_set(const unsigned char *p, size_t len, + heim_any_set *data, size_t *size) +{ + return der_get_octet_string(p, len, data, size); +} + +void ASN1CALL +free_heim_any_set(heim_any_set *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_heim_any_set(const heim_any_set *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_heim_any_set(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_heim_any_set(const heim_any_set *from, heim_any_set *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +heim_any_cmp(const heim_any_set *p, const heim_any_set *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +encode_HEIM_ANY_SET(unsigned char *p, size_t len, + const heim_any_set *data, size_t *size) +{ + return encode_heim_any_set(p, len, data, size); +} + +int ASN1CALL +decode_HEIM_ANY_SET(const unsigned char *p, size_t len, + heim_any_set *data, size_t *size) +{ + return decode_heim_any_set(p, len, data, size); +} + +void ASN1CALL +free_HEIM_ANY_SET(heim_any_set *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_HEIM_ANY_SET(const heim_any_set *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_HEIM_ANY_SET(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_HEIM_ANY_SET(const heim_any_set *from, heim_any_set *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +HEIM_ANY_cmp(const heim_any_set *p, const heim_any_set *q) +{ + return der_heim_octet_string_cmp(p, q); +} diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq b/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq new file mode 100644 index 0000000..21ac360 Binary files /dev/null and b/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq differ diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt b/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt new file mode 100644 index 0000000..7e9bc70 Binary files /dev/null and b/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt differ diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der b/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der new file mode 100644 index 0000000..ec1c2c2 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der @@ -0,0 +1,5 @@ +`aJohnPSmith +DirectorB3 +C19710917aMaryTSmithB1aRalphTSmith +C195711111aSusanBSmith +C19590717 \ No newline at end of file diff --git a/third_party/heimdal/lib/asn1/fuzzer.c b/third_party/heimdal/lib/asn1/fuzzer.c new file mode 100644 index 0000000..527f7e9 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzzer.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include + +enum trigger_method { FOFF, FRANDOM, FLINEAR, FLINEAR_SIZE }; + +#ifdef ASN1_FUZZER +static enum trigger_method method = FOFF; + +/* FLINEAR */ +static unsigned long fnum, fcur, fsize; +#endif + +int +asn1_fuzzer_method(const char *mode) +{ +#ifdef ASN1_FUZZER + if (mode == NULL || strcasecmp(mode, "off") == 0) { + method = FOFF; + } else if (strcasecmp(mode, "random") == 0) { + method = FRANDOM; + } else if (strcasecmp(mode, "linear") == 0) { + method = FLINEAR; + } else if (strcasecmp(mode, "linear-size") == 0) { + method = FLINEAR_SIZE; + } else + return 1; + return 0; +#else + return 1; +#endif +} + +void +asn1_fuzzer_reset(void) +{ +#ifdef ASN1_FUZZER + fcur = 0; + fsize = 0; + fnum = 0; +#endif +} + +void +asn1_fuzzer_next(void) +{ +#ifdef ASN1_FUZZER + fcur = 0; + fsize = 0; + fnum++; +#endif +} + +int +asn1_fuzzer_done(void) +{ +#ifndef ASN1_FUZZER + abort(); +#else + /* since code paths */ + return (fnum > 10000); +#endif +} + +#ifdef ASN1_FUZZER + +static int +fuzzer_trigger(unsigned int chance) +{ + switch(method) { + case FOFF: + return 0; + case FRANDOM: + if ((rk_random() % chance) != 1) + return 0; + return 1; + case FLINEAR: + if (fnum == fcur++) + return 1; + return 0; + case FLINEAR_SIZE: + return 0; + } + return 0; +} + +static int +fuzzer_size_trigger(unsigned long *cur) +{ + if (method != FLINEAR_SIZE) + return 0; + if (fnum == (*cur)++) + return 1; + return 0; +} + +static size_t +fuzzer_length_len (size_t len) +{ + if (fuzzer_size_trigger(&fsize)) { + len = 0; + } else if (fuzzer_size_trigger(&fsize)) { + len = 129; + } else if (fuzzer_size_trigger(&fsize)) { + len = 0xffff; + } + + if (len < 128) + return 1; + else { + int ret = 0; + do { + ++ret; + len /= 256; + } while (len); + return ret + 1; + } +} + +static int +fuzzer_put_length (unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (len < 1) + return ASN1_OVERFLOW; + + if (fuzzer_size_trigger(&fcur)) { + val = 0; + } else if (fuzzer_size_trigger(&fcur)) { + val = 129; + } else if (fuzzer_size_trigger(&fcur)) { + val = 0xffff; + } + + if (val < 128) { + *p = val; + *size = 1; + } else { + size_t l = 0; + + while(val > 0) { + if(len < 2) + return ASN1_OVERFLOW; + *p-- = val % 256; + val /= 256; + len--; + l++; + } + *p = 0x80 | l; + if(size) + *size = l + 1; + } + return 0; +} + +static int +fuzzer_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + unsigned fcont = 0; + + if (tag <= 30) { + if (len < 1) + return ASN1_OVERFLOW; + if (fuzzer_trigger(100)) + *p = MAKE_TAG(class, type, 0x1f); + else + *p = MAKE_TAG(class, type, tag); + *size = 1; + } else { + size_t ret = 0; + unsigned int continuation = 0; + + do { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = tag % 128 | continuation; + len--; + ret++; + tag /= 128; + continuation = 0x80; + } while(tag > 0); + if (len < 1) + return ASN1_OVERFLOW; + if (fuzzer_trigger(100)) + *p-- = MAKE_TAG(class, type, 0); + else + *p-- = MAKE_TAG(class, type, 0x1f); + ret++; + *size = ret; + } + return 0; +} + +static int +fuzzer_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = fuzzer_put_length (p, len, len_val, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = fuzzer_put_tag (p, len, class, type, tag, &l); + if(e) + return e; + + ret += l; + *size = ret; + return 0; +} + +static int +fuzzer_put_general_string (unsigned char *p, size_t len, + const heim_general_string *str, size_t *size) +{ + size_t slen = strlen(*str); + + if (len < slen) + return ASN1_OVERFLOW; + p -= slen; + if (slen >= 2 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%s", 2); + } else if (slen >= 2 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n", 2); + } else if (slen >= 4 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%10n", 4); + } else if (slen >= 10 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n%n%n%n%n", 10); + } else if (slen >= 10 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n%p%s%d%x", 10); + } else if (slen >= 7 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%.1024d", 7); + } else if (slen >= 7 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%.2049d", 7); + } else if (fuzzer_trigger(100)) { + memset(p+1, 0, slen); + } else if (fuzzer_trigger(100)) { + memset(p+1, 0xff, slen); + } else if (fuzzer_trigger(100)) { + memset(p+1, 'A', slen); + } else { + memcpy(p+1, *str, slen); + } + *size = slen; + return 0; +} + + +struct asn1_type_func fuzzerprim[A1T_NUM_ENTRY] = { +#define fuzel(name, type) { \ + (asn1_type_encode)fuzzer_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } +#define el(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } +#define elber(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name##_ber, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } + el(integer, int), + el(integer64, int64_t), + el(heim_integer, heim_integer), + el(integer, int), + el(unsigned, unsigned), + el(uninteger64, uint64_t), + fuzel(general_string, heim_general_string), + el(octet_string, heim_octet_string), + elber(octet_string, heim_octet_string), + el(ia5_string, heim_ia5_string), + el(bmp_string, heim_bmp_string), + el(universal_string, heim_universal_string), + el(printable_string, heim_printable_string), + el(visible_string, heim_visible_string), + el(utf8string, heim_utf8_string), + el(generalized_time, time_t), + el(utctime, time_t), + el(bit_string, heim_bit_string), + { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, + (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, + (asn1_type_release)der_free_integer, sizeof(int) + }, + el(oid, heim_oid), + el(general_string, heim_general_string), +#undef fuzel +#undef el +#undef elber +}; + + + +int +_asn1_encode_fuzzer(const struct asn1_template *t, + unsigned char *p, size_t len, + const void *data, size_t *size) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + size_t oldlen = len; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_encode_fuzzer(t->ptr, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->encode)(p, len, el, &newsize); + } + + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + const void *olddata = data; + size_t l, datalen; + + data = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + + ret = _asn1_encode_fuzzer(t->ptr, p, len, data, &datalen); + if (ret) + return ret; + + len -= datalen; p -= datalen; + + ret = fuzzer_put_length_and_tag(p, len, datalen, + A1_TAG_CLASS(t->tt), + A1_TAG_TYPE(t->tt), + A1_TAG_TAG(t->tt), &l); + if (ret) + return ret; + + p -= l; len -= l; + + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (type > sizeof(fuzzerprim)/sizeof(fuzzerprim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (fuzzerprim[type].encode)(p, len, el, &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + heim_octet_string *val; + unsigned char *elptr = el->val; + size_t i, totallen; + + if (el->len == 0) + break; + + if (el->len > UINT_MAX/sizeof(val[0])) + return ERANGE; + + val = malloc(sizeof(val[0]) * el->len); + if (val == NULL) + return ENOMEM; + + for(totallen = 0, i = 0; i < el->len; i++) { + unsigned char *next; + size_t l; + + val[i].length = _asn1_length(t->ptr, elptr); + val[i].data = malloc(val[i].length); + + ret = _asn1_encode_fuzzer(t->ptr, DPO(val[i].data, val[i].length - 1), + val[i].length, elptr, &l); + if (ret) + break; + + next = elptr + ellen; + if (next < elptr) { + ret = ASN1_OVERFLOW; + break; + } + elptr = next; + totallen += val[i].length; + } + if (ret == 0 && totallen > len) + ret = ASN1_OVERFLOW; + if (ret) { + do { + free(val[i].data); + } while(i-- > 0); + free(val); + return ret; + } + + len -= totallen; + + qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); + + i = el->len - 1; + do { + p -= val[i].length; + memcpy(p + 1, val[i].data, val[i].length); + free(val[i].data); + } while(i-- > 0); + free(val); + + break; + + } + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + size_t newsize; + unsigned int i; + unsigned char *elptr = el->val; + + if (el->len == 0) + break; + + elptr += ellen * (el->len - 1); + + for (i = 0; i < el->len; i++) { + ret = _asn1_encode_fuzzer(t->ptr, p, len, + elptr, + &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + elptr -= ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + size_t pos; + unsigned char c = 0; + unsigned int bitset = 0; + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + bmember += elements; + + if (rfc1510) + pos = 31; + else + pos = bmember->offset; + + while (elements && len) { + while (bmember->offset / 8 < pos / 8) { + if (rfc1510 || bitset || c) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + c = 0; + pos -= 8; + } + _asn1_bmember_put_bit(&c, data, bmember->offset, size, &bitset); + elements--; bmember--; + } + if (rfc1510 || bitset) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + + if (len < 1) + return ASN1_OVERFLOW; + if (rfc1510 || bitset == 0) + *p-- = 0; + else + *p-- = bitset - 1; + + len--; + + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + size_t datalen; + const void *el; + + if (*element > A1_HEADER_LEN(choice)) { + printf("element: %d\n", *element); + return ASN1_PARSE_ERROR; + } + + if (*element == 0) { + ret += der_put_octet_string(p, len, + DPOC(data, choice->tt), &datalen); + } else { + choice += *element; + el = DPOC(data, choice->offset); + ret = _asn1_encode_fuzzer(choice->ptr, p, len, el, &datalen); + if (ret) + return ret; + } + len -= datalen; p -= datalen; + + break; + } + default: + ABORT_ON_ERROR(); + } + t--; + elements--; + } + + if (fuzzer_trigger(1000)) { + memset(p + 1, 0, oldlen - len); + } else if (fuzzer_trigger(1000)) { + memset(p + 1, 0x41, oldlen - len); + } else if (fuzzer_trigger(1000)) { + memset(p + 1, 0xff, oldlen - len); + } + + if (size) + *size = oldlen - len; + + return 0; +} + +size_t +_asn1_length_fuzzer(const struct asn1_template *t, const void *data) +{ + size_t elements = A1_HEADER_LEN(t); + size_t ret = 0; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret += _asn1_length(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + ret += (f->length)(el); + } + break; + } + case A1_OP_TAG: { + size_t datalen; + const void *olddata = data; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + datalen = _asn1_length(t->ptr, data); + ret += der_length_tag(A1_TAG_TAG(t->tt)) + fuzzer_length_len(datalen); + ret += datalen; + data = olddata; + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + ret += (asn1_template_prim[type].length)(el); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + ret += _asn1_length(t->ptr, element); + element += ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + if (rfc1510) { + ret += 5; + } else { + + ret += 1; + + bmember += elements; + + while (elements) { + if (_asn1_bmember_isset_bit(data, bmember->offset, size)) { + ret += (bmember->offset / 8) + 1; + break; + } + elements--; bmember--; + } + } + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + ret += der_length_octet_string(DPOC(data, choice->tt)); + } else { + choice += *element; + ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + elements--; + t--; + } + return ret; +} + +#endif /* ASN1_FUZZER */ diff --git a/third_party/heimdal/lib/asn1/gen.c b/third_party/heimdal/lib/asn1/gen.c new file mode 100644 index 0000000..55ec5f6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen.c @@ -0,0 +1,2090 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +extern const char *enum_prefix; +extern int prefix_enum; + +RCSID("$Id$"); + +FILE *jsonfile, *privheaderfile, *headerfile, *oidsfile, *codefile, *logfile, *templatefile; +FILE *symsfile; + +#define STEM "asn1" + +static const char *orig_filename; +static char *privheader, *header, *template; +static const char *headerbase = STEM; + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +/* + * list of all IMPORTs + */ + +struct import { + const char *module; + struct import *next; +}; + +static struct import *imports = NULL; + +void +add_import (const char *module) +{ + struct import *tmp = emalloc (sizeof(*tmp)); + + tmp->module = module; + tmp->next = imports; + imports = tmp; + + fprintf (headerfile, "#include <%s_asn1.h>\n", module); + fprintf(jsonfile, "{\"imports\":\"%s\"}\n", module); +} + +/* + * List of all exported symbols + * + * XXX A hash table would be nice here. + */ + +struct sexport { + const char *name; + int defined; + struct sexport *next; +}; + +static struct sexport *exports = NULL; + +void +add_export (const char *name) +{ + struct sexport *tmp = emalloc (sizeof(*tmp)); + + tmp->name = name; + tmp->next = exports; + exports = tmp; +} + +int +is_export(const char *name) +{ + struct sexport *tmp; + + if (exports == NULL) /* no export list, all exported */ + return 1; + + for (tmp = exports; tmp != NULL; tmp = tmp->next) { + if (strcmp(tmp->name, name) == 0) { + tmp->defined = 1; + return 1; + } + } + return 0; +} + +const char * +get_filename (void) +{ + return orig_filename; +} + +void +init_generate (const char *filename, const char *base) +{ + char *fn = NULL; + + orig_filename = filename; + if (base != NULL) { + headerbase = strdup(base); + if (headerbase == NULL) + errx(1, "strdup"); + } + + /* JSON file */ + if (asprintf(&fn, "%s.json", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + jsonfile = fopen(fn, "w"); + if (jsonfile == NULL) + err(1, "open %s", fn); + free(fn); + fn = NULL; + + /* public header file */ + if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL) + errx(1, "malloc"); + if (asprintf(&fn, "%s.h", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + headerfile = fopen (fn, "w"); + if (headerfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* private header file */ + if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL) + errx(1, "malloc"); + if (asprintf(&fn, "%s-priv.h", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + privheaderfile = fopen (fn, "w"); + if (privheaderfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* template file */ + if (asprintf(&template, "%s-template.c", headerbase) < 0 || template == NULL) + errx(1, "malloc"); + fprintf (headerfile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n", + filename); + fprintf (headerfile, + "#ifndef __%s_h__\n" + "#define __%s_h__\n\n", headerbase, headerbase); + fprintf (headerfile, + "#include \n" + "#include \n" + "#include \n\n"); + fprintf (headerfile, + "#ifndef __asn1_common_definitions__\n" + "#define __asn1_common_definitions__\n\n"); + fprintf (headerfile, + "#ifndef __HEIM_BASE_DATA__\n" + "#define __HEIM_BASE_DATA__ 1\n" + "struct heim_base_data {\n" + " size_t length;\n" + " void *data;\n" + "};\n" + "typedef struct heim_base_data heim_octet_string;\n" + "#endif\n\n"); + fprintf (headerfile, + "typedef struct heim_integer {\n" + " size_t length;\n" + " void *data;\n" + " int negative;\n" + "} heim_integer;\n\n"); + fprintf (headerfile, + "typedef char *heim_general_string;\n\n" + ); + fprintf (headerfile, + "typedef char *heim_utf8_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_base_data heim_printable_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_base_data heim_ia5_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_bmp_string {\n" + " size_t length;\n" + " uint16_t *data;\n" + "} heim_bmp_string;\n\n"); + fprintf (headerfile, + "typedef struct heim_universal_string {\n" + " size_t length;\n" + " uint32_t *data;\n" + "} heim_universal_string;\n\n"); + fprintf (headerfile, + "typedef char *heim_visible_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_oid {\n" + " size_t length;\n" + " unsigned *components;\n" + "} heim_oid;\n\n"); + fprintf (headerfile, + "typedef struct heim_bit_string {\n" + " size_t length;\n" + " void *data;\n" + "} heim_bit_string;\n\n"); + fprintf (headerfile, + "typedef struct heim_base_data heim_any;\n" + "typedef struct heim_base_data heim_any_set;\n" + "typedef struct heim_base_data HEIM_ANY;\n" + "typedef struct heim_base_data HEIM_ANY_SET;\n\n"); + + fprintf (headerfile, + "enum asn1_print_flags {\n" + " ASN1_PRINT_INDENT = 1,\n" + "};\n\n"); + fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n" + " do { \\\n" + " (BL) = length_##T((S)); \\\n" + " (B) = calloc(1, (BL)); \\\n" + " if((B) == NULL) { \\\n" + " *(L) = 0; \\\n" + " (R) = ENOMEM; \\\n" + " } else { \\\n" + " (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n" + " (S), (L)); \\\n" + " if((R) != 0) { \\\n" + " free((B)); \\\n" + " (B) = NULL; \\\n" + " *(L) = 0; \\\n" + " } \\\n" + " } \\\n" + " } while (0)\n\n", + headerfile); + fputs("#ifdef _WIN32\n" + "#ifndef ASN1_LIB\n" + "#define ASN1EXP __declspec(dllimport)\n" + "#else\n" + "#define ASN1EXP\n" + "#endif\n" + "#define ASN1CALL __stdcall\n" + "#else\n" + "#define ASN1EXP\n" + "#define ASN1CALL\n" + "#endif\n", + headerfile); + fputs("#ifndef ENOTSUP\n" + "/* Very old MSVC CRTs lack ENOTSUP */\n" + "#define ENOTSUP EINVAL\n" + "#endif\n", + headerfile); + fprintf (headerfile, "struct units;\n\n"); + fprintf (headerfile, "#endif\n\n"); + if (asprintf(&fn, "%s_files", base) < 0 || fn == NULL) + errx(1, "malloc"); + logfile = fopen(fn, "w"); + if (logfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + if (asprintf(&fn, "%s_oids.c", base) < 0 || fn == NULL) + errx(1, "malloc"); + oidsfile = fopen(fn, "w"); + if (oidsfile == NULL) + err (1, "open %s", fn); + if (asprintf(&fn, "%s_syms.c", base) < 0 || fn == NULL) + errx(1, "malloc"); + symsfile = fopen(fn, "w"); + if (symsfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* if one code file, write into the one codefile */ + if (one_code_file) + return; + + templatefile = fopen (template, "w"); + if (templatefile == NULL) + err (1, "open %s", template); + + fprintf (templatefile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include <%s>\n", + filename, + type_file_string); + + fprintf (templatefile, + "#include <%s>\n" + "#include <%s>\n" + "#include \n" + "#include \n", + header, privheader); + + +} + +void +close_generate (void) +{ + fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase); + + if (headerfile && fclose(headerfile) == EOF) + err(1, "writes to public header file failed"); + if (privheaderfile && fclose(privheaderfile) == EOF) + err(1, "writes to private header file failed"); + if (templatefile && fclose(templatefile) == EOF) + err(1, "writes to template file failed"); + if (!jsonfile) abort(); + if (fclose(jsonfile) == EOF) + err(1, "writes to JSON file failed"); + if (!oidsfile) abort(); + if (fclose(oidsfile) == EOF) + err(1, "writes to OIDs file failed"); + if (!symsfile) abort(); + if (fclose(symsfile) == EOF) + err(1, "writes to symbols file failed"); + if (!logfile) abort(); + fprintf(logfile, "\n"); + if (fclose(logfile) == EOF) + err(1, "writes to log file failed"); +} + +void +gen_assign_defval(const char *var, struct value *val) +{ + switch(val->type) { + case stringvalue: + fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue); + break; + case integervalue: + fprintf(codefile, "%s = %lld;\n", + var, (long long)val->u.integervalue); + break; + case booleanvalue: + if(val->u.booleanvalue) + fprintf(codefile, "%s = 1;\n", var); + else + fprintf(codefile, "%s = 0;\n", var); + break; + default: + abort(); + } +} + +void +gen_compare_defval(const char *var, struct value *val) +{ + switch(val->type) { + case stringvalue: + fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue); + break; + case integervalue: + fprintf(codefile, "if(%s != %lld)\n", + var, (long long)val->u.integervalue); + break; + case booleanvalue: + if(val->u.booleanvalue) + fprintf(codefile, "if(!%s)\n", var); + else + fprintf(codefile, "if(%s)\n", var); + break; + default: + abort(); + } +} + +void +generate_header_of_codefile(const char *name) +{ + char *filename = NULL; + + if (codefile != NULL) + abort(); + + if (asprintf (&filename, "%s_%s.c", STEM, name) < 0 || filename == NULL) + errx(1, "malloc"); + codefile = fopen (filename, "w"); + if (codefile == NULL) + err (1, "fopen %s", filename); + if (logfile) + fprintf(logfile, "%s ", filename); + free(filename); + filename = NULL; + fprintf (codefile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n" + "#if defined(_WIN32) && !defined(ASN1_LIB)\n" + "# error \"ASN1_LIB must be defined\"\n" + "#endif\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include <%s>\n", + orig_filename, + type_file_string); + + fprintf (codefile, + "#include \"%s\"\n" + "#include \"%s\"\n", + header, privheader); + fprintf (codefile, + "#include \n" + "#include \n" + "#include \n\n"); + + if (parse_units_flag) + fprintf (codefile, + "#include \n\n"); + +#ifdef _WIN32 + fprintf(codefile, "#pragma warning(disable: 4101)\n\n"); +#endif +} + +void +close_codefile(void) +{ + if (codefile == NULL) + abort(); + + if (fclose(codefile) == EOF) + err(1, "writes to source code file failed"); + codefile = NULL; +} + +/* Object identifiers are parsed backwards; this reverses that */ +struct objid ** +objid2list(struct objid *o) +{ + struct objid *el, **list; + size_t i, len; + + for (el = o, len = 0; el; el = el->next) + len++; + if (len == 0) + return NULL; + list = ecalloc(len + 1, sizeof(*list)); + + for (i = 0; o; o = o->next) + list[i++] = o; + list[i] = NULL; + + /* Reverse the list */ + for (i = 0; i < (len>>1); i++) { + el = list[i]; + list[i] = list[len - (i + 1)]; + list[len - (i + 1)] = el; + } + return list; +} + +void +generate_constant (const Symbol *s) +{ + switch(s->value->type) { + case booleanvalue: + break; + case integervalue: + /* + * Work around the fact that OpenSSL defines macros for PKIX constants + * that we want to generate as enums, which causes conflicts for things + * like ub-name (ub_name). + */ + fprintf(headerfile, + "#ifdef %s\n" + "#undef %s\n" + "#endif\n" + "enum { %s = %lld };\n\n", + s->gen_name, s->gen_name, s->gen_name, + (long long)s->value->u.integervalue); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_INTVAL(\"%s\", \"%s\", %s, %lld)\n", + s->name, s->gen_name, s->gen_name, + (long long)s->value->u.integervalue); + fprintf(jsonfile, + "{\"name\":\"%s\",\"gen_name\":\"%s\",\"type\":\"INTEGER\"," + "\"constant\":true,\"exported\":%s,\"value\":%lld}\n", + s->name, s->gen_name, is_export(s->name) ? "true" : "false", + (long long)s->value->u.integervalue); + break; + case nullvalue: + break; + case stringvalue: + break; + case objectidentifiervalue: { + struct objid *o, **list; + size_t i, len; + char *gen_upper; + + if (!one_code_file) + generate_header_of_codefile(s->gen_name); + + list = objid2list(s->value->u.objectidentifiervalue); + for (len = 0; list && list[len]; len++) + ; + if (len == 0) { + errx(1, "Empty OBJECT IDENTIFIER named %s\n", s->name); + break; + } + + fprintf(jsonfile, + "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"type\":\"OBJECT IDENTIFIER\"," + "\"constant\":true,\"exported\":%s,\"value\":[\n", + s->name, s->gen_name, is_export(s->name) ? "true" : "false"); + fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name); + for (i = 0; i < len; i++) { + o = list[i]; + fprintf(headerfile, "%s(%d) ", + o->label ? o->label : "label-less", o->value); + if (o->label == NULL) + fprintf(jsonfile, "%s{\"label\":null,\"value\":%d}", + i ? "," : "", o->value); + else + fprintf(jsonfile, "%s{\"label\":\"%s\",\"value\":%d}", + i ? "," : "", o->label, o->value); + } + fprintf(jsonfile, "]}\n"); + + fprintf (codefile, "static unsigned oid_%s_variable_num[%lu] = {", + s->gen_name, (unsigned long)len); + for (i = 0; list[i]; i++) { + fprintf(codefile, "%s %d", i ? "," : "", list[i]->value); + } + fprintf(codefile, "};\n"); + + fprintf (codefile, "const heim_oid asn1_oid_%s = " + "{ %lu, oid_%s_variable_num };\n\n", + s->gen_name, (unsigned long)len, s->gen_name); + + fprintf(oidsfile, "DEFINE_OID_WITH_NAME(%s)\n", s->gen_name); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_OID(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); + + free(list); + + /* header file */ + + gen_upper = strdup(s->gen_name); + len = strlen(gen_upper); + for (i = 0; i < len; i++) + gen_upper[i] = toupper((unsigned char)s->gen_name[i]); + + fprintf (headerfile, "} */\n"); + fprintf (headerfile, + "extern ASN1EXP const heim_oid asn1_oid_%s;\n" + "#define ASN1_OID_%s (&asn1_oid_%s)\n\n", + s->gen_name, + gen_upper, + s->gen_name); + + free(gen_upper); + + if (!one_code_file) + close_codefile(); + + break; + } + default: + abort(); + } +} + +int +is_tagged_type(const Type *t) +{ + /* + * Start by chasing aliasings like this: + * + * Type0 ::= ... + * Type1 ::= Type0 + * .. + * TypeN ::= TypeN-1 + * + * to , then check if is tagged. + */ + while (t->type == TType) { + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + abort(); + + } + if (t->type == TTag && t->tag.tagenv == TE_EXPLICIT) + return 1; + if (t->type == TTag) { + if (t->subtype) + return is_tagged_type(t->subtype); + if (t->symbol && t->symbol->type) + return is_tagged_type(t->symbol->type); + /* This is the tag */ + return 1; + } + return 0; +} + +int +is_primitive_type(const Type *t) +{ + /* + * Start by chasing aliasings like this: + * + * Type0 ::= ... + * Type1 ::= Type0 + * .. + * TypeN ::= TypeN-1 + * + * to , then check if is primitive. + */ + while (t->type == TType && + t->symbol && + t->symbol->type) { + if (t->symbol->type->type == TType) + t = t->symbol->type; /* Alias */ + else if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagenv == TE_IMPLICIT) + /* + * IMPLICIT-tagged alias, something like: + * + * Type0 ::= [0] IMPLICIT ... + * + * Just recurse. + */ + return is_primitive_type(t->symbol->type); + else + break; + + } + /* EXPLICIT non-UNIVERSAL tags are always constructed */ + if (t->type == TTag && t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) + return 0; + if (t->symbol && t->symbol->type) { + /* EXPLICIT non-UNIVERSAL tags are constructed */ + if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagclass != ASN1_C_UNIV && + t->symbol->type->tag.tagenv == TE_EXPLICIT) + return 0; + /* EXPLICIT UNIVERSAL tags are constructed if they are SEQUENCE/SET */ + if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagclass == ASN1_C_UNIV) { + switch (t->symbol->type->tag.tagvalue) { + case UT_Sequence: return 0; + case UT_Set: return 0; + default: return 1; + } + } + } + switch(t->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TBitString: + case TEnumerated: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TOID: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TNull: + return 1; + case TTag: + return is_primitive_type(t->subtype); + default: + return 0; + } +} + +static void +space(int level) +{ + while(level-- > 0) + fprintf(headerfile, " "); +} + +static const char * +last_member_p(struct member *m) +{ + struct member *n = HEIM_TAILQ_NEXT(m, members); + if (n == NULL) + return ""; + if (n->ellipsis && HEIM_TAILQ_NEXT(n, members) == NULL) + return ""; + return ","; +} + +static struct member * +have_ellipsis(Type *t) +{ + struct member *m; + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) + return m; + } + return NULL; +} + +static void +define_asn1 (int level, Type *t) +{ + switch (t->type) { + case TType: + if (!t->symbol && t->typeref.iosclass) { + fprintf(headerfile, "%s.&%s", + t->typeref.iosclass->symbol->name, + t->typeref.field->name); + } else if (t->symbol) + fprintf(headerfile, "%s", t->symbol->name); + else + abort(); + break; + case TInteger: + if(t->members == NULL) { + fprintf (headerfile, "INTEGER"); + if (t->range) + fprintf (headerfile, " (%lld..%lld)", + (long long)t->range->min, + (long long)t->range->max); + } else { + Member *m; + fprintf (headerfile, "INTEGER {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space (level + 1); + fprintf(headerfile, "%s(%lld)%s\n", m->gen_name, + (long long)m->val, last_member_p(m)); + } + space(level); + fprintf (headerfile, "}"); + } + break; + case TBoolean: + fprintf (headerfile, "BOOLEAN"); + break; + case TOctetString: + fprintf (headerfile, "OCTET STRING"); + break; + case TEnumerated: + case TBitString: { + Member *m; + + space(level); + if(t->type == TBitString) + fprintf (headerfile, "BIT STRING {\n"); + else + fprintf (headerfile, "ENUMERATED {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 1); + fprintf(headerfile, "%s(%lld)%s\n", m->name, + (long long)m->val, last_member_p(m)); + } + space(level); + fprintf (headerfile, "}"); + break; + } + case TChoice: + case TSet: + case TSequence: { + Member *m; + size_t max_width = 0; + + if(t->type == TChoice) + fprintf(headerfile, "CHOICE {\n"); + else if(t->type == TSet) + fprintf(headerfile, "SET {\n"); + else + fprintf(headerfile, "SEQUENCE {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if(strlen(m->name) > max_width) + max_width = strlen(m->name); + } + max_width += 3; + if(max_width < 16) max_width = 16; + HEIM_TAILQ_FOREACH(m, t->members, members) { + size_t width = max_width; + space(level + 1); + if (m->ellipsis) { + fprintf (headerfile, "..."); + } else { + width -= fprintf(headerfile, "%s", m->name); + fprintf(headerfile, "%*s", (int)width, ""); + define_asn1(level + 1, m->type); + if(m->optional) + fprintf(headerfile, " OPTIONAL"); + } + if(last_member_p(m)) + fprintf (headerfile, ","); + fprintf (headerfile, "\n"); + } + space(level); + fprintf (headerfile, "}"); + break; + } + case TSequenceOf: + fprintf (headerfile, "SEQUENCE OF "); + define_asn1 (0, t->subtype); + break; + case TSetOf: + fprintf (headerfile, "SET OF "); + define_asn1 (0, t->subtype); + break; + case TGeneralizedTime: + fprintf (headerfile, "GeneralizedTime"); + break; + case TGeneralString: + fprintf (headerfile, "GeneralString"); + break; + case TTeletexString: + fprintf (headerfile, "TeletexString"); + break; + case TTag: { + const char *classnames[] = { "UNIVERSAL ", "APPLICATION ", + "" /* CONTEXT */, "PRIVATE " }; + if(t->tag.tagclass != ASN1_C_UNIV) + fprintf (headerfile, "[%s%d] ", + classnames[t->tag.tagclass], + t->tag.tagvalue); + if(t->tag.tagenv == TE_IMPLICIT) + fprintf (headerfile, "IMPLICIT "); + define_asn1 (level, t->subtype); + break; + } + case TUTCTime: + fprintf (headerfile, "UTCTime"); + break; + case TUTF8String: + space(level); + fprintf (headerfile, "UTF8String"); + break; + case TPrintableString: + space(level); + fprintf (headerfile, "PrintableString"); + break; + case TIA5String: + space(level); + fprintf (headerfile, "IA5String"); + break; + case TBMPString: + space(level); + fprintf (headerfile, "BMPString"); + break; + case TUniversalString: + space(level); + fprintf (headerfile, "UniversalString"); + break; + case TVisibleString: + space(level); + fprintf (headerfile, "VisibleString"); + break; + case TOID : + space(level); + fprintf(headerfile, "OBJECT IDENTIFIER"); + break; + case TNull: + space(level); + fprintf (headerfile, "NULL"); + break; + default: + abort (); + } +} + +static void +getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name) +{ + if (typedefp) + *newbasename = strdup(name); + else { + if (name[0] == '*') + name++; + if (asprintf(newbasename, "%s_%s", basename, name) < 0) + errx(1, "malloc"); + } + if (*newbasename == NULL) + err(1, "malloc"); +} + +typedef enum define_type_options { + DEF_TYPE_NONE = 0, + DEF_TYPE_PRESERVE = 1, + DEF_TYPE_TYPEDEFP = 2, + DEF_TYPE_EMIT_NAME = 4 +} define_type_options; +static void define_type(int, const char *, const char *, Type *, Type *, define_type_options); + +/* + * Get the SET/SEQUENCE member pair and CLASS field pair defining an open type. + * + * There are three cases: + * + * - open types embedded in OCTET STRING, with the open type object class + * relation declared via a constraint + * + * - open types not embedded in OCTET STRING, which are really more like ANY + * DEFINED BY types, so, HEIM_ANY + * + * - open types in a nested structure member where the type ID field is in a + * member of the ancestor structure (this happens in PKIX's `AttributeSet', + * where the open type is essentially a SET OF HEIM_ANY). + * + * In a type like PKIX's SingleAttribute the type ID member would be the one + * named "type" and the open type member would be the one named "value", and + * the corresponding fields of the ATTRIBUTE class would be named "id" and + * "Type". + * + * NOTE: We assume a single open type member pair in any SET/SEQUENCE. In + * principle there could be more pairs and we could iterate them, or + * better yet, we could be given the name of an open type member and then + * just find its related type ID member and fields, then our caller would + * iterate the SET/SEQUENCE type's members looking for open type members + * and would call this function for each one found. + */ +void +get_open_type_defn_fields(const Type *t, + Member **typeidmember, + Member **opentypemember, + Field **typeidfield, + Field **opentypefield, + int *is_array_of) +{ + Member *m; + Field *junk1, *junk2; + char *idmembername = NULL; + + if (!typeidfield) typeidfield = &junk1; + if (!opentypefield) opentypefield = &junk2; + + *typeidfield = *opentypefield = NULL; + *typeidmember = *opentypemember = NULL; + *is_array_of = 0; + + /* Look for the open type member */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + Type *subtype = m->type; + Type *sOfType = NULL; + + while (subtype->type == TTag || + subtype->type == TSetOf || + subtype->type == TSequenceOf) { + if (subtype->type == TTag && subtype->subtype) { + if (subtype->subtype->type == TOctetString || + subtype->subtype->type == TBitString) + break; + subtype = subtype->subtype; + } else if (subtype->type == TSetOf || subtype->type == TSequenceOf) { + sOfType = subtype; + if (sOfType->symbol) + break; + if (subtype->subtype) + subtype = subtype->subtype; + } else + break; + } + /* + * If we traversed through a non-inlined SET OF or SEQUENCE OF type, + * then this cannot be an open type field. + */ + if (sOfType && sOfType->symbol) + continue; + /* + * The type of the field we're interested in has to have an information + * object constraint. + */ + if (!subtype->constraint) + continue; + if (subtype->type != TType && subtype->type != TTag) + continue; + /* + * Check if it's an ANY-like member or like an OCTET STRING CONTAINING + * member. Those are the only two possibilities. + */ + if ((subtype->type == TTag || subtype->type == TType) && + subtype->subtype && + subtype->constraint->ctype == CT_CONTENTS && + subtype->constraint->u.content.type && + subtype->constraint->u.content.type->type == TType && + !subtype->constraint->u.content.type->subtype && + subtype->constraint->u.content.type->constraint && + subtype->constraint->u.content.type->constraint->ctype == CT_TABLE_CONSTRAINT) { + /* Type like OCTET STRING or BIT STRING CONTAINING open type */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); + *opentypemember = m; + *opentypefield = subtype->constraint->u.content.type->typeref.field; + *is_array_of = sOfType != NULL; + idmembername = subtype->constraint->u.content.type->constraint->u.content.crel.membername; + break; + } else if (subtype->symbol && strcmp(subtype->symbol->name, "HEIM_ANY") == 0) { + /* Open type, but NOT embedded in OCTET STRING or BIT STRING */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); + *opentypemember = m; + *opentypefield = subtype->typeref.field; + *is_array_of = sOfType != NULL; + idmembername = subtype->constraint->u.content.crel.membername; + break; + } + } + + if (!idmembername) + errx(1, "Missing open type id member in %s", + t->symbol ? t->symbol->name : ""); + /* Look for the type ID member identified in the previous loop */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (!m->type->subtype || strcmp(m->name, idmembername) != 0) + continue; + if (m->type->constraint && + m->type->constraint->ctype == CT_TABLE_CONSTRAINT) + *typeidfield = m->type->typeref.field; + else if (m->type->subtype->constraint && + m->type->subtype->constraint->ctype == CT_TABLE_CONSTRAINT) + *typeidfield = m->type->subtype->typeref.field; + else + continue; + /* This is the type ID field (because there _is_ a subtype) */ + *typeidmember = m; + break; + } +} + +/* + * Generate CHOICE-like struct fields for open types declared via + * X.681/682/683 syntax. + * + * We could support multiple open type members in a SET/SEQUENCE, but for now + * we support only one. + */ +static void +define_open_type(int level, const char *newbasename, const char *name, const char *basename, Type *pt, Type *t) +{ + Member *opentypemember, *typeidmember; + Field *opentypefield, *typeidfield; + ObjectField *of; + IOSObjectSet *os = pt->actual_parameter; + IOSObject **objects; + size_t nobjs, i; + int is_array_of_open_type; + + get_open_type_defn_fields(pt, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + if (!opentypemember || !typeidmember || + !opentypefield || !typeidfield) + errx(1, "Open type specification in %s is incomplete", name); + + sort_object_set(os, typeidfield, &objects, &nobjs); + + fprintf(headerfile, "struct {\n"); + fprintf(jsonfile, "{\"opentype\":true,\"arraytype\":%s,", + is_array_of_open_type ? "true" : "false"); + fprintf(jsonfile, "\"classname\":\"%s\",", os->iosclass->symbol->name); + fprintf(jsonfile, "\"objectsetname\":\"%s\",", os->symbol->name); + fprintf(jsonfile, "\"typeidmember\":\"%s\",", typeidmember->name); + fprintf(jsonfile, "\"opentypemember\":\"%s\",", opentypemember->name); + fprintf(jsonfile, "\"typeidfield\":\"%s\",", typeidfield->name); + fprintf(jsonfile, "\"opentypefield\":\"%s\",", opentypefield->name); + + /* Iterate objects in the object set, gen enum labels */ + fprintf(headerfile, "enum { choice_%s_iosnumunknown = 0,\n", + newbasename); + fprintf(jsonfile, "\"opentypeids\":["); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) != 0) + continue; + if (!of->value || !of->value->s) + errx(1, "Unknown value in value field %s of object %s", + of->name, objects[i]->symbol->name); + fprintf(headerfile, "choice_%s_iosnum_%s,\n", + newbasename, of->value->s->gen_name); + fprintf(jsonfile, "\"%s\"", of->value->s->gen_name); + fprintf(jsonfile, "%s", (i + 1) < nobjs ? "," : ""); + } + } + fprintf(jsonfile, "],\n"); + fprintf(headerfile, "} element;\n"); + + if (is_array_of_open_type) + fprintf(headerfile, "unsigned int len;\n"); + + /* Iterate objects in the object set, gen union arms */ + fprintf(headerfile, "union {\nvoid *_any;\n"); + fprintf(jsonfile, "\"members\":["); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + char *n = NULL; + + /* XXX Print the type IDs into the jsonfile too pls */ + + if (strcmp(of->name, opentypefield->name) != 0) + continue; + if (!of->type || (!of->type->symbol && of->type->type != TTag) || + of->type->tag.tagclass != ASN1_C_UNIV) { + warnx("Ignoring unknown or unset type field %s of object %s", + of->name, objects[i]->symbol->name); + continue; + } + + if (asprintf(&n, "*%s", objects[i]->symbol->gen_name) < 0 || n == NULL) + err(1, "malloc"); + define_type(level + 2, n, newbasename, NULL, of->type, DEF_TYPE_NONE); + fprintf(jsonfile, "%s", (i + 1) < nobjs ? "," : ""); + free(n); + } + } + fprintf(jsonfile, "]}\n"); + if (is_array_of_open_type) { + fprintf(headerfile, "} *val;\n} _ioschoice_%s;\n", opentypemember->gen_name); + } else { + fprintf(headerfile, "} u;\n"); + fprintf(headerfile, "} _ioschoice_%s;\n", opentypemember->gen_name); + } + free(objects); +} + +static const char * const tagclassnames[] = { + "UNIVERSAL", "APPLICATION", "CONTEXT", "PRIVATE" +}; + +static void +define_type(int level, const char *name, const char *basename, + Type *pt, Type *t, define_type_options opts) +{ + const char *label_prefix = NULL; + const char *label_prefix_sep = NULL; + char *newbasename = NULL; + + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"is_type\":true,\"exported\":%s,\"typedef\":%s,", + basename, name, + t->symbol && is_export(t->symbol->name) ? "true" : "false", + (opts & DEF_TYPE_TYPEDEFP) ? "true" : "false"); + + switch (t->type) { + case TType: + space(level); + if (!t->symbol && t->actual_parameter) { + define_open_type(level, newbasename, name, basename, t, t); + } else if (!t->symbol && pt->actual_parameter) { + define_open_type(level, newbasename, name, basename, pt, t); + } else if (t->symbol) { + fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name); + fprintf(jsonfile, "\"ttype\":\"%s\"," + "\"alias\":true\n", t->symbol->gen_name); + } else + abort(); + break; + case TInteger: + if (t->symbol && t->symbol->emitted_definition) + break; + + space(level); + if(t->members) { + Member *m; + + label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : ""); + label_prefix_sep = prefix_enum ? "_" : ""; + fprintf (headerfile, "enum %s {\n", (opts & DEF_TYPE_TYPEDEFP) ? name : ""); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"enum\"," + "\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space (level + 1); + fprintf(headerfile, "%s%s%s = %lld%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld}%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + } + fprintf(headerfile, "} %s;\n", name); + fprintf(jsonfile, "]"); + } else if (t->range == NULL) { + fprintf(headerfile, "heim_integer %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"heim_integer\""); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + fprintf(headerfile, "int64_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int64_t\""); + } else if (t->range->min < 0) { + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int\""); + } else if (t->range->max > UINT_MAX) { + fprintf (headerfile, "uint64_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"uint64_t\""); + } else { + fprintf (headerfile, "unsigned int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"unsigned int\""); + } + break; + case TBoolean: + space(level); + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"BOOLEAN\",\"ctype\":\"unsigned int\""); + break; + case TOctetString: + space(level); + fprintf (headerfile, "heim_octet_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"OCTET STRING\",\"ctype\":\"heim_octet_string\""); + break; + case TBitString: { + Member *m; + Type i; + struct range range = { 0, UINT_MAX }; + size_t max_memno = 0; + size_t bitset_size; + + if (t->symbol && t->symbol->emitted_definition) + break; + memset(&i, 0, sizeof(i)); + + /* + * range.max implies the size of the base unsigned integer used for the + * bitfield members. If it's less than or equal to UINT_MAX, then that + * will be unsigned int, otherwise it will be uint64_t. + * + * We could just use uint64_t, yes, but for now, and in case that any + * projects were exposing the BIT STRING types' C representations in + * ABIs prior to this compiler supporting BIT STRING with larger + * members, we stick to this. + */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > max_memno) + max_memno = m->val; + } + if (max_memno > 63) + range.max = INT64_MAX; + else + range.max = 1ULL << max_memno; + + i.type = TInteger; + i.range = ⦥ + i.members = NULL; + i.constraint = NULL; + + space(level); + fprintf(jsonfile, "\"ttype\":\"BIT STRING\","); + if(HEIM_TAILQ_EMPTY(t->members)) { + fprintf (headerfile, "heim_bit_string %s;\n", name); + fprintf(jsonfile, "\"ctype\":\"heim_bit_string\""); + } else { + int64_t pos = 0; + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ctype\":\"struct %s\",\"members\":[\n", newbasename); + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *n = NULL; + + /* + * pad unused bits beween declared members (hopefully this + * forces the compiler to give us an obvious layout) + */ + while (pos < m->val) { + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) + err(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, ","); + free(n); + pos++; + } + + n = NULL; + if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", last_member_p(m)); + free (n); + n = NULL; + pos++; + } + /* pad unused tail (ditto) */ + bitset_size = max_memno; + if (max_memno > 31) + bitset_size += 64 - (max_memno % 64); + else + bitset_size = 32; + if (pos < bitset_size) + fprintf(jsonfile, ","); + while (pos < bitset_size) { + char *n = NULL; + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) + errx(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", (pos + 1) < bitset_size ? "," : ""); + free(n); + pos++; + } + + space(level); + fprintf(headerfile, "}%s%s;\n\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + } + break; + } + case TEnumerated: { + Member *m; + + if (t->symbol && t->symbol->emitted_definition) + break; + + label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : ""); + label_prefix_sep = prefix_enum ? "_" : ""; + space(level); + fprintf (headerfile, "enum %s {\n", (opts & DEF_TYPE_TYPEDEFP) ? name : ""); + fprintf(jsonfile, "\"ctype\":\"enum %s\",\"extensible\":%s,\"members\":[\n", + (opts & DEF_TYPE_TYPEDEFP) ? name : "", have_ellipsis(t) ? "true" : "false"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 1); + if (m->ellipsis) { + fprintf (headerfile, "/* ... */\n"); + } else { + fprintf(headerfile, "%s%s%s = %lld%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld%s}\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + } + } + space(level); + fprintf(headerfile, "}%s%s;\n\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + break; + } + case TSet: + case TSequence: { + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + space(level); + + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"%s\",\"extensible\":%s," + "\"ctype\":\"struct %s\"", + t->type == TSet ? "SET" : "SEQUENCE", + have_ellipsis(t) ? "true" : "false", newbasename); + if (t->type == TSequence && (opts & DEF_TYPE_PRESERVE)) { + space(level + 1); + fprintf(headerfile, "heim_octet_string _save;\n"); + fprintf(jsonfile, ",\"preserve\":true"); + } + fprintf(jsonfile, ",\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) { + ; + } else if (m->optional || m->defval) { + char *n = NULL, *defval = NULL; + const char *namep, *defvalp; + + if (m->defval) { + switch (m->defval->type) { + case stringvalue: + if (asprintf(&defval, "\"%s\"", m->defval->u.stringvalue) < 0 || defval == NULL) + errx(1, "malloc"); + defvalp = defval; + break; + case integervalue: + if (asprintf(&defval, "%lld", (long long)m->defval->u.integervalue) < 0 || defval == NULL) + errx(1, "malloc"); + defvalp = defval; + break; + case booleanvalue: + defvalp = m->defval->u.booleanvalue ? "true" : "false"; + break; + default: + abort(); + } + } else + defvalp = "null"; + + if (m->optional) { + if (asprintf(&n, "*%s", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + namep = n; + } else + namep = m->gen_name; + + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"optional\":%s,\"defval\":%s,\"type\":", + m->name, m->gen_name, m->optional ? "true" : "false", defvalp); + define_type(level + 1, namep, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + free (n); + free (defval); + } else { + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"optional\":false,\"type\":", m->name, m->gen_name); + define_type(level + 1, m->gen_name, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + } + } + fprintf(jsonfile, "]"); + if (t->actual_parameter && t->actual_parameter->objects) { + fprintf(jsonfile, ",\"opentype\":"); + define_open_type(level, newbasename, name, basename, t, t); + } + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); + } + if (decorated) + fprintf(jsonfile, "]"); + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + free(deco.field_type); + break; + } + case TSetOf: + case TSequenceOf: { + Type i; + struct range range = { 0, UINT_MAX }; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + memset(&i, 0, sizeof(i)); + i.type = TInteger; + i.range = ⦥ + + space(level); + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"%s\",\"ctype\":\"struct %s\",\"members\":[", + t->type == TSetOf ? "SET OF" : "SEQUENCE OF", newbasename); + define_type(level + 1, "len", newbasename, t, &i, DEF_TYPE_NONE); + fprintf(jsonfile, ","); + define_type(level + 1, "*val", newbasename, t, t->subtype, DEF_TYPE_NONE | DEF_TYPE_EMIT_NAME); + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + break; + } + case TGeneralizedTime: + space(level); + fprintf (headerfile, "time_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"GeneralizedTime\",\"ctype\":\"time_t\""); + break; + case TGeneralString: + space(level); + fprintf (headerfile, "heim_general_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"GeneralString\",\"ctype\":\"heim_general_string\""); + break; + case TTeletexString: + space(level); + fprintf (headerfile, "heim_general_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"TeletexString\",\"ctype\":\"heim_general_string\""); + break; + case TTag: + if (t->implicit_choice) { + fprintf(jsonfile, "\"desired_tagenv\":\"IMPLICIT\","); + } + fprintf(jsonfile, "\"tagclass\":\"%s\",\"tagvalue\":%d,\"tagenv\":\"%s\",\n", + tagclassnames[t->tag.tagclass], t->tag.tagvalue, + t->tag.tagenv == TE_EXPLICIT ? "EXPLICIT" : "IMPLICIT"); + fprintf(jsonfile, "\"ttype\":\n"); + define_type(level, name, basename, t, t->subtype, opts); + break; + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; + int first = 1; + Member *m; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + space(level); + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"CHOICE\",\"ctype\":\"struct %s\"", + newbasename); + if ((opts & DEF_TYPE_PRESERVE)) { + space(level + 1); + fprintf(headerfile, "heim_octet_string _save;\n"); + fprintf(jsonfile, ",\"preserve\":true"); + } + space(level + 1); + fprintf (headerfile, "enum %s_enum {\n", newbasename); + m = have_ellipsis(t); + if (m) { + space(level + 2); + fprintf (headerfile, "%s = 0,\n", m->label); + first = 0; + } + fprintf(jsonfile, ",\"extensible\":%s", m ? "true" : "false"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 2); + if (m->ellipsis) + fprintf (headerfile, "/* ... */\n"); + else + fprintf (headerfile, "%s%s%s\n", m->label, + first ? " = 1" : "", + last_member_p(m)); + first = 0; + } + space(level + 1); + fprintf (headerfile, "} element;\n"); + space(level + 1); + fprintf (headerfile, "union {\n"); + fprintf(jsonfile, ",\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) { + space(level + 2); + fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n"); + } else if (m->optional) { + char *n = NULL; + + if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + fprintf(jsonfile, "{\"optional\":"); + define_type(level + 2, n, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + free (n); + } else { + define_type(level + 2, m->gen_name, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", last_member_p(m)); + } + } + space(level + 1); + fprintf (headerfile, "} u;\n"); + fprintf(jsonfile, "]"); + + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); + } + if (decorated) + fprintf(jsonfile, "]"); + + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + break; + } + case TUTCTime: + space(level); + fprintf (headerfile, "time_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UTCTime\",\"ctype\":\"time_t\""); + break; + case TUTF8String: + space(level); + fprintf (headerfile, "heim_utf8_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UTF8String\",\"ctype\":\"heim_utf8_string\""); + break; + case TPrintableString: + space(level); + fprintf (headerfile, "heim_printable_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"PrintableString\",\"ctype\":\"heim_printable_string\""); + break; + case TIA5String: + space(level); + fprintf (headerfile, "heim_ia5_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"IA5String\",\"ctype\":\"heim_ia5_string\""); + break; + case TBMPString: + space(level); + fprintf (headerfile, "heim_bmp_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"BMPString\",\"ctype\":\"heim_bmp_string\""); + break; + case TUniversalString: + space(level); + fprintf (headerfile, "heim_universal_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UniversalString\",\"ctype\":\"heim_universal_string\""); + break; + case TVisibleString: + space(level); + fprintf (headerfile, "heim_visible_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"VisibleString\",\"ctype\":\"heim_visible_string\""); + break; + case TOID : + space(level); + fprintf (headerfile, "heim_oid %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"OBJECT IDENTIFIER\",\"ctype\":\"heim_oid\""); + break; + case TNull: + space(level); + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"NULL\",\"ctype\":\"int\""); + break; + default: + abort (); + } + fprintf(jsonfile, "}\n"); + free(newbasename); +} + +static void +declare_type(const Symbol *s, Type *t, int typedefp) +{ + char *newbasename = NULL; + + if (typedefp) + fprintf(headerfile, "typedef "); + + switch (t->type) { + case TType: + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_PRESERVE | DEF_TYPE_TYPEDEFP | + (s->emitted_declaration ? 0 : DEF_TYPE_EMIT_NAME)); + if (template_flag && !s->emitted_declaration) + generate_template_type_forward(s->gen_name); + emitted_declaration(s); + return; + case TInteger: + case TBoolean: + case TOctetString: + case TBitString: + case TEnumerated: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TOID : + case TNull: + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_PRESERVE | DEF_TYPE_TYPEDEFP | + (s->emitted_declaration ? 0 : DEF_TYPE_EMIT_NAME)); + if (template_flag && !s->emitted_declaration) + generate_template_type_forward(s->gen_name); + emitted_declaration(s); + emitted_definition(s); + return; + case TTag: + if (!s->emitted_declaration) + declare_type(s, t->subtype, FALSE); + emitted_declaration(s); + return; + default: + break; + } + + switch (t->type) { + case TSet: + case TSequence: { + struct decoration deco; + ssize_t more_deco = -1; + + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } + break; + } + case TSetOf: + case TSequenceOf: + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + break; + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } + break; + } + default: + abort (); + } + free(newbasename); + emitted_declaration(s); +} + +static void generate_subtypes_header_helper(const Member *m); +static void generate_type_header(const Symbol *); + +static void +generate_subtypes_header_helper(const Member *m) +{ + Member *sm; + Symbol *s; + + if (m->ellipsis) + return; + if (m->type->symbol && (s = getsym(m->type->symbol->name)) && + !s->emitted_definition) { + /* A field of some named type; recurse */ + if (!m->optional && !m->defval) + generate_type_header(s); + return; + } + if (!m->type->subtype && !m->type->members) + return; + if (m->type->type == TTag && + m->type->subtype && m->type->subtype->symbol && + (s = getsym(m->type->subtype->symbol->name))) { + if (!m->optional && !m->defval) + generate_type_header(s); + return; + } + if (m->type->subtype) { + switch (m->type->subtype->type) { + case TSet: + case TSequence: + case TChoice: + break; + default: + return; + } + /* A field of some anonymous (inlined) structured type */ + HEIM_TAILQ_FOREACH(sm, m->type->subtype->members, members) { + generate_subtypes_header_helper(sm); + } + } + if (m->type->members) { + HEIM_TAILQ_FOREACH(sm, m->type->members, members) { + generate_subtypes_header_helper(sm); + } + } +} + +static void +generate_subtypes_header(const Symbol *s) +{ + Type *t = s->type; + Member *m; + + /* + * Recurse down structured types to make sure top-level types get + * defined before they are referenced. + * + * We'll take care to skip OPTIONAL member fields of constructed types so + * that we can have circular types like: + * + * Foo ::= SEQUENCE { + * bar Bar OPTIONAL + * } + * + * Bar ::= SEQUENCE { + * foo Foo OPTIONAL + * } + * + * not unlike XDR, which uses `*' to mean "optional", except in XDR it's + * called a "pointer". With some care we should be able to eventually + * support the silly XDR linked list example: + * + * ListOfFoo ::= SEQUENCE { + * someField SomeType, + * next ListOfFoo OPTIONAL + * } + * + * Not that anyone needs it -- just use a SEQUENCE OF and be done. + */ + + while (t->type == TTag && t->subtype) { + switch (t->subtype->type) { + case TTag: + case TSet: + case TSequence: + case TChoice: + t = t->subtype; + continue; + default: + break; + } + break; + } + + switch (t->type) { + default: return; + case TType: { + Symbol *s2; + if (t->symbol && (s2 = getsym(t->symbol->name)) != s) + generate_type_header(s2); + return; + } + case TSet: + case TSequence: + case TChoice: + break; + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + generate_subtypes_header_helper(m); + } +} + +static void +generate_type_header (const Symbol *s) +{ + Type *t = s->type; + + if (!s->type) + return; + + /* + * Recurse down the types of member fields of `s' to make sure that + * referenced types have had their definitions emitted already if the + * member fields are not OPTIONAL/DEFAULTed. + */ + generate_subtypes_header(s); + if (!s->emitted_asn1) { + fprintf(headerfile, "/*\n"); + fprintf(headerfile, "%s ::= ", s->name); + define_asn1 (0, s->type); + fprintf(headerfile, "\n*/\n\n"); + emitted_asn1(s); + } + + /* + * Emit enums for the outermost tag of this type. These are needed for + * dealing with IMPLICIT tags so we know what to rewrite the tag to when + * decoding. + * + * See gen_encode.c and gen_decode.c for a complete explanation. Short + * version: we need to change the prototypes of the length/encode/decode + * functions to take an optional IMPLICIT tag to use instead of the type's + * outermost tag, but for now we hack it, and to do that we need to know + * the type's outermost tag outside the context of the bodies of the codec + * functions we generate for it. Using an enum means no extra space is + * needed in stripped objects. + */ + if (!s->emitted_tag_enums) { + while (t->type == TType && s->type->symbol && s->type->symbol->type) { + if (t->subtype) + t = t->subtype; + else + t = s->type->symbol->type; + } + + if (t->type == TType && t->symbol && + strcmp(t->symbol->name, "HEIM_ANY") != 0) { + /* + * This type is ultimately an alias of an imported type, so we don't + * know its outermost tag here. + */ + fprintf(headerfile, + "enum { asn1_tag_length_%s = asn1_tag_length_%s,\n" + " asn1_tag_class_%s = asn1_tag_class_%s,\n" + " asn1_tag_tag_%s = asn1_tag_tag_%s };\n", + s->gen_name, s->type->symbol->gen_name, + s->gen_name, s->type->symbol->gen_name, + s->gen_name, s->type->symbol->gen_name); + emitted_tag_enums(s); + } else if (t->type != TType) { + /* This type's outermost tag is known here */ + fprintf(headerfile, + "enum { asn1_tag_length_%s = %lu,\n" + " asn1_tag_class_%s = %d,\n" + " asn1_tag_tag_%s = %d };\n", + s->gen_name, (unsigned long)length_tag(s->type->tag.tagvalue), + s->gen_name, s->type->tag.tagclass, + s->gen_name, s->type->tag.tagvalue); + emitted_tag_enums(s); + } + } + + if (s->emitted_definition) + return; + + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); + + if (!s->emitted_declaration) { + fprintf(headerfile, "typedef "); + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_TYPEDEFP | DEF_TYPE_EMIT_NAME | + (preserve_type(s->name) ? DEF_TYPE_PRESERVE : 0)); + } else if (s->type->type == TType) { + /* This is a type alias and we've already declared it */ + } else if (s->type->type == TTag && + s->type->subtype != NULL && + s->type->subtype->symbol != NULL) { + /* This is a type alias and we've already declared it */ + } else { + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_TYPEDEFP | + (preserve_type(s->name) ? DEF_TYPE_PRESERVE : 0)); + } + fprintf(headerfile, "\n"); + + emitted_definition(s); +} + +void +generate_type_header_forwards(const Symbol *s) +{ + declare_type(s, s->type, TRUE); + fprintf(headerfile, "\n"); + if (template_flag) + generate_template_type_forward(s->gen_name); +} + +void +generate_type (const Symbol *s) +{ + FILE *h; + const char * exp; + + if (!one_code_file) + generate_header_of_codefile(s->gen_name); + + generate_type_header(s); + + if (template_flag) + generate_template(s); + + if (template_flag == 0 || is_template_compat(s) == 0) { + generate_type_encode (s); + generate_type_decode (s); + generate_type_free (s); + generate_type_length (s); + generate_type_copy (s); + generate_type_print_stub(s); + } + generate_type_seq (s); + generate_glue (s->type, s->gen_name); + + /* generate prototypes */ + + if (is_export(s->name)) { + h = headerfile; + exp = "ASN1EXP "; + } else { + h = privheaderfile; + exp = ""; + } + + fprintf (h, + "%sint ASN1CALL " + "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%sint ASN1CALL " + "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%ssize_t ASN1CALL length_%s(const %s *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%sint ASN1CALL copy_%s (const %s *, %s *);\n", + exp, + s->gen_name, s->gen_name, s->gen_name); + fprintf (h, + "%svoid ASN1CALL free_%s (%s *);\n", + exp, + s->gen_name, s->gen_name); + + fprintf(h, + "%schar * ASN1CALL print_%s (const %s *, int);\n", + exp, + s->gen_name, s->gen_name); + + fprintf(h, "\n\n"); + + if (!one_code_file) { + fprintf(codefile, "\n\n"); + close_codefile(); + } +} diff --git a/third_party/heimdal/lib/asn1/gen_copy.c b/third_party/heimdal/lib/asn1/gen_copy.c new file mode 100644 index 0000000..c6d420a --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_copy.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static int used_fail; + +static void +copy_primitive (const char *typename, const char *from, const char *to) +{ + fprintf (codefile, "if(der_copy_%s(%s, %s)) goto fail;\n", + typename, from, to); + used_fail++; +} + +static void +copy_type (const char *from, const char *to, const Type *t, int preserve) +{ + switch (t->type) { + case TType: +#if 0 + copy_type (from, to, t->symbol->type, preserve); +#endif + fprintf (codefile, "if(copy_%s(%s, %s)) goto fail;\n", + t->symbol->gen_name, from, to); + used_fail++; + break; + case TInteger: + if (t->range == NULL && t->members == NULL) { + copy_primitive ("heim_integer", from, to); + break; + } + HEIM_FALLTHROUGH; + case TBoolean: + case TEnumerated : + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TOctetString: + copy_primitive ("octet_string", from, to); + break; + case TBitString: + if (HEIM_TAILQ_EMPTY(t->members)) + copy_primitive ("bit_string", from, to); + else + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TSet: + case TSequence: + case TChoice: { + Member *m, *have_ellipsis = NULL; + + if(t->members == NULL) + break; + + if ((t->type == TSequence || t->type == TChoice) && preserve) { + fprintf(codefile, + "{ int ret;\n" + "ret = der_copy_octet_string(&(%s)->_save, &(%s)->_save);\n" + "if (ret) goto fail;\n" + "}\n", + from, to); + used_fail++; + } + + if(t->type == TChoice) { + fprintf(codefile, "(%s)->element = (%s)->element;\n", to, from); + fprintf(codefile, "switch((%s)->element) {\n", from); + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *fs; + char *ts; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + + if (asprintf (&fs, "%s(%s)->%s%s", + m->optional ? "" : "&", from, + t->type == TChoice ? "u." : "", m->gen_name) < 0) + errx(1, "malloc"); + if (fs == NULL) + errx(1, "malloc"); + if (asprintf (&ts, "%s(%s)->%s%s", + m->optional ? "" : "&", to, + t->type == TChoice ? "u." : "", m->gen_name) < 0) + errx(1, "malloc"); + if (ts == NULL) + errx(1, "malloc"); + if(m->optional){ + fprintf(codefile, "if(%s) {\n", fs); + fprintf(codefile, "%s = calloc(1, sizeof(*%s));\n", ts, ts); + fprintf(codefile, "if(%s == NULL) goto fail;\n", ts); + used_fail++; + } + copy_type (fs, ts, m->type, FALSE); + if(m->optional){ + fprintf(codefile, "}else\n"); + fprintf(codefile, "%s = NULL;\n", ts); + } + free (fs); + free (ts); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + if(t->type == TChoice) { + if (have_ellipsis) { + fprintf(codefile, "case %s: {\n" + "int ret;\n" + "ret=der_copy_octet_string(&(%s)->u.%s, &(%s)->u.%s);\n" + "if (ret) goto fail;\n" + "break;\n" + "}\n", + have_ellipsis->label, + from, have_ellipsis->gen_name, + to, have_ellipsis->gen_name); + used_fail++; + } + fprintf(codefile, "}\n"); + } + break; + } + case TSetOf: + case TSequenceOf: { + char *f = NULL, *T = NULL; + + fprintf (codefile, "if(((%s)->val = " + "calloc(1, (%s)->len * sizeof(*(%s)->val))) == NULL && (%s)->len != 0)\n", + to, from, to, from); + fprintf (codefile, "goto fail;\n"); + used_fail++; + fprintf(codefile, + "for((%s)->len = 0; (%s)->len < (%s)->len; (%s)->len++){\n", + to, to, from, to); + if (asprintf(&f, "&(%s)->val[(%s)->len]", from, to) < 0) + errx(1, "malloc"); + if (f == NULL) + errx(1, "malloc"); + if (asprintf(&T, "&(%s)->val[(%s)->len]", to, to) < 0) + errx(1, "malloc"); + if (T == NULL) + errx(1, "malloc"); + copy_type(f, T, t->subtype, FALSE); + fprintf(codefile, "}\n"); + free(f); + free(T); + break; + } + case TGeneralizedTime: + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TGeneralString: + copy_primitive ("general_string", from, to); + break; + case TTeletexString: + copy_primitive ("general_string", from, to); + break; + case TUTCTime: + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TUTF8String: + copy_primitive ("utf8string", from, to); + break; + case TPrintableString: + copy_primitive ("printable_string", from, to); + break; + case TIA5String: + copy_primitive ("ia5_string", from, to); + break; + case TBMPString: + copy_primitive ("bmp_string", from, to); + break; + case TUniversalString: + copy_primitive ("universal_string", from, to); + break; + case TVisibleString: + copy_primitive ("visible_string", from, to); + break; + case TTag: + copy_type (from, to, t->subtype, preserve); + break; + case TOID: + copy_primitive ("oid", from, to); + break; + case TNull: + break; + default : + abort (); + } +} + +void +generate_type_copy (const Symbol *s) +{ + struct decoration deco; + ssize_t more_deco = -1; + int preserve = preserve_type(s->name) ? TRUE : FALSE; + int save_used_fail = used_fail; + + used_fail = 0; + + fprintf (codefile, "int ASN1CALL\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + "memset(to, 0, sizeof(*to));\n", + s->gen_name, s->gen_name, s->gen_name); + copy_type ("from", "to", s->type, preserve); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.copy_function_name == NULL) { + /* Decorated with field of external type but no copy function */ + if (deco.ptr) + fprintf(codefile, "(to)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, "memset(&(to)->%s, 0, sizeof((to)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ copy function */ + if (deco.ptr) { + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", + deco.field_name, deco.field_name); + fprintf(codefile, "if (%s((from)->%s, (to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "if (%s(&(from)->%s, &(to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", deco.field_name, deco.field_name); + fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); + fprintf(codefile, "}\n"); + } else { + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); + } + used_fail++; + free(deco.field_type); + } + fprintf (codefile, "return 0;\n"); + + if (used_fail) + fprintf (codefile, "fail:\n" + "free_%s(to);\n" + "return ENOMEM;\n", + s->gen_name); + + fprintf(codefile, + "}\n\n"); + used_fail = save_used_fail; +} + diff --git a/third_party/heimdal/lib/asn1/gen_decode.c b/third_party/heimdal/lib/asn1/gen_decode.c new file mode 100644 index 0000000..fa9d79a --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_decode.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include "lex.h" + +RCSID("$Id$"); + +static void +decode_primitive (const char *typename, const char *name, const char *forwstr) +{ +#if 0 + fprintf (codefile, + "e = decode_%s(p, len, %s, &l);\n" + "%s;\n", + typename, + name, + forwstr); +#else + fprintf (codefile, + "e = der_get_%s(p, len, %s, &l);\n" + "if(e) %s;\np += l; len -= l; ret += l;\n", + typename, + name, + forwstr); +#endif +} + +static void +find_tag (const Type *t, + Der_class *cl, Der_type *ty, unsigned *tag) +{ + switch (t->type) { + case TBitString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_BitString; + break; + case TBoolean: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Boolean; + break; + case TChoice: + errx(1, "Cannot have recursive CHOICE"); + case TEnumerated: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Enumerated; + break; + case TGeneralString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_GeneralString; + break; + case TTeletexString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_TeletexString; + break; + case TGeneralizedTime: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_GeneralizedTime; + break; + case TIA5String: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_IA5String; + break; + case TInteger: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Integer; + break; + case TNull: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Null; + break; + case TOID: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_OID; + break; + case TOctetString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_OctetString; + break; + case TPrintableString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_PrintableString; + break; + case TSequence: + case TSequenceOf: + *cl = ASN1_C_UNIV; + *ty = CONS; + *tag = UT_Sequence; + break; + case TSet: + case TSetOf: + *cl = ASN1_C_UNIV; + *ty = CONS; + *tag = UT_Set; + break; + case TTag: + *cl = t->tag.tagclass; + *ty = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype) ? PRIM : CONS; + *tag = t->tag.tagvalue; /* XXX is this correct? */ + break; + case TType: + if ((t->symbol->stype == Stype && t->symbol->type == NULL) + || t->symbol->stype == SUndefined) { + lex_error_message("%s is imported or still undefined, " + " can't generate tag checking data in CHOICE " + "without this information", + t->symbol->name); + exit(1); + } + find_tag(t->symbol->type, cl, ty, tag); + return; + case TUTCTime: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UTCTime; + break; + case TUTF8String: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UTF8String; + break; + case TBMPString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_BMPString; + break; + case TUniversalString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UniversalString; + break; + case TVisibleString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_VisibleString; + break; + default: + abort(); + } +} + +static void +range_check(const char *name, + const char *length, + const char *forwstr, + struct range *r) +{ + if (r->min == r->max + 2 || r->min < r->max) + fprintf (codefile, + "if ((%s)->%s > %lld) {\n" + "e = ASN1_MAX_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->max, forwstr); + if ((r->min - 1 == r->max || r->min < r->max) && r->min > 0) + fprintf (codefile, + "if ((%s)->%s < %lld) {\n" + "e = ASN1_MIN_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->min, forwstr); + if (r->max == r->min) + fprintf (codefile, + "if ((%s)->%s != %lld) {\n" + "e = ASN1_EXACT_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->min, forwstr); +} + +static int +decode_type(const char *name, const Type *t, int optional, struct value *defval, + const char *forwstr, const char *tmpstr, const char *dertype, + unsigned int depth) +{ + switch (t->type) { + case TType: { + if (optional) + fprintf(codefile, + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) %s;\n", + name, name, name, forwstr); + fprintf (codefile, + "e = decode_%s(p, len, %s, &l);\n", + t->symbol->gen_name, name); + if (optional) { + fprintf (codefile, + "if(e == ASN1_MISSING_FIELD) {\n" + "free(%s);\n" + "%s = NULL;\n" + "} else if (e) { %s; \n" + "} else {\n" + "p += l; len -= l; ret += l;\n" + "}\n", + name, name, forwstr); + } else if (defval) { + fprintf(codefile, + "if (e == ASN1_MISSING_FIELD) {\n"); + /* + * `name' starts with an ampersand here and is not an lvalue. + * We skip the ampersand and then it is an lvalue. + */ + gen_assign_defval(name + 1, defval); + fprintf(codefile, + "} else if (e) { %s;\n" + "} else { p += l; len -= l; ret += l; }\n", + forwstr); + } else { + fprintf (codefile, + "if(e) %s;\n", + forwstr); + fprintf (codefile, + "p += l; len -= l; ret += l;\n"); + } + break; + } + case TInteger: + if(t->members) { + /* + * This will produce a worning, how its hard to fix since: + * if its enum to an NameType, we can add appriate + * type-cast. If its not though, we have to figure out if + * there is negative enum enum and use appropriate + * signness and size on the intertype we cast the result + * too. + */ + fprintf(codefile, + "{\n" + "int enumint;\n"); + decode_primitive ("integer", "&enumint", forwstr); + fprintf(codefile, + "*%s = enumint;\n" + "}\n", + name); + } else if (t->range == NULL) { + decode_primitive ("heim_integer", name, forwstr); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + decode_primitive ("integer64", name, forwstr); + } else if (t->range->min < 0) { + decode_primitive ("integer", name, forwstr); + } else if (t->range->max > UINT_MAX) { + decode_primitive ("unsigned64", name, forwstr); + } else { + decode_primitive ("unsigned", name, forwstr); + } + break; + case TBoolean: + decode_primitive ("boolean", name, forwstr); + break; + case TEnumerated: + decode_primitive ("enumerated", name, forwstr); + break; + case TOctetString: + if (dertype) { + fprintf(codefile, + "if (%s == CONS) {\n", + dertype); + decode_primitive("octet_string_ber", name, forwstr); + fprintf(codefile, + "} else {\n"); + } + decode_primitive ("octet_string", name, forwstr); + if (dertype) + fprintf(codefile, "}\n"); + if (t->range) + range_check(name, "length", forwstr, t->range); + break; + case TBitString: { + Member *m; + int pos = 0; + + if (HEIM_TAILQ_EMPTY(t->members)) { + decode_primitive ("bit_string", name, forwstr); + break; + } + fprintf(codefile, + "if (len < 1) return ASN1_OVERRUN;\n" + "p++; len--; ret++;\n"); + fprintf(codefile, + "do {\n" + "if (len < 1) break;\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + while (m->val / 8 > pos / 8) { + fprintf (codefile, + "p++; len--; ret++;\n" + "if (len < 1) break;\n"); + pos += 8; + } + fprintf(codefile, + "(%s)->%s = (*p >> %d) & 1;\n", + name, m->gen_name, (int)(7 - m->val % 8)); + } + fprintf(codefile, + "} while(0);\n"); + fprintf (codefile, + "p += len; ret += len;\n"); + break; + } + case TSequence: { + Member *m; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s = NULL; + + if (m->ellipsis) + continue; + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", + name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + decode_type(s, m->type, m->optional, m->defval, forwstr, + m->gen_name, NULL, depth + 1); + free (s); + } + + break; + } + case TSet: { + /* + * SET { ... } is the dumbest construct in ASN.1. It's semantically + * indistinguishable from SEQUENCE { ... } but in BER you can write the + * fields in any order you wish, and in DER you have to write them in + * lexicographic order. If you want a reason to hate ASN.1, this is + * certainly one, though the real reason to hate ASN.1 is BER/DER/CER, + * and, really, all tag-length-value (TLV) encodings ever invented, + * including Protocol Buffers. Fortunately not all ASN.1 encoding + * rules are TLV or otherwise self-describing. "Self-describing" + * encoding rules other than those meant to be [somewhat] readable by + * humans, such as XML and JSON, are simply dumb. But SET { ... } is a + * truly special sort of dumb. The only possible use of SET { ... } + * might well be for ASN.1 mappings of XML schemas(?). + */ + Member *m; + unsigned int memno; + + if(t->members == NULL) + break; + + fprintf(codefile, "{\n"); + fprintf(codefile, "uint64_t members = 0;\n"); + fprintf(codefile, "while(len > 0) {\n"); + fprintf(codefile, + "Der_class class;\n" + "Der_type type;\n" + "unsigned int tag;\n" + "e = der_get_tag (p, len, &class, &type, &tag, NULL);\n" + "if(e) %s;\n", forwstr); + fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n"); + memno = 0; + HEIM_TAILQ_FOREACH(m, t->members, members) { + Type *mst = m->type; /* Member sub-type */ + char *s; + + while (mst->type == TType) { + assert(mst->subtype || (mst->symbol && mst->symbol->type)); + mst = mst->subtype ? mst->subtype : mst->symbol->type; + } + assert(mst->type == TTag); + + fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n", + classname(mst->tag.tagclass), + (mst->tag.tagclass == ASN1_C_UNIV || mst->tag.tagenv == TE_IMPLICIT) && + is_primitive_type(mst->subtype) ? "PRIM" : "CONS", + valuename(mst->tag.tagclass, mst->tag.tagvalue)); + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if(m->optional) + fprintf(codefile, + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) { e = ENOMEM; %s; }\n", + s, s, s, forwstr); + decode_type (s, mst, 0, NULL, forwstr, m->gen_name, NULL, depth + 1); + free (s); + + fprintf(codefile, "members |= (1ULL << %u);\n", memno); + memno++; + fprintf(codefile, "break;\n"); + } + fprintf(codefile, + "default:\n" + "return ASN1_MISPLACED_FIELD;\n" + "break;\n"); + fprintf(codefile, "}\n"); + fprintf(codefile, "}\n"); + memno = 0; + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "if((members & (1ULL << %u)) == 0)\n", memno); + if(m->optional) + fprintf(codefile, "%s = NULL;\n", s); + else if(m->defval) + gen_assign_defval(s, m->defval); + else + fprintf(codefile, "return ASN1_MISSING_FIELD;\n"); + free(s); + memno++; + } + fprintf(codefile, "}\n"); + break; + } + case TSetOf: + case TSequenceOf: { + char *n = NULL; + char *sname = NULL; + + fprintf (codefile, + "{\n" + "size_t %s_origlen = len;\n" + "size_t %s_oldret = ret;\n" + "size_t %s_olen = 0;\n" + "void *%s_tmp;\n" + "ret = 0;\n" + "(%s)->len = 0;\n" + "(%s)->val = NULL;\n", + tmpstr, + tmpstr, + tmpstr, + tmpstr, + name, + name); + + fprintf (codefile, + "while(ret < %s_origlen) {\n" + "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n" + "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n" + "%s_olen = %s_nlen;\n" + "%s_tmp = realloc((%s)->val, %s_olen);\n" + "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n" + "(%s)->val = %s_tmp;\n", + tmpstr, + tmpstr, tmpstr, name, + tmpstr, tmpstr, forwstr, + tmpstr, tmpstr, + tmpstr, name, tmpstr, + tmpstr, forwstr, + name, tmpstr); + + if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + decode_type(n, t->subtype, 0, NULL, forwstr, sname, NULL, depth + 1); + fprintf (codefile, + "(%s)->len++;\n" + "len = %s_origlen - ret;\n" + "}\n" + "ret += %s_oldret;\n" + "}\n", + name, + tmpstr, tmpstr); + if (t->range) + range_check(name, "len", forwstr, t->range); + free (n); + free (sname); + break; + } + case TGeneralizedTime: + decode_primitive ("generalized_time", name, forwstr); + break; + case TGeneralString: + decode_primitive ("general_string", name, forwstr); + break; + case TTeletexString: + decode_primitive ("general_string", name, forwstr); + break; + case TTag:{ + char *tname = NULL, *typestring = NULL; + char *ide = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + /* + * XXX See the comments in gen_encode() about this. + */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && + strcmp(t->subtype->symbol->name, "HEIM_ANY") != 0) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + replace_tag = is_tagged_type(t->subtype->symbol->type); + + if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL) + errx(1, "malloc"); + + fprintf(codefile, + "{\n" + "size_t %s_datalen;\n" + "Der_type %s;\n", + tmpstr, typestring); + if (replace_tag) + fprintf(codefile, + "const unsigned char *psave%u = p;\n" + "unsigned char *pcopy%u;\n" + "size_t lensave%u, lsave%u;\n", + depth, depth, depth, depth); + else if (support_ber) + fprintf(codefile, + "int is_indefinite%u;\n", depth); + if (!replace_tag) + fprintf(codefile, + "size_t %s_oldlen;\n", tmpstr); + + fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, " + "&%s_datalen, &l);\n", + classname(t->tag.tagclass), + typestring, + valuename(t->tag.tagclass, t->tag.tagvalue), + tmpstr); + + /* XXX hardcode for now */ + if (!replace_tag && support_ber && t->subtype->type == TOctetString) { + ide = typestring; + } else { + fprintf(codefile, + "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n", + typestring, + prim ? "PRIM" : "CONS"); + } + + if(optional) { + fprintf(codefile, + "if(e) {\n" + "%s = NULL;\n" + "} else {\n" + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) { e = ENOMEM; %s; }\n", + name, name, name, name, forwstr); + } else if (defval) { + char *s; + + if (asprintf(&s, "*(%s)", name) == -1 || s == NULL) + return ENOMEM; + fprintf(codefile, "if (e && e != ASN1_MISSING_FIELD) %s;\n", forwstr); + fprintf(codefile, "if (e == ASN1_MISSING_FIELD) {\n"); + gen_assign_defval(s, defval); + free(s); + fprintf(codefile, "e = 0; l= 0;\n} else {\n"); + } else { + fprintf(codefile, "if (e) %s;\n", forwstr); + } + + if (replace_tag) + fprintf(codefile, + "lsave%u = %s_datalen + l;\n" + "lensave%u = len;\n" + "e = der_replace_tag(p, len, &pcopy%u, &len, asn1_tag_class_%s, %s, asn1_tag_tag_%s);\n" + "if (e) %s;\n" + "p = pcopy%u;\n", + depth, tmpstr, depth, depth, t->subtype->symbol->gen_name, + prim ? "PRIM" : "CONS", + t->subtype->symbol->gen_name, + forwstr, depth); + else + fprintf(codefile, + "p += l; len -= l; ret += l;\n"); + if (!replace_tag) + fprintf(codefile, + "%s_oldlen = len;\n", + tmpstr); + if (support_ber && !replace_tag) + fprintf (codefile, + "if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n" + "{ e = ASN1_BAD_FORMAT; %s; }\n" + "if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }", + depth, tmpstr, forwstr, depth, forwstr); + else if (!replace_tag) + fprintf(codefile, + "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n" + "len = %s_datalen;\n", tmpstr, forwstr, tmpstr); + if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + /* + * If `replace_tag' then here `p' and `len' will be the copy mutated by + * der_replace_tag(). + */ + decode_type(name, t->subtype, 0, NULL, forwstr, tname, ide, depth + 1); + if (replace_tag) + fprintf(codefile, + "p = psave%u + lsave%u;\n" + "len = lensave%u - lsave%u;\n" + "ret += lsave%u - l;\n" + "free(pcopy%u);\n", + depth, depth, depth, depth, depth, depth); + else if(support_ber) + fprintf(codefile, + "if(is_indefinite%u){\n" + "len += 2;\n" + "e = der_match_tag_and_length(p, len, " + "(Der_class)0, &%s, UT_EndOfContent, " + "&%s_datalen, &l);\n" + "if(e) %s;\n" + "p += l; len -= l; ret += l;\n" + "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n" + "} else \n", + depth, + typestring, + tmpstr, + forwstr, + typestring, forwstr); + if (!replace_tag) + fprintf(codefile, + "len = %s_oldlen - %s_datalen;\n", + tmpstr, tmpstr); + if (optional) + fprintf(codefile, "}\n"); + else if (defval) + fprintf(codefile, "}\n"); + fprintf(codefile, "}\n"); + free(tname); + free(typestring); + break; + } + case TChoice: { + Member *m, *have_ellipsis = NULL; + const char *els = ""; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH(m, t->members, members) { + const Type *tt = m->type; + char *s = NULL; + Der_class cl; + Der_type ty; + unsigned tag; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + find_tag(tt, &cl, &ty, &tag); + + fprintf(codefile, + "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n", + els, + classname(cl), + ty ? "CONS" : "PRIM", + valuename(cl, tag)); + fprintf(codefile, + "(%s)->element = %s;\n", + name, m->label); + if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&", + name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + decode_type(s, m->type, m->optional, NULL, forwstr, m->gen_name, + NULL, depth + 1); + free(s); + fprintf(codefile, + "}\n"); + els = "else "; + } + if (have_ellipsis) { + fprintf(codefile, + "else {\n" + "(%s)->element = %s;\n" + "(%s)->u.%s.data = calloc(1, len);\n" + "if ((%s)->u.%s.data == NULL) {\n" + "e = ENOMEM; %s;\n" + "}\n" + "(%s)->u.%s.length = len;\n" + "memcpy((%s)->u.%s.data, p, len);\n" + "p += len;\n" + "ret += len;\n" + "len = 0;\n" + "}\n", + name, have_ellipsis->label, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + forwstr, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name); + } else { + fprintf(codefile, + "else {\n" + "e = ASN1_PARSE_ERROR;\n" + "%s;\n" + "}\n", + forwstr); + } + break; + } + case TUTCTime: + decode_primitive ("utctime", name, forwstr); + break; + case TUTF8String: + decode_primitive ("utf8string", name, forwstr); + break; + case TPrintableString: + decode_primitive ("printable_string", name, forwstr); + break; + case TIA5String: + decode_primitive ("ia5_string", name, forwstr); + break; + case TBMPString: + decode_primitive ("bmp_string", name, forwstr); + break; + case TUniversalString: + decode_primitive ("universal_string", name, forwstr); + break; + case TVisibleString: + decode_primitive ("visible_string", name, forwstr); + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + break; + case TOID: + decode_primitive ("oid", name, forwstr); + break; + default : + abort (); + } + return 0; +} + +void +generate_type_decode (const Symbol *s) +{ + int preserve = preserve_type(s->name) ? TRUE : FALSE; + + fprintf (codefile, "int ASN1CALL\n" + "decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE," + " size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n" + "{\n", + s->gen_name, s->gen_name); + + switch (s->type->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TOID: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TUTCTime: + case TNull: + case TEnumerated: + case TBitString: + case TSequence: + case TSequenceOf: + case TSet: + case TSetOf: + case TTag: + case TType: + case TChoice: + fprintf (codefile, + "size_t ret = 0;\n" + "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" + "int e HEIMDAL_UNUSED_ATTRIBUTE;\n"); + if (preserve) + fprintf (codefile, "const unsigned char *begin = p;\n"); + + fprintf (codefile, "\n"); + fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */ + + decode_type("data", s->type, 0, NULL, "goto fail", "Top", NULL, 1); + if (preserve) + fprintf (codefile, + "data->_save.data = calloc(1, ret);\n" + "if (data->_save.data == NULL) { \n" + "e = ENOMEM; goto fail; \n" + "}\n" + "data->_save.length = ret;\n" + "memcpy(data->_save.data, begin, ret);\n"); + fprintf (codefile, + "if(size) *size = ret;\n" + "return 0;\n"); + fprintf (codefile, + "fail:\n" + "free_%s(data);\n" + "return e;\n", + s->gen_name); + break; + default: + abort (); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_encode.c b/third_party/heimdal/lib/asn1/gen_encode.c new file mode 100644 index 0000000..403ddac --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_encode.c @@ -0,0 +1,747 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +static void +encode_primitive (const char *typename, const char *name) +{ + fprintf (codefile, + "e = der_put_%s(p, len, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + typename, + name); +} + +const char * +classname(Der_class class) +{ + const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL", + "ASN1_C_CONTEXT", "ASN1_C_PRIV" }; + if ((int)class >= sizeof(cn) / sizeof(cn[0])) + return "???"; + return cn[class]; +} + + +const char * +valuename(Der_class class, int value) +{ + static char s[32]; + struct { + int value; + const char *s; + } *p, values[] = { +#define X(Y) { Y, #Y } + X(UT_BMPString), + X(UT_BitString), + X(UT_Boolean), + X(UT_EmbeddedPDV), + X(UT_Enumerated), + X(UT_External), + X(UT_GeneralString), + X(UT_GeneralizedTime), + X(UT_GraphicString), + X(UT_IA5String), + X(UT_Integer), + X(UT_Null), + X(UT_NumericString), + X(UT_OID), + X(UT_ObjectDescriptor), + X(UT_OctetString), + X(UT_PrintableString), + X(UT_Real), + X(UT_RelativeOID), + X(UT_Sequence), + X(UT_Set), + X(UT_TeletexString), + X(UT_UTCTime), + X(UT_UTF8String), + X(UT_UniversalString), + X(UT_VideotexString), + X(UT_VisibleString), +#undef X + { -1, NULL } + }; + if(class == ASN1_C_UNIV) { + for(p = values; p->value != -1; p++) + if(p->value == value) + return p->s; + } + snprintf(s, sizeof(s), "%d", value); + return s; +} + +static int +encode_type (const char *name, const Type *t, const char *tmpstr) +{ + int constructed = 1; + + switch (t->type) { + case TType: +#if 0 + encode_type (name, t->symbol->type); +#endif + fprintf (codefile, + "e = encode_%s(p, len, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + t->symbol->gen_name, name); + constructed = !is_primitive_type(t); + break; + case TInteger: + if(t->members) { + fprintf(codefile, + "{\n" + "int enumint = (int)*%s;\n", + name); + encode_primitive("integer", "&enumint"); + fprintf(codefile, "}\n;"); + } else if (t->range == NULL) { + encode_primitive("heim_integer", name); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + encode_primitive("integer64", name); + } else if (t->range->min < 0) { + encode_primitive("integer", name); + } else if (t->range->max > UINT_MAX) { + encode_primitive("unsigned64", name); + } else { + encode_primitive("unsigned", name); + } + + constructed = 0; + break; + case TBoolean: + encode_primitive ("boolean", name); + constructed = 0; + break; + case TOctetString: + encode_primitive ("octet_string", name); + constructed = 0; + break; + case TBitString: { + Member *m; + int pos; + + if (HEIM_TAILQ_EMPTY(t->members)) { + encode_primitive("bit_string", name); + constructed = 0; + break; + } + + fprintf (codefile, "{\n" + "unsigned char c = 0;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "int rest = 0;\n" + "int bit_set = 0;\n"); +#if 0 + pos = t->members->prev->val; + /* fix for buggy MIT (and OSF?) code */ + if (pos > 31) + abort (); +#endif + /* + * It seems that if we do not always set pos to 31 here, the MIT + * code will do the wrong thing. + * + * I hate ASN.1 (and DER), but I hate it even more when everybody + * has to screw it up differently. + */ + pos = HEIM_TAILQ_LAST(t->members, memhead)->val; + if (rfc1510_bitstring) { + if (pos < 31) + pos = 31; + } + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + while (m->val / 8 < pos / 8) { + if (!rfc1510_bitstring) + fprintf (codefile, + "if (c != 0 || bit_set) {\n"); + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = c; len--; ret++;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" + "bit_set = 1;\n" + "}\n" + "}\n"); + fprintf (codefile, + "c = 0;\n"); + pos -= 8; + } + fprintf (codefile, + "if((%s)->%s) {\n" + "c |= 1<<%d;\n", + name, m->gen_name, (int)(7 - m->val % 8)); + fprintf (codefile, + "}\n"); + } + + if (!rfc1510_bitstring) + fprintf (codefile, + "if (c != 0 || bit_set) {\n"); + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = c; len--; ret++;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "if(c) { \n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" + "}\n" + "}\n" + "}\n"); + + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = %s;\n" + "len -= 1;\n" + "ret += 1;\n" + "}\n\n", + rfc1510_bitstring ? "0" : "rest"); + constructed = 0; + break; + } + case TEnumerated : { + encode_primitive ("enumerated", name); + constructed = 0; + break; + } + + case TSet: + case TSequence: { + Member *m; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + char *s = NULL; + + if (m->ellipsis) + continue; + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "/* %s */\n", m->name); + if (m->optional) + fprintf (codefile, + "if(%s) ", + s); + else if(m->defval) + gen_compare_defval(s + 1, m->defval); + fprintf (codefile, "{\n"); + fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr); + fprintf (codefile, "ret = 0;\n"); + encode_type (s, m->type, m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + fprintf (codefile, "}\n"); + free (s); + } + break; + } + case TSetOf: { + + fprintf(codefile, + "{\n" + "heim_octet_string *val;\n" + "size_t elen = 0, totallen = 0;\n" + "int eret = 0;\n"); + + fprintf(codefile, + "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n" + "return ERANGE;\n", + name); + + fprintf(codefile, + "val = calloc(1, sizeof(val[0]) * (%s)->len);\n" + "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", + name, name); + + fprintf(codefile, + "for(i = 0; i < (int)(%s)->len; i++) {\n", + name); + + fprintf(codefile, + "ASN1_MALLOC_ENCODE(%s, val[i].data, " + "val[i].length, &(%s)->val[i], &elen, eret);\n", + t->subtype->symbol->gen_name, + name); + + fprintf(codefile, + "if(eret) {\n" + "i--;\n" + "while (i >= 0) {\n" + "free(val[i].data);\n" + "i--;\n" + "}\n" + "free(val);\n" + "return eret;\n" + "}\n" + "totallen += elen;\n" + "}\n"); + + fprintf(codefile, + "if (totallen > len) {\n" + "for (i = 0; i < (int)(%s)->len; i++) {\n" + "free(val[i].data);\n" + "}\n" + "free(val);\n" + "return ASN1_OVERFLOW;\n" + "}\n", + name); + + fprintf(codefile, + "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n", + name); + + fprintf (codefile, + "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" + "p -= val[i].length;\n" + "ret += val[i].length;\n" + "memcpy(p + 1, val[i].data, val[i].length);\n" + "free(val[i].data);\n" + "}\n" + "free(val);\n" + "}\n", + name); + break; + } + case TSequenceOf: { + char *sname = NULL; + char *n = NULL; + + fprintf (codefile, + "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" + "size_t %s_for_oldret = ret;\n" + "ret = 0;\n", + name, tmpstr); + if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + encode_type (n, t->subtype, sname); + fprintf (codefile, + "ret += %s_for_oldret;\n" + "}\n", + tmpstr); + free (n); + free (sname); + break; + } + case TGeneralizedTime: + encode_primitive ("generalized_time", name); + constructed = 0; + break; + case TGeneralString: + encode_primitive ("general_string", name); + constructed = 0; + break; + case TTeletexString: + encode_primitive ("general_string", name); + constructed = 0; + break; + case TTag: { + char *tname = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + int c; + if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + /* + * HACK HACK HACK + * + * This is part of the fix to the bug where we treated IMPLICIT tags of + * named types as EXPLICIT. I.e. + * + * Foo ::= SEQUENCE { ... } + * Bar ::= SEQUENCE { foo [0] IMPLICIT Foo } + * + * would get a context [0] constructed tag *and* a universal sequence + * constructed tag when it should get only the first tag. + * + * Properly fixing this would require changing the signatures of the + * encode, length, and decode functions we generate to take an optional + * tag to replace the one the encoder would generate / decoder would + * expect. That would change the ABI, which... isn't stable, but it's + * a bit soon to make that change. + * + * So, we're looking for IMPLICIT, and if we see any, we generate code + * to replace the tag. + * + * On the decode side we need to know what tag to restore. For this we + * generate enums in the generated header. + * + * NOTE: We *do* "replace" the tags of IMPLICIT-tagged primitive types, + * but our primitive codec functions leave those tags out, which + * is why we don't have to der_replace_tag() them here. + */ + /* + * If the tag is IMPLICIT and it's not primitive and the subtype is not + * any kind of structure... + */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + /* If it is a named type for a structured thing */ + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any")) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + /* + * Because the subtype is named we are generating its codec + * functions, and those will be adding their UNIVERSAL or whatever + * tags unlike our raw primtive codec library. + */ + replace_tag = is_tagged_type(t->subtype->symbol->type); + + if (replace_tag) + fprintf(codefile, + "{ unsigned char *psave_%s = p, *pfree_%s = NULL;\n" + "size_t l2_%s, lensave_%s = len;\n" + "len = length_%s(%s);\n" + /* Allocate a temp buffer for the encoder */ + "if ((p = pfree_%s = calloc(1, len)) == NULL) return ENOMEM;\n" + /* Make p point to the last byte of the allocated buf */ + "p += len - 1;\n", + tmpstr, tmpstr, tmpstr, tmpstr, + t->subtype->symbol->gen_name, name, tmpstr); + + /* XXX Currently we generate code that leaks `pfree_%s` here. */ + c = encode_type (name, t->subtype, tname); + /* Explicit non-UNIVERSAL tags are always constructed */ + if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT) + c = 1; + if (replace_tag) + fprintf(codefile, + "if (len) { free(pfree_%s); return EINVAL; }\n" + /* + * Here we have `p' pointing to one byte before the buffer + * we allocated above. + * + * [ T_wrong | LL | VVVV ] // temp buffer + * ^ ^ + * | | + * | \ + * \ +-- p + 1 + * +-- p + * + * psave_ still points to the last byte in the + * original buffer passed in where we should write the + * encoding of . + * + * We adjust psave_ to point to before the TLV + * encoding of (with wrong tag) in the original + * buffer (this may NOT be a valid pointer, but we won't + * dereference it): + * + * [ ... | T_wrong | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_ + */ + "psave_%s -= l;\n" + /* + * We further adjust psave_ to point to the last + * byte of what should be the T(ag) of the TLV encoding of + * (this is now a valid pointer), then... + * + * |<--->| (not written yet) + * | | |<-------->| (not written yet) + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_ + */ + "psave_%s += asn1_tag_length_%s;\n" + /* + * ...copy the L(ength)V(alue) of the TLV encoding of + * . + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_ + 1 + * + * |<----->| length is + * | | `l' - asn1_tag_length_ + * [ T_wrong | LL | VVVV ] // temp buffer + * ^ ^ + * | | + * | \ + * \ +-- p + 1 + asn1_tag_length_%s + * +-- p + 1 + */ + "memcpy(psave_%s + 1, p + 1 + asn1_tag_length_%s, l - asn1_tag_length_%s);\n" + /* + * Encode the IMPLICIT tag. Recall that encoders like + * der_put_tag() take a pointer to the last byte they + * should write to, and a length of bytes to the left of + * that that they are allowed to write into. + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_ + */ + "e = der_put_tag(psave_%s, %zu, %s, %s, %d, &l2_%s);\n" + "if (e) { free(pfree_%s); return e; }\n" + /* Restore `len' and adjust it (see `p' below) */ + "len = lensave_%s - (l + %zu - asn1_tag_length_%s);\n" + /* + * Adjust `ret' to account for the difference in size + * between the length of the right and wrong tags. + */ + "ret += %zu - asn1_tag_length_%s;\n" + /* Free the buffer and restore `p' */ + "free(pfree_%s);\n" + /* + * Make `p' point into the original buffer again, to one + * byte before the bytes we wrote: + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- p + */ + "p = psave_%s - (1 + %zu - asn1_tag_length_%s); }\n", + tmpstr, tmpstr, tmpstr, t->subtype->symbol->name, + tmpstr, t->subtype->symbol->name, t->subtype->symbol->name, + tmpstr, length_tag(t->tag.tagvalue), + classname(t->tag.tagclass), + c ? "CONS" : "PRIM", + t->tag.tagvalue, + tmpstr, + + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name, + length_tag(t->tag.tagvalue), t->subtype->symbol->name, + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name); + else + fprintf(codefile, + "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + classname(t->tag.tagclass), + c ? "CONS" : "PRIM", + valuename(t->tag.tagclass, t->tag.tagvalue)); + free(tname); + constructed = c; + break; + } + case TChoice:{ + Member *m, *have_ellipsis = NULL; + char *s = NULL; + + if (t->members == NULL) + break; + + fprintf(codefile, "\n"); + + if (asprintf (&s, "(%s)", name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "switch(%s->element) {\n", s); + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + char *s2 = NULL; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + fprintf (codefile, "case %s: {", m->label); + if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&", + s, m->gen_name) < 0 || s2 == NULL) + errx(1, "malloc"); + if (m->optional) + fprintf (codefile, "if(%s) {\n", s2); + fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr); + fprintf (codefile, "ret = 0;\n"); + constructed = encode_type (s2, m->type, m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + if(m->optional) + fprintf (codefile, "}\n"); + fprintf(codefile, "break;\n"); + fprintf(codefile, "}\n"); + free (s2); + } + free (s); + if (have_ellipsis) { + fprintf(codefile, + "case %s: {\n" + "if (len < (%s)->u.%s.length)\n" + "return ASN1_OVERFLOW;\n" + "p -= (%s)->u.%s.length;\n" + "ret += (%s)->u.%s.length;\n" + "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n" + "break;\n" + "}\n", + have_ellipsis->label, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name); + } + fprintf(codefile, "};\n"); + break; + } + case TOID: + encode_primitive ("oid", name); + constructed = 0; + break; + case TUTCTime: + encode_primitive ("utctime", name); + constructed = 0; + break; + case TUTF8String: + encode_primitive ("utf8string", name); + constructed = 0; + break; + case TPrintableString: + encode_primitive ("printable_string", name); + constructed = 0; + break; + case TIA5String: + encode_primitive ("ia5_string", name); + constructed = 0; + break; + case TBMPString: + encode_primitive ("bmp_string", name); + constructed = 0; + break; + case TUniversalString: + encode_primitive ("universal_string", name); + constructed = 0; + break; + case TVisibleString: + encode_primitive ("visible_string", name); + constructed = 0; + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + constructed = 0; + break; + default: + abort (); + } + return constructed; +} + +void +generate_type_encode (const Symbol *s) +{ + fprintf (codefile, "int ASN1CALL\n" + "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE," + " const %s *data, size_t *size)\n" + "{\n", + s->gen_name, s->gen_name); + + switch (s->type->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TNull: + case TBitString: + case TEnumerated: + case TOID: + case TSequence: + case TSequenceOf: + case TSet: + case TSetOf: + case TTag: + case TType: + case TChoice: + fprintf (codefile, + "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n" + "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" + "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n"); + + encode_type("data", s->type, "Top"); + + fprintf (codefile, "*size = ret;\n" + "return 0;\n"); + break; + default: + abort (); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_free.c b/third_party/heimdal/lib/asn1/gen_free.c new file mode 100644 index 0000000..ff80063 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_free.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static void +free_primitive (const char *typename, const char *name) +{ + fprintf (codefile, "der_free_%s(%s);\n", typename, name); +} + +static void +free_type (const char *name, const Type *t, int preserve) +{ + switch (t->type) { + case TType: +#if 0 + free_type (name, t->symbol->type, preserve); +#endif + fprintf (codefile, "free_%s(%s);\n", t->symbol->gen_name, name); + break; + case TInteger: + if (t->range == NULL && t->members == NULL) { + free_primitive ("heim_integer", name); + break; + } + HEIM_FALLTHROUGH; + case TBoolean: + case TEnumerated : + case TNull: + case TGeneralizedTime: + case TUTCTime: + /* + * This doesn't do much, but it leaves zeros where garbage might + * otherwise have been found. Gets us closer to having the equivalent + * of a memset()-to-zero data structure after calling the free + * functions. + */ + fprintf(codefile, "*%s = 0;\n", name); + break; + case TBitString: + if (HEIM_TAILQ_EMPTY(t->members)) + free_primitive("bit_string", name); + break; + case TOctetString: + free_primitive ("octet_string", name); + break; + case TChoice: + case TSet: + case TSequence: { + Member *m, *have_ellipsis = NULL; + + if (t->members == NULL) + break; + + if ((t->type == TSequence || t->type == TChoice) && preserve) + fprintf(codefile, "der_free_octet_string(&data->_save);\n"); + + if(t->type == TChoice) + fprintf(codefile, "switch((%s)->element) {\n", name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (m->ellipsis){ + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + if (asprintf (&s, "%s(%s)->%s%s", + m->optional ? "" : "&", name, + t->type == TChoice ? "u." : "", m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if(m->optional) + fprintf(codefile, "if(%s) {\n", s); + free_type (s, m->type, FALSE); + if(m->optional) + fprintf(codefile, + "free(%s);\n" + "%s = NULL;\n" + "}\n",s, s); + free (s); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + + if(t->type == TChoice) { + if (have_ellipsis) + fprintf(codefile, + "case %s:\n" + "der_free_octet_string(&(%s)->u.%s);\n" + "break;", + have_ellipsis->label, + name, have_ellipsis->gen_name); + fprintf(codefile, "}\n"); + } + break; + } + case TSetOf: + case TSequenceOf: { + char *n; + + fprintf (codefile, "if ((%s)->val)\nwhile((%s)->len){\n", name, name); + if (asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name) < 0 || n == NULL) + errx(1, "malloc"); + free_type(n, t->subtype, FALSE); + fprintf(codefile, + "(%s)->len--;\n" + "} else (%s)->len = 0;\n", + name, name); + fprintf(codefile, + "free((%s)->val);\n" + "(%s)->val = NULL;\n", name, name); + free(n); + break; + } + case TGeneralString: + free_primitive ("general_string", name); + break; + case TTeletexString: + free_primitive ("general_string", name); + break; + case TUTF8String: + free_primitive ("utf8string", name); + break; + case TPrintableString: + free_primitive ("printable_string", name); + break; + case TIA5String: + free_primitive ("ia5_string", name); + break; + case TBMPString: + free_primitive ("bmp_string", name); + break; + case TUniversalString: + free_primitive ("universal_string", name); + break; + case TVisibleString: + free_primitive ("visible_string", name); + break; + case TTag: + free_type (name, t->subtype, preserve); + break; + case TOID : + free_primitive ("oid", name); + break; + default : + abort (); + } +} + +void +generate_type_free (const Symbol *s) +{ + struct decoration deco; + ssize_t more_deco = -1; + int preserve = preserve_type(s->name) ? TRUE : FALSE; + + fprintf (codefile, "void ASN1CALL\n" + "free_%s(%s *data)\n" + "{\n", + s->gen_name, s->gen_name); + + free_type ("data", s->type, preserve); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.free_function_name == NULL) { + /* Decorated with field of external type but no free function */ + if (deco.ptr) + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ free function */ + if (deco.ptr) { + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "%s((data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "%s(&(data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "free_%s((data)->%s);\n", + deco.field_type, deco.field_name); + fprintf(codefile, "free((data)->%s);\n", deco.field_name); + fprintf(codefile, "(data)->%s = NULL;\n", deco.field_name); + fprintf(codefile, "}\n"); + } else { + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "free_%s(&(data)->%s);\n", + deco.field_type, deco.field_name); + } + free(deco.field_type); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_glue.c b/third_party/heimdal/lib/asn1/gen_glue.c new file mode 100644 index 0000000..424e5de --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_glue.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1997, 1999, 2000, 2003 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static FILE * +get_code_file(void) +{ + if (!one_code_file && template_flag && templatefile) + return templatefile; + return codefile; +} + +static void +generate_2int (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "uint64_t %s2int(%s);\n", + gen_name, gen_name); + + fprintf (get_code_file(), + "uint64_t %s2int(%s f)\n" + "{\n" + "uint64_t r = 0;\n", + gen_name, gen_name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + fprintf (get_code_file(), "if(f.%s) r |= (1ULL << %d);\n", + m->gen_name, (int)m->val); + } + fprintf (get_code_file(), "return r;\n" + "}\n\n"); +} + +static void +generate_int2 (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "%s int2%s(uint64_t);\n", + gen_name, gen_name); + + fprintf (get_code_file(), + "%s int2%s(uint64_t n)\n" + "{\n" + "\t%s flags;\n\n" + "\tmemset(&flags, 0, sizeof(flags));\n\n", + gen_name, gen_name, gen_name); + + if(t->members) { + HEIM_TAILQ_FOREACH(m, t->members, members) { + fprintf (get_code_file(), "\tflags.%s = (n >> %d) & 1;\n", + m->gen_name, (int)m->val); + } + } + fprintf (get_code_file(), "\treturn flags;\n" + "}\n\n"); +} + +/* + * This depends on the bit string being declared in increasing order + */ + +static void +generate_units (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "const struct units * asn1_%s_units(void);\n", + gen_name); + + fprintf (get_code_file(), + "static struct units %s_units[] = {\n", + gen_name); + + if(t->members) { + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + fprintf (get_code_file(), + "\t{\"%s\",\t1ULL << %d},\n", m->name, (int)m->val); + } + } + + fprintf (get_code_file(), + "\t{NULL,\t0}\n" + "};\n\n"); + + fprintf (get_code_file(), + "const struct units * asn1_%s_units(void){\n" + "return %s_units;\n" + "}\n\n", + gen_name, gen_name); + + +} + +void +generate_glue (const Type *t, const char *gen_name) +{ + switch(t->type) { + case TTag: + generate_glue(t->subtype, gen_name); + break; + case TBitString : { + Member *m; + + if (HEIM_TAILQ_EMPTY(t->members)) + break; + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > 63) { + warnx("Not generating 2int, int2, or units for %s due to " + "having a member valued more than 63", gen_name); + return; + } + } + generate_2int (t, gen_name); + generate_int2 (t, gen_name); + if (parse_units_flag) + generate_units (t, gen_name); + break; + } + default : + break; + } +} diff --git a/third_party/heimdal/lib/asn1/gen_length.c b/third_party/heimdal/lib/asn1/gen_length.c new file mode 100644 index 0000000..ab5c5f3 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_length.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static void +length_primitive (const char *typename, + const char *name, + const char *variable) +{ + fprintf (codefile, "%s += der_length_%s(%s);\n", variable, typename, name); +} + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + + +static int +length_type (const char *name, const Type *t, + const char *variable, const char *tmpstr) +{ + switch (t->type) { + case TType: +#if 0 + length_type (name, t->symbol->type); +#endif + fprintf (codefile, "%s += length_%s(%s);\n", + variable, t->symbol->gen_name, name); + break; + case TInteger: + if(t->members) { + fprintf(codefile, + "{\n" + "int enumint = *%s;\n", name); + length_primitive ("integer", "&enumint", variable); + fprintf(codefile, "}\n"); + } else if (t->range == NULL) { + length_primitive ("heim_integer", name, variable); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + length_primitive ("integer64", name, variable); + } else if (t->range->min < 0) { + length_primitive ("integer", name, variable); + } else if (t->range->max > UINT_MAX) { + length_primitive ("unsigned64", name, variable); + } else { + length_primitive ("unsigned", name, variable); + } + break; + case TBoolean: + fprintf (codefile, "%s += 1;\n", variable); + break; + case TEnumerated : + length_primitive ("enumerated", name, variable); + break; + case TOctetString: + length_primitive ("octet_string", name, variable); + break; + case TBitString: { + if (HEIM_TAILQ_EMPTY(t->members)) + length_primitive("bit_string", name, variable); + else { + if (!rfc1510_bitstring) { + Member *m; + int pos = HEIM_TAILQ_LAST(t->members, memhead)->val; + + fprintf(codefile, + "do {\n"); + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + while (m->val / 8 < pos / 8) { + pos -= 8; + } + fprintf (codefile, + "if((%s)->%s) { %s += %d; break; }\n", + name, m->gen_name, variable, (pos + 8) / 8); + } + fprintf(codefile, + "} while(0);\n"); + fprintf (codefile, "%s += 1;\n", variable); + } else { + fprintf (codefile, "%s += 5;\n", variable); + } + } + break; + } + case TSet: + case TSequence: + case TChoice: { + Member *m, *have_ellipsis = NULL; + + if (t->members == NULL) + break; + + if(t->type == TChoice) + fprintf (codefile, "switch((%s)->element) {\n", name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + + if (asprintf (&s, "%s(%s)->%s%s", + m->optional ? "" : "&", name, + t->type == TChoice ? "u." : "", m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if (m->optional) + fprintf (codefile, "if(%s)", s); + else if(m->defval) + gen_compare_defval(s + 1, m->defval); + fprintf (codefile, "{\n" + "size_t %s_oldret = %s;\n" + "%s = 0;\n", tmpstr, variable, variable); + length_type (s, m->type, "ret", m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + fprintf (codefile, "}\n"); + free (s); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + if(t->type == TChoice) { + if (have_ellipsis) + fprintf(codefile, + "case %s:\n" + "ret += (%s)->u.%s.length;\n" + "break;\n", + have_ellipsis->label, + name, + have_ellipsis->gen_name); + fprintf (codefile, "}\n"); /* switch */ + } + break; + } + case TSetOf: + case TSequenceOf: { + char *n = NULL; + char *sname = NULL; + + fprintf (codefile, + "{\n" + "size_t %s_oldret = %s;\n" + "unsigned int n_%s;\n" + "%s = 0;\n", + tmpstr, variable, tmpstr, variable); + + fprintf (codefile, "for(n_%s = (%s)->len; n_%s > 0; --n_%s){\n", + tmpstr, name, tmpstr, tmpstr); + fprintf (codefile, "size_t %s_for_oldret = %s;\n" + "%s = 0;\n", tmpstr, variable, variable); + if (asprintf (&n, "&(%s)->val[n_%s - 1]", name, tmpstr) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + length_type(n, t->subtype, variable, sname); + fprintf (codefile, "%s += %s_for_oldret;\n", + variable, tmpstr); + fprintf (codefile, "}\n"); + + fprintf (codefile, + "%s += %s_oldret;\n" + "}\n", variable, tmpstr); + free(n); + free(sname); + break; + } + case TGeneralizedTime: + length_primitive ("generalized_time", name, variable); + break; + case TGeneralString: + length_primitive ("general_string", name, variable); + break; + case TTeletexString: + length_primitive ("general_string", name, variable); + break; + case TUTCTime: + length_primitive ("utctime", name, variable); + break; + case TUTF8String: + length_primitive ("utf8string", name, variable); + break; + case TPrintableString: + length_primitive ("printable_string", name, variable); + break; + case TIA5String: + length_primitive ("ia5_string", name, variable); + break; + case TBMPString: + length_primitive ("bmp_string", name, variable); + break; + case TUniversalString: + length_primitive ("universal_string", name, variable); + break; + case TVisibleString: + length_primitive ("visible_string", name, variable); + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + break; + case TTag:{ + char *tname = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + if (asprintf(&tname, "%s_tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + length_type (name, t->subtype, variable, tname); + /* See the comments in encode_type() about IMPLICIT tags */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any")) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + replace_tag = is_tagged_type(t->subtype->symbol->type); + if (replace_tag) + /* + * We're replacing the tag of the underlying type. If that type is + * imported, then we don't know its tag, so we rely on the + * asn1_tag_tag_ enum value we generated for it, and we + * use the asn1_tag_length_ enum value to avoid having to + * call der_length_tag() at run-time. + */ + fprintf(codefile, "ret += %lu - asn1_tag_length_%s;\n", + (unsigned long)length_tag(t->tag.tagvalue), + t->subtype->symbol->gen_name); + else + fprintf(codefile, "ret += %lu + der_length_len (ret);\n", + (unsigned long)length_tag(t->tag.tagvalue)); + free(tname); + break; + } + case TOID: + length_primitive ("oid", name, variable); + break; + default : + abort (); + } + return 0; +} + +void +generate_type_length (const Symbol *s) +{ + fprintf (codefile, + "size_t ASN1CALL\n" + "length_%s(const %s *data)\n" + "{\n" + "size_t ret = 0;\n", + s->gen_name, s->gen_name); + + length_type ("data", s->type, "ret", "Top"); + fprintf (codefile, "return ret;\n}\n\n"); +} + diff --git a/third_party/heimdal/lib/asn1/gen_locl.h b/third_party/heimdal/lib/asn1/gen_locl.h new file mode 100644 index 0000000..f37f149 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_locl.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __GEN_LOCL_H__ +#define __GEN_LOCL_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hash.h" +#include "symbol.h" +#include "asn1-common.h" +#include "der.h" +#include "der-private.h" + +/* + * XXX We need to move all module state out of globals and into a struct that + * we pass around when parsing and compiling a module, and also that we keep on + * a linked list of parsed modules. + * + * This is needed to: + * + * - implement IMPORTS correctly, because we need to know the type of a symbol + * in order to emit an extern declaration of it + * - implement value parsing + * - implement an ASN.1 library that does value parsing + * + * Value parsing, in particular, would be fantastic. We could then have + * options in hxtool(1) to load arbitrary ASN.1 modules and then parse SAN + * values given in ASN.1 value syntax on the command-line or in files. Eat + * your heart out OpenSSL if we do this! + * + * As well we'll need a `-I' option to the compiler so it knows where to find + * modules to IMPORT FROM. + */ +typedef struct asn1_module { + /* Name of ASN.1 module file: */ + const char *orig_filename; + /* Name of file to always include for common type definitions: */ + const char *type_file_string; + /* Name of public header file for module: */ + const char *header; + /* Name of private header file for module: */ + const char *privheader; + /* Basename of module: */ + const char *headerbase; + /* Open stdio file handles for output: */ + FILE *jsonfile; + FILE *privheaderfile; + FILE *headerfile; + FILE *oidsfile; + FILE *codefile; + FILE *logfile; + FILE *templatefile; + /* Module contents: */ + struct sexport *exports; + struct import *imports; + Hashtab *htab; /* symbols */ + /* Template state: */ + struct templatehead *template; + struct tlisthead *tlistmaster; + /* CLI options and flags needed everywhere: */ + getarg_strings preserve; + getarg_strings seq; + const char *enum_prefix; + unsigned int one_code_file:1; + unsigned int support_ber:1; + unsigned int parse_units_flag:1; + unsigned int prefix_enum:1; /* Should be a getarg_strings of bitrsting types to do this for */ + unsigned int rfc1510_bitstring:1; /* Should be a getarg_strings of bitrsting types to do this for */ +} *asn1_module; + +void generate_type (const Symbol *); +void generate_type_header_forwards(const Symbol *); +void generate_constant (const Symbol *); +void generate_type_encode (const Symbol *); +void generate_type_decode (const Symbol *); +void generate_type_free (const Symbol *); +void generate_type_length (const Symbol *); +void generate_type_print_stub(const Symbol *); +void generate_type_copy (const Symbol *); +void generate_type_seq (const Symbol *); +void generate_glue (const Type *, const char*); + +const char *classname(Der_class); +const char *valuename(Der_class, int); + +void gen_compare_defval(const char *, struct value *); +void gen_assign_defval(const char *, struct value *); + +int objid_cmp(struct objid *, struct objid *); + +void init_generate (const char *, const char *); +const char *get_filename (void); +void close_generate(void); +void add_import(const char *); +void add_export(const char *); +int is_export(const char *); +int yyparse(void); +int is_primitive_type(const Type *); +int is_tagged_type(const Type *); + +int preserve_type(const char *); +int seq_type(const char *); + +struct decoration { + char *field_type; /* C type name */ + char *field_name; /* C struct field name */ + char *copy_function_name; /* copy constructor function name */ + char *free_function_name; /* destructor function name */ + char *header_name; /* header name */ + unsigned int decorated:1; + unsigned int first:1; /* optional */ + unsigned int opt:1; /* optional */ + unsigned int ext:1; /* external */ + unsigned int ptr:1; /* external, pointer */ + unsigned int void_star:1; /* external, void * */ + unsigned int struct_star:1; /* external, struct foo * */ +}; +int decorate_type(const char *, struct decoration *, ssize_t *); + +void generate_header_of_codefile(const char *); +void close_codefile(void); + +void get_open_type_defn_fields(const Type *, Member **, Member **, Field **, + Field **, int *); +void sort_object_set(IOSObjectSet *, Field *, IOSObject ***, size_t *); +int object_cmp(const void *, const void *); + +int is_template_compat (const Symbol *); +void generate_template(const Symbol *); +void generate_template_type_forward(const char *); +void generate_template_objectset_forwards(const Symbol *); +void gen_template_import(const Symbol *); + +struct objid **objid2list(struct objid *); + +extern FILE *jsonfile, *privheaderfile, *headerfile, *codefile, *logfile, *templatefile; +extern const char *fuzzer_string; +extern int support_ber; +extern int template_flag; +extern int rfc1510_bitstring; +extern int one_code_file; +extern int original_order; +extern int parse_units_flag; +extern char *type_file_string; + +extern int error_flag; + +#endif /* __GEN_LOCL_H__ */ diff --git a/third_party/heimdal/lib/asn1/gen_print.c b/third_party/heimdal/lib/asn1/gen_print.c new file mode 100644 index 0000000..4cca9e0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_print.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +void +generate_type_print_stub(const Symbol *s) +{ + fprintf(codefile, "char * ASN1CALL\n" + "print_%s(const %s *data, int flags)\n" + "{ errno = EINVAL; return 0; }\n\n", + s->gen_name, s->gen_name); +} diff --git a/third_party/heimdal/lib/asn1/gen_seq.c b/third_party/heimdal/lib/asn1/gen_seq.c new file mode 100644 index 0000000..9762813 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_seq.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static FILE * +get_code_file(void) +{ + if (!one_code_file && template_flag && templatefile) + return templatefile; + return codefile; +} + +void +generate_type_seq (const Symbol *s) +{ + char *subname; + Type *type; + + if (!seq_type(s->name)) + return; + type = s->type; + while(type->type == TTag) + type = type->subtype; + + if (type->type != TSequenceOf && type->type != TSetOf) { + fprintf(stderr, "%s not seq of %d\n", s->name, (int)type->type); + return; + } + + /* + * Require the subtype to be a type so we can name it and use + * copy_/free_ + */ + + if (type->subtype->type != TType) { + fprintf(stderr, "%s subtype is not a type, can't generate " + "sequence code for this case: %d\n", + s->name, (int)type->subtype->type); + exit(1); + } + + subname = type->subtype->symbol->gen_name; + + fprintf (headerfile, + "ASN1EXP int ASN1CALL add_%s (%s *, const %s *);\n" + "ASN1EXP int ASN1CALL remove_%s (%s *, unsigned int);\n", + s->gen_name, s->gen_name, subname, + s->gen_name, s->gen_name); + + fprintf (get_code_file(), "int ASN1CALL\n" + "add_%s(%s *data, const %s *element)\n" + "{\n", + s->gen_name, s->gen_name, subname); + + fprintf (get_code_file(), + "int ret;\n" + "void *ptr;\n" + "\n" + "ptr = realloc(data->val, \n" + "\t(data->len + 1) * sizeof(data->val[0]));\n" + "if (ptr == NULL) return ENOMEM;\n" + "data->val = ptr;\n\n" + "ret = copy_%s(element, &data->val[data->len]);\n" + "if (ret) return ret;\n" + "data->len++;\n" + "return 0;\n", + subname); + + fprintf (get_code_file(), "}\n\n"); + + fprintf (get_code_file(), "int ASN1CALL\n" + "remove_%s(%s *data, unsigned int element)\n" + "{\n", + s->gen_name, s->gen_name); + + fprintf (get_code_file(), + "void *ptr;\n" + "\n" + "if (data->len == 0 || element >= data->len)\n" + "\treturn ASN1_OVERRUN;\n" + "free_%s(&data->val[element]);\n" + "data->len--;\n" + /* don't move if its the last element */ + "if (element < data->len)\n" + "\tmemmove(&data->val[element], &data->val[element + 1], \n" + "\t\tsizeof(data->val[0]) * (data->len - element));\n" + /* resize but don't care about failures since it doesn't matter */ + "ptr = realloc(data->val, data->len * sizeof(data->val[0]));\n" + "if (ptr != NULL || data->len == 0) data->val = ptr;\n" + "return 0;\n", + subname); + + fprintf (get_code_file(), "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_template.c b/third_party/heimdal/lib/asn1/gen_template.c new file mode 100644 index 0000000..67d18ec --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_template.c @@ -0,0 +1,1675 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Currently we generate C source code defining constant arrays of structures + * containing a sort of a "byte-coded" template of an ASN.1 compiler to be + * interpreted at run-time. + */ + +#include "gen_locl.h" +#include +#include + +static const char *symbol_name(const char *, const Type *); +static void generate_template_type(const char *, const char **, const char *, const char *, const char *, + Type *, int, int, int); + +static const char * +ttype_symbol(const char *basename, const Type *t) +{ + return t->symbol->gen_name; +} + +static const char * +integer_symbol(const char *basename, const Type *t) +{ + if (t->members) + /* + * XXX enum foo -- compute the size either from inspecting the members + * and applying the ABI's rules for enum size, OR infer the field + * size from a template by using the offsetof field. The latter is + * hard to do though. + */ + return "int"; + else if (t->range == NULL) + return "heim_integer"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + return "int64_t"; + else if (t->range->min < 0) + return "int"; + else if (t->range->max > UINT_MAX) + return "uint64_t"; + else + return "unsigned"; +} + +static const char * +boolean_symbol(const char *basename, const Type *t) +{ + return "int"; +} + + +static const char * +octetstring_symbol(const char *basename, const Type *t) +{ + return "heim_octet_string"; +} + +static const char * +sequence_symbol(const char *basename, const Type *t) +{ + return basename; +} + +static const char * +time_symbol(const char *basename, const Type *t) +{ + return "time_t"; +} + +static const char * +tag_symbol(const char *basename, const Type *t) +{ + return symbol_name(basename, t->subtype); +} + +static const char * +generalstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +printablestring_symbol(const char *basename, const Type *t) +{ + return "heim_printable_string"; +} + +static const char * +ia5string_symbol(const char *basename, const Type *t) +{ + return "heim_ia5_string"; +} + +static const char * +teletexstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +visiblestring_symbol(const char *basename, const Type *t) +{ + return "heim_visible_string"; +} + +static const char * +utf8string_symbol(const char *basename, const Type *t) +{ + return "heim_utf8_string"; +} + +static const char * +bmpstring_symbol(const char *basename, const Type *t) +{ + return "heim_bmp_string"; +} + +static const char * +universalstring_symbol(const char *basename, const Type *t) +{ + return "heim_universal_string"; +} + +static const char * +oid_symbol(const char *basename, const Type *t) +{ + return "heim_oid"; +} + +static const char * +bitstring_symbol(const char *basename, const Type *t) +{ + if (t->members) + return basename; + return "heim_bit_string"; +} + + + +/* Keep this sorted by `type' so we can just index this by type */ +const struct { + enum typetype type; + const char *(*symbol_name)(const char *, const Type *); + int is_struct; +} types[] = { + { TBitString, bitstring_symbol, 0 }, + { TBoolean, boolean_symbol, 0 }, + { TChoice, sequence_symbol, 1 }, + { TEnumerated, integer_symbol, 0 }, + { TGeneralString, generalstring_symbol, 0 }, + { TTeletexString, teletexstring_symbol, 0 }, + { TGeneralizedTime, time_symbol, 0 }, + { TIA5String, ia5string_symbol, 0 }, + { TInteger, integer_symbol, 0 }, + { TNull, integer_symbol, 1 }, + { TOID, oid_symbol, 0 }, + { TOctetString, octetstring_symbol, 0 }, + { TPrintableString, printablestring_symbol, 0 }, + { TSequence, sequence_symbol, 1 }, + { TSequenceOf, tag_symbol, 1 }, + { TSet, sequence_symbol, 1 }, + { TSetOf, tag_symbol, 1 }, + { TTag, tag_symbol, 1 }, + { TType, ttype_symbol, 1 }, + { TUTCTime, time_symbol, 0 }, + { TUTF8String, utf8string_symbol, 0 }, + { TBMPString, bmpstring_symbol, 0 }, + { TUniversalString, universalstring_symbol, 0 }, + { TVisibleString, visiblestring_symbol, 0 }, +}; + +static FILE * +get_code_file(void) +{ + if (!one_code_file) + return templatefile; + return codefile; +} + + +static int +is_supported_type_p(const Type *t) +{ + return t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type; +} + +int +is_template_compat (const Symbol *s) +{ + return is_supported_type_p(s->type); +} + +static const char * +symbol_name(const char *basename, const Type *t) +{ + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) + return (types[t->type].symbol_name)(basename, t); + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return NULL; +} + + +static char * +partial_offset(const char *basetype, const char *name, int need_offset, int isstruct) +{ + char *str; + if (name == NULL || need_offset == 0) + return strdup("0"); + if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL) + errx(1, "malloc"); + return str; +} + +struct template { + char *line; + char *tt; + char *offset; + char *ptr; + HEIM_TAILQ_ENTRY(template) members; +}; + +HEIM_TAILQ_HEAD(templatehead, template); + +struct tlist { + char *name; + char *header; + struct templatehead template; + HEIM_TAILQ_ENTRY(tlist) tmembers; +}; + +HEIM_TAILQ_HEAD(tlisthead, tlist); + +static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static struct template * + add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static int tlist_cmp(const struct tlist *, const struct tlist *); + +static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_string(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + + +static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster); +static unsigned long numdups = 0; + +static struct tlist * +tlist_new(const char *name) +{ + struct tlist *tl = calloc(1, sizeof(*tl)); + tl->name = strdup(name); + HEIM_TAILQ_INIT(&tl->template); + return tl; +} + +static void +tlist_header(struct tlist *t, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL) + errx(1, "malloc"); + va_end(ap); +} + +static unsigned long +tlist_count(struct tlist *tl) +{ + unsigned int count = 0; + struct template *q; + + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + count++; + } + return count; +} + +static void +tlist_add(struct tlist *tl) +{ + HEIM_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers); +} + +static void +tlist_print(struct tlist *tl) +{ + struct template *q; + unsigned int i = 1; + FILE *f = get_code_file(); + + fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name); + fprintf(f, "/* 0 */ %s,\n", tl->header); + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + int last = (HEIM_TAILQ_LAST(&tl->template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); +} + +static struct tlist * +tlist_find_by_name(const char *name) +{ + struct tlist *ql; + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (strcmp(ql->name, name) == 0) + return ql; + } + return NULL; +} + +static int +tlist_cmp_name(const char *tname, const char *qname) +{ + struct tlist *tl = tlist_find_by_name(tname); + struct tlist *ql = tlist_find_by_name(qname); + if (tl == NULL) + return 1; + if (ql == NULL) + return -1; + return tlist_cmp(tl, ql); +} + +static int +tlist_cmp(const struct tlist *tl, const struct tlist *ql) +{ + int ret; + struct template *t, *q; + + if (tl == ql) + return 0; + ret = strcmp(tl->header, ql->header); + if (ret != 0) return ret; + + q = HEIM_TAILQ_FIRST(&ql->template); + HEIM_TAILQ_FOREACH(t, &tl->template, members) { + if (q == NULL) return 1; + + if (t->ptr == NULL || q->ptr == NULL) { + ret = strcmp(t->line, q->line); + if (ret != 0) return ret; + } else { + ret = strcmp(t->tt, q->tt); + if (ret != 0) return ret; + + ret = strcmp(t->offset, q->offset); + if (ret != 0) return ret; + + if ((ret = strcmp(t->ptr, q->ptr)) != 0 || + (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0) + return ret; + } + q = HEIM_TAILQ_NEXT(q, members); + } + if (q != NULL) return -1; + return 0; +} + + +static const char * +tlist_find_dup(const struct tlist *tl) +{ + struct tlist *ql; + + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (tlist_cmp(ql, tl) == 0) { + numdups++; + return ql->name; + } + } + return NULL; +} + + +/* + * Add an entry to a template. + */ + +static struct template * +add_line(struct templatehead *t, const char *fmt, ...) +{ + struct template *q = calloc(1, sizeof(*q)); + va_list ap; + va_start(ap, fmt); + if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL) + errx(1, "malloc"); + va_end(ap); + HEIM_TAILQ_INSERT_TAIL(t, q, members); + return q; +} + +/* + * Add an entry to a template, with the pointer field being a symbol name of a + * template (i.e., an array, which decays to a pointer as usual in C). + */ +static void +add_line_pointer(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + if (ptr[0] == '&') + q = add_line(t, "{ %s, %s, %s }", tt, offset, ptr); + else + q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +/* + * Add an entry to a template where the pointer field is a string literal. + */ +static void +add_line_string(struct templatehead *t, + const char *str, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(str); +} + +/* + * Add an entry to a template, with the pointer field being a reference to + * named object of a type other than a template or other array type. + */ +static void +add_line_pointer_reference(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, (const void *)&asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +static int +use_extern(const Symbol *s) +{ + if (s->type == NULL) + return 1; + return 0; +} + +static int +is_struct(const Type *t, int isstruct) +{ + if (t->type == TType) + return 0; + if (t->type == TSequence || t->type == TSet || t->type == TChoice) + return 1; + if (t->type == TTag) + return is_struct(t->subtype, isstruct); + + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) { + if (types[t->type].is_struct == 0) + return 0; + return isstruct; + } + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return isstruct; +} + +static const Type * +compact_tag(const Type *t) +{ + while (t->type == TTag) + t = t->subtype; + return t; +} + +static void +defval(struct templatehead *temp, Member *m) +{ + switch (m->defval->type) { + case booleanvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)(uintptr_t)%u }", + m->defval->u.booleanvalue); + break; + case nullvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)(uintptr_t)0 }"); + break; + case integervalue: { + const char *dv = "A1_DV_INTEGER"; + Type *t = m->type; + + for (;;) { + if (t->range) + break; + if (t->type == TInteger && t->members) + break; + if (t->type == TEnumerated) + break; + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + errx(1, "DEFAULT values for unconstrained INTEGER members not supported"); + } + + if (t->members) + dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */ + else if (t->range && t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + dv = "A1_DV_INTEGER64"; + else if (t->range && t->range->min < 0) + dv = "A1_DV_INTEGER32"; + else if (t->range && t->range->max > UINT_MAX) + dv = "A1_DV_INTEGER64"; + else + dv = "A1_DV_INTEGER32"; + add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)(uintptr_t)%llu }", + dv, (long long)m->defval->u.integervalue); + break; + } + case stringvalue: { + char *quoted; + + if (rk_strasvis("ed, m->defval->u.stringvalue, + VIS_CSTYLE | VIS_NL, "\"") < 0) + err(1, "Could not quote a string"); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)(uintptr_t)\"%s\" }", + quoted); + free(quoted); + break; + } + case objectidentifiervalue: { + struct objid *o; + size_t sz = sizeof("{ }"); + char *s, *p; + int len; + + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(0, 0, " %d", o->value)) < 0) + err(1, "Could not format integer"); + sz += len; + } + + if ((p = s = malloc(sz)) == NULL) + err(1, "Could not allocate string"); + + len = snprintf(p, sz, "{"); + sz -= len; + p += len; + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1) + err(1, "Could not format integer"); + sz -= len; + p += len; + } + if ((len = snprintf(p, sz, " }")) >= sz) + abort(); + sz -= len; + if (sz != 0) + abort(); + + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)(uintptr_t)\"%s\" }", s); + free(s); + break; + } + default: abort(); + } +} + +int +objid_cmp(struct objid *oida, struct objid *oidb) +{ + struct objid *p; + size_t ai, bi, alen, blen; + int avals[20]; + int bvals[20]; + int c; + + /* + * Our OID values are backwards here. Comparing them is hard. + */ + + for (p = oida, alen = 0; + p && alen < sizeof(avals)/sizeof(avals[0]); + p = p->next) + avals[alen++] = p->value; + for (p = oidb, blen = 0; + p && blen < sizeof(bvals)/sizeof(bvals[0]); + p = p->next) + bvals[blen++] = p->value; + if (alen >= sizeof(avals)/sizeof(avals[0]) || + blen >= sizeof(bvals)/sizeof(bvals[0])) + err(1, "OIDs with more components than %llu not supported", + (unsigned long long)sizeof(avals)/sizeof(avals[0])); + + for (ai = 0, bi = 0; ai < alen && bi < blen;) + if ((c = avals[(alen-1)-(ai++)] - bvals[(blen-1)-(bi++)])) + return c; + + if (ai == alen && bi == blen) + return 0; + if (ai == alen) + return 1; + return -1; +} + +int +object_cmp(const void *va, const void *vb) +{ + const IOSObject *oa = *(const IOSObject * const *)va; + const IOSObject *ob = *(const IOSObject * const *)vb; + + switch (oa->typeidf->value->type) { + case booleanvalue: + return oa->typeidf->value->u.booleanvalue - + ob->typeidf->value->u.booleanvalue; + case nullvalue: + return 0; + case integervalue: + return oa->typeidf->value->u.integervalue - + ob->typeidf->value->u.integervalue; + case stringvalue: + return strcmp(oa->typeidf->value->u.stringvalue, + ob->typeidf->value->u.stringvalue); + case objectidentifiervalue: { + return objid_cmp(oa->typeidf->value->u.objectidentifiervalue, + ob->typeidf->value->u.objectidentifiervalue); + } + default: + abort(); + return -1; + } +} + +void +sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ + Field *typeidfield, /* Field to sort by */ + IOSObject ***objectsp, /* Output: array of objects */ + size_t *nobjsp) /* Output: count of objects */ +{ + IOSObject **objects; + IOSObject *o; + size_t i, nobjs = 0; + + *objectsp = NULL; + + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (!typeidobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing type ID field)", + o->symbol ? o->symbol->name : ""); + continue; + } + o->typeidf = typeidobjf; + nobjs++; + } + *nobjsp = nobjs; + + if (nobjs == 0) + return; + + if ((objects = calloc(nobjs, sizeof(*objects))) == NULL) + err(1, "Out of memory"); + *objectsp = objects; + + i = 0; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (typeidobjf) + objects[i++] = o; + } + qsort(objects, nobjs, sizeof(*objects), object_cmp); +} + +static void +template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) +{ + IOSObject **objects = NULL; + IOSObject *o; + struct tlist *tl; + size_t nobjs, i; + + if (os->symbol->emitted_template) + return; + + sort_object_set(os, typeidfield, &objects, &nobjs); + + tl = tlist_new(os->symbol->name); + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name); + for (i = 0; i < nobjs; i++) { + ObjectField *typeidobjf = NULL, *opentypeobjf = NULL; + ObjectField *of; + char *s = NULL; + + o = objects[i]; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + else if (strcmp(of->name, opentypefield->name) == 0) + opentypeobjf = of; + } + if (!typeidobjf) + continue; /* We've warned about this one already when sorting */ + if (!opentypeobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing open type field)", + o->symbol ? o->symbol->name : ""); + continue; + } + + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name); + /* + * Some of this logic could stand to move into sanity checks of object + * definitions in asn1parse.y. + */ + switch (typeidobjf->value->type) { + case integervalue: + add_line(&tl->template, + "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)(uintptr_t)%lld }", + (long long)typeidobjf->value->u.integervalue); + break; + case objectidentifiervalue: + if (asprintf(&s, "oid_%s", + typeidobjf->value->s->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, s, "0", "A1_OP_OPENTYPE_ID"); + free(s); + s = NULL; + break; + default: + errx(1, "Only integer and OID types supported " + "for open type type-ID fields"); + } + + if (asprintf(&s, "sizeof(%s)", + opentypeobjf->type->symbol->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, + opentypeobjf->type->symbol->gen_name, s, + "A1_OP_OPENTYPE"); + free(s); + } + free(objects); + + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nobjs); + tlist_print(tl); + tlist_add(tl); + os->symbol->emitted_template = 1; +} + +static void +template_open_type(struct templatehead *temp, + const char *basetype, + const Type *t, + size_t typeididx, + size_t opentypeidx, + Field *typeidfield, + Field *opentypefield, + Member *m, + int is_array_of_open_type) +{ + char *s = NULL; + + if (typeididx >= 1<<10 || opentypeidx >= 1<<10) + errx(1, "SET/SEQUENCE with too many members (%s)", basetype); + + if (asprintf(&s, "offsetof(%s, _ioschoice_%s)", + basetype, m->gen_name) == -1 || !s) + err(1, "Out of memory"); + + template_object_set(t->actual_parameter, typeidfield, opentypefield); + add_line_pointer(temp, t->actual_parameter->symbol->gen_name, s, + /* + * We always sort object sets for now as we can't import + * values yet, so they must all be known. + */ + "A1_OP_OPENTYPE_OBJSET | A1_OS_IS_SORTED |%s | (%llu << 10) | %llu", + is_array_of_open_type ? "A1_OS_OT_IS_ARRAY" : "0", + (unsigned long long)opentypeidx, + (unsigned long long)typeididx); + free(s); +} + +static void +template_names(struct templatehead *temp, const char *basetype, const Type *t) +{ + Member *m; + + add_line_string(temp, basetype, "0", "A1_OP_NAME"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line_string(temp, m->name, "0", "A1_OP_NAME"); + } +} + +static void +template_members(struct templatehead *temp, + const char *basetype, + const char *name, + const Type *t, + int optional, + int defaulted, + int implicit, + int isstruct, + int need_offset) +{ + char *poffset = NULL; + + if (optional && t->type != TTag && t->type != TType) + errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name); + + poffset = partial_offset(basetype, name, need_offset, isstruct); + + switch (t->type) { + case TType: + if (use_extern(t->symbol)) { + add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : "", + poffset, t->symbol->gen_name); + } else { + add_line_pointer(temp, t->symbol->gen_name, poffset, + "A1_OP_TYPE %s%s%s", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : ""); + + } + break; + case TEnumerated: + case TInteger: { + char *varname = NULL; + char *itype = NULL; + + if (t->members) + itype = "IMEMBER"; + else if (t->range == NULL) + itype = "HEIM_INTEGER"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + itype = "INTEGER64"; + else if (t->range->min < 0) + itype = "INTEGER"; + else if (t->range->max > UINT_MAX) + itype = "UNSIGNED64"; + else + itype = "UNSIGNED"; + + /* + * If `t->members' then we should generate a template for those + * members. + * + * We don't know the name of this field, and the type may not have a + * name. If it has no name, we should generate a name for it, and if + * it does have a name, use it, to name a template for its members. + * + * Then we could use that in _asn1_print() to pretty-print values of + * enumerations. + */ + if (t->members && t->symbol) { + struct tlist *tl; + Member *m; + size_t nmemb = 0; + + if (asprintf(&varname, "%s_enum_names", t->symbol->gen_name) == -1 || + varname == NULL) + err(1, "Out of memory"); + + tl = tlist_new(varname); + /* + * XXX We're going to assume that t->members is sorted in + * numerically ascending order in the module source. We should + * really sort it here. + */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle %s type %s with named bit %s " + "larger than 63", + t->type == TEnumerated ? "ENUMERATED" : "INTEGER", + name, m->gen_name); + add_line(&tl->template, + "{ A1_OP_NAME, %d, \"%s\" }", (int)m->val, m->name); + nmemb++; + } + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nmemb); + /* XXX Accidentally O(N^2)? */ + if (!tlist_find_dup(tl)) { + tlist_print(tl); + tlist_add(tl); + } + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, asn1_%s }", itype, poffset, varname); + } else { + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset); + } + break; + } + case TGeneralString: + add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset); + break; + case TTeletexString: + add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset); + break; + case TPrintableString: + add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset); + break; + case TOctetString: + add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset); + break; + case TIA5String: + add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset); + break; + case TBMPString: + add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset); + break; + case TUniversalString: + add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset); + break; + case TVisibleString: + add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset); + break; + case TUTF8String: + add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset); + break; + case TGeneralizedTime: + add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset); + break; + case TUTCTime: + add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset); + break; + case TBoolean: + add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset); + break; + case TOID: + add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset); + break; + case TNull: + break; + case TBitString: { + struct templatehead template; + struct template *q; + Member *m; + size_t count = 0, i; + char *bname = NULL; + FILE *f = get_code_file(); + static unsigned long bmember_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (HEIM_TAILQ_EMPTY(t->members)) { + add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset); + break; + } + + if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL) + errx(1, "malloc"); + output_name(bname); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle BIT STRING type %s with named bit %s " + "larger than 63", name, m->gen_name); + add_line(&template, "{ 0, %d, \"%s\" }", (int)m->val, m->gen_name); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname); + fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)(uintptr_t)%lu) },\n", + rfc1510_bitstring ? "|A1_HBF_RFC1510" : "", + basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname); + + free(bname); + + break; + } + case TSet: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tset: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TSequence: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TTag: { + char *tname = NULL, *elname = NULL; + const char *sename, *dupname; + int subtype_is_struct = is_struct(t->subtype, isstruct); + static unsigned long tag_counter = 0; + int tagimplicit = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + if (t->tag.tagenv == TE_IMPLICIT) { + Type *t2 = t->subtype; + + while (t2->type == TType && (t2->subtype || t2->symbol->type)) + t2 = t2->subtype ? t2->subtype : t2->symbol->type; + if (t2->type != TChoice) + tagimplicit = 1; + } + + fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp"); + + if (subtype_is_struct) + sename = basetype; + else + sename = symbol_name(basetype, t->subtype); + + if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + output_name(tname); + + if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, name, + t->subtype, 0, subtype_is_struct, 0); + + add_line_pointer(temp, dupname, poffset, + "A1_TAG_T(%s,%s,%s)%s%s%s", + classname(t->tag.tagclass), + prim ? "PRIM" : "CONS", + valuename(t->tag.tagclass, t->tag.tagvalue), + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + tagimplicit ? "|A1_FLAG_IMPLICIT" : ""); + + free(tname); + free(elname); + + break; + } + case TSetOf: + case TSequenceOf: { + const char *type = NULL, *tname, *dupname; + char *sename = NULL, *elname = NULL; + int subtype_is_struct = is_struct(t->subtype, 0); + static unsigned long seof_counter = 0; + + if (name && subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_%s_val", basetype, name) < 0) + errx(1, "malloc"); + } else if (subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0) + errx(1, "malloc"); + } else { + if (name) + tname = name; + else + tname = "seofTstruct"; + sename = strdup(symbol_name(basetype, t->subtype)); + } + if (sename == NULL) + errx(1, "malloc"); + + if (t->type == TSetOf) type = "A1_OP_SETOF"; + else if (t->type == TSequenceOf) type = "A1_OP_SEQOF"; + else abort(); + + if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype, + 0, subtype_is_struct, need_offset); + + add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname); + free(sename); + break; + } + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + struct templatehead template; + struct template *q; + size_t count = 0, i; + char *tname = NULL; + FILE *f = get_code_file(); + Member *m; + int ellipsis = 0; + char *e; + static unsigned long choice_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (asprintf(&tname, "asn1_choice_%s_%s%lu", + basetype, name ? name : "", choice_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + const char *dupname; + char *elname = NULL; + char *newbasename = NULL; + int subtype_is_struct; + + if (m->ellipsis) { + ellipsis = 1; + continue; + } + + subtype_is_struct = is_struct(m->type, 0); + + if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL) + errx(1, "malloc"); + + if (subtype_is_struct) { + if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + + if (newbasename == NULL) + errx(1, "malloc"); + + + generate_template_type(elname, &dupname, NULL, + symbol_name(newbasename, m->type), + NULL, m->type, 0, subtype_is_struct, 1); + + add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }", + m->label, isstruct ? "struct " : "", + basetype, m->gen_name, + dupname); + + free(elname); + free(newbasename); + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line(&template, "{ 0, 0, \"%s\" }", m->name); + } + + e = NULL; + if (ellipsis) { + if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL) + errx(1, "malloc"); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template %s[] = {\n", tname); + fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)(uintptr_t)%lu) },\n", + e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + free(e); + free(tname); + break; + } + default: + abort (); + } + if (poffset) + free(poffset); +} + +static void +gen_extern_stubs(FILE *f, const char *name) +{ + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s = {\n" + "\t(asn1_type_encode)encode_%s,\n" + "\t(asn1_type_decode)decode_%s,\n" + "\t(asn1_type_length)length_%s,\n" + "\t(asn1_type_copy)copy_%s,\n" + "\t(asn1_type_release)free_%s,\n" + "\t(asn1_type_print)print_%s,\n" + "\tsizeof(%s)\n" + "};\n", + name, name, name, name, + name, name, name, name); +} + +void +gen_template_import(const Symbol *s) +{ + FILE *f = get_code_file(); + + if (template_flag == 0) + return; + + gen_extern_stubs(f, s->gen_name); +} + +void +generate_template_type_forward(const char *name) +{ + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", name); +} + +void +generate_template_objectset_forwards(const Symbol *s) +{ + if (!template_flag) + return; + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", + s->gen_name); +} + +static void +generate_template_type(const char *varname, + const char **dupname, + const char *symname, + const char *basetype, + const char *name, + Type *type, + int optional, + int isstruct, + int need_offset) +{ + struct tlist *tl; + const char *d; + char *szt = NULL; + int have_ellipsis = 0; + int implicit = 0; + int n; + + tl = tlist_new(varname); + + if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) { + Type *t = type->subtype ? type->subtype : type->symbol->type; + + while (t->type == TType && (t->subtype || t->symbol->type)) + t = t->subtype ? t->subtype : t->symbol->type; + if (t->type != TChoice) + implicit = (type->tag.tagenv == TE_IMPLICIT); + } + + template_members(&tl->template, basetype, name, type, optional, 0, + implicit, isstruct, need_offset); + + /* if its a sequence or set type, check if there is a ellipsis */ + if (type->type == TSequence || type->type == TSet) { + Member *m; + HEIM_TAILQ_FOREACH(m, type->members, members) { + if (m->ellipsis) + have_ellipsis = 1; + } + } + + if (isstruct) + if (name) + n = asprintf(&szt, "struct %s_%s", basetype, name); + else + n = asprintf(&szt, "struct %s", basetype); + else + n = asprintf(&szt, "%s", basetype); + if (n < 0 || szt == NULL) + errx(1, "malloc"); + + if (HEIM_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull) + errx(1, "Tag %s...%s with no content ?", basetype, name ? name : ""); + + fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name); + + tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)(uintptr_t)%lu) }", + (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "", + have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl)); + + free(szt); + + /* XXX Accidentally O(N^2)? */ + d = tlist_find_dup(tl); + if (d) { +#if 0 + if (strcmp(d, tl->name) == 0) + errx(1, "found dup of ourself: %s", d); +#endif + *dupname = d; + } else { + *dupname = tl->name; + tlist_print(tl); + tlist_add(tl); + } +} + + +void +generate_template(const Symbol *s) +{ + FILE *f = get_code_file(); + const char *dupname; + struct decoration deco; + ssize_t more_deco = -1; + + if (use_extern(s)) { + gen_extern_stubs(f, s->gen_name); + return; + } + + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (!deco.ext) + continue; + if (deco.void_star && deco.header_name) + fprintf(f, "#include %s\n", deco.header_name); + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s_%s = {\n" + "\t(asn1_type_encode)0,\n" + "\t(asn1_type_decode)0,\n" + "\t(asn1_type_length)0,\n" + "\t(asn1_type_copy)%s,\n" + "\t(asn1_type_release)%s,\n" + "\t(asn1_type_print)0,\n" + "\tsizeof(%s)\n" + "};\n", s->gen_name, deco.field_name, + deco.copy_function_name && deco.copy_function_name[0] ? + deco.copy_function_name : "0", + deco.free_function_name && deco.free_function_name[0] ? + deco.free_function_name : "0", + deco.void_star ? "void *" : deco.field_type); + free(deco.field_type); + } + + generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n" + "{\n" + " memset(data, 0, sizeof(*data));\n" + " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname, + support_ber ? "A1_PF_ALLOW_BER" : "0"); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n" + "{\n" + " return _asn1_encode%s(asn1_%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + fprintf(f, + "\n" + "size_t ASN1CALL\n" + "length_%s(const %s *data)\n" + "{\n" + " return _asn1_length%s(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + + fprintf(f, + "\n" + "void ASN1CALL\n" + "free_%s(%s *data)\n" + "{\n" + " _asn1_free_top(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + " return _asn1_copy_top(asn1_%s, from, to);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "char * ASN1CALL\n" + "print_%s(const %s *data, int flags)\n" + "{\n" + " return _asn1_print_top(asn1_%s, flags, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); +} diff --git a/third_party/heimdal/lib/asn1/hash.c b/third_party/heimdal/lib/asn1/hash.c new file mode 100644 index 0000000..73b6cf9 --- /dev/null +++ b/third_party/heimdal/lib/asn1/hash.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Hash table functions + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static Hashentry *_search(Hashtab * htab, /* The hash table */ + void *ptr); /* And key */ + +Hashtab * +hashtabnew(int sz, + int (*cmp) (void *, void *), + unsigned (*hash) (void *)) +{ + Hashtab *htab; + int i; + + assert(sz > 0); + + htab = (Hashtab *) malloc(sizeof(Hashtab) + (sz - 1) * sizeof(Hashentry *)); + if (htab == NULL) + return NULL; + + for (i = 0; i < sz; ++i) + htab->tab[i] = NULL; + + htab->cmp = cmp; + htab->hash = hash; + htab->sz = sz; + return htab; +} + +/* Intern search function */ + +static Hashentry * +_search(Hashtab * htab, void *ptr) +{ + Hashentry *hptr; + + assert(htab && ptr); + + for (hptr = htab->tab[(*htab->hash) (ptr) % htab->sz]; + hptr; + hptr = hptr->next) + if ((*htab->cmp) (ptr, hptr->ptr) == 0) + break; + return hptr; +} + +/* Search for element in hash table */ + +void * +hashtabsearch(Hashtab * htab, void *ptr) +{ + Hashentry *tmp; + + tmp = _search(htab, ptr); + return tmp ? tmp->ptr : tmp; +} + +/* add element to hash table */ +/* if already there, set new value */ +/* !NULL if succesful */ + +void * +hashtabadd(Hashtab * htab, void *ptr) +{ + Hashentry *h = _search(htab, ptr); + Hashentry **tabptr; + + assert(htab && ptr); + + if (h) + free((void *) h->ptr); + else { + h = (Hashentry *) malloc(sizeof(Hashentry)); + if (h == NULL) { + return NULL; + } + tabptr = &htab->tab[(*htab->hash) (ptr) % htab->sz]; + h->next = *tabptr; + *tabptr = h; + h->prev = tabptr; + if (h->next) + h->next->prev = &h->next; + } + h->ptr = ptr; + return h; +} + +/* delete element with key key. Iff freep, free Hashentry->ptr */ + +int +_hashtabdel(Hashtab * htab, void *ptr, int freep) +{ + Hashentry *h; + + assert(htab && ptr); + + h = _search(htab, ptr); + if (h) { + if (freep) + free(h->ptr); + if ((*(h->prev) = h->next)) + h->next->prev = h->prev; + free(h); + return 0; + } else + return -1; +} + +/* Do something for each element */ + +void +hashtabforeach(Hashtab * htab, int (*func) (void *ptr, void *arg), + void *arg) +{ + Hashentry **h, *g; + + assert(htab); + + for (h = htab->tab; h < &htab->tab[htab->sz]; ++h) + for (g = *h; g; g = g->next) + if ((*func) (g->ptr, arg)) + return; +} + +/* standard hash-functions for strings */ + +unsigned +hashadd(const char *s) +{ /* Standard hash function */ + unsigned i; + + assert(s); + + for (i = 0; *s; ++s) + i += *s; + return i; +} + +unsigned +hashcaseadd(const char *s) +{ /* Standard hash function */ + unsigned i; + + assert(s); + + for (i = 0; *s; ++s) + i += toupper((unsigned char)*s); + return i; +} + +#define TWELVE (sizeof(unsigned)) +#define SEVENTYFIVE (6*sizeof(unsigned)) +#define HIGH_BITS (~((unsigned)(~0) >> TWELVE)) + +unsigned +hashjpw(const char *ss) +{ /* another hash function */ + unsigned h = 0; + unsigned g; + const unsigned char *s = (const unsigned char *)ss; + + for (; *s; ++s) { + h = (h << TWELVE) + *s; + if ((g = h & HIGH_BITS)) + h = (h ^ (g >> SEVENTYFIVE)) & ~HIGH_BITS; + } + return h; +} diff --git a/third_party/heimdal/lib/asn1/hash.h b/third_party/heimdal/lib/asn1/hash.h new file mode 100644 index 0000000..f37bdbb --- /dev/null +++ b/third_party/heimdal/lib/asn1/hash.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * hash.h. Header file for hash table functions + */ + +/* $Id$ */ + +struct hashentry { /* Entry in bucket */ + struct hashentry **prev; + struct hashentry *next; + void *ptr; +}; + +typedef struct hashentry Hashentry; + +struct hashtab { /* Hash table */ + int (*cmp)(void *, void *); /* Compare function */ + unsigned (*hash)(void *); /* hash function */ + int sz; /* Size */ + Hashentry *tab[1]; /* The table */ +}; + +typedef struct hashtab Hashtab; + +/* prototypes */ + +Hashtab *hashtabnew(int sz, + int (*cmp)(void *, void *), + unsigned (*hash)(void *)); /* Make new hash table */ + +void *hashtabsearch(Hashtab *htab, /* The hash table */ + void *ptr); /* The key */ + + +void *hashtabadd(Hashtab *htab, /* The hash table */ + void *ptr); /* The element */ + +int _hashtabdel(Hashtab *htab, /* The table */ + void *ptr, /* Key */ + int freep); /* Free data part? */ + +void hashtabforeach(Hashtab *htab, + int (*func)(void *ptr, void *arg), + void *arg); + +unsigned hashadd(const char *s); /* Standard hash function */ +unsigned hashcaseadd(const char *s); /* Standard hash function */ +unsigned hashjpw(const char *s); /* another hash function */ + +/* macros */ + + /* Don't free space */ +#define hashtabdel(htab,key) _hashtabdel(htab,key,FALSE) + +#define hashtabfree(htab,key) _hashtabdel(htab,key,TRUE) /* Do! */ diff --git a/third_party/heimdal/lib/asn1/heim_asn1.h b/third_party/heimdal/lib/asn1/heim_asn1.h new file mode 100644 index 0000000..072ff15 --- /dev/null +++ b/third_party/heimdal/lib/asn1/heim_asn1.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __HEIM_ANY_H__ +#define __HEIM_ANY_H__ 1 + +int ASN1CALL encode_heim_any(unsigned char *, size_t, const heim_any *, size_t *); +int ASN1CALL decode_heim_any(const unsigned char *, size_t, heim_any *, size_t *); +void ASN1CALL free_heim_any(heim_any *); +char *ASN1CALL print_heim_any(const heim_any *, int); +size_t ASN1CALL length_heim_any(const heim_any *); +int ASN1CALL copy_heim_any(const heim_any *, heim_any *); + +int ASN1CALL encode_heim_any_set(unsigned char *, size_t, + const heim_any_set *, size_t *); +int ASN1CALL decode_heim_any_set(const unsigned char *, size_t, + heim_any_set *,size_t *); +void ASN1CALL free_heim_any_set(heim_any_set *); +char *ASN1CALL print_heim_any_set(const heim_any_set *, int); +size_t ASN1CALL length_heim_any_set(const heim_any_set *); +int ASN1CALL copy_heim_any_set(const heim_any_set *, heim_any_set *); +int ASN1CALL heim_any_cmp(const heim_any_set *, const heim_any_set *); + +int ASN1CALL encode_HEIM_ANY(unsigned char *, size_t, const heim_any *, size_t *); +int ASN1CALL decode_HEIM_ANY(const unsigned char *, size_t, heim_any *, size_t *); +void ASN1CALL free_HEIM_ANY(heim_any *); +char *ASN1CALL print_HEIM_ANY(const heim_any *, int); +size_t ASN1CALL length_HEIM_ANY(const heim_any *); +int ASN1CALL copy_HEIM_ANY(const heim_any *, heim_any *); + +int ASN1CALL encode_HEIM_ANY_SET(unsigned char *, size_t, + const heim_any_set *, size_t *); +int ASN1CALL decode_HEIM_ANY_SET(const unsigned char *, size_t, + heim_any_set *,size_t *); +void ASN1CALL free_HEIM_ANY_SET(heim_any_set *); +char *ASN1CALL print_HEIM_ANY_SET(const heim_any_set *, int); +size_t ASN1CALL length_HEIM_ANY_SET(const heim_any_set *); +int ASN1CALL copy_HEIM_ANY_SET(const heim_any_set *, heim_any_set *); +int ASN1CALL heim_any_cmp(const heim_any_set *, const heim_any_set *); + +#endif /* __HEIM_ANY_H__ */ diff --git a/third_party/heimdal/lib/asn1/krb5.asn1 b/third_party/heimdal/lib/asn1/krb5.asn1 new file mode 100644 index 0000000..bf279a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/krb5.asn1 @@ -0,0 +1,1066 @@ +-- $Id$ + +KERBEROS5 DEFINITIONS ::= +BEGIN +EXPORTS + AD-AND-OR, + AD-IF-RELEVANT, + AD-KDCIssued, + AD-LoginAlias, + AP-REP, + AP-REQ, + AS-REP, + AS-REQ, + AUTHDATA-TYPE, + Authenticator, + AuthorizationData, + AuthorizationDataElement, + CKSUMTYPE, + ChangePasswdDataMS, + Checksum, + CompositePrincipal, + ENCTYPE, + ETYPE-INFO, + ETYPE-INFO-ENTRY, + ETYPE-INFO2, + ETYPE-INFO2-ENTRY, + EncAPRepPart, + EncASRepPart, + EncKDCRepPart, + EncKrbCredPart, + EncKrbPrivPart, + EncTGSRepPart, + EncTicketPart, + EncryptedData, + EncryptionKey, + EtypeList, + HostAddress, + HostAddresses, + KDC-REQ-BODY, + KDCOptions, + KDC-REP, + KRB-CRED, + KRB-ERROR, + KRB-PRIV, + KRB-SAFE, + KRB-SAFE-BODY, + KerberosString, + KerberosTime, + KrbCredInfo, + LR-TYPE, + LastReq, + METHOD-DATA, + NAME-TYPE, + PA-ClientCanonicalized, + PA-ClientCanonicalizedNames, + PA-DATA, + PA-ENC-TS-ENC, + PA-KERB-KEY-LIST-REP, + PA-KERB-KEY-LIST-REQ, + PA-PAC-OPTIONS, + PA-PAC-REQUEST, + PA-S4U2Self, + PA-S4U-X509-USER, + PA-SERVER-REFERRAL-DATA, + PA-ServerReferralData, + PA-SvrReferralData, + PADATA-TYPE, + PA-FX-FAST-REQUEST, + PA-FX-FAST-REPLY, + Principal, + PrincipalName, + Principals, + Realm, + TGS-REP, + TGS-REQ, + Ticket, + TicketFlags, + TransitedEncoding, + TypedData, + KrbFastResponse, + KrbFastFinished, + KrbFastReq, + KrbFastArmor, + KrbFastArmoredReq, + KDCFastState, + KDCFastCookie, + KDC-PROXY-MESSAGE, + KERB-AD-RESTRICTION-ENTRY, + KERB-TIMES, + KERB-CRED, + KERB-TGS-REQ-IN, + KERB-TGS-REQ-OUT, + KERB-ARMOR-SERVICE-REPLY, + KERB-ERROR-DATA + ; + +NAME-TYPE ::= INTEGER { + KRB5_NT_UNKNOWN(0), -- Name type not known + KRB5_NT_PRINCIPAL(1), -- Just the name of the principal as in + KRB5_NT_SRV_INST(2), -- Service and other unique instance (krbtgt) + KRB5_NT_SRV_HST(3), -- Service with host name as instance + KRB5_NT_SRV_XHST(4), -- Service with host as remaining components + KRB5_NT_UID(5), -- Unique ID + KRB5_NT_X500_PRINCIPAL(6), -- PKINIT + KRB5_NT_SMTP_NAME(7), -- Name in form of SMTP email name + KRB5_NT_ENTERPRISE_PRINCIPAL(10), -- Windows 2000 UPN + KRB5_NT_WELLKNOWN(11), -- Wellknown + KRB5_NT_SRV_HST_DOMAIN(12), -- Domain based service with host name as instance (RFC5179) + KRB5_NT_ENT_PRINCIPAL_AND_ID(-130), -- Windows 2000 UPN and SID + KRB5_NT_MS_PRINCIPAL(-128), -- NT 4 style name + KRB5_NT_MS_PRINCIPAL_AND_ID(-129), -- NT style name and SID + KRB5_NT_NTLM(-1200), -- NTLM name, realm is domain + KRB5_NT_X509_GENERAL_NAME(-1201), -- x509 general name (base64 encoded) + KRB5_NT_GSS_HOSTBASED_SERVICE(-1202), -- not used; remove + KRB5_NT_CACHE_UUID(-1203), -- name is actually a uuid pointing to ccache, use client name in cache + KRB5_NT_SRV_HST_NEEDS_CANON (-195894762) -- Internal: indicates that name canonicalization is needed +} + +-- message types + +MESSAGE-TYPE ::= INTEGER { + krb-as-req(10), -- Request for initial authentication + krb-as-rep(11), -- Response to KRB_AS_REQ request + krb-tgs-req(12), -- Request for authentication based on TGT + krb-tgs-rep(13), -- Response to KRB_TGS_REQ request + krb-ap-req(14), -- application request to server + krb-ap-rep(15), -- Response to KRB_AP_REQ_MUTUAL + krb-safe(20), -- Safe (checksummed) application message + krb-priv(21), -- Private (encrypted) application message + krb-cred(22), -- Private (encrypted) message to forward credentials + krb-error(30) -- Error response +} + + +-- pa-data types + +PADATA-TYPE ::= INTEGER { + KRB5-PADATA-NONE(0), + KRB5-PADATA-TGS-REQ(1), + KRB5-PADATA-AP-REQ(1), + KRB5-PADATA-ENC-TIMESTAMP(2), + KRB5-PADATA-PW-SALT(3), + KRB5-PADATA-ENC-UNIX-TIME(5), + KRB5-PADATA-SANDIA-SECUREID(6), + KRB5-PADATA-SESAME(7), + KRB5-PADATA-OSF-DCE(8), + KRB5-PADATA-CYBERSAFE-SECUREID(9), + KRB5-PADATA-AFS3-SALT(10), + KRB5-PADATA-ETYPE-INFO(11), + KRB5-PADATA-SAM-CHALLENGE(12), -- (sam/otp) + KRB5-PADATA-SAM-RESPONSE(13), -- (sam/otp) + KRB5-PADATA-PK-AS-REQ-19(14), -- (PKINIT-19) + KRB5-PADATA-PK-AS-REP-19(15), -- (PKINIT-19) + KRB5-PADATA-PK-AS-REQ-WIN(15), -- (PKINIT - old number) + KRB5-PADATA-PK-AS-REQ(16), -- (PKINIT-25) + KRB5-PADATA-PK-AS-REP(17), -- (PKINIT-25) + KRB5-PADATA-PA-PK-OCSP-RESPONSE(18), + KRB5-PADATA-ETYPE-INFO2(19), + KRB5-PADATA-USE-SPECIFIED-KVNO(20), + KRB5-PADATA-SVR-REFERRAL-INFO(20), --- old ms referral number + KRB5-PADATA-SAM-REDIRECT(21), -- (sam/otp) + KRB5-PADATA-GET-FROM-TYPED-DATA(22), + KRB5-PADATA-SAM-ETYPE-INFO(23), + KRB5-PADATA-SERVER-REFERRAL(25), + KRB5-PADATA-ALT-PRINC(24), -- (crawdad@fnal.gov) + KRB5-PADATA-SAM-CHALLENGE2(30), -- (kenh@pobox.com) + KRB5-PADATA-SAM-RESPONSE2(31), -- (kenh@pobox.com) + KRB5-PA-EXTRA-TGT(41), -- Reserved extra TGT + KRB5-PADATA-FX-FAST-ARMOR(71), -- fast armor + KRB5-PADATA-TD-KRB-PRINCIPAL(102), -- PrincipalName + KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT + KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT + KRB5-PADATA-TD-APP-DEFINED-ERROR(106), -- application specific + KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER + KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER + KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com + KRB5-PADATA-FOR-USER(129), -- MS-KILE + KRB5-PADATA-FOR-X509-USER(130), -- MS-KILE + KRB5-PADATA-FOR-CHECK-DUPS(131), -- MS-KILE + KRB5-PADATA-AS-CHECKSUM(132), -- MS-KILE + KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to + -- tell KDC that is supports + -- the asCheckSum in the + -- PK-AS-REP + KRB5-PADATA-FX-COOKIE(133), -- krb-wg-preauth-framework + KRB5-PADATA-AUTHENTICATION-SET(134), -- krb-wg-preauth-framework + KRB5-PADATA-AUTH-SET-SELECTED(135), -- krb-wg-preauth-framework + KRB5-PADATA-FX-FAST(136), -- krb-wg-preauth-framework + KRB5-PADATA-FX-ERROR(137), -- krb-wg-preauth-framework + KRB5-PADATA-ENCRYPTED-CHALLENGE(138), -- krb-wg-preauth-framework + KRB5-PADATA-OTP-CHALLENGE(141), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-REQUEST(142), -- (gareth.richards@rsa.com) + KBB5-PADATA-OTP-CONFIRM(143), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-PIN-CHANGE(144), -- (gareth.richards@rsa.com) + KRB5-PADATA-EPAK-AS-REQ(145), + KRB5-PADATA-EPAK-AS-REP(146), + KRB5-PADATA-PKINIT-KX(147), -- krb-wg-anon + KRB5-PADATA-PKU2U-NAME(148), -- zhu-pku2u + KRB5-PADATA-REQ-ENC-PA-REP(149), -- + KRB5-PADATA-AS-FRESHNESS(150), -- RFC 8070 + KER5-PADATA-KERB-KEY-LIST-REQ(161), -- MS-KILE + KER5-PADATA-KERB-PAKEY-LIST-REP(162), -- MS-KILE + KRB5-PADATA-SUPPORTED-ETYPES(165), -- MS-KILE + KRB5-PADATA-PAC-OPTIONS(167), -- MS-KILE + KRB5-PADATA-GSS(655) -- krb-wg-gss-preauth + +} + +AUTHDATA-TYPE ::= INTEGER { + KRB5-AUTHDATA-IF-RELEVANT(1), + KRB5-AUTHDATA-INTENDED-FOR_SERVER(2), + KRB5-AUTHDATA-INTENDED-FOR-APPLICATION-CLASS(3), + KRB5-AUTHDATA-KDC-ISSUED(4), + KRB5-AUTHDATA-AND-OR(5), + KRB5-AUTHDATA-MANDATORY-TICKET-EXTENSIONS(6), + KRB5-AUTHDATA-IN-TICKET-EXTENSIONS(7), + KRB5-AUTHDATA-MANDATORY-FOR-KDC(8), + KRB5-AUTHDATA-INITIAL-VERIFIED-CAS(9), + KRB5-AUTHDATA-OSF-DCE(64), + KRB5-AUTHDATA-SESAME(65), + KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66), + KRB5-AUTHDATA-AUTHENTICATION-STRENGTH(70), + KRB5-AUTHDATA-FX-FAST-ARMOR(71), + KRB5-AUTHDATA-FX-FAST-USED(72), + KRB5-AUTHDATA-WIN2K-PAC(128), + KRB5-AUTHDATA-GSS-API-ETYPE-NEGOTIATION(129), -- Authenticator only + KRB5-AUTHDATA-SIGNTICKET-OLDER(-17), + KRB5-AUTHDATA-SIGNTICKET-OLD(142), + KRB5-AUTHDATA-SIGNTICKET(512), + KRB5-AUTHDATA-SYNTHETIC-PRINC-USED(513), -- principal was synthetised + KRB5-AUTHDATA-KERB-LOCAL(141), -- MS-KILE + KRB5-AUTHDATA-TOKEN-RESTRICTIONS(142), -- MS-KILE + KRB5-AUTHDATA-AP-OPTIONS(143), -- MS-KILE + KRB5-AUTHDATA-TARGET-PRINCIPAL(144), -- MS-KILE + -- N.B. these assignments have not been confirmed yet. + -- + -- DO NOT USE in production yet! + KRB5-AUTHDATA-ON-BEHALF-OF(580), -- UTF8String princ name + KRB5-AUTHDATA-BEARER-TOKEN-JWT(581), -- JWT token + KRB5-AUTHDATA-BEARER-TOKEN-SAML(582), -- SAML token + KRB5-AUTHDATA-BEARER-TOKEN-OIDC(583), -- OIDC token + KRB5-AUTHDATA-CSR-AUTHORIZED(584), -- Proxy has authorized client + -- to requested exts in CSR + KRB5-AUTHDATA-GSS-COMPOSITE-NAME(655) -- gss_export_name_composite +} + +-- checksumtypes + +CKSUMTYPE ::= INTEGER { + CKSUMTYPE_NONE(0), + CKSUMTYPE_CRC32(1), + CKSUMTYPE_RSA_MD4(2), + CKSUMTYPE_RSA_MD4_DES(3), + CKSUMTYPE_DES_MAC(4), + CKSUMTYPE_DES_MAC_K(5), + CKSUMTYPE_RSA_MD4_DES_K(6), + CKSUMTYPE_RSA_MD5(7), + CKSUMTYPE_RSA_MD5_DES(8), + CKSUMTYPE_RSA_MD5_DES3(9), + CKSUMTYPE_SHA1_OTHER(10), + CKSUMTYPE_HMAC_SHA1_DES3(12), + CKSUMTYPE_SHA1(14), + CKSUMTYPE_HMAC_SHA1_96_AES_128(15), + CKSUMTYPE_HMAC_SHA1_96_AES_256(16), + CKSUMTYPE_HMAC_SHA256_128_AES128(19), + CKSUMTYPE_HMAC_SHA384_192_AES256(20), + CKSUMTYPE_GSSAPI(0x8003), + CKSUMTYPE_HMAC_MD5(-138), -- unofficial microsoft number + CKSUMTYPE_HMAC_MD5_ENC(-1138), -- even more unofficial + CKSUMTYPE_SHA256(-21), + CKSUMTYPE_SHA384(-22), + CKSUMTYPE_SHA512(-23) +} + +--enctypes +ENCTYPE ::= INTEGER { + KRB5_ENCTYPE_NULL(0), + KRB5_ENCTYPE_DES_CBC_CRC(1), + KRB5_ENCTYPE_DES_CBC_MD4(2), + KRB5_ENCTYPE_DES_CBC_MD5(3), + KRB5_ENCTYPE_DES3_CBC_MD5(5), + KRB5_ENCTYPE_OLD_DES3_CBC_SHA1(7), + KRB5_ENCTYPE_SIGN_DSA_GENERATE(8), + KRB5_ENCTYPE_ENCRYPT_RSA_PRIV(9), + KRB5_ENCTYPE_ENCRYPT_RSA_PUB(10), + KRB5_ENCTYPE_DES3_CBC_SHA1(16), -- with key derivation + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96(17), + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96(18), + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128(19), + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192(20), + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5(23), + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56(24), + KRB5_ENCTYPE_ENCTYPE_PK_CROSS(48), +-- some "old" windows types + KRB5_ENCTYPE_ARCFOUR_MD4(-128), + KRB5_ENCTYPE_ARCFOUR_HMAC_OLD(-133), + KRB5_ENCTYPE_ARCFOUR_HMAC_OLD_EXP(-135), +-- these are for Heimdal internal use + KRB5_ENCTYPE_DES_CBC_NONE(-0x1000), + KRB5_ENCTYPE_DES3_CBC_NONE(-0x1001), + KRB5_ENCTYPE_DES_CFB64_NONE(-0x1002), + KRB5_ENCTYPE_DES_PCBC_NONE(-0x1003), + KRB5_ENCTYPE_DIGEST_MD5_NONE(-0x1004), -- private use, lukeh@padl.com + KRB5_ENCTYPE_CRAM_MD5_NONE(-0x1005) -- private use, lukeh@padl.com +} + + + + +-- this is sugar to make something ASN1 does not have: unsigned + +Krb5UInt32 ::= INTEGER (0..4294967295) +Krb5Int32 ::= INTEGER (-2147483648..2147483647) + +KerberosString ::= GeneralString + +Realm ::= GeneralString +PrincipalName ::= SEQUENCE { + name-type[0] NAME-TYPE, + name-string[1] SEQUENCE OF GeneralString +} + +HostAddress ::= SEQUENCE { + addr-type[0] Krb5Int32, + address[1] OCTET STRING +} + +-- This is from RFC1510. +-- +-- HostAddresses ::= SEQUENCE OF SEQUENCE { +-- addr-type[0] Krb5Int32, +-- address[1] OCTET STRING +-- } + +-- This seems much better. +HostAddresses ::= SEQUENCE OF HostAddress + + +KerberosTime ::= GeneralizedTime -- Specifying UTC time zone (Z) + +AuthorizationDataElement ::= SEQUENCE { + ad-type[0] Krb5Int32, + ad-data[1] OCTET STRING +} + +AuthorizationData ::= SEQUENCE OF AuthorizationDataElement + +APOptions ::= BIT STRING { + reserved(0), + use-session-key(1), + mutual-required(2) +} + +TicketFlags ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + may-postdate(5), + postdated(6), + invalid(7), + renewable(8), + initial(9), + pre-authent(10), + hw-authent(11), + transited-policy-checked(12), + ok-as-delegate(13), + enc-pa-rep(15), + anonymous(16) +} + +KDCOptions ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + allow-postdate(5), + postdated(6), + renewable(8), + cname-in-addl-tkt(14), -- ms extension + canonicalize(15), + request-anonymous(16), + disable-transited-check(26), + renewable-ok(27), + enc-tkt-in-skey(28), + renew(30), + validate(31) +} + +LR-TYPE ::= INTEGER { + LR_NONE(0), -- no information + LR_INITIAL_TGT(1), -- last initial TGT request + LR_INITIAL(2), -- last initial request + LR_ISSUE_USE_TGT(3), -- time of newest TGT used + LR_RENEWAL(4), -- time of last renewal + LR_REQUEST(5), -- time of last request (of any type) + LR_PW_EXPTIME(6), -- expiration time of password + LR_ACCT_EXPTIME(7) -- expiration time of account +} + +LastReq ::= SEQUENCE OF SEQUENCE { + lr-type[0] LR-TYPE, + lr-value[1] KerberosTime +} + + +EncryptedData ::= SEQUENCE { + etype[0] ENCTYPE, -- EncryptionType + kvno[1] Krb5Int32 OPTIONAL, + cipher[2] OCTET STRING -- ciphertext +} + +EncryptionKey ::= SEQUENCE { + keytype[0] Krb5Int32, + keyvalue[1] OCTET STRING +} + +-- encoded Transited field +TransitedEncoding ::= SEQUENCE { + tr-type[0] Krb5Int32, -- must be registered + contents[1] OCTET STRING +} + +Ticket ::= [APPLICATION 1] SEQUENCE { + tkt-vno[0] Krb5Int32, + realm[1] Realm, + sname[2] PrincipalName, + enc-part[3] EncryptedData +} +-- Encrypted part of ticket +EncTicketPart ::= [APPLICATION 3] SEQUENCE { + flags[0] TicketFlags, + key[1] EncryptionKey, + crealm[2] Realm, + cname[3] PrincipalName, + transited[4] TransitedEncoding, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + caddr[9] HostAddresses OPTIONAL, + authorization-data[10] AuthorizationData OPTIONAL +} + +Checksum ::= SEQUENCE { + cksumtype[0] CKSUMTYPE, + checksum[1] OCTET STRING +} + +-- For GSS name attributes [RFC6680] we'll decorate Principal (which is not an +-- RFC4120 type, but which we use a) in HDB, b) in the API as that which +-- krb5_principal points to) with PrincipalNameAttrs. +-- +-- Attributes have three possible sources in Heimdal Kerberos at this time: +-- +-- - the EncKDCRepPart (for the client's attributes on the client side) +-- - the EncTicketPart (for the client's attributes on the server side) +-- - the Authenticator's AuthorizationData (if any; server-side) +-- +-- In principle there can be more: +-- +-- - locally-set (asserted) attributes +-- - locally-looked-up attributes (e.g., in LDAP) +-- - locally-transformed attributes (e.g., local groups, filtered SIDs from a +-- PAC, etc.) +-- +-- We could also cache "cooked" attributes as reported by the RFC6680 API given +-- the sources we have. +-- +-- For now we'll only support authenticated attributes where those come from +-- the KDC, and attributes asserted in Authenticator authz-data. +PrincipalNameAttrSrc ::= CHOICE { + enc-kdc-rep-part [0] EncKDCRepPart, -- minus session key + enc-ticket-part [1] EncTicketPart -- minus session key +} +PrincipalNameAttrs ::= SEQUENCE { + -- True if this name was authenticated via an AP-REQ or a KDC-REP + authenticated [0] BOOLEAN, + -- These are compiled from the Ticket, KDC-REP, and/or Authenticator + source [1] PrincipalNameAttrSrc OPTIONAL, + authenticator-ad [2] AuthorizationData OPTIONAL, + -- For the server on the client side we should keep track of the + -- transit path taken to reach it (if absent -> unknown). + -- + -- We don't learn much more about the server from the KDC. + peer-realm [3] Realm OPTIONAL, + transited [4] TransitedEncoding OPTIONAL, + -- True if the PAC was verified + pac-verified [5] BOOLEAN, + -- True if any AD-KDC-ISSUEDs in the Ticket were validated + kdc-issued-verified [6] BOOLEAN, + -- TODO: Add requested attributes, for gss_set_name_attribute(), which + -- should cause corresponding authz-data elements to be added to + -- any TGS-REQ or to the AP-REQ's Authenticator as appropriate. + want-ad [7] AuthorizationData OPTIONAL +} +-- This is our type for exported composite name tokens for GSS [RFC6680]. +-- It's the same as Principal (below) as decorated with (see krb5.opt file and +-- asn1_compile usage), except it's not decorated, so the name attributes are +-- encoded/decoded. +CompositePrincipal ::= [APPLICATION 48] SEQUENCE { + name[0] PrincipalName, + realm[1] Realm, + nameattrs[2] PrincipalNameAttrs OPTIONAL +} + +-- This is not part of RFC1510/RFC4120. We use this internally as our +-- krb5_principal (which is a typedef of *Principal), and in HDB entries. +Principal ::= SEQUENCE { + name[0] PrincipalName, + realm[1] Realm + -- This will be decorated with an optional nameattrs field of + -- PrincipalNameAttrs type that doesn't get encoded. Same as + -- CompositePrincipal above, except that CompositePrincipal's + -- nameattrs field does get encoded, while Principal's does not: + -- + -- nameattrs[2] PrincipalNameAttrs OPTIONAL +} + +Principals ::= SEQUENCE OF Principal + +Authenticator ::= [APPLICATION 2] SEQUENCE { + authenticator-vno[0] Krb5Int32, + crealm[1] Realm, + cname[2] PrincipalName, + cksum[3] Checksum OPTIONAL, + cusec[4] Krb5Int32, + ctime[5] KerberosTime, + subkey[6] EncryptionKey OPTIONAL, + seq-number[7] Krb5UInt32 OPTIONAL, + authorization-data[8] AuthorizationData OPTIONAL +} + +PA-DATA ::= SEQUENCE { + -- might be encoded AP-REQ + padata-type[1] PADATA-TYPE, + padata-value[2] OCTET STRING +} + +ETYPE-INFO-ENTRY ::= SEQUENCE { + etype[0] ENCTYPE, + salt[1] OCTET STRING OPTIONAL, + salttype[2] Krb5Int32 OPTIONAL +} + +ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY + +ETYPE-INFO2-ENTRY ::= SEQUENCE { + etype[0] ENCTYPE, + salt[1] KerberosString OPTIONAL, + s2kparams[2] OCTET STRING OPTIONAL +} + +ETYPE-INFO2 ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY + +METHOD-DATA ::= SEQUENCE OF PA-DATA + +TypedData ::= SEQUENCE { + data-type[0] Krb5Int32, + data-value[1] OCTET STRING OPTIONAL +} + +TYPED-DATA ::= SEQUENCE SIZE (1..MAX) OF TypedData + +KDC-REQ-BODY ::= SEQUENCE { + kdc-options[0] KDCOptions, + cname[1] PrincipalName OPTIONAL, -- Used only in AS-REQ + realm[2] Realm, -- Server's realm + -- Also client's in AS-REQ + sname[3] PrincipalName OPTIONAL, + from[4] KerberosTime OPTIONAL, + till[5] KerberosTime OPTIONAL, + rtime[6] KerberosTime OPTIONAL, + nonce[7] Krb5Int32, + etype[8] SEQUENCE OF ENCTYPE, -- EncryptionType, + -- in preference order + addresses[9] HostAddresses OPTIONAL, + enc-authorization-data[10] EncryptedData OPTIONAL, + -- Encrypted AuthorizationData encoding + additional-tickets[11] SEQUENCE OF Ticket OPTIONAL +} + +KDC-REQ ::= SEQUENCE { + pvno[1] Krb5Int32, + msg-type[2] MESSAGE-TYPE, + padata[3] METHOD-DATA OPTIONAL, + req-body[4] KDC-REQ-BODY +} + +AS-REQ ::= [APPLICATION 10] KDC-REQ +TGS-REQ ::= [APPLICATION 12] KDC-REQ + +-- padata-type ::= PA-ENC-TIMESTAMP +-- padata-value ::= EncryptedData - PA-ENC-TS-ENC + +PA-ENC-TS-ENC ::= SEQUENCE { + patimestamp[0] KerberosTime, -- client's time + pausec[1] Krb5Int32 OPTIONAL +} + +-- draft-brezak-win2k-krb-authz-01 +PA-PAC-REQUEST ::= SEQUENCE { + include-pac[0] BOOLEAN -- Indicates whether a PAC + -- should be included or not +} + +-- MS-KILE + +KERB-ERROR-DATA ::= SEQUENCE { + data-type [1] KerbErrorDataType, + data-value [2] OCTET STRING OPTIONAL +} + +KerbErrorDataType ::= INTEGER { + kERB-AP-ERR-TYPE-SKEW-RECOVERY(2), + kERB-ERR-TYPE-EXTENDED(3) +} + +-- MS-KILE/MS-SFU +PAC-OPTIONS-FLAGS ::= BIT STRING { + claims(0), + branch-aware(1), + forward-to-full-dc(2), + resource-based-constrained-delegation(3) +} + +-- MS-KILE +PA-PAC-OPTIONS ::= SEQUENCE { + flags [0] PAC-OPTIONS-FLAGS +} + +-- MS-KILE +-- captures show that [UNIVERSAL 16] is required to parse it +KERB-AD-RESTRICTION-ENTRY ::= [UNIVERSAL 16] SEQUENCE { + restriction-type [0] Krb5Int32, + restriction [1] OCTET STRING -- LSAP_TOKEN_INFO_INTEGRITY structure +} + +-- MS-KILE Section 2.2.11 +PA-KERB-KEY-LIST-REQ ::= SEQUENCE OF ENCTYPE + +-- MS-KILE Section 2.2.12 + +PA-KERB-KEY-LIST-REP ::= SEQUENCE OF ENCTYPE -- EncryptionType, + +-- PacketCable provisioning server location, PKT-SP-SEC-I09-030728.pdf +PROV-SRV-LOCATION ::= GeneralString + +KDC-REP ::= SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + padata[2] METHOD-DATA OPTIONAL, + crealm[3] Realm, + cname[4] PrincipalName, + ticket[5] Ticket, + enc-part[6] EncryptedData +} + +AS-REP ::= [APPLICATION 11] KDC-REP +TGS-REP ::= [APPLICATION 13] KDC-REP + +EncKDCRepPart ::= SEQUENCE { + key[0] EncryptionKey, + last-req[1] LastReq, + nonce[2] Krb5Int32, + key-expiration[3] KerberosTime OPTIONAL, + flags[4] TicketFlags, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + srealm[9] Realm, + sname[10] PrincipalName, + caddr[11] HostAddresses OPTIONAL, + encrypted-pa-data[12] METHOD-DATA OPTIONAL +} + +EncASRepPart ::= [APPLICATION 25] EncKDCRepPart +EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart + +AP-REQ ::= [APPLICATION 14] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + ap-options[2] APOptions, + ticket[3] Ticket, + authenticator[4] EncryptedData +} + +AP-REP ::= [APPLICATION 15] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + enc-part[2] EncryptedData +} + +EncAPRepPart ::= [APPLICATION 27] SEQUENCE { + ctime[0] KerberosTime, + cusec[1] Krb5Int32, + subkey[2] EncryptionKey OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL +} + +KRB-SAFE-BODY ::= SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] Krb5Int32 OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, + r-address[5] HostAddress OPTIONAL +} + +KRB-SAFE ::= [APPLICATION 20] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + safe-body[2] KRB-SAFE-BODY, + cksum[3] Checksum +} + +KRB-PRIV ::= [APPLICATION 21] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + enc-part[3] EncryptedData +} +EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] Krb5Int32 OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, -- sender's addr + r-address[5] HostAddress OPTIONAL -- recip's addr +} + +KRB-CRED ::= [APPLICATION 22] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, -- KRB_CRED + tickets[2] SEQUENCE OF Ticket, + enc-part[3] EncryptedData +} + +KrbCredInfo ::= SEQUENCE { + key[0] EncryptionKey, + prealm[1] Realm OPTIONAL, + pname[2] PrincipalName OPTIONAL, + flags[3] TicketFlags OPTIONAL, + authtime[4] KerberosTime OPTIONAL, + starttime[5] KerberosTime OPTIONAL, + endtime[6] KerberosTime OPTIONAL, + renew-till[7] KerberosTime OPTIONAL, + srealm[8] Realm OPTIONAL, + sname[9] PrincipalName OPTIONAL, + caddr[10] HostAddresses OPTIONAL +} + +EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { + ticket-info[0] SEQUENCE OF KrbCredInfo, + nonce[1] Krb5Int32 OPTIONAL, + timestamp[2] KerberosTime OPTIONAL, + usec[3] Krb5Int32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, + r-address[5] HostAddress OPTIONAL +} + +KRB-ERROR ::= [APPLICATION 30] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + ctime[2] KerberosTime OPTIONAL, + cusec[3] Krb5Int32 OPTIONAL, + stime[4] KerberosTime, + susec[5] Krb5Int32, + error-code[6] Krb5Int32, + crealm[7] Realm OPTIONAL, + cname[8] PrincipalName OPTIONAL, + realm[9] Realm, -- Correct realm + sname[10] PrincipalName, -- Correct name + e-text[11] GeneralString OPTIONAL, + e-data[12] OCTET STRING OPTIONAL +} + +ChangePasswdDataMS ::= SEQUENCE { + newpasswd[0] OCTET STRING, + targname[1] PrincipalName OPTIONAL, + targrealm[2] Realm OPTIONAL +} + +EtypeList ::= SEQUENCE OF ENCTYPE + -- the client's proposed enctype list in + -- decreasing preference order, favorite choice first + +krb5-pvno Krb5Int32 ::= 5 -- current Kerberos protocol version number + +-- transited encodings + +domain-X500-Compress Krb5Int32 ::= 1 + +-- authorization data primitives + +AD-IF-RELEVANT ::= AuthorizationData + +AD-KDCIssued ::= SEQUENCE { + ad-checksum[0] Checksum, + i-realm[1] Realm OPTIONAL, + i-sname[2] PrincipalName OPTIONAL, + elements[3] AuthorizationData +} + +AD-AND-OR ::= SEQUENCE { + condition-count[0] Krb5Int32, + elements[1] AuthorizationData +} + +AD-MANDATORY-FOR-KDC ::= AuthorizationData + +-- PA-SAM-RESPONSE-2/PA-SAM-RESPONSE-2 + +PA-SAM-TYPE ::= INTEGER { + PA_SAM_TYPE_ENIGMA(1), -- Enigma Logic + PA_SAM_TYPE_DIGI_PATH(2), -- Digital Pathways + PA_SAM_TYPE_SKEY_K0(3), -- S/key where KDC has key 0 + PA_SAM_TYPE_SKEY(4), -- Traditional S/Key + PA_SAM_TYPE_SECURID(5), -- Security Dynamics + PA_SAM_TYPE_CRYPTOCARD(6) -- CRYPTOCard +} + +PA-SAM-REDIRECT ::= HostAddresses + +SAMFlags ::= BIT STRING { + use-sad-as-key(0), + send-encrypted-sad(1), + must-pk-encrypt-sad(2) +} + +PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE { + sam-type[0] Krb5Int32, + sam-flags[1] SAMFlags, + sam-type-name[2] GeneralString OPTIONAL, + sam-track-id[3] GeneralString OPTIONAL, + sam-challenge-label[4] GeneralString OPTIONAL, + sam-challenge[5] GeneralString OPTIONAL, + sam-response-prompt[6] GeneralString OPTIONAL, + sam-pk-for-sad[7] EncryptionKey OPTIONAL, + sam-nonce[8] Krb5Int32, + sam-etype[9] Krb5Int32, + ... +} + +PA-SAM-CHALLENGE-2 ::= SEQUENCE { + sam-body[0] PA-SAM-CHALLENGE-2-BODY, + sam-cksum[1] SEQUENCE OF Checksum, -- (1..MAX) + ... +} + +PA-SAM-RESPONSE-2 ::= SEQUENCE { + sam-type[0] Krb5Int32, + sam-flags[1] SAMFlags, + sam-track-id[2] GeneralString OPTIONAL, + sam-enc-nonce-or-sad[3] EncryptedData, -- PA-ENC-SAM-RESPONSE-ENC + sam-nonce[4] Krb5Int32, + ... +} + +PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE { + sam-nonce[0] Krb5Int32, + sam-sad[1] GeneralString OPTIONAL, + ... +} + +PA-S4U2Self ::= SEQUENCE { + name[0] PrincipalName, + realm[1] Realm, + cksum[2] Checksum, + auth[3] GeneralString +} + +PA-S4U-X509-USER::= SEQUENCE { + user-id[0] S4UUserID, + checksum[1] Checksum +} + +S4UUserID ::= SEQUENCE { + nonce [0] Krb5UInt32, -- the nonce in KDC-REQ-BODY + cname [1] PrincipalName OPTIONAL, -- Certificate mapping hints + crealm [2] Realm, + subject-certificate [3] OCTET STRING OPTIONAL, + options [4] BIT STRING OPTIONAL, + ... +} + +AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD -- + login-alias [0] PrincipalName, + checksum [1] Checksum +} + +-- old ms referral +PA-SvrReferralData ::= SEQUENCE { + referred-name [1] PrincipalName OPTIONAL, + referred-realm [0] Realm +} + +PA-SERVER-REFERRAL-DATA ::= EncryptedData + +PA-ServerReferralData ::= SEQUENCE { + referred-realm [0] Realm OPTIONAL, + true-principal-name [1] PrincipalName OPTIONAL, + requested-principal-name [2] PrincipalName OPTIONAL, + referral-valid-until [3] KerberosTime OPTIONAL, + ... +} + +FastOptions ::= BIT STRING { + reserved(0), + hide-client-names(1), + critical2(2), + critical3(3), + critical4(4), + critical5(5), + critical6(6), + critical7(7), + critical8(8), + critical9(9), + critical10(10), + critical11(11), + critical12(12), + critical13(13), + critical14(14), + critical15(15), + kdc-follow-referrals(16) +} + +KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + padata [1] METHOD-DATA, + req-body [2] KDC-REQ-BODY, + ... +} + +KrbFastArmor ::= SEQUENCE { + armor-type [0] Krb5Int32, + armor-value [1] OCTET STRING, + ... +} + +KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + req-checksum [1] Checksum, + enc-fast-req [2] EncryptedData -- KrbFastReq -- +} + +PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... +} + +KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Krb5Int32, + crealm [2] Realm, + cname [3] PrincipalName, + ticket-checksum [4] Checksum, + ... +} + +KrbFastResponse ::= SEQUENCE { + padata [0] METHOD-DATA, + strengthen-key [1] EncryptionKey OPTIONAL, + finished [2] KrbFastFinished OPTIONAL, + nonce [3] Krb5UInt32, + ... +} + +KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + ... +} + +PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... +} + +KDCFastFlags ::= BIT STRING { + use-reply-key(0), + reply-key-used(1), + reply-key-replaced(2), + kdc-verified(3), + requested-hidden-names(4) +} + +-- KDCFastState is stored in FX_COOKIE +KDCFastState ::= SEQUENCE { + flags [0] KDCFastFlags, + expiration [1] GeneralizedTime, + fast-state [2] METHOD-DATA, + expected-pa-types [3] SEQUENCE OF PADATA-TYPE OPTIONAL +} + +KDCFastCookie ::= SEQUENCE { + version [0] UTF8String, + cookie [1] EncryptedData +} + +KDC-PROXY-MESSAGE ::= SEQUENCE { + kerb-message [0] OCTET STRING, + target-domain [1] Realm OPTIONAL, + dclocator-hint [2] INTEGER OPTIONAL +} + +-- these messages are used in the GSSCred communication and is not part of Kerberos propper + +KERB-TIMES ::= SEQUENCE { + authtime [0] KerberosTime, + starttime [1] KerberosTime, + endtime [2] KerberosTime, + renew_till [3] KerberosTime +} + +KERB-CRED ::= SEQUENCE { + client [0] Principal, + server [1] Principal, + keyblock [2] EncryptionKey, + times [3] KERB-TIMES, + ticket [4] OCTET STRING, + authdata [5] OCTET STRING, + addresses [6] HostAddresses, + flags [7] TicketFlags +} + +KERB-TGS-REQ-IN ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + addrs [1] HostAddresses, + flags [2] Krb5UInt32, + imp [3] Principal OPTIONAL, + ticket [4] OCTET STRING OPTIONAL, + in_cred [5] KERB-CRED, + krbtgt [6] KERB-CRED, + padata [7] METHOD-DATA +} + +KERB-TGS-REQ-OUT ::= SEQUENCE { + subkey [0] EncryptionKey OPTIONAL, + t [1] TGS-REQ +} + + + +KERB-TGS-REP-IN ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + subkey [1] EncryptionKey OPTIONAL, + in_cred [2] KERB-CRED, + t [3] TGS-REP +} + +KERB-TGS-REP-OUT ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + cred [1] KERB-CRED, + subkey [2] EncryptionKey +} + +KERB-ARMOR-SERVICE-REPLY ::= SEQUENCE { + armor [0] KrbFastArmor, + armor-key [1] EncryptionKey +} + +END + +-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1 diff --git a/third_party/heimdal/lib/asn1/krb5.opt b/third_party/heimdal/lib/asn1/krb5.opt new file mode 100644 index 0000000..a8bd85c --- /dev/null +++ b/third_party/heimdal/lib/asn1/krb5.opt @@ -0,0 +1,9 @@ +--encode-rfc1510-bit-string +--sequence=Principals +--sequence=AuthorizationData +--sequence=METHOD-DATA +--sequence=ETYPE-INFO +--sequence=ETYPE-INFO2 +--preserve-binary=KDC-REQ-BODY +--decorate=PrincipalNameAttrs:void *:pac +--decorate=Principal:PrincipalNameAttrs:nameattrs? diff --git a/third_party/heimdal/lib/asn1/kx509.asn1 b/third_party/heimdal/lib/asn1/kx509.asn1 new file mode 100644 index 0000000..af8a4d6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/kx509.asn1 @@ -0,0 +1,204 @@ +-- $Id$ + +-- Version 2 of the kx509 protocol is documented in RFC6717. +-- +-- Our version here has extensions without changing the version number on the +-- wire. + +KX509 DEFINITIONS ::= BEGIN +IMPORTS Extensions FROM rfc2459 + KerberosTime FROM krb5; + +KX509-ERROR-CODE ::= INTEGER { + KX509-STATUS-GOOD(0), + KX509-STATUS-CLIENT-BAD(1), + KX509-STATUS-CLIENT-FIX(2), + KX509-STATUS-CLIENT-TEMP(3), + KX509-STATUS-SERVER-BAD(4), + KX509-STATUS-SERVER-TEMP(5), + -- 6 is used internally in the umich client, avoid that + KX509-STATUS-SERVER-KEY(7), + -- CSR use negotiation: + KX509-STATUS-CLIENT-USE-CSR(8) + -- Let us reserve 1000+ for Kebreros protocol wire error codes -Nico +} + +-- Originally kx509 requests carried only a public key. We'd like to have +-- proof of possession, and the ability to carry additional options, both, in +-- cleartext and otherwise. +-- +-- We'll use a CSR for proof of posession and desired certificate extensions. +-- +-- We'll also provide a non-CSR-based method of conveying desired certificate +-- extensions. The reason for this is simply that we may want to have a [e.g., +-- RESTful HTTP] proxy for the kx509 service, and we want clients to be able to +-- be as simple as possible -cargo-culted even- with support for attributes +-- (desired certificate extensions) as parameters outside the CSR that the +-- proxy can encode without having the private key for the CSR (naturally). +-- +-- I.e., ultimately we'll have a REST endpoint, /kx509, say, with query +-- parameters like: +-- +-- - csr= +-- - eku= +-- - ku= +-- - rfc822Name= +-- - xMPPName= +-- - dNSName= +-- - dNSSrv= +-- - registeredID= +-- - principalName= +-- +-- with exactly one CSR and zero, one, or more of the other parameters. +-- +-- We'll even have a way to convey a bearer token from the REST proxy so that +-- we may have a way to get PKIX credentials using bearer tokens. And then, +-- using PKINIT, we may have a way to get Kerberos credentials using bearer +-- tokens. +-- +-- To do this we define a Kx509CSRPlus that we can use in the `pk-key' field of +-- Kx509Request (see below): +Kx509CSRPlus ::= [APPLICATION 35] SEQUENCE { + -- PKCS#10, DER-encoded CSR, with or without meaningful attributes + csr OCTET STRING, + -- Desired certificate Extensions such as KeyUsage, ExtKeyUsage, or + -- subjectAlternativeName (SAN) + exts Extensions OPTIONAL, + -- Desired certificate lifetime + req-life KerberosTime OPTIONAL, + ... +} + +-- Version 2 +Kx509Request ::= SEQUENCE { + authenticator OCTET STRING, + pk-hash OCTET STRING, -- HMAC(ticket_session_key, pk-key) + pk-key OCTET STRING -- one of: + -- - the public key, DER-encoded (RSA, basically) + -- - a Kx509CSRPlus +} + +-- Kx509ErrorCode is a Heimdal-specific enhancement with no change on the wire, +-- and really only just so the error-code field below can fit on one line. +Kx509ErrorCode ::= INTEGER (-2147483648..2147483647) + +Kx509Response ::= SEQUENCE { + error-code[0] Kx509ErrorCode DEFAULT 0, + hash[1] OCTET STRING OPTIONAL, -- HMAC(session_key, ...) + certificate[2] OCTET STRING OPTIONAL, -- DER-encoded Certificate + -- if client sent raw RSA SPK + -- or DER-encoded Certificates + -- (i.e., SEQ. OF Certificate) + -- if client used a + -- Kx509CSRPlus + e-text[3] VisibleString OPTIONAL +} + +-- Offset for Kerberos protocol errors when error-code set to one: +kx509-krb5-error-base INTEGER ::= 1000 + +-- RFC6717 says this about error codes: +-- +-- +------------+-----------------------------+------------------------+ +-- | error-code | Condition | Example | +-- +------------+-----------------------------+------------------------+ +-- | 1 | Permanent problem with | Incompatible version | +-- | | client request | | +-- | 2 | Solvable problem with | Expired Kerberos | +-- | | client request | credentials | +-- | 3 | Temporary problem with | Packet loss | +-- | | client request | | +-- | 4 | Permanent problem with the | Internal | +-- | | server | misconfiguration | +-- | 5 | Temporary problem with the | Server overloaded | +-- | | server | | +-- +------------+-----------------------------+------------------------+ +-- +-- Looking at UMich CITI's kca (server-side of kx509) implementation, it always +-- sends 0 as the status code, and the UMich CITI kx509 client never checks it. +-- All of these error codes are local only in the UMich CITI implementation. +-- +-- Meanwhile, Heimdal used to never send error responses at all. +-- +-- As a result we can use whatever error codes we want. We'll send Kerberos +-- protocol errors + 1000. And we'll never use RFC6717 error codes at all. +-- +-- Looking at umich source... +-- +-- #define KX509_STATUS_GOOD 0 /* No problems handling client request */ +-- #define KX509_STATUS_CLNT_BAD 1 /* Client-side permanent problem */ +-- /* ex. version incompatible */ +-- #define KX509_STATUS_CLNT_FIX 2 /* Client-side solvable problem */ +-- /* ex. re-authenticate */ +-- #define KX509_STATUS_CLNT_TMP 3 /* Client-side temporary problem */ +-- /* ex. packet loss */ +-- #define KX509_STATUS_SRVR_BAD 4 /* Server-side permanent problem */ +-- /* ex. server broken */ +-- #define KX509_STATUS_SRVR_TMP 5 /* Server-side temporary problem */ +-- /* ex. server overloaded */ +-- #define KX509_STATUS_SRVR_CANT_CLNT_VERS 6 /* Server-side doesn't handle */ +-- /* existence of client_version */ +-- /* field in KX509_REQUEST */ +-- +-- The umich server uses these errors in these situations: +-- +-- - KX509_STATUS_SRVR_TMP is for: +-- - request decode errors +-- - krb5_is_ap_req() errors +-- - wrong Kerberos protocol vno in AP-REQ +-- - some ENOMEMs +-- - UDP read errors (??) +-- - LDAP issues (they use LDAP to map realm-chopped user princ names to +-- full names) +-- - pk decode errors +-- - KX509_STATUS_CLNT_TMP is for: +-- - HMAC mismatch +-- - some ENOMEMs +-- - failure to accept AP-REQ +-- - failure to unparse princ names from AP-REQ's Ticket +-- - KX509_STATUS_SRVR_BAD is for: +-- - configuration issues (missing issuer creds) +-- - serial number transaction issues (we should randomize) +-- - subjectName construction issues +-- - certificate construction issues (ENOMEM, say) +-- - failure to authenticate (never happens, since KX509_STATUS_CLNT_TMP is +-- used earlier when krb5_rd_req() fails) +-- - KX509_STATUS_CLNT_FIX is for: +-- - more than one component client principals +-- - client princ name component zero string length shorter than 3 or +-- longer than 8 (WTF) +-- - other policy issues +-- - KX509_STATUS_CLNT_BAD +-- - wrong protocol version number (version_2_0) + +-- Possible new version designs: +-- +-- - keep the protocol the same but use a CSR instead of a raw RSA public key +-- - on the server try decoding first a CSR, then a raw RSA public key +-- +-- - keep the protocol the same but use either a CSR or a self-signed cert +-- - on the server try decoding first a Certificate, then a CSR, then a raw +-- RSA public key +-- +-- CSRs are a pain to deal with. Self-signed certificates can act as a +-- CSR of a sort. Use notBefore == 1970-01-01T00:00:00Z and an EKU +-- denoting "this certificate is really a much-easier-to-work-with CSR +-- alternative". +-- +-- - keep the protocol similar, but use the checksum field of the +-- Authenticator to authenticate the request data; use a KRB-PRIV for the +-- reply +-- +-- - extend the KDC/AS/TGS protocols to support certificate issuance, either +-- at the same time as ticket acquisition, or as an alternative +-- - send a CSR as a authz-data element +-- - expect an EncryptedData with the issued Certificate inside as the +-- Ticket in the result (again, ugly hack) +-- - or maybe just add new messages, but, the thing is that the existing +-- "AP-REP + stuff" kx509 protocol is a fine design pattern, there's no +-- need to radically change it, just slightly. +-- +-- The main benefit of using an extension to the KDC/AS/TGS protocols is that +-- we could then use FAST for confidentiality protection. + +END diff --git a/third_party/heimdal/lib/asn1/lex.h b/third_party/heimdal/lib/asn1/lex.h new file mode 100644 index 0000000..1ee5341 --- /dev/null +++ b/third_party/heimdal/lib/asn1/lex.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#include + +void lex_error_message (const char *, ...) +__attribute__ ((format (printf, 1, 2))); +extern int error_flag; + +int yylex(void); diff --git a/third_party/heimdal/lib/asn1/lex.l b/third_party/heimdal/lib/asn1/lex.l new file mode 100644 index 0000000..4554a94 --- /dev/null +++ b/third_party/heimdal/lib/asn1/lex.l @@ -0,0 +1,310 @@ +%{ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#undef ECHO +#include "symbol.h" +#include "asn1parse.h" +#include "lex.h" +#include "gen_locl.h" + +static unsigned lineno = 1; + +#undef ECHO + +static void unterminated(const char *, unsigned); + +%} + +/* This is for broken old lexes (solaris 10 and hpux) */ +%e 2000 +%p 5000 +%a 5000 +%n 1000 +%o 10000 + +%% +ABSENT { return kw_ABSENT; } +ABSTRACT-SYNTAX { return kw_ABSTRACT_SYNTAX; } +ALL { return kw_ALL; } +APPLICATION { return kw_APPLICATION; } +AUTOMATIC { return kw_AUTOMATIC; } +BEGIN { return kw_BEGIN; } +BIT { return kw_BIT; } +BMPString { return kw_BMPString; } +BOOLEAN { return kw_BOOLEAN; } +BY { return kw_BY; } +CHARACTER { return kw_CHARACTER; } +CHOICE { return kw_CHOICE; } +CLASS { return kw_CLASS; } +COMPONENT { return kw_COMPONENT; } +COMPONENTS { return kw_COMPONENTS; } +CONSTRAINED { return kw_CONSTRAINED; } +CONTAINING { return kw_CONTAINING; } +DEFAULT { return kw_DEFAULT; } +DEFINITIONS { return kw_DEFINITIONS; } +EMBEDDED { return kw_EMBEDDED; } +ENCODED { return kw_ENCODED; } +END { return kw_END; } +ENUMERATED { return kw_ENUMERATED; } +EXCEPT { return kw_EXCEPT; } +EXPLICIT { return kw_EXPLICIT; } +EXPORTS { return kw_EXPORTS; } +EXTENSIBILITY { return kw_EXTENSIBILITY; } +EXTERNAL { return kw_EXTERNAL; } +FALSE { return kw_FALSE; } +FROM { return kw_FROM; } +GeneralString { return kw_GeneralString; } +GeneralizedTime { return kw_GeneralizedTime; } +GraphicString { return kw_GraphicString; } +IA5String { return kw_IA5String; } +IDENTIFIER { return kw_IDENTIFIER; } +IMPLICIT { return kw_IMPLICIT; } +IMPLIED { return kw_IMPLIED; } +IMPORTS { return kw_IMPORTS; } +INCLUDES { return kw_INCLUDES; } +INSTANCE { return kw_INSTANCE; } +INTEGER { return kw_INTEGER; } +INTERSECTION { return kw_INTERSECTION; } +ISO646String { return kw_ISO646String; } +MAX { return kw_MAX; } +MIN { return kw_MIN; } +MINUS-INFINITY { return kw_MINUS_INFINITY; } +NULL { return kw_NULL; } +NumericString { return kw_NumericString; } +OBJECT { return kw_OBJECT; } +OCTET { return kw_OCTET; } +OF { return kw_OF; } +OPTIONAL { return kw_OPTIONAL; } +ObjectDescriptor { return kw_ObjectDescriptor; } +PATTERN { return kw_PATTERN; } +PDV { return kw_PDV; } +PLUS-INFINITY { return kw_PLUS_INFINITY; } +PRESENT { return kw_PRESENT; } +PRIVATE { return kw_PRIVATE; } +PrintableString { return kw_PrintableString; } +REAL { return kw_REAL; } +RELATIVE_OID { return kw_RELATIVE_OID; } +SEQUENCE { return kw_SEQUENCE; } +SET { return kw_SET; } +SIZE { return kw_SIZE; } +STRING { return kw_STRING; } +SYNTAX { return kw_SYNTAX; } +T61String { return kw_T61String; } +TAGS { return kw_TAGS; } +TRUE { return kw_TRUE; } +TYPE-IDENTIFIER { return kw_TYPE_IDENTIFIER; } +TeletexString { return kw_TeletexString; } +UNION { return kw_UNION; } +UNIQUE { return kw_UNIQUE; } +UNIVERSAL { return kw_UNIVERSAL; } +UTCTime { return kw_UTCTime; } +UTF8String { return kw_UTF8String; } +UniversalString { return kw_UniversalString; } +VideotexString { return kw_VideotexString; } +VisibleString { return kw_VisibleString; } +WITH { return kw_WITH; } +[-,;{}()|] { return *yytext; } +"[" { return *yytext; } +"]" { return *yytext; } +"&" { return *yytext; } +"." { return *yytext; } +":" { return *yytext; } +"@" { return *yytext; } +::= { return EEQUAL; } +-- { + int c, start_lineno = lineno; + int f = 0; + while((c = input()) != EOF) { + if(f && c == '-') + break; + if(c == '-') { + f = 1; + continue; + } + if(c == '\n') { + lineno++; + break; + } + f = 0; + } + if(c == EOF) + unterminated("comment", start_lineno); + } +\/\* { + int c, start_lineno = lineno; + int level = 1; + int seen_star = 0; + int seen_slash = 0; + while((c = input()) != EOF) { + if(c == '/') { + if(seen_star) { + if(--level == 0) + break; + seen_star = 0; + continue; + } + seen_slash = 1; + continue; + } + if(seen_star && c == '/') { + if(--level == 0) + break; + seen_star = 0; + continue; + } + if(c == '*') { + if(seen_slash) { + level++; + seen_star = seen_slash = 0; + continue; + } + seen_star = 1; + continue; + } + seen_star = seen_slash = 0; + if(c == '\n') { + lineno++; + continue; + } + } + if(c == EOF) + unterminated("comment", start_lineno); + } +"\"" { + int start_lineno = lineno; + int c; + char buf[1024]; + char *p = buf; + int f = 0; + int skip_ws = 0; + + while((c = input()) != EOF) { + if(isspace(c) && skip_ws) { + if(c == '\n') + lineno++; + continue; + } + skip_ws = 0; + + if(c == '"') { + if(f) { + *p++ = '"'; + f = 0; + } else + f = 1; + continue; + } + if(f == 1) { + unput(c); + break; + } + if(c == '\n') { + lineno++; + while(p > buf && isspace((unsigned char)p[-1])) + p--; + skip_ws = 1; + continue; + } + *p++ = c; + } + if(c == EOF) + unterminated("string", start_lineno); + *p++ = '\0'; + yylval.name = estrdup(buf); + return STRING; + } + +-?0x[0-9A-Fa-f]+|-?[0-9]+ { char *e, *y = yytext; + yylval.constant = strtoll((const char *)yytext, + &e, 0); + if(e == y) + lex_error_message("malformed constant (%s)", yytext); + else + return NUMBER; + } +[_][-A-Z0-9]* { + yylval.name = estrdup ((const char *)yytext); + return CLASS_IDENTIFIER; + } +[A-Z][-A-Za-z0-9_]* { + yylval.name = estrdup ((const char *)yytext); + return TYPE_IDENTIFIER; + } +[a-z][-A-Za-z0-9_]* { + yylval.name = estrdup ((const char *)yytext); + return VALUE_IDENTIFIER; + } +[ \t] ; +\n { ++lineno; } +\.\.\. { return ELLIPSIS; } +\.\. { return RANGE; } +. { lex_error_message("Ignoring char(%c)\n", *yytext); } +%% + +int +yywrap () +{ + return 1; +} + +void +lex_error_message (const char *format, ...) +{ + va_list args; + + va_start (args, format); + fprintf (stderr, "%s:%d: ", get_filename(), lineno); + vfprintf (stderr, format, args); + va_end (args); + error_flag++; +} + +static void +unterminated(const char *type, unsigned start_lineno) +{ + lex_error_message("unterminated %s, possibly started on line %d\n", type, start_lineno); +} diff --git a/third_party/heimdal/lib/asn1/libasn1-exports.def b/third_party/heimdal/lib/asn1/libasn1-exports.def new file mode 100644 index 0000000..76a568f --- /dev/null +++ b/third_party/heimdal/lib/asn1/libasn1-exports.def @@ -0,0 +1,2655 @@ +EXPORTS + _asn1_decode_top + _asn1_encode + _asn1_length + _asn1_free_top + _asn1_copy_top + _asn1_bmember_isset_bit + _asn1_bmember_put_bit + _asn1_copy + _asn1_copy_top + _asn1_decode + _asn1_decode_top + _asn1_encode + _asn1_free + _asn1_free_top + _asn1_length + _asn1_print_top + _asn1_sizeofType + add_AttributeValues + add_AuthorizationData + add_CertificatePolicies + add_Certificates + add_CRLDistributionPoints + add_DigestAlgorithmIdentifiers + add_ETYPE_INFO + add_ETYPE_INFO2 + add_Extensions + add_GeneralNames + add_METHOD_DATA + add_PolicyMappings + add_PolicyQualifierInfos + add_Principals + add_RDNSequence + APOptions2int + asn1_APOptions_units + asn1_DigestTypes_units + asn1_DistributionPointReasonFlags_units + asn1_FastOptions_units + asn1_KDCFastFlags_units + asn1_KDCOptions_units + asn1_KeyUsage_units + asn1_oid_id_aa_communityIdentifiers DATA + asn1_oid_id_aa_decryptKeyID DATA + asn1_oid_id_aa_firmwarePackageID DATA + asn1_oid_id_aa_firmwarePackageInfo DATA + asn1_oid_id_aa_implCompressAlgs DATA + asn1_oid_id_aa_implCryptoAlgs DATA + asn1_oid_id_aa_targetHardwareIDs DATA + asn1_oid_id_aa_wrappedFirmwareKey DATA + asn1_oid_id_aes_128_cbc DATA + asn1_oid_id_aes_192_cbc DATA + asn1_oid_id_aes_256_cbc DATA + asn1_oid_id_apple_system_id DATA + asn1_oid_id_at_commonName DATA + asn1_oid_id_at_countryName DATA + asn1_oid_id_at_description DATA + asn1_oid_id_at_dnQualifier DATA + asn1_oid_id_at_emailAddress DATA + asn1_oid_id_at_generationQualifier DATA + asn1_oid_id_at_givenName DATA + asn1_oid_id_at_initials DATA + asn1_oid_id_at_localityName DATA + asn1_oid_id_at_name DATA + asn1_oid_id_at_organizationalUnitName DATA + asn1_oid_id_at_organizationName DATA + asn1_oid_id_at_pseudonym DATA + asn1_oid_id_at_serialNumber DATA + asn1_oid_id_at_stateOrProvinceName DATA + asn1_oid_id_at_streetAddress DATA + asn1_oid_id_at_surname DATA + asn1_oid_id_at_title DATA + asn1_oid_id_ct_firmwareLoadError DATA + asn1_oid_id_ct_firmwareLoadReceipt DATA + asn1_oid_id_ct_firmwarePackage DATA + asn1_oid_id_dhpublicnumber DATA + asn1_oid_id_domainComponent DATA + asn1_oid_id_dsa DATA + asn1_oid_id_dsa_with_sha1 DATA + asn1_oid_id_ecDH DATA + asn1_oid_id_ecdsa_with_SHA1 DATA + asn1_oid_id_ecdsa_with_SHA224 DATA + asn1_oid_id_ecdsa_with_SHA256 DATA + asn1_oid_id_ecdsa_with_SHA384 DATA + asn1_oid_id_ecdsa_with_SHA512 DATA + asn1_oid_id_ec_group_secp160r1 DATA + asn1_oid_id_ec_group_secp160r2 DATA + asn1_oid_id_ec_group_secp224r1 DATA + asn1_oid_id_ec_group_secp256r1 DATA + asn1_oid_id_ec_group_secp384r1 DATA + asn1_oid_id_ec_group_secp521r1 DATA + asn1_oid_id_ecMQV DATA + asn1_oid_id_ecPublicKey DATA + asn1_oid_id_heim_rsa_pkcs1_x509 DATA + asn1_oid_id_ms_cert_enroll_domaincontroller DATA + asn1_oid_id_msft DATA + asn1_oid_id_msft_kp_msCodeCom DATA + asn1_oid_id_msft_kp_msCodeInd DATA + asn1_oid_id_msft_kp_msCTLSign DATA + asn1_oid_id_msft_kp_msEFS DATA + asn1_oid_id_msft_kp_msSGC DATA + asn1_oid_id_msft_kp_msSmartcardLogin DATA + asn1_oid_id_msft_kp_msUPN DATA + asn1_oid_id_netscape_cert_comment DATA + asn1_oid_id_netscape DATA + asn1_oid_id_nist_aes_algs DATA + asn1_oid_id_nistAlgorithm DATA + asn1_oid_id_nist_sha_algs DATA + asn1_oid_id_on_hardwareModuleName DATA + asn1_oid_id_pbeWithSHAAnd128BitRC2_CBC DATA + asn1_oid_id_pbeWithSHAAnd128BitRC4 DATA + asn1_oid_id_pbeWithSHAAnd2_KeyTripleDES_CBC DATA + asn1_oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC DATA + asn1_oid_id_pbewithSHAAnd40BitRC2_CBC DATA + asn1_oid_id_pbeWithSHAAnd40BitRC4 DATA + asn1_oid_id_pkauthdata DATA + asn1_oid_id_pkcs12_bagtypes DATA + asn1_oid_id_pkcs12_certBag DATA + asn1_oid_id_pkcs12_crlBag DATA + asn1_oid_id_pkcs_12 DATA + asn1_oid_id_pkcs12_keyBag DATA + asn1_oid_id_pkcs_12PbeIds DATA + asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag DATA + asn1_oid_id_pkcs12_safeContentsBag DATA + asn1_oid_id_pkcs12_secretBag DATA + asn1_oid_id_pkcs_1 DATA + asn1_oid_id_pkcs1_md2WithRSAEncryption DATA + asn1_oid_id_pkcs1_md5WithRSAEncryption DATA + asn1_oid_id_pkcs1_rsaEncryption DATA + asn1_oid_id_pkcs1_sha1WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha256WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha384WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha512WithRSAEncryption DATA + asn1_oid_id_pkcs_2 DATA + asn1_oid_id_pkcs2_md2 DATA + asn1_oid_id_pkcs2_md4 DATA + asn1_oid_id_pkcs2_md5 DATA + asn1_oid_id_pkcs_3 DATA + asn1_oid_id_pkcs3_des_ede3_cbc DATA + asn1_oid_id_pkcs3_rc2_cbc DATA + asn1_oid_id_pkcs3_rc4 DATA + asn1_oid_id_pkcs7 DATA + asn1_oid_id_pkcs7_data DATA + asn1_oid_id_pkcs7_digestedData DATA + asn1_oid_id_pkcs7_encryptedData DATA + asn1_oid_id_pkcs7_envelopedData DATA + asn1_oid_id_pkcs7_signedAndEnvelopedData DATA + asn1_oid_id_pkcs7_signedData DATA + asn1_oid_id_pkcs_9_at_certTypes DATA + asn1_oid_id_pkcs_9_at_certTypes_x509 DATA + asn1_oid_id_pkcs_9_at_friendlyName DATA + asn1_oid_id_pkcs_9_at_localKeyId DATA + asn1_oid_id_pkcs9_contentType DATA + asn1_oid_id_pkcs9_countersignature DATA + asn1_oid_id_pkcs_9 DATA + asn1_oid_id_pkcs9_emailAddress DATA + asn1_oid_id_pkcs9_extReq DATA + asn1_oid_id_pkcs9_messageDigest DATA + asn1_oid_id_pkcs9_signingTime DATA + asn1_oid_id_pkdhkeydata DATA + asn1_oid_id_pkekuoid DATA + asn1_oid_id_pkinit DATA + asn1_oid_id_pkinit_kdf_ah_sha1 DATA + asn1_oid_id_pkinit_kdf_ah_sha256 DATA + asn1_oid_id_pkinit_kdf_ah_sha512 DATA + asn1_oid_id_pkinit_kdf DATA + asn1_oid_id_pkinit_ms_eku DATA + asn1_oid_id_pkinit_ms_san DATA + asn1_oid_id_pkinit_san DATA + asn1_oid_id_pkix_ad_caIssuers DATA + asn1_oid_id_pkix_ad_caRepository DATA + asn1_oid_id_pkix_ad DATA + asn1_oid_id_pkix_ad_ocsp DATA + asn1_oid_id_pkix_ad_timeStamping DATA + asn1_oid_id_pkix DATA + asn1_oid_id_pkix_kp_bgpsec_router DATA + asn1_oid_id_pkix_kp_capwapAC DATA + asn1_oid_id_pkix_kp_capwapWTP DATA + asn1_oid_id_pkix_kp_clientAuth DATA + asn1_oid_id_pkix_kp_cmcArchive DATA + asn1_oid_id_pkix_kp_cmcCA DATA + asn1_oid_id_pkix_kp_cmcRA DATA + asn1_oid_id_pkix_kp_codeSigning DATA + asn1_oid_id_pkix_kp DATA + asn1_oid_id_pkix_kp_DVCS DATA + asn1_oid_id_pkix_kp_emailProtection DATA + asn1_oid_id_pkix_kp_ipsecEndSystem DATA + asn1_oid_id_pkix_kp_ipsecIKE DATA + asn1_oid_id_pkix_kp_ipsecTunnel DATA + asn1_oid_id_pkix_kp_ipsecUser DATA + asn1_oid_id_pkix_kp_OCSPSigning DATA + asn1_oid_id_pkix_kp_secureShellClient DATA + asn1_oid_id_pkix_kp_secureShellServer DATA + asn1_oid_id_pkix_kp_sendOwner DATA + asn1_oid_id_pkix_kp_sendProxiedOwner DATA + asn1_oid_id_pkix_kp_sendProxiedRouter DATA + asn1_oid_id_pkix_kp_sendRouter DATA + asn1_oid_id_pkix_kp_serverAuth DATA + asn1_oid_id_pkix_kp_sipDomain DATA + asn1_oid_id_pkix_kp_timeStamping DATA + asn1_oid_id_pkix_ocsp_basic DATA + asn1_oid_id_pkix_ocsp DATA + asn1_oid_id_pkix_ocsp_nonce DATA + asn1_oid_id_pkix_on DATA + asn1_oid_id_pkix_on_dnsSRV DATA + asn1_oid_id_pkix_on_hardwareModuleName DATA + asn1_oid_id_pkix_on_permanentIdentifier DATA + asn1_oid_id_pkix_on_pkinit_ms_san DATA + asn1_oid_id_pkix_on_pkinit_san DATA + asn1_oid_id_pkix_on_xmppAddr DATA + asn1_oid_id_pkix_pe_authorityInfoAccess DATA + asn1_oid_id_pkix_pe DATA + asn1_oid_id_pkix_pe_proxyCertInfo DATA + asn1_oid_id_pkix_pe_subjectInfoAccess DATA + asn1_oid_id_pkix_ppl_anyLanguage DATA + asn1_oid_id_pkix_ppl DATA + asn1_oid_id_pkix_ppl_independent DATA + asn1_oid_id_pkix_ppl_inheritAll DATA + asn1_oid_id_pkix_qt_cps DATA + asn1_oid_id_pkix_qt DATA + asn1_oid_id_pkix_qt_unotice DATA + asn1_oid_id_pkkdcekuoid DATA + asn1_oid_id_pkrkeydata DATA + asn1_oid_id_rsa_digestAlgorithm DATA + asn1_oid_id_rsa_digest_md2 DATA + asn1_oid_id_rsa_digest_md4 DATA + asn1_oid_id_rsa_digest_md5 DATA + asn1_oid_id_rsadsi_des_ede3_cbc DATA + asn1_oid_id_rsadsi_encalg DATA + asn1_oid_id_rsadsi_rc2_cbc DATA + asn1_oid_id_secsig_sha_1 DATA + asn1_oid_id_secsig_sha_1WithRSAEncryption DATA + asn1_oid_id_sha224 DATA + asn1_oid_id_sha256 DATA + asn1_oid_id_sha384 DATA + asn1_oid_id_sha512 DATA + asn1_oid_id_Userid DATA + asn1_oid_id_uspkicommon_card_id DATA + asn1_oid_id_uspkicommon_piv_interim DATA + asn1_oid_id_x509_ce_anyExtendedKeyUsage DATA + asn1_oid_id_x509_ce_authorityKeyIdentifier DATA + asn1_oid_id_x509_ce_basicConstraints DATA + asn1_oid_id_x509_ce_certificateIssuer DATA + asn1_oid_id_x509_ce_certificatePolicies_anyPolicy DATA + asn1_oid_id_x509_ce_certificatePolicies DATA + asn1_oid_id_x509_ce_cRLDistributionPoints DATA + asn1_oid_id_x509_ce_cRLNumber DATA + asn1_oid_id_x509_ce_cRLReason DATA + asn1_oid_id_x509_ce_cRLReasons DATA + asn1_oid_id_x509_ce DATA + asn1_oid_id_x509_ce_deltaCRLIndicator DATA + asn1_oid_id_x509_ce_extKeyUsage DATA + asn1_oid_id_x509_ce_freshestCRL DATA + asn1_oid_id_x509_ce_holdInstructionCode DATA + asn1_oid_id_x509_ce_inhibitAnyPolicy DATA + asn1_oid_id_x509_ce_invalidityDate DATA + asn1_oid_id_x509_ce_issuerAltName DATA + asn1_oid_id_x509_ce_issuingDistributionPoint DATA + asn1_oid_id_x509_ce_keyUsage DATA + asn1_oid_id_x509_ce_nameConstraints DATA + asn1_oid_id_x509_ce_policyConstraints DATA + asn1_oid_id_x509_ce_policyMappings DATA + asn1_oid_id_x509_ce_privateKeyUsagePeriod DATA + asn1_oid_id_x509_ce_subjectAltName DATA + asn1_oid_id_x509_ce_subjectDirectoryAttributes DATA + asn1_oid_id_x509_ce_subjectKeyIdentifier DATA + asn1_oid_id_x520_at DATA + asn1_oid_id_x9_57 DATA + asn1_oid_tcg_at_tpmManufacturer DATA + asn1_oid_tcg_at_tpmModel DATA + asn1_oid_tcg_at_tpmSecurityAssertions DATA + asn1_oid_tcg_at_tpmSpecification DATA + asn1_oid_tcg_at_tpmVersion DATA + asn1_oid_tcg_attribute DATA + asn1_oid_tcg_cap_verifiedTPMFixed DATA + asn1_oid_tcg_cap_verifiedTPMResidency DATA + asn1_oid_tcg_cap_verifiedTPMRestricted DATA + asn1_oid_tcg DATA + asn1_oid_tcg_kp DATA + asn1_oid_tcg_kp_EKCertificate DATA + asn1_oid_tcg_on_ekPermIdSha256 DATA + asn1_oid_tcg_tpm20 DATA + asn1_SAMFlags_units + asn1_TicketFlags_units + copy_AccessDescription + copy_AD_AND_OR + copy_AD_IF_RELEVANT + copy_AD_INITIAL_VERIFIED_CAS + copy_AD_KDCIssued + copy_AD_LoginAlias + copy_AD_MANDATORY_FOR_KDC + copy_AlgorithmIdentifier + copy_AliasIA5String + copy_AliasPrintableString + copy_AliasUTF8String + copy_APOptions + copy_AP_REP + copy_AP_REQ + copy_AS_REP + copy_AS_REQ + copy_Attribute + copy_AttributeSet + copy_AttributeType + copy_AttributeTypeAndValue + copy_AttributeValue + copy_AttributeValues + copy_AUTHDATA_TYPE + copy_Authenticator + copy_AuthorityInfoAccessSyntax + copy_AuthorityKeyIdentifier + copy_AuthorizationData + copy_AuthorizationDataElement + copy_AuthPack + copy_AuthPack_Win2k + copy_BaseDistance + copy_BasicConstraints + copy_Certificate + copy_CertificateList + copy_CertificatePolicies + copy_CertificateRevocationLists + copy_Certificates + copy_CertificateSerialNumber + copy_CertificateSet + copy_CertificationRequest + copy_CertificationRequestInfo + copy_CertPolicyId + copy_ChangePasswdDataMS + copy_Checksum + copy_CKSUMTYPE + copy_CMSAttributes + copy_CMSCBCParameter + copy_CMSEncryptedData + copy_CMSIdentifier + copy_CMSRC2CBCParameter + copy_CMSVersion + copy_CommonCriteriaMeasures + copy_CommunityIdentifier + copy_CommunityIdentifiers + copy_CompositePrincipal + copy_ContentEncryptionAlgorithmIdentifier + copy_ContentInfo + copy_ContentType + copy_CPSuri + copy_CRIAttributeSet + copy_CRIExtensions + copy_CRLCertificateList + copy_CRLDistributionPoints + copy_CRLReason + copy_CurrentFWConfig + copy_DecryptKeyIdentifier + copy_DHNonce + copy_DHParameter + copy_DHPublicKey + copy_DHRepInfo + copy_DigestAlgorithmIdentifier + copy_DigestAlgorithmIdentifiers + copy_DigestError + copy_DigestInfo + copy_DigestInit + copy_DigestInitReply + copy_DigestREP + copy_DigestRepInner + copy_DigestREQ + copy_DigestReqInner + copy_DigestRequest + copy_DigestResponse + copy_DigestTypes + copy_DirectoryString + copy_DisplayText + copy_DistributionPoint + copy_DistributionPointName + copy_DistributionPointReasonFlags + copy_DomainParameters + copy_DSAParams + copy_DSAPublicKey + copy_DSASigValue + copy_ECDSA_Sig_Value + copy_ECParameters + copy_ECPoint + copy_EKCertificateGenerationLocation + copy_EKGenerationLocation + copy_EKGenerationType + copy_EncAPRepPart + copy_EncapsulatedContentInfo + copy_EncASRepPart + copy_EncKDCRepPart + copy_EncKrbCredPart + copy_EncKrbPrivPart + copy_EncryptedContent + copy_EncryptedContentInfo + copy_EncryptedData + copy_EncryptedKey + copy_EncryptionKey + copy_EncTGSRepPart + copy_EncTicketPart + copy_ENCTYPE + copy_EnvelopedData + copy_ETYPE_INFO + copy_ETYPE_INFO2 + copy_ETYPE_INFO2_ENTRY + copy_ETYPE_INFO_ENTRY + copy_EtypeList + copy_EvaluationAssuranceLevel + copy_EvaluationStatus + copy_Extension + copy_Extensions + copy_ExternalPrincipalIdentifier + copy_ExternalPrincipalIdentifiers + copy_ExtKeyUsage + copy_FastOptions + copy_FIPSLevel + copy_FirmwarePackageIdentifier + copy_FirmwarePackageInfo + copy_FirmwarePackageLoadError + copy_FirmwarePackageLoadErrorCode + copy_FirmwarePackageLoadReceipt + copy_FirmwarePkgData + copy_FWErrorVersion + copy_FWReceiptVersion + copy_GeneralName + copy_GeneralNames + copy_GeneralSubtree + copy_GeneralSubtrees + copy_HardwareModuleName + copy_HardwareModules + copy_HardwareSerialEntry + copy_heim_any + copy_HEIM_ANY + copy_heim_any_set + copy_HEIM_ANY_SET + copy_HostAddress + copy_HostAddresses + copy_ImplementedCompressAlgorithms + copy_ImplementedCryptoAlgorithms + copy_IOSCertificationRequest + copy_IOSCertificationRequestInfo + copy_IssuerAndSerialNumber + copy_KDCDHKeyInfo + copy_KDCDHKeyInfo_Win2k + copy_KDCFastCookie + copy_KDCFastFlags + copy_KDCFastState + copy_KDCOptions + copy_KDC_PROXY_MESSAGE + copy_KDC_REP + copy_KDC_REQ + copy_KDC_REQ_BODY + copy_KDFAlgorithmId + copy_KERB_AD_RESTRICTION_ENTRY + copy_KERB_ARMOR_SERVICE_REPLY + copy_KERB_CRED + copy_KerberosString + copy_KerberosTime + copy_KERB_ERROR_DATA + copy_KERB_TGS_REP_IN + copy_KERB_TGS_REP_OUT + copy_KERB_TGS_REQ_IN + copy_KERB_TGS_REQ_OUT + copy_KERB_TIMES + copy_KeyEncryptionAlgorithmIdentifier + copy_KeyIdentifier + copy_KeyTransRecipientInfo + copy_KeyUsage + copy_Krb5Int32 + copy_KRB5PrincipalName + copy_Krb5UInt32 + copy_KRB_CRED + copy_KrbCredInfo + copy_KRB_ERROR + copy_KrbFastArmor + copy_KrbFastArmoredRep + copy_KrbFastArmoredReq + copy_KrbFastFinished + copy_KrbFastReq + copy_KrbFastResponse + copy_KRB_PRIV + copy_KRB_SAFE + copy_KRB_SAFE_BODY + copy_Kx509CSRPlus + copy_Kx509ErrorCode + copy_KX509_ERROR_CODE + copy_Kx509Request + copy_Kx509Response + copy_LastReq + copy_LR_TYPE + copy_MessageDigest + copy_MESSAGE_TYPE + copy_METHOD_DATA + copy_MS_UPN_SAN + copy_Name + copy_NameConstraints + copy_NAME_TYPE + copy_NoticeReference + copy_NTLMInit + copy_NTLMInitReply + copy_NTLMReply + copy_NTLMRequest + copy_NTLMRequest2 + copy_NTLMResponse + copy_OCSPBasicOCSPResponse + copy_OCSPCertID + copy_OCSPCertStatus + copy_OCSPInnerRequest + copy_OCSPKeyHash + copy_OCSPRequest + copy_OCSPResponderID + copy_OCSPResponse + copy_OCSPResponseBytes + copy_OCSPResponseData + copy_OCSPResponseStatus + copy_OCSPSignature + copy_OCSPSingleResponse + copy_OCSPTBSRequest + copy_OCSPVersion + copy_OriginatorInfo + copy_OtherName + copy_PA_DATA + copy_PADATA_TYPE + copy_PA_ENC_SAM_RESPONSE_ENC + copy_PA_ENC_TS_ENC + copy_PA_FX_FAST_REPLY + copy_PA_FX_FAST_REQUEST + copy_PA_KERB_KEY_LIST_REP + copy_PA_KERB_KEY_LIST_REQ + copy_PA_PAC_OPTIONS + copy_PA_PAC_REQUEST + copy_PA_PK_AS_REP + copy_PA_PK_AS_REP_BTMM + copy_PA_PK_AS_REP_Win2k + copy_PA_PK_AS_REQ + copy_PA_PK_AS_REQ_Win2k + copy_PA_S4U_X509_USER + copy_PA_S4U2Self + copy_PA_SAM_CHALLENGE_2 + copy_PA_SAM_CHALLENGE_2_BODY + copy_PA_SAM_REDIRECT + copy_PA_SAM_RESPONSE_2 + copy_PA_SAM_TYPE + copy_PA_ServerReferralData + copy_PA_SERVER_REFERRAL_DATA + copy_PA_SvrReferralData + copy_PermanentIdentifier + copy_PKAuthenticator + copy_PKAuthenticator_Win2k + copy_PKCS12_Attribute + copy_PKCS12_Attributes + copy_PKCS12_AuthenticatedSafe + copy_PKCS12_CertBag + copy_PKCS12_MacData + copy_PKCS12_OctetString + copy_PKCS12_PBEParams + copy_PKCS12_PFX + copy_PKCS12_SafeBag + copy_PKCS12_SafeContents + copy_PKCS8Attributes + copy_PKCS8EncryptedData + copy_PKCS8EncryptedPrivateKeyInfo + copy_PKCS8PrivateKey + copy_PKCS8PrivateKeyAlgorithmIdentifier + copy_PKCS8PrivateKeyInfo + copy_PKCS9_BMPString + copy_PKCS9_friendlyName + copy_PkinitSP80056AOtherInfo + copy_PkinitSuppPubInfo + copy_PKIXXmppAddr + copy_PolicyConstraints + copy_PolicyInformation + copy_PolicyMapping + copy_PolicyMappings + copy_PolicyQualifierId + copy_PolicyQualifierInfo + copy_PolicyQualifierInfos + copy_PreferredOrLegacyPackageIdentifier + copy_PreferredOrLegacyStalePackageIdentifier + copy_PreferredPackageIdentifier + copy_Principal + copy_PrincipalName + copy_Principals + copy_PrivateKeyUsagePeriod + copy_PROV_SRV_LOCATION + copy_ProxyCertInfo + copy_ProxyPolicy + copy_RDNSequence + copy_Realm + copy_RecipientIdentifier + copy_RecipientInfo + copy_RecipientInfos + copy_RelativeDistinguishedName + copy_ReplyKeyPack + copy_ReplyKeyPack_Win2k + copy_RSAPrivateKey + copy_RSAPublicKey + copy_SAMFlags + copy_SecurityLevel + copy_SignatureAlgorithmIdentifier + copy_SignatureValue + copy_SignedData + copy_SignerIdentifier + copy_SignerInfo + copy_SignerInfos + copy_SingleAttribute + copy_SkipCerts + copy_SRVName + copy_StrengthOfFunction + copy_SubjectDirectoryAttributes + copy_SubjectInfoAccessSyntax + copy_SubjectKeyIdentifier + copy_SubjectPublicKeyInfo + copy_TargetHardwareIdentifiers + copy_TBSCertificate + copy_TBSCRLCertList + copy_TD_DH_PARAMETERS + copy_TD_INVALID_CERTIFICATES + copy_TD_TRUSTED_CERTIFIERS + copy_TGS_REP + copy_TGS_REQ + copy_Ticket + copy_TicketFlags + copy_Time + copy_TPMSecurityAssertions + copy_TPMSpecification + copy_TPMVersion + copy_TransitedEncoding + copy_TrustedCA + copy_TrustedCA_Win2k + copy_TypedData + copy_TYPED_DATA + copy_UniqueIdentifier + copy_UnprotectedAttributes + copy_URIReference + copy_UserNotice + copy_ValidationParms + copy_Validity + copy_VendorLoadErrorCode + copy_Version + copy_WrappedFirmwareKey + copy_X520CommonName + copy_X520LocalityName + copy_X520name + copy_X520OrganizationalUnitName + copy_X520OrganizationName + copy_X520StateOrProvinceName + copy_X690SampleChildInformation + copy_X690SampleDate + copy_X690SampleEmployeeNumber + copy_X690SampleName + copy_X690SamplePersonnelRecord + decode_AccessDescription + decode_AD_AND_OR + decode_AD_IF_RELEVANT + decode_AD_INITIAL_VERIFIED_CAS + decode_AD_KDCIssued + decode_AD_LoginAlias + decode_AD_MANDATORY_FOR_KDC + decode_AlgorithmIdentifier + decode_AliasIA5String + decode_AliasPrintableString + decode_AliasUTF8String + decode_APOptions + decode_AP_REP + decode_AP_REQ + decode_AS_REP + decode_AS_REQ + decode_Attribute + decode_AttributeSet + decode_AttributeType + decode_AttributeTypeAndValue + decode_AttributeValue + decode_AttributeValues + decode_AUTHDATA_TYPE + decode_Authenticator + decode_AuthorityInfoAccessSyntax + decode_AuthorityKeyIdentifier + decode_AuthorizationData + decode_AuthorizationDataElement + decode_AuthPack + decode_AuthPack_Win2k + decode_BaseDistance + decode_BasicConstraints + decode_Certificate + decode_CertificateList + decode_CertificatePolicies + decode_CertificateRevocationLists + decode_Certificates + decode_CertificateSerialNumber + decode_CertificateSet + decode_CertificationRequest + decode_CertificationRequestInfo + decode_CertPolicyId + decode_ChangePasswdDataMS + decode_Checksum + decode_CKSUMTYPE + decode_CMSAttributes + decode_CMSCBCParameter + decode_CMSEncryptedData + decode_CMSIdentifier + decode_CMSRC2CBCParameter + decode_CMSVersion + decode_CommonCriteriaMeasures + decode_CommunityIdentifier + decode_CommunityIdentifiers + decode_CompositePrincipal + decode_ContentEncryptionAlgorithmIdentifier + decode_ContentInfo + decode_ContentType + decode_CPSuri + decode_CRIAttributeSet + decode_CRIExtensions + decode_CRIExtensions + decode_CRLCertificateList + decode_CRLDistributionPoints + decode_CRLReason + decode_CurrentFWConfig + decode_DecryptKeyIdentifier + decode_DHNonce + decode_DHParameter + decode_DHPublicKey + decode_DHRepInfo + decode_DigestAlgorithmIdentifier + decode_DigestAlgorithmIdentifiers + decode_DigestError + decode_DigestInfo + decode_DigestInit + decode_DigestInitReply + decode_DigestREP + decode_DigestRepInner + decode_DigestREQ + decode_DigestReqInner + decode_DigestRequest + decode_DigestResponse + decode_DigestTypes + decode_DirectoryString + decode_DisplayText + decode_DistributionPoint + decode_DistributionPointName + decode_DistributionPointReasonFlags + decode_DomainParameters + decode_DSAParams + decode_DSAPublicKey + decode_DSASigValue + decode_ECDSA_Sig_Value + decode_ECParameters + decode_ECPoint + decode_EKCertificateGenerationLocation + decode_EKGenerationLocation + decode_EKGenerationType + decode_EncAPRepPart + decode_EncapsulatedContentInfo + decode_EncASRepPart + decode_EncKDCRepPart + decode_EncKrbCredPart + decode_EncKrbPrivPart + decode_EncryptedContent + decode_EncryptedContentInfo + decode_EncryptedData + decode_EncryptedKey + decode_EncryptionKey + decode_EncTGSRepPart + decode_EncTicketPart + decode_ENCTYPE + decode_EnvelopedData + decode_ETYPE_INFO + decode_ETYPE_INFO2 + decode_ETYPE_INFO2_ENTRY + decode_ETYPE_INFO_ENTRY + decode_EtypeList + decode_EvaluationAssuranceLevel + decode_EvaluationStatus + decode_Extension + decode_Extensions + decode_ExternalPrincipalIdentifier + decode_ExternalPrincipalIdentifiers + decode_ExtKeyUsage + decode_FastOptions + decode_FIPSLevel + decode_FirmwarePackageIdentifier + decode_FirmwarePackageInfo + decode_FirmwarePackageLoadError + decode_FirmwarePackageLoadErrorCode + decode_FirmwarePackageLoadReceipt + decode_FirmwarePkgData + decode_FWErrorVersion + decode_FWReceiptVersion + decode_GeneralName + decode_GeneralNames + decode_GeneralSubtree + decode_GeneralSubtrees + decode_HardwareModuleName + decode_HardwareModules + decode_HardwareSerialEntry + decode_heim_any + decode_HEIM_ANY + decode_heim_any_set + decode_HEIM_ANY_SET + decode_HostAddress + decode_HostAddresses + decode_ImplementedCompressAlgorithms + decode_ImplementedCryptoAlgorithms + decode_IOSCertificationRequest + decode_IOSCertificationRequest + decode_IOSCertificationRequestInfo + decode_IOSCertificationRequestInfo + decode_IssuerAndSerialNumber + decode_KDCDHKeyInfo + decode_KDCDHKeyInfo_Win2k + decode_KDCFastCookie + decode_KDCFastFlags + decode_KDCFastState + decode_KDCOptions + decode_KDC_PROXY_MESSAGE + decode_KDC_REP + decode_KDC_REQ + decode_KDC_REQ_BODY + decode_KDFAlgorithmId + decode_KERB_AD_RESTRICTION_ENTRY + decode_KERB_ARMOR_SERVICE_REPLY + decode_KERB_CRED + decode_KerberosString + decode_KerberosTime + decode_KERB_ERROR_DATA + decode_KERB_TGS_REP_IN + decode_KERB_TGS_REP_OUT + decode_KERB_TGS_REQ_IN + decode_KERB_TGS_REQ_OUT + decode_KERB_TIMES + decode_KeyEncryptionAlgorithmIdentifier + decode_KeyIdentifier + decode_KeyTransRecipientInfo + decode_KeyUsage + decode_Krb5Int32 + decode_KRB5PrincipalName + decode_Krb5UInt32 + decode_KRB_CRED + decode_KrbCredInfo + decode_KRB_ERROR + decode_KrbFastArmor + decode_KrbFastArmoredRep + decode_KrbFastArmoredReq + decode_KrbFastFinished + decode_KrbFastReq + decode_KrbFastResponse + decode_KRB_PRIV + decode_KRB_SAFE + decode_KRB_SAFE_BODY + decode_Kx509CSRPlus + decode_Kx509ErrorCode + decode_KX509_ERROR_CODE + decode_Kx509Request + decode_Kx509Response + decode_LastReq + decode_LR_TYPE + decode_MessageDigest + decode_MESSAGE_TYPE + decode_METHOD_DATA + decode_MS_UPN_SAN + decode_Name + decode_NameConstraints + decode_NAME_TYPE + decode_NoticeReference + decode_NTLMInit + decode_NTLMInitReply + decode_NTLMReply + decode_NTLMRequest + decode_NTLMRequest2 + decode_NTLMResponse + decode_OCSPBasicOCSPResponse + decode_OCSPCertID + decode_OCSPCertStatus + decode_OCSPInnerRequest + decode_OCSPKeyHash + decode_OCSPRequest + decode_OCSPResponderID + decode_OCSPResponse + decode_OCSPResponseBytes + decode_OCSPResponseData + decode_OCSPResponseStatus + decode_OCSPSignature + decode_OCSPSingleResponse + decode_OCSPTBSRequest + decode_OCSPVersion + decode_OriginatorInfo + decode_OtherName + decode_PA_DATA + decode_PADATA_TYPE + decode_PA_ENC_SAM_RESPONSE_ENC + decode_PA_ENC_TS_ENC + decode_PA_FX_FAST_REPLY + decode_PA_FX_FAST_REQUEST + decode_PA_KERB_KEY_LIST_REP + decode_PA_KERB_KEY_LIST_REQ + decode_PA_PAC_OPTIONS + decode_PA_PAC_REQUEST + decode_PA_PK_AS_REP + decode_PA_PK_AS_REP_BTMM + decode_PA_PK_AS_REP_Win2k + decode_PA_PK_AS_REQ + decode_PA_PK_AS_REQ_Win2k + decode_PA_S4U_X509_USER + decode_PA_S4U2Self + decode_PA_SAM_CHALLENGE_2 + decode_PA_SAM_CHALLENGE_2_BODY + decode_PA_SAM_REDIRECT + decode_PA_SAM_RESPONSE_2 + decode_PA_SAM_TYPE + decode_PA_ServerReferralData + decode_PA_SERVER_REFERRAL_DATA + decode_PA_SvrReferralData + decode_PermanentIdentifier + decode_PKAuthenticator + decode_PKAuthenticator_Win2k + decode_PKCS12_Attribute + decode_PKCS12_Attributes + decode_PKCS12_AuthenticatedSafe + decode_PKCS12_CertBag + decode_PKCS12_MacData + decode_PKCS12_OctetString + decode_PKCS12_PBEParams + decode_PKCS12_PFX + decode_PKCS12_SafeBag + decode_PKCS12_SafeContents + decode_PKCS8Attributes + decode_PKCS8EncryptedData + decode_PKCS8EncryptedPrivateKeyInfo + decode_PKCS8PrivateKey + decode_PKCS8PrivateKeyAlgorithmIdentifier + decode_PKCS8PrivateKeyInfo + decode_PKCS9_BMPString + decode_PKCS9_friendlyName + decode_PkinitSP80056AOtherInfo + decode_PkinitSuppPubInfo + decode_PKIXXmppAddr + decode_PolicyConstraints + decode_PolicyInformation + decode_PolicyMapping + decode_PolicyMappings + decode_PolicyQualifierId + decode_PolicyQualifierInfo + decode_PolicyQualifierInfos + decode_PreferredOrLegacyPackageIdentifier + decode_PreferredOrLegacyStalePackageIdentifier + decode_PreferredPackageIdentifier + decode_Principal + decode_PrincipalName + decode_Principals + decode_PrivateKeyUsagePeriod + decode_PROV_SRV_LOCATION + decode_ProxyCertInfo + decode_ProxyPolicy + decode_RDNSequence + decode_Realm + decode_RecipientIdentifier + decode_RecipientInfo + decode_RecipientInfos + decode_RelativeDistinguishedName + decode_ReplyKeyPack + decode_ReplyKeyPack_Win2k + decode_RSAPrivateKey + decode_RSAPublicKey + decode_SAMFlags + decode_SecurityLevel + decode_SignatureAlgorithmIdentifier + decode_SignatureValue + decode_SignedData + decode_SignerIdentifier + decode_SignerInfo + decode_SignerInfos + decode_SingleAttribute + decode_SkipCerts + decode_SRVName + decode_StrengthOfFunction + decode_SubjectDirectoryAttributes + decode_SubjectInfoAccessSyntax + decode_SubjectKeyIdentifier + decode_SubjectPublicKeyInfo + decode_TargetHardwareIdentifiers + decode_TBSCertificate + decode_TBSCRLCertList + decode_TD_DH_PARAMETERS + decode_TD_INVALID_CERTIFICATES + decode_TD_TRUSTED_CERTIFIERS + decode_TGS_REP + decode_TGS_REQ + decode_Ticket + decode_TicketFlags + decode_Time + decode_TPMSecurityAssertions + decode_TPMSpecification + decode_TPMVersion + decode_TransitedEncoding + decode_TrustedCA + decode_TrustedCA_Win2k + decode_TypedData + decode_TYPED_DATA + decode_UniqueIdentifier + decode_UnprotectedAttributes + decode_URIReference + decode_UserNotice + decode_ValidationParms + decode_Validity + decode_VendorLoadErrorCode + decode_Version + decode_WrappedFirmwareKey + decode_X520CommonName + decode_X520LocalityName + decode_X520name + decode_X520OrganizationalUnitName + decode_X520OrganizationName + decode_X520StateOrProvinceName + decode_X690SampleChildInformation + decode_X690SampleDate + decode_X690SampleEmployeeNumber + decode_X690SampleName + decode_X690SamplePersonnelRecord + der_copy_bit_string + der_copy_bmp_string + der_copy_generalized_time + der_copy_general_string + der_copy_heim_integer + der_copy_ia5_string + der_copy_integer + der_copy_integer64 + der_copy_octet_string + der_copy_oid + der_copy_printable_string + der_copy_universal_string + der_copy_unsigned + der_copy_unsigned64 + der_copy_utctime + der_copy_utf8string + der_copy_visible_string + der_find_heim_oid_by_name + der_find_heim_oid_by_oid + der_find_or_parse_heim_oid + der_free_bit_string + der_free_bmp_string + der_free_generalized_time + der_free_general_string + der_free_heim_integer + der_free_ia5_string + der_free_integer + der_free_integer64 + der_free_octet_string + der_free_oid + der_free_printable_string + der_free_universal_string + der_free_unsigned + der_free_unsigned64 + der_free_utctime + der_free_utf8string + der_free_visible_string + der_get_bit_string + der_get_bmp_string + der_get_boolean + der_get_class_name + der_get_class_num + der_get_generalized_time + der_get_general_string + der_get_heim_integer + der_get_ia5_string + der_get_integer + der_get_integer64 + der_get_length + der_get_octet_string + der_get_octet_string_ber + der_get_oid + der_get_printable_string + der_get_tag + der_get_tag_name + der_get_tag_num + der_get_type_name + der_get_type_num + der_get_universal_string + der_get_unsigned + der_get_unsigned64 + der_get_utctime + der_get_utf8string + der_get_visible_string + _der_gmtime + der_heim_bit_string_cmp + der_heim_bmp_string_cmp + der_heim_integer_cmp + der_heim_octet_string_cmp + der_heim_oid_cmp + der_heim_universal_string_cmp + der_ia5_string_cmp + der_length_bit_string + der_length_bmp_string + der_length_boolean + der_length_enumerated + der_length_generalized_time + der_length_general_string + der_length_heim_integer + der_length_ia5_string + der_length_integer + der_length_integer64 + der_length_len + der_length_octet_string + der_length_oid + der_length_printable_string + der_length_tag + der_length_universal_string + der_length_unsigned + der_length_unsigned64 + der_length_utctime + der_length_utf8string + der_length_visible_string + der_match_heim_oid_by_name + der_match_tag + der_match_tag2 + der_match_tag_and_length + der_parse_heim_oid + der_parse_hex_heim_integer + der_printable_string_cmp + der_print_bit_string + der_print_bmp_string + der_print_boolean + der_print_generalized_time + der_print_general_string + der_print_heim_integer + der_print_heim_oid + der_print_heim_oid_sym + der_print_hex_heim_integer + der_print_ia5_string + der_print_integer + der_print_integer64 + der_print_octet_string + der_print_oid + der_print_printable_string + der_print_universal_string + der_print_unsigned + der_print_unsigned64 + der_print_utctime + der_print_utf8string + der_print_visible_string + der_put_bit_string + der_put_bmp_string + der_put_boolean + der_put_generalized_time + der_put_general_string + der_put_heim_integer + der_put_ia5_string + der_put_integer + der_put_integer64 + der_put_length + der_put_length_and_tag + der_put_octet_string + der_put_oid + der_put_printable_string + der_put_tag + der_put_universal_string + der_put_unsigned + der_put_unsigned64 + der_put_utctime + der_put_utf8string + der_put_visible_string + der_replace_tag + _der_timegm + DigestTypes2int + DistributionPointReasonFlags2int + encode_AccessDescription + encode_AD_AND_OR + encode_AD_IF_RELEVANT + encode_AD_INITIAL_VERIFIED_CAS + encode_AD_KDCIssued + encode_AD_LoginAlias + encode_AD_MANDATORY_FOR_KDC + encode_AlgorithmIdentifier + encode_AliasIA5String + encode_AliasPrintableString + encode_AliasUTF8String + encode_APOptions + encode_AP_REP + encode_AP_REQ + encode_AS_REP + encode_AS_REQ + encode_Attribute + encode_AttributeSet + encode_AttributeType + encode_AttributeTypeAndValue + encode_AttributeValue + encode_AttributeValues + encode_AUTHDATA_TYPE + encode_Authenticator + encode_AuthorityInfoAccessSyntax + encode_AuthorityKeyIdentifier + encode_AuthorizationData + encode_AuthorizationDataElement + encode_AuthPack + encode_AuthPack_Win2k + encode_BaseDistance + encode_BasicConstraints + encode_Certificate + encode_CertificateList + encode_CertificatePolicies + encode_CertificateRevocationLists + encode_Certificates + encode_CertificateSerialNumber + encode_CertificateSet + encode_CertificationRequest + encode_CertificationRequestInfo + encode_CertPolicyId + encode_ChangePasswdDataMS + encode_Checksum + encode_CKSUMTYPE + encode_CMSAttributes + encode_CMSCBCParameter + encode_CMSEncryptedData + encode_CMSIdentifier + encode_CMSRC2CBCParameter + encode_CMSVersion + encode_CommonCriteriaMeasures + encode_CommunityIdentifier + encode_CommunityIdentifiers + encode_CompositePrincipal + encode_ContentEncryptionAlgorithmIdentifier + encode_ContentInfo + encode_ContentType + encode_CPSuri + encode_CRIAttributeSet + encode_CRIExtensions + encode_CRIExtensions + encode_CRLCertificateList + encode_CRLDistributionPoints + encode_CRLReason + encode_CurrentFWConfig + encode_DecryptKeyIdentifier + encode_DHNonce + encode_DHParameter + encode_DHPublicKey + encode_DHRepInfo + encode_DigestAlgorithmIdentifier + encode_DigestAlgorithmIdentifiers + encode_DigestError + encode_DigestInfo + encode_DigestInit + encode_DigestInitReply + encode_DigestREP + encode_DigestRepInner + encode_DigestREQ + encode_DigestReqInner + encode_DigestRequest + encode_DigestResponse + encode_DigestTypes + encode_DirectoryString + encode_DisplayText + encode_DistributionPoint + encode_DistributionPointName + encode_DistributionPointReasonFlags + encode_DomainParameters + encode_DSAParams + encode_DSAPublicKey + encode_DSASigValue + encode_ECDSA_Sig_Value + encode_ECParameters + encode_ECPoint + encode_EKCertificateGenerationLocation + encode_EKGenerationLocation + encode_EKGenerationType + encode_EncAPRepPart + encode_EncapsulatedContentInfo + encode_EncASRepPart + encode_EncKDCRepPart + encode_EncKrbCredPart + encode_EncKrbPrivPart + encode_EncryptedContent + encode_EncryptedContentInfo + encode_EncryptedData + encode_EncryptedKey + encode_EncryptionKey + encode_EncTGSRepPart + encode_EncTicketPart + encode_ENCTYPE + encode_EnvelopedData + encode_ETYPE_INFO + encode_ETYPE_INFO2 + encode_ETYPE_INFO2_ENTRY + encode_ETYPE_INFO_ENTRY + encode_EtypeList + encode_EvaluationAssuranceLevel + encode_EvaluationStatus + encode_Extension + encode_Extensions + encode_ExternalPrincipalIdentifier + encode_ExternalPrincipalIdentifiers + encode_ExtKeyUsage + encode_FastOptions + encode_FIPSLevel + encode_FirmwarePackageIdentifier + encode_FirmwarePackageInfo + encode_FirmwarePackageLoadError + encode_FirmwarePackageLoadErrorCode + encode_FirmwarePackageLoadReceipt + encode_FirmwarePkgData + encode_FWErrorVersion + encode_FWReceiptVersion + encode_GeneralName + encode_GeneralNames + encode_GeneralSubtree + encode_GeneralSubtrees + encode_HardwareModuleName + encode_HardwareModules + encode_HardwareSerialEntry + encode_heim_any + encode_HEIM_ANY + encode_heim_any_set + encode_HEIM_ANY_SET + encode_HostAddress + encode_HostAddresses + encode_ImplementedCompressAlgorithms + encode_ImplementedCryptoAlgorithms + encode_IOSCertificationRequest + encode_IOSCertificationRequest + encode_IOSCertificationRequestInfo + encode_IOSCertificationRequestInfo + encode_IssuerAndSerialNumber + encode_KDCDHKeyInfo + encode_KDCDHKeyInfo_Win2k + encode_KDCFastCookie + encode_KDCFastFlags + encode_KDCFastState + encode_KDCOptions + encode_KDC_PROXY_MESSAGE + encode_KDC_REP + encode_KDC_REQ + encode_KDC_REQ_BODY + encode_KDFAlgorithmId + encode_KERB_AD_RESTRICTION_ENTRY + encode_KERB_ARMOR_SERVICE_REPLY + encode_KERB_CRED + encode_KerberosString + encode_KerberosTime + encode_KERB_ERROR_DATA + encode_KERB_TGS_REP_IN + encode_KERB_TGS_REP_OUT + encode_KERB_TGS_REQ_IN + encode_KERB_TGS_REQ_OUT + encode_KERB_TIMES + encode_KeyEncryptionAlgorithmIdentifier + encode_KeyIdentifier + encode_KeyTransRecipientInfo + encode_KeyUsage + encode_Krb5Int32 + encode_KRB5PrincipalName + encode_Krb5UInt32 + encode_KRB_CRED + encode_KrbCredInfo + encode_KRB_ERROR + encode_KrbFastArmor + encode_KrbFastArmoredRep + encode_KrbFastArmoredReq + encode_KrbFastFinished + encode_KrbFastReq + encode_KrbFastResponse + encode_KRB_PRIV + encode_KRB_SAFE + encode_KRB_SAFE_BODY + encode_Kx509CSRPlus + encode_Kx509ErrorCode + encode_KX509_ERROR_CODE + encode_Kx509Request + encode_Kx509Response + encode_LastReq + encode_LR_TYPE + encode_MessageDigest + encode_MESSAGE_TYPE + encode_METHOD_DATA + encode_MS_UPN_SAN + encode_Name + encode_NameConstraints + encode_NAME_TYPE + encode_NoticeReference + encode_NTLMInit + encode_NTLMInitReply + encode_NTLMReply + encode_NTLMRequest + encode_NTLMRequest2 + encode_NTLMResponse + encode_OCSPBasicOCSPResponse + encode_OCSPCertID + encode_OCSPCertStatus + encode_OCSPInnerRequest + encode_OCSPKeyHash + encode_OCSPRequest + encode_OCSPResponderID + encode_OCSPResponse + encode_OCSPResponseBytes + encode_OCSPResponseData + encode_OCSPResponseStatus + encode_OCSPSignature + encode_OCSPSingleResponse + encode_OCSPTBSRequest + encode_OCSPVersion + encode_OriginatorInfo + encode_OtherName + encode_PA_DATA + encode_PADATA_TYPE + encode_PA_ENC_SAM_RESPONSE_ENC + encode_PA_ENC_TS_ENC + encode_PA_FX_FAST_REPLY + encode_PA_FX_FAST_REQUEST + encode_PA_KERB_KEY_LIST_REP + encode_PA_KERB_KEY_LIST_REQ + encode_PA_PAC_OPTIONS + encode_PA_PAC_REQUEST + encode_PA_PK_AS_REP + encode_PA_PK_AS_REP_BTMM + encode_PA_PK_AS_REP_Win2k + encode_PA_PK_AS_REQ + encode_PA_PK_AS_REQ_Win2k + encode_PA_S4U_X509_USER + encode_PA_S4U2Self + encode_PA_SAM_CHALLENGE_2 + encode_PA_SAM_CHALLENGE_2_BODY + encode_PA_SAM_REDIRECT + encode_PA_SAM_RESPONSE_2 + encode_PA_SAM_TYPE + encode_PA_ServerReferralData + encode_PA_SERVER_REFERRAL_DATA + encode_PA_SvrReferralData + encode_PermanentIdentifier + encode_PKAuthenticator + encode_PKAuthenticator_Win2k + encode_PKCS12_Attribute + encode_PKCS12_Attributes + encode_PKCS12_AuthenticatedSafe + encode_PKCS12_CertBag + encode_PKCS12_MacData + encode_PKCS12_OctetString + encode_PKCS12_PBEParams + encode_PKCS12_PFX + encode_PKCS12_SafeBag + encode_PKCS12_SafeContents + encode_PKCS8Attributes + encode_PKCS8EncryptedData + encode_PKCS8EncryptedPrivateKeyInfo + encode_PKCS8PrivateKey + encode_PKCS8PrivateKeyAlgorithmIdentifier + encode_PKCS8PrivateKeyInfo + encode_PKCS9_BMPString + encode_PKCS9_friendlyName + encode_PkinitSP80056AOtherInfo + encode_PkinitSuppPubInfo + encode_PKIXXmppAddr + encode_PolicyConstraints + encode_PolicyInformation + encode_PolicyMapping + encode_PolicyMappings + encode_PolicyQualifierId + encode_PolicyQualifierInfo + encode_PolicyQualifierInfos + encode_PreferredOrLegacyPackageIdentifier + encode_PreferredOrLegacyStalePackageIdentifier + encode_PreferredPackageIdentifier + encode_Principal + encode_PrincipalName + encode_Principals + encode_PrivateKeyUsagePeriod + encode_PROV_SRV_LOCATION + encode_ProxyCertInfo + encode_ProxyPolicy + encode_RDNSequence + encode_Realm + encode_RecipientIdentifier + encode_RecipientInfo + encode_RecipientInfos + encode_RelativeDistinguishedName + encode_ReplyKeyPack + encode_ReplyKeyPack_Win2k + encode_RSAPrivateKey + encode_RSAPublicKey + encode_SAMFlags + encode_SecurityLevel + encode_SignatureAlgorithmIdentifier + encode_SignatureValue + encode_SignedData + encode_SignerIdentifier + encode_SignerInfo + encode_SignerInfos + encode_SingleAttribute + encode_SkipCerts + encode_SRVName + encode_StrengthOfFunction + encode_SubjectDirectoryAttributes + encode_SubjectInfoAccessSyntax + encode_SubjectKeyIdentifier + encode_SubjectPublicKeyInfo + encode_TargetHardwareIdentifiers + encode_TBSCertificate + encode_TBSCRLCertList + encode_TD_DH_PARAMETERS + encode_TD_INVALID_CERTIFICATES + encode_TD_TRUSTED_CERTIFIERS + encode_TGS_REP + encode_TGS_REQ + encode_Ticket + encode_TicketFlags + encode_Time + encode_TPMSecurityAssertions + encode_TPMSpecification + encode_TPMVersion + encode_TransitedEncoding + encode_TrustedCA + encode_TrustedCA_Win2k + encode_TypedData + encode_TYPED_DATA + encode_UniqueIdentifier + encode_UnprotectedAttributes + encode_URIReference + encode_UserNotice + encode_ValidationParms + encode_Validity + encode_VendorLoadErrorCode + encode_Version + encode_WrappedFirmwareKey + encode_X520CommonName + encode_X520LocalityName + encode_X520name + encode_X520OrganizationalUnitName + encode_X520OrganizationName + encode_X520StateOrProvinceName + encode_X690SampleChildInformation + encode_X690SampleDate + encode_X690SampleEmployeeNumber + encode_X690SampleName + encode_X690SamplePersonnelRecord + FastOptions2int + free_AccessDescription + free_AD_AND_OR + free_AD_IF_RELEVANT + free_AD_INITIAL_VERIFIED_CAS + free_AD_KDCIssued + free_AD_LoginAlias + free_AD_MANDATORY_FOR_KDC + free_AlgorithmIdentifier + free_AliasIA5String + free_AliasPrintableString + free_AliasUTF8String + free_APOptions + free_AP_REP + free_AP_REQ + free_AS_REP + free_AS_REQ + free_Attribute + free_AttributeSet + free_AttributeType + free_AttributeTypeAndValue + free_AttributeValue + free_AttributeValues + free_AUTHDATA_TYPE + free_Authenticator + free_AuthorityInfoAccessSyntax + free_AuthorityKeyIdentifier + free_AuthorizationData + free_AuthorizationDataElement + free_AuthPack + free_AuthPack_Win2k + free_BaseDistance + free_BasicConstraints + free_Certificate + free_CertificateList + free_CertificatePolicies + free_CertificateRevocationLists + free_Certificates + free_CertificateSerialNumber + free_CertificateSet + free_CertificationRequest + free_CertificationRequestInfo + free_CertPolicyId + free_ChangePasswdDataMS + free_Checksum + free_CKSUMTYPE + free_CMSAttributes + free_CMSCBCParameter + free_CMSEncryptedData + free_CMSIdentifier + free_CMSRC2CBCParameter + free_CMSVersion + free_CommonCriteriaMeasures + free_CommunityIdentifier + free_CommunityIdentifiers + free_CompositePrincipal + free_ContentEncryptionAlgorithmIdentifier + free_ContentInfo + free_ContentType + free_CPSuri + free_CRIAttributeSet + free_CRIExtensions + free_CRIExtensions + free_CRLCertificateList + free_CRLDistributionPoints + free_CRLReason + free_CurrentFWConfig + free_DecryptKeyIdentifier + free_DHNonce + free_DHParameter + free_DHPublicKey + free_DHRepInfo + free_DigestAlgorithmIdentifier + free_DigestAlgorithmIdentifiers + free_DigestError + free_DigestInfo + free_DigestInit + free_DigestInitReply + free_DigestREP + free_DigestRepInner + free_DigestREQ + free_DigestReqInner + free_DigestRequest + free_DigestResponse + free_DigestTypes + free_DirectoryString + free_DisplayText + free_DistributionPoint + free_DistributionPointName + free_DistributionPointReasonFlags + free_DomainParameters + free_DSAParams + free_DSAPublicKey + free_DSASigValue + free_ECDSA_Sig_Value + free_ECParameters + free_ECPoint + free_EKCertificateGenerationLocation + free_EKGenerationLocation + free_EKGenerationType + free_EncAPRepPart + free_EncapsulatedContentInfo + free_EncASRepPart + free_EncKDCRepPart + free_EncKrbCredPart + free_EncKrbPrivPart + free_EncryptedContent + free_EncryptedContentInfo + free_EncryptedData + free_EncryptedKey + free_EncryptionKey + free_EncTGSRepPart + free_EncTicketPart + free_ENCTYPE + free_EnvelopedData + free_ETYPE_INFO + free_ETYPE_INFO2 + free_ETYPE_INFO2_ENTRY + free_ETYPE_INFO_ENTRY + free_EtypeList + free_EvaluationAssuranceLevel + free_EvaluationStatus + free_Extension + free_Extensions + free_ExternalPrincipalIdentifier + free_ExternalPrincipalIdentifiers + free_ExtKeyUsage + free_FastOptions + free_FIPSLevel + free_FirmwarePackageIdentifier + free_FirmwarePackageInfo + free_FirmwarePackageLoadError + free_FirmwarePackageLoadErrorCode + free_FirmwarePackageLoadReceipt + free_FirmwarePkgData + free_FWErrorVersion + free_FWReceiptVersion + free_GeneralName + free_GeneralNames + free_GeneralSubtree + free_GeneralSubtrees + free_HardwareModuleName + free_HardwareModules + free_HardwareSerialEntry + free_heim_any + free_HEIM_ANY + free_heim_any_set + free_HEIM_ANY_SET + free_HostAddress + free_HostAddresses + free_ImplementedCompressAlgorithms + free_ImplementedCryptoAlgorithms + free_IOSCertificationRequest + free_IOSCertificationRequest + free_IOSCertificationRequestInfo + free_IOSCertificationRequestInfo + free_IssuerAndSerialNumber + free_KDCDHKeyInfo + free_KDCDHKeyInfo_Win2k + free_KDCFastCookie + free_KDCFastFlags + free_KDCFastState + free_KDCOptions + free_KDC_PROXY_MESSAGE + free_KDC_REP + free_KDC_REQ + free_KDC_REQ_BODY + free_KDFAlgorithmId + free_KERB_AD_RESTRICTION_ENTRY + free_KERB_ARMOR_SERVICE_REPLY + free_KERB_CRED + free_KerberosString + free_KerberosTime + free_KERB_ERROR_DATA + free_KERB_TGS_REP_IN + free_KERB_TGS_REP_OUT + free_KERB_TGS_REQ_IN + free_KERB_TGS_REQ_OUT + free_KERB_TIMES + free_KeyEncryptionAlgorithmIdentifier + free_KeyIdentifier + free_KeyTransRecipientInfo + free_KeyUsage + free_Krb5Int32 + free_KRB5PrincipalName + free_Krb5UInt32 + free_KRB_CRED + free_KrbCredInfo + free_KRB_ERROR + free_KrbFastArmor + free_KrbFastArmoredRep + free_KrbFastArmoredReq + free_KrbFastFinished + free_KrbFastReq + free_KrbFastResponse + free_KRB_PRIV + free_KRB_SAFE + free_KRB_SAFE_BODY + free_Kx509CSRPlus + free_Kx509ErrorCode + free_KX509_ERROR_CODE + free_Kx509Request + free_Kx509Response + free_LastReq + free_LR_TYPE + free_MessageDigest + free_MESSAGE_TYPE + free_METHOD_DATA + free_MS_UPN_SAN + free_Name + free_NameConstraints + free_NAME_TYPE + free_NoticeReference + free_NTLMInit + free_NTLMInitReply + free_NTLMReply + free_NTLMRequest + free_NTLMRequest2 + free_NTLMResponse + free_OCSPBasicOCSPResponse + free_OCSPCertID + free_OCSPCertStatus + free_OCSPInnerRequest + free_OCSPKeyHash + free_OCSPRequest + free_OCSPResponderID + free_OCSPResponse + free_OCSPResponseBytes + free_OCSPResponseData + free_OCSPResponseStatus + free_OCSPSignature + free_OCSPSingleResponse + free_OCSPTBSRequest + free_OCSPVersion + free_OriginatorInfo + free_OtherName + free_PA_DATA + free_PADATA_TYPE + free_PA_ENC_SAM_RESPONSE_ENC + free_PA_ENC_TS_ENC + free_PA_FX_FAST_REPLY + free_PA_FX_FAST_REQUEST + free_PA_KERB_KEY_LIST_REP + free_PA_KERB_KEY_LIST_REQ + free_PA_PAC_OPTIONS + free_PA_PAC_REQUEST + free_PA_PK_AS_REP + free_PA_PK_AS_REP_BTMM + free_PA_PK_AS_REP_Win2k + free_PA_PK_AS_REQ + free_PA_PK_AS_REQ_Win2k + free_PA_S4U_X509_USER + free_PA_S4U2Self + free_PA_SAM_CHALLENGE_2 + free_PA_SAM_CHALLENGE_2_BODY + free_PA_SAM_REDIRECT + free_PA_SAM_RESPONSE_2 + free_PA_SAM_TYPE + free_PA_ServerReferralData + free_PA_SERVER_REFERRAL_DATA + free_PA_SvrReferralData + free_PermanentIdentifier + free_PKAuthenticator + free_PKAuthenticator_Win2k + free_PKCS12_Attribute + free_PKCS12_Attributes + free_PKCS12_AuthenticatedSafe + free_PKCS12_CertBag + free_PKCS12_MacData + free_PKCS12_OctetString + free_PKCS12_PBEParams + free_PKCS12_PFX + free_PKCS12_SafeBag + free_PKCS12_SafeContents + free_PKCS8Attributes + free_PKCS8EncryptedData + free_PKCS8EncryptedPrivateKeyInfo + free_PKCS8PrivateKey + free_PKCS8PrivateKeyAlgorithmIdentifier + free_PKCS8PrivateKeyInfo + free_PKCS9_BMPString + free_PKCS9_friendlyName + free_PkinitSP80056AOtherInfo + free_PkinitSuppPubInfo + free_PKIXXmppAddr + free_PolicyConstraints + free_PolicyInformation + free_PolicyMapping + free_PolicyMappings + free_PolicyQualifierId + free_PolicyQualifierInfo + free_PolicyQualifierInfos + free_PreferredOrLegacyPackageIdentifier + free_PreferredOrLegacyStalePackageIdentifier + free_PreferredPackageIdentifier + free_Principal + free_PrincipalName + free_Principals + free_PrivateKeyUsagePeriod + free_PROV_SRV_LOCATION + free_ProxyCertInfo + free_ProxyPolicy + free_RDNSequence + free_Realm + free_RecipientIdentifier + free_RecipientInfo + free_RecipientInfos + free_RelativeDistinguishedName + free_ReplyKeyPack + free_ReplyKeyPack_Win2k + free_RSAPrivateKey + free_RSAPublicKey + free_SAMFlags + free_SecurityLevel + free_SignatureAlgorithmIdentifier + free_SignatureValue + free_SignedData + free_SignerIdentifier + free_SignerInfo + free_SignerInfos + free_SingleAttribute + free_SkipCerts + free_SRVName + free_StrengthOfFunction + free_SubjectDirectoryAttributes + free_SubjectInfoAccessSyntax + free_SubjectKeyIdentifier + free_SubjectPublicKeyInfo + free_TargetHardwareIdentifiers + free_TBSCertificate + free_TBSCRLCertList + free_TD_DH_PARAMETERS + free_TD_INVALID_CERTIFICATES + free_TD_TRUSTED_CERTIFIERS + free_TGS_REP + free_TGS_REQ + free_Ticket + free_TicketFlags + free_Time + free_TPMSecurityAssertions + free_TPMSpecification + free_TPMVersion + free_TransitedEncoding + free_TrustedCA + free_TrustedCA_Win2k + free_TypedData + free_TYPED_DATA + free_UniqueIdentifier + free_UnprotectedAttributes + free_URIReference + free_UserNotice + free_ValidationParms + free_Validity + free_VendorLoadErrorCode + free_Version + free_WrappedFirmwareKey + free_X520CommonName + free_X520LocalityName + free_X520name + free_X520OrganizationalUnitName + free_X520OrganizationName + free_X520StateOrProvinceName + free_X690SampleChildInformation + free_X690SampleDate + free_X690SampleEmployeeNumber + free_X690SampleName + free_X690SamplePersonnelRecord + heim_any_cmp + HEIM_ANY_cmp + _heim_der_set_sort + _heim_fix_dce + _heim_len_int + _heim_len_int64 + _heim_len_unsigned + _heim_len_unsigned64 + _heim_time2generalizedtime + initialize_asn1_error_table + initialize_asn1_error_table_r + int2APOptions + int2DigestTypes + int2DistributionPointReasonFlags + int2FastOptions + int2KDCFastFlags + int2KDCOptions + int2KeyUsage + int2SAMFlags + int2TicketFlags + KDCFastFlags2int + KDCOptions2int + KeyUsage2int + length_AccessDescription + length_AD_AND_OR + length_AD_IF_RELEVANT + length_AD_INITIAL_VERIFIED_CAS + length_AD_KDCIssued + length_AD_LoginAlias + length_AD_MANDATORY_FOR_KDC + length_AlgorithmIdentifier + length_AliasIA5String + length_AliasPrintableString + length_AliasUTF8String + length_APOptions + length_AP_REP + length_AP_REQ + length_AS_REP + length_AS_REQ + length_Attribute + length_AttributeSet + length_AttributeType + length_AttributeTypeAndValue + length_AttributeValue + length_AttributeValues + length_AUTHDATA_TYPE + length_Authenticator + length_AuthorityInfoAccessSyntax + length_AuthorityKeyIdentifier + length_AuthorizationData + length_AuthorizationDataElement + length_AuthPack + length_AuthPack_Win2k + length_BaseDistance + length_BasicConstraints + length_Certificate + length_CertificateList + length_CertificatePolicies + length_CertificateRevocationLists + length_Certificates + length_CertificateSerialNumber + length_CertificateSet + length_CertificationRequest + length_CertificationRequestInfo + length_CertPolicyId + length_ChangePasswdDataMS + length_Checksum + length_CKSUMTYPE + length_CMSAttributes + length_CMSCBCParameter + length_CMSEncryptedData + length_CMSIdentifier + length_CMSRC2CBCParameter + length_CMSVersion + length_CommonCriteriaMeasures + length_CommunityIdentifier + length_CommunityIdentifiers + length_CompositePrincipal + length_ContentEncryptionAlgorithmIdentifier + length_ContentInfo + length_ContentType + length_CPSuri + length_CRIAttributeSet + length_CRIExtensions + length_CRLCertificateList + length_CRLDistributionPoints + length_CRLReason + length_CurrentFWConfig + length_DecryptKeyIdentifier + length_DHNonce + length_DHParameter + length_DHPublicKey + length_DHRepInfo + length_DigestAlgorithmIdentifier + length_DigestAlgorithmIdentifiers + length_DigestError + length_DigestInfo + length_DigestInit + length_DigestInitReply + length_DigestREP + length_DigestRepInner + length_DigestREQ + length_DigestReqInner + length_DigestRequest + length_DigestResponse + length_DigestTypes + length_DirectoryString + length_DisplayText + length_DistributionPoint + length_DistributionPointName + length_DistributionPointReasonFlags + length_DomainParameters + length_DSAParams + length_DSAPublicKey + length_DSASigValue + length_ECDSA_Sig_Value + length_ECParameters + length_ECPoint + length_EKCertificateGenerationLocation + length_EKGenerationLocation + length_EKGenerationType + length_EncAPRepPart + length_EncapsulatedContentInfo + length_EncASRepPart + length_EncKDCRepPart + length_EncKrbCredPart + length_EncKrbPrivPart + length_EncryptedContent + length_EncryptedContentInfo + length_EncryptedData + length_EncryptedKey + length_EncryptionKey + length_EncTGSRepPart + length_EncTicketPart + length_ENCTYPE + length_EnvelopedData + length_ETYPE_INFO + length_ETYPE_INFO2 + length_ETYPE_INFO2_ENTRY + length_ETYPE_INFO_ENTRY + length_EtypeList + length_EvaluationAssuranceLevel + length_EvaluationStatus + length_Extension + length_Extensions + length_ExternalPrincipalIdentifier + length_ExternalPrincipalIdentifiers + length_ExtKeyUsage + length_FastOptions + length_FIPSLevel + length_FirmwarePackageIdentifier + length_FirmwarePackageInfo + length_FirmwarePackageLoadError + length_FirmwarePackageLoadErrorCode + length_FirmwarePackageLoadReceipt + length_FirmwarePkgData + length_FWErrorVersion + length_FWReceiptVersion + length_GeneralName + length_GeneralNames + length_GeneralSubtree + length_GeneralSubtrees + length_HardwareModuleName + length_HardwareModules + length_HardwareSerialEntry + length_heim_any + length_HEIM_ANY + length_heim_any_set + length_HEIM_ANY_SET + length_HostAddress + length_HostAddresses + length_ImplementedCompressAlgorithms + length_ImplementedCryptoAlgorithms + length_IOSCertificationRequest + length_IOSCertificationRequestInfo + length_IssuerAndSerialNumber + length_KDCDHKeyInfo + length_KDCDHKeyInfo_Win2k + length_KDCFastCookie + length_KDCFastFlags + length_KDCFastState + length_KDCOptions + length_KDC_PROXY_MESSAGE + length_KDC_REP + length_KDC_REQ + length_KDC_REQ_BODY + length_KDFAlgorithmId + length_KERB_AD_RESTRICTION_ENTRY + length_KERB_ARMOR_SERVICE_REPLY + length_KERB_CRED + length_KerberosString + length_KerberosTime + length_KERB_ERROR_DATA + length_KERB_TGS_REP_IN + length_KERB_TGS_REP_OUT + length_KERB_TGS_REQ_IN + length_KERB_TGS_REQ_OUT + length_KERB_TIMES + length_KeyEncryptionAlgorithmIdentifier + length_KeyIdentifier + length_KeyTransRecipientInfo + length_KeyUsage + length_Krb5Int32 + length_KRB5PrincipalName + length_Krb5UInt32 + length_KRB_CRED + length_KrbCredInfo + length_KRB_ERROR + length_KrbFastArmor + length_KrbFastArmoredRep + length_KrbFastArmoredReq + length_KrbFastFinished + length_KrbFastReq + length_KrbFastResponse + length_KRB_PRIV + length_KRB_SAFE + length_KRB_SAFE_BODY + length_Kx509CSRPlus + length_Kx509ErrorCode + length_KX509_ERROR_CODE + length_Kx509Request + length_Kx509Response + length_LastReq + length_LR_TYPE + length_MessageDigest + length_MESSAGE_TYPE + length_METHOD_DATA + length_MS_UPN_SAN + length_Name + length_NameConstraints + length_NAME_TYPE + length_NoticeReference + length_NTLMInit + length_NTLMInitReply + length_NTLMReply + length_NTLMRequest + length_NTLMRequest2 + length_NTLMResponse + length_OCSPBasicOCSPResponse + length_OCSPCertID + length_OCSPCertStatus + length_OCSPInnerRequest + length_OCSPKeyHash + length_OCSPRequest + length_OCSPResponderID + length_OCSPResponse + length_OCSPResponseBytes + length_OCSPResponseData + length_OCSPResponseStatus + length_OCSPSignature + length_OCSPSingleResponse + length_OCSPTBSRequest + length_OCSPVersion + length_OriginatorInfo + length_OtherName + length_PA_DATA + length_PADATA_TYPE + length_PA_ENC_SAM_RESPONSE_ENC + length_PA_ENC_TS_ENC + length_PA_FX_FAST_REPLY + length_PA_FX_FAST_REQUEST + length_PA_KERB_KEY_LIST_REP + length_PA_KERB_KEY_LIST_REQ + length_PA_PAC_OPTIONS + length_PA_PAC_REQUEST + length_PA_PK_AS_REP + length_PA_PK_AS_REP_BTMM + length_PA_PK_AS_REP_Win2k + length_PA_PK_AS_REQ + length_PA_PK_AS_REQ_Win2k + length_PA_S4U_X509_USER + length_PA_S4U2Self + length_PA_SAM_CHALLENGE_2 + length_PA_SAM_CHALLENGE_2_BODY + length_PA_SAM_REDIRECT + length_PA_SAM_RESPONSE_2 + length_PA_SAM_TYPE + length_PA_ServerReferralData + length_PA_SERVER_REFERRAL_DATA + length_PA_SvrReferralData + length_PermanentIdentifier + length_PKAuthenticator + length_PKAuthenticator_Win2k + length_PKCS12_Attribute + length_PKCS12_Attributes + length_PKCS12_AuthenticatedSafe + length_PKCS12_CertBag + length_PKCS12_MacData + length_PKCS12_OctetString + length_PKCS12_PBEParams + length_PKCS12_PFX + length_PKCS12_SafeBag + length_PKCS12_SafeContents + length_PKCS8Attributes + length_PKCS8EncryptedData + length_PKCS8EncryptedPrivateKeyInfo + length_PKCS8PrivateKey + length_PKCS8PrivateKeyAlgorithmIdentifier + length_PKCS8PrivateKeyInfo + length_PKCS9_BMPString + length_PKCS9_friendlyName + length_PkinitSP80056AOtherInfo + length_PkinitSuppPubInfo + length_PKIXXmppAddr + length_PolicyConstraints + length_PolicyInformation + length_PolicyMapping + length_PolicyMappings + length_PolicyQualifierId + length_PolicyQualifierInfo + length_PolicyQualifierInfos + length_PreferredOrLegacyPackageIdentifier + length_PreferredOrLegacyStalePackageIdentifier + length_PreferredPackageIdentifier + length_Principal + length_PrincipalName + length_Principals + length_PrivateKeyUsagePeriod + length_PROV_SRV_LOCATION + length_ProxyCertInfo + length_ProxyPolicy + length_RDNSequence + length_Realm + length_RecipientIdentifier + length_RecipientInfo + length_RecipientInfos + length_RelativeDistinguishedName + length_ReplyKeyPack + length_ReplyKeyPack_Win2k + length_RSAPrivateKey + length_RSAPublicKey + length_SAMFlags + length_SecurityLevel + length_SignatureAlgorithmIdentifier + length_SignatureValue + length_SignedData + length_SignerIdentifier + length_SignerInfo + length_SignerInfos + length_SingleAttribute + length_SkipCerts + length_SRVName + length_StrengthOfFunction + length_SubjectDirectoryAttributes + length_SubjectInfoAccessSyntax + length_SubjectKeyIdentifier + length_SubjectPublicKeyInfo + length_TargetHardwareIdentifiers + length_TBSCertificate + length_TBSCRLCertList + length_TD_DH_PARAMETERS + length_TD_INVALID_CERTIFICATES + length_TD_TRUSTED_CERTIFIERS + length_TGS_REP + length_TGS_REQ + length_Ticket + length_TicketFlags + length_Time + length_TPMSecurityAssertions + length_TPMSpecification + length_TPMVersion + length_TransitedEncoding + length_TrustedCA + length_TrustedCA_Win2k + length_TypedData + length_TYPED_DATA + length_UniqueIdentifier + length_UnprotectedAttributes + length_URIReference + length_UserNotice + length_ValidationParms + length_Validity + length_VendorLoadErrorCode + length_Version + length_WrappedFirmwareKey + length_X520CommonName + length_X520LocalityName + length_X520name + length_X520OrganizationalUnitName + length_X520OrganizationName + length_X520StateOrProvinceName + length_X690SampleChildInformation + length_X690SampleDate + length_X690SampleEmployeeNumber + length_X690SampleName + length_X690SamplePersonnelRecord + print_AccessDescription + print_AD_AND_OR + print_AD_IF_RELEVANT + print_AD_INITIAL_VERIFIED_CAS + print_AD_KDCIssued + print_AD_LoginAlias + print_AD_MANDATORY_FOR_KDC + print_AlgorithmIdentifier + print_AliasIA5String + print_AliasPrintableString + print_AliasUTF8String + print_APOptions + print_AP_REP + print_AP_REQ + print_AS_REP + print_AS_REQ + print_Attribute + print_AttributeSet + print_AttributeType + print_AttributeTypeAndValue + print_AttributeValue + print_AttributeValues + print_AUTHDATA_TYPE + print_Authenticator + print_AuthorityInfoAccessSyntax + print_AuthorityKeyIdentifier + print_AuthorizationData + print_AuthorizationDataElement + print_AuthPack + print_AuthPack_Win2k + print_BaseDistance + print_BasicConstraints + print_Certificate + print_CertificateList + print_CertificatePolicies + print_CertificateRevocationLists + print_Certificates + print_CertificateSerialNumber + print_CertificateSet + print_CertificationRequest + print_CertificationRequestInfo + print_CertPolicyId + print_ChangePasswdDataMS + print_Checksum + print_CKSUMTYPE + print_CMSAttributes + print_CMSCBCParameter + print_CMSEncryptedData + print_CMSIdentifier + print_CMSRC2CBCParameter + print_CMSVersion + print_CommonCriteriaMeasures + print_CommunityIdentifier + print_CommunityIdentifiers + print_CompositePrincipal + print_ContentEncryptionAlgorithmIdentifier + print_ContentInfo + print_ContentType + print_CPSuri + print_CRIAttributeSet + print_CRIExtensions + print_CRIExtensions + print_CRLCertificateList + print_CRLDistributionPoints + print_CRLReason + print_CurrentFWConfig + print_DecryptKeyIdentifier + print_DHNonce + print_DHParameter + print_DHPublicKey + print_DHRepInfo + print_DigestAlgorithmIdentifier + print_DigestAlgorithmIdentifiers + print_DigestError + print_DigestInfo + print_DigestInit + print_DigestInitReply + print_DigestREP + print_DigestRepInner + print_DigestREQ + print_DigestReqInner + print_DigestRequest + print_DigestResponse + print_DigestTypes + print_DirectoryString + print_DisplayText + print_DistributionPoint + print_DistributionPointName + print_DistributionPointReasonFlags + print_DomainParameters + print_DSAParams + print_DSAPublicKey + print_DSASigValue + print_ECDSA_Sig_Value + print_ECParameters + print_ECPoint + print_EKCertificateGenerationLocation + print_EKGenerationLocation + print_EKGenerationType + print_EncAPRepPart + print_EncapsulatedContentInfo + print_EncASRepPart + print_EncKDCRepPart + print_EncKrbCredPart + print_EncKrbPrivPart + print_EncryptedContent + print_EncryptedContentInfo + print_EncryptedData + print_EncryptedKey + print_EncryptionKey + print_EncTGSRepPart + print_EncTicketPart + print_ENCTYPE + print_EnvelopedData + print_ETYPE_INFO + print_ETYPE_INFO2 + print_ETYPE_INFO2_ENTRY + print_ETYPE_INFO_ENTRY + print_EtypeList + print_EvaluationAssuranceLevel + print_EvaluationStatus + print_Extension + print_Extensions + print_ExternalPrincipalIdentifier + print_ExternalPrincipalIdentifiers + print_ExtKeyUsage + print_FastOptions + print_FIPSLevel + print_FirmwarePackageIdentifier + print_FirmwarePackageInfo + print_FirmwarePackageLoadError + print_FirmwarePackageLoadErrorCode + print_FirmwarePackageLoadReceipt + print_FirmwarePkgData + print_FWErrorVersion + print_FWReceiptVersion + print_GeneralName + print_GeneralNames + print_GeneralSubtree + print_GeneralSubtrees + print_HardwareModuleName + print_HardwareModules + print_HardwareSerialEntry + print_heim_any + print_HEIM_ANY + print_heim_any_set + print_HEIM_ANY_SET + print_HostAddress + print_HostAddresses + print_ImplementedCompressAlgorithms + print_ImplementedCryptoAlgorithms + print_IOSCertificationRequest + print_IOSCertificationRequest + print_IOSCertificationRequestInfo + print_IOSCertificationRequestInfo + print_IssuerAndSerialNumber + print_KDCDHKeyInfo + print_KDCDHKeyInfo_Win2k + print_KDCFastCookie + print_KDCFastFlags + print_KDCFastState + print_KDCOptions + print_KDC_PROXY_MESSAGE + print_KDC_REP + print_KDC_REQ + print_KDC_REQ_BODY + print_KDFAlgorithmId + print_KERB_ARMOR_SERVICE_REPLY + print_KERB_CRED + print_KerberosString + print_KerberosTime + print_KERB_ERROR_DATA + print_KERB_TGS_REP_IN + print_KERB_TGS_REP_OUT + print_KERB_TGS_REQ_IN + print_KERB_TGS_REQ_OUT + print_KERB_TIMES + print_KeyEncryptionAlgorithmIdentifier + print_KeyIdentifier + print_KeyTransRecipientInfo + print_KeyUsage + print_Krb5Int32 + print_KRB5PrincipalName + print_Krb5UInt32 + print_KRB_CRED + print_KrbCredInfo + print_KRB_ERROR + print_KrbFastArmor + print_KrbFastArmoredRep + print_KrbFastArmoredReq + print_KrbFastFinished + print_KrbFastReq + print_KrbFastResponse + print_KRB_PRIV + print_KRB_SAFE + print_KRB_SAFE_BODY + print_Kx509CSRPlus + print_Kx509ErrorCode + print_KX509_ERROR_CODE + print_Kx509Request + print_Kx509Response + print_LastReq + print_LR_TYPE + print_MessageDigest + print_MESSAGE_TYPE + print_METHOD_DATA + print_MS_UPN_SAN + print_Name + print_NameConstraints + print_NAME_TYPE + print_NoticeReference + print_NTLMInit + print_NTLMInitReply + print_NTLMReply + print_NTLMRequest + print_NTLMRequest2 + print_NTLMResponse + print_OCSPBasicOCSPResponse + print_OCSPCertID + print_OCSPCertStatus + print_OCSPInnerRequest + print_OCSPKeyHash + print_OCSPRequest + print_OCSPResponderID + print_OCSPResponse + print_OCSPResponseBytes + print_OCSPResponseData + print_OCSPResponseStatus + print_OCSPSignature + print_OCSPSingleResponse + print_OCSPTBSRequest + print_OCSPVersion + print_OriginatorInfo + print_OtherName + print_PA_DATA + print_PADATA_TYPE + print_PA_ENC_SAM_RESPONSE_ENC + print_PA_ENC_TS_ENC + print_PA_FX_FAST_REPLY + print_PA_FX_FAST_REQUEST + print_PA_PAC_REQUEST + print_PA_PK_AS_REP + print_PA_PK_AS_REP_BTMM + print_PA_PK_AS_REP_Win2k + print_PA_PK_AS_REQ + print_PA_PK_AS_REQ_Win2k + print_PA_S4U2Self + print_PA_SAM_CHALLENGE_2 + print_PA_SAM_CHALLENGE_2_BODY + print_PA_SAM_REDIRECT + print_PA_SAM_RESPONSE_2 + print_PA_SAM_TYPE + print_PA_ServerReferralData + print_PA_SERVER_REFERRAL_DATA + print_PA_SvrReferralData + print_PermanentIdentifier + print_PKAuthenticator + print_PKAuthenticator_Win2k + print_PKCS12_Attribute + print_PKCS12_Attributes + print_PKCS12_AuthenticatedSafe + print_PKCS12_CertBag + print_PKCS12_MacData + print_PKCS12_OctetString + print_PKCS12_PBEParams + print_PKCS12_PFX + print_PKCS12_SafeBag + print_PKCS12_SafeContents + print_PKCS8Attributes + print_PKCS8EncryptedData + print_PKCS8EncryptedPrivateKeyInfo + print_PKCS8PrivateKey + print_PKCS8PrivateKeyAlgorithmIdentifier + print_PKCS8PrivateKeyInfo + print_PKCS9_BMPString + print_PKCS9_friendlyName + print_PkinitSP80056AOtherInfo + print_PkinitSuppPubInfo + print_PKIXXmppAddr + print_PolicyConstraints + print_PolicyInformation + print_PolicyMapping + print_PolicyMappings + print_PolicyQualifierId + print_PolicyQualifierInfo + print_PolicyQualifierInfos + print_PreferredOrLegacyPackageIdentifier + print_PreferredOrLegacyStalePackageIdentifier + print_PreferredPackageIdentifier + print_Principal + print_PrincipalName + print_Principals + print_PrivateKeyUsagePeriod + print_PROV_SRV_LOCATION + print_ProxyCertInfo + print_ProxyPolicy + print_RDNSequence + print_Realm + print_RecipientIdentifier + print_RecipientInfo + print_RecipientInfos + print_RelativeDistinguishedName + print_ReplyKeyPack + print_ReplyKeyPack_Win2k + print_RSAPrivateKey + print_RSAPublicKey + print_SAMFlags + print_SecurityLevel + print_SignatureAlgorithmIdentifier + print_SignatureValue + print_SignedData + print_SignerIdentifier + print_SignerInfo + print_SignerInfos + print_SingleAttribute + print_SkipCerts + print_SRVName + print_StrengthOfFunction + print_SubjectDirectoryAttributes + print_SubjectInfoAccessSyntax + print_SubjectKeyIdentifier + print_SubjectPublicKeyInfo + print_TargetHardwareIdentifiers + print_TBSCertificate + print_TBSCRLCertList + print_TD_DH_PARAMETERS + print_TD_INVALID_CERTIFICATES + print_TD_TRUSTED_CERTIFIERS + print_TGS_REP + print_TGS_REQ + print_Ticket + print_TicketFlags + print_Time + print_TPMSecurityAssertions + print_TPMSpecification + print_TPMVersion + print_TransitedEncoding + print_TrustedCA + print_TrustedCA_Win2k + print_TypedData + print_TYPED_DATA + print_UniqueIdentifier + print_UnprotectedAttributes + print_URIReference + print_UserNotice + print_ValidationParms + print_Validity + print_VendorLoadErrorCode + print_Version + print_WrappedFirmwareKey + print_X520CommonName + print_X520LocalityName + print_X520name + print_X520OrganizationalUnitName + print_X520OrganizationName + print_X520StateOrProvinceName + print_X690SampleChildInformation + print_X690SampleDate + print_X690SampleEmployeeNumber + print_X690SampleName + print_X690SamplePersonnelRecord + remove_AttributeValues + remove_AuthorizationData + remove_CertificatePolicies + remove_Certificates + remove_CRLDistributionPoints + remove_DigestAlgorithmIdentifiers + remove_ETYPE_INFO + remove_ETYPE_INFO2 + remove_Extensions + remove_GeneralNames + remove_METHOD_DATA + remove_PolicyMappings + remove_PolicyQualifierInfos + remove_Principals + remove_RDNSequence + SAMFlags2int + TicketFlags2int diff --git a/third_party/heimdal/lib/asn1/main.c b/third_party/heimdal/lib/asn1/main.c new file mode 100644 index 0000000..babcc00 --- /dev/null +++ b/third_party/heimdal/lib/asn1/main.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include +#include "lex.h" + +extern FILE *yyin; + +static getarg_strings preserve; +static getarg_strings seq; +static getarg_strings decorate; + +static int +strcmp4mergesort_r(const void *ap, const void *bp, void *d) +{ + const char *a = *(const char **)ap; + const char *b = *(const char **)bp; + char sep = *(const char *)d; + int cmp; + + if (sep) { + const char *sepa = strchr(a, sep); + const char *sepb = strchr(b, sep); + size_t alen, blen; + + if (sepa == NULL) sepa = a + strlen(a); + if (sepb == NULL) sepb = b + strlen(b); + alen = sepa - a; + blen = sepb - b; + cmp = strncmp(a, b, alen > blen ? alen : blen); + if (cmp == 0) + cmp = alen - blen; + } else + cmp = strcmp(a, b); + if (cmp == 0) + return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */ + return cmp; +} + +static int +prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp) +{ + if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep) + return 1; + if (*cmp == 0) + *cmp = 1; + return 0; +} + +static ssize_t +bsearch_strings(struct getarg_strings *strs, const char *p, + char sep, ssize_t *more) +{ + ssize_t right = (ssize_t)strs->num_strings - 1; + ssize_t left = 0; + ssize_t plen = 0; + int cmp; + + if (sep) + plen = strlen(p); + + if (strs->num_strings == 0) + return -1; + + if (sep && more && *more > -1) { + /* If *more > -1 we're continuing an iteration */ + if (*more > right) + return -1; + if (prefix_check(strs->strings[*more], p, plen, sep, &cmp)) + return (*more)++; + (*more)++; + return -1; + } + + while (left <= right) { + ssize_t mid = left + (right - left) / 2; + + if (sep) { + int cmp2; + + while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) && + mid > 0 && + prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2)) + mid--; + } else + cmp = strcmp(p, strs->strings[mid]); + if (cmp == 0) { + if (more) + *more = mid + 1; + return mid; + } + if (cmp < 0) + right = mid - 1; /* -1 if `p' is smaller than smallest in strs */ + else + left = mid + 1; + } + return -1; +} + +int +preserve_type(const char *p) +{ + return bsearch_strings(&preserve, p, '\0', 0) > -1; +} + +int +seq_type(const char *p) +{ + return bsearch_strings(&seq, p, '\0', 0) > -1; +} + +/* + * Split `s' on `sep' and fill fs[] with pointers to the substrings. + * + * Only the first substring is to be freed -- the rest share the same + * allocation. + * + * The last element may contain `sep' chars if there are more fields in `s' + * than output locations in `fs[]'. + */ +static void +split_str(const char *s, char sep, char ***fs) +{ + size_t i; + + fs[0][0] = estrdup(s); + for (i = 1; fs[i]; i++) { + char *q; + + if ((q = strchr(fs[i-1][0], sep)) == NULL) + break; + *(q++) = '\0'; + fs[i][0] = q; + } + for (; fs[i]; i++) + fs[i][0] = NULL; +} + +/* + * If `p' is "decorated" with a not-to-be-encoded-or-decoded field, + * output the field's typename and fieldname, whether it's optional, whether + * it's an ASN.1 type or an "external" type, and if external the names of + * functions to copy and free values of that type. + */ +int +decorate_type(const char *p, struct decoration *deco, ssize_t *more) +{ + ssize_t i; + char **s[7]; + char *junk = NULL; + char *cp; + + deco->first = *more == -1; + deco->decorated = 0; + deco->field_type = NULL; + if ((i = bsearch_strings(&decorate, p, ':', more)) == -1) + return 0; + + deco->decorated = 1; + deco->opt = deco->ext = deco->ptr = 0; + deco->void_star = deco->struct_star = 0; + deco->field_name = deco->copy_function_name = deco->free_function_name = + deco->header_name = NULL; + + s[0] = &deco->field_type; + s[1] = &deco->field_name; + s[2] = &deco->copy_function_name; + s[3] = &deco->free_function_name; + s[4] = &deco->header_name; + s[5] = &junk; + s[6] = NULL; + split_str(decorate.strings[i] + strlen(p) + 1, ':', s); + + if (junk || deco->field_type[0] == '\0' || !deco->field_name || + deco->field_name[0] == '\0' || deco->field_name[0] == '?') { + errx(1, "Invalidate type decoration specification: --decorate=\"%s\"", + decorate.strings[i]); + } + if ((cp = strchr(deco->field_name, '?'))) { + deco->opt = 1; + *cp = '\0'; + } + if (strcmp(deco->field_type, "void*") == 0 || + strcmp(deco->field_type, "void *") == 0) { + deco->ext = deco->ptr = deco->void_star = 1; + deco->opt = 1; + deco->header_name = NULL; + } else if (strncmp(deco->field_type, "struct ", sizeof("struct ") - 1) == 0 && + deco->field_type[strlen(deco->field_type) - 1] == '*') + deco->ptr = deco->struct_star = 1; + if (deco->ptr || deco->copy_function_name) + deco->ext = 1; + if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0]) + deco->copy_function_name = NULL; + if (deco->ext && deco->free_function_name && !deco->free_function_name[0]) + deco->free_function_name = NULL; + if (deco->header_name && !deco->header_name[0]) + deco->header_name = NULL; + if (deco->ptr) + deco->opt = 0; + return 1; +} + +static const char * +my_basename(const char *fn) +{ + const char *base, *p; + + for (p = base = fn; *p; p++) { +#ifdef WIN32 + if (*p == '/' || *p == '\\') + base = p + 1; +#else + if (*p == '/') + base = p + 1; +#endif + } + return base; +} + +const char *fuzzer_string = ""; +const char *enum_prefix; +const char *name; +int prefix_enum; +int fuzzer_flag; +int support_ber; +int template_flag; +int rfc1510_bitstring; +int one_code_file; +char *option_file; +int parse_units_flag = 1; +char *type_file_string = "krb5-types.h"; +int original_order; +int version_flag; +int help_flag; +struct getargs args[] = { + { "fuzzer", 0, arg_flag, &fuzzer_flag, NULL, NULL }, + { "template", 0, arg_flag, &template_flag, NULL, NULL }, + { "prefix-enum", 0, arg_flag, &prefix_enum, + "prefix C enum labels for ENUMERATED types and INTEGER types with the " + "type's name", NULL }, + { "enum-prefix", 0, arg_string, &enum_prefix, + "prefix for C enum labels for ENUMERATED types and INTEGER types with " + "enumerated values", "PREFIX" }, + { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring, + "Use RFC1510 incorrect BIT STRING handling for all BIT STRING types " + "in the module", NULL }, + { "decode-dce-ber", 0, arg_flag, &support_ber, + "Allow DCE-style BER on decode", NULL }, + { "support-ber", 0, arg_flag, &support_ber, "Allow BER on decode", NULL }, + { "preserve-binary", 0, arg_strings, &preserve, + "Names of types for which to generate _save fields, saving original " + "encoding, in containing structures (useful for signature " + "verification)", "TYPE" }, + { "sequence", 0, arg_strings, &seq, + "Generate add/remove functions for SEQUENCE OF types", "TYPE" }, + { "decorate", 0, arg_strings, &decorate, + "Generate private field for SEQUENCE/SET type", "DECORATION" }, + { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL }, + { "gen-name", 0, arg_string, &name, + "Name of generated module", "NAME" }, + { "option-file", 0, arg_string, &option_file, + "File with additional compiler CLI options", "FILE" }, + { "original-order", 0, arg_flag, &original_order, + "Define C types and functions in the order in which they appear in " + "the ASN.1 module instead of topologically sorting types. This " + "is useful for comparing output to earlier compiler versions.", + NULL }, + { "parse-units", 0, arg_negative_flag, &parse_units_flag, + "Do not generate roken-style units", NULL }, + { "type-file", 0, arg_string, &type_file_string, + "Name of a C header file to generate includes of for base types", + "FILE" }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + if (code) + dup2(STDERR_FILENO, STDOUT_FILENO); + else + dup2(STDOUT_FILENO, STDERR_FILENO); + arg_printusage(args, num_args, NULL, "[asn1-file [name]]"); + fprintf(stderr, + "\nA DECORATION is one of:\n\n" + "\tTYPE:FTYPE:fname[?]\n" + "\tTYPE:FTYPE:fname[?]:[copy_function]:[free_function]:header\n" + "\tTYPE:void:fname:::\n" + "\nSee the manual page.\n"); + exit(code); +} + +int error_flag; + +int +main(int argc, char **argv) +{ + int ret; + const char *file; + FILE *opt = NULL; + int optidx = 0; + char **arg = NULL; + size_t len = 0; + size_t sz = 0; + int i; + + setprogname(argv[0]); + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if (help_flag) + usage(0); + if (version_flag) { + print_version(NULL); + exit(0); + } + if (argc == optidx) { + /* Compile the module on stdin */ + file = "stdin"; + name = "stdin"; + yyin = stdin; + } else { + /* Compile a named module */ + file = argv[optidx]; + + /* + * If the .asn1 stem is not given, then assume it, and also assume + * --option-file was given if the .opt file exists + */ + if (strchr(file, '.') == NULL) { + char *s = NULL; + + if (asprintf(&s, "%s.opt", file) == -1 || s == NULL) + err(1, "Out of memory"); + if ((opt = fopen(s, "r"))) + option_file = s; + else + free(s); + if (asprintf(&s, "%s.asn1", file) == -1 || s == NULL) + err(1, "Out of memory"); + file = s; + } + yyin = fopen (file, "r"); + if (yyin == NULL) + err (1, "open %s", file); + if (argc == optidx + 1) { + char *p; + + /* C module name substring not given; derive from file name */ + name = my_basename(estrdup(file)); + p = strrchr(name, '.'); + if (p) + *p = '\0'; + } else + name = argv[optidx + 1]; + } + + /* + * Parse extra options file + */ + if (option_file) { + char buf[1024]; + + if (opt == NULL && + (opt = fopen(option_file, "r")) == NULL) + err(1, "Could not open given option file %s", option_file); + + arg = calloc(2, sizeof(arg[0])); + if (arg == NULL) { + perror("calloc"); + exit(1); + } + arg[0] = option_file; + arg[1] = NULL; + len = 1; + sz = 2; + + while (fgets(buf, sizeof(buf), opt) != NULL) { + size_t buflen, ws; + + buf[strcspn(buf, "\n\r")] = '\0'; + + buflen = strlen(buf); + if ((ws = strspn(buf, " \t"))) + memmove(buf, buf + ws, buflen - ws); + if (buf[0] == '\0' || buf[0] == '#') + continue; + + if (len + 1 >= sz) { + arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0])); + if (arg == NULL) { + perror("malloc"); + exit(1); + } + sz += (sz>>1) + 2; + } + arg[len] = strdup(buf); + if (arg[len] == NULL) { + perror("strdup"); + exit(1); + } + arg[len + 1] = NULL; + len++; + } + fclose(opt); + + optidx = 0; + if(getarg(args, num_args, len, arg, &optidx)) + usage(1); + + if (len != optidx) { + fprintf(stderr, "extra args"); + exit(1); + } + } + + if (fuzzer_flag) { + if (!template_flag) { + printf("can't do fuzzer w/o --template"); + exit(1); + } +#ifdef ASN1_FUZZER + fuzzer_string = "_fuzzer"; +#endif + } + + if (preserve.num_strings) + mergesort_r(preserve.strings, preserve.num_strings, + sizeof(preserve.strings[0]), strcmp4mergesort_r, ""); + if (seq.num_strings) + mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]), + strcmp4mergesort_r, ""); + if (decorate.num_strings) + mergesort_r(decorate.strings, decorate.num_strings, + sizeof(decorate.strings[0]), strcmp4mergesort_r, ":"); + + init_generate(file, name); + + if (one_code_file) + generate_header_of_codefile(name); + + initsym (); + ret = yyparse (); + if(ret != 0 || error_flag != 0) + exit(1); + if (!original_order) + generate_types(); + if (argc != optidx) + fclose(yyin); + + if (one_code_file) + close_codefile(); + close_generate(); + + if (arg) { + for (i = 1; i < len; i++) + free(arg[i]); + free(arg); + } + + return 0; +} diff --git a/third_party/heimdal/lib/asn1/ocsp.asn1 b/third_party/heimdal/lib/asn1/ocsp.asn1 new file mode 100644 index 0000000..eb090a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/ocsp.asn1 @@ -0,0 +1,113 @@ +-- From rfc2560 +-- $Id$ +OCSP DEFINITIONS EXPLICIT TAGS::= + +BEGIN + +IMPORTS + Certificate, AlgorithmIdentifier, CRLReason, + Name, GeneralName, CertificateSerialNumber, Extensions + FROM rfc2459; + +OCSPVersion ::= INTEGER { ocsp-v1(0) } + +OCSPCertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT -- OCSPRevokedInfo -- SEQUENCE { + revocationTime GeneralizedTime, + revocationReason[0] EXPLICIT CRLReason OPTIONAL + }, + unknown [2] IMPLICIT NULL } + +OCSPCertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } + +OCSPSingleResponse ::= SEQUENCE { + certID OCSPCertID, + certStatus OCSPCertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPInnerRequest ::= SEQUENCE { + reqCert OCSPCertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + +OCSPTBSRequest ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF OCSPInnerRequest, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + +OCSPSignature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +OCSPRequest ::= SEQUENCE { + tbsRequest OCSPTBSRequest, + optionalSignature [0] EXPLICIT OCSPSignature OPTIONAL } + +OCSPResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + +OCSPResponseStatus ::= ENUMERATED { + successful (0), --Response has valid confirmations + malformedRequest (1), --Illegal confirmation request + internalError (2), --Internal error in issuer + tryLater (3), --Try again later + --(4) is not used + sigRequired (5), --Must sign the request + unauthorized (6) --Request unauthorized +} + +OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT OCSPResponseBytes OPTIONAL } + +OCSPKeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + --(excluding the tag and length fields) + +OCSPResponderID ::= CHOICE { + byName [1] Name, + byKey [2] OCSPKeyHash } + +OCSPResponseData ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + responderID OCSPResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF OCSPSingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPBasicOCSPResponse ::= SEQUENCE { + tbsResponseData OCSPResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +-- ArchiveCutoff ::= GeneralizedTime + +-- AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER + +-- Object Identifiers + +id-pkix-ocsp OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) pkix-ad(48) 1 +} + +id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } +id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 } +-- id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 } +-- id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 } +-- id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } +-- id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 } +-- id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 } + + +END + diff --git a/third_party/heimdal/lib/asn1/ocsp.opt b/third_party/heimdal/lib/asn1/ocsp.opt new file mode 100644 index 0000000..697aa03 --- /dev/null +++ b/third_party/heimdal/lib/asn1/ocsp.opt @@ -0,0 +1,2 @@ +--preserve-binary=OCSPTBSRequest +--preserve-binary=OCSPResponseData diff --git a/third_party/heimdal/lib/asn1/oid_resolution.c b/third_party/heimdal/lib/asn1/oid_resolution.c new file mode 100644 index 0000000..db11b11 --- /dev/null +++ b/third_party/heimdal/lib/asn1/oid_resolution.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2019 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include + +#include "cms_asn1.h" +#include "crmf_asn1.h" +#include "digest_asn1.h" +#include "krb5_asn1.h" +#include "kx509_asn1.h" +#include "ocsp_asn1.h" +#include "pkcs10_asn1.h" +#include "pkcs12_asn1.h" +#include "pkcs8_asn1.h" +#include "pkcs9_asn1.h" +#include "pkinit_asn1.h" +#include "rfc2459_asn1.h" +#include "rfc4108_asn1.h" + + +struct sym_oid { + const char *sym; + const heim_oid *oid; +}; + +#ifndef WIN32 +#define DEFINE_OID_WITH_NAME(sym) \ + { #sym, &asn1_oid_ ## sym }, + +static const struct sym_oid sym_oids[] = { +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" +#include "rfc4108_asn1_oids.c" +}; + +static size_t num_sym_oids = sizeof(sym_oids) / sizeof(sym_oids[0]); + +#undef DEFINE_OID_WITH_NAME + +#define init_sym_oids() + +#else + +/* + * We can't use C99 non-literal initializers for static objects in the Windows + * build... + */ + +static struct sym_oid *sym_oids; +static size_t num_sym_oids; + +#define DEFINE_OID_WITH_NAME(sym) (c++); +static size_t +count_sym_oids(void) +{ + size_t c = 0; +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" + return c; +} +#undef DEFINE_OID_WITH_NAME + +#define DEFINE_OID_WITH_NAME(s) \ + tmp[i].sym = #s; \ + tmp[i++].oid = &asn1_oid_ ## s; + +static void +init_sym_oids(void) +{ + static struct sym_oid *tmp; + size_t i = 0; + size_t c; + + if (!sym_oids && + (c = count_sym_oids()) && + (tmp = calloc(c, sizeof(tmp[0])))) { +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" + num_sym_oids = c; + sym_oids = tmp; + } +} +#undef DEFINE_OID_WITH_NAME + +#endif + +static struct sym_oid *sym_oids_sorted_by_name; +static struct sym_oid *sym_oids_sorted_by_oid; + +static int +sym_cmp_name(const void *va, const void *vb) +{ + const struct sym_oid *a = va; + const struct sym_oid *b = vb; + + return (strcmp(a->sym, b->sym)); +} + +static int +sym_cmp_oid(const void *va, const void *vb) +{ + const struct sym_oid *a = va; + const struct sym_oid *b = vb; + + return der_heim_oid_cmp(a->oid, b->oid); +} + +static struct sym_oid * +sort_sym_oids(int (*cmp)(const void *, const void *)) +{ + struct sym_oid *tmp; + + init_sym_oids(); + if ((tmp = calloc(num_sym_oids, sizeof(tmp[0]))) == NULL) + return NULL; + + memcpy(tmp, sym_oids, num_sym_oids * sizeof(tmp[0])); + qsort(tmp, num_sym_oids, sizeof(struct sym_oid), cmp); + return tmp; +} + +static int +fix_oid_name(const char **namep, char **freeme) +{ + char *dash = strchr(*namep, '-'); + + *freeme = NULL; + if (dash == NULL) + return 0; + if ((*freeme = strdup(*namep)) == NULL) + return ENOMEM; + *namep = *freeme; + for (dash = strchr(*namep, '-'); dash; dash = strchr(dash, '-')) + *dash = '_'; + return 0; +} + +int ASN1CALL +der_find_heim_oid_by_name(const char *str, const heim_oid **oid) +{ + size_t right = num_sym_oids - 1; + size_t left = 0; + char *s = NULL; + int ret; + + *oid = NULL; + if (sym_oids_sorted_by_name == NULL && + (sym_oids_sorted_by_name = sort_sym_oids(sym_cmp_name)) == NULL) + return ENOMEM; + + if ((ret = fix_oid_name(&str, &s))) + return ret; + + while (left <= right) { + size_t mid = left + (right - left) / 2; + int cmp; + + cmp = strcmp(str, sym_oids_sorted_by_name[mid].sym); + if (cmp == 0) { + *oid = sym_oids_sorted_by_name[mid].oid; + free(s); + return 0; + } + if (cmp < 0 && mid > 0) {/* avoid underflow */ + right = mid - 1; + } else if (cmp < 0) { + free(s); + return -1; + } else { + left = mid + 1; + } + } + free(s); + return -1; +} + +int ASN1CALL +der_find_or_parse_heim_oid(const char *str, const char *sep, heim_oid *oid) +{ + const heim_oid *found = NULL; + + switch (der_find_heim_oid_by_name(str, &found)) { + case 0: return der_copy_oid(found, oid); + case -1: return der_parse_heim_oid(str, sep, oid); + default: return ENOMEM; + } +} + +int ASN1CALL +der_find_heim_oid_by_oid(const heim_oid *oid, const char **name) +{ + size_t right = num_sym_oids; + size_t left = 0; + + *name = NULL; + if (sym_oids_sorted_by_oid == NULL && + (sym_oids_sorted_by_oid = sort_sym_oids(sym_cmp_oid)) == NULL) + return ENOMEM; + + while (left <= right) { + size_t mid = (left + right) >> 1; + int cmp; + + cmp = der_heim_oid_cmp(oid, sym_oids_sorted_by_oid[mid].oid); + if (cmp == 0) { + *name = sym_oids_sorted_by_oid[mid].sym; + return 0; + } + if (cmp < 0 && mid) + right = mid - 1; + else if (cmp < 0) + return -1; + else if (mid < num_sym_oids - 1) + left = mid + 1; + else + return -1; + } + return -1; +} + +int ASN1CALL +der_match_heim_oid_by_name(const char *str, int *c, const heim_oid **oid) +{ + size_t i; + char *s = NULL; + int ret; + + if ((ret = fix_oid_name(&str, &s))) + return ret; + + if (*c < 0) + *c = 0; + + init_sym_oids(); + for (i = (size_t)*c; i < num_sym_oids; i++) { + /* + * XXX We need a lib/roken strcasestr(), or maybe we should support + * globbing here. + */ + if (strstr(sym_oids[i].sym, str)) { + *oid = sym_oids[i].oid; + free(s); + if (i >= INT_MAX) + return -1; + *c = i + 1; /* num_sym_oids is much less than INT_MAX */ + return 0; + } + } + free(s); + return -1; +} + +/* Warning: der_print_heim_oid_sym() will not round-trip */ + +int ASN1CALL +der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp) +{ + const char *sym; + char *s1 = NULL; + char *s2 = NULL; + char *p; + int ret; + + if (der_find_heim_oid_by_oid(oid, &sym)) + return der_print_heim_oid(oid, delim, strp); + + if ((ret = der_print_heim_oid(oid, delim, &s1))) + return ret; + if (asprintf(&s2, "%s (%s)", s1, sym) == -1 || s2 == NULL) { + *strp = s1; + return 0; + } + for (p = s2 + strlen(s1) + 1; *p; p++) { + if (*p == '_') + *p = '-'; + } + *strp = s2; + free(s1); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/pkcs10.asn1 b/third_party/heimdal/lib/asn1/pkcs10.asn1 new file mode 100644 index 0000000..04cda4e --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs10.asn1 @@ -0,0 +1,64 @@ +-- $Id$ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Name, SubjectPublicKeyInfo, AlgorithmIdentifier, Attribute, Extensions + FROM rfc2459 + HEIM_ANY FROM heim; + +PKCS10-Version ::= INTEGER { pkcs10-v1(0) } + +CertificationRequestInfo ::= SEQUENCE { + version PKCS10-Version, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} + +CertificationRequest ::= SEQUENCE { + certificationRequestInfo CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +IOSCertificationRequestInfo ::= SEQUENCE { + version PKCS10-Version, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF CRIAttributeSet OPTIONAL +} + +IOSCertificationRequest ::= SEQUENCE { + certificationRequestInfo IOSCertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +-- Copied from rfc2459.asn1 because we can't IMPORT classes and parameterized +-- types yet. +_ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL +} + +id-pkcs9-extReq-copy OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14 +} + +-- Workaround compiler limitation: +CRIExtensions ::= Extensions + +at-extReq _ATTRIBUTE ::= { &Type CRIExtensions, &id id-pkcs9-extReq-copy } +CRIAttributes _ATTRIBUTE ::= { at-extReq } +CRIAttributeSet{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + values SET --SIZE (1..MAX)-- OF _ATTRIBUTE.&Type({AttrSet}{@type}) +} +CRIAttributeSet ::= CRIAttributeSet{CRIAttributes} + +END + diff --git a/third_party/heimdal/lib/asn1/pkcs10.opt b/third_party/heimdal/lib/asn1/pkcs10.opt new file mode 100644 index 0000000..499fab2 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs10.opt @@ -0,0 +1 @@ +--preserve-binary=CertificationRequestInfo diff --git a/third_party/heimdal/lib/asn1/pkcs12.asn1 b/third_party/heimdal/lib/asn1/pkcs12.asn1 new file mode 100644 index 0000000..61d3e2c --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs12.asn1 @@ -0,0 +1,81 @@ +-- $Id$ -- + +PKCS12 DEFINITIONS ::= + +BEGIN + +IMPORTS ContentInfo FROM cms + DigestInfo FROM rfc2459 + HEIM_ANY, HEIM_ANY_SET FROM heim; + +-- The PFX PDU + +id-pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) pkcs-12(12) } + +id-pkcs-12PbeIds OBJECT IDENTIFIER ::= { id-pkcs-12 1} +id-pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 1} +id-pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 2} +id-pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 3} +id-pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 4} +id-pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 5} +id-pbewithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 6} + +id-pkcs12-bagtypes OBJECT IDENTIFIER ::= { id-pkcs-12 10 1} + +id-pkcs12-keyBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 1 } +id-pkcs12-pkcs8ShroudedKeyBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 2 } +id-pkcs12-certBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 3 } +id-pkcs12-crlBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 4 } +id-pkcs12-secretBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 5 } +id-pkcs12-safeContentsBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 6 } + + +PKCS12-MacData ::= SEQUENCE { + mac DigestInfo, + macSalt OCTET STRING, + iterations INTEGER OPTIONAL +} + +PKCS12-PFX ::= SEQUENCE { + version INTEGER, + authSafe ContentInfo, + macData PKCS12-MacData OPTIONAL +} + +PKCS12-AuthenticatedSafe ::= SEQUENCE OF ContentInfo + -- Data if unencrypted + -- EncryptedData if password-encrypted + -- EnvelopedData if public key-encrypted + +PKCS12-Attribute ::= SEQUENCE { + attrId OBJECT IDENTIFIER, + attrValues -- SET OF -- HEIM_ANY_SET +} + +PKCS12-Attributes ::= SET OF PKCS12-Attribute + +PKCS12-SafeBag ::= SEQUENCE { + bagId OBJECT IDENTIFIER, + bagValue [0] HEIM_ANY, + bagAttributes PKCS12-Attributes OPTIONAL +} + +PKCS12-SafeContents ::= SEQUENCE OF PKCS12-SafeBag + +PKCS12-CertBag ::= SEQUENCE { + certType OBJECT IDENTIFIER, + certValue [0] HEIM_ANY +} + +PKCS12-PBEParams ::= SEQUENCE { + salt OCTET STRING, + iterations INTEGER (0..4294967295) OPTIONAL +} + +PKCS12-OctetString ::= OCTET STRING + +-- KeyBag ::= PrivateKeyInfo +-- PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo + +END diff --git a/third_party/heimdal/lib/asn1/pkcs8.asn1 b/third_party/heimdal/lib/asn1/pkcs8.asn1 new file mode 100644 index 0000000..6227033 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs8.asn1 @@ -0,0 +1,29 @@ +-- $Id$ -- + +PKCS8 DEFINITIONS ::= + +BEGIN + +IMPORTS Attribute, AlgorithmIdentifier FROM rfc2459; + +PKCS8PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + +PKCS8PrivateKey ::= OCTET STRING + +PKCS8Attributes ::= SET OF Attribute + +PKCS8PrivateKeyInfo ::= SEQUENCE { + version INTEGER, + privateKeyAlgorithm PKCS8PrivateKeyAlgorithmIdentifier, + privateKey PKCS8PrivateKey, + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} + +PKCS8EncryptedData ::= OCTET STRING + +PKCS8EncryptedPrivateKeyInfo ::= SEQUENCE { + encryptionAlgorithm AlgorithmIdentifier, + encryptedData PKCS8EncryptedData +} + +END diff --git a/third_party/heimdal/lib/asn1/pkcs9.asn1 b/third_party/heimdal/lib/asn1/pkcs9.asn1 new file mode 100644 index 0000000..43b4a9d --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs9.asn1 @@ -0,0 +1,29 @@ +-- $Id$ -- + +PKCS9 DEFINITIONS ::= + +BEGIN + +-- The PFX PDU + +id-pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) pkcs-9(9) } + +id-pkcs9-emailAddress OBJECT IDENTIFIER ::= {id-pkcs-9 1 } +id-pkcs9-contentType OBJECT IDENTIFIER ::= {id-pkcs-9 3 } +id-pkcs9-messageDigest OBJECT IDENTIFIER ::= {id-pkcs-9 4 } +id-pkcs9-signingTime OBJECT IDENTIFIER ::= {id-pkcs-9 5 } +id-pkcs9-countersignature OBJECT IDENTIFIER ::= {id-pkcs-9 6 } +id-pkcs9-extReq OBJECT IDENTIFIER ::= {id-pkcs-9 14} + +id-pkcs-9-at-friendlyName OBJECT IDENTIFIER ::= {id-pkcs-9 20} +id-pkcs-9-at-localKeyId OBJECT IDENTIFIER ::= {id-pkcs-9 21} +id-pkcs-9-at-certTypes OBJECT IDENTIFIER ::= {id-pkcs-9 22} +id-pkcs-9-at-certTypes-x509 OBJECT IDENTIFIER ::= {id-pkcs-9-at-certTypes 1} + +PKCS9-BMPString ::= BMPString + +PKCS9-friendlyName ::= SET OF PKCS9-BMPString + +END + diff --git a/third_party/heimdal/lib/asn1/pkinit.asn1 b/third_party/heimdal/lib/asn1/pkinit.asn1 new file mode 100644 index 0000000..99dda00 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkinit.asn1 @@ -0,0 +1,201 @@ +-- $Id$ -- + +PKINIT DEFINITIONS ::= BEGIN + +IMPORTS EncryptionKey, PrincipalName, Realm, KerberosTime, Checksum, Ticket FROM krb5 + IssuerAndSerialNumber FROM cms + SubjectPublicKeyInfo, AlgorithmIdentifier FROM rfc2459 + HEIM_ANY FROM heim; + +id-pkinit OBJECT IDENTIFIER ::= + { iso (1) org (3) dod (6) internet (1) security (5) + kerberosv5 (2) pkinit (3) } + +id-pkauthdata OBJECT IDENTIFIER ::= { id-pkinit 1 } +id-pkdhkeydata OBJECT IDENTIFIER ::= { id-pkinit 2 } +id-pkrkeydata OBJECT IDENTIFIER ::= { id-pkinit 3 } +id-pkekuoid OBJECT IDENTIFIER ::= { id-pkinit 4 } +id-pkkdcekuoid OBJECT IDENTIFIER ::= { id-pkinit 5 } + +id-heim-eku-pkinit-certlife-is-max-life OBJECT IDENTIFIER ::= + { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 3 } + +id-apple-system-id OBJECT IDENTIFIER ::= { 1 2 840 113635 100 4 4 } + +id-pkinit-kdf OBJECT IDENTIFIER ::= { id-pkinit 6 } +id-pkinit-kdf-ah-sha1 OBJECT IDENTIFIER ::= { id-pkinit-kdf 1 } +id-pkinit-kdf-ah-sha256 OBJECT IDENTIFIER ::= { id-pkinit-kdf 2 } +id-pkinit-kdf-ah-sha512 OBJECT IDENTIFIER ::= { id-pkinit-kdf 3 } + +id-pkinit-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) security(5) kerberosv5(2) + x509-sanan(2) } + +id-pkinit-ms-eku OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 2 } + +id-pkinit-ms-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 3 } + +MS-UPN-SAN ::= UTF8String + +pa-pk-as-req INTEGER ::= 16 +pa-pk-as-rep INTEGER ::= 17 + +td-trusted-certifiers INTEGER ::= 104 +td-invalid-certificates INTEGER ::= 105 +td-dh-parameters INTEGER ::= 109 + +DHNonce ::= OCTET STRING + +KDFAlgorithmId ::= SEQUENCE { + kdf-id [0] OBJECT IDENTIFIER, + ... +} + +TrustedCA ::= SEQUENCE { + caName [0] IMPLICIT OCTET STRING, + certificateSerialNumber [1] INTEGER OPTIONAL, + subjectKeyIdentifier [2] OCTET STRING OPTIONAL, + ... +} + +ExternalPrincipalIdentifier ::= SEQUENCE { + subjectName [0] IMPLICIT OCTET STRING OPTIONAL, + issuerAndSerialNumber [1] IMPLICIT OCTET STRING OPTIONAL, + subjectKeyIdentifier [2] IMPLICIT OCTET STRING OPTIONAL, + ... +} + +ExternalPrincipalIdentifiers ::= SEQUENCE OF ExternalPrincipalIdentifier + +PA-PK-AS-REQ ::= SEQUENCE { + signedAuthPack [0] IMPLICIT OCTET STRING, + trustedCertifiers [1] ExternalPrincipalIdentifiers OPTIONAL, + kdcPkId [2] IMPLICIT OCTET STRING OPTIONAL, + ... +} + +PKAuthenticator ::= SEQUENCE { + cusec [0] INTEGER -- (0..999999) --, + ctime [1] KerberosTime, + nonce [2] INTEGER (0..4294967295), + paChecksum [3] OCTET STRING OPTIONAL, + freshnessToken [4] OCTET STRING OPTIONAL, + ... +} + +AuthPack ::= SEQUENCE { + pkAuthenticator [0] PKAuthenticator, + clientPublicValue [1] SubjectPublicKeyInfo OPTIONAL, + supportedCMSTypes [2] SEQUENCE OF AlgorithmIdentifier OPTIONAL, + clientDHNonce [3] DHNonce OPTIONAL, + ..., + supportedKDFs [4] SEQUENCE OF KDFAlgorithmId OPTIONAL, + ... +} + +TD-TRUSTED-CERTIFIERS ::= ExternalPrincipalIdentifiers +TD-INVALID-CERTIFICATES ::= ExternalPrincipalIdentifiers + +AD-INITIAL-VERIFIED-CAS ::= SEQUENCE OF ExternalPrincipalIdentifier + +DHRepInfo ::= SEQUENCE { + dhSignedData [0] IMPLICIT OCTET STRING, + serverDHNonce [1] DHNonce OPTIONAL, + ..., + kdf [2] KDFAlgorithmId OPTIONAL, + ... +} + +PA-PK-AS-REP ::= CHOICE { + dhInfo [0] DHRepInfo, + encKeyPack [1] IMPLICIT OCTET STRING, + ... +} + +KDCDHKeyInfo ::= SEQUENCE { + subjectPublicKey [0] BIT STRING, + nonce [1] INTEGER (0..4294967295), + dhKeyExpiration [2] KerberosTime OPTIONAL, + ... +} + +ReplyKeyPack ::= SEQUENCE { + replyKey [0] EncryptionKey, + asChecksum [1] Checksum, + ... +} + +TD-DH-PARAMETERS ::= SEQUENCE OF AlgorithmIdentifier + + +-- Windows compat glue -- + +PKAuthenticator-Win2k ::= SEQUENCE { + kdcName [0] PrincipalName, + kdcRealm [1] Realm, + cusec [2] INTEGER (0..4294967295), + ctime [3] KerberosTime, + nonce [4] INTEGER (-2147483648..2147483647) +} + +AuthPack-Win2k ::= SEQUENCE { + pkAuthenticator [0] PKAuthenticator-Win2k, + clientPublicValue [1] SubjectPublicKeyInfo OPTIONAL +} + + +TrustedCA-Win2k ::= CHOICE { + caName [1] HEIM_ANY, + issuerAndSerial [2] IssuerAndSerialNumber +} + +PA-PK-AS-REQ-Win2k ::= SEQUENCE { + signed-auth-pack [0] IMPLICIT OCTET STRING, + trusted-certifiers [2] SEQUENCE OF TrustedCA-Win2k OPTIONAL, + kdc-cert [3] IMPLICIT OCTET STRING OPTIONAL, + encryption-cert [4] IMPLICIT OCTET STRING OPTIONAL +} + +PA-PK-AS-REP-Win2k ::= CHOICE { + dhSignedData [0] IMPLICIT OCTET STRING, + encKeyPack [1] IMPLICIT OCTET STRING +} + +KDCDHKeyInfo-Win2k ::= SEQUENCE { + nonce [0] INTEGER (-2147483648..2147483647), + subjectPublicKey [2] BIT STRING +} + +ReplyKeyPack-Win2k ::= SEQUENCE { + replyKey [0] EncryptionKey, + nonce [1] INTEGER (-2147483648..2147483647), + ... +} + +PA-PK-AS-REP-BTMM ::= SEQUENCE { + dhSignedData [0] HEIM_ANY OPTIONAL, + encKeyPack [1] HEIM_ANY OPTIONAL +} + + +PkinitSP80056AOtherInfo ::= SEQUENCE { + algorithmID AlgorithmIdentifier, + partyUInfo [0] OCTET STRING, + partyVInfo [1] OCTET STRING, + suppPubInfo [2] OCTET STRING OPTIONAL, + suppPrivInfo [3] OCTET STRING OPTIONAL +} + +PkinitSuppPubInfo ::= SEQUENCE { + enctype [0] INTEGER (-2147483648..2147483647), + as-REQ [1] OCTET STRING, + pk-as-rep [2] OCTET STRING, + ticket [3] Ticket, + ... +} + +END diff --git a/third_party/heimdal/lib/asn1/pku2u.asn1 b/third_party/heimdal/lib/asn1/pku2u.asn1 new file mode 100644 index 0000000..ca3a91f --- /dev/null +++ b/third_party/heimdal/lib/asn1/pku2u.asn1 @@ -0,0 +1,30 @@ +-- $Id$ + +PKU2U DEFINITIONS ::= BEGIN + +IMPORTS Checksum FROM krb5 + GeneralName FROM rfc2459; + +GSS_KRB5_FINISHED ::= SEQUENCE { + gss-mic [1] Checksum, + ... +} + +InitiatorName ::= CHOICE { + sanIndex INTEGER (-2147483648..2147483647), + nameNotInCert [0] GeneralName, + ... +} + +TargetName ::= CHOICE { + exportedTargName OCTET STRING, + generalName [0] GeneralName, + ... +} + +InitiatorNameAssertion ::= SEQUENCE { + initiatorName [0] InitiatorName OPTIONAL, + targetName [1] TargetName OPTIONAL +} + +END diff --git a/third_party/heimdal/lib/asn1/rfc2459.asn1 b/third_party/heimdal/lib/asn1/rfc2459.asn1 new file mode 100644 index 0000000..7ceefe3 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc2459.asn1 @@ -0,0 +1,1210 @@ +-- $Id$ -- +-- Definitions from RFCs 2459, 3280, 5280 +-- +-- Note that those RFCs come with *two* ASN.1 modules, one being a default- +-- EXPLICIT tagged module, and the other being default-IMPLICIT. Some types +-- are in one module, while others are in the other. Here the two modules +-- are merged into a single default-EXPLICIT tagged module, with IMPLICIT added +-- for all tags for types in the default-IMPLICIT module. + +RFC2459 DEFINITIONS ::= BEGIN + +IMPORTS HEIM_ANY FROM heim + PrincipalName, Realm FROM krb5; + -- For OtherName we really want to also import: + -- KRB5PrincipalName FROM pkinit + -- PermanentIdentifier FROM rfc4043 + -- HardwareModuleName FROM rfc4108; + -- But we can't because that creates circular dependencies. + +Version ::= INTEGER { + rfc3280_version_1(0), + rfc3280_version_2(1), + rfc3280_version_3(2) +} + +id-pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 1 } +id-pkcs1-rsaEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 1 } +id-pkcs1-md2WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 2 } +id-pkcs1-md5WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 4 } +id-pkcs1-sha1WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 5 } +id-pkcs1-sha256WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 11 } +id-pkcs1-sha384WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 12 } +id-pkcs1-sha512WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 13 } + +id-heim-rsa-pkcs1-x509 OBJECT IDENTIFIER ::= { 1 2 752 43 16 1 } + +id-pkcs-2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 2 } +id-pkcs2-md2 OBJECT IDENTIFIER ::= { id-pkcs-2 2 } +id-pkcs2-md4 OBJECT IDENTIFIER ::= { id-pkcs-2 4 } +id-pkcs2-md5 OBJECT IDENTIFIER ::= { id-pkcs-2 5 } + +id-rsa-digestAlgorithm OBJECT IDENTIFIER ::= +{ iso(1) member-body(2) us(840) rsadsi(113549) 2 } + +id-rsa-digest-md2 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 2 } +id-rsa-digest-md4 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 4 } +id-rsa-digest-md5 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 5 } + +id-pkcs-3 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 3 } + +id-pkcs3-rc2-cbc OBJECT IDENTIFIER ::= { id-pkcs-3 2 } +id-pkcs3-rc4 OBJECT IDENTIFIER ::= { id-pkcs-3 4 } +id-pkcs3-des-ede3-cbc OBJECT IDENTIFIER ::= { id-pkcs-3 7 } + +id-rsadsi-encalg OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) 3 } + +id-rsadsi-rc2-cbc OBJECT IDENTIFIER ::= { id-rsadsi-encalg 2 } +id-rsadsi-des-ede3-cbc OBJECT IDENTIFIER ::= { id-rsadsi-encalg 7 } + +id-secsig-sha-1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + oiw(14) secsig(3) algorithm(2) 26 } + +id-secsig-sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + oiw(14) secsig(3) algorithm(2) 29 } + +id-nistAlgorithm OBJECT IDENTIFIER ::= { + joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) 4 } + +id-nist-aes-algs OBJECT IDENTIFIER ::= { id-nistAlgorithm 1 } + +id-aes-128-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 2 } +id-aes-192-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 22 } +id-aes-256-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 42 } + +id-nist-sha-algs OBJECT IDENTIFIER ::= { id-nistAlgorithm 2 } + +id-sha256 OBJECT IDENTIFIER ::= { id-nist-sha-algs 1 } +id-sha224 OBJECT IDENTIFIER ::= { id-nist-sha-algs 4 } +id-sha384 OBJECT IDENTIFIER ::= { id-nist-sha-algs 2 } +id-sha512 OBJECT IDENTIFIER ::= { id-nist-sha-algs 3 } + +id-dhpublicnumber OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-x942(10046) + number-type(2) 1 } + +-- ECC + +id-ecPublicKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } + +id-ecDH OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecdh(12) } + +id-ecMQV OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecmqv(13) } + +id-ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 4 } + +id-ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 3 } + +id-ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 2 } + +id-ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 1 } + +id-ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } + +-- some EC group ids + +id-ec-group-secp256r1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) + prime(1) 7 } + +id-ec-group-secp160r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 8 } + +id-ec-group-secp160r2 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 30 } + +id-ec-group-secp224r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 33 } + +id-ec-group-secp384r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 34 } + +id-ec-group-secp521r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 35 } + +-- DSA + +id-x9-57 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-x942(10046) 4 } + +id-dsa OBJECT IDENTIFIER ::= { id-x9-57 1 } +id-dsa-with-sha1 OBJECT IDENTIFIER ::= { id-x9-57 3 } + +-- x.520 names types + +id-x520-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 } + +id-at-commonName OBJECT IDENTIFIER ::= { id-x520-at 3 } +id-at-surname OBJECT IDENTIFIER ::= { id-x520-at 4 } +id-at-serialNumber OBJECT IDENTIFIER ::= { id-x520-at 5 } +id-at-countryName OBJECT IDENTIFIER ::= { id-x520-at 6 } +id-at-localityName OBJECT IDENTIFIER ::= { id-x520-at 7 } +id-at-stateOrProvinceName OBJECT IDENTIFIER ::= { id-x520-at 8 } +id-at-streetAddress OBJECT IDENTIFIER ::= { id-x520-at 9 } +id-at-organizationName OBJECT IDENTIFIER ::= { id-x520-at 10 } +id-at-organizationalUnitName OBJECT IDENTIFIER ::= { id-x520-at 11 } +id-at-title OBJECT IDENTIFIER ::= { id-x520-at 12 } +id-at-description OBJECT IDENTIFIER ::= { id-x520-at 13 } +id-at-name OBJECT IDENTIFIER ::= { id-x520-at 41 } +id-at-givenName OBJECT IDENTIFIER ::= { id-x520-at 42 } +id-at-initials OBJECT IDENTIFIER ::= { id-x520-at 43 } +id-at-generationQualifier OBJECT IDENTIFIER ::= { id-x520-at 44 } +id-at-dnQualifier OBJECT IDENTIFIER ::= { id-x520-at 46 } +id-at-pseudonym OBJECT IDENTIFIER ::= { id-x520-at 65 } +-- RFC 2247 +id-Userid OBJECT IDENTIFIER ::= + { 0 9 2342 19200300 100 1 1 } +id-domainComponent OBJECT IDENTIFIER ::= + { 0 9 2342 19200300 100 1 25 } + +id-at-emailAddress AttributeType ::= + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 1 } + + + +-- rfc3280 + +id-x509-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters HEIM_ANY OPTIONAL +} + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= HEIM_ANY + +DirectoryString ::= CHOICE { + ia5String IA5String, + teletexString TeletexString, + printableString PrintableString, + universalString UniversalString, + utf8String UTF8String, + bmpString BMPString +} + +AttributeValues ::= SET OF AttributeValue + +Attribute ::= SEQUENCE { + type AttributeType, + value AttributeValues +} + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value DirectoryString +} + +-- RDNs really should be SET OF SingleAttribute per the RFCs, but making that +-- change will affect lib/hx509 code, so we'll wait. The issue is that there +-- is code in lib/hx509 and in lib/asn1/check-gen.c that assumes that the +-- `value` of an rdn is a `DirectoryString` and not an open type. +-- +-- Also, it's really not worth making this change, as a) it will increase the +-- amount of code needed in lib/hx509, and b) it really is useful to be able to +-- assume RDN values are ultimately only strings, c) we don't have any attrs +-- for RDNs that aren't strings, and d) the non-string attributes from TCG that +-- are used in SubjectDirectoryAttributes will never be used here (so we hope). +-- +-- Until we fix this lib/hx509 cannot support name attributes whose type isn't +-- DirectoryString. For example, the UID attribute is broken at this time, as +-- that wants NumericString. +-- +RelativeDistinguishedName ::= SET OF AttributeTypeAndValue -- XXX SingleAttribute + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +Name ::= CHOICE { + rdnSequence RDNSequence +} + +CertificateSerialNumber ::= INTEGER + +Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime +} + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time +} + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING +} + +-- XXX Should be _OTHER-NAME ::= _TYPE-IDENTIFIER +_OTHER-NAME ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type +} + +OtherName{_OTHER-NAME:OtherNameSet} ::= SEQUENCE { + type-id _OTHER-NAME.&id({OtherNameSet}), + value [0] _OTHER-NAME.&Type({OtherNameSet}{@type-id}) +} + +_ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + -- &equality-match MATCHING-RULE OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL +} + +SingleAttribute{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + value _ATTRIBUTE.&Type({AttrSet}{@type}) +} + +AttributeSet{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + values SET --SIZE (1..MAX)-- OF _ATTRIBUTE.&Type({AttrSet}{@type}) +} + +_EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType, + &Critical BOOLEAN DEFAULT FALSE +} + +Extension{_EXTENSION:ExtensionSet} ::= SEQUENCE { + extnID _EXTENSION.&id({ExtensionSet}), + critical BOOLEAN +-- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + extnValue OCTET STRING (CONTAINING + _EXTENSION.&ExtnType({ExtensionSet}{@extnID})) +} + +Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + +TBSCertificate ::= SEQUENCE { + version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING -- UniqueIdentifier -- OPTIONAL, + -- If present, version shall be v2 or v3 + subjectUniqueID [2] IMPLICIT BIT STRING -- UniqueIdentifier -- OPTIONAL, + -- If present, version shall be v2 or v3 + extensions [3] EXPLICIT Extensions OPTIONAL + -- If present, version shall be v3 +} + +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +Certificates ::= SEQUENCE OF Certificate + +ValidationParms ::= SEQUENCE { + seed BIT STRING, + pgenCounter INTEGER +} + +DomainParameters ::= SEQUENCE { + p INTEGER, -- odd prime, p=jq +1 + g INTEGER, -- generator, g + q INTEGER OPTIONAL, -- factor of p-1 + j INTEGER OPTIONAL, -- subgroup factor + validationParms ValidationParms OPTIONAL -- ValidationParms +} + +-- As defined by PKCS3 +DHParameter ::= SEQUENCE { + prime INTEGER, -- odd prime, p=jq +1 + base INTEGER, -- generator, g + privateValueLength INTEGER OPTIONAL +} + +DHPublicKey ::= INTEGER + +GeneralName ::= CHOICE { + otherName [0] IMPLICIT OtherName, + rfc822Name [1] IMPLICIT IA5String, + dNSName [2] IMPLICIT IA5String, +-- x400Address [3] IMPLICIT ORAddress,-- + directoryName [4] IMPLICIT Name, +-- ediPartyName [5] IMPLICIT EDIPartyName, -- + uniformResourceIdentifier [6] IMPLICIT IA5String, + iPAddress [7] IMPLICIT OCTET STRING, + registeredID [8] IMPLICIT OBJECT IDENTIFIER +} + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +id-x509-ce-keyUsage OBJECT IDENTIFIER ::= { id-x509-ce 15 } + +KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) +} + +-- private key usage period extension OID and syntax + +PrivateKeyUsagePeriod ::= SEQUENCE { + notBefore [0] IMPLICIT GeneralizedTime OPTIONAL, + notAfter [1] IMPLICIT GeneralizedTime OPTIONAL + -- either notBefore or notAfter MUST be present +} + +-- certificate policies extension OID and syntax + +_POLICYQUALIFIERINFO ::= CLASS { -- Heimdal extension + &id OBJECT IDENTIFIER UNIQUE, + &Type +} + +CertPolicyId ::= OBJECT IDENTIFIER +PolicyQualifierId ::= OBJECT IDENTIFIER -- ( id-qt-cps | id-qt-unotice ) + +PolicyQualifierInfo{_POLICYQUALIFIERINFO:PolicyQualifierSet} ::= SEQUENCE { + policyQualifierId _POLICYQUALIFIERINFO.&id({PolicyQualifierSet}), + qualifier _POLICYQUALIFIERINFO.&Type({PolicyQualifierSet}{@policyQualifierId}) +} + +PolicyQualifierInfos ::= SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo + +PolicyInformation ::= SEQUENCE { + policyIdentifier CertPolicyId, + policyQualifiers PolicyQualifierInfos OPTIONAL +} + +CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + +-- CPS pointer qualifier + +CPSuri ::= IA5String + +-- user notice qualifier + +DisplayText ::= CHOICE { + ia5String IA5String, --(SIZE (1..200)) + visibleString VisibleString, --(SIZE (1..200)) + bmpString BMPString, --(SIZE (1..200)) + utf8String UTF8String --(SIZE (1..200)) +} + +NoticeReference ::= SEQUENCE { + organization DisplayText, + noticeNumbers SEQUENCE OF INTEGER +} + +UserNotice ::= SEQUENCE { + noticeRef NoticeReference OPTIONAL, + explicitText DisplayText OPTIONAL +} + +-- policy mapping extension OID and syntax + +PolicyMapping ::= SEQUENCE { + issuerDomainPolicy CertPolicyId, + subjectDomainPolicy CertPolicyId +} + +PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF PolicyMapping + +-- subject key identifier OID and syntax + +id-x509-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-x509-ce 35 } + +KeyIdentifier ::= OCTET STRING + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] IMPLICIT OCTET STRING OPTIONAL, + authorityCertIssuer [1] IMPLICIT -- GeneralName -- + SEQUENCE -- SIZE (1..MAX) -- OF GeneralName OPTIONAL, + authorityCertSerialNumber [2] IMPLICIT INTEGER OPTIONAL +} + +id-x509-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-x509-ce 14 } + +SubjectKeyIdentifier ::= KeyIdentifier + +id-x509-ce-basicConstraints OBJECT IDENTIFIER ::= { id-x509-ce 19 } + +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..4294967295) OPTIONAL +} + +id-x509-ce-nameConstraints OBJECT IDENTIFIER ::= { id-x509-ce 30 } + +BaseDistance ::= INTEGER (0..4294967295) + +GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] IMPLICIT BaseDistance DEFAULT 0, + maximum [1] IMPLICIT BaseDistance OPTIONAL +} + +GeneralSubtrees ::= SEQUENCE -- SIZE (1..MAX) -- OF GeneralSubtree + +NameConstraints ::= SEQUENCE { + permittedSubtrees [0] IMPLICIT -- GeneralSubtrees -- SEQUENCE OF GeneralSubtree OPTIONAL, + excludedSubtrees [1] IMPLICIT -- GeneralSubtrees -- SEQUENCE OF GeneralSubtree OPTIONAL +} + +id-x509-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-x509-ce 16 } +id-x509-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-x509-ce 32 } +id-x509-ce-certificatePolicies-anyPolicy OBJECT IDENTIFIER ::= { id-x509-ce-certificatePolicies 0 } +id-x509-ce-policyMappings OBJECT IDENTIFIER ::= { id-x509-ce 33 } +id-x509-ce-subjectAltName OBJECT IDENTIFIER ::= { id-x509-ce 17 } +id-x509-ce-issuerAltName OBJECT IDENTIFIER ::= { id-x509-ce 18 } +id-x509-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-x509-ce 9 } +id-x509-ce-policyConstraints OBJECT IDENTIFIER ::= { id-x509-ce 36 } + +id-x509-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-x509-ce 37} +id-x509-ce-anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-x509-ce-extKeyUsage 0 } + +ExtKeyUsage ::= SEQUENCE OF OBJECT IDENTIFIER + +id-x509-ce-cRLReasons OBJECT IDENTIFIER ::= { id-x509-ce 21 } +id-x509-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-x509-ce 31 } +id-x509-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-x509-ce 27 } +id-x509-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-x509-ce 28 } +id-x509-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-x509-ce 23 } +id-x509-ce-invalidityDate OBJECT IDENTIFIER ::= { id-x509-ce 24 } +id-x509-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-x509-ce 29 } +id-x509-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-x509-ce 54 } + +-- Heimdal extension +id-heim-ce-pkinit-princ-max-life OBJECT IDENTIFIER ::= + { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 4 } + + +DistributionPointReasonFlags ::= BIT STRING { + unused (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) +} + +DistributionPointName ::= CHOICE { + fullName [0] IMPLICIT -- GeneralNames -- SEQUENCE SIZE (1..MAX) OF GeneralName, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName +} + +DistributionPoint ::= SEQUENCE { + distributionPoint [0] IMPLICIT DistributionPointName OPTIONAL, + reasons [1] IMPLICIT DistributionPointReasonFlags OPTIONAL, + cRLIssuer [2] IMPLICIT GeneralNames OPTIONAL +} + +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + + +-- rfc3279 + +DSASigValue ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +DSAPublicKey ::= INTEGER + +DSAParams ::= SEQUENCE { + p INTEGER, + q INTEGER, + g INTEGER +} + +-- draft-ietf-pkix-ecc-subpubkeyinfo-11 + +ECPoint ::= OCTET STRING + +ECParameters ::= CHOICE { + namedCurve OBJECT IDENTIFIER + -- implicitCurve NULL + -- specifiedCurve SpecifiedECDomain +} + +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +-- really pkcs1 + +RSAPublicKey ::= SEQUENCE { + modulus INTEGER, -- n + publicExponent INTEGER -- e +} + +RSAPrivateKey ::= SEQUENCE { + version INTEGER (0..4294967295), + modulus INTEGER, -- n + publicExponent INTEGER, -- e + privateExponent INTEGER, -- d + prime1 INTEGER, -- p + prime2 INTEGER, -- q + exponent1 INTEGER, -- d mod (p-1) + exponent2 INTEGER, -- d mod (q-1) + coefficient INTEGER -- (inverse of q) mod p +} + +DigestInfo ::= SEQUENCE { + digestAlgorithm AlgorithmIdentifier, + digest OCTET STRING +} + +-- some ms ext + +-- szOID_ENROLL_CERTTYPE_EXTENSION "1.3.6.1.4.1.311.20.2" is Encoded as a + +-- UNICODESTRING (0x1E tag) + +-- szOID_CERTIFICATE_TEMPLATE "1.3.6.1.4.1.311.21.7" is Encoded as: + +-- TemplateVersion ::= INTEGER (0..4294967295) + +-- CertificateTemplate ::= SEQUENCE { +-- templateID OBJECT IDENTIFIER, +-- templateMajorVersion TemplateVersion, +-- templateMinorVersion TemplateVersion OPTIONAL +-- } + + +-- +-- CRL +-- + +TBSCRLCertList ::= SEQUENCE { + version Version OPTIONAL, -- if present, MUST be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, MUST be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, MUST be v2 +} + + +CRLCertificateList ::= SEQUENCE { + tbsCertList TBSCRLCertList, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +id-x509-ce-cRLNumber OBJECT IDENTIFIER ::= { id-x509-ce 20 } +id-x509-ce-freshestCRL OBJECT IDENTIFIER ::= { id-x509-ce 46 } +id-x509-ce-cRLReason OBJECT IDENTIFIER ::= { id-x509-ce 21 } + +CRLReason ::= ENUMERATED { + unspecified (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + removeFromCRL (8), + privilegeWithdrawn (9), + aACompromise (10) +} + +PKIXXmppAddr ::= UTF8String + +SRVName ::= IA5String -- (SIZE (1..MAX)), but our compiler doesn't do that + +id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + +id-pkix-on OBJECT IDENTIFIER ::= { id-pkix 8 } +id-pkix-on-xmppAddr OBJECT IDENTIFIER ::= { id-pkix-on 5 } +id-pkix-on-dnsSRV OBJECT IDENTIFIER ::= { id-pkix-on 7 } + +-- From RFC4108 +id-pkix-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-pkix-on 4 } +HardwareModuleName ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING +} + +-- XXX Not really the right name +id-pkix-on-pkinit-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) security(5) kerberosv5(2) + x509-sanan(2) } +KRB5PrincipalName ::= SEQUENCE { + realm [0] Realm, + principalName [1] PrincipalName +} + +-- From RFC4043: +-- Permanent identifier Object Identifier and Syntax +id-pkix-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-pkix-on 3 } + +PermanentIdentifier ::= SEQUENCE { + identifierValue UTF8String OPTIONAL, + -- if absent, use the serialNumber attribute + -- if there is a single such attribute present + -- in the subject DN + assigner OBJECT IDENTIFIER OPTIONAL + -- if absent, the assigner is + -- the certificate issuer +} + +-- EKUs +id-pkix-kp OBJECT IDENTIFIER ::= { id-pkix 3 } +id-pkix-kp-serverAuth OBJECT IDENTIFIER ::= { id-pkix-kp 1 } +id-pkix-kp-clientAuth OBJECT IDENTIFIER ::= { id-pkix-kp 2 } +id-pkix-kp-codeSigning OBJECT IDENTIFIER ::= { id-pkix-kp 3 } +id-pkix-kp-emailProtection OBJECT IDENTIFIER ::= { id-pkix-kp 4 } +id-pkix-kp-ipsecEndSystem OBJECT IDENTIFIER ::= { id-pkix-kp 5 } +id-pkix-kp-ipsecTunnel OBJECT IDENTIFIER ::= { id-pkix-kp 6 } +id-pkix-kp-ipsecUser OBJECT IDENTIFIER ::= { id-pkix-kp 7 } +id-pkix-kp-timeStamping OBJECT IDENTIFIER ::= { id-pkix-kp 8 } +id-pkix-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-pkix-kp 9 } +-- The following are taken from RFC7299 and others +id-pkix-kp-DVCS OBJECT IDENTIFIER ::= { id-pkix-kp 10 } +id-pkix-kp-ipsecIKE OBJECT IDENTIFIER ::= { id-pkix-kp 17 } +id-pkix-kp-capwapAC OBJECT IDENTIFIER ::= { id-pkix-kp 18 } +id-pkix-kp-capwapWTP OBJECT IDENTIFIER ::= { id-pkix-kp 19 } +id-pkix-kp-sipDomain OBJECT IDENTIFIER ::= { id-pkix-kp 20 } -- RFC5924 +id-pkix-kp-secureShellClient OBJECT IDENTIFIER ::= { id-pkix-kp 21 } +id-pkix-kp-secureShellServer OBJECT IDENTIFIER ::= { id-pkix-kp 22 } +id-pkix-kp-sendRouter OBJECT IDENTIFIER ::= { id-pkix-kp 23 } +id-pkix-kp-sendProxiedRouter OBJECT IDENTIFIER ::= { id-pkix-kp 24 } +id-pkix-kp-sendOwner OBJECT IDENTIFIER ::= { id-pkix-kp 25 } +id-pkix-kp-sendProxiedOwner OBJECT IDENTIFIER ::= { id-pkix-kp 26 } +id-pkix-kp-cmcCA OBJECT IDENTIFIER ::= { id-pkix-kp 27 } -- RFC6402 +id-pkix-kp-cmcRA OBJECT IDENTIFIER ::= { id-pkix-kp 28 } -- RFC6402 +id-pkix-kp-cmcArchive OBJECT IDENTIFIER ::= { id-pkix-kp 29 } -- RFC6402 +id-pkix-kp-bgpsec-router OBJECT IDENTIFIER ::= { id-pkix-kp 30 } -- RFC8209 +-- The following are MSFT EKUs taken from OpenSSL +id-msft OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 311 } +id-msft-kp-msCodeInd OBJECT IDENTIFIER ::= { id-msft 2 1 21 } +id-msft-kp-msCodeCom OBJECT IDENTIFIER ::= { id-msft 2 1 22 } +id-msft-kp-msCTLSign OBJECT IDENTIFIER ::= { id-msft 10 3 1 } +id-msft-kp-msSGC OBJECT IDENTIFIER ::= { id-msft 10 3 3 } +id-msft-kp-msEFS OBJECT IDENTIFIER ::= { id-msft 10 3 4 } +id-msft-kp-msSmartcardLogin OBJECT IDENTIFIER ::= { id-msft 20 2 2 } +id-msft-kp-msUPN OBJECT IDENTIFIER ::= { id-msft 20 2 3 } + +id-pkix-pe OBJECT IDENTIFIER ::= { id-pkix 1 } +id-pkix-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pkix-pe 1 } + +AccessDescription ::= SEQUENCE { + accessMethod OBJECT IDENTIFIER, + accessLocation GeneralName +} + +AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription + +-- RFC 3820 Proxy Certificate Profile + +id-pkix-pe-proxyCertInfo OBJECT IDENTIFIER ::= { id-pkix-pe 14 } + +id-pkix-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pkix-pe 11 } + +SubjectInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +id-pkix-ppl OBJECT IDENTIFIER ::= { id-pkix 21 } + +id-pkix-ppl-anyLanguage OBJECT IDENTIFIER ::= { id-pkix-ppl 0 } +id-pkix-ppl-inheritAll OBJECT IDENTIFIER ::= { id-pkix-ppl 1 } +id-pkix-ppl-independent OBJECT IDENTIFIER ::= { id-pkix-ppl 2 } + +ProxyPolicy ::= SEQUENCE { + policyLanguage OBJECT IDENTIFIER, + policy OCTET STRING OPTIONAL +} + +ProxyCertInfo ::= SEQUENCE { + pCPathLenConstraint INTEGER (0..4294967295) OPTIONAL, -- really MAX + proxyPolicy ProxyPolicy +} + +-- TCG contents: + +-- See tcg.asn1 for commentary. + +--TCG specific OIDs +tcg OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) international-organizations(23) tcg(133)} +tcg-attribute OBJECT IDENTIFIER ::= {tcg 2} +tcg-kp OBJECT IDENTIFIER ::= {tcg 8} + +--TCG Attribute OIDs +tcg-at-tpmManufacturer OBJECT IDENTIFIER ::= {tcg-attribute 1} +tcg-at-tpmModel OBJECT IDENTIFIER ::= {tcg-attribute 2} +tcg-at-tpmVersion OBJECT IDENTIFIER ::= {tcg-attribute 3} +tcg-at-tpmSpecification OBJECT IDENTIFIER ::= {tcg-attribute 16} +tcg-at-tpmSecurityAssertions OBJECT IDENTIFIER ::= {tcg-attribute 18} + +--TCG Attribute objects +at-TPMSecurityAssertions _ATTRIBUTE ::= { &Type TPMSecurityAssertions, &id tcg-at-tpmSecurityAssertions } +at-TPMManufacturer _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmManufacturer } +at-TPMModel _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmModel } +at-TPMVersion _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmVersion } +at-TPMSpecification _ATTRIBUTE ::= { &Type TPMSpecification, &id tcg-at-tpmSpecification } + +--TCG Extended Key Usage OIDs +tcg-kp-EKCertificate OBJECT IDENTIFIER ::= {tcg-kp 1} + +-- OIDs not in the module in TCG_IWG_EKCredentialProfile_v2p3_r2_pub but in +-- TCG_IWG_DevID_v1r2_02dec2020 (missing arc names not mentioned in the TCG +-- specs): +tcg-tpm20 OBJECT IDENTIFIER ::= {tcg 1 2} -- this OID is not named in the TCG specs +tcg-on-ekPermIdSha256 OBJECT IDENTIFIER ::= {tcg 12 1} -- assigner value for PermanentIdentifier SAN +tcg-cap-verifiedTPMResidency OBJECT IDENTIFIER ::= {tcg 11 1 1} -- policy OID +tcg-cap-verifiedTPMFixed OBJECT IDENTIFIER ::= {tcg 11 1 2} -- policy OID +tcg-cap-verifiedTPMRestricted OBJECT IDENTIFIER ::= {tcg 11 1 3} -- policy OID + +EKGenerationType ::= ENUMERATED { + ekgt-internal (0), + ekgt-injected (1), + ekgt-internalRevocable(2), + ekgt-injectedRevocable(3) +} +EKGenerationLocation ::= ENUMERATED { + tpmManufacturer (0), + platformManufacturer (1), + ekCertSigner (2) +} +EKCertificateGenerationLocation ::= EKGenerationLocation -- XXX +EvaluationAssuranceLevel ::= ENUMERATED { + ealevell (1), + ealevel2 (2), + ealevel3 (3), + ealevel4 (4), + ealevel5 (5), + ealevel6 (6), + ealevel7 (7) +} +SecurityLevel ::= ENUMERATED { + sllevel1 (1), + sllevel2 (2), + sllevel3 (3), + sllevel4 (4) +} +StrengthOfFunction ::= ENUMERATED { + sof-basic (0), + sof-medium (1), + sof-high (2) +} +URIReference ::= SEQUENCE { + uniformResourceIdentifier IA5String, -- (SIZE (1..URIMAX)) + hashAlgorithm AlgorithmIdentifier OPTIONAL, + hashValue BIT STRING OPTIONAL +} +EvaluationStatus ::= ENUMERATED { + designedToMeet (0), + evaluationInProgress (1), + evaluationCompleted (2) +} + +--tcg specification attributes for tpm +TPMSpecification ::= SEQUENCE { + family UTF8String, -- (SIZE (1..STRMAX)) + level INTEGER (0..4294967295), + revision INTEGER (0..4294967295), + ... +} + + +--common criteria evaluation +CommonCriteriaMeasures ::= SEQUENCE { + version IA5String, -- (SIZE (1..STRMAX)) “2.2” or “3.1”;future syntax defined by CC + assurancelevel EvaluationAssuranceLevel, + evaluationStatus EvaluationStatus, + plus BOOLEAN DEFAULT FALSE, + strengthOfFunction [0] IMPLICIT StrengthOfFunction OPTIONAL, + profileOid [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL, + profileUri [2] IMPLICIT URIReference OPTIONAL, + targetOid [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL, + targetUri [4] IMPLICIT URIReference OPTIONAL, + ... +} + +--fips evaluation +FIPSLevel ::= SEQUENCE { + version IA5String, -- (SIZE (1..STRMAX)) “140-1” or “140-2” + level SecurityLevel, + plus BOOLEAN DEFAULT FALSE, + ... +} + +--tpm security assertions +TPMVersion ::= INTEGER { tpm-v1(0) } +TPMSecurityAssertions ::= SEQUENCE { + version TPMVersion DEFAULT 0, -- v1 + fieldUpgradable BOOLEAN DEFAULT FALSE, + -- The TCG EK cert profile spec says all these context tags are IMPLICIT, + -- but samples in the field have them as EXPLICIT. + ekGenerationType [0] EXPLICIT EKGenerationType OPTIONAL, + ekGenerationLocation [1] EXPLICIT EKGenerationLocation OPTIONAL, + ekCertificateGenerationLocation [2] EXPLICIT EKCertificateGenerationLocation OPTIONAL, + ccInfo [3] EXPLICIT CommonCriteriaMeasures OPTIONAL, + fipsLevel [4] EXPLICIT FIPSLevel OPTIONAL, + iso9000Certified [5] EXPLICIT BOOLEAN DEFAULT FALSE, + iso9000Uri IA5String OPTIONAL, -- (SIZE (1..URIMAX)) + ... +} + +-- Back to OtherName, SingleAttribute, AttributeSet, and Extension + +-- XXX Not really the right name for this OID: +id-pkix-on-pkinit-ms-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 3 } + +-- XXX Work around bug (where we don't know the names of universal types in the +-- template backend) by creating aliases for universal types we use in IOS +-- objects. +AliasUTF8String ::= UTF8String +AliasIA5String ::= UTF8String +AliasPrintableString ::= PrintableString +on-xmppAddr _OTHER-NAME ::= { &id id-pkix-on-xmppAddr, &Type AliasUTF8String } +on-dnsSRV _OTHER-NAME ::= { &id id-pkix-on-dnsSRV, &Type AliasIA5String } +on-hardwareModuleName _OTHER-NAME ::= { + &id id-pkix-on-hardwareModuleName, + &Type HardwareModuleName +} +on-permanentIdentifier _OTHER-NAME ::= { + &id id-pkix-on-permanentIdentifier, + &Type PermanentIdentifier +} +on-krb5PrincipalName _OTHER-NAME ::= { + &id id-pkix-on-pkinit-san, + &Type KRB5PrincipalName +} +on-pkinit-ms-san _OTHER-NAME ::= { + &id id-pkix-on-pkinit-ms-san, + &Type AliasUTF8String +} + +KnownOtherNameTypes _OTHER-NAME ::= { + on-xmppAddr + | on-dnsSRV + | on-hardwareModuleName + | on-permanentIdentifier + | on-krb5PrincipalName + | on-pkinit-ms-san +} + +OtherName ::= OtherName{KnownOtherNameTypes} + +X520name ::= DirectoryString --{ub-name} +X520CommonName ::= DirectoryString --{ub-common-name} +X520LocalityName ::= DirectoryString --{ub-locality-name} +X520OrganizationName ::= DirectoryString --{ub-organization-name} +X520StateOrProvinceName ::= DirectoryString --{ub-state-name} +X520OrganizationalUnitName ::= DirectoryString --{ub-organizational-unit-name} + +at-name _ATTRIBUTE ::= { &Type X520name, &id id-at-name } +at-surname _ATTRIBUTE ::= { &Type X520name, &id id-at-surname } +at-givenName _ATTRIBUTE ::= { &Type X520name, &id id-at-givenName } +at-initials _ATTRIBUTE ::= { &Type X520name, &id id-at-initials } +at-generationQualifier _ATTRIBUTE ::= { &Type X520name, &id id-at-generationQualifier } +at-x520CommonName _ATTRIBUTE ::= {&Type X520CommonName, &id id-at-commonName } +at-x520LocalityName _ATTRIBUTE ::= { &Type X520LocalityName, &id id-at-localityName } +at-x520StateOrProvinceName _ATTRIBUTE ::= { &Type DirectoryString --{ub-state-name}--, &id id-at-stateOrProvinceName } +at-x520OrganizationName _ATTRIBUTE ::= { &Type DirectoryString --{ub-organization-name}--, &id id-at-organizationName } +at-x520OrganizationalUnitName _ATTRIBUTE ::= { &Type DirectoryString --{ub-organizational-unit-name}--, &id id-at-organizationalUnitName } +at-x520Title _ATTRIBUTE ::= { &Type DirectoryString --{ub-title}--, &id id-at-title } +at-x520dnQualifier _ATTRIBUTE ::= { &Type AliasPrintableString, &id id-at-dnQualifier } +at-x520countryName _ATTRIBUTE ::= { &Type AliasPrintableString --(SIZE (2))--, &id id-at-countryName } +at-x520SerialNumber _ATTRIBUTE ::= {&Type AliasPrintableString --(SIZE (1..ub-serial-number))--, &id id-at-serialNumber } +at-x520Pseudonym _ATTRIBUTE ::= { &Type DirectoryString --{ub-pseudonym}--, &id id-at-pseudonym } +at-domainComponent _ATTRIBUTE ::= { &Type AliasIA5String, &id id-domainComponent } +at-emailAddress _ATTRIBUTE ::= { &Type AliasIA5String --(SIZE (1..ub-emailaddress-length))--, &id id-at-emailAddress } + +SupportedAttributes _ATTRIBUTE ::= { + at-name + | at-surname + | at-givenName + | at-initials + | at-generationQualifier + | at-x520CommonName + | at-x520LocalityName + | at-x520StateOrProvinceName + | at-x520OrganizationName + | at-x520OrganizationalUnitName + | at-x520Title + | at-x520dnQualifier + | at-x520countryName + | at-x520SerialNumber + | at-x520Pseudonym + | at-domainComponent + | at-emailAddress + | at-TPMSecurityAssertions + | at-TPMManufacturer + | at-TPMModel + | at-TPMVersion + | at-TPMSpecification +} + +SingleAttribute ::= SingleAttribute{SupportedAttributes} +AttributeSet ::= AttributeSet{SupportedAttributes} +SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF AttributeSet + +ext-AuthorityKeyIdentifier _EXTENSION ::= { + &id id-x509-ce-authorityKeyIdentifier, + &Critical FALSE, + &ExtnType AuthorityKeyIdentifier +} +ext-KeyUsage _EXTENSION ::= { + &id id-x509-ce-keyUsage, + &Critical FALSE, + &ExtnType KeyUsage +} +ext-SubjectKeyIdentifier _EXTENSION ::= { + &id id-x509-ce-subjectKeyIdentifier, + &Critical FALSE, + &ExtnType SubjectKeyIdentifier +} +ext-PrivateKeyUsagePeriod _EXTENSION ::= { + &id id-x509-ce-privateKeyUsagePeriod, + &Critical FALSE, + &ExtnType PrivateKeyUsagePeriod +} +ext-CertificatePolicies _EXTENSION ::= { + &id id-x509-ce-certificatePolicies, + &Critical FALSE, + &ExtnType CertificatePolicies +} +ext-PolicyMappings _EXTENSION ::= { + &id id-x509-ce-policyMappings, + &Critical FALSE, + &ExtnType PolicyMappings +} +ext-SubjectAltName _EXTENSION ::= { + &id id-x509-ce-subjectAltName, + &Critical FALSE, + &ExtnType GeneralNames +} +ext-IssuerAltName _EXTENSION ::= { + &id id-x509-ce-issuerAltName, + &Critical FALSE, + &ExtnType GeneralNames +} +ext-SubjectDirectoryAttributes _EXTENSION ::= { + &id id-x509-ce-subjectDirectoryAttributes, + &Critical FALSE, + &ExtnType SubjectDirectoryAttributes +} +ext-BasicConstraints _EXTENSION ::= { + &id id-x509-ce-basicConstraints, + &Critical FALSE, + &ExtnType BasicConstraints +} +ext-NameConstraints _EXTENSION ::= { + &id id-x509-ce-nameConstraints, + &Critical FALSE, + &ExtnType NameConstraints +} +SkipCerts ::= INTEGER (0..4294967295) +PolicyConstraints ::= SEQUENCE { + requireExplicitPolicy [0] IMPLICIT SkipCerts OPTIONAL, + inhibitPolicyMapping [1] IMPLICIT SkipCerts OPTIONAL +} +ext-PolicyConstraints _EXTENSION ::= { + &id id-x509-ce-policyConstraints, + &Critical FALSE, + &ExtnType PolicyConstraints +} +ext-ExtKeyUsage _EXTENSION ::= { + &id id-x509-ce-extKeyUsage, + &Critical FALSE, + &ExtnType ExtKeyUsage +} +ext-CRLDistributionPoints _EXTENSION ::= { + &id id-x509-ce-cRLDistributionPoints, + &Critical FALSE, + &ExtnType CRLDistributionPoints +} +ext-InhibitAnyPolicy _EXTENSION ::= { + &id id-x509-ce-inhibitAnyPolicy, + &Critical FALSE, + &ExtnType SkipCerts +} +ext-FreshestCRL _EXTENSION ::= { + &id id-x509-ce-freshestCRL, + &Critical FALSE, + &ExtnType CRLDistributionPoints +} +ext-AuthorityInfoAccess _EXTENSION ::= { + &id id-pkix-pe-authorityInfoAccess, + &Critical FALSE, + &ExtnType AuthorityInfoAccessSyntax +} +ext-SubjectInfoAccessSyntax _EXTENSION ::= { + &id id-pkix-pe-subjectInfoAccess, + &Critical FALSE, + &ExtnType SubjectInfoAccessSyntax +} +ext-ProxyCertInfo _EXTENSION ::= { + &id id-pkix-pe-proxyCertInfo, + &Critical FALSE, + &ExtnType ProxyCertInfo +} +HeimPkinitPrincMaxLifeSecs ::= INTEGER (0..4294967295) +ext-HeimPkinitPrincMaxLife _EXTENSION ::= { + &id id-heim-ce-pkinit-princ-max-life, + &Critical FALSE, + &ExtnType HeimPkinitPrincMaxLifeSecs +} +CertExtensions _EXTENSION ::= { + ext-AuthorityKeyIdentifier + | ext-SubjectKeyIdentifier + | ext-KeyUsage + | ext-PrivateKeyUsagePeriod + | ext-CertificatePolicies + | ext-PolicyMappings + | ext-SubjectAltName + | ext-IssuerAltName + | ext-SubjectDirectoryAttributes + | ext-BasicConstraints + | ext-NameConstraints + | ext-PolicyConstraints + | ext-ExtKeyUsage + | ext-CRLDistributionPoints + | ext-InhibitAnyPolicy + | ext-FreshestCRL + | ext-AuthorityInfoAccess + | ext-SubjectInfoAccessSyntax + | ext-ProxyCertInfo + | ext-HeimPkinitPrincMaxLife +} + +Extension ::= Extension { CertExtensions } + +--- U.S. Federal PKI Common Policy Framework +-- Card Authentication key +id-uspkicommon-card-id OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 6 6 } +id-uspkicommon-piv-interim OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 6 9 1 } + +--- Netscape extensions + +id-netscape OBJECT IDENTIFIER ::= + { joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730) } +id-netscape-cert-comment OBJECT IDENTIFIER ::= { id-netscape 1 13 } + +--- MS extensions + +id-ms-cert-enroll-domaincontroller OBJECT IDENTIFIER ::= + { 1 3 6 1 4 1 311 20 2 } + +-- This is a duplicate of id-pkix-kp-clientAuth +-- id-ms-client-authentication OBJECT IDENTIFIER ::= +-- { 1 3 6 1 5 5 7 3 2 } + +-- DER:1e:20:00:44:00:6f:00:6d:00:61:00:69:00:6e:00:43:00:6f:00:6e:00:74:00:72:00:6f:00:6c:00:6c:00:65:00:72 + +-- Upper bounds: + +ub-name INTEGER ::= 32768 +ub-common-name INTEGER ::= 64 +ub-locality-name INTEGER ::= 128 +ub-state-name INTEGER ::= 128 +ub-organization-name INTEGER ::= 64 +ub-organizational-unit-name INTEGER ::= 64 +ub-title INTEGER ::= 64 +ub-serial-number INTEGER ::= 64 +ub-match INTEGER ::= 128 +ub-emailaddress-length INTEGER ::= 255 +ub-common-name-length INTEGER ::= 64 +ub-country-name-alpha-length INTEGER ::= 2 +ub-country-name-numeric-length INTEGER ::= 3 +ub-domain-defined-attributes INTEGER ::= 4 +ub-domain-defined-attribute-type-length INTEGER ::= 8 +ub-domain-defined-attribute-value-length INTEGER ::= 128 +ub-domain-name-length INTEGER ::= 16 +ub-extension-attributes INTEGER ::= 256 +ub-e163-4-number-length INTEGER ::= 15 +ub-e163-4-sub-address-length INTEGER ::= 40 +ub-generation-qualifier-length INTEGER ::= 3 +ub-given-name-length INTEGER ::= 16 +ub-initials-length INTEGER ::= 5 +ub-integer-options INTEGER ::= 256 +ub-numeric-user-id-length INTEGER ::= 32 +ub-organization-name-length INTEGER ::= 64 +ub-organizational-unit-name-length INTEGER ::= 32 +ub-organizational-units INTEGER ::= 4 +ub-pds-name-length INTEGER ::= 16 +ub-pds-parameter-length INTEGER ::= 30 +ub-pds-physical-address-lines INTEGER ::= 6 +ub-postal-code-length INTEGER ::= 16 +ub-pseudonym INTEGER ::= 128 +ub-surname-length INTEGER ::= 40 +ub-terminal-id-length INTEGER ::= 24 +ub-unformatted-address-length INTEGER ::= 180 +ub-x121-address-length INTEGER ::= 16 + +-- Misc OIDs from RFC5280. We should add related types as well. + +-- Policy qualifiers +id-pkix-qt OBJECT IDENTIFIER ::= { id-pkix 2 } +id-pkix-qt-cps OBJECT IDENTIFIER ::= { id-pkix-qt 1 } +id-pkix-qt-unotice OBJECT IDENTIFIER ::= { id-pkix-qt 2 } + +-- Access description +id-pkix-ad OBJECT IDENTIFIER ::= { id-pkix 48 } +id-pkix-ad-ocsp OBJECT IDENTIFIER ::= { id-pkix-ad 1 } +id-pkix-ad-caIssuers OBJECT IDENTIFIER ::= { id-pkix-ad 2 } +id-pkix-ad-timeStamping OBJECT IDENTIFIER ::= { id-pkix-ad 3 } +id-pkix-ad-caRepository OBJECT IDENTIFIER ::= { id-pkix-ad 5 } + +pq-CPS _POLICYQUALIFIERINFO ::= { + &id id-pkix-qt-cps, + &Type AliasIA5String +} +pq-UserNotice _POLICYQUALIFIERINFO ::= { + &id id-pkix-qt-unotice, + &Type UserNotice +} +KnownPolicyQualifiers _POLICYQUALIFIERINFO ::= { + pq-CPS + | pq-UserNotice +} +PolicyQualifierInfo ::= PolicyQualifierInfo{KnownPolicyQualifiers} + +END diff --git a/third_party/heimdal/lib/asn1/rfc2459.opt b/third_party/heimdal/lib/asn1/rfc2459.opt new file mode 100644 index 0000000..2070568 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc2459.opt @@ -0,0 +1,12 @@ +--preserve-binary=Name +--preserve-binary=TBSCertificate +--preserve-binary=TBSCRLCertList +--sequence=AttributeValues +--sequence=CRLDistributionPoints +--sequence=Extensions +--sequence=GeneralNames +--sequence=RDNSequence +--sequence=Certificates +--sequence=CertificatePolicies +--sequence=PolicyQualifierInfos +--sequence=PolicyMappings diff --git a/third_party/heimdal/lib/asn1/rfc4108.asn1 b/third_party/heimdal/lib/asn1/rfc4108.asn1 new file mode 100644 index 0000000..34f9396 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc4108.asn1 @@ -0,0 +1,207 @@ +CMSFirmwareWrapper + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) + pkcs-9(9) smime(16) modules(0) cms-firmware-wrap(22) } + +DEFINITIONS IMPLICIT TAGS ::= BEGIN + +IMPORTS + -- We moved HardwareModuleName to avoid circular dependencies if + -- we have to have rfc2459 import it from here so we can define an + -- object set of OTHER-NAME class. + EnvelopedData + FROM cms -- [CMS] + { iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }; + + +-- Firmware Package Content Type and Object Identifier + +id-ct-firmwarePackage OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 16 } + +FirmwarePkgData ::= OCTET STRING + + +-- Firmware Package Signed Attributes and Object Identifiers + +id-aa-firmwarePackageID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 35 } + +PreferredPackageIdentifier ::= SEQUENCE { + fwPkgID OBJECT IDENTIFIER, + verNum INTEGER (0..MAX) } + +PreferredOrLegacyPackageIdentifier ::= CHOICE { + preferred PreferredPackageIdentifier, + legacy OCTET STRING } + +PreferredOrLegacyStalePackageIdentifier ::= CHOICE { + preferredStaleVerNum INTEGER (0..MAX), + legacyStaleVersion OCTET STRING } + +FirmwarePackageIdentifier ::= SEQUENCE { + name PreferredOrLegacyPackageIdentifier, + stale PreferredOrLegacyStalePackageIdentifier OPTIONAL } + + +id-aa-targetHardwareIDs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 36 } + +TargetHardwareIdentifiers ::= SEQUENCE OF OBJECT IDENTIFIER + + +id-aa-decryptKeyID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 37 } + +DecryptKeyIdentifier ::= OCTET STRING + + +id-aa-implCryptoAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 38 } + +ImplementedCryptoAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + +id-aa-implCompressAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 43 } + +ImplementedCompressAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + + +id-aa-communityIdentifiers OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 40 } + +HardwareSerialEntry ::= CHOICE { + all NULL, + single OCTET STRING, + block SEQUENCE { + low OCTET STRING, + high OCTET STRING } } + +HardwareModules ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialEntries SEQUENCE OF HardwareSerialEntry } + +CommunityIdentifier ::= CHOICE { + communityOID OBJECT IDENTIFIER, + hwModuleList HardwareModules } + +CommunityIdentifiers ::= SEQUENCE OF CommunityIdentifier + +id-aa-firmwarePackageInfo OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 42 } + +FirmwarePackageInfo ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + dependencies SEQUENCE OF + PreferredOrLegacyPackageIdentifier OPTIONAL } + + +-- Firmware Package Unsigned Attributes and Object Identifiers + +id-aa-wrappedFirmwareKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 39 } + +WrappedFirmwareKey ::= EnvelopedData + + +-- Firmware Package Load Receipt Content Type and Object Identifier + +id-ct-firmwareLoadReceipt OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 17 } + +FWReceiptVersion ::= INTEGER { rfc4108-v1(1) } + +FirmwarePackageLoadReceipt ::= SEQUENCE { + version FWReceiptVersion DEFAULT 1, -- v1, but asn1_compile doesn't handle this + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + fwPkgName PreferredOrLegacyPackageIdentifier, + trustAnchorKeyID OCTET STRING OPTIONAL, + decryptKeyID [1] OCTET STRING OPTIONAL } + +-- Firmware Package Load Error Report Content Type +-- and Object Identifier + +id-ct-firmwareLoadError OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 18 } + +FWErrorVersion ::= FWReceiptVersion + +FirmwarePackageLoadErrorCode ::= ENUMERATED { + decodeFailure (1), + badContentInfo (2), + badSignedData (3), + badEncapContent (4), + badCertificate (5), + badSignerInfo (6), + badSignedAttrs (7), + badUnsignedAttrs (8), + missingContent (9), + noTrustAnchor (10), + notAuthorized (11), + badDigestAlgorithm (12), + badSignatureAlgorithm (13), + unsupportedKeySize (14), + signatureFailure (15), + contentTypeMismatch (16), + badEncryptedData (17), + unprotectedAttrsPresent (18), + badEncryptContent (19), + badEncryptAlgorithm (20), + missingCiphertext (21), + noDecryptKey (22), + decryptFailure (23), + badCompressAlgorithm (24), + missingCompressedContent (25), + decompressFailure (26), + wrongHardware (27), + stalePackage (28), + notInCommunity (29), + unsupportedPackageType (30), + missingDependency (31), + wrongDependencyVersion (32), + insufficientMemory (33), + badFirmware (34), + unsupportedParameters (35), + breaksDependency (36), + otherError (99) } + +VendorLoadErrorCode ::= INTEGER + +CurrentFWConfig ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier } + +FirmwarePackageLoadError ::= SEQUENCE { + version FWErrorVersion DEFAULT 1, -- v1, but see above + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + errorCode FirmwarePackageLoadErrorCode, + vendorErrorCode VendorLoadErrorCode OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier OPTIONAL, + config [1] SEQUENCE OF CurrentFWConfig OPTIONAL } + +-- Other Name syntax for Hardware Module Name + +id-on-hardwareModuleName OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) security(5) + mechanisms(5) pkix(7) on(8) 4 } + +-- Moved to rfc2459.asn1 so we can have the OtherName type decode it +-- automatically: +--HardwareModuleName ::= SEQUENCE { +-- hwType OBJECT IDENTIFIER, +-- hwSerialNum OCTET STRING } + +END diff --git a/third_party/heimdal/lib/asn1/roken_rename.h b/third_party/heimdal/lib/asn1/roken_rename.h new file mode 100644 index 0000000..76e108a --- /dev/null +++ b/third_party/heimdal/lib/asn1/roken_rename.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __roken_rename_h__ +#define __roken_rename_h__ + +#ifndef HAVE_STRTOLL +#define strtoll rk_strtoll +#endif +#ifndef HAVE_STRTOULL +#define strtoull rk_strtoull +#endif + +#endif /* __roken_rename_h__ */ diff --git a/third_party/heimdal/lib/asn1/setchgpw2.asn1 b/third_party/heimdal/lib/asn1/setchgpw2.asn1 new file mode 100644 index 0000000..2f52cb1 --- /dev/null +++ b/third_party/heimdal/lib/asn1/setchgpw2.asn1 @@ -0,0 +1,193 @@ +-- $Id$ + +SETCHGPW2 DEFINITIONS ::= +BEGIN + +IMPORTS PrincipalName, Realm, ENCTYPE FROM krb5; + +ProtocolErrorCode ::= ENUMERATED { + generic-error(0), + unsupported-major-version(1), + unsupported-minor-version(2), + unsupported-operation(3), + authorization-failed(4), + initial-ticket-required(5), + target-principal-unknown(6), + ... +} + +Key ::= SEQUENCE { + enc-type[0] INTEGER, + key[1] OCTET STRING, + ... +} + +Language-Tag ::= UTF8String -- Constrained by RFC3066 + +LangTaggedText ::= SEQUENCE { + language[0] Language-Tag OPTIONAL, + text[1] UTF8String, + ... +} + +-- NULL Op + +Req-null ::= NULL +Rep-null ::= NULL +Err-null ::= NULL + +-- Change password +Req-change-pw ::= SEQUENCE { + old-pw[0] UTF8String, + new-pw[1] UTF8String OPTIONAL, + etypes[2] SEQUENCE OF ENCTYPE OPTIONAL, + ... +} + +Rep-change-pw ::= SEQUENCE { + info-text[0] UTF8String OPTIONAL, + new-pw[1] UTF8String OPTIONAL, + etypes[2] SEQUENCE OF ENCTYPE OPTIONAL +} + +Err-change-pw ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + code[1] ENUMERATED { + generic(0), + wont-generate-new-pw(1), + old-pw-incorrect(2), + new-pw-rejected-geneneric(3), + pw-change-too-short(4), + ... + }, + suggested-new-pw[2] UTF8String OPTIONAL, + ... +} + +-- Change/Set keys +Req-set-keys ::= SEQUENCE { + etypes[0] SEQUENCE OF ENCTYPE, + entropy[1] OCTET STRING, + ... +} + +Rep-set-keys ::= SEQUENCE { + info-text[0] UTF8String OPTIONAL, + kvno[1] INTEGER, + keys[2] SEQUENCE OF Key, + aliases[3] SEQUENCE OF SEQUENCE { + name[0] PrincipalName, + realm[1] Realm OPTIONAL, + ... + }, + ... +} + +Err-set-keys ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + enctypes[1] SEQUENCE OF ENCTYPE OPTIONAL, + code[1] ENUMERATED { + etype-no-support(0), + ... + }, + ... +} + +-- Get password policy +Req-get-pw-policy ::= NULL + +Rep-get-pw-policy ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + policy-name[1] UTF8String OPTIONAL, + description[2] UTF8String OPTIONAL, + ... +} + +Err-get-pw-policy ::= NULL + +-- Get principal aliases +Req-get-princ-aliases ::= NULL + +Rep-get-princ-aliases ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + aliases[1] SEQUENCE OF SEQUENCE { + name[0] PrincipalName, + realm[1] Realm OPTIONAL, + ... + } OPTIONAL, + ... +} + +Err-get-princ-aliases ::= NULL + +-- Get list of encryption types supported by KDC for new types +Req-get-supported-etypes ::= NULL + +Rep-get-supported-etypes ::= SEQUENCE OF ENCTYPE + +Err-get-supported-etypes ::= NULL + +-- Choice switch + +Op-req ::= CHOICE { + null[0] Req-null, + change-pw[1] Req-change-pw, + set-keys[2] Req-set-keys, + get-pw-policy[3] Req-get-pw-policy, + get-princ-aliases[4] Req-get-princ-aliases, + get-supported-etypes[5] Req-get-supported-etypes, + ... +} + +Op-rep ::= CHOICE { + null[0] Rep-null, + change-pw[1] Rep-change-pw, + set-keys[2] Rep-set-keys, + get-pw-policy[3] Rep-get-pw-policy, + get-princ-aliases[4] Rep-get-princ-aliases, + get-supported-etypes[5] Rep-get-supported-etypes, + ... +} + +Op-error ::= CHOICE { + null[0] Err-null, + change-pw[1] Err-change-pw, + set-keys[2] Err-set-keys, + get-pw-policy[3] Err-get-pw-policy, + get-princ-aliases[4] Err-get-princ-aliases, + get-supported-etypes[5] Err-get-supported-etypes, + ... +} + + +Request ::= [ APPLICATION 0 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + languages[2] SEQUENCE OF Language-Tag OPTIONAL, + targ-name[3] PrincipalName OPTIONAL, + targ-realm[4] Realm OPTIONAL, + operation[5] Op-Req, + ... +} + +Response ::= [ APPLICATION 1 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + language[2] Language-Tag DEFAULT "i-default", + result[3] Op-rep OPTIONAL, + ... +} + +Error-Response ::= [ APPLICATION 2 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + language[2] Language-Tag DEFAULT "i-default", + error-code[3] ProtocolErrorCode, + help-text[4] UTF8String OPTIONAL, + op-error[5] Op-error OP-ERROR, + ... +} + +END + +-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' setchgpw2.asn1 diff --git a/third_party/heimdal/lib/asn1/symbol.c b/third_party/heimdal/lib/asn1/symbol.c new file mode 100644 index 0000000..b472ebd --- /dev/null +++ b/third_party/heimdal/lib/asn1/symbol.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include "lex.h" +#include "lex.h" + +static Hashtab *htab; + +struct symhead symbols; + +static int +cmp(void *a, void *b) +{ + Symbol *s1 = (Symbol *) a; + Symbol *s2 = (Symbol *) b; + + return strcmp(s1->name, s2->name); +} + +static unsigned +hash(void *a) +{ + Symbol *s = (Symbol *) a; + + return hashjpw(s->name); +} + +void +initsym(void) +{ + htab = hashtabnew(101, cmp, hash); +} + + +void +output_name(char *s) +{ + char *p; + + for (p = s; *p; ++p) + if (*p == '-' || *p == '.') + *p = '_'; +} + +Symbol * +addsym(char *name) +{ + Symbol key, *s; + + key.name = name; + s = (Symbol *) hashtabsearch(htab, (void *) &key); + if (s == NULL) { + s = (Symbol *) ecalloc(1, sizeof(*s)); + s->name = name; + s->gen_name = estrdup(name); + output_name(s->gen_name); + s->stype = SUndefined; + hashtabadd(htab, s); + //HEIM_TAILQ_INSERT_TAIL(&symbols, s, symlist); + do { + if (((s)->symlist.tqe_next = (&symbols)->tqh_first) != NULL) + (&symbols)->tqh_first->symlist.tqe_prev = &(s)->symlist.tqe_next; + else + (&symbols)->tqh_last = &(s)->symlist.tqe_next; + (&symbols)->tqh_first = (s); + (s)->symlist.tqe_prev = &(&symbols)->tqh_first; + } while (0); + } + return s; +} + +Symbol * +getsym(char *name) +{ + Symbol key; + + key.name = name; + return (Symbol *) hashtabsearch(htab, (void *) &key); +} + +static int +checkfunc(void *ptr, void *arg) +{ + Symbol *s = ptr; + if (s->stype == SUndefined) { + lex_error_message("%s is still undefined\n", s->name); + *(int *) arg = 1; + } + return 0; +} + +int +checkundefined(void) +{ + int f = 0; + hashtabforeach(htab, checkfunc, &f); + return f; +} + +#if 0 +static int +generate_1type(void *ptr, void *arg) +{ + Symbol *s = ptr; + + if (s->stype == Stype && s->type) + generate_type(s); + return 0; +} +#endif + +void +generate_types(void) +{ + Symbol *s; + + if (checkundefined()) + errx(1, "Some types are undefined"); + HEIM_TAILQ_FOREACH_REVERSE(s, &symbols, symhead, symlist) { + if (s->stype == Stype && s->type) + generate_type(s); + } + //hashtabforeach(htab, generate_1type, NULL); +} + +void +emitted_declaration(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_declaration = 1; +} + +void +emitted_definition(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_definition = 1; +} + +void +emitted_tag_enums(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_tag_enums = 1; +} + +void +emitted_asn1(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_asn1 = 1; +} diff --git a/third_party/heimdal/lib/asn1/symbol.h b/third_party/heimdal/lib/asn1/symbol.h new file mode 100644 index 0000000..108749b --- /dev/null +++ b/third_party/heimdal/lib/asn1/symbol.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef _SYMBOL_H +#define _SYMBOL_H + +#include + +enum typetype { + TBitString, + TBoolean, + TChoice, + TEnumerated, + TGeneralString, + TTeletexString, + TGeneralizedTime, + TIA5String, + TInteger, + TNull, + TOID, + TOctetString, + TPrintableString, + TSequence, + TSequenceOf, + TSet, + TSetOf, + TTag, + TType, + TUTCTime, + TUTF8String, + TBMPString, + TUniversalString, + TVisibleString +}; + +typedef enum typetype Typetype; + +struct type; +struct value; +struct typereference; + +struct value { + enum { booleanvalue, + nullvalue, + integervalue, + stringvalue, + objectidentifiervalue + } type; + union { + int booleanvalue; + int64_t integervalue; + char *stringvalue; + struct objid *objectidentifiervalue; + } u; + struct symbol *s; +}; + +struct member { + char *name; + char *gen_name; + char *label; + int64_t val; + int optional; + int ellipsis; + struct type *type; + HEIM_TAILQ_ENTRY(member) members; + struct value *defval; +}; + +typedef struct member Member; + +HEIM_TAILQ_HEAD(memhead, member); + +struct symbol; + +struct tagtype { + int tagclass; + int tagvalue; + enum { TE_IMPLICIT, TE_EXPLICIT } tagenv; +}; + +struct range { + /* + * We can't represent unsigned 64-bit ranges because max might be + * negative... + */ + int64_t min; + int64_t max; +}; + +enum ctype { CT_CONTENTS, CT_USER, CT_TABLE_CONSTRAINT, CT_RANGE } ; + +struct constraint_spec; + +struct iosclassfield { + char *name; + struct type *type; + struct value *defval; + HEIM_TAILQ_ENTRY(iosclassfield) fields; + unsigned long id; + unsigned int optional:1; + unsigned int unique:1; +}; + +typedef struct iosclassfield Field; +HEIM_TAILQ_HEAD(fieldhead, iosclassfield); + +struct iosobjectfield { + char *name; + struct type *type; + struct value *value; + HEIM_TAILQ_ENTRY(iosobjectfield) objfields; + unsigned long id; +}; + +typedef struct iosobjectfield ObjectField; +HEIM_TAILQ_HEAD(objfieldhead, iosobjectfield); + +struct iosclass { + struct symbol *symbol; + struct fieldhead *fields; + unsigned long id; +}; + +typedef struct iosclass IOSClass; + +struct iosobject { + struct symbol *symbol; + struct objfieldhead *objfields; + ObjectField *typeidf; + IOSClass *iosclass; + HEIM_TAILQ_ENTRY(iosobject) objects; + unsigned long id; + unsigned int ellipsis:1; + unsigned int optional:1; +}; + +typedef struct iosobject IOSObject; +HEIM_TAILQ_HEAD(objectshead, iosobject); + +struct iosobjectset { + struct symbol *symbol; + IOSClass *iosclass; + struct objectshead *objects; + unsigned long id; +}; + +typedef struct iosobjectset IOSObjectSet; + +struct typereference { + /* + * For now we don't support link fields, so we don't support chains of more + * than one field. + */ + IOSClass *iosclass; + Field *field; +}; + +struct type { + Typetype type; + struct memhead *members; + struct symbol *symbol; + struct type *subtype; + struct typereference typeref; /* For type fields */ + IOSClass *formal_parameter; + IOSObjectSet *actual_parameter; + struct tagtype tag; + struct range *range; + struct constraint_spec *constraint; + unsigned long id; + unsigned int implicit_choice:1; +}; + +typedef struct type Type; + +struct component_relation_constraint { + char *objectname; + char *membername; +}; + +struct constraint_spec { + enum ctype ctype; + union { + struct { + Type *type; + struct value *encoding; + struct component_relation_constraint crel; + } content; + struct range *range; + } u; +}; + +struct objid { + const char *label; + int value; + struct objid *next; +}; + +struct symbol { + char *name; + char *gen_name; + enum { SUndefined, SValue, Stype, Sparamtype, Sclass, Sobj, Sobjset } stype; + struct value *value; + Type *type; + IOSClass *iosclass; + IOSObject *object; + IOSObjectSet *objectset; + HEIM_TAILQ_ENTRY(symbol) symlist; + unsigned int emitted_asn1:1; + unsigned int emitted_declaration:1; + unsigned int emitted_definition:1; + unsigned int emitted_tag_enums:1; + unsigned int emitted_template:1; +}; + +typedef struct symbol Symbol; + +//HEIM_TAILQ_HEAD(symhead, symbol); +struct symhead { + struct symbol *tqh_first; + struct symbol **tqh_last; +}; + +extern struct symhead symbols; + +void initsym (void); +Symbol *addsym (char *); +Symbol *getsym(char *name); +void output_name (char *); +int checkundefined(void); +void generate_types(void); +void emitted_asn1(const Symbol *); +void emitted_declaration(const Symbol *); +void emitted_definition(const Symbol *); +void emitted_tag_enums(const Symbol *); +#endif diff --git a/third_party/heimdal/lib/asn1/tcg.asn1 b/third_party/heimdal/lib/asn1/tcg.asn1 new file mode 100644 index 0000000..14129b0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/tcg.asn1 @@ -0,0 +1,42 @@ +TCG DEFINITIONS ::= BEGIN + +-- BEGIN Heimdal commentary +-- +-- Copy-pasted from section 4 of +-- https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_EKCredentialProfile_v2p3_r2_pub.pdf +-- https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf +-- and adjusted to compile as follows: +-- +-- - Due to limitations of the Heimdal compiler we've moved all of this +-- module's contents to rfc2459.asn1. +-- +-- - Extensibility markers added to all SEQUENCEs as per the TCG's spec they +-- reserve the right to add fields in the future. +-- - Information Object System annotations commented out (Heimdal does not +-- support them) +-- +-- - Types sorted topologically (at the time I did that the Heimdal ASN.1 +-- compiler wouldn't do that on its own) +-- +-- - Two otherwise equal ENUMERATED types share a definition now (at the time +-- the Heimdal ASN.1 compiler did not prefix labels of ENUMERATED types) +-- +-- A small note for anyone whoever finds this: do not add complex structures as +-- DN attributes, or, indeed, never add DN attributes again. If some metadata +-- is name-like, then add a subjectAlternativeName otherName for it, otherwise +-- add a certificate extension to carry that metadata. And, for any name-like +-- metadata, always always include query and display syntax for it. +-- +-- Anyone designing anything but the simplest schema in ASN.1 should have to +-- learn a bit more about ASN.1 and/or get a review from ASN.1 experts. +-- +-- Anyone designing anything but the simplest x.509 extensions should have to +-- learn a bit more about ASN.1 and x.509 and/or get a review from x.509 +-- experts. +-- +-- Note that a module OID was not provided. Indeed, a valid, complete ASN.1 +-- module was not provided. +-- +-- END Heimdal commentary (though some minor Heimdal commentary appears below) + +END diff --git a/third_party/heimdal/lib/asn1/template.c b/third_party/heimdal/lib/asn1/template.c new file mode 100644 index 0000000..ed215d8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/template.c @@ -0,0 +1,3104 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include +#include +#include +#include + +#ifndef ENOTSUP +/* Very old MSVC CRTs don't have ENOTSUP */ +#define ENOTSUP EINVAL +#endif + +struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { +#define el(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ + sizeof(type) \ + } +#define elber(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name##_ber, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ + sizeof(type) \ + } + el(integer, int), + el(heim_integer, heim_integer), + el(integer, int), + el(integer64, int64_t), + el(unsigned, unsigned), + el(unsigned64, uint64_t), + el(general_string, heim_general_string), + el(octet_string, heim_octet_string), + elber(octet_string, heim_octet_string), + el(ia5_string, heim_ia5_string), + el(bmp_string, heim_bmp_string), + el(universal_string, heim_universal_string), + el(printable_string, heim_printable_string), + el(visible_string, heim_visible_string), + el(utf8string, heim_utf8_string), + el(generalized_time, time_t), + el(utctime, time_t), + el(bit_string, heim_bit_string), + { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, + (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, + (asn1_type_release)der_free_integer, (asn1_type_print)der_print_boolean, + sizeof(int) + }, + el(oid, heim_oid), + el(general_string, heim_general_string), +#undef el +#undef elber +}; + +size_t +_asn1_sizeofType(const struct asn1_template *t) +{ + return t->offset; +} + +/* + * Here is abstraction to not so well evil fact of bit fields in C, + * they are endian dependent, so when getting and setting bits in the + * host local structure we need to know the endianness of the host. + * + * Its not the first time in Heimdal this have bitten us, and some day + * we'll grow up and use #defined constant, but bit fields are still + * so pretty and shiny. + */ + +static void +_asn1_bmember_get_bit(const unsigned char *p, void *data, + unsigned int bit, size_t size) +{ + unsigned int localbit = bit % 8; + if ((*p >> (7 - localbit)) & 1) { +#ifdef WORDS_BIGENDIAN + *(unsigned int *)data |= (1u << ((size * 8) - bit - 1)); +#else + *(unsigned int *)data |= (1u << bit); +#endif + } +} + +int +_asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size) +{ +#ifdef WORDS_BIGENDIAN + if ((*(unsigned int *)data) & (1u << ((size * 8) - bit - 1))) + return 1; + return 0; +#else + if ((*(unsigned int *)data) & (1u << bit)) + return 1; + return 0; +#endif +} + +void +_asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit, + size_t size, unsigned int *bitset) +{ + unsigned int localbit = bit % 8; + + if (_asn1_bmember_isset_bit(data, bit, size)) { + *p |= (1u << (7 - localbit)); + if (*bitset == 0) + *bitset = (7 - localbit) + 1; + } +} + +/* + * Utility function to tell us if the encoding of some type per its template + * will have an outer tag. This is needed when the caller wants to slap on an + * IMPLICIT tag: if the inner type has a tag then we need to replace it. + */ +static int +is_tagged(const struct asn1_template *t) +{ + size_t elements = A1_HEADER_LEN(t); + + t += A1_HEADER_LEN(t); + if (elements != 1) + return 0; + switch (t->tt & A1_OP_MASK) { + case A1_OP_SEQOF: return 0; + case A1_OP_SETOF: return 0; + case A1_OP_BMEMBER: return 0; + case A1_OP_PARSE: return 0; + case A1_OP_TAG: return 1; + case A1_OP_CHOICE: return 1; + case A1_OP_TYPE: return 1; + case A1_OP_TYPE_EXTERN: { + const struct asn1_type_func *f = t->ptr; + + /* + * XXX Add a boolean to struct asn1_type_func to tell us if the type is + * tagged or not. Basically, it's not tagged if it's primitive. + */ + if (f->encode == (asn1_type_encode)encode_heim_any || + f->encode == (asn1_type_encode)encode_HEIM_ANY) + return 0; + abort(); /* XXX */ + } + default: abort(); + } +} + +static size_t +inner_type_taglen(const struct asn1_template *t) +{ + size_t elements = A1_HEADER_LEN(t); + + t += A1_HEADER_LEN(t); + if (elements != 1) + return 0; + switch (t->tt & A1_OP_MASK) { + case A1_OP_SEQOF: return 0; + case A1_OP_SETOF: return 0; + case A1_OP_BMEMBER: return 0; + case A1_OP_PARSE: return 0; + case A1_OP_CHOICE: return 1; + case A1_OP_TYPE: return inner_type_taglen(t->ptr); + case A1_OP_TAG: return der_length_tag(A1_TAG_TAG(t->tt)); + case A1_OP_TYPE_EXTERN: { + const struct asn1_type_func *f = t->ptr; + + /* + * XXX Add a boolean to struct asn1_type_func to tell us if the type is + * tagged or not. Basically, it's not tagged if it's primitive. + */ + if (f->encode == (asn1_type_encode)encode_heim_any || + f->encode == (asn1_type_encode)encode_HEIM_ANY) + return 0; + abort(); /* XXX */ + } + default: abort(); +#ifdef WIN32 + _exit(0); /* Quiet VC */ +#endif + } +} + +/* + * Compare some int of unknown size in a type ID field to the int value in + * some IOS object's type ID template entry. + * + * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)' + * template as the `ttypeid'. + */ +static int +typeid_int_cmp(const void *intp, + int64_t i, + const struct asn1_template *ttypeid) +{ + const struct asn1_template *tint = ttypeid->ptr; + + if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE) + return -1; + if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER && + A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED && + A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER64 && + A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED64 && + A1_PARSE_TYPE(tint[1].tt) != A1T_IMEMBER) + return -1; + switch (tint[0].offset) { + case 8: return i - *(const int64_t *)intp; + case 4: return i - *(const int32_t *)intp; + default: return -1; + } +} + +/* + * Map a logical SET/SEQUENCE member to a template entry. + * + * This should really have been done by the compiler, but clearly it wasn't. + * + * The point is that a struct type's template may be littered with entries that + * don't directly correspond to a struct field (SET/SEQUENCE member), so we + * have to count just the ones that do to get to the one we want. + */ +static const struct asn1_template * +template4member(const struct asn1_template *t, size_t f) +{ + size_t n = (uintptr_t)t->ptr; + size_t i; + + for (i = 0, t++; i < n; t++, i++) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TAG: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: + if (f-- == 0) + return t; + continue; + case A1_OP_OPENTYPE_OBJSET: + case A1_OP_NAME: + return NULL; + default: + continue; + } + } + return NULL; +} + +/* + * Attempt to decode known open type alternatives into a CHOICE-like + * discriminated union. + * + * Arguments: + * + * - object set template + * - decoder flags + * - pointer to memory object (C struct) to decode into + * - template for type ID field of `data' + * - template for open type field of `data' (an octet string or HEIM_ANY) + * + * Returns: + * + * - 0 + * - ENOMEM + * + * Other errors in decoding open type values are ignored, but applications can + * note that an error must have occurred. (Perhaps we should generate a `ret' + * field for the discriminated union we decode into that we could use to + * indicate what went wrong with decoding an open type value? The application + * can always try to decode itself to find out what the error was, but the + * whole point is to save the developer the bother of writing code to decode + * open type values. Then again, the specific cause of any one decode failure + * is not usually very important to users, so it's not very important to + * applications either.) + * + * Here `data' is something like this: + * + * typedef struct SingleAttribute { + * heim_oid type; // <--- decoded already + * HEIM_ANY value; // <--- decoded already + * // We must set this: + * // vvvvvvvv + * struct { + * enum { + * choice_SingleAttribute_iosnumunknown = 0, + * choice_SingleAttribute_iosnum_id_at_name, + * .. + * choice_SingleAttribute_iosnum_id_at_emailAddress, + * } element; // <--- map type ID to enum + * union { + * X520name* at_name; + * X520name* at_surname; + * .. + * AliasIA5String* at_emailAddress; + * } u; // <--- alloc and decode val above into this + * } _ioschoice_value; + * } SingleAttribute; + * + * or + * + * typedef struct AttributeSet { + * heim_oid type; // <--- decoded already + * struct AttributeSet_values { + * unsigned int len; // <--- decoded already + * HEIM_ANY *val; // <--- decoded already + * } values; + * // We must set this: + * // vvvvvvvv + * struct { + * enum { choice_AttributeSet_iosnumunknown = 0, + * choice_AttributeSet_iosnum_id_at_name, + * choice_AttributeSet_iosnum_id_at_surname, + * .. + * choice_AttributeSet_iosnum_id_at_emailAddress, + * } element; // <--- map type ID to enum + * unsigned int len; // <--- set len to len as above + * union { + * X520name *at_name; + * X520name *at_surname; + * .. + * AliasIA5String *at_emailAddress; + * } *val; // <--- alloc and decode vals above into this + * } _ioschoice_values; + * } AttributeSet; + */ +static int +_asn1_decode_open_type(const struct asn1_template *t, + unsigned flags, + void *data, + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t sz, n; + size_t i = 0; + unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + void **dp = NULL; /* Decoded open type struct pointer */ + int *elementp; /* Choice enum pointer */ + int typeid_is_oid = 0; + int typeid_is_int = 0; + int ret = 0; + + /* + * NOTE: Here expressions like `DPO(data, t->offset + ...)' refer to parts + * of a _ioschoice_ struct field of `data'. + * + * Expressions like `DPO(data, topentype->offset + ...)' refer to + * the open type field in `data', which is either a `heim_any', a + * `heim_octet_string', or an array of one of those. + * + * Expressions like `DPO(data, ttypeid->offset)' refer to the open + * type's type ID field in `data'. + */ + + /* + * Minimal setup: + * + * - set type choice to choice__iosnumunknown (zero). + * - set union value to zero + * + * We need a pointer to the choice ID: + * + * typedef struct AttributeSet { + * heim_oid type; // <--- decoded already + * struct AttributeSet_values { + * unsigned int len; // <--- decoded already + * HEIM_ANY *val; // <--- decoded already + * } values; + * struct { + * enum { choice_AttributeSet_iosnumunknown = 0, + * -----------> ... + * } element; // HERE + * ... + * } ... + * } + * + * XXX NOTE: We're assuming that sizeof(enum) == sizeof(int)! + */ + elementp = DPO(data, t->offset); + *elementp = 0; /* Set the choice to choice__iosnumunknown */ + if (t->tt & A1_OS_OT_IS_ARRAY) { + /* + * The open type is a SET OF / SEQUENCE OF -- an array. + * + * Get the number of elements to decode from: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * ------------>unsigned int len; // HERE + * HEIM_ANY *val; + * } values; + * ... + * } + */ + len = *((unsigned int *)DPO(data, topentype->offset)); + + /* + * Set the number of decoded elements to zero for now: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * HEIM_ANY *val; + * } values; + * struct { + * enum { ... } element; + * ------------>unsigned int len; // HERE + * ... + * } _ioschoice_values; + * } + */ + lenp = DPO(data, t->offset + sizeof(*elementp)); + *lenp = 0; + /* + * Get a pointer to the place where we must put the decoded value: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * HEIM_ANY *val; + * } values; + * struct { + * enum { ... } element; + * unsigned int len; + * struct { + * union { SomeType *some_choice; ... } u; + * ------------>} *val; // HERE + * } _ioschoice_values; + * } AttributeSet; + */ + dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + } else { + /* + * Get a pointer to the place where we must put the decoded value: + * + * typedef struct SingleAttribute { + * heim_oid type; + * HEIM_ANY value; + * struct { + * enum { ... } element; + * ------------>union { SomeType *some_choice; ... } u; // HERE + * } _ioschoice_value; + * } SingleAttribute; + */ + dp = DPO(data, t->offset + sizeof(*elementp)); + } + + /* Align `dp' */ + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + *dp = NULL; + + /* + * Find out the type of the type ID member. We currently support only + * integers and OIDs. + * + * Chase through any tags to get to the type. + */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) + return 0; /* Do nothing, silently */ + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE) + return 0; /* Do nothing, silently */ + if (A1_PARSE_TYPE(tint->tt) != A1T_INTEGER && + A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED && + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER64 && + A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED64 && + A1_PARSE_TYPE(tint->tt) != A1T_IMEMBER) + return 0; /* Do nothing, silently (maybe a large int) */ + typeid_is_int = 1; + break; + } + /* It might be cool to support string types as type ID types */ + default: return 0; /* Do nothing, silently */ + } + break; + default: return 0; /* Do nothing, silently */ + } + + /* + * Find the type of the open type. + * + * An object set template looks like: + * + * const struct asn1_template asn1_ObjectSetName[] = { + * // Header entry (in this case it says there's 17 objects): + * { 0, 0, ((void*)17) }, + * + * // here's the name of the object set: + * { A1_OP_NAME, 0, "ObjectSetName" }, + * + * // then three entries per object: object name, object type ID, + * // object type: + * { A1_OP_NAME, 0, "ext-AuthorityInfoAccess" }, + * { A1_OP_OPENTYPE_ID, 0, (const void*)&asn1_oid_oidName }, + * { A1_OP_OPENTYPE, sizeof(SomeType), (const void*)&asn1_SomeType }, + * ... + * }; + * + * `i' being a logical object offset, i*3+3 would be the index of the + * A1_OP_OPENTYPE_ID entry for the current object, and i*3+4 the index of + * the A1_OP_OPENTYPE entry for the current object. + */ + if (t->tt & A1_OS_IS_SORTED) { + size_t left = 0; + size_t right = A1_HEADER_LEN(tos); + const void *vp = DPO(data, ttypeid->offset); + int c = -1; + + while (left < right) { + size_t mid = (left + right) >> 1; + + if ((tos[3 + mid * 3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int) + c = typeid_int_cmp(vp, (intptr_t)tos[3 + mid * 3].ptr, + ttypeid_univ); + else if (typeid_is_oid) + c = der_heim_oid_cmp(vp, tos[3 + mid * 3].ptr); + if (c < 0) { + right = mid; + } else if (c > 0) { + left = mid + 1; + } else { + i = mid; + break; + } + } + if (c) + return 0; /* No match */ + } else { + for (i = 0, n = A1_HEADER_LEN(tos); i < n; i++) { + /* We add 1 to `i' because we're skipping the header */ + if ((tos[3 + i*3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int && + typeid_int_cmp(DPO(data, ttypeid->offset), + (intptr_t)tos[3 + i*3].ptr, + ttypeid_univ)) + continue; + if (typeid_is_oid && + der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[3 + i*3].ptr)) + continue; + break; + } + if (i == n) + return 0; /* No match */ + } + + /* Match! */ + *elementp = i+1; /* Zero is the "unknown" choice, so add 1 */ + + /* + * We want the A1_OP_OPENTYPE template entry. Its `offset' is the sizeof + * the object we'll be decoding into, and its `ptr' is the pointer to the + * template for decoding that type. + */ + tactual_type = &tos[i*3 + 4]; + + /* Decode the encoded open type value(s) */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + /* + * Not a SET OF/SEQUENCE OF open type, just singular. + * + * We need the address of the octet string / ANY field containing the + * encoded open type value: + * + * typedef struct SingleAttribute { + * heim_oid type; + * -------->HEIM_ANY value; // HERE + * struct { + * ... + * } ... + * } + */ + const struct heim_base_data *d = DPOC(data, topentype->offset); + void *o; + + if (d->data && d->length) { + if ((o = calloc(1, tactual_type->offset)) == NULL) + return ENOMEM; + + /* Re-enter to decode the encoded open type value */ + ret = _asn1_decode(tactual_type->ptr, flags, d->data, d->length, o, &sz); + /* + * Store the decoded object in the union: + * + * typedef struct SingleAttribute { + * heim_oid type; + * HEIM_ANY value; + * struct { + * enum { ... } element; + * ------------>union { SomeType *some_choice; ... } u; // HERE + * } _ioschoice_value; + * } SingleAttribute; + * + * All the union arms are pointers. + */ + if (ret) { + _asn1_free(tactual_type->ptr, o); + free(o); + /* + * So we failed to decode the open type -- that should not be fatal + * to decoding the rest of the input. Only ENOMEM should be fatal. + */ + ret = 0; + } else { + *dp = o; + } + } + return ret; + } else { + const struct heim_base_data * const *d; + void **val; /* Array of pointers */ + + /* + * A SET OF/SEQUENCE OF open type, plural. + * + * We need the address of the octet string / ANY array pointer field + * containing the encoded open type values: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * ------------>HEIM_ANY *val; // HERE + * } values; + * ... + * } + * + * We already know the value of the `len' field. + */ + d = DPOC(data, topentype->offset + sizeof(unsigned int)); + while (sizeof(void *) != sizeof(len) && + ((uintptr_t)d) % sizeof(void *) != 0) + d = (const void *)(((const char *)d) + sizeof(len)); + + if ((val = calloc(len, sizeof(*val))) == NULL) + ret = ENOMEM; + + /* Increment the count of decoded values as we decode */ + *lenp = len; + for (i = 0; ret != ENOMEM && i < len; i++) { + if ((val[i] = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + if (ret == 0) + /* Re-enter to decode the encoded open type value */ + ret = _asn1_decode(tactual_type->ptr, flags, d[0][i].data, + d[0][i].length, val[i], &sz); + if (ret) { + _asn1_free(tactual_type->ptr, val[i]); + free(val[i]); + val[i] = NULL; + } + } + if (ret != ENOMEM) + ret = 0; /* See above */ + *dp = val; + return ret; + } +} + +int +_asn1_decode(const struct asn1_template *t, unsigned flags, + const unsigned char *p, size_t len, void *data, size_t *size) +{ + const struct asn1_template *tbase = t; + const struct asn1_template *tdefval = NULL; + size_t elements = A1_HEADER_LEN(t); + size_t oldlen = len; + int ret = 0; + const unsigned char *startp = NULL; + unsigned int template_flags = t->tt; + + /* + * Important notes: + * + * - by and large we don't call _asn1_free() on error, except when we're + * decoding optional things or choices, then we do call _asn1_free() + * here + * + * instead we leave it to _asn1_decode_top() to call _asn1_free() on + * error + * + * - on error all fields of whatever we didn't _asn1_free() must have been + * initialized to sane values because _asn1_decode_top() will call + * _asn1_free() on error, so we must have left everything initialized + * that _asn1_free() could possibly look at + * + * - so we must initialize everything + * + * FIXME? but we mostly rely on calloc() to do this... + * + * - we don't use malloc() unless we're going to write over the whole + * thing with memcpy() or whatever + */ + + /* skip over header */ + t++; + + if (template_flags & A1_HF_PRESERVE) + startp = p; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + + /* Note that the only error returned here would be ENOMEM */ + ret = _asn1_decode_open_type(t, flags, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + if (ret) + return ret; + break; + } + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_NAME: break; + case A1_OP_DEFVAL: + tdefval = t; + break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize, elsize; + void *el = DPO(data, t->offset); + void **pel = (void **)el; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + elsize = _asn1_sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + elsize = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + *pel = calloc(1, elsize); + if (*pel == NULL) + return ENOMEM; + el = *pel; + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->decode)(p, len, el, &newsize); + } + if (ret) { + /* + * Optional field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + _asn1_free(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + f->release(el); + } + free(*pel); + *pel = NULL; + break; + } + } else { + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->decode)(p, len, el, &newsize); + } + } + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)el; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)el; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)el; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)el; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = el; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + break; + } + return ret; /* Error decoding required field */ + } + p += newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + Der_type dertype; + size_t newsize = 0; + size_t datalen, l = 0; + void *olddata = data; + int is_indefinite = 0; + int subflags = flags; + int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + void *el = data = DPO(data, t->offset); + void **pel = (void **)el; + + /* + * XXX If this type (chasing t->ptr through IMPLICIT tags, if this + * one is too, till we find a non-TTag) is a [UNIVERSAL SET] type, + * then we have to accept fields out of order. For each field tag + * we see we'd have to do a linear search of the SET's template + * because it won't be sorted (or we could sort a copy and do a + * binary search on that, but these SETs will always be small so it + * won't be worthwhile). We'll need a utility function to do all + * of this. + */ + ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt), + &dertype, A1_TAG_TAG(t->tt), + &datalen, &l); + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + data = olddata; + break; + } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)data; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)data; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)data; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)data; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = data; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + data = olddata; + break; + } + return ret; /* Error decoding required field */ + } + + p += l; len -= l; + + /* + * Only allow indefinite encoding for OCTET STRING and BER + * for now. Should handle BIT STRING too. + */ + + if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) { + const struct asn1_template *subtype = t->ptr; + subtype++; /* skip header */ + + if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) && + A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING) + subflags |= A1_PF_INDEFINTE; + } + + if (datalen == ASN1_INDEFINITE) { + if ((flags & A1_PF_ALLOW_BER) == 0) + return ASN1_GOT_BER; + is_indefinite = 1; + datalen = len; + if (datalen < 2) + return ASN1_OVERRUN; + /* hide EndOfContent for sub-decoder, catching it below */ + datalen -= 2; + } else if (datalen > len) + return ASN1_OVERRUN; + + if (t->tt & A1_FLAG_OPTIONAL) { + size_t ellen = _asn1_sizeofType(t->ptr); + + *pel = calloc(1, ellen); + if (*pel == NULL) + return ENOMEM; + data = *pel; + } + + if (replace_tag) { + const struct asn1_template *subtype = t->ptr; + int have_tag = 0; + + /* + * So, we have an IMPLICIT tag. What we want to do is find the + * template for the body of the type so-tagged. That's going + * to be a template that has a tag that isn't itself IMPLICIT. + * + * So we chase the pointer in the template until we find such a + * thing, then decode using that template. + */ + while (!have_tag) { + subtype++; + if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG) + replace_tag = (subtype->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + if (replace_tag) { + subtype = subtype->ptr; + continue; + } + if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG) { + ret = _asn1_decode(subtype->ptr, subflags, p, datalen, data, &newsize); + have_tag = 1; + } else { + subtype = subtype->ptr; + } + } + } else { + ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize); + } + if (ret == 0 && !is_indefinite && newsize != datalen) + /* Hidden data */ + ret = ASN1_EXTRA_DATA; + + if (ret == 0) { + if (is_indefinite) { + /* If we use indefinite encoding, the newsize is the datasize. */ + datalen = newsize; + } + + len -= datalen; + p += datalen; + + /* + * Indefinite encoding needs a trailing EndOfContent, + * check for that. + */ + if (is_indefinite) { + ret = der_match_tag_and_length(p, len, ASN1_C_UNIV, + &dertype, UT_EndOfContent, + &datalen, &l); + if (ret == 0 && dertype != PRIM) + ret = ASN1_BAD_ID; + else if (ret == 0 && datalen != 0) + ret = ASN1_INDEF_EXTRA_DATA; + if (ret == 0) { + p += l; len -= l; + } + } + } + if (ret) { + if (!(t->tt & A1_FLAG_OPTIONAL)) + return ret; + + _asn1_free(t->ptr, data); + free(data); + *pel = NULL; + return ret; + } + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + void *el = DPO(data, t->offset); + + /* + * INDEFINITE primitive types are one element after the + * same type but non-INDEFINITE version. + */ + if (flags & A1_PF_INDEFINTE) + type++; + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (asn1_template_prim[type].decode)(p, len, el, &newsize); + if (ret) + return ret; + p += newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t newsize; + size_t ellen = _asn1_sizeofType(t->ptr); + size_t vallength = 0; + + while (len > 0) { + void *tmp; + size_t newlen = vallength + ellen; + if (vallength > newlen) + return ASN1_OVERFLOW; + + /* XXX Slow */ + tmp = realloc(el->val, newlen); + if (tmp == NULL) + return ENOMEM; + + memset(DPO(tmp, vallength), 0, ellen); + el->val = tmp; + + el->len++; + ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len, + DPO(el->val, vallength), &newsize); + if (ret) + return ret; + vallength = newlen; + p += newsize; len -= newsize; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t bsize = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + size_t pos = 0; + + bmember++; + + memset(data, 0, bsize); + + if (len < 1) + return ASN1_OVERRUN; + p++; len--; + + while (belements && len) { + while (bmember->offset / 8 > pos / 8) { + if (len < 1) + break; + p++; len--; + pos += 8; + } + if (len) { + _asn1_bmember_get_bit(p, data, bmember->offset, bsize); + belements--; bmember++; + } + } + len = 0; + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + unsigned int *element = DPO(data, choice->offset); + size_t datalen; + unsigned int i; + + /* + * CHOICE element IDs are assigned in monotonically increasing + * fashion. Therefore any unrealistic value is a suitable invalid + * CHOICE value. The largest binary value (or -1 if treating the + * enum as signed on a twos-complement system, or...) will do. + */ + *element = ~0; + + for (i = 1; i < A1_HEADER_LEN(choice) + 1 && choice[i].tt; i++) { + /* + * This is more permissive than is required. CHOICE + * alternatives must have different outer tags, so in principle + * we should just match the tag at `p' and `len' in sequence to + * the choice alternatives. + * + * Trying every alternative instead happens to do this anyways + * because each one will first match the tag at `p' and `len', + * but if there are CHOICE altnernatives with the same outer + * tag, then we'll allow it, and they had better be unambiguous + * in their internal details, otherwise there would be some + * aliasing. + * + * Arguably the *compiler* should detect ambiguous CHOICE types + * and raise an error, then we don't have to be concerned here + * at all. + */ + ret = _asn1_decode(choice[i].ptr, 0, p, len, + DPO(data, choice[i].offset), &datalen); + if (ret == 0) { + *element = i; + p += datalen; len -= datalen; + break; + } + _asn1_free(choice[i].ptr, DPO(data, choice[i].offset)); + if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && + ret != ASN1_MISSING_FIELD) + return ret; + } + if (i >= A1_HEADER_LEN(choice) + 1 || !choice[i].tt) { + /* + * If this is an extensible CHOICE, then choice->tt will be the + * offset to u.ellipsis. If it's not, then this "extension" is + * an error and must stop parsing it. (We could be permissive + * and throw away the extension, though one might as well just + * mark such a CHOICE as extensible.) + */ + if (choice->tt == 0) + return ASN1_BAD_ID; + + /* This is the ellipsis case */ + *element = 0; + ret = der_get_octet_string(p, len, + DPO(data, choice->tt), &datalen); + if (ret) + return ret; + p += datalen; len -= datalen; + } + + break; + } + default: + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + t++; + elements--; + } + /* if we are using padding, eat up read of context */ + if (template_flags & A1_HF_ELLIPSIS) + len = 0; + + oldlen -= len; + + if (size) + *size = oldlen; + + /* + * saved the raw bits if asked for it, useful for signature + * verification. + */ + if (startp) { + heim_octet_string *save = data; + + save->data = malloc(oldlen); + if (save->data == NULL) + return ENOMEM; + else { + save->length = oldlen; + memcpy(save->data, startp, oldlen); + } + } + return 0; +} + +/* + * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)' + * template as the `ttypeid'. + */ +static int +typeid_int_copy(void *intp, + int64_t i, + const struct asn1_template *ttypeid) +{ + const struct asn1_template *tint = ttypeid->ptr; + + if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE) + return -1; + if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER) + return -1; + switch (tint[0].offset) { + case 8: *((int64_t *)intp) = i; return 0; + case 4: *((int32_t *)intp) = i; return 0; + default: memset(intp, 0, tint[0].offset); return 0; + } +} + +/* See commentary in _asn1_decode_open_type() */ +static int +_asn1_encode_open_type(const struct asn1_template *t, + const void *data, /* NOTE: Not really const */ + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t sz, i; + unsigned int *lenp = NULL; + unsigned int len = 1; + int element = *(const int *)DPOC(data, t->offset); + int typeid_is_oid = 0; + int typeid_is_int = 0; + int enotsup = 0; + int ret = 0; + + if (element == 0 || element >= A1_HEADER_LEN(tos) + 1) + return 0; + + if (t->tt & A1_OS_OT_IS_ARRAY) { + /* The actual `len' is from the decoded open type field */ + len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element)); + + if (!len) + return 0; /* The app may be encoding the open type by itself */ + } + + /* Work out the type ID field's type */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) { + enotsup = 1; + break; + } + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE || + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER) { + enotsup = 1; + break; + } + typeid_is_int = 1; + break; + } + default: enotsup = 1; break; + } + break; + default: enotsup = 1; break; + } + + /* + * The app may not be aware of our automatic open type handling, so if the + * open type already appears to have been encoded, then ignore the decoded + * values. + */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + + if (os->length && os->data) + return 0; + } else { + struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len)); + + while (sizeof(void *) != sizeof(unsigned int) && + ((uintptr_t)os) % sizeof(void *) != 0) + os = (void *)(((char *)os) + sizeof(unsigned int)); + + lenp = DPO(data, topentype->offset); + if (*lenp == len && os[0]->length && os[0]->data) + return 0; + } + + if (typeid_is_int) { + /* + * Copy the int from the type ID object field to the type ID struct + * field. + */ + ret = typeid_int_copy(DPO(data, ttypeid->offset), + (intptr_t)tos[3 + (element-1)*3].ptr, ttypeid_univ); + } else if (typeid_is_oid) { + /* + * Copy the OID from the type ID object field to the type ID struct + * field. + */ + ret = der_copy_oid(tos[3 + (element-1)*3].ptr, DPO(data, ttypeid->offset)); + } else + enotsup = 1; + + /* + * If the app did not already encode the open type, we can't help it if we + * don't know what it is. + */ + if (enotsup) + return ENOTSUP; + + tactual_type = &tos[(element-1)*3 + 4]; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + const void * const *d = DPOC(data, t->offset + sizeof(element)); + + while (sizeof(void *) != sizeof(element) && + ((uintptr_t)d) % sizeof(void *) != 0) { + d = (void *)(((char *)d) + sizeof(element)); + } + + os->length = _asn1_length(tactual_type->ptr, *d); + if ((os->data = malloc(os->length)) == NULL) + return ENOMEM; + ret = _asn1_encode(tactual_type->ptr, (os->length - 1) + (unsigned char *)os->data, os->length, *d, &sz); + } else { + struct heim_base_data *os; + const void * const *val = + DPOC(data, t->offset + sizeof(element) + sizeof(*lenp)); + + if ((os = calloc(len, sizeof(*os))) == NULL) + return ENOMEM; + + *lenp = len; + for (i = 0; ret == 0 && i < len; i++) { + os[i].length = _asn1_length(tactual_type->ptr, val[i]); + if ((os[i].data = malloc(os[i].length)) == NULL) + ret = ENOMEM; + if (ret == 0) + ret = _asn1_encode(tactual_type->ptr, (os[i].length - 1) + (unsigned char *)os[i].data, os[i].length, + val[i], &sz); + } + if (ret) { + for (i = 0; i < (*lenp); i++) + free(os[i].data); + free(os); + *lenp = 0; + return ret; + } + *(struct heim_base_data **)DPO(data, topentype->offset + sizeof(len)) = os; + } + return ret; +} + +int +_asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size) +{ + const struct asn1_template *tbase = t; + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + size_t oldlen = len; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + ret = _asn1_encode_open_type(t, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + if (ret) + return ret; + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_encode(t->ptr, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->encode)(p, len, el, &newsize); + } + + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + const void *olddata = data; + size_t l, datalen = 0; + int replace_tag = 0; + + /* + * XXX If this type (chasing t->ptr through IMPLICIT tags, if this + * one is too) till we find a non-TTag) is a [UNIVERSAL SET] type, + * then we have to sort [a copy of] its template by tag, then + * encode the SET using that sorted template. These SETs will + * generally be small, so when they are we might want to allocate + * the copy on the stack and insertion sort it. We'll need a + * utility function to do all of this. + */ + + data = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } + + replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + + /* IMPLICIT tags need special handling (see gen_encode.c) */ + if (replace_tag) { + unsigned char *pfree, *psave = p; + Der_class found_class; + Der_type found_type = 0; + unsigned int found_tag; + size_t lensave = len; + size_t oldtaglen = 0; + size_t taglen = der_length_tag(A1_TAG_TAG(t->tt));; + + /* Allocate a buffer at least as big as we need */ + len = _asn1_length(t->ptr, data) + taglen; + if ((p = pfree = malloc(len)) == NULL) { + ret = ENOMEM; + } else { + /* + * Encode into it (with the wrong tag, which we'll replace + * below). + */ + p += len - 1; + ret = _asn1_encode(t->ptr, p, len, data, &datalen); + } + if (ret == 0) { + /* Get the old tag and, critically, its length */ + len -= datalen; p -= datalen; + ret = der_get_tag(p + 1, datalen, &found_class, &found_type, + &found_tag, &oldtaglen); + } + if (ret == 0) { + /* Drop the old tag */ + len += oldtaglen; p += oldtaglen; + /* Put the new tag */ + ret = der_put_tag(p, len, + A1_TAG_CLASS(t->tt), + found_type, + A1_TAG_TAG(t->tt), &l); + } + if (ret == 0) { + /* Copy the encoding where it belongs */ + psave -= (datalen + l - oldtaglen); + lensave -= (datalen + l - oldtaglen); + memcpy(psave + 1, p + 1 - l, datalen + l - oldtaglen); + p = psave; + len = lensave; + } + free(pfree); + } else { + /* Easy case */ + ret = _asn1_encode(t->ptr, p, len, data, &datalen); + if (ret) + return ret; + + len -= datalen; p -= datalen; + + ret = der_put_length_and_tag(p, len, datalen, + A1_TAG_CLASS(t->tt), + A1_TAG_TYPE(t->tt), + A1_TAG_TAG(t->tt), &l); + if (ret == 0) { + p -= l; len -= l; + } + } + if (ret) + return ret; + + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (asn1_template_prim[type].encode)(p, len, el, &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + heim_octet_string *val; + unsigned char *elptr = el->val; + size_t i, totallen; + + if (el->len == 0) + break; + + if (el->len > UINT_MAX/sizeof(val[0])) + return ERANGE; + + val = calloc(el->len, sizeof(val[0])); + if (val == NULL) + return ENOMEM; + + for(totallen = 0, i = 0; i < el->len; i++) { + unsigned char *next; + size_t l; + + val[i].length = _asn1_length(t->ptr, elptr); + if (val[i].length) { + val[i].data = malloc(val[i].length); + if (val[i].data == NULL) { + ret = ENOMEM; + break; + } + } + + ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1), + val[i].length, elptr, &l); + if (ret) + break; + + next = elptr + ellen; + if (next < elptr) { + ret = ASN1_OVERFLOW; + break; + } + elptr = next; + totallen += val[i].length; + } + if (ret == 0 && totallen > len) + ret = ASN1_OVERFLOW; + if (ret) { + for (i = 0; i < el->len; i++) + free(val[i].data); + free(val); + return ret; + } + + len -= totallen; + + qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); + + i = el->len - 1; + do { + p -= val[i].length; + memcpy(p + 1, val[i].data, val[i].length); + free(val[i].data); + } while(i-- > 0); + free(val); + + break; + + } + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + size_t newsize; + unsigned int i; + unsigned char *elptr = el->val; + + if (el->len == 0) + break; + + elptr += ellen * (el->len - 1); + + for (i = 0; i < el->len; i++) { + ret = _asn1_encode(t->ptr, p, len, + elptr, + &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + elptr -= ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t bsize = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + size_t pos; + unsigned char c = 0; + unsigned int bitset = 0; + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + bmember += belements; + + if (rfc1510) + pos = 31; + else + pos = bmember->offset; + + while (belements && len) { + while (bmember->offset / 8 < pos / 8) { + if (rfc1510 || bitset || c) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + c = 0; + pos -= 8; + } + _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset); + belements--; bmember--; + } + if (rfc1510 || bitset) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + + if (len < 1) + return ASN1_OVERFLOW; + if (rfc1510 || bitset == 0) + *p-- = 0; + else + *p-- = bitset - 1; + + len--; + + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + size_t datalen; + const void *el; + + if (*element > A1_HEADER_LEN(choice)) { + printf("element: %d\n", *element); + return ASN1_PARSE_ERROR; + } + + if (*element == 0) { + if (choice->tt) { + /* This is an extensible CHOICE */ + ret += der_put_octet_string(p, len, + DPOC(data, choice->tt), &datalen); + len -= datalen; p -= datalen; + } /* else this is really an error -- XXX what to do? */ + } else { + choice += *element; + el = DPOC(data, choice->offset); + ret = _asn1_encode(choice->ptr, p, len, el, &datalen); + if (ret) + return ret; + len -= datalen; p -= datalen; + } + + break; + } + default: + ABORT_ON_ERROR(); + } + t--; + elements--; + } + if (size) + *size = oldlen - len; + + return 0; +} + +static size_t +_asn1_length_open_type_helper(const struct asn1_template *t, + size_t sz) +{ + const struct asn1_template *tinner = t->ptr; + + switch (t->tt & A1_OP_MASK) { + case A1_OP_TAG: + /* XXX Not tail-recursive :( */ + sz = _asn1_length_open_type_helper(tinner, sz); + sz += der_length_len(sz); + sz += der_length_tag(A1_TAG_TAG(t->tt)); + return sz; + default: + return sz; + } +} + +static size_t +_asn1_length_open_type_id(const struct asn1_template *t, + const void *data) +{ + struct asn1_template pretend[2] = { + { 0, 0, ((void*)(uintptr_t)1) }, + }; + pretend[1] = *t; + while ((t->tt & A1_OP_MASK) == A1_OP_TAG) + t = t->ptr; + pretend[0].offset = t->offset; + return _asn1_length(pretend, data); +} + +/* See commentary in _asn1_encode_open_type() */ +static size_t +_asn1_length_open_type(const struct asn1_template *tbase, + const struct asn1_template *t, + const void *data, + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + const unsigned int *lenp = NULL; + unsigned int len = 1; + size_t sz = 0; + size_t i; + int element = *(const int *)DPOC(data, t->offset); + int typeid_is_oid = 0; + int typeid_is_int = 0; + + /* If nothing to encode, we add nothing to the length */ + if (element == 0 || element >= A1_HEADER_LEN(tos) + 1) + return 0; + if (t->tt & A1_OS_OT_IS_ARRAY) { + len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element)); + if (!len) + return 0; + } + + /* Work out the type ID field's type */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) + return 0; + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE || + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER) + return 0; + typeid_is_int = 1; + break; + } + default: return 0; + } + break; + default: return 0; + } + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + + if (os->length && os->data) + return 0; + } else { + struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len)); + + while (sizeof(void *) != sizeof(unsigned int) && + ((uintptr_t)os) % sizeof(void *) != 0) + os = (void *)(((char *)os) + sizeof(unsigned int)); + + lenp = DPOC(data, topentype->offset); + if (*lenp == len && os[0]->length && os[0]->data) + return 0; + } + + /* Compute the size of the type ID field */ + if (typeid_is_int) { + int64_t i8; + int32_t i4; + + switch (ttypeid_univ->offset) { + case 8: + i8 = (intptr_t)t->ptr; + sz = _asn1_length_open_type_id(ttypeid, &i8); + i8 = 0; + sz -= _asn1_length_open_type_id(ttypeid, &i8); + break; + case 4: + i4 = (intptr_t)t->ptr; + sz = _asn1_length_open_type_id(ttypeid, &i4); + i4 = 0; + sz -= _asn1_length_open_type_id(ttypeid, &i8); + break; + default: + return 0; + } + } else if (typeid_is_oid) { + heim_oid no_oid = { 0, 0 }; + + sz = _asn1_length_open_type_id(ttypeid, tos[3 + (element - 1)*3].ptr); + sz -= _asn1_length_open_type_id(ttypeid, &no_oid); + } + + tactual_type = &tos[(element-1)*3 + 4]; + + /* Compute the size of the encoded value(s) */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + const void * const *d = DPOC(data, t->offset + sizeof(element)); + + while (sizeof(void *) != sizeof(element) && + ((uintptr_t)d) % sizeof(void *) != 0) + d = (void *)(((char *)d) + sizeof(element)); + if (*d) + sz += _asn1_length(tactual_type->ptr, *d); + } else { + size_t bodysz; + const void * const * val = + DPOC(data, t->offset + sizeof(element) + sizeof(*lenp)); + + /* Compute the size of the encoded SET OF / SEQUENCE OF body */ + for (i = 0, bodysz = 0; i < len; i++) { + if (val[i]) + bodysz += _asn1_length(tactual_type->ptr, val[i]); + } + + /* + * We now know the size of the body of the SET OF or SEQUENCE OF. Now + * we just need to count the length of all the TLs on the outside. + */ + sz += _asn1_length_open_type_helper(topentype, bodysz); + } + return sz; +} + +size_t +_asn1_length(const struct asn1_template *t, const void *data) +{ + const struct asn1_template *tbase = t; + size_t elements = A1_HEADER_LEN(t); + size_t ret = 0; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + ret += _asn1_length_open_type(tbase, t, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret += _asn1_length(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + ret += (f->length)(el); + } + break; + } + case A1_OP_TAG: { + size_t datalen; + const void *olddata = data; + size_t oldtaglen = 0; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + exclude = 1; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } + + if (t->tt & A1_FLAG_IMPLICIT) + oldtaglen = inner_type_taglen(t->ptr); + + datalen = _asn1_length(t->ptr, data); + ret += datalen; + ret += der_length_tag(A1_TAG_TAG(t->tt)); + ret += oldtaglen ? -oldtaglen : der_length_len(datalen); + data = olddata; + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + ret += (asn1_template_prim[type].length)(el); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + ret += _asn1_length(t->ptr, element); + element += ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + if (rfc1510) { + ret += 5; + } else { + + ret += 1; + + bmember += belements; + + while (belements) { + if (_asn1_bmember_isset_bit(data, bmember->offset, size)) { + ret += (bmember->offset / 8) + 1; + break; + } + belements--; bmember--; + } + } + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + if (choice->tt) + ret += der_length_octet_string(DPOC(data, choice->tt)); + } else { + choice += *element; + ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + elements--; + t--; + } + return ret; +} + +/* See commentary in _asn1_decode_open_type() */ +static void +_asn1_free_open_type(const struct asn1_template *t, /* object set template */ + void *data) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + size_t i; + void **dp; + void **val; + int *elementp = DPO(data, t->offset); /* Choice enum pointer */ + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) + return; /* Unknown choice -> it's not decoded, nothing to free here */ + tactual_type = tos[3*(*elementp - 1) + 4].ptr; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dp = DPO(data, t->offset + sizeof(*elementp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + if (*dp) { + _asn1_free(tactual_type, *dp); + free(*dp); + *dp = NULL; + } + return; + } + + lenp = DPO(data, t->offset + sizeof(*elementp)); + len = *lenp; + dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + val = *dp; + + for (i = 0; i < len; i++) { + if (val[i]) { + _asn1_free(tactual_type, val[i]); + free(val[i]); + } + } + free(val); + *lenp = 0; + *dp = NULL; +} + +void +_asn1_free(const struct asn1_template *t, void *data) +{ + size_t elements = A1_HEADER_LEN(t); + + if (t->tt & A1_HF_PRESERVE) + der_free_octet_string(data); + + t++; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + _asn1_free_open_type(t, data); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: + case A1_OP_TYPE_DECORATE: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + void *el = DPO(data, t->offset); + void **pel = (void **)el; + + if (t->tt & A1_FLAG_OPTIONAL) { + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + _asn1_free(t->ptr, el); + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { + const struct asn1_type_func *f = t->ptr; + (f->release)(el); + } else { + /* A1_OP_TYPE_DECORATE_EXTERN */ + const struct asn1_type_func *f = t->ptr; + + if (f && f->release) + (f->release)(el); + else if (f) + memset(el, 0, f->size); + } + if (t->tt & A1_FLAG_OPTIONAL) { + free(el); + *pel = NULL; + } + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + void *el = DPO(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + (asn1_template_prim[type].release)(el); + break; + } + case A1_OP_TAG: { + void *el = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + + if (*pel == NULL) + break; + _asn1_free(t->ptr, *pel); + free(*pel); + *pel = NULL; + } else { + _asn1_free(t->ptr, el); + } + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + _asn1_free(t->ptr, element); + element += ellen; + } + free(el->val); + el->val = NULL; + el->len = 0; + + break; + } + case A1_OP_BMEMBER: + break; + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + /* + * If choice->tt != 0 then this is an extensible choice, and + * the offset choice->tt is the offset to u.ellipsis. + */ + if (choice->tt != 0) + der_free_octet_string(DPO(data, choice->tt)); + /* + * Else this was a not-fully initialized CHOICE. We could + * stand to memset clear the rest of it though... + */ + } else { + choice += *element; + _asn1_free(choice->ptr, DPO(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } +} + +static char * +getindent(int flags, unsigned int i) +{ + char *s; + + if (!(flags & ASN1_PRINT_INDENT) || i == 0) + return NULL; + if (i > 128) + i = 128; + if ((s = malloc(i * 2 + 2)) == NULL) + return NULL; + s[0] = '\n'; + s[i * 2 + 1] = '\0'; + memset(s + 1, ' ', i * 2); + return s; +} + +static struct rk_strpool *_asn1_print(const struct asn1_template *, + struct rk_strpool *, + int, + unsigned int, + const void *, + const heim_octet_string *); + +/* See commentary in _asn1_decode_open_type() */ +static struct rk_strpool * +_asn1_print_open_type(const struct asn1_template *t, /* object set template */ + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const char *opentype_name) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + const unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + size_t i; + const void * const *dp; + const void * const *val; + const int *elementp = DPOC(data, t->offset); /* Choice enum pointer */ + char *indents = getindent(flags, indent); + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) { + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"_ERROR_DECODING_\"", + indents ? indents : "", opentype_name); + free(indents); + return r; + } + tactual_type = tos[3*(*elementp - 1) + 4].ptr; + + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"%s\"", + indents ? indents : "", opentype_name, + (const char *)tos[3*(*elementp - 1) + 2].ptr); + if (!r) { + free(indents); + return r; + } + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dp = DPOC(data, t->offset + sizeof(*elementp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + if (*dp) { + struct rk_strpool *r2 = NULL; + char *s = NULL; + + r2 = _asn1_print(tactual_type, r2, flags, indent + 1, *dp, NULL); + if (r2 == NULL) { + r = rk_strpoolprintf(r, ",%s\"_%s\":\"_ERROR_FORMATTING_\"", + indents ? indents : "", opentype_name); + free(indents); + return r; + } + s = rk_strpoolcollect(r2); + if (s) + r = rk_strpoolprintf(r, ",%s\"_%s\":%s", + indents ? indents : "", opentype_name, s); + free(s); + } + free(indents); + return r; + } + + lenp = DPOC(data, t->offset + sizeof(*elementp)); + len = *lenp; + dp = DPOC(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + val = *dp; + + r = rk_strpoolprintf(r, ",%s\"_%s\":[", indents ? indents : "", + opentype_name); + free(indents); + indents = getindent(flags, indent + 1); + r = rk_strpoolprintf(r, "%s", indents ? indents : ""); + for (i = 0; r && i < len; i++) { + struct rk_strpool *r2 = NULL; + char *s = NULL;; + + if (val[i]) { + r2 = _asn1_print(tactual_type, r2, flags, indent + 2, val[i], NULL); + if (r2 == NULL) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + } + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + if (r) + r = rk_strpoolprintf(r, "%s", (s = rk_strpoolcollect(r2))); + free(s); + } + free(indents); + return rk_strpoolprintf(r, "]"); +} + +static struct rk_strpool * +_asn1_print(const struct asn1_template *t, + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const heim_octet_string *saved) +{ + const struct asn1_template *tbase = t; + const struct asn1_template *tnames; + size_t nelements = A1_HEADER_LEN(t); + size_t elements = nelements; + size_t nnames = 0; + char *indents = getindent(flags, indent); + + for (t += nelements; t > tbase && (t->tt & A1_OP_MASK) == A1_OP_NAME; t--) + nnames++; + + tnames = tbase + nelements - nnames + 1; + + if (!r) + r = rk_strpoolprintf(r, "%s", ""); + + if (nnames) + r = rk_strpoolprintf(r, "%s{\"_type\":\"%s\"", + indents ? indents : "", + (const char *)(tnames++)->ptr); + if (saved && r) { + char *s = der_print_octet_string(data, 0); + + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + r = rk_strpoolprintf(r, ",%s\"_save\":\"%s\"", + indents ? indents : "", s); + free(s); + } + saved = NULL; + if (tbase->tt & A1_HF_PRESERVE) + saved = data; + + t = tbase + 1; + while (r && elements && (t->tt & A1_OP_MASK) != A1_OP_NAME) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_NAME: + continue; + case A1_OP_DEFVAL: + t++; + elements--; + continue; + case A1_OP_OPENTYPE_OBJSET: { + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + r = _asn1_print_open_type(t, r, flags, indent + 1, data, + tbase[(nelements - nnames) + 2 + opentype].ptr); + t++; + elements--; + continue; + } + default: break; + } + if (nnames && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE_EXTERN && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE) + r = rk_strpoolprintf(r, ",%s\"%s\":", + indents ? indents : "", + (const char *)(tnames++)->ptr); + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: + break; + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */ + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void *const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + } else { + const struct asn1_type_func *f = t->ptr; + char *s = NULL; + + s = (f->print)(el, 0); + if (s == NULL) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + r = rk_strpoolprintf(r, "%s", s); + free(s); + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + char *s = NULL; + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + + if (type == A1T_IMEMBER && t->ptr) { + /* Enumeration. Use the symbolic name of this value */ + const struct asn1_template *tenum = t->ptr; + size_t left = 0; + size_t right = A1_HEADER_LEN(tenum); + size_t mid; + uint32_t v = *(unsigned int *)el; + int c = -1; + + while (left <= right) { + mid = (left + right) >> 1; + + if ((tenum[mid].tt & A1_OP_MASK) != A1_OP_NAME) + break; + c = v - tenum[mid].offset; + if (c < 0) { + if (mid) + right = mid - 1; + else + break; + } else if (c > 0) { + left = mid + 1; + } else { + break; + } + } + if (c == 0) { + r = rk_strpoolprintf(r, "\"%s\"", (const char *)tenum[mid].ptr); + break; + } + } + s = (asn1_template_prim[type].print)(el, flags); + switch (type) { + case A1T_OID: + case A1T_IMEMBER: + case A1T_BOOLEAN: + case A1T_INTEGER: + case A1T_INTEGER64: + case A1T_UNSIGNED: + case A1T_UNSIGNED64: + if (s) + r = rk_strpoolprintf(r, "%s", s); + break; + default: { + char *s2 = NULL; + + if (s) + (void) rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = s2; + if (s) + r = rk_strpoolprintf(r, "\"%s\"", s); + } + } + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + free(s); + break; + } + case A1_OP_TAG: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void * const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + for (i = 0; r && i < el->len; i++) { + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + r = _asn1_print(t->ptr, r, flags, indent + 1, element, saved); + element += ellen; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + int first = 1; + + bmember += belements; + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + while (r && belements) { + if (r && _asn1_bmember_isset_bit(data, bmember->offset, size)) { + if (!first) + r = rk_strpoolprintf(r, ","); + first = 0; + r = rk_strpoolprintf(r, "%s\"%s\"", indents ? indents : "", + (const char *)bmember->ptr); + } + belements--; bmember--; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + unsigned int nchoices = ((uintptr_t)choice->ptr) >> 1; + + if (*element > A1_HEADER_LEN(choice)) { + r = rk_strpoolprintf(r, "null"); + } else if (*element == 0) { + /* XXX If choice->tt then we should print the u.ellipsis */ + r = rk_strpoolprintf(r, "null"); + } else { + choice += *element; + r = rk_strpoolprintf(r, "%s{\"_choice\":\"%s\",%s\"value\":", + indents ? indents : "", + (const char *)choice[nchoices].ptr, + indents ? indents : ""); + if (r) + r = _asn1_print(choice->ptr, r, flags, indent + 1, + DPOC(data, choice->offset), NULL); + if (r) + r = rk_strpoolprintf(r, "}"); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + free(indents); + if (nnames && r) + return rk_strpoolprintf(r, "}"); + return r; +} + +char * +_asn1_print_top(const struct asn1_template *t, + int flags, + const void *data) +{ + struct rk_strpool *r = _asn1_print(t, NULL, flags, 0, data, NULL); + + if (r == NULL) + return NULL; + return rk_strpoolcollect(r); +} + +/* See commentary in _asn1_decode_open_type() */ +static int +_asn1_copy_open_type(const struct asn1_template *t, /* object set template */ + const void *from, + void *to) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t i; + const void * const *dfromp; + const void * const *valfrom; + const unsigned int *lenfromp; + void **dtop; + void **valto; + unsigned int *lentop; + unsigned int len; + const int *efromp = DPO(from, t->offset); + int *etop = DPO(to, t->offset); + int ret = 0; + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*efromp || *efromp >= A1_HEADER_LEN(tos) + 1) { + if ((t->tt & A1_OS_OT_IS_ARRAY)) + memset(etop, 0, sizeof(int) + sizeof(unsigned int) + sizeof(void *)); + else + memset(etop, 0, sizeof(int) + sizeof(void *)); + return 0; /* Unknown choice -> not copied */ + } + tactual_type = &tos[3*(*efromp - 1) + 4]; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dfromp = DPO(from, t->offset + sizeof(*efromp)); + while (sizeof(void *) != sizeof(*efromp) && + ((uintptr_t)dfromp) % sizeof(void *) != 0) + dfromp = (void *)(((char *)dfromp) + sizeof(*efromp)); + if (!*dfromp) + return 0; + + dtop = DPO(to, t->offset + sizeof(*etop)); + while (sizeof(void *) != sizeof(*etop) && + ((uintptr_t)dtop) % sizeof(void *) != 0) + dtop = (void *)(((char *)dtop) + sizeof(*etop)); + + if ((*dtop = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + if (ret == 0) + ret = _asn1_copy(tactual_type->ptr, *dfromp, *dtop); + if (ret == 0) + *etop = *efromp; + return ret; + } + + lenfromp = DPO(from, t->offset + sizeof(*efromp)); + dfromp = DPO(from, t->offset + sizeof(*efromp) + sizeof(*lenfromp)); + valfrom = *dfromp; + lentop = DPO(to, t->offset + sizeof(*etop)); + dtop = DPO(to, t->offset + sizeof(*etop) + sizeof(*lentop)); + + *etop = *efromp; + + len = *lenfromp; + *lentop = 0; + *dtop = NULL; + if ((valto = calloc(len, sizeof(valto[0]))) == NULL) + ret = ENOMEM; + for (i = 0, len = *lenfromp; ret == 0 && i < len; i++) { + if (valfrom[i] == NULL) { + valto[i] = NULL; + continue; + } + if ((valto[i] = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + else + ret = _asn1_copy(tactual_type->ptr, valfrom[i], valto[i]); + (*lentop)++; + } + + for (i = 0; ret && i < (*lentop); i++) { + if (valto[i]) { + _asn1_free(tactual_type->ptr, valto[i]); + free(valto[i]); + } + } + if (ret) { + free(valto); + *lentop = 0; + } else + *dtop = valto; + return ret; +} + +int +_asn1_copy(const struct asn1_template *t, const void *from, void *to) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + int preserve = (t->tt & A1_HF_PRESERVE); + + t++; + + if (preserve) { + ret = der_copy_octet_string(from, to); + if (ret) + return ret; + } + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + _asn1_copy_open_type(t, from, to); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: + case A1_OP_TYPE_DECORATE: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + void **ptel = (void **)tel; + size_t size; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || + (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + size = _asn1_sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + size = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pfel = (void **)fel; + if (*pfel == NULL) + break; + fel = *pfel; + + tel = *ptel = calloc(1, size); + if (tel == NULL) + return ENOMEM; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || + (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + ret = _asn1_copy(t->ptr, fel, tel); + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { + const struct asn1_type_func *f = t->ptr; + ret = (f->copy)(fel, tel); + } else { + const struct asn1_type_func *f = t->ptr; + + /* A1_OP_TYPE_DECORATE_EXTERN */ + if (f && f->copy) + ret = (f->copy)(fel, tel); + else if (f) + memset(tel, 0, f->size); + } + + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + free(*ptel); + *ptel = NULL; + } + return ret; + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + ret = (asn1_template_prim[type].copy)(fel, tel); + if (ret) + return ret; + break; + } + case A1_OP_TAG: { + const void *oldfrom = from; + void *oldto = to; + void **tel = NULL; + + from = DPOC(from, t->offset); + to = DPO(to, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **fel = (void **)from; + tel = (void **)to; + if (*fel == NULL) { + from = oldfrom; + to = oldto; + break; + } + from = *fel; + + to = *tel = calloc(1, _asn1_sizeofType(t->ptr)); + if (to == NULL) + return ENOMEM; + } + + ret = _asn1_copy(t->ptr, from, to); + if (ret) { + if (tel) { + free(*tel); + *tel = NULL; + } + return ret; + } + + from = oldfrom; + to = oldto; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *fel = DPOC(from, t->offset); + struct template_of *tel = DPO(to, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + unsigned int i; + + tel->val = calloc(fel->len, ellen); + if (tel->val == NULL && fel->len > 0) + return ENOMEM; + + tel->len = fel->len; + + for (i = 0; i < fel->len; i++) { + ret = _asn1_copy(t->ptr, + DPOC(fel->val, (i * ellen)), + DPO(tel->val, (i *ellen))); + if (ret) + return ret; + } + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + memcpy(to, from, size); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *felement = DPOC(from, choice->offset); + unsigned int *telement = DPO(to, choice->offset); + + if (*felement > A1_HEADER_LEN(choice)) + return ASN1_PARSE_ERROR; + + *telement = *felement; + + if (*felement == 0) { + if (choice->tt) + ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt)); + /* + * Else we should really memset clear the rest of this choice, + * but we don't really know its size. + */ + } else { + choice += *felement; + ret = _asn1_copy(choice->ptr, + DPOC(from, choice->offset), + DPO(to, choice->offset)); + } + if (ret) + return ret; + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + return 0; +} + +int +_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size) +{ + int ret; + memset(data, 0, t->offset); + ret = _asn1_decode(t, flags, p, len, data, size); + if (ret) + _asn1_free_top(t, data); + + return ret; +} + +int +_asn1_copy_top(const struct asn1_template *t, const void *from, void *to) +{ + int ret; + memset(to, 0, t->offset); + ret = _asn1_copy(t, from, to); + if (ret) + _asn1_free_top(t, to); + + return ret; +} + +void +_asn1_free_top(const struct asn1_template *t, void *data) +{ + _asn1_free(t, data); + memset(data, 0, t->offset); +} diff --git a/third_party/heimdal/lib/asn1/test.asn1 b/third_party/heimdal/lib/asn1/test.asn1 new file mode 100644 index 0000000..08c7dcd --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.asn1 @@ -0,0 +1,309 @@ +-- $Id$ -- + +TEST DEFINITIONS ::= + +BEGIN + +IMPORTS HEIM_ANY FROM heim; + +-- Check that we handle out of order definitions. +-- The compiler should emit the definition of TESTOutOfOrderBar before that of +-- TESTOutOfOrderFoo. +TESTOutOfOrderFoo ::= SEQUENCE { + bar TESTOutOfOrderBar +} + +TESTOutOfOrderBar ::= SEQUENCE { + aMember INTEGER +} + +-- Check that we can handle rpc.mountd style "lists". This is unnecessarily +-- inefficient in its encoding, and there's no point to using this over +-- SEQUENCE OF (arrays), but it's neat that we can do this now that we can do +-- out of order definitions. +-- +-- This could be useful if we ever extend asn1_compile to also handle XDR, +-- which we well might since XDR's syntax is a dual of a strict subset of +-- ASN.1, and since XDR the encoding is fairly straightforward. +-- +-- Note that the `next' member has to be OPTIONAL for this to work. +TESTCircular ::= SEQUENCE { + name UTF8String, + next TESTCircular OPTIONAL +} + +TESTDefault ::= SEQUENCE { + name UTF8String DEFAULT "Heimdal", + version [0] TESTuint32 DEFAULT 8, + maxint TESTuint64 DEFAULT 9223372036854775807, + works BOOLEAN DEFAULT TRUE +} + +TESTuint32 ::= INTEGER (0..4294967295) +TESTuint64 ::= INTEGER(0..9223372036854775807) +TESTint64 ::= INTEGER(-9223372036854775808..9223372036854775807) + +TESTLargeTag ::= SEQUENCE { + foo[127] INTEGER (-2147483648..2147483647), + bar[128] INTEGER (-2147483648..2147483647) +} + +TESTSeq ::= SEQUENCE { + tag0[0] INTEGER (-2147483648..2147483647), + tag1[1] TESTLargeTag, + tagless INTEGER (-2147483648..2147483647), + tag3[2] INTEGER (-2147483648..2147483647) +} + +TESTChoice1 ::= CHOICE { + i1[1] INTEGER (-2147483648..2147483647), + i2[2] INTEGER (-2147483648..2147483647), + ... +} + +TESTChoice2 ::= CHOICE { + i1[1] INTEGER (-2147483648..2147483647), + ... +} + +TESTInteger ::= INTEGER (-2147483648..2147483647) + +TESTInteger2 ::= [4] IMPLICIT TESTInteger +TESTInteger3 ::= [5] IMPLICIT TESTInteger2 + +TESTImplicit ::= SEQUENCE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[1] IMPLICIT SEQUENCE { + foo[127] INTEGER (-2147483648..2147483647) + }, + ti3[2] IMPLICIT [5] IMPLICIT [4] IMPLICIT INTEGER (-2147483648..2147483647) +} + +TESTImplicit2 ::= SEQUENCE { + ti1[0] IMPLICIT TESTInteger, +-- ti2[1] IMPLICIT TESTLargeTag, this is disabled since the IMPLICT encoder does't get the types right when stepping inside an structure -- + ti3[2] IMPLICIT TESTInteger3, + ti4[51] IMPLICIT TESTInteger OPTIONAL +} + +TESTImplicit3 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT CHOICE { i1[1] INTEGER (-2147483648..2147483647) } +} + +TESTImplicit4 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT TESTChoice2 +} + +TESTAllocInner ::= SEQUENCE { + ai[0] TESTInteger +} + +TESTAlloc ::= SEQUENCE { + tagless TESTAllocInner OPTIONAL, + three [1] INTEGER (-2147483648..2147483647), + tagless2 HEIM_ANY OPTIONAL +} + +TESTOptional ::= SEQUENCE { + zero [0] INTEGER (-2147483648..2147483647) OPTIONAL, + one [1] INTEGER (-2147483648..2147483647) OPTIONAL +} + + +TESTCONTAINING ::= OCTET STRING ( CONTAINING INTEGER ) +TESTENCODEDBY ::= OCTET STRING ( ENCODED BY + { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } +) + +testDer OBJECT IDENTIFIER ::= { + joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) +} + +testContainingEncodedBy ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY + { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } +) + +testContainingEncodedBy2 ::= OCTET STRING ( + CONTAINING INTEGER ENCODED BY testDer +) + + +testValue1 INTEGER ::= 1 + +testUserConstrained ::= OCTET STRING (CONSTRAINED BY { -- meh -- }) +-- TESTUSERCONSTRAINED2 ::= OCTET STRING (CONSTRAINED BY { TESTInteger }) +-- TESTUSERCONSTRAINED3 ::= OCTET STRING (CONSTRAINED BY { INTEGER }) +-- TESTUSERCONSTRAINED4 ::= OCTET STRING (CONSTRAINED BY { INTEGER : 1 }) + +TESTSeqOf ::= SEQUENCE OF TESTInteger + +TESTSeqSizeOf1 ::= SEQUENCE SIZE (2) OF TESTInteger +TESTSeqSizeOf2 ::= SEQUENCE SIZE (1..2) OF TESTInteger +TESTSeqSizeOf3 ::= SEQUENCE SIZE (1..MAX) OF TESTInteger +TESTSeqSizeOf4 ::= SEQUENCE SIZE (0..2) OF TESTInteger + +TESTOSSize1 ::= OCTET STRING SIZE (1..2) + +TESTSeqOfSeq ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger +} + +TESTSeqOfSeq2 ::= SEQUENCE OF SEQUENCE { + string [0] GeneralString +} + +TESTSeqOfSeq3 ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger, + string [0] GeneralString +} + +TESTSeqOf2 ::= SEQUENCE { + strings SEQUENCE OF GeneralString +} + +TESTSeqOf3 ::= SEQUENCE { + strings SEQUENCE OF GeneralString OPTIONAL +} + +-- Larger/more complex to increase odds of out-of-bounds +-- read/writes if miscoded + +TESTSeqOf4 ::= SEQUENCE { + b1 [0] SEQUENCE OF SEQUENCE { + s1 OCTET STRING, + s2 OCTET STRING, + u1 TESTuint64, + u2 TESTuint64 + } OPTIONAL, + b2 [1] IMPLICIT SEQUENCE OF SEQUENCE { + u1 TESTuint64, + u2 TESTuint64, + u3 TESTuint64, + s1 OCTET STRING, + s2 OCTET STRING, + s3 OCTET STRING + } OPTIONAL, + b3 [2] IMPLICIT SEQUENCE OF SEQUENCE { + s1 OCTET STRING, + u1 TESTuint64, + s2 OCTET STRING, + u2 TESTuint64, + s3 OCTET STRING, + u3 TESTuint64, + s4 OCTET STRING, + u4 TESTuint64 + } OPTIONAL +} + +TESTSeqOf5 ::= SEQUENCE { + outer SEQUENCE { + inner SEQUENCE { + u0 TESTuint64, + s0 OCTET STRING, + u1 TESTuint64, + s1 OCTET STRING, + u2 TESTuint64, + s2 OCTET STRING, + u3 TESTuint64, + s3 OCTET STRING, + u4 TESTuint64, + s4 OCTET STRING, + u5 TESTuint64, + s5 OCTET STRING, + u6 TESTuint64, + s6 OCTET STRING, + u7 TESTuint64, + s7 OCTET STRING + } + } + OPTIONAL +} + +TESTPreserve ::= SEQUENCE { + zero [0] TESTInteger, + one [1] TESTInteger +} + +TESTBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31) +} + +TESTBitString64 ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + thirtytwo(32), + sixtythree(63) +} + +TESTLargeBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + onehundredtwenty(120) +} + +TESTMechType::= OBJECT IDENTIFIER +TESTMechTypeList ::= SEQUENCE OF TESTMechType + + +-- IOS stuff +_EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType, + &Critical BOOLEAN DEFAULT FALSE +} + +TESTExtension{_EXTENSION:ExtensionSet} ::= SEQUENCE { + extnID _EXTENSION.&id({ExtensionSet}), + critical BOOLEAN +-- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + extnValue OCTET STRING (CONTAINING + _EXTENSION.&ExtnType({ExtensionSet}{@extnID})) +} + +id-test-default OBJECT IDENTIFIER ::= { 1 2 3 4 } +testext-TESTDefault _EXTENSION ::= { + &id id-test-default, + &Critical FALSE, + &ExtnType TESTDefault +} + +-- And Here's an object set for the EXTENSION CLASS collecting a bunch of +-- related extensions (here they are the extensions that certificates can +-- carry in their extensions member): +TestExtensions _EXTENSION ::= { testext-TESTDefault } + +TESTExtension ::= TESTExtension { TestExtensions } + +TESTExtensible ::= SEQUENCE { + version INTEGER, + extensions SEQUENCE OF TESTExtension +} + +TESTDecorated ::= SEQUENCE { + version TESTuint32 + -- gets decorated with varius fields (see test.opt) +} + +TESTNotDecorated ::= SEQUENCE { + version TESTuint32 + -- should have the same encoding as TESTDecorated +} + +TESTDecoratedChoice ::= CHOICE { + version TESTuint32 + -- gets decorated with varius fields (see test.opt) +} + +TESTNotDecoratedChoice ::= CHOICE { + version TESTuint32 + -- should have the same encoding as TESTDecoratedChoice +} + +END diff --git a/third_party/heimdal/lib/asn1/test.gen b/third_party/heimdal/lib/asn1/test.gen new file mode 100644 index 0000000..bfb0486 --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.gen @@ -0,0 +1,14 @@ +# $Id$ +# Sample for TESTSeq in test.asn1 +# + +UNIV CONS Sequence 23 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 01 + CONTEXT CONS 1 8 + UNIV CONS Sequence 6 + CONTEXT CONS 127 3 + UNIV PRIM Integer 1 01 + UNIV PRIM Integer 1 01 + CONTEXT CONS 2 3 + UNIV PRIM Integer 1 01 diff --git a/third_party/heimdal/lib/asn1/test.opt b/third_party/heimdal/lib/asn1/test.opt new file mode 100644 index 0000000..755eba0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.opt @@ -0,0 +1,7 @@ +--sequence=TESTSeqOf +--decorate=TESTDecorated:TESTuint32:version2? +--decorate=TESTDecorated:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecorated:void *:privthing +--decorate=TESTDecoratedChoice:TESTuint32:version2? +--decorate=TESTDecoratedChoice:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecoratedChoice:void *:privthing diff --git a/third_party/heimdal/lib/asn1/timegm.c b/third_party/heimdal/lib/asn1/timegm.c new file mode 100644 index 0000000..4746fa8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/timegm.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#define ASN1_MAX_YEAR 2000 + +static int +is_leap(unsigned y) +{ + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + +/* + * This is a simplifed version of timegm(3) that doesn't accept out of + * bound values that timegm(3) normally accepts but those are not + * valid in asn1 encodings. + */ + +time_t +_der_timegm (struct tm *tm) +{ + time_t res = 0; + int i; + + /* + * See comment in _der_gmtime + */ + if (tm->tm_year > ASN1_MAX_YEAR) + return 0; + + if (tm->tm_year < 0) + return -1; + if (tm->tm_mon < 0 || tm->tm_mon > 11) + return -1; + if (tm->tm_mday < 1 || tm->tm_mday > (int)ndays[is_leap(tm->tm_year)][tm->tm_mon]) + return -1; + if (tm->tm_hour < 0 || tm->tm_hour > 23) + return -1; + if (tm->tm_min < 0 || tm->tm_min > 59) + return -1; + if (tm->tm_sec < 0 || tm->tm_sec > 59) + return -1; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} + +struct tm * +_der_gmtime(time_t t, struct tm *tm) +{ + time_t secday = t % (3600 * 24); + time_t days = t / (3600 * 24); + + memset(tm, 0, sizeof(*tm)); + + tm->tm_sec = secday % 60; + tm->tm_min = (secday % 3600) / 60; + tm->tm_hour = (int)(secday / 3600); + + /* + * Refuse to calculate time ~ 2000 years into the future, this is + * not possible for systems where time_t is a int32_t, however, + * when time_t is a int64_t, that can happen, and this becomes a + * denial of sevice. + */ + if (days > (ASN1_MAX_YEAR * 365)) + return NULL; + + tm->tm_year = 70; + while(1) { + unsigned dayinyear = (is_leap(tm->tm_year) ? 366 : 365); + if (days < dayinyear) + break; + tm->tm_year += 1; + days -= dayinyear; + } + tm->tm_mon = 0; + + while (1) { + unsigned daysinmonth = ndays[is_leap(tm->tm_year)][tm->tm_mon]; + if (days < daysinmonth) + break; + days -= daysinmonth; + tm->tm_mon++; + } + tm->tm_mday = (int)(days + 1); + + return tm; +} diff --git a/third_party/heimdal/lib/asn1/version-script.map b/third_party/heimdal/lib/asn1/version-script.map new file mode 100644 index 0000000..67f9ff0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/version-script.map @@ -0,0 +1,6 @@ +# Export everything, but put a tag on is so that we make ourself incompatible with older versions + +HEIMDAL_ASN1_1.0 { + global: + *; +}; diff --git a/third_party/heimdal/lib/asn1/x690sample.asn1 b/third_party/heimdal/lib/asn1/x690sample.asn1 new file mode 100644 index 0000000..18954a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/x690sample.asn1 @@ -0,0 +1,181 @@ +x690sample DEFINITIONS ::= BEGIN + +-- This is taken from Appendix A of X.690. The same module is used by all +-- X.690 series specifications of ASN.1 Encoding Rules. +-- +-- This doesn't exercise every feature, like OPTIONAL, not really DEFAULT, not +-- EXPLICIT tagging, extensibility markers, etc., but it exercises some hard +-- ones like SET and IMPLICIT tagging. +-- +-- Because we don't yet have an option to add a namespace prefix to generated +-- symbols, to avoid conflicts with rfc2459's Name we're prefixing the type +-- names here manually. +-- +-- WARNING: The encoding rules used for the sample encoding given in Appendix A +-- of X.690, and used in lib/asn1/check-gen.c, is not specified in +-- X.690! It seems very likely that it is neither CER nor DER but BER +-- because the tags in the X690SamplePersonnelRecord (a SET { ... }) +-- are not in canonical order: +-- +-- APPL CONS tag 0 = 133 bytes [0] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "John" +-- UNIV PRIM VisibleString = "P" +-- UNIV PRIM VisibleString = "Smith" +-- -> CONTEXT CONS tag 0 = 10 bytes [0] +-- UNIV PRIM VisibleString = "Director" +-- -> APPL PRIM tag 2 = 1 bytes [2] IMPLICIT content +-- ... +-- +-- The canonical ordering of members in SET { ... } types is by tag, +-- with UNIVERSAL tags before APPLICATION tags, those before CONTEXT, +-- and those before PRIVATE, and within each class from lowest to +-- highest numeric tag value. See X.680, section 8.6, which is +-- referenced from X.690, section 10.3. +-- +-- Here we can see that the `title` member should come _after_ the +-- `number` member, but it does not. +-- +-- Our test relies on our compiler producing the same test data when +-- encoding the structure that the given test data decodes to. That +-- works here only because our compiler does NOT sort SET { ... } +-- members as it should (since we always produce DER). +-- +-- Sorting SET members in the compiler is hard currently because we +-- don't parse imported modules, so we don't know the tags of imported +-- types, so we can only sort at run-time, which we don't do. +-- +-- There is an obvious workaround, however: sort the SET { ... } +-- definition manually! + +X690SamplePersonnelRecord ::= [APPLICATION 0] IMPLICIT SET { + name X690SampleName, + title [0] VisibleString, + number X690SampleEmployeeNumber, + dateOfHire [1] X690SampleDate, + nameOfSpouse [2] X690SampleName, + -- Heimdal's ASN.1 compiler doesn't handle DEFAULT values for types for + -- which it doesn't support literal values. + children [3] IMPLICIT SEQUENCE OF X690SampleChildInformation -- DEFAULT {} +} + +X690SampleChildInformation ::= SET { + name X690SampleName, + dateOfBirth [0] X690SampleDate +} + +X690SampleName ::= [APPLICATION 1] IMPLICIT SEQUENCE { + givenName VisibleString, + initial VisibleString, + familyName VisibleString +} + +-- Range added for test convenience. +X690SampleEmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) + +X690SampleDate::= [APPLICATION 3] IMPLICIT VisibleString --YYYYMMDD + +-- The following is value syntax for the above, but Heimdal's ASN.1 compiler +-- does not yet support value syntax for anything other than OIDs, booleans, +-- integers, and UTF-8 strings: +-- +-- { name { givenName "John", initial "P", familyName "Smith" }, +-- title "Director", +-- number 51, +-- dateOfHire "19710917", +-- nameOfSpouse {givenName "Mary", initial "T", familyName "Smith" }, +-- children { +-- {name {givenName "Ralph", initial "T", familyName "Smith" }, +-- dateOfBirth "19571111"}, +-- {name {givenName "Susan", initial "B", familyName "Jones" }, +-- I dateOfBirth "19590717"} +-- } +-- } +-- +-- The encoding of this value is supposed to be (all hex) (adapted from X.690 +-- Appendix A): +-- +-- 60818561101A044A6F686E1A01501A05536D697468A00A1A084469726563746F +-- 72420133A10A43083139373130393137A21261101A044D6172791A01541A0553 +-- 6D697468A342311F61111A0552616C70681A01541A05536D697468A00A430831 +-- 39353731313131311F61111A05537573616E1A01421A05536D697468A00A4308 +-- 3139353930373137 +-- +-- And a rough visualization of this is (adapted from X.690 Appendix A): +-- +-- T L +-- 60 8185 # 3 +-- Name +-- T L +-- 61 10 # 2 +-- T L "John" +-- 1A 04 4A6F686E # 6 +-- T L "P" +-- 1A 01 50 # 3 +-- T L "Smith" +-- 1A 05 536D697468 # 7 +-- Title +-- T L T L "Director" +-- A0 0A 1A 08 4469726563746F72 #12 +-- Emp. # +-- 42 01 33 # 3 +-- Date of hire +-- A1 0A 43 08 3139373130393137 #12 +-- Spouse +-- A2 12 # 2 +-- Name +-- 61 10 # 2 +-- 1A 04 4D617279 # 6 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- Children +-- A3 42 # 2 +-- 31 1F # 2 +-- Name +-- 61 11 1A 05 52616C7068 # 9 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- DoB +-- A0 0A 43 08 3139353731313131 #12 +-- 31 1F # 2 bytes +-- 61 11 1A 05 537573616E # 9 bytes +-- 1A 01 42 # 3 bytes +-- 1A 05 536D697468 # 7 bytes +-- A0 0A 43 08 3139353930373137 #12 bytes +-- +-- Our asn1_print program dumps this as follows, which looks correct: +-- +-- APPL CONS tag 0 = 133 bytes [0] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "John" +-- UNIV PRIM VisibleString = "P" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- UNIV PRIM VisibleString = "Director" +-- APPL PRIM tag 2 = 1 bytes [2] IMPLICIT content +-- CONTEXT CONS tag 1 = 10 bytes [1] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- CONTEXT CONS tag 2 = 18 bytes [2] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "Mary" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 3 = 66 bytes [3] +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Ralph" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Susan" +-- UNIV PRIM VisibleString = "B" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } + +END diff --git a/third_party/heimdal/lib/base/Makefile.am b/third_party/heimdal/lib/base/Makefile.am new file mode 100644 index 0000000..606e00a --- /dev/null +++ b/third_party/heimdal/lib/base/Makefile.am @@ -0,0 +1,97 @@ + +include $(top_srcdir)/Makefile.am.common + +if do_roken_rename +ES = base64.c +endif + +IMPLEMENT_TLS= +if MAINTAINER_MODE +IMPLEMENT_TLS += dll.c +AM_CPPFLAGS += -DHEIM_BASE_MAINTAINER +endif + +AM_CPPFLAGS += $(ROKEN_RENAME) -I../com_err -I$(srcdir)/../com_err + +lib_LTLIBRARIES = libheimbase.la +check_PROGRAMS = test_base + +test_base_CFLAGS = -Wno-string-concatenation + +libheimbase_la_LDFLAGS = -version-info 1:0:0 + +if FRAMEWORK_COREFOUNDATION +libheimbase_la_LDFLAGS += -framework CoreFoundation +endif + +TESTS = test_base + +if versionscript +libheimbase_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +libheimbase_la_LIBADD = $(PTHREAD_LIBADD) $(LIB_dlopen) $(LIB_com_err) + +include_HEADERS = heimbase.h common_plugin.h heimbase-atomics.h heimbase-svc.h + +ERR_FILES = heim_err.c + +dist_libheimbase_la_SOURCES = \ + array.c \ + baselocl.h \ + bsearch.c \ + bool.c \ + common_plugin.h \ + config_file.c \ + context.c \ + data.c \ + db.c \ + dict.c \ + $(IMPLEMENT_TLS) \ + error.c \ + error_string.c \ + expand_path.c \ + heimbase.c \ + heimbasepriv.h \ + json.c \ + log.c \ + null.c \ + number.c \ + plugin.c \ + roken_rename.h \ + string.c \ + warn.c + +nodist_libheimbase_la_SOURCES = $(ES) $(ERR_FILES) + +$(libheimbase_la_OBJECTS): $(srcdir)/heimbase-protos.h heim_err.h + +$(srcdir)/heimbase-protos.h: $(dist_libheimbase_la_SOURCES) + cd $(srcdir) && \ + perl ../../cf/make-proto.pl -q -P comment -o heimbase-protos.h $(dist_libheimbase_la_SOURCES) || \ + rm -f heimbase-protos.h + +$(srcdir)/heimbase-private.h: $(dist_libheimbase_la_SOURCES) + cd $(srcdir) && \ + perl ../../cf/make-proto.pl -q -P comment -p heimbase-private.h $(dist_libheimbase_la_SOURCES) || \ + rm -f heimbase-private.h + +# install these? + +libheimbase_la_DEPENDENCIES = version-script.map + +test_base_LDADD = libheimbase.la $(LIB_roken) + +CLEANFILES = base64.c test_db.json heim_err.c heim_err.h + +EXTRA_DIST = NTMakefile version-script.map config_reg.c heim_err.et + +dist_include_HEADERS = heimbase-protos.h + +nodist_include_HEADERS = heim_err.h + +heim_err.h: heim_err.et + +base64.c: + rm -f base64.c + $(LN_S) $(srcdir)/../roken/base64.c . diff --git a/third_party/heimdal/lib/base/NTMakefile b/third_party/heimdal/lib/base/NTMakefile new file mode 100644 index 0000000..49cd8b8 --- /dev/null +++ b/third_party/heimdal/lib/base/NTMakefile @@ -0,0 +1,134 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\base + +intcflags=-I$(SRCDIR) -I$(OBJ) + +!include ../../windows/NTMakefile.w32 + +INCFILES= \ + $(INCDIR)\heimbase.h \ + $(INCDIR)\heimbase-protos.h \ + $(INCDIR)\heimbase-atomics.h \ + $(INCDIR)\heimbase-svc.h \ + $(INCDIR)\heim_err.h \ + $(INCDIR)\common_plugin.h + +test_binaries = $(OBJ)\test_base.exe + +libheimbase_SOURCES = \ + array.c \ + bool.c \ + bsearch.c \ + config_file.c \ + config_reg.c \ + context.c \ + data.c \ + db.c \ + dict.c \ + dll.c \ + error.c \ + error_string.c \ + expand_path.c \ + heimbase.c \ + json.c \ + log.c \ + null.c \ + number.c \ + plugin.c \ + string.c \ + warn.c + +libheimbase_OBJS = \ + $(OBJ)\array.obj \ + $(OBJ)\bool.obj \ + $(OBJ)\bsearch.obj \ + $(OBJ)\config_file.obj \ + $(OBJ)\config_reg.obj \ + $(OBJ)\context.obj \ + $(OBJ)\data.obj \ + $(OBJ)\db.obj \ + $(OBJ)\dict.obj \ + $(OBJ)\dll.obj \ + $(OBJ)\error.obj \ + $(OBJ)\error_string.obj \ + $(OBJ)\expand_path.obj \ + $(OBJ)\heimbase.obj \ + $(OBJ)\json.obj \ + $(OBJ)\log.obj \ + $(OBJ)\null.obj \ + $(OBJ)\number.obj \ + $(OBJ)\plugin.obj \ + $(OBJ)\string.obj \ + $(OBJ)\warn.obj + +libheimbase_gen_OBJS= $(OBJ)\heim_err.obj + +$(LIBHEIMBASE): $(libheimbase_OBJS) $(libheimbase_gen_OBJS) + $(LIBCON_C) -OUT:$@ $(LIBROKEN) $(LIBCOMERR) $(PTHREAD_LIB) Secur32.lib Shell32.lib Advapi32.lib Shlwapi.lib @<< +$(libheimbase_OBJS: = +) +$(libheimbase_gen_OBJS: = +) +<< + +$(OBJ)\heimbase-protos.h: $(libheimbase_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -E KRB5_LIB -q -P remove -o $(OBJ)\heimbase-protos.h $(libheimbase_SOURCES) || $(RM) -f $(OBJ)\heimbase-protos.h + +$(OBJ)\heimbase-private.h: $(libheimbase_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\heimbase-private.h $(libheimbase_SOURCES) || $(RM) -f $(OBJ)\heimbase-private.h + +$(OBJ)\heim_err.c $(OBJ)\heim_err.h: heim_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\heim_err.et + cd $(SRCDIR) + +test:: test-binaries test-run + +test-run: + cd $(OBJ) + -test_base.exe + cd $(SRCDIR) + +all:: $(INCFILES) $(LIBHEIMBASE) + +clean:: + -$(RM) $(INCFILES) + +test-binaries: $(test_binaries) + +$(test_binaries): $$(@R).obj $(LIBHEIMBASE) $(LIBVERS) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(test_binaries:.exe=.obj): $$(@B).c + $(C2OBJ_C) -Fo$@ -Fd$(@D)\ $** -DBlah diff --git a/third_party/heimdal/lib/base/array.c b/third_party/heimdal/lib/base/array.c new file mode 100644 index 0000000..994fa7d --- /dev/null +++ b/third_party/heimdal/lib/base/array.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +/* + * + */ + +struct heim_array_data { + size_t len; + heim_object_t *val; + size_t allocated_len; + heim_object_t *allocated; +}; + +static void HEIM_CALLCONV +array_dealloc(heim_object_t ptr) +{ + heim_array_t array = ptr; + size_t n; + for (n = 0; n < array->len; n++) + heim_release(array->val[n]); + free(array->allocated); +} + +struct heim_type_data array_object = { + HEIM_TID_ARRAY, + "array-object", + NULL, + array_dealloc, + NULL, + NULL, + NULL, + NULL +}; + +/** + * Allocate an array + * + * @return A new allocated array, free with heim_release() + */ + +heim_array_t +heim_array_create(void) +{ + heim_array_t array; + + array = _heim_alloc_object(&array_object, sizeof(*array)); + if (array == NULL) + return NULL; + + array->allocated = NULL; + array->allocated_len = 0; + array->val = NULL; + array->len = 0; + + return array; +} + +/** + * Get type id of an dict + * + * @return the type id + */ + +heim_tid_t +heim_array_get_type_id(void) +{ + return HEIM_TID_ARRAY; +} + +/** + * Append object to array + * + * @param array array to add too + * @param object the object to add + * + * @return zero if added, errno otherwise + */ + +int +heim_array_append_value(heim_array_t array, heim_object_t object) +{ + heim_object_t *ptr; + size_t leading = array->val - array->allocated; /* unused leading slots */ + size_t trailing = array->allocated_len - array->len - leading; + size_t new_len; + + if (trailing > 0) { + /* We have pre-allocated space; use it */ + array->val[array->len++] = heim_retain(object); + return 0; + } + + if (leading > (array->len + 1)) { + /* + * We must have appending to, and deleting at index 0 from this + * array a lot; don't want to grow forever! + */ + (void) memmove(&array->allocated[0], &array->val[0], + array->len * sizeof(array->val[0])); + array->val = array->allocated; + + /* We have pre-allocated space; use it */ + array->val[array->len++] = heim_retain(object); + return 0; + } + + /* Pre-allocate extra .5 times number of used slots */ + new_len = leading + array->len + 1 + (array->len >> 1); + ptr = realloc(array->allocated, new_len * sizeof(array->val[0])); + if (ptr == NULL) + return ENOMEM; + array->allocated = ptr; + array->allocated_len = new_len; + array->val = &ptr[leading]; + array->val[array->len++] = heim_retain(object); + + return 0; +} + +/* + * Internal function to insert at index 0, taking care to optimize the + * case where we're always inserting at index 0, particularly the case + * where we insert at index 0 and delete from the right end. + */ +static int +heim_array_prepend_value(heim_array_t array, heim_object_t object) +{ + heim_object_t *ptr; + size_t leading = array->val - array->allocated; /* unused leading slots */ + size_t trailing = array->allocated_len - array->len - leading; + size_t new_len; + + if (leading > 0) { + /* We have pre-allocated space; use it */ + array->val--; + array->val[0] = heim_retain(object); + array->len++; + return 0; + } + if (trailing > (array->len + 1)) { + /* + * We must have prepending to, and deleting at index + * array->len - 1 from this array a lot; don't want to grow + * forever! + */ + (void) memmove(&array->allocated[array->len], &array->val[0], + array->len * sizeof(array->val[0])); + array->val = &array->allocated[array->len]; + + /* We have pre-allocated space; use it */ + array->val--; + array->val[0] = heim_retain(object); + array->len++; + return 0; + } + /* Pre-allocate extra .5 times number of used slots */ + new_len = array->len + 1 + trailing + (array->len >> 1); + ptr = realloc(array->allocated, new_len * sizeof(array->val[0])); + if (ptr == NULL) + return ENOMEM; + (void) memmove(&ptr[1], &ptr[0], array->len * sizeof (array->val[0])); + array->allocated = ptr; + array->allocated_len = new_len; + array->val = &ptr[0]; + array->val[0] = heim_retain(object); + array->len++; + + return 0; +} + +/** + * Insert an object at a given index in an array + * + * @param array array to add too + * @param idx index where to add element (-1 == append, -2 next to last, ...) + * @param object the object to add + * + * @return zero if added, errno otherwise + */ + +int +heim_array_insert_value(heim_array_t array, size_t idx, heim_object_t object) +{ + int ret; + + if (idx == 0) + return heim_array_prepend_value(array, object); + else if (idx > array->len) + heim_abort("index too large"); + + /* + * We cheat: append this element then rotate elements around so we + * have this new element at the desired location, unless we're truly + * appending the new element. This means reusing array growth in + * heim_array_append_value() instead of duplicating that here. + */ + ret = heim_array_append_value(array, object); + if (ret != 0 || idx == (array->len - 1)) + return ret; + /* + * Shift to the right by one all the elements after idx, then set + * [idx] to the new object. + */ + (void) memmove(&array->val[idx + 1], &array->val[idx], + (array->len - idx - 1) * sizeof(array->val[0])); + array->val[idx] = heim_retain(object); + + return 0; +} + +/** + * Iterate over all objects in array + * + * @param array array to iterate over + * @param ctx context passed to fn + * @param fn function to call on each object + */ + +void +heim_array_iterate_f(heim_array_t array, void *ctx, heim_array_iterator_f_t fn) +{ + size_t n; + int stop = 0; + for (n = 0; n < array->len; n++) { + fn(array->val[n], ctx, &stop); + if (stop) + return; + } +} + +#ifdef __BLOCKS__ +/** + * Iterate over all objects in array + * + * @param array array to iterate over + * @param fn block to call on each object + */ + +void +heim_array_iterate(heim_array_t array, void (^fn)(heim_object_t, int *)) +{ + size_t n; + int stop = 0; + for (n = 0; n < array->len; n++) { + fn(array->val[n], &stop); + if (stop) + return; + } +} +#endif + +/** + * Iterate over all objects in array, backwards + * + * @param array array to iterate over + * @param ctx context passed to fn + * @param fn function to call on each object + */ + +void +heim_array_iterate_reverse_f(heim_array_t array, void *ctx, heim_array_iterator_f_t fn) +{ + size_t n; + int stop = 0; + + for (n = array->len; n > 0; n--) { + fn(array->val[n - 1], ctx, &stop); + if (stop) + return; + } +} + +#ifdef __BLOCKS__ +/** + * Iterate over all objects in array, backwards + * + * @param array array to iterate over + * @param fn block to call on each object + */ + +void +heim_array_iterate_reverse(heim_array_t array, void (^fn)(heim_object_t, int *)) +{ + size_t n; + int stop = 0; + for (n = array->len; n > 0; n--) { + fn(array->val[n - 1], &stop); + if (stop) + return; + } +} +#endif + +/** + * Get length of array + * + * @param array array to get length of + * + * @return length of array + */ + +size_t +heim_array_get_length(heim_array_t array) +{ + return array->len; +} + +/** + * Get value of element at array index + * + * @param array array copy object from + * @param idx index of object, 0 based, must be smaller then + * heim_array_get_length() + * + * @return a not-retained copy of the object + */ + +heim_object_t +heim_array_get_value(heim_array_t array, size_t idx) +{ + if (idx >= array->len) + heim_abort("index too large"); + return array->val[idx]; +} + +/** + * Get value of element at array index + * + * @param array array copy object from + * @param idx index of object, 0 based, must be smaller then + * heim_array_get_length() + * + * @return a retained copy of the object + */ + +heim_object_t +heim_array_copy_value(heim_array_t array, size_t idx) +{ + if (idx >= array->len) + heim_abort("index too large"); + return heim_retain(array->val[idx]); +} + +/** + * Set value at array index + * + * @param array array copy object from + * @param idx index of object, 0 based, must be smaller then + * heim_array_get_length() + * @param value value to set + * + */ + +void +heim_array_set_value(heim_array_t array, size_t idx, heim_object_t value) +{ + if (idx >= array->len) + heim_abort("index too large"); + heim_release(array->val[idx]); + array->val[idx] = heim_retain(value); +} + +/** + * Delete value at idx + * + * @param array the array to modify + * @param idx the key to delete + */ + +void +heim_array_delete_value(heim_array_t array, size_t idx) +{ + heim_object_t obj; + if (idx >= array->len) + heim_abort("index too large"); + obj = array->val[idx]; + + array->len--; + + /* + * Deleting the first or last elements is cheap, as we leave + * allocated space for opportunistic reuse later; no realloc(), no + * memmove(). All others require a memmove(). + * + * If we ever need to optimize deletion of non-last/ non-first + * element we can use a tagged object type to signify "deleted + * value" so we can leave holes in the array, avoid memmove()s on + * delete, and opportunistically re-use those holes on insert. + */ + if (idx == 0) + array->val++; + else if (idx < array->len) + (void) memmove(&array->val[idx], &array->val[idx + 1], + (array->len - idx) * sizeof(array->val[0])); + + heim_release(obj); +} + +/** + * Filter out entres of array when function return true + * + * @param array the array to modify + * @param fn filter function + */ + +void +heim_array_filter_f(heim_array_t array, void *ctx, heim_array_filter_f_t fn) +{ + size_t n = 0; + + while (n < array->len) { + if (fn(array->val[n], ctx)) { + heim_array_delete_value(array, n); + } else { + n++; + } + } +} + +#ifdef __BLOCKS__ + +/** + * Filter out entres of array when block return true + * + * @param array the array to modify + * @param block filter block + */ + +void +heim_array_filter(heim_array_t array, int (^block)(heim_object_t)) +{ + size_t n = 0; + + while (n < array->len) { + if (block(array->val[n])) { + heim_array_delete_value(array, n); + } else { + n++; + } + } +} + +#endif /* __BLOCKS__ */ diff --git a/third_party/heimdal/lib/base/baselocl.h b/third_party/heimdal/lib/base/baselocl.h new file mode 100644 index 0000000..7ca6439 --- /dev/null +++ b/third_party/heimdal/lib/base/baselocl.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010 - 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include + +#define ISTILDE(x) (x == '~') +#ifdef _WIN32 +# define ISPATHSEP(x) (x == '/' || x =='\\') +#else +# define ISPATHSEP(x) (x == '/') +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define HEIMDAL_TEXTDOMAIN "heimdal_krb5" + +#ifdef LIBINTL +#include +#define N_(x,y) dgettext(HEIMDAL_TEXTDOMAIN, x) +#else +#define N_(x,y) (x) +#define bindtextdomain(package, localedir) +#endif + +#include "heimqueue.h" +#include "heim_threads.h" +#include "heimbase.h" +#include "heimbasepriv.h" + +#ifdef HAVE_DISPATCH_DISPATCH_H +#include +#endif + +/* tagged strings/object/XXX */ +#define heim_base_is_tagged(x) (((uintptr_t)(x)) & 0x3) + +#define heim_base_is_tagged_object(x) ((((uintptr_t)(x)) & 0x3) == 1) +#define heim_base_make_tagged_object(x, tid) \ + ((heim_object_t)((((uintptr_t)(x)) << 5) | ((tid) << 2) | 0x1)) +#define heim_base_tagged_object_tid(x) ((((uintptr_t)(x)) & 0x1f) >> 2) +#define heim_base_tagged_object_value(x) (((uintptr_t)(x)) >> 5) + +/* + * + */ + +#undef HEIMDAL_NORETURN_ATTRIBUTE +#define HEIMDAL_NORETURN_ATTRIBUTE +#undef HEIMDAL_PRINTF_ATTRIBUTE +#define HEIMDAL_PRINTF_ATTRIBUTE(x) + +struct heim_context_s { + heim_log_facility *log_dest; + heim_log_facility *warn_dest; + heim_log_facility *debug_dest; + char *time_fmt; + unsigned int log_utc:1; + unsigned int homedir_access:1; + struct et_list *et_list; + char *error_string; + heim_error_code error_code; +}; diff --git a/third_party/heimdal/lib/base/bool.c b/third_party/heimdal/lib/base/bool.c new file mode 100644 index 0000000..f7b66ee --- /dev/null +++ b/third_party/heimdal/lib/base/bool.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +struct heim_type_data _heim_bool_object = { + HEIM_TID_BOOL, + "bool-object", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +heim_bool_t +heim_bool_create(int val) +{ + return heim_base_make_tagged_object(!!val, HEIM_TID_BOOL); +} + +int +heim_bool_val(heim_bool_t ptr) +{ + return heim_base_tagged_object_value(ptr); +} diff --git a/third_party/heimdal/lib/base/bsearch.c b/third_party/heimdal/lib/base/bsearch.c new file mode 100644 index 0000000..268cc01 --- /dev/null +++ b/third_party/heimdal/lib/base/bsearch.c @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2011, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "baselocl.h" + +#include +#include +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include + +/* + * This file contains functions for binary searching flat text in memory + * and in text files where each line is a [variable length] record. + * Each record has a key and an optional value separated from the key by + * unquoted whitespace. Whitespace in the key, and leading whitespace + * for the value, can be quoted with backslashes (but CR and LF must be + * quoted in such a way that they don't appear in the quoted result). + * + * Binary searching a tree are normally a dead simple algorithm. It + * turns out that binary searching flat text with *variable* length + * records is... tricky. There's no indexes to record beginning bytes, + * thus any index selected during the search is likely to fall in the + * middle of a record. When deciding to search a left sub-tree one + * might fail to find the last record in that sub-tree on account of the + * right boundary falling in the middle of it -- the chosen solution to + * this makes left sub-tree searches slightly less efficient than right + * sub-tree searches. + * + * If binary searching flat text in memory is tricky, using block-wise + * I/O instead is trickier! But it's necessary in order to support + * large files (which we either can't or wouldn't want to read or map + * into memory). Each block we read has to be large enough that the + * largest record can fit in it. And each block might start and/or end + * in the middle of a record. Here it is the right sub-tree searches + * that are less efficient than left sub-tree searches. + * + * bsearch_common() contains the common text block binary search code. + * + * _bsearch_text() is the interface for searching in-core text. + * _bsearch_file() is the interface for block-wise searching files. + */ + +struct bsearch_file_handle { + int fd; /* file descriptor */ + char *cache; /* cache bytes */ + char *page; /* one double-size page worth of bytes */ + size_t file_sz; /* file size */ + size_t cache_sz; /* cache size */ + size_t page_sz; /* page size */ +}; + +/* Find a new-line */ +static const char * +find_line(const char *buf, size_t i, size_t right) +{ + if (i == 0) + return &buf[i]; + for (; i < right; i++) { + if (buf[i] == '\n') { + if ((i + 1) < right) + return &buf[i + 1]; + return NULL; + } + } + return NULL; +} + +/* + * Common routine for binary searching text in core. + * + * Perform a binary search of a char array containing a block from a + * text file where each line is a record (LF and CRLF supported). Each + * record consists of a key followed by an optional value separated from + * the key by whitespace. Whitespace can be quoted with backslashes. + * It's the caller's responsibility to encode/decode keys/values if + * quoting is desired; newlines should be encoded such that a newline + * does not appear in the result. + * + * All output arguments are optional. + * + * Returns 0 if key is found, -1 if not found, or an error code such as + * ENOMEM in case of error. + * + * Inputs: + * + * @buf String to search + * @sz Size of string to search + * @key Key string to search for + * @buf_is_start True if the buffer starts with a record, false if it + * starts in the middle of a record or if the caller + * doesn't know. + * + * Outputs: + * + * @value Location to store a copy of the value (caller must free) + * @location Record location if found else the location where the + * record should be inserted (index into @buf) + * @cmp Set to less than or greater than 0 to indicate that a + * key not found would have fit in an earlier or later + * part of a file. Callers should use this to decide + * whether to read a block to the left or to the right and + * search that. + * @loops Location to store a count of bisections required for + * search (useful for confirming logarithmic performance) + */ +static int +bsearch_common(const char *buf, size_t sz, const char *key, + int buf_is_start, char **value, size_t *location, + int *cmp, size_t *loops) +{ + const char *linep; + size_t key_start, key_len; /* key string in buf */ + size_t val_start, val_len; /* value string in buf */ + int key_cmp = -1; + size_t k; + size_t l; /* left side of buffer for binary search */ + size_t r; /* right side of buffer for binary search */ + size_t rmax; /* right side of buffer for binary search */ + size_t i; /* index into buffer, typically in the middle of l and r */ + size_t loop_count = 0; + int ret = -1; + + if (value) + *value = NULL; + if (cmp) + *cmp = 0; + if (loops) + *loops = 0; + + /* Binary search; file should be sorted */ + for (l = 0, r = rmax = sz, i = sz >> 1; i >= l && i < rmax; loop_count++) { + heim_assert(i < sz, "invalid aname2lname db index"); + + /* buf[i] is likely in the middle of a line; find the next line */ + linep = find_line(buf, i, rmax); + k = linep ? linep - buf : i; + if (linep == NULL || k >= rmax) { + /* + * No new line found to the right; search to the left then + * but don't change rmax (this isn't optimal, but it's + * simple). + */ + if (i == l) + break; + r = i; + i = l + ((r - l) >> 1); + continue; + } + i = k; + heim_assert(i >= l && i < rmax, "invalid aname2lname db index"); + + /* Got a line; check it */ + + /* Search for and split on unquoted whitespace */ + val_start = 0; + for (key_start = i, key_len = 0, val_len = 0, k = i; k < rmax; k++) { + if (buf[k] == '\\') { + k++; + continue; + } + if (buf[k] == '\r' || buf[k] == '\n') { + /* We now know where the key ends, and there's no value */ + key_len = k - i; + break; + } + if (!isspace((unsigned char)buf[k])) + continue; + + while (k < rmax && isspace((unsigned char)buf[k])) { + key_len = k - i; + k++; + } + if (k < rmax) + val_start = k; + /* Find end of value */ + for (; k < rmax && buf[k] != '\0'; k++) { + if (buf[k] == '\r' || buf[k] == '\n') { + val_len = k - val_start; + break; + } + } + break; + } + + /* + * The following logic is for dealing with partial buffers, + * which we use for block-wise binary searches of large files + */ + if (key_start == 0 && !buf_is_start) { + /* + * We're at the beginning of a block that might have started + * in the middle of a record whose "key" might well compare + * as greater than the key we're looking for, so we don't + * bother comparing -- we know key_cmp must be -1 here. + */ + key_cmp = -1; + break; + } + if ((val_len && buf[val_start + val_len] != '\n') || + (!val_len && buf[key_start + key_len] != '\n')) { + /* + * We're at the end of a block that ends in the middle of a + * record whose "key" might well compare as less than the + * key we're looking for, so we don't bother comparing -- we + * know key_cmp must be >= 0 but we can't tell. Our caller + * will end up reading a double-size block to handle this. + */ + key_cmp = 1; + break; + } + + key_cmp = strncmp(key, &buf[key_start], key_len); + if (key_cmp == 0 && strlen(key) != key_len) + key_cmp = 1; + if (key_cmp < 0) { + /* search left */ + r = rmax = (linep - buf); + i = l + ((r - l) >> 1); + if (location) + *location = key_start; + } else if (key_cmp > 0) { + /* search right */ + if (l == i) + break; /* not found */ + l = i; + i = l + ((r - l) >> 1); + if (location) + *location = val_start + val_len; + } else { + /* match! */ + if (location) + *location = key_start; + ret = 0; + if (val_len && value) { + /* Avoid strndup() so we don't need libroken here yet */ + if ((*value = malloc(val_len + 1))) { + (void) memcpy(*value, &buf[val_start], val_len); + (*value)[val_len] = '\0'; + } else { + ret = errno; + } + } + break; + } + } + + if (cmp) + *cmp = key_cmp; + if (loops) + *loops = loop_count; + + return ret; +} + +/* + * Binary search a char array containing sorted text records separated + * by new-lines (or CRLF). Each record consists of a key and an + * optional value following the key, separated from the key by unquoted + * whitespace. + * + * All output arguments are optional. + * + * Returns 0 if key is found, -1 if not found, or an error code such as + * ENOMEM in case of error. + * + * Inputs: + * + * @buf Char array pointer + * @buf_sz Size of buf + * @key Key to search for + * + * Outputs: + * + * @value Location where to put the value, if any (caller must free) + * @location Record location if found else the location where the record + * should be inserted (index into @buf) + * @loops Location where to put a number of loops (or comparisons) + * needed for the search (useful for benchmarking) + */ +int +_bsearch_text(const char *buf, size_t buf_sz, const char *key, + char **value, size_t *location, size_t *loops) +{ + return bsearch_common(buf, buf_sz, key, 1, value, location, NULL, loops); +} + +#define MAX_BLOCK_SIZE (1024 * 1024) +#define DEFAULT_MAX_FILE_SIZE (1024 * 1024) +/* + * Open a file for binary searching. The file will be read in entirely + * if it is smaller than @max_sz, else a cache of @max_sz bytes will be + * allocated. + * + * Returns 0 on success, else an error number or -1 if the file is empty. + * + * Inputs: + * + * @fname Name of file to open + * @max_sz Maximum size of cache to allocate, in bytes (if zero, default) + * @page_sz Page size (must be a power of two, larger than 256, smaller + * than 1MB; if zero use default) + * + * Outputs: + * + * @bfh Handle for use with _bsearch_file() and _bsearch_file_close() + * @reads Number of reads performed + */ +int +_bsearch_file_open(const char *fname, size_t max_sz, size_t page_sz, + bsearch_file_handle *bfh, size_t *reads) +{ + bsearch_file_handle new_bfh = NULL; + struct stat st; + size_t i; + int fd; + int ret; + + *bfh = NULL; + + if (reads) + *reads = 0; + + fd = open(fname, O_RDONLY); + if (fd == -1) + return errno; + + if (fstat(fd, &st) == -1) { + ret = errno; + goto err; + } + + if (st.st_size == 0) { + ret = -1; /* no data -> no binary search */ + goto err; + } + + /* Validate / default arguments */ + if (max_sz == 0) + max_sz = DEFAULT_MAX_FILE_SIZE; + for (i = page_sz; i; i >>= 1) { + /* Make sure page_sz is a power of two */ + if ((i % 2) && (i >> 1)) { + page_sz = 0; + break; + } + } + if (page_sz == 0) +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + page_sz = st.st_blksize; +#else + page_sz = 4096; +#endif + for (i = page_sz; i; i >>= 1) { + /* Make sure page_sz is a power of two */ + if ((i % 2) && (i >> 1)) { + /* Can't happen! Filesystems always use powers of two! */ + page_sz = 4096; + break; + } + } + if (page_sz > MAX_BLOCK_SIZE) + page_sz = MAX_BLOCK_SIZE; + + new_bfh = calloc(1, sizeof (*new_bfh)); + if (new_bfh == NULL) { + ret = ENOMEM; + goto err; + } + + new_bfh->fd = fd; + new_bfh->page_sz = page_sz; + new_bfh->file_sz = st.st_size; + + if (max_sz >= st.st_size) { + /* Whole-file method */ + new_bfh->cache = malloc(st.st_size + 1); + if (new_bfh->cache) { + new_bfh->cache[st.st_size] = '\0'; + new_bfh->cache_sz = st.st_size; + ret = read(fd, new_bfh->cache, st.st_size); + if (ret < 0) { + ret = errno; + goto err; + } + if (ret != st.st_size) { + ret = EIO; /* XXX ??? */ + goto err; + } + if (reads) + *reads = 1; + (void) close(fd); + new_bfh->fd = -1; + *bfh = new_bfh; + return 0; + } + } + + /* Block-size method, or above malloc() failed */ + new_bfh->page = malloc(new_bfh->page_sz << 1); + if (new_bfh->page == NULL) { + /* Can't even allocate a single double-size page! */ + ret = ENOMEM; + goto err; + } + + new_bfh->cache_sz = max_sz < st.st_size ? max_sz : st.st_size; + new_bfh->cache = malloc(new_bfh->cache_sz); + *bfh = new_bfh; + + /* + * malloc() may have failed because we were asking for a lot of + * memory, but we may still be able to operate without a cache, + * so let's not fail. + */ + if (new_bfh->cache == NULL) { + new_bfh->cache_sz = 0; + return 0; + } + + /* Initialize cache */ + for (i = 0; i < new_bfh->cache_sz; i += new_bfh->page_sz) + new_bfh->cache[i] = '\0'; + return 0; + +err: + (void) close(fd); + if (new_bfh) { + free(new_bfh->page); + free(new_bfh->cache); + free(new_bfh); + } + return ret; +} + +/* + * Indicate whether the given binary search file handle will be searched + * with block-wise method. + */ +void +_bsearch_file_info(bsearch_file_handle bfh, + size_t *page_sz, size_t *max_sz, int *blockwise) +{ + if (page_sz) + *page_sz = bfh->page_sz; + if (max_sz) + *max_sz = bfh->cache_sz; + if (blockwise) + *blockwise = (bfh->file_sz != bfh->cache_sz); +} + +/* + * Close the given binary file search handle. + * + * Inputs: + * + * @bfh Pointer to variable containing handle to close. + */ +void +_bsearch_file_close(bsearch_file_handle *bfh) +{ + if (!*bfh) + return; + if ((*bfh)->fd >= 0) + (void) close((*bfh)->fd); + if ((*bfh)->page) + free((*bfh)->page); + if ((*bfh)->cache) + free((*bfh)->cache); + free(*bfh); + *bfh = NULL; +} + +/* + * Private function to get a page from a cache. The cache is a char + * array of 2^n - 1 double-size page worth of bytes, where n is the + * number of tree levels that the cache stores. The cache can be + * smaller than n implies. + * + * The page may or may not be valid. If the first byte of it is NUL + * then it's not valid, else it is. + * + * Returns 1 if page is in cache and valid, 0 if the cache is too small + * or the page is invalid. The page address is output in @buf if the + * cache is large enough to contain it regardless of whether the page is + * valid. + * + * Inputs: + * + * @bfh Binary search file handle + * @level Level in the tree that we want a page for + * @page_idx Page number in the given level (0..2^level - 1) + * + * Outputs: + * + * @buf Set to address of page if the cache is large enough + */ +static int +get_page_from_cache(bsearch_file_handle bfh, size_t level, size_t page_idx, + char **buf) +{ + size_t idx = 0; + size_t page_sz; + + page_sz = bfh->page_sz << 1; /* we use double-size pages in the cache */ + + *buf = NULL; + + /* + * Compute index into cache. The cache is basically an array of + * double-size pages. The first (zeroth) double-size page in the + * cache will be the middle page of the file -- the root of the + * tree. The next two double-size pages will be the left and right + * pages of the second level in the tree. The next four double-size + * pages will be the four pages at the next level. And so on for as + * many pages as fit in the cache. + * + * The page index is the number of the page at the given level. We + * then compute (2^level - 1 + page index) * 2page size, check that + * we have that in the cache, check that the page has been read (it + * doesn't start with NUL). + */ + if (level) + idx = (1 << level) - 1 + page_idx; + if (((idx + 1) * page_sz * 2) > bfh->cache_sz) + return 0; + + *buf = &bfh->cache[idx * page_sz * 2]; + if (bfh->cache[idx * page_sz * 2] == '\0') + return 0; /* cache[idx] == NUL -> page not loaded in cache */ + return 1; +} + +/* + * Private function to read a page of @page_sz from @fd at offset @off + * into @buf, outputing the number of bytes read, which will be the same + * as @page_sz unless the page being read is the last page, in which + * case the number of remaining bytes in the file will be output. + * + * Returns 0 on success or an errno value otherwise (EIO if reads are + * short). + * + * Inputs: + * + * @bfh Binary search file handle + * @level Level in the binary search tree that we're at + * @page_idx Page "index" at the @level of the tree that we want + * @page Actual page number that we want + * want_double Whether we need a page or double page read + * + * Outputs: + * + * @buf Page read or cached + * @bytes Bytes read (may be less than page or double page size in + * the case of the last page, of course) + */ +static int +read_page(bsearch_file_handle bfh, size_t level, size_t page_idx, size_t page, + int want_double, const char **buf, size_t *bytes) +{ + int ret; + off_t off; + size_t expected; + size_t wanted; + char *page_buf; + + /* Figure out where we're reading and how much */ + off = page * bfh->page_sz; + if (off < 0) + return EOVERFLOW; + + wanted = bfh->page_sz << want_double; + expected = ((bfh->file_sz - off) > wanted) ? wanted : bfh->file_sz - off; + + if (get_page_from_cache(bfh, level, page_idx, &page_buf)) { + *buf = page_buf; + *bytes = expected; + return 0; /* found in cache */ + } + + + *bytes = 0; + *buf = NULL; + + /* OK, we have to read a page or double-size page */ + + if (page_buf) + want_double = 1; /* we'll be caching; we cache double-size pages */ + else + page_buf = bfh->page; /* we won't cache this page */ + + wanted = bfh->page_sz << want_double; + expected = ((bfh->file_sz - off) > wanted) ? wanted : bfh->file_sz - off; + +#ifdef HAVE_PREAD + ret = pread(bfh->fd, page_buf, expected, off); +#else + if (lseek(bfh->fd, off, SEEK_SET) == (off_t)-1) + return errno; + ret = read(bfh->fd, page_buf, expected); +#endif + if (ret < 0) + return errno; + + if (ret != expected) + return EIO; /* XXX ??? */ + + *buf = page_buf; + *bytes = expected; + return 0; +} + +/* + * Perform a binary search of a file where each line is a record (LF and + * CRLF supported). Each record consists of a key followed by an + * optional value separated from the key by whitespace. Whitespace can + * be quoted with backslashes. It's the caller's responsibility to + * encode/decode keys/values if quoting is desired; newlines should be + * encoded such that a newline does not appear in the result. + * + * The search is done with block-wise I/O (i.e., the whole file is not + * read into memory). + * + * All output arguments are optional. + * + * Returns 0 if key is found, -1 if not found, or an error code such as + * ENOMEM in case of error. + * + * NOTE: We could improve this by not freeing the buffer, instead + * requiring that the caller provide it. Further, we could cache + * the top N levels of [double-size] pages (2^N - 1 pages), which + * should speed up most searches by reducing the number of reads + * by N. + * + * Inputs: + * + * @fd File descriptor (file to search) + * @page_sz Page size (if zero then the file's st_blksize will be used) + * @key Key string to search for + * + * Outputs: + * + * @value Location to store a copy of the value (caller must free) + * @location Record location if found else the location where the + * record should be inserted (index into @buf) + * @loops Location to store a count of bisections required for + * search (useful for confirming logarithmic performance) + * @reads Location to store a count of pages read during search + * (useful for confirming logarithmic performance) + */ +int +_bsearch_file(bsearch_file_handle bfh, const char *key, + char **value, size_t *location, size_t *loops, size_t *reads) +{ + int ret; + const char *buf; + size_t buf_sz; + size_t page, l, r; + size_t my_reads = 0; + size_t my_loops_total = 0; + size_t my_loops; + size_t level; /* level in the tree */ + size_t page_idx = 0; /* page number in the tree level */ + size_t buf_location; + int cmp; + int buf_ends_in_eol = 0; + int buf_is_start = 0; + + if (reads) + *reads = 0; + if (value) + *value = NULL; + if (loops) + *loops = 0; + + /* If whole file is in memory then search that and we're done */ + if (bfh->file_sz == bfh->cache_sz) + return _bsearch_text(bfh->cache, bfh->cache_sz, key, value, location, loops); + + /* Else block-wise binary search */ + + l = 0; + r = (bfh->file_sz / bfh->page_sz) + 1; + for (level = 0, page = r >> 1; page >= l && page < r ; level++) { + ret = read_page(bfh, level, page_idx, page, 0, &buf, &buf_sz); + if (ret != 0) + return ret; + my_reads++; + if (buf[buf_sz - 1] == '\r' || buf[buf_sz - 1] == '\n') + buf_ends_in_eol = 1; + else + buf_ends_in_eol = 0; + + buf_is_start = page == 0 ? 1 : 0; + ret = bsearch_common(buf, (size_t)buf_sz, key, buf_is_start, + value, &buf_location, &cmp, &my_loops); + if (ret > 0) + return ret; + /* Found or no we update stats */ + my_loops_total += my_loops; + if (loops) + *loops = my_loops_total; + if (reads) + *reads = my_reads; + if (location) + *location = page * bfh->page_sz + buf_location; + if (ret == 0) + return 0; /* found! */ + /* Not found */ + if (cmp < 0) { + /* Search left */ + page_idx <<= 1; + r = page; + page = l + ((r - l) >> 1); + continue; + } else { + /* + * Search right, but first search the current and next + * blocks in case that the record we're looking for either + * straddles the boundary between this and the next record, + * or in case the record starts exactly at the next page. + */ + heim_assert(cmp > 0, "cmp > 0"); + + if (!buf_ends_in_eol || page == l || page == (r - 1)) { + ret = read_page(bfh, level, page_idx, page, 1, &buf, &buf_sz); + if (ret != 0) + return ret; + my_reads++; + + buf_is_start = page == l ? 1 : 0; + + ret = bsearch_common(buf, (size_t)buf_sz, key, buf_is_start, + value, &buf_location, &cmp, &my_loops); + if (ret > 0) + return ret; + my_loops_total += my_loops; + if (loops) + *loops = my_loops_total; + if (reads) + *reads = my_reads; + if (location) + *location = page * bfh->page_sz + buf_location; + if (ret == 0) + return 0; + } + + /* Oh well, search right */ + if (l == page && r == (l + 1)) + break; + page_idx = (page_idx << 1) + 1; + l = page; + page = l + ((r - l) >> 1); + continue; + } + } + return -1; +} + + +static int +stdb_open(void *plug, const char *dbtype, const char *dbname, + heim_dict_t options, void **db, heim_error_t *error) +{ + bsearch_file_handle bfh; + char *p; + int ret; + + if (error) + *error = NULL; + if (dbname == NULL || *dbname == '\0') { + if (error) + *error = heim_error_create(EINVAL, + N_("DB name required for sorted-text DB " + "plugin", "")); + return EINVAL; + } + p = strrchr(dbname, '.'); + if (p == NULL || strcmp(p, ".txt") != 0) { + if (error) + *error = heim_error_create(ENOTSUP, + N_("Text file (name ending in .txt) " + "required for sorted-text DB plugin", + "")); + return ENOTSUP; + } + + ret = _bsearch_file_open(dbname, 0, 0, &bfh, NULL); + if (ret) + return ret; + + *db = bfh; + return 0; +} + +static int +stdb_close(void *db, heim_error_t *error) +{ + bsearch_file_handle bfh = db; + + if (error) + *error = NULL; + _bsearch_file_close(&bfh); + return 0; +} + +static heim_data_t +stdb_copy_value(void *db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + bsearch_file_handle bfh = db; + const char *k; + char *v = NULL; + heim_data_t value; + int ret; + + if (error) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + if (table != HSTR("")) + return NULL; + + if (heim_get_tid(key) == HEIM_TID_STRING) + k = heim_string_get_utf8((heim_string_t)key); + else + k = (const char *)heim_data_get_ptr(key); + ret = _bsearch_file(bfh, k, &v, NULL, NULL, NULL); + if (ret == 0 && v == NULL) + ret = -1; /* Quiet lint */ + if (ret != 0) { + if (ret > 0 && error) + *error = heim_error_create(ret, "%s", strerror(ret)); + return NULL; + } + value = heim_data_create(v, strlen(v)); + free(v); + /* XXX Handle ENOMEM */ + return value; +} + +struct heim_db_type heim_sorted_text_file_dbtype = { + 1, stdb_open, NULL, stdb_close, NULL, NULL, NULL, NULL, NULL, NULL, + stdb_copy_value, NULL, NULL, NULL +}; diff --git a/third_party/heimdal/lib/base/common_plugin.h b/third_party/heimdal/lib/base/common_plugin.h new file mode 100644 index 0000000..d7b6bca --- /dev/null +++ b/third_party/heimdal/lib/base/common_plugin.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006 - 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2018 AuriStor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIMDAL_BASE_COMMON_PLUGIN_H +#define HEIMDAL_BASE_COMMON_PLUGIN_H + +#include + +#ifdef _WIN32 +# ifndef HEIM_CALLCONV +# define HEIM_CALLCONV __stdcall +# endif +# ifndef HEIM_LIB_CALL +# define HEIM_LIB_CALL __stdcall +# endif +#else +# ifndef HEIM_CALLCONV +# define HEIM_CALLCONV +# endif +# ifndef HEIM_LIB_CALL +# define HEIM_LIB_CALL +# endif +#endif +#ifndef KRB5_CALLCONV +# define KRB5_CALLCONV HEIM_CALLCONV +#endif +#ifndef KRB5_LIB_CALL +# define KRB5_LIB_CALL HEIM_LIB_CALL +#endif + +/* For krb5 plugins, this is a krb5_context */ +typedef struct heim_pcontext_s *heim_pcontext; + +typedef uintptr_t +(HEIM_LIB_CALL *heim_get_instance_func_t)(const char *); +typedef heim_get_instance_func_t krb5_get_instance_t; + +/* + * All plugin function tables extend the following structure. + */ +struct heim_plugin_common_ftable_desc { + HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(heim_pcontext); +}; +typedef struct heim_plugin_common_ftable_desc heim_plugin_common_ftable; +typedef struct heim_plugin_common_ftable_desc *heim_plugin_common_ftable_p; +typedef const struct heim_plugin_common_ftable_desc *heim_plugin_common_ftable_const_p; +typedef struct heim_plugin_common_ftable_desc * const heim_plugin_common_ftable_cp; + +typedef int +(HEIM_CALLCONV heim_plugin_load_ft)(heim_pcontext context, + heim_get_instance_func_t *func, + size_t *n_ftables, + heim_plugin_common_ftable_cp **ftables); + +typedef heim_plugin_load_ft *heim_plugin_load_t; + +/* For source backwards-compatibility */ +typedef struct heim_plugin_common_ftable_desc krb5_plugin_common_ftable; +typedef struct heim_plugin_common_ftable_desc *krb5_plugin_common_ftable_p; +typedef struct heim_plugin_common_ftable_desc * const krb5_plugin_common_ftable_cp; +typedef heim_plugin_load_ft krb5_plugin_load_ft; +typedef heim_plugin_load_ft *krb5_plugin_load_t; + +/* + * All plugins must export a function named "_plugin_load" with + * a signature of: + * + * int HEIM_CALLCONV + * _plugin_load(heim_pcontext context, + * heim_get_instance_func_t *func, + * size_t *n_ftables, + * const heim_plugin_common_ftable *const **ftables); + */ +#endif /* HEIMDAL_BASE_COMMON_PLUGIN_H */ diff --git a/third_party/heimdal/lib/base/config_file.c b/third_party/heimdal/lib/base/config_file.c new file mode 100644 index 0000000..b1675ea --- /dev/null +++ b/third_party/heimdal/lib/base/config_file.c @@ -0,0 +1,1472 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include +#include +#include + +#if defined(HAVE_FRAMEWORK_COREFOUNDATION) +#include +#endif + +/* Gaah! I want a portable funopen */ +struct fileptr { + heim_context context; + const char *s; + FILE *f; +}; + +static char * +config_fgets(char *str, size_t len, struct fileptr *ptr) +{ + /* XXX this is not correct, in that they don't do the same if the + line is longer than len */ + if(ptr->f != NULL) + return fgets(str, len, ptr->f); + else { + /* this is almost strsep_copy */ + const char *p; + ssize_t l; + if(*ptr->s == '\0') + return NULL; + p = ptr->s + strcspn(ptr->s, "\n"); + if(*p == '\n') + p++; + l = min(len, (size_t)(p - ptr->s)); + if(len > 0) { + memcpy(str, ptr->s, l); + str[l] = '\0'; + } + ptr->s = p; + return str; + } +} + +static heim_error_code parse_section(char *p, heim_config_section **s, + heim_config_section **res, + const char **err_message); +static heim_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p, + heim_config_binding **b, + heim_config_binding **parent, + const char **err_message); +static heim_error_code parse_list(struct fileptr *f, unsigned *lineno, + heim_config_binding **parent, + const char **err_message); + +heim_config_section * +heim_config_get_entry(heim_config_section **parent, const char *name, int type) +{ + heim_config_section **q; + + for (q = parent; *q != NULL; q = &(*q)->next) + if (type == heim_config_list && + (unsigned)type == (*q)->type && + strcmp(name, (*q)->name) == 0) + return *q; + *q = calloc(1, sizeof(**q)); + if (*q == NULL) + return NULL; + (*q)->name = strdup(name); + (*q)->type = type; + if ((*q)->name == NULL) { + free(*q); + *q = NULL; + return NULL; + } + return *q; +} + +/* + * Parse a section: + * + * [section] + * foo = bar + * b = { + * a + * } + * ... + * + * starting at the line in `p', storing the resulting structure in + * `s' and hooking it into `parent'. + * Store the error message in `err_message'. + */ + +static heim_error_code +parse_section(char *p, heim_config_section **s, heim_config_section **parent, + const char **err_message) +{ + char *p1; + heim_config_section *tmp; + + p1 = strchr (p + 1, ']'); + if (p1 == NULL) { + *err_message = "missing ]"; + return HEIM_ERR_CONFIG_BADFORMAT; + } + *p1 = '\0'; + tmp = heim_config_get_entry(parent, p + 1, heim_config_list); + if(tmp == NULL) { + *err_message = "out of memory"; + return HEIM_ERR_CONFIG_BADFORMAT; + } + *s = tmp; + return 0; +} + +/* + * Parse a brace-enclosed list from `f', hooking in the structure at + * `parent'. + * Store the error message in `err_message'. + */ + +static heim_error_code +parse_list(struct fileptr *f, unsigned *lineno, heim_config_binding **parent, + const char **err_message) +{ + char buf[2048]; + heim_error_code ret; + heim_config_binding *b = NULL; + unsigned beg_lineno = *lineno; + + while(config_fgets(buf, sizeof(buf), f) != NULL) { + char *p; + + ++*lineno; + buf[strcspn(buf, "\r\n")] = '\0'; + p = buf; + while(isspace((unsigned char)*p)) + ++p; + if (*p == '#' || *p == ';' || *p == '\0') + continue; + while(isspace((unsigned char)*p)) + ++p; + if (*p == '}') + return 0; + if (*p == '\0') + continue; + ret = parse_binding (f, lineno, p, &b, parent, err_message); + if (ret) + return ret; + } + *lineno = beg_lineno; + *err_message = "unclosed {"; + return HEIM_ERR_CONFIG_BADFORMAT; +} + +/* + * + */ + +static heim_error_code +parse_binding(struct fileptr *f, unsigned *lineno, char *p, + heim_config_binding **b, heim_config_binding **parent, + const char **err_message) +{ + heim_config_binding *tmp; + char *p1, *p2; + heim_error_code ret = 0; + + p1 = p; + while (*p && *p != '=' && !isspace((unsigned char)*p)) + ++p; + if (*p == '\0') { + *err_message = "missing ="; + return HEIM_ERR_CONFIG_BADFORMAT; + } + p2 = p; + while (isspace((unsigned char)*p)) + ++p; + if (*p != '=') { + *err_message = "missing ="; + return HEIM_ERR_CONFIG_BADFORMAT; + } + ++p; + while(isspace((unsigned char)*p)) + ++p; + *p2 = '\0'; + if (*p == '{') { + tmp = heim_config_get_entry(parent, p1, heim_config_list); + if (tmp == NULL) { + *err_message = "out of memory"; + return HEIM_ERR_CONFIG_BADFORMAT; + } + ret = parse_list (f, lineno, &tmp->u.list, err_message); + } else { + tmp = heim_config_get_entry(parent, p1, heim_config_string); + if (tmp == NULL) { + *err_message = "out of memory"; + return HEIM_ERR_CONFIG_BADFORMAT; + } + p1 = p; + p = p1 + strlen(p1); + while(p > p1 && isspace((unsigned char)*(p-1))) + --p; + *p = '\0'; + tmp->u.string = strdup(p1); + } + *b = tmp; + return ret; +} + +#if defined(HAVE_FRAMEWORK_COREFOUNDATION) + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 +#define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1 +#endif + +static char * +cfstring2cstring(CFStringRef string) +{ + CFIndex len; + char *str; + + str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8); + if (str) + return strdup(str); + + len = CFStringGetLength(string); + len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); + str = malloc(len); + if (str == NULL) + return NULL; + + if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) { + free (str); + return NULL; + } + return str; +} + +static void +convert_content(const void *key, const void *value, void *context) +{ + heim_config_section *tmp, **parent = context; + char *k; + + if (CFGetTypeID(key) != CFStringGetTypeID()) + return; + + k = cfstring2cstring(key); + if (k == NULL) + return; + + if (CFGetTypeID(value) == CFStringGetTypeID()) { + tmp = heim_config_get_entry(parent, k, heim_config_string); + tmp->u.string = cfstring2cstring(value); + } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) { + tmp = heim_config_get_entry(parent, k, heim_config_list); + CFDictionaryApplyFunction(value, convert_content, &tmp->u.list); + } else { + /* log */ + } + free(k); +} + +static heim_error_code +parse_plist_config(heim_context context, const char *path, heim_config_section **parent) +{ + CFReadStreamRef s; + CFDictionaryRef d; + CFURLRef url; + + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), 0); + if (url == NULL) { + heim_clear_error_message(context); + return ENOMEM; + } + + s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); + CFRelease(url); + if (s == NULL) { + heim_clear_error_message(context); + return ENOMEM; + } + + if (!CFReadStreamOpen(s)) { + CFRelease(s); + heim_clear_error_message(context); + return ENOENT; + } + +#ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM + d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL); +#else + d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL); +#endif + CFRelease(s); + if (d == NULL) { + heim_clear_error_message(context); + return ENOENT; + } + + CFDictionaryApplyFunction(d, convert_content, parent); + CFRelease(d); + + return 0; +} + +#endif + +static int +is_absolute_path(const char *path) +{ + /* + * An absolute path is one that refers to an explicit object + * without ambiguity. + */ +#ifdef WIN32 + size_t len = strlen(path); + + /* UNC path is by definition absolute */ + if (len > 2 + && ISPATHSEP(path[0]) + && ISPATHSEP(path[1])) + return 1; + + /* A drive letter path might be absolute */ + if (len > 3 + && isalpha((unsigned char)path[0]) + && path[1] == ':' + && ISPATHSEP(path[2])) + return 1; + + /* + * if no drive letter but first char is a path + * separator then the drive letter must be obtained + * from the including file. + */ +#else + /* UNIX is easy, first char '/' is absolute */ + if (ISPATHSEP(path[0])) + return 1; +#endif + return 0; +} + +/* + * Parse the config file `fname', generating the structures into `res' + * returning error messages in `err_message' + */ + +static heim_error_code +heim_config_parse_debug(struct fileptr *f, + heim_config_section **res, + unsigned *lineno, + const char **err_message) +{ + heim_config_section *s = NULL; + heim_config_binding *b = NULL; + char buf[2048]; + heim_error_code ret; + + *lineno = 0; + *err_message = ""; + + while (config_fgets(buf, sizeof(buf), f) != NULL) { + char *p; + + ++*lineno; + buf[strcspn(buf, "\r\n")] = '\0'; + p = buf; + while(isspace((unsigned char)*p)) + ++p; + if (*p == '#' || *p == ';') + continue; + if (*p == '[') { + ret = parse_section(p, &s, res, err_message); + if (ret) + return ret; + b = NULL; + } else if (*p == '}') { + *err_message = "unmatched }"; + return 2048; + } else if (strncmp(p, "include", sizeof("include") - 1) == 0 && + isspace((unsigned char)p[sizeof("include") - 1])) { + p += sizeof("include"); + while (isspace((unsigned char)*p)) + p++; + if (!is_absolute_path(p)) { + heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT, + "Configuration include path must be " + "absolute"); + return HEIM_ERR_CONFIG_BADFORMAT; + } + ret = heim_config_parse_file_multi(f->context, p, res); + if (ret) + return ret; + } else if (strncmp(p, "includedir", sizeof("includedir") - 1) == 0 && + isspace((unsigned char)p[sizeof("includedir") - 1])) { + p += sizeof("includedir"); + while (isspace((unsigned char)*p)) + p++; + if (!is_absolute_path(p)) { + heim_set_error_message(f->context, HEIM_ERR_CONFIG_BADFORMAT, + "Configuration includedir path must be " + "absolute"); + return HEIM_ERR_CONFIG_BADFORMAT; + } + ret = heim_config_parse_dir_multi(f->context, p, res); + if (ret) + return ret; + } else if(*p != '\0') { + if (s == NULL) { + *err_message = "binding before section"; + return 2048; + } + ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message); + if (ret) + return ret; + } + } + return 0; +} + +static int +is_plist_file(const char *fname) +{ + size_t len = strlen(fname); + char suffix[] = ".plist"; + if (len < sizeof(suffix)) + return 0; + if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0) + return 0; + return 1; +} + +/** + * Parse configuration files in the given directory and add the result + * into res. Only files whose names consist only of alphanumeric + * characters, hyphen, and underscore, will be parsed, though files + * ending in ".conf" will also be parsed. + * + * This interface can be used to parse several configuration directories + * into one resulting heim_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param dname a directory name to a Kerberos configuration file + * @param res the returned result, must be free with heim_free_config_files(). + * @return Return an error code or 0, see heim_get_error_message(). + * + * @ingroup heim_support + */ + +heim_error_code +heim_config_parse_dir_multi(heim_context context, + const char *dname, + heim_config_section **res) +{ + struct dirent *entry; + heim_error_code ret; + DIR *d; + + if ((d = opendir(dname)) == NULL) + return errno; + + while ((entry = readdir(d)) != NULL) { + char *p = entry->d_name; + char *path; + int is_valid = 1; + + while (*p) { + /* + * Here be dragons. The call to heim_config_parse_file_multi() + * below expands path tokens. Because of the limitations here + * on file naming, we can't have path tokens in the file name, + * so we're safe. Anyone changing this if condition here should + * be aware. + */ + if (!isalnum((unsigned char)*p) && *p != '_' && *p != '-' && + strcmp(p, ".conf") != 0) { + is_valid = 0; + break; + } + p++; + } + if (!is_valid) + continue; + + if (asprintf(&path, "%s/%s", dname, entry->d_name) == -1 || + path == NULL) { + (void) closedir(d); + return heim_enomem(context); + } + ret = heim_config_parse_file_multi(context, path, res); + free(path); + if (ret == ENOMEM) { + (void) closedir(d); + return ENOMEM; + } + /* Ignore malformed config files so we don't lock out admins, etc... */ + } + (void) closedir(d); + return 0; +} + +static int +is_devnull(struct stat *st) +{ +#ifdef WIN32 + return 0; +#else + struct stat devnullst; + + if (stat("/dev/null", &devnullst) == -1) + return 0; + return st->st_dev == devnullst.st_dev && st->st_ino == devnullst.st_ino; +#endif +} + +HEIMDAL_THREAD_LOCAL int config_include_depth = 0; + +/** + * Parse a configuration file and add the result into res. This + * interface can be used to parse several configuration files into one + * resulting heim_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param fname a file name to a Kerberos configuration file + * @param res the returned result, must be free with heim_free_config_files(). + * @return Return an error code or 0, see heim_get_error_message(). + * + * @ingroup heim_support + */ + +heim_error_code +heim_config_parse_file_multi(heim_context context, + const char *fname, + heim_config_section **res) +{ + const char *str; + char *newfname = NULL; + unsigned lineno = 0; + heim_error_code ret = 0; + struct fileptr f; + struct stat st; + + if (config_include_depth > 5) { + heim_warnx(context, "Maximum config file include depth reached; " + "not including %s", fname); + return 0; + } + config_include_depth++; + + /** + * If the fname starts with "~/" parse configuration file in the + * current users home directory. The behavior can be disabled and + * enabled by calling heim_set_home_dir_access(). + */ + if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) { + if (!heim_context_get_homedir_access(context)) { + heim_set_error_message(context, EPERM, + "Access to home directory not allowed"); + ret = EPERM; + goto out; + } + if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 || + newfname == NULL) { + ret = heim_enomem(context); + goto out; + } + fname = newfname; + } + + if (is_plist_file(fname)) { +#if defined(HAVE_FRAMEWORK_COREFOUNDATION) + ret = parse_plist_config(context, fname, res); + if (ret) { + heim_set_error_message(context, ret, + "Failed to parse plist %s", fname); + goto out; + } +#else + heim_set_error_message(context, ENOENT, + "no support for plist configuration files"); + ret = ENOENT; + goto out; +#endif + } else { + char *exp_fname = NULL; + + /* + * Note that heim_config_parse_dir_multi() doesn't want tokens + * expanded here, but it happens to limit the names of files to + * include such that there can be no tokens to expand. Don't + * add token expansion for tokens using _, say. + */ + ret = heim_expand_path_tokens(context, fname, 1, &exp_fname, NULL); + if (ret) + goto out; + free(newfname); + fname = newfname = exp_fname; + + f.context = context; + f.f = fopen(fname, "r"); + f.s = NULL; + if (f.f == NULL || fstat(fileno(f.f), &st) == -1) { + if (f.f != NULL) + (void) fclose(f.f); + ret = errno; + heim_set_error_message(context, ret, "open or stat %s: %s", + fname, strerror(ret)); + goto out; + } + + if (!S_ISREG(st.st_mode) && !is_devnull(&st)) { + (void) fclose(f.f); + heim_set_error_message(context, EISDIR, "not a regular file %s: %s", + fname, strerror(EISDIR)); + ret = EISDIR; + goto out; + } + + ret = heim_config_parse_debug(&f, res, &lineno, &str); + fclose(f.f); + if (ret) { + if (ret != HEIM_ERR_CONFIG_BADFORMAT) + ret = HEIM_ERR_CONFIG_BADFORMAT; + heim_set_error_message(context, ret, "%s:%u: %s", + fname, lineno, str); + goto out; + } + } + + out: + config_include_depth--; + if (ret == HEIM_ERR_CONFIG_BADFORMAT || (ret && config_include_depth > 0)) { + heim_warn(context, ret, "Ignoring"); + if (config_include_depth > 0) + ret = 0; + } + free(newfname); + return ret; +} + +heim_error_code +heim_config_parse_file(heim_context context, + const char *fname, + heim_config_section **res) +{ + *res = NULL; + return heim_config_parse_file_multi(context, fname, res); +} + +static void +free_binding(heim_context context, heim_config_binding *b) +{ + heim_config_binding *next_b; + + while (b) { + free (b->name); + assert(b->type == heim_config_string || b->type == heim_config_list); + if (b->type == heim_config_string) + free (b->u.string); + else + free_binding (context, b->u.list); + next_b = b->next; + free (b); + b = next_b; + } +} + +/** + * Free configuration file section, the result of + * heim_config_parse_file() and heim_config_parse_file_multi(). + * + * @param context A Kerberos 5 context + * @param s the configuration section to free + * + * @return returns 0 on successes, otherwise an error code, see + * heim_get_error_message() + * + * @ingroup heim_support + */ + +heim_error_code +heim_config_file_free(heim_context context, heim_config_section *s) +{ + free_binding (context, s); + return 0; +} + +#ifndef HEIMDAL_SMALLER + +heim_error_code +heim_config_copy(heim_context context, + heim_config_section *c, + heim_config_section **head) +{ + heim_config_binding *d, *previous = NULL; + + *head = NULL; + + while (c) { + d = calloc(1, sizeof(*d)); + + if (*head == NULL) + *head = d; + + d->name = strdup(c->name); + d->type = c->type; + assert(d->type == heim_config_string || d->type == heim_config_list); + if (d->type == heim_config_string) + d->u.string = strdup(c->u.string); + else + heim_config_copy (context, c->u.list, &d->u.list); + if (previous) + previous->next = d; + + previous = d; + c = c->next; + } + return 0; +} + +#endif /* HEIMDAL_SMALLER */ + +const void * +heim_config_get_next(heim_context context, + const heim_config_section *c, + const heim_config_binding **pointer, + int type, + ...) +{ + const char *ret; + va_list args; + + va_start(args, type); + ret = heim_config_vget_next(context, c, pointer, type, args); + va_end(args); + return ret; +} + +static const void * +vget_next(heim_context context, + const heim_config_binding *b, + const heim_config_binding **pointer, + int type, + const char *name, + va_list args) +{ + const char *p = va_arg(args, const char *); + + while (b != NULL) { + if (strcmp(b->name, name) == 0) { + if (b->type == (unsigned)type && p == NULL) { + *pointer = b; + return b->u.generic; + } else if (b->type == heim_config_list && p != NULL) { + return vget_next(context, b->u.list, pointer, type, p, args); + } + } + b = b->next; + } + return NULL; +} + +const void * +heim_config_vget_next(heim_context context, + const heim_config_section *c, + const heim_config_binding **pointer, + int type, + va_list args) +{ + const heim_config_binding *b; + const char *p; + + if (c == NULL) + return NULL; + + if (*pointer == NULL) { + /* first time here, walk down the tree looking for the right + section */ + p = va_arg(args, const char *); + if (p == NULL) + return NULL; + return vget_next(context, c, pointer, type, p, args); + } + + /* we were called again, so just look for more entries with the + same name and type */ + for (b = (*pointer)->next; b != NULL; b = b->next) { + if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) { + *pointer = b; + return b->u.generic; + } + } + return NULL; +} + +const void * +heim_config_get(heim_context context, + const heim_config_section *c, + int type, + ...) +{ + const void *ret; + va_list args; + + va_start(args, type); + ret = heim_config_vget(context, c, type, args); + va_end(args); + return ret; +} + + +const void * +heim_config_vget(heim_context context, + const heim_config_section *c, + int type, + va_list args) +{ + const heim_config_binding *foo = NULL; + + return heim_config_vget_next(context, c, &foo, type, args); +} + +/** + * Get a list of configuration binding list for more processing + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return NULL if configuration list is not found, a list otherwise + * + * @ingroup heim_support + */ + +const heim_config_binding * +heim_config_get_list(heim_context context, + const heim_config_section *c, + ...) +{ + const heim_config_binding *ret; + va_list args; + + va_start(args, c); + ret = heim_config_vget_list(context, c, args); + va_end(args); + return ret; +} + +/** + * Get a list of configuration binding list for more processing + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return NULL if configuration list is not found, a list otherwise + * + * @ingroup heim_support + */ + +const heim_config_binding * +heim_config_vget_list(heim_context context, + const heim_config_section *c, + va_list args) +{ + return heim_config_vget(context, c, heim_config_list, args); +} + +/** + * Returns a "const char *" to a string in the configuration database. + * The string may not be valid after a reload of the configuration + * database so a caller should make a local copy if it needs to keep + * the string. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return NULL if configuration string not found, a string otherwise + * + * @ingroup heim_support + */ + +const char * +heim_config_get_string(heim_context context, + const heim_config_section *c, + ...) +{ + const char *ret; + va_list args; + + va_start(args, c); + ret = heim_config_vget_string(context, c, args); + va_end(args); + return ret; +} + +/** + * Like heim_config_get_string(), but uses a va_list instead of ... + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return NULL if configuration string not found, a string otherwise + * + * @ingroup heim_support + */ + +const char * +heim_config_vget_string(heim_context context, + const heim_config_section *c, + va_list args) +{ + return heim_config_vget(context, c, heim_config_string, args); +} + +/** + * Like heim_config_vget_string(), but instead of returning NULL, + * instead return a default value. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return a configuration string + * + * @ingroup heim_support + */ + +const char * +heim_config_vget_string_default(heim_context context, + const heim_config_section *c, + const char *def_value, + va_list args) +{ + const char *ret; + + ret = heim_config_vget_string(context, c, args); + if (ret == NULL) + ret = def_value; + return ret; +} + +/** + * Like heim_config_get_string(), but instead of returning NULL, + * instead return a default value. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return a configuration string + * + * @ingroup heim_support + */ + +const char * +heim_config_get_string_default(heim_context context, + const heim_config_section *c, + const char *def_value, + ...) +{ + const char *ret; + va_list args; + + va_start(args, def_value); + ret = heim_config_vget_string_default (context, c, def_value, args); + va_end(args); + return ret; +} + +static char * +next_component_string(char * begin, const char * delims, char **state) +{ + char * end; + + if (begin == NULL) + begin = *state; + + if (*begin == '\0') + return NULL; + + end = begin; + while (*end == '"') { + char * t = strchr(end + 1, '"'); + + if (t) + end = ++t; + else + end += strlen(end); + } + + if (*end != '\0') { + size_t pos; + + pos = strcspn(end, delims); + end = end + pos; + } + + if (*end != '\0') { + *end = '\0'; + *state = end + 1; + if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) { + begin++; *(end - 1) = '\0'; + } + return begin; + } + + *state = end; + if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) { + begin++; *(end - 1) = '\0'; + } + return begin; +} + +/** + * Get a list of configuration strings, free the result with + * heim_config_free_strings(). + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +char ** +heim_config_vget_strings(heim_context context, + const heim_config_section *c, + va_list args) +{ + char **strings = NULL; + size_t nstr = 0; + const heim_config_binding *b = NULL; + const char *p; + + while((p = heim_config_vget_next(context, c, &b, + heim_config_string, args))) { + char *tmp = strdup(p); + char *pos = NULL; + char *s; + if(tmp == NULL) + goto cleanup; + s = next_component_string(tmp, " \t", &pos); + while(s){ + char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings)); + if(tmp2 == NULL) { + free(tmp); + goto cleanup; + } + strings = tmp2; + strings[nstr] = strdup(s); + nstr++; + if(strings[nstr-1] == NULL) { + free(tmp); + goto cleanup; + } + s = next_component_string(NULL, " \t", &pos); + } + free(tmp); + } + if(nstr){ + char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings)); + if(tmp == NULL) + goto cleanup; + strings = tmp; + strings[nstr] = NULL; + } + return strings; +cleanup: + while(nstr--) + free(strings[nstr]); + free(strings); + return NULL; + +} + +/** + * Get a list of configuration strings, free the result with + * heim_config_free_strings(). + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +char ** +heim_config_get_strings(heim_context context, + const heim_config_section *c, + ...) +{ + va_list ap; + char **ret; + va_start(ap, c); + ret = heim_config_vget_strings(context, c, ap); + va_end(ap); + return ret; +} + +/** + * Free the resulting strings from heim_config-get_strings() and + * heim_config_vget_strings(). + * + * @param strings strings to free + * + * @ingroup heim_support + */ + +void +heim_config_free_strings(char **strings) +{ + char **s = strings; + + while (s && *s) { + free(*s); + s++; + } + free(strings); +} + +/** + * Like heim_config_get_bool_default() but with a va_list list of + * configuration selection. + * + * Configuration value to a boolean value, where yes/true and any + * non-zero number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +int +heim_config_vget_bool_default(heim_context context, + const heim_config_section *c, + int def_value, + va_list args) +{ + const char *str; + str = heim_config_vget_string(context, c, args); + if (str == NULL) + return def_value; + return !!(strcasecmp(str, "yes") == 0 || + strcasecmp(str, "true") == 0 || + atoi(str)); +} + +/** + * heim_config_get_bool() will convert the configuration + * option value to a boolean value, where yes/true and any non-zero + * number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +int +heim_config_vget_bool(heim_context context, + const heim_config_section *c, + va_list args) +{ + return heim_config_vget_bool_default(context, c, 0, args); +} + +/** + * heim_config_get_bool_default() will convert the configuration + * option value to a boolean value, where yes/true and any non-zero + * number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +int +heim_config_get_bool_default(heim_context context, + const heim_config_section *c, + int def_value, + ...) +{ + va_list ap; + int ret; + + va_start(ap, def_value); + ret = heim_config_vget_bool_default(context, c, def_value, ap); + va_end(ap); + return ret; +} + +/** + * Like heim_config_get_bool() but with a va_list list of + * configuration selection. + * + * Configuration value to a boolean value, where yes/true and any + * non-zero number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup heim_support + */ + +int +heim_config_get_bool(heim_context context, + const heim_config_section *c, + ...) +{ + va_list ap; + int ret; + va_start(ap, c); + ret = heim_config_vget_bool (context, c, ap); + va_end(ap); + return ret; +} + +/** + * Get the time from the configuration file using a relative time. + * + * Like heim_config_get_time_default() but with a va_list list of + * configuration selection. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return parsed the time (or def_value on parse error) + * + * @ingroup heim_support + */ + +time_t +heim_config_vget_time_default(heim_context context, + const heim_config_section *c, + int def_value, + va_list args) +{ + const char *str; + time_t t = -1; + + if ((str = heim_config_vget_string(context, c, args))) + t = parse_time(str, "s"); + return t != -1 ? t : def_value; +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return parsed the time or -1 on error + * + * @ingroup heim_support + */ + +time_t +heim_config_vget_time(heim_context context, + const heim_config_section *c, + va_list args) +{ + return heim_config_vget_time_default(context, c, -1, args); +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return parsed the time (or def_value on parse error) + * + * @ingroup heim_support + */ + +time_t +heim_config_get_time_default(heim_context context, + const heim_config_section *c, + int def_value, + ...) +{ + va_list ap; + time_t ret; + + va_start(ap, def_value); + ret = heim_config_vget_time_default(context, c, def_value, ap); + va_end(ap); + return ret; +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return parsed the time or -1 on error + * + * @ingroup heim_support + */ + +time_t +heim_config_get_time(heim_context context, + const heim_config_section *c, + ...) +{ + va_list ap; + int ret; + va_start(ap, c); + ret = heim_config_vget_time(context, c, ap); + va_end(ap); + return ret; +} + + +int +heim_config_vget_int_default(heim_context context, + const heim_config_section *c, + int def_value, + va_list args) +{ + const char *str; + str = heim_config_vget_string (context, c, args); + if(str == NULL) + return def_value; + else { + char *endptr; + long l; + l = strtol(str, &endptr, 0); + if (endptr == str) + return def_value; + else + return l; + } +} + +int +heim_config_vget_int(heim_context context, + const heim_config_section *c, + va_list args) +{ + return heim_config_vget_int_default(context, c, -1, args); +} + +int +heim_config_get_int_default(heim_context context, + const heim_config_section *c, + int def_value, + ...) +{ + va_list ap; + int ret; + + va_start(ap, def_value); + ret = heim_config_vget_int_default(context, c, def_value, ap); + va_end(ap); + return ret; +} + +int +heim_config_get_int(heim_context context, + const heim_config_section *c, + ...) +{ + va_list ap; + int ret; + va_start(ap, c); + ret = heim_config_vget_int (context, c, ap); + va_end(ap); + return ret; +} + +#ifndef HEIMDAL_SMALLER +heim_error_code +heim_config_parse_string_multi(heim_context context, + const char *string, + heim_config_section **res) +{ + const char *str; + unsigned lineno = 0; + heim_error_code ret; + struct fileptr f; + + f.context = context; + f.f = NULL; + f.s = string; + + ret = heim_config_parse_debug(&f, res, &lineno, &str); + if (ret) { + if (ret != HEIM_ERR_CONFIG_BADFORMAT) { + ret = HEIM_ERR_CONFIG_BADFORMAT; + heim_set_error_message(context, ret, "%s:%u: %s", + "", lineno, str); + } + return ret; + } + return 0; +} +#endif diff --git a/third_party/heimdal/lib/base/config_reg.c b/third_party/heimdal/lib/base/config_reg.c new file mode 100644 index 0000000..cb24e50 --- /dev/null +++ b/third_party/heimdal/lib/base/config_reg.c @@ -0,0 +1,658 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include "baselocl.h" + +#ifndef _WIN32 +#error config_reg.c is only for Windows +#endif + +#include + +#ifndef MAX_DWORD +#define MAX_DWORD 0xFFFFFFFF +#endif + +/** + * Store a string as a registry value of the specified type + * + * The following registry types are handled: + * + * - REG_DWORD: The string is converted to a number. + * + * - REG_SZ: The string is stored as is. + * + * - REG_EXPAND_SZ: The string is stored as is. + * + * - REG_MULTI_SZ: + * + * . If a separator is specified, the input string is broken + * up into multiple strings and stored as a multi-sz. + * + * . If no separator is provided, the input string is stored + * as a multi-sz. + * + * - REG_NONE: + * + * . If the string is all numeric, it will be stored as a + * REG_DWORD. + * + * . Otherwise, the string is stored as a REG_SZ. + * + * Other types are rejected. + * + * If cb_data is MAX_DWORD, the string pointed to by data must be nul-terminated + * otherwise a buffer overrun will occur. + * + * @param [in]valuename Name of the registry value to be modified or created + * @param [in]type Type of the value. REG_NONE if unknown + * @param [in]data The input string to be stored in the registry. + * @param [in]cb_data Size of the input string in bytes. MAX_DWORD if unknown. + * @param [in]separator Separator character for parsing strings. + * + * @retval 0 if success or non-zero on error. + * If non-zero is returned, an error message has been set using + * heim_set_error_message(). + * + */ +int +heim_store_string_to_reg_value(heim_context context, + HKEY key, const char *valuename, + DWORD type, const char *data, DWORD cb_data, + const char *separator) +{ + LONG rcode; + int dwData; + BYTE static_buffer[16384]; + + if (data == NULL) + { + if (context) + heim_set_error_message(context, 0, + "'data' must not be NULL"); + return -1; + } + + if (cb_data == MAX_DWORD) + { + cb_data = (DWORD)strlen(data) + 1; + } + else if ((type == REG_MULTI_SZ && cb_data >= sizeof(static_buffer) - 1) || + cb_data >= sizeof(static_buffer)) + { + if (context) + heim_set_error_message(context, 0, "cb_data too big"); + return -1; + } + else if (data[cb_data-1] != '\0') + { + memcpy(static_buffer, data, cb_data); + static_buffer[cb_data++] = '\0'; + if (type == REG_MULTI_SZ) + static_buffer[cb_data++] = '\0'; + data = static_buffer; + } + + if (type == REG_NONE) + { + /* + * If input is all numeric, convert to DWORD and save as REG_DWORD. + * Otherwise, store as REG_SZ. + */ + if ( StrToIntExA( data, STIF_SUPPORT_HEX, &dwData) ) + { + type = REG_DWORD; + } else { + type = REG_SZ; + } + } + + switch (type) { + case REG_SZ: + case REG_EXPAND_SZ: + rcode = RegSetValueEx(key, valuename, 0, type, data, cb_data); + if (rcode) + { + if (context) + heim_set_error_message(context, 0, + "Unexpected error when setting registry value %s gle 0x%x", + valuename, + GetLastError()); + return -1; + } + break; + case REG_MULTI_SZ: + if (separator && *separator) + { + char *cp; + + if (data != static_buffer) + static_buffer[cb_data++] = '\0'; + + for ( cp = static_buffer; cp < static_buffer+cb_data; cp++) + { + if (*cp == *separator) + *cp = '\0'; + } + + rcode = RegSetValueEx(key, valuename, 0, type, data, cb_data); + if (rcode) + { + if (context) + heim_set_error_message(context, 0, + "Unexpected error when setting registry value %s gle 0x%x", + valuename, + GetLastError()); + return -1; + } + } + break; + case REG_DWORD: + if ( !StrToIntExA( data, STIF_SUPPORT_HEX, &dwData) ) + { + if (context) + heim_set_error_message(context, 0, + "Unexpected error when parsing %s as number gle 0x%x", + data, + GetLastError()); + } + + rcode = RegSetValueEx(key, valuename, 0, type, (BYTE *)&dwData, sizeof(DWORD)); + if (rcode) + { + if (context) + heim_set_error_message(context, 0, + "Unexpected error when setting registry value %s gle 0x%x", + valuename, + GetLastError()); + return -1; + } + break; + default: + return -1; + } + + return 0; +} + +/** + * Parse a registry value as a string + * + * @see heim_parse_reg_value_as_multi_string() + */ +char * +heim_parse_reg_value_as_string(heim_context context, + HKEY key, const char * valuename, + DWORD type, DWORD cb_data) +{ + return heim_parse_reg_value_as_multi_string(context, key, valuename, + type, cb_data, " "); +} + +/** + * Parse a registry value as a multi string + * + * The following registry value types are handled: + * + * - REG_DWORD: The decimal string representation is used as the + * value. + * + * - REG_SZ: The string is used as-is. + * + * - REG_EXPAND_SZ: Environment variables in the string are expanded + * and the result is used as the value. + * + * - REG_MULTI_SZ: The list of strings is concatenated using the + * separator. No quoting is performed. + * + * Any other value type is rejected. + * + * @param [in]valuename Name of the registry value to be queried + * @param [in]type Type of the value. REG_NONE if unknown + * @param [in]cbdata Size of value. 0 if unknown. + * @param [in]separator Separator character for concatenating strings. + * + * @a type and @a cbdata are only considered valid if both are + * specified. + * + * @retval The registry value string, or NULL if there was an error. + * If NULL is returned, an error message has been set using + * heim_set_error_message(). + */ +char * +heim_parse_reg_value_as_multi_string(heim_context context, + HKEY key, const char * valuename, + DWORD type, DWORD cb_data, char *separator) +{ + LONG rcode = ERROR_MORE_DATA; + + BYTE static_buffer[16384]; + BYTE *pbuffer = &static_buffer[0]; + DWORD cb_alloc = sizeof(static_buffer); + char *ret_string = NULL; + + /* If we know a type and cb_data from a previous call to + * RegEnumValue(), we use it. Otherwise we use the + * static_buffer[] and query directly. We do this to minimize the + * number of queries. */ + + if (type == REG_NONE || cb_data == 0) { + + pbuffer = &static_buffer[0]; + cb_alloc = cb_data = sizeof(static_buffer); + rcode = RegQueryValueExA(key, valuename, NULL, &type, pbuffer, &cb_data); + + if (rcode == ERROR_SUCCESS && + + ((type != REG_SZ && + type != REG_EXPAND_SZ) || cb_data + 1 <= sizeof(static_buffer)) && + + (type != REG_MULTI_SZ || cb_data + 2 <= sizeof(static_buffer))) + goto have_data; + + if (rcode != ERROR_MORE_DATA && rcode != ERROR_SUCCESS) + return NULL; + } + + /* Either we don't have the data or we aren't sure of the size + * (due to potentially missing terminating NULs). */ + + switch (type) { + case REG_DWORD: + if (cb_data != sizeof(DWORD)) { + if (context) + heim_set_error_message(context, 0, + "Unexpected size while reading registry value %s", + valuename); + return NULL; + } + break; + + case REG_SZ: + case REG_EXPAND_SZ: + + if (rcode == ERROR_SUCCESS && cb_data > 0 && pbuffer[cb_data - 1] == '\0') + goto have_data; + + cb_data += sizeof(char); /* Accout for potential missing NUL + * terminator. */ + break; + + case REG_MULTI_SZ: + + if (rcode == ERROR_SUCCESS && cb_data > 0 && pbuffer[cb_data - 1] == '\0' && + (cb_data == 1 || pbuffer[cb_data - 2] == '\0')) + goto have_data; + + cb_data += sizeof(char) * 2; /* Potential missing double NUL + * terminator. */ + break; + + default: + if (context) + heim_set_error_message(context, 0, + "Unexpected type while reading registry value %s", + valuename); + return NULL; + } + + if (cb_data <= sizeof(static_buffer)) + pbuffer = &static_buffer[0]; + else { + pbuffer = malloc(cb_data); + if (pbuffer == NULL) + return NULL; + } + + cb_alloc = cb_data; + rcode = RegQueryValueExA(key, valuename, NULL, NULL, pbuffer, &cb_data); + + if (rcode != ERROR_SUCCESS) { + + /* This can potentially be from a race condition. I.e. some + * other process or thread went and modified the registry + * value between the time we queried its size and queried for + * its value. Ideally we would retry the query in a loop. */ + + if (context) + heim_set_error_message(context, 0, + "Unexpected error while reading registry value %s", + valuename); + goto done; + } + + if (cb_data > cb_alloc || cb_data == 0) { + if (context) + heim_set_error_message(context, 0, + "Unexpected size while reading registry value %s", + valuename); + goto done; + } + +have_data: + switch (type) { + case REG_DWORD: + asprintf(&ret_string, "%d", *((DWORD *) pbuffer)); + break; + + case REG_SZ: + { + char * str = (char *) pbuffer; + + if (str[cb_data - 1] != '\0') { + if (cb_data < cb_alloc) + str[cb_data] = '\0'; + else + break; + } + + if (pbuffer != static_buffer) { + ret_string = (char *) pbuffer; + pbuffer = NULL; + } else { + ret_string = strdup((char *) pbuffer); + } + } + break; + + case REG_EXPAND_SZ: + { + char *str = (char *) pbuffer; + char expsz[32768]; /* Size of output buffer for + * ExpandEnvironmentStrings() is + * limited to 32K. */ + + if (str[cb_data - 1] != '\0') { + if (cb_data < cb_alloc) + str[cb_data] = '\0'; + else + break; + } + + if (ExpandEnvironmentStrings(str, expsz, sizeof(expsz)/sizeof(char)) != 0) { + ret_string = strdup(expsz); + } else { + if (context) + heim_set_error_message(context, 0, + "Overflow while expanding environment strings " + "for registry value %s", valuename); + } + } + break; + + case REG_MULTI_SZ: + { + char * str = (char *) pbuffer; + char * iter; + + str[cb_alloc - 1] = '\0'; + str[cb_alloc - 2] = '\0'; + + for (iter = str; *iter;) { + size_t len = strlen(iter); + + iter += len; + if (iter[1] != '\0') + *iter++ = *separator; + else + break; + } + + if (pbuffer != static_buffer) { + ret_string = str; + pbuffer = NULL; + } else { + ret_string = strdup(str); + } + } + break; + + default: + if (context) + heim_set_error_message(context, 0, + "Unexpected type while reading registry value %s", + valuename); + } + +done: + if (pbuffer != static_buffer && pbuffer != NULL) + free(pbuffer); + + return ret_string; +} + +/** + * Parse a registry value as a configuration value + * + * @see parse_reg_value_as_string() + */ +static heim_error_code +parse_reg_value(heim_context context, + HKEY key, const char * valuename, + DWORD type, DWORD cbdata, heim_config_section ** parent) +{ + char *reg_string = NULL; + heim_config_section *value; + heim_error_code code = 0; + + reg_string = heim_parse_reg_value_as_string(context, key, valuename, type, cbdata); + + if (reg_string == NULL) + return HEIM_ERR_CONFIG_BADFORMAT; + + value = heim_config_get_entry(parent, valuename, heim_config_string); + if (value == NULL) { + code = ENOMEM; + goto done; + } + + if (value->u.string != NULL) + free(value->u.string); + + value->u.string = reg_string; + reg_string = NULL; + +done: + if (reg_string != NULL) + free(reg_string); + + return code; +} + +static heim_error_code +parse_reg_values(heim_context context, + HKEY key, + heim_config_section ** parent) +{ + DWORD index; + LONG rcode; + + for (index = 0; ; index ++) { + char name[16385]; + DWORD cch = sizeof(name)/sizeof(name[0]); + DWORD type; + DWORD cbdata = 0; + heim_error_code code; + + rcode = RegEnumValue(key, index, name, &cch, NULL, + &type, NULL, &cbdata); + if (rcode != ERROR_SUCCESS) + break; + + if (cbdata == 0) + continue; + + code = parse_reg_value(context, key, name, type, cbdata, parent); + if (code != 0) + return code; + } + + return 0; +} + +static heim_error_code +parse_reg_subkeys(heim_context context, + HKEY key, + heim_config_section ** parent) +{ + DWORD index; + LONG rcode; + + for (index = 0; ; index ++) { + HKEY subkey = NULL; + char name[256]; + DWORD cch = sizeof(name)/sizeof(name[0]); + heim_config_section *section = NULL; + heim_error_code code; + + rcode = RegEnumKeyEx(key, index, name, &cch, NULL, NULL, NULL, NULL); + if (rcode != ERROR_SUCCESS) + break; + + rcode = RegOpenKeyEx(key, name, 0, KEY_READ, &subkey); + if (rcode != ERROR_SUCCESS) + continue; + + section = heim_config_get_entry(parent, name, heim_config_list); + if (section == NULL) { + RegCloseKey(subkey); + return ENOMEM; + } + + code = parse_reg_values(context, subkey, §ion->u.list); + if (code) { + RegCloseKey(subkey); + return code; + } + + code = parse_reg_subkeys(context, subkey, §ion->u.list); + if (code) { + RegCloseKey(subkey); + return code; + } + + RegCloseKey(subkey); + } + + return 0; +} + +static heim_error_code +parse_reg_root(heim_context context, + HKEY key, + heim_config_section ** parent) +{ + heim_config_section *libdefaults = NULL; + heim_error_code code = 0; + + libdefaults = heim_config_get_entry(parent, "libdefaults", heim_config_list); + if (libdefaults == NULL) + return heim_enomem(context); + + code = parse_reg_values(context, key, &libdefaults->u.list); + if (code) + return code; + + return parse_reg_subkeys(context, key, parent); +} + +static heim_error_code +load_config_from_regpath(heim_context context, + HKEY hk_root, + const char* key_path, + heim_config_section ** res) +{ + HKEY key = NULL; + LONG rcode; + heim_error_code code = 0; + + rcode = RegOpenKeyEx(hk_root, key_path, 0, KEY_READ, &key); + if (rcode == ERROR_SUCCESS) { + code = parse_reg_root(context, key, res); + RegCloseKey(key); + key = NULL; + } + + return code; +} + +/** + * Load configuration from registry + * + * The registry keys 'HKCU\Software\Heimdal' and + * 'HKLM\Software\Heimdal' are treated as krb5.conf files. Each + * registry key corresponds to a configuration section (or bound list) + * and each value in a registry key is treated as a bound value. The + * set of values that are directly under the Heimdal key are treated + * as if they were defined in the [libdefaults] section. + * + * @see parse_reg_value() for details about how each type of value is handled. + */ +heim_error_code +heim_load_config_from_registry(heim_context context, + const char *path0, + const char *path1, + heim_config_section **res) +{ + heim_error_code code; + + if (!path0 && !path1) + return EINVAL; + + if (path0) { + code = load_config_from_regpath(context, HKEY_LOCAL_MACHINE, + path0, res); + if (code) + return code; + } + + if (path1) { + code = load_config_from_regpath(context, HKEY_LOCAL_MACHINE, + path1, res); + if (code) + return code; + } + + if (path0) { + code = load_config_from_regpath(context, HKEY_CURRENT_USER, + path0, res); + if (code) + return code; + } + + if (path0) { + code = load_config_from_regpath(context, HKEY_CURRENT_USER, + path1, res); + if (code) + return code; + } + return 0; +} diff --git a/third_party/heimdal/lib/base/context.c b/third_party/heimdal/lib/base/context.c new file mode 100644 index 0000000..f22ce94 --- /dev/null +++ b/third_party/heimdal/lib/base/context.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +#undef __attribute__ +#define __attribute__(X) + +heim_context +heim_context_init(void) +{ + heim_context context; + + if ((context = calloc(1, sizeof(*context))) == NULL) + return NULL; + + context->homedir_access = !issuid(); + context->log_utc = 1; + context->error_string = NULL; + context->debug_dest = NULL; + context->warn_dest = NULL; + context->log_dest = NULL; + context->time_fmt = NULL; + context->et_list = NULL; + return context; +} + +void +heim_context_free(heim_context *contextp) +{ + heim_context context = *contextp; + + *contextp = NULL; + if (!context) + return; + heim_closelog(context, context->debug_dest); + heim_closelog(context, context->warn_dest); + heim_closelog(context, context->log_dest); + free_error_table(context->et_list); + free(context->time_fmt); + free(context->error_string); + free(context); +} + +heim_error_code +heim_add_et_list(heim_context context, void (*func)(struct et_list **)) +{ + (*func)(&context->et_list); + return 0; +} + +heim_error_code +heim_context_set_time_fmt(heim_context context, const char *fmt) +{ + char *s; + + if (fmt == NULL) { + free(context->time_fmt); + return 0; + } + if ((s = strdup(fmt)) == NULL) + return heim_enomem(context); + free(context->time_fmt); + context->time_fmt = s; + return 0; +} + +const char * +heim_context_get_time_fmt(heim_context context) +{ + return context->time_fmt ? context->time_fmt : "%Y-%m-%dT%H:%M:%S"; +} + +unsigned int +heim_context_set_log_utc(heim_context context, unsigned int log_utc) +{ + unsigned int old = context->log_utc; + + context->log_utc = log_utc ? 1 : 0; + return old; +} + +int +heim_context_get_log_utc(heim_context context) +{ + return context->log_utc; +} + +unsigned int +heim_context_set_homedir_access(heim_context context, unsigned int homedir_access) +{ + unsigned int old = context->homedir_access; + + context->homedir_access = homedir_access ? 1 : 0; + return old; +} + +unsigned int +heim_context_get_homedir_access(heim_context context) +{ + return context->homedir_access; +} + +heim_error_code +heim_enomem(heim_context context) +{ + heim_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; +} + +heim_log_facility * +heim_get_log_dest(heim_context context) +{ + return context->log_dest; +} + +heim_log_facility * +heim_get_warn_dest(heim_context context) +{ + return context->warn_dest; +} + +heim_log_facility * +heim_get_debug_dest(heim_context context) +{ + return context->debug_dest; +} + +heim_error_code +heim_set_log_dest(heim_context context, heim_log_facility *fac) +{ + context->log_dest = heim_log_ref(fac); + return 0; +} + +heim_error_code +heim_set_warn_dest(heim_context context, heim_log_facility *fac) +{ + context->warn_dest = fac; + return 0; +} + +heim_error_code +heim_set_debug_dest(heim_context context, heim_log_facility *fac) +{ + context->debug_dest = fac; + return 0; +} + +#ifndef PATH_SEP +# define PATH_SEP ":" +#endif + +static heim_error_code +add_file(char ***pfilenames, int *len, char *file) +{ + char **pp = *pfilenames; + int i; + + for(i = 0; i < *len; i++) { + if(strcmp(pp[i], file) == 0) { + free(file); + return 0; + } + } + + pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp)); + if (pp == NULL) { + free(file); + return ENOMEM; + } + + pp[*len] = file; + pp[*len + 1] = NULL; + *pfilenames = pp; + *len += 1; + return 0; +} + +#ifdef WIN32 +static char * +get_default_config_config_files_from_registry(const char *envvar) +{ + static const char *KeyName = "Software\\Heimdal"; /* XXX #define this */ + const char *ValueName; + char *config_file = NULL; + LONG rcode; + HKEY key; + + if (stricmp(envvar, "KRB5_CONFIG") == 0) + ValueName = "config"; + else + ValueName = envvar; + + rcode = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName, 0, KEY_READ, &key); + if (rcode == ERROR_SUCCESS) { + config_file = heim_parse_reg_value_as_multi_string(NULL, key, ValueName, + REG_NONE, 0, PATH_SEP); + RegCloseKey(key); + } + + if (config_file) + return config_file; + + rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &key); + if (rcode == ERROR_SUCCESS) { + config_file = heim_parse_reg_value_as_multi_string(NULL, key, ValueName, + REG_NONE, 0, PATH_SEP); + RegCloseKey(key); + } + + return config_file; +} +#endif + +heim_error_code +heim_prepend_config_files(const char *filelist, + char **pq, + char ***ret_pp) +{ + heim_error_code ret; + const char *p, *q; + char **pp; + int len; + char *fn; + + pp = NULL; + + len = 0; + p = filelist; + while(1) { + ssize_t l; + q = p; + l = strsep_copy(&q, PATH_SEP, NULL, 0); + if(l == -1) + break; + fn = malloc(l + 1); + if(fn == NULL) { + heim_free_config_files(pp); + return ENOMEM; + } + (void) strsep_copy(&p, PATH_SEP, fn, l + 1); + ret = add_file(&pp, &len, fn); + if (ret) { + heim_free_config_files(pp); + return ret; + } + } + + if (pq != NULL) { + int i; + + for (i = 0; pq[i] != NULL; i++) { + fn = strdup(pq[i]); + if (fn == NULL) { + heim_free_config_files(pp); + return ENOMEM; + } + ret = add_file(&pp, &len, fn); + if (ret) { + heim_free_config_files(pp); + return ret; + } + } + } + + *ret_pp = pp; + return 0; +} + +heim_error_code +heim_prepend_config_files_default(const char *prepend, + const char *def, + const char *envvar, + char ***pfilenames) +{ + heim_error_code ret; + char **defpp, **pp = NULL; + + ret = heim_get_default_config_files(def, envvar, &defpp); + if (ret) + return ret; + + ret = heim_prepend_config_files(prepend, defpp, &pp); + heim_free_config_files(defpp); + if (ret) { + return ret; + } + *pfilenames = pp; + return 0; +} + +heim_error_code +heim_get_default_config_files(const char *def, + const char *envvar, + char ***pfilenames) +{ + const char *files = NULL; + + files = secure_getenv(envvar); + +#ifdef _WIN32 + if (files == NULL) { + char * reg_files; + reg_files = get_default_config_config_files_from_registry(envvar); + if (reg_files != NULL) { + heim_error_code code; + + code = heim_prepend_config_files(reg_files, NULL, pfilenames); + free(reg_files); + + return code; + } + } +#endif + + if (files == NULL) + files = def; + return heim_prepend_config_files(files, NULL, pfilenames); +} + +#ifdef _WIN32 +#define REGPATH_KERBEROS "SOFTWARE\\Kerberos" +#define REGPATH_HEIMDAL "SOFTWARE\\Heimdal" +#endif + +heim_error_code +heim_set_config_files(heim_context context, char **filenames, + heim_config_binding **res) +{ + heim_error_code ret = 0; + + *res = NULL; + while (filenames != NULL && *filenames != NULL && **filenames != '\0') { + ret = heim_config_parse_file_multi(context, *filenames, res); + if (ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM + && ret != HEIM_ERR_CONFIG_BADFORMAT) { + heim_config_file_free(context, *res); + *res = NULL; + return ret; + } + filenames++; + } + +#ifdef _WIN32 + /* + * We always ignored errors from loading from the registry, so we still do. + */ + heim_load_config_from_registry(context, REGPATH_KERBEROS, + REGPATH_HEIMDAL, res); + +#endif + return 0; +} + +void +heim_free_config_files(char **filenames) +{ + char **p; + + for (p = filenames; p && *p != NULL; p++) + free(*p); + free(filenames); +} diff --git a/third_party/heimdal/lib/base/data.c b/third_party/heimdal/lib/base/data.c new file mode 100644 index 0000000..cefdde0 --- /dev/null +++ b/third_party/heimdal/lib/base/data.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include + +static void HEIM_CALLCONV +data_dealloc(void *ptr) +{ + heim_data_t d = ptr; + heim_octet_string *os = (heim_octet_string *)d; + heim_data_free_f_t *deallocp; + heim_data_free_f_t dealloc; + + if (os->data == NULL) + return; + + /* Possible string ref */ + deallocp = _heim_get_isaextra(os, 0); + dealloc = *deallocp; + if (dealloc != NULL) + dealloc(os->data); +} + +static int +data_cmp(void *a, void *b) +{ + heim_octet_string *osa = a, *osb = b; + if (osa->length != osb->length) + return osa->length - osb->length; + return memcmp(osa->data, osb->data, osa->length); +} + +static uintptr_t +data_hash(void *ptr) +{ + heim_octet_string *os = ptr; + const unsigned char *s = os->data; + + if (os->length < 4) + return os->length; + + return ((unsigned long)s[os->length - 1] << 24) + | (s[os->length - 2] << 16) | (s[1] << 8) | s[0]; +} + +struct heim_type_data _heim_data_object = { + HEIM_TID_DATA, + "data-object", + NULL, + data_dealloc, + NULL, + data_cmp, + data_hash, + NULL +}; + +/** + * Create a data object + * + * @param string the string to create, must be an utf8 string + * + * @return string object + */ + +heim_data_t +heim_data_create(const void *data, size_t length) +{ + heim_octet_string *os; + + os = _heim_alloc_object(&_heim_data_object, sizeof(*os) + length); + if (os) { + os->data = (uint8_t *)os + sizeof(*os); + os->length = length; + memcpy(os->data, data, length); + } + return (heim_data_t)os; +} + +heim_data_t +heim_data_ref_create(const void *data, size_t length, + heim_data_free_f_t dealloc) +{ + heim_octet_string *os; + heim_data_free_f_t *deallocp; + + os = _heim_alloc_object(&_heim_data_object, sizeof(*os) + length); + if (os) { + os->data = (void *)data; + os->length = length; + deallocp = _heim_get_isaextra(os, 0); + *deallocp = dealloc; + } + return (heim_data_t)os; +} + + +/** + * Return the type ID of data objects + * + * @return type id of data objects + */ + +heim_tid_t +heim_data_get_type_id(void) +{ + return HEIM_TID_DATA; +} + +/** + * Get the data value of the content. + * + * @param data the data object to get the value from + * + * @return a heim_octet_string + */ + +const heim_octet_string * +heim_data_get_data(heim_data_t data) +{ + /* Note that this works for data and data_ref objects */ + return (const heim_octet_string *)data; +} + +const void * +heim_data_get_ptr(heim_data_t data) +{ + /* Note that this works for data and data_ref objects */ + return ((const heim_octet_string *)data)->data; +} + +size_t heim_data_get_length(heim_data_t data) +{ + /* Note that this works for data and data_ref objects */ + return ((const heim_octet_string *)data)->length; +} diff --git a/third_party/heimdal/lib/base/db.c b/third_party/heimdal/lib/base/db.c new file mode 100644 index 0000000..e6f6af4 --- /dev/null +++ b/third_party/heimdal/lib/base/db.c @@ -0,0 +1,1724 @@ +/* + * Copyright (c) 2011, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is a pluggable simple DB abstraction, with a simple get/set/ + * delete key/value pair interface. + * + * Plugins may provide any of the following optional features: + * + * - tables -- multiple attribute/value tables in one DB + * - locking + * - transactions (i.e., allow any heim_object_t as key or value) + * - transcoding of values + * + * Stackable plugins that provide missing optional features are + * possible. + * + * Any plugin that provides locking will also provide transactions, but + * those transactions will not be atomic in the face of failures (a + * memory-based rollback log is used). + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "baselocl.h" +#include + +#define HEIM_ENOMEM(ep) \ + (((ep) && !*(ep)) ? \ + heim_error_get_code((*(ep) = heim_error_create_enomem())) : ENOMEM) + +#define HEIM_ERROR_HELPER(ep, ec, args) \ + (((ep) && !*(ep)) ? \ + heim_error_get_code((*(ep) = heim_error_create args)) : (ec)) + +#define HEIM_ERROR(ep, ec, args) \ + (ec == ENOMEM) ? HEIM_ENOMEM(ep) : HEIM_ERROR_HELPER(ep, ec, args); + +static heim_string_t to_base64(heim_data_t, heim_error_t *); +static heim_data_t from_base64(heim_string_t, heim_error_t *); + +static int open_file(const char *, int , int, int *, heim_error_t *); +static int read_json(const char *, heim_object_t *, heim_error_t *); +static struct heim_db_type json_dbt; + +static void HEIM_CALLCONV db_dealloc(void *ptr); + +struct heim_type_data db_object = { + HEIM_TID_DB, + "db-object", + NULL, + db_dealloc, + NULL, + NULL, + NULL, + NULL +}; + + +static heim_base_once_t db_plugin_init_once = HEIM_BASE_ONCE_INIT; + +static heim_dict_t db_plugins; + +typedef struct db_plugin { + heim_string_t name; + heim_db_plug_open_f_t openf; + heim_db_plug_clone_f_t clonef; + heim_db_plug_close_f_t closef; + heim_db_plug_lock_f_t lockf; + heim_db_plug_unlock_f_t unlockf; + heim_db_plug_sync_f_t syncf; + heim_db_plug_begin_f_t beginf; + heim_db_plug_commit_f_t commitf; + heim_db_plug_rollback_f_t rollbackf; + heim_db_plug_copy_value_f_t copyf; + heim_db_plug_set_value_f_t setf; + heim_db_plug_del_key_f_t delf; + heim_db_plug_iter_f_t iterf; + void *data; +} db_plugin_desc, *db_plugin; + +struct heim_db_data { + db_plugin plug; + heim_string_t dbtype; + heim_string_t dbname; + heim_dict_t options; + void *db_data; + heim_data_t to_release; + heim_error_t error; + int ret; + unsigned int in_transaction:1; + unsigned int ro:1; + unsigned int ro_tx:1; + heim_dict_t set_keys; + heim_dict_t del_keys; + heim_string_t current_table; +}; + +static int +db_do_log_actions(heim_db_t db, heim_error_t *error); +static int +db_replay_log(heim_db_t db, heim_error_t *error); + +static HEIMDAL_MUTEX db_type_mutex = HEIMDAL_MUTEX_INITIALIZER; + +static void +db_init_plugins_once(void *arg) +{ + db_plugins = heim_retain(arg); +} + +static void HEIM_CALLCONV +plugin_dealloc(void *arg) +{ + db_plugin plug = arg; + + heim_release(plug->name); +} + +/** heim_db_register + * @brief Registers a DB type for use with heim_db_create(). + * + * @param dbtype Name of DB type + * @param data Private data argument to the dbtype's openf method + * @param plugin Structure with DB type methods (function pointers) + * + * Backends that provide begin/commit/rollback methods must provide ACID + * semantics. + * + * The registered DB type will have ACID semantics for backends that do + * not provide begin/commit/rollback methods but do provide lock/unlock + * and rdjournal/wrjournal methods (using a replay log journalling + * scheme). + * + * If the registered DB type does not natively provide read vs. write + * transaction isolation but does provide a lock method then the DB will + * provide read/write transaction isolation. + * + * @return ENOMEM on failure, else 0. + * + * @addtogroup heimbase + */ +int +heim_db_register(const char *dbtype, + void *data, + struct heim_db_type *plugin) +{ + heim_dict_t plugins; + heim_string_t s; + db_plugin plug, plug2; + int ret = 0; + + if ((plugin->beginf != NULL && plugin->commitf == NULL) || + (plugin->beginf != NULL && plugin->rollbackf == NULL) || + (plugin->lockf != NULL && plugin->unlockf == NULL) || + plugin->copyf == NULL) + heim_abort("Invalid DB plugin; make sure methods are paired"); + + /* Initialize */ + plugins = heim_dict_create(11); + if (plugins == NULL) + return ENOMEM; + heim_base_once_f(&db_plugin_init_once, plugins, db_init_plugins_once); + heim_release(plugins); + heim_assert(db_plugins != NULL, "heim_db plugin table initialized"); + + s = heim_string_create(dbtype); + if (s == NULL) + return ENOMEM; + + plug = heim_alloc(sizeof (*plug), "db_plug", plugin_dealloc); + if (plug == NULL) { + heim_release(s); + return ENOMEM; + } + + plug->name = heim_retain(s); + plug->openf = plugin->openf; + plug->clonef = plugin->clonef; + plug->closef = plugin->closef; + plug->lockf = plugin->lockf; + plug->unlockf = plugin->unlockf; + plug->syncf = plugin->syncf; + plug->beginf = plugin->beginf; + plug->commitf = plugin->commitf; + plug->rollbackf = plugin->rollbackf; + plug->copyf = plugin->copyf; + plug->setf = plugin->setf; + plug->delf = plugin->delf; + plug->iterf = plugin->iterf; + plug->data = data; + + HEIMDAL_MUTEX_lock(&db_type_mutex); + plug2 = heim_dict_get_value(db_plugins, s); + if (plug2 == NULL) + ret = heim_dict_set_value(db_plugins, s, plug); + HEIMDAL_MUTEX_unlock(&db_type_mutex); + heim_release(plug); + heim_release(s); + + return ret; +} + +static void HEIM_CALLCONV +db_dealloc(void *arg) +{ + heim_db_t db = arg; + heim_assert(!db->in_transaction, + "rollback or commit heim_db_t before releasing it"); + if (db->db_data) + (void) db->plug->closef(db->db_data, NULL); + heim_release(db->to_release); + heim_release(db->dbtype); + heim_release(db->dbname); + heim_release(db->options); + heim_release(db->set_keys); + heim_release(db->del_keys); + heim_release(db->error); +} + +struct dbtype_iter { + heim_db_t db; + const char *dbname; + heim_dict_t options; + heim_error_t *error; +}; + +/* + * Helper to create a DB handle with the first registered DB type that + * can open the given DB. This is useful when the app doesn't know the + * DB type a priori. This assumes that DB types can "taste" DBs, either + * from the filename extension or from the actual file contents. + */ +static void +dbtype_iter2create_f(heim_object_t dbtype, heim_object_t junk, void *arg) +{ + struct dbtype_iter *iter_ctx = arg; + + if (iter_ctx->db != NULL) + return; + iter_ctx->db = heim_db_create(heim_string_get_utf8(dbtype), + iter_ctx->dbname, iter_ctx->options, + iter_ctx->error); +} + +/** + * Open a database of the given dbtype. + * + * Database type names can be composed of one or more pseudo-DB types + * and one concrete DB type joined with a '+' between each. For + * example: "transaction+bdb" might be a Berkeley DB with a layer above + * that provides transactions. + * + * Options may be provided via a dict (an associative array). Existing + * options include: + * + * - "create", with any value (create if DB doesn't exist) + * - "exclusive", with any value (exclusive create) + * - "truncate", with any value (truncate the DB) + * - "read-only", with any value (disallow writes) + * - "sync", with any value (make transactions durable) + * - "journal-name", with a string value naming a journal file name + * + * @param dbtype Name of DB type + * @param dbname Name of DB (likely a file path) + * @param options Options dict + * @param db Output open DB handle + * @param error Output error object + * + * @return a DB handle + * + * @addtogroup heimbase + */ +heim_db_t +heim_db_create(const char *dbtype, const char *dbname, + heim_dict_t options, heim_error_t *error) +{ + heim_string_t s; + char *p; + db_plugin plug; + heim_db_t db; + int ret = 0; + + if (options == NULL) { + options = heim_dict_create(11); + if (options == NULL) { + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + } else { + (void) heim_retain(options); + } + + if (db_plugins == NULL) { + heim_release(options); + return NULL; + } + + if (dbtype == NULL || *dbtype == '\0') { + struct dbtype_iter iter_ctx = { NULL, dbname, options, error}; + + /* Try all dbtypes */ + heim_dict_iterate_f(db_plugins, &iter_ctx, dbtype_iter2create_f); + heim_release(options); + return iter_ctx.db; + } else if (strstr(dbtype, "json")) { + (void) heim_db_register(dbtype, NULL, &json_dbt); + } + + /* + * Allow for dbtypes that are composed from pseudo-dbtypes chained + * to a real DB type with '+'. For example a pseudo-dbtype might + * add locking, transactions, transcoding of values, ... + */ + p = strchr(dbtype, '+'); + if (p != NULL) + s = heim_string_create_with_bytes(dbtype, p - dbtype); + else + s = heim_string_create(dbtype); + if (s == NULL) { + heim_release(options); + return NULL; + } + + HEIMDAL_MUTEX_lock(&db_type_mutex); + plug = heim_dict_get_value(db_plugins, s); + HEIMDAL_MUTEX_unlock(&db_type_mutex); + heim_release(s); + if (plug == NULL) { + if (error) + *error = heim_error_create(ENOENT, + N_("Heimdal DB plugin not found: %s", ""), + dbtype); + heim_release(options); + return NULL; + } + + db = _heim_alloc_object(&db_object, sizeof(*db)); + if (db == NULL) { + heim_release(options); + return NULL; + } + + db->in_transaction = 0; + db->ro_tx = 0; + db->set_keys = NULL; + db->del_keys = NULL; + db->plug = plug; + db->options = options; + + ret = plug->openf(plug->data, dbtype, dbname, options, &db->db_data, error); + if (ret) { + heim_release(db); + if (error && *error == NULL) + *error = heim_error_create(ENOENT, + N_("Heimdal DB could not be opened: %s", ""), + dbname); + return NULL; + } + + ret = db_replay_log(db, error); + if (ret) { + heim_release(db); + return NULL; + } + + if (plug->clonef == NULL) { + db->dbtype = heim_string_create(dbtype); + db->dbname = heim_string_create(dbname); + + if (!db->dbtype || ! db->dbname) { + heim_release(db); + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + } + + return db; +} + +/** + * Clone (duplicate) an open DB handle. + * + * This is useful for multi-threaded applications. Applications must + * synchronize access to any given DB handle. + * + * Returns EBUSY if there is an open transaction for the input db. + * + * @param db Open DB handle + * @param error Output error object + * + * @return a DB handle + * + * @addtogroup heimbase + */ +heim_db_t +heim_db_clone(heim_db_t db, heim_error_t *error) +{ + heim_db_t result; + int ret; + + if (heim_get_tid(db) != HEIM_TID_DB) + heim_abort("Expected a database"); + if (db->in_transaction) + heim_abort("DB handle is busy"); + + if (db->plug->clonef == NULL) { + return heim_db_create(heim_string_get_utf8(db->dbtype), + heim_string_get_utf8(db->dbname), + db->options, error); + } + + result = _heim_alloc_object(&db_object, sizeof(*result)); + if (result == NULL) { + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + + result->set_keys = NULL; + result->del_keys = NULL; + ret = db->plug->clonef(db->db_data, &result->db_data, error); + if (ret) { + heim_release(result); + if (error && !*error) + *error = heim_error_create(ENOENT, + N_("Could not re-open DB while cloning", "")); + return NULL; + } + db->db_data = NULL; + return result; +} + +/** + * Open a transaction on the given db. + * + * @param db Open DB handle + * @param error Output error object + * + * @return 0 on success, system error otherwise + * + * @addtogroup heimbase + */ +int +heim_db_begin(heim_db_t db, int read_only, heim_error_t *error) +{ + int ret; + + if (heim_get_tid(db) != HEIM_TID_DB) + return EINVAL; + + if (db->in_transaction && (read_only || !db->ro_tx || (!read_only && !db->ro_tx))) + heim_abort("DB already in transaction"); + + if (db->plug->setf == NULL || db->plug->delf == NULL) + return EINVAL; + + if (db->plug->beginf) { + ret = db->plug->beginf(db->db_data, read_only, error); + if (ret) + return ret; + } else if (!db->in_transaction) { + /* Try to emulate transactions */ + + if (db->plug->lockf == NULL) + return EINVAL; /* can't lock? -> no transactions */ + + /* Assume unlock provides sync/durability */ + ret = db->plug->lockf(db->db_data, read_only, error); + if (ret) + return ret; + + ret = db_replay_log(db, error); + if (ret) { + ret = db->plug->unlockf(db->db_data, error); + return ret; + } + + db->set_keys = heim_dict_create(11); + if (db->set_keys == NULL) + return ENOMEM; + db->del_keys = heim_dict_create(11); + if (db->del_keys == NULL) { + heim_release(db->set_keys); + db->set_keys = NULL; + return ENOMEM; + } + } else { + heim_assert(read_only == 0, "Internal error"); + ret = db->plug->lockf(db->db_data, 0, error); + if (ret) + return ret; + } + db->in_transaction = 1; + db->ro_tx = !!read_only; + return 0; +} + +/** + * Commit an open transaction on the given db. + * + * @param db Open DB handle + * @param error Output error object + * + * @return 0 on success, system error otherwise + * + * @addtogroup heimbase + */ +int +heim_db_commit(heim_db_t db, heim_error_t *error) +{ + int ret, ret2; + heim_string_t journal_fname = NULL; + + if (heim_get_tid(db) != HEIM_TID_DB) + return EINVAL; + if (!db->in_transaction) + return 0; + if (db->plug->commitf == NULL && db->plug->lockf == NULL) + return EINVAL; + + if (db->plug->commitf != NULL) { + ret = db->plug->commitf(db->db_data, error); + if (ret) + (void) db->plug->rollbackf(db->db_data, error); + + db->in_transaction = 0; + db->ro_tx = 0; + return ret; + } + + if (db->ro_tx) { + ret = 0; + goto done; + } + + if (db->options) + journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename")); + + if (journal_fname != NULL) { + heim_array_t a; + heim_string_t journal_contents; + size_t len, bytes; + int save_errno; + + /* Create contents for replay log */ + ret = ENOMEM; + a = heim_array_create(); + if (a == NULL) + goto err; + ret = heim_array_append_value(a, db->set_keys); + if (ret) { + heim_release(a); + goto err; + } + ret = heim_array_append_value(a, db->del_keys); + if (ret) { + heim_release(a); + goto err; + } + journal_contents = heim_json_copy_serialize(a, 0, error); + heim_release(a); + + /* Write replay log */ + if (journal_fname != NULL) { + int fd; + + ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error); + if (ret) { + heim_release(journal_contents); + goto err; + } + len = strlen(heim_string_get_utf8(journal_contents)); + bytes = write(fd, heim_string_get_utf8(journal_contents), len); + save_errno = errno; + heim_release(journal_contents); + ret = close(fd); + if (bytes != len) { + /* Truncate replay log */ + (void) open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error); + ret = save_errno; + goto err; + } + if (ret) + goto err; + } + } + + /* Apply logged actions */ + ret = db_do_log_actions(db, error); + if (ret) + return ret; + + if (db->plug->syncf != NULL) { + /* fsync() or whatever */ + ret = db->plug->syncf(db->db_data, error); + if (ret) + return ret; + } + + /* Truncate replay log and we're done */ + if (journal_fname != NULL) { + int fd; + + ret2 = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error); + if (ret2 == 0) + (void) close(fd); + } + + /* + * Clean up; if we failed to remore the replay log that's OK, we'll + * handle that again in heim_db_commit() + */ +done: + heim_release(db->set_keys); + heim_release(db->del_keys); + db->set_keys = NULL; + db->del_keys = NULL; + db->in_transaction = 0; + db->ro_tx = 0; + + ret2 = db->plug->unlockf(db->db_data, error); + if (ret == 0) + ret = ret2; + + return ret; + +err: + return HEIM_ERROR(error, ret, + (ret, N_("Error while committing transaction: %s", ""), + strerror(ret))); +} + +/** + * Rollback an open transaction on the given db. + * + * @param db Open DB handle + * @param error Output error object + * + * @return 0 on success, system error otherwise + * + * @addtogroup heimbase + */ +int +heim_db_rollback(heim_db_t db, heim_error_t *error) +{ + int ret = 0; + + if (heim_get_tid(db) != HEIM_TID_DB) + return EINVAL; + if (!db->in_transaction) + return 0; + + if (db->plug->rollbackf != NULL) + ret = db->plug->rollbackf(db->db_data, error); + else if (db->plug->unlockf != NULL) + ret = db->plug->unlockf(db->db_data, error); + + heim_release(db->set_keys); + heim_release(db->del_keys); + db->set_keys = NULL; + db->del_keys = NULL; + db->in_transaction = 0; + db->ro_tx = 0; + + return ret; +} + +/** + * Get type ID of heim_db_t objects. + * + * @addtogroup heimbase + */ +heim_tid_t +heim_db_get_type_id(void) +{ + return HEIM_TID_DB; +} + +heim_data_t +_heim_db_get_value(heim_db_t db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + heim_release(db->to_release); + db->to_release = heim_db_copy_value(db, table, key, error); + return db->to_release; +} + +/** + * Lookup a key's value in the DB. + * + * Returns 0 on success, -1 if the key does not exist in the DB, or a + * system error number on failure. + * + * @param db Open DB handle + * @param key Key + * @param error Output error object + * + * @return the value (retained), if there is one for the given key + * + * @addtogroup heimbase + */ +heim_data_t +heim_db_copy_value(heim_db_t db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + heim_object_t v; + heim_data_t result; + + if (heim_get_tid(db) != HEIM_TID_DB) + return NULL; + + if (error != NULL) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + if (db->in_transaction) { + heim_string_t key64; + + key64 = to_base64(key, error); + if (key64 == NULL) { + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + + v = heim_path_copy(db->set_keys, error, table, key64, NULL); + if (v != NULL) { + heim_release(key64); + return v; + } + v = heim_path_copy(db->del_keys, error, table, key64, NULL); /* can't be NULL */ + heim_release(key64); + if (v != NULL) + return NULL; + } + + result = db->plug->copyf(db->db_data, table, key, error); + + return result; +} + +/** + * Set a key's value in the DB. + * + * @param db Open DB handle + * @param key Key + * @param value Value (if NULL the key will be deleted, but empty is OK) + * @param error Output error object + * + * @return 0 on success, system error otherwise + * + * @addtogroup heimbase + */ +int +heim_db_set_value(heim_db_t db, heim_string_t table, + heim_data_t key, heim_data_t value, heim_error_t *error) +{ + heim_string_t key64 = NULL; + int ret; + + if (error != NULL) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + if (value == NULL) + /* Use heim_null_t instead of NULL */ + return heim_db_delete_key(db, table, key, error); + + if (heim_get_tid(db) != HEIM_TID_DB) + return EINVAL; + + if (heim_get_tid(key) != HEIM_TID_DATA) + return HEIM_ERROR(error, EINVAL, + (EINVAL, N_("DB keys must be data", ""))); + + if (db->plug->setf == NULL) + return EBADF; + + if (!db->in_transaction) { + ret = heim_db_begin(db, 0, error); + if (ret) + goto err; + heim_assert(db->in_transaction, "Internal error"); + ret = heim_db_set_value(db, table, key, value, error); + if (ret) { + (void) heim_db_rollback(db, NULL); + return ret; + } + return heim_db_commit(db, error); + } + + /* Transaction emulation */ + heim_assert(db->set_keys != NULL, "Internal error"); + key64 = to_base64(key, error); + if (key64 == NULL) + return HEIM_ENOMEM(error); + + if (db->ro_tx) { + ret = heim_db_begin(db, 0, error); + if (ret) + goto err; + } + ret = heim_path_create(db->set_keys, 29, value, error, table, key64, NULL); + if (ret) + goto err; + heim_path_delete(db->del_keys, error, table, key64, NULL); + heim_release(key64); + + return 0; + +err: + heim_release(key64); + return HEIM_ERROR(error, ret, + (ret, N_("Could not set a dict value while while " + "setting a DB value", ""))); +} + +/** + * Delete a key and its value from the DB + * + * + * @param db Open DB handle + * @param key Key + * @param error Output error object + * + * @return 0 on success, system error otherwise + * + * @addtogroup heimbase + */ +int +heim_db_delete_key(heim_db_t db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + heim_string_t key64 = NULL; + int ret; + + if (error != NULL) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + if (heim_get_tid(db) != HEIM_TID_DB) + return EINVAL; + + if (db->plug->delf == NULL) + return EBADF; + + if (!db->in_transaction) { + ret = heim_db_begin(db, 0, error); + if (ret) + goto err; + heim_assert(db->in_transaction, "Internal error"); + ret = heim_db_delete_key(db, table, key, error); + if (ret) { + (void) heim_db_rollback(db, NULL); + return ret; + } + return heim_db_commit(db, error); + } + + /* Transaction emulation */ + heim_assert(db->set_keys != NULL, "Internal error"); + key64 = to_base64(key, error); + if (key64 == NULL) + return HEIM_ENOMEM(error); + if (db->ro_tx) { + ret = heim_db_begin(db, 0, error); + if (ret) + goto err; + } + ret = heim_path_create(db->del_keys, 29, heim_number_create(1), error, table, key64, NULL); + if (ret) + goto err; + heim_path_delete(db->set_keys, error, table, key64, NULL); + heim_release(key64); + + return 0; + +err: + heim_release(key64); + return HEIM_ERROR(error, ret, + (ret, N_("Could not set a dict value while while " + "deleting a DB value", ""))); +} + +/** + * Iterate a callback function over keys and values from a DB. + * + * @param db Open DB handle + * @param iter_data Callback function's private data + * @param iter_f Callback function, called once per-key/value pair + * @param error Output error object + * + * @addtogroup heimbase + */ +void +heim_db_iterate_f(heim_db_t db, heim_string_t table, void *iter_data, + heim_db_iterator_f_t iter_f, heim_error_t *error) +{ + if (error != NULL) + *error = NULL; + + if (heim_get_tid(db) != HEIM_TID_DB) + return; + + if (!db->in_transaction) + db->plug->iterf(db->db_data, table, iter_data, iter_f, error); +} + +static void +db_replay_log_table_set_keys_iter(heim_object_t key, heim_object_t value, + void *arg) +{ + heim_db_t db = arg; + heim_data_t k, v; + + if (db->ret) + return; + + k = from_base64((heim_string_t)key, &db->error); + if (k == NULL) { + db->ret = ENOMEM; + return; + } + v = (heim_data_t)value; + + db->ret = db->plug->setf(db->db_data, db->current_table, k, v, &db->error); + heim_release(k); +} + +static void +db_replay_log_table_del_keys_iter(heim_object_t key, heim_object_t value, + void *arg) +{ + heim_db_t db = arg; + heim_data_t k; + + if (db->ret) { + db->ret = ENOMEM; + return; + } + + k = from_base64((heim_string_t)key, &db->error); + if (k == NULL) + return; + + db->ret = db->plug->delf(db->db_data, db->current_table, k, &db->error); + heim_release(k); +} + +static void +db_replay_log_set_keys_iter(heim_object_t table, heim_object_t table_dict, + void *arg) +{ + heim_db_t db = arg; + + if (db->ret) + return; + + db->current_table = table; + heim_dict_iterate_f(table_dict, db, db_replay_log_table_set_keys_iter); +} + +static void +db_replay_log_del_keys_iter(heim_object_t table, heim_object_t table_dict, + void *arg) +{ + heim_db_t db = arg; + + if (db->ret) + return; + + db->current_table = table; + heim_dict_iterate_f(table_dict, db, db_replay_log_table_del_keys_iter); +} + +static int +db_do_log_actions(heim_db_t db, heim_error_t *error) +{ + int ret; + + if (error) + *error = NULL; + + db->ret = 0; + db->error = NULL; + if (db->set_keys != NULL) + heim_dict_iterate_f(db->set_keys, db, db_replay_log_set_keys_iter); + if (db->del_keys != NULL) + heim_dict_iterate_f(db->del_keys, db, db_replay_log_del_keys_iter); + + ret = db->ret; + db->ret = 0; + if (error && db->error) { + *error = db->error; + db->error = NULL; + } else { + heim_release(db->error); + db->error = NULL; + } + return ret; +} + +static int +db_replay_log(heim_db_t db, heim_error_t *error) +{ + int ret; + heim_string_t journal_fname = NULL; + heim_object_t journal; + size_t len; + + heim_assert(!db->in_transaction, "DB transaction not open"); + heim_assert(db->set_keys == NULL && db->set_keys == NULL, "DB transaction not open"); + + if (error) + *error = NULL; + + if (db->options == NULL) + return 0; + + journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename")); + if (journal_fname == NULL) + return 0; + + ret = read_json(heim_string_get_utf8(journal_fname), &journal, error); + if (ret == ENOENT) { + heim_release(journal_fname); + return 0; + } + if (ret == 0 && journal == NULL) { + heim_release(journal_fname); + return 0; + } + if (ret != 0) { + heim_release(journal_fname); + return ret; + } + + if (heim_get_tid(journal) != HEIM_TID_ARRAY) { + heim_release(journal_fname); + return HEIM_ERROR(error, EINVAL, + (ret, N_("Invalid journal contents; delete journal", + ""))); + } + + len = heim_array_get_length(journal); + + if (len > 0) + db->set_keys = heim_array_get_value(journal, 0); + if (len > 1) + db->del_keys = heim_array_get_value(journal, 1); + ret = db_do_log_actions(db, error); + if (ret) { + heim_release(journal_fname); + return ret; + } + + /* Truncate replay log and we're done */ + ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error); + heim_release(journal_fname); + if (ret) + return ret; + heim_release(db->set_keys); + heim_release(db->del_keys); + db->set_keys = NULL; + db->del_keys = NULL; + + return 0; +} + +static +heim_string_t to_base64(heim_data_t data, heim_error_t *error) +{ + char *b64 = NULL; + heim_string_t s = NULL; + const heim_octet_string *d; + int ret; + + d = heim_data_get_data(data); + ret = rk_base64_encode(d->data, d->length, &b64); + if (ret < 0 || b64 == NULL) + goto enomem; + s = heim_string_ref_create(b64, free); + if (s == NULL) + goto enomem; + return s; + +enomem: + free(b64); + if (error) + *error = heim_error_create_enomem(); + return NULL; +} + +static +heim_data_t from_base64(heim_string_t s, heim_error_t *error) +{ + ssize_t len = -1; + void *buf; + heim_data_t d; + + buf = malloc(strlen(heim_string_get_utf8(s))); + if (buf) + len = rk_base64_decode(heim_string_get_utf8(s), buf); + if (len > -1 && (d = heim_data_ref_create(buf, len, free))) + return d; + free(buf); + if (error) + *error = heim_error_create_enomem(); + return NULL; +} + + +static int +open_file(const char *dbname, int for_write, int excl, int *fd_out, heim_error_t *error) +{ +#ifdef WIN32 + HANDLE hFile; + int ret = 0; + + if (fd_out) + *fd_out = -1; + + if (for_write) + hFile = CreateFile(dbname, GENERIC_WRITE | GENERIC_READ, 0, + NULL, /* we'll close as soon as we read */ + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + else + hFile = CreateFile(dbname, GENERIC_READ, FILE_SHARE_READ, + NULL, /* we'll close as soon as we read */ + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + ret = GetLastError(); + _set_errno(ret); /* CreateFile() does not set errno */ + goto err; + } + if (fd_out == NULL) { + (void) CloseHandle(hFile); + return 0; + } + + *fd_out = _open_osfhandle((intptr_t) hFile, 0); + if (*fd_out < 0) { + ret = errno; + (void) CloseHandle(hFile); + goto err; + } + + /* No need to lock given share deny mode */ + return 0; + +err: + if (error != NULL) { + char *s = NULL; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + 0, ret, 0, (LPTSTR) &s, 0, NULL); + *error = heim_error_create(ret, N_("Could not open JSON file %s: %s", ""), + dbname, s ? s : ""); + LocalFree(s); + } + return ret; +#else + int ret = 0; + int fd; + + if (fd_out) + *fd_out = -1; + + if (for_write && excl) + fd = open(dbname, O_CREAT | O_EXCL | O_WRONLY, 0600); + else if (for_write) + fd = open(dbname, O_CREAT | O_TRUNC | O_WRONLY, 0600); + else + fd = open(dbname, O_RDONLY); + if (fd < 0) { + if (error != NULL) + *error = heim_error_create(ret, N_("Could not open JSON file %s: %s", ""), + dbname, strerror(errno)); + return errno; + } + + if (fd_out == NULL) { + (void) close(fd); + return 0; + } + + ret = flock(fd, for_write ? LOCK_EX : LOCK_SH); + if (ret == -1) { + /* Note that we if O_EXCL we're leaving the [lock] file around */ + (void) close(fd); + return HEIM_ERROR(error, errno, + (errno, N_("Could not lock JSON file %s: %s", ""), + dbname, strerror(errno))); + } + + *fd_out = fd; + + return 0; +#endif +} + +static int +read_json(const char *dbname, heim_object_t *out, heim_error_t *error) +{ + struct stat st; + char *str = NULL; + int ret; + int fd = -1; + ssize_t bytes; + + *out = NULL; + ret = open_file(dbname, 0, 0, &fd, error); + if (ret) + return ret; + + ret = fstat(fd, &st); + if (ret == -1) { + (void) close(fd); + return HEIM_ERROR(error, errno, + (ret, N_("Could not stat JSON DB %s: %s", ""), + dbname, strerror(errno))); + } + + if (st.st_size == 0) { + (void) close(fd); + return 0; + } + + str = malloc(st.st_size + 1); + if (str == NULL) { + (void) close(fd); + return HEIM_ENOMEM(error); + } + + bytes = read(fd, str, st.st_size); + (void) close(fd); + if (bytes != st.st_size) { + free(str); + if (bytes >= 0) + errno = EINVAL; /* ?? */ + return HEIM_ERROR(error, errno, + (ret, N_("Could not read JSON DB %s: %s", ""), + dbname, strerror(errno))); + } + str[st.st_size] = '\0'; + *out = heim_json_create(str, 10, 0, error); + free(str); + if (*out == NULL) + return (error && *error) ? heim_error_get_code(*error) : EINVAL; + return 0; +} + +typedef struct json_db { + heim_dict_t dict; + heim_string_t dbname; + heim_string_t bkpname; + int fd; + time_t last_read_time; + unsigned int read_only:1; + unsigned int locked:1; + unsigned int locked_needs_unlink:1; +} *json_db_t; + +static int +json_db_open(void *plug, const char *dbtype, const char *dbname, + heim_dict_t options, void **db, heim_error_t *error) +{ + json_db_t jsondb; + heim_dict_t contents = NULL; + heim_string_t dbname_s = NULL; + heim_string_t bkpname_s = NULL; + + if (error) + *error = NULL; + if (dbtype && *dbtype && strcmp(dbtype, "json") != 0) + return HEIM_ERROR(error, EINVAL, (EINVAL, N_("Wrong DB type", ""))); + if (dbname && *dbname && strcmp(dbname, "MEMORY") != 0) { + char *ext = strrchr(dbname, '.'); + char *bkpname; + size_t len; + int ret; + + if (ext == NULL || strcmp(ext, ".json") != 0) + return HEIM_ERROR(error, EINVAL, + (EINVAL, N_("JSON DB files must end in .json", + ""))); + + if (options) { + heim_object_t vc, ve, vt; + + vc = heim_dict_get_value(options, HSTR("create")); + ve = heim_dict_get_value(options, HSTR("exclusive")); + vt = heim_dict_get_value(options, HSTR("truncate")); + if (vc && vt) { + ret = open_file(dbname, 1, ve ? 1 : 0, NULL, error); + if (ret) + return ret; + } else if (vc || ve || vt) { + return HEIM_ERROR(error, EINVAL, + (EINVAL, N_("Invalid JSON DB open options", + ""))); + } + /* + * We don't want cloned handles to truncate the DB, eh? + * + * We should really just create a copy of the options dict + * rather than modify the caller's! But for that it'd be + * nicer to have copy utilities in heimbase, something like + * this: + * + * heim_object_t heim_copy(heim_object_t src, int depth, + * heim_error_t *error); + * + * so that options = heim_copy(options, 1); means copy the + * dict but nothing else (whereas depth == 0 would mean + * heim_retain(), and depth > 1 would be copy that many + * levels). + */ + heim_dict_delete_key(options, HSTR("create")); + heim_dict_delete_key(options, HSTR("exclusive")); + heim_dict_delete_key(options, HSTR("truncate")); + } + dbname_s = heim_string_create(dbname); + if (dbname_s == NULL) + return HEIM_ENOMEM(error); + + len = snprintf(NULL, 0, "%s~", dbname); + bkpname = malloc(len + 2); + if (bkpname == NULL) { + heim_release(dbname_s); + return HEIM_ENOMEM(error); + } + (void) snprintf(bkpname, len + 1, "%s~", dbname); + bkpname_s = heim_string_create(bkpname); + free(bkpname); + if (bkpname_s == NULL) { + heim_release(dbname_s); + return HEIM_ENOMEM(error); + } + + ret = read_json(dbname, (heim_object_t *)&contents, error); + if (ret) { + heim_release(bkpname_s); + heim_release(dbname_s); + return ret; + } + + if (contents != NULL && heim_get_tid(contents) != HEIM_TID_DICT) { + heim_release(bkpname_s); + heim_release(dbname_s); + return HEIM_ERROR(error, EINVAL, + (EINVAL, N_("JSON DB contents not valid JSON", + ""))); + } + } + + jsondb = heim_alloc(sizeof (*jsondb), "json_db", NULL); + if (jsondb == NULL) { + heim_release(contents); + heim_release(dbname_s); + heim_release(bkpname_s); + return ENOMEM; + } + + jsondb->last_read_time = time(NULL); + jsondb->fd = -1; + jsondb->dbname = dbname_s; + jsondb->bkpname = bkpname_s; + jsondb->read_only = 0; + + if (contents != NULL) + jsondb->dict = contents; + else { + jsondb->dict = heim_dict_create(29); + if (jsondb->dict == NULL) { + heim_release(jsondb); + return ENOMEM; + } + } + + *db = jsondb; + return 0; +} + +static int +json_db_close(void *db, heim_error_t *error) +{ + json_db_t jsondb = db; + + if (error) + *error = NULL; + if (jsondb->fd > -1) + (void) close(jsondb->fd); + jsondb->fd = -1; + heim_release(jsondb->dbname); + heim_release(jsondb->bkpname); + heim_release(jsondb->dict); + heim_release(jsondb); + return 0; +} + +static int +json_db_lock(void *db, int read_only, heim_error_t *error) +{ + json_db_t jsondb = db; + int ret; + + heim_assert(jsondb->fd == -1 || (jsondb->read_only && !read_only), + "DB locks are not recursive"); + + jsondb->read_only = read_only ? 1 : 0; + if (jsondb->fd > -1) + return 0; + + ret = open_file(heim_string_get_utf8(jsondb->bkpname), 1, 1, &jsondb->fd, error); + if (ret == 0) { + jsondb->locked_needs_unlink = 1; + jsondb->locked = 1; + } + return ret; +} + +static int +json_db_unlock(void *db, heim_error_t *error) +{ + json_db_t jsondb = db; + int ret = 0; + + heim_assert(jsondb->locked, "DB not locked when unlock attempted"); + if (jsondb->fd > -1) + ret = close(jsondb->fd); + jsondb->fd = -1; + jsondb->read_only = 0; + jsondb->locked = 0; + if (jsondb->locked_needs_unlink) + unlink(heim_string_get_utf8(jsondb->bkpname)); + jsondb->locked_needs_unlink = 0; + return ret; +} + +static int +json_db_sync(void *db, heim_error_t *error) +{ + json_db_t jsondb = db; + size_t len, bytes; + heim_error_t e; + heim_string_t json; + const char *json_text = NULL; + int ret = 0; + int fd = -1; +#ifdef WIN32 + int tries = 3; +#endif + + heim_assert(jsondb->fd > -1, "DB not locked when sync attempted"); + + json = heim_json_copy_serialize(jsondb->dict, 0, &e); + if (json == NULL) { + ret = heim_error_get_code(e); + if (error) + *error = e; + else + heim_release(e); + return ret; + } + + json_text = heim_string_get_utf8(json); + len = strlen(json_text); + errno = 0; + +#ifdef WIN32 + while (tries--) { + ret = open_file(heim_string_get_utf8(jsondb->dbname), 1, 0, &fd, error); + if (ret == 0) + break; + sleep(1); + } + if (ret) { + heim_release(json); + return ret; + } +#else + fd = jsondb->fd; +#endif /* WIN32 */ + + bytes = write(fd, json_text, len); + heim_release(json); + if (bytes != len) + return errno ? errno : EIO; + ret = fsync(fd); + if (ret) + return ret; + +#ifdef WIN32 + ret = close(fd); + if (ret) + return GetLastError(); +#else + ret = rename(heim_string_get_utf8(jsondb->bkpname), heim_string_get_utf8(jsondb->dbname)); + if (ret == 0) { + jsondb->locked_needs_unlink = 0; + return 0; + } +#endif /* WIN32 */ + + return errno; +} + +static heim_data_t +json_db_copy_value(void *db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + json_db_t jsondb = db; + heim_string_t key_string; + const heim_octet_string *key_data = heim_data_get_data(key); + struct stat st; + heim_data_t result; + + if (error) + *error = NULL; + + if (strnlen(key_data->data, key_data->length) != key_data->length) { + HEIM_ERROR(error, EINVAL, + (EINVAL, N_("JSON DB requires keys that are actually " + "strings", ""))); + return NULL; + } + + if (stat(heim_string_get_utf8(jsondb->dbname), &st) == -1) { + HEIM_ERROR(error, errno, + (errno, N_("Could not stat JSON DB file", ""))); + return NULL; + } + + if (st.st_mtime > jsondb->last_read_time || + st.st_ctime > jsondb->last_read_time) { + heim_dict_t contents = NULL; + int ret; + + /* Ignore file is gone (ENOENT) */ + ret = read_json(heim_string_get_utf8(jsondb->dbname), + (heim_object_t *)&contents, error); + if (ret) + return NULL; + if (contents == NULL) + contents = heim_dict_create(29); + heim_release(jsondb->dict); + jsondb->dict = contents; + jsondb->last_read_time = time(NULL); + } + + key_string = heim_string_create_with_bytes(key_data->data, + key_data->length); + if (key_string == NULL) { + (void) HEIM_ENOMEM(error); + return NULL; + } + + result = heim_path_copy(jsondb->dict, error, table, key_string, NULL); + heim_release(key_string); + return result; +} + +static int +json_db_set_value(void *db, heim_string_t table, + heim_data_t key, heim_data_t value, heim_error_t *error) +{ + json_db_t jsondb = db; + heim_string_t key_string; + const heim_octet_string *key_data = heim_data_get_data(key); + int ret; + + if (error) + *error = NULL; + + if (strnlen(key_data->data, key_data->length) != key_data->length) + return HEIM_ERROR(error, EINVAL, + (EINVAL, + N_("JSON DB requires keys that are actually strings", + ""))); + + key_string = heim_string_create_with_bytes(key_data->data, + key_data->length); + if (key_string == NULL) + return HEIM_ENOMEM(error); + + if (table == NULL) + table = HSTR(""); + + ret = heim_path_create(jsondb->dict, 29, value, error, table, key_string, NULL); + heim_release(key_string); + return ret; +} + +static int +json_db_del_key(void *db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + json_db_t jsondb = db; + heim_string_t key_string; + const heim_octet_string *key_data = heim_data_get_data(key); + + if (error) + *error = NULL; + + if (strnlen(key_data->data, key_data->length) != key_data->length) + return HEIM_ERROR(error, EINVAL, + (EINVAL, + N_("JSON DB requires keys that are actually strings", + ""))); + + key_string = heim_string_create_with_bytes(key_data->data, + key_data->length); + if (key_string == NULL) + return HEIM_ENOMEM(error); + + if (table == NULL) + table = HSTR(""); + + heim_path_delete(jsondb->dict, error, table, key_string, NULL); + heim_release(key_string); + return 0; +} + +struct json_db_iter_ctx { + heim_db_iterator_f_t iter_f; + void *iter_ctx; +}; + +static void json_db_iter_f(heim_object_t key, heim_object_t value, void *arg) +{ + struct json_db_iter_ctx *ctx = arg; + const char *key_string; + heim_data_t key_data; + + key_string = heim_string_get_utf8((heim_string_t)key); + key_data = heim_data_ref_create(key_string, strlen(key_string), NULL); + ctx->iter_f(key_data, (heim_object_t)value, ctx->iter_ctx); + heim_release(key_data); +} + +static void +json_db_iter(void *db, heim_string_t table, void *iter_data, + heim_db_iterator_f_t iter_f, heim_error_t *error) +{ + json_db_t jsondb = db; + struct json_db_iter_ctx ctx; + heim_dict_t table_dict; + + if (error) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + table_dict = heim_dict_get_value(jsondb->dict, table); + if (table_dict == NULL) + return; + + ctx.iter_ctx = iter_data; + ctx.iter_f = iter_f; + + heim_dict_iterate_f(table_dict, &ctx, json_db_iter_f); +} + +static struct heim_db_type json_dbt = { + 1, json_db_open, NULL, json_db_close, + json_db_lock, json_db_unlock, json_db_sync, + NULL, NULL, NULL, + json_db_copy_value, json_db_set_value, + json_db_del_key, json_db_iter +}; + diff --git a/third_party/heimdal/lib/base/dict.c b/third_party/heimdal/lib/base/dict.c new file mode 100644 index 0000000..86be109 --- /dev/null +++ b/third_party/heimdal/lib/base/dict.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2002, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +struct hashentry { + struct hashentry **prev; + struct hashentry *next; + heim_object_t key; + heim_object_t value; +}; + +struct heim_dict_data { + size_t size; + struct hashentry **tab; +}; + +static void HEIM_CALLCONV +dict_dealloc(void *ptr) +{ + heim_dict_t dict = ptr; + struct hashentry **h, *g, *i; + + for (h = dict->tab; h < &dict->tab[dict->size]; ++h) { + for (g = h[0]; g; g = i) { + i = g->next; + heim_release(g->key); + heim_release(g->value); + free(g); + } + } + free(dict->tab); +} + +struct heim_type_data dict_object = { + HEIM_TID_DICT, + "dict-object", + NULL, + dict_dealloc, + NULL, + NULL, + NULL, + NULL +}; + +static size_t +isprime(size_t p) +{ + size_t q, i; + + for(i = 2 ; i < p; i++) { + q = p / i; + + if (i * q == p) + return 0; + if (i * i > p) + return 1; + } + return 1; +} + +static size_t +findprime(size_t p) +{ + if (p % 2 == 0) + p++; + + while (isprime(p) == 0) + p += 2; + + return p; +} + +/** + * Allocate an array + * + * @return A new allocated array, free with heim_release() + */ + +heim_dict_t +heim_dict_create(size_t size) +{ + heim_dict_t dict; + + dict = _heim_alloc_object(&dict_object, sizeof(*dict)); + if (dict == NULL) + return NULL; + + dict->size = findprime(size); + if (dict->size == 0) { + heim_release(dict); + return NULL; + } + + dict->tab = calloc(dict->size, sizeof(dict->tab[0])); + if (dict->tab == NULL) { + dict->size = 0; + heim_release(dict); + return NULL; + } + + return dict; +} + +/** + * Get type id of an dict + * + * @return the type id + */ + +heim_tid_t +heim_dict_get_type_id(void) +{ + return HEIM_TID_DICT; +} + +/* Intern search function */ + +static struct hashentry * +_search(heim_dict_t dict, heim_object_t ptr) +{ + uintptr_t v = heim_get_hash(ptr); + struct hashentry *p; + + for (p = dict->tab[v % dict->size]; p != NULL; p = p->next) + if (heim_cmp(ptr, p->key) == 0) + return p; + + return NULL; +} + +/** + * Search for element in hash table + * + * @value dict the dict to search in + * @value key the key to search for + * + * @return a not-retained copy of the value for key or NULL if not found + */ + +heim_object_t +heim_dict_get_value(heim_dict_t dict, heim_object_t key) +{ + struct hashentry *p; + p = _search(dict, key); + if (p == NULL) + return NULL; + + return p->value; +} + +/** + * Search for element in hash table + * + * @value dict the dict to search in + * @value key the key to search for + * + * @return a retained copy of the value for key or NULL if not found + */ + +heim_object_t +heim_dict_copy_value(heim_dict_t dict, heim_object_t key) +{ + struct hashentry *p; + p = _search(dict, key); + if (p == NULL) + return NULL; + + return heim_retain(p->value); +} + +/** + * Add key and value to dict + * + * @value dict the dict to add too + * @value key the key to add + * @value value the value to add + * + * @return 0 if added, errno if not + */ + +int +heim_dict_set_value(heim_dict_t dict, heim_object_t key, heim_object_t value) +{ + struct hashentry **tabptr, *h; + + h = _search(dict, key); + if (h) { + heim_release(h->value); + h->value = heim_retain(value); + } else { + uintptr_t v; + + h = malloc(sizeof(*h)); + if (h == NULL) + return ENOMEM; + + h->key = heim_retain(key); + h->value = heim_retain(value); + + v = heim_get_hash(key); + + tabptr = &dict->tab[v % dict->size]; + h->next = *tabptr; + *tabptr = h; + h->prev = tabptr; + if (h->next) + h->next->prev = &h->next; + } + + return 0; +} + +/** + * Delete element with key key + * + * @value dict the dict to delete from + * @value key the key to delete + */ + +void +heim_dict_delete_key(heim_dict_t dict, heim_object_t key) +{ + struct hashentry *h = _search(dict, key); + + if (h == NULL) + return; + + heim_release(h->key); + heim_release(h->value); + + if ((*(h->prev) = h->next) != NULL) + h->next->prev = h->prev; + + free(h); +} + +/** + * Do something for each element + * + * @value dict the dict to interate over + * @value func the function to search for + * @value arg argument to func + */ + +void +heim_dict_iterate_f(heim_dict_t dict, void *arg, heim_dict_iterator_f_t func) +{ + struct hashentry **h, *g; + + for (h = dict->tab; h < &dict->tab[dict->size]; ++h) + for (g = *h; g; g = g->next) + func(g->key, g->value, arg); +} + +#ifdef __BLOCKS__ +/** + * Do something for each element + * + * @value dict the dict to interate over + * @value func the function to search for + */ + +void +heim_dict_iterate(heim_dict_t dict, void (^func)(heim_object_t, heim_object_t)) +{ + struct hashentry **h, *g; + + for (h = dict->tab; h < &dict->tab[dict->size]; ++h) + for (g = *h; g; g = g->next) + func(g->key, g->value); +} +#endif diff --git a/third_party/heimdal/lib/base/dll.c b/third_party/heimdal/lib/base/dll.c new file mode 100644 index 0000000..53f1f63 --- /dev/null +++ b/third_party/heimdal/lib/base/dll.c @@ -0,0 +1,325 @@ +/*********************************************************************** + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +/* + * This is an implementation of thread-specific storage with + * destructors. WIN32 doesn't quite have this. Instead it has + * DllMain(), an entry point in every DLL that gets called to notify the + * DLL of thread/process "attach"/"detach" events. + * + * We use __thread (or __declspec(thread)) for the thread-local itself + * and DllMain() DLL_THREAD_DETACH events to drive destruction of + * thread-local values. + * + * When building in maintainer mode on non-Windows pthread systems this + * uses a single pthread key instead to implement multiple keys. This + * keeps the code from rotting when modified by non-Windows developers. + */ + +#include "baselocl.h" + +#ifdef WIN32 +#include +#endif + +#ifdef HEIM_WIN32_TLS +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +/* Logical array of keys that grows lock-lessly */ +typedef struct tls_keys tls_keys; +struct tls_keys { + void (**keys_dtors)(void *); /* array of destructors */ + size_t keys_start_idx; /* index of first destructor */ + size_t keys_num; + tls_keys *keys_next; +}; + +/* + * Well, not quite locklessly. We need synchronization primitives to do + * this locklessly. An atomic CAS will do. + */ +static HEIMDAL_MUTEX tls_key_defs_lock = HEIMDAL_MUTEX_INITIALIZER; +static tls_keys *tls_key_defs; + +/* Logical array of values (per-thread; no locking needed here) */ +struct tls_values { + void **values; /* realloc()ed */ + size_t values_num; +}; + +static HEIMDAL_THREAD_LOCAL struct tls_values values; + +static char dead_key[1]; +static void no_dtor(void *d) { (void)d; } + +void +heim_w32_service_thread_detach(void *unused) +{ + tls_keys *key_defs; + void (*dtor)(void*); + size_t i; + + HEIMDAL_MUTEX_lock(&tls_key_defs_lock); + key_defs = tls_key_defs; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + + if (key_defs == NULL) + return; + + for (i = 0; i < values.values_num; i++) { + assert(i >= key_defs->keys_start_idx); + if (i >= key_defs->keys_start_idx + key_defs->keys_num) { + HEIMDAL_MUTEX_lock(&tls_key_defs_lock); + key_defs = key_defs->keys_next; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + + assert(key_defs != NULL); + assert(i >= key_defs->keys_start_idx); + assert(i < key_defs->keys_start_idx + key_defs->keys_num); + } + dtor = key_defs->keys_dtors[i - key_defs->keys_start_idx]; + if (values.values[i] != NULL && dtor != NULL && dtor != no_dtor) + dtor(values.values[i]); + values.values[i] = NULL; + } +} + +#if !defined(WIN32) +static pthread_key_t pt_key; +pthread_once_t pt_once = PTHREAD_ONCE_INIT; + +static void +atexit_del_tls_for_thread(void) +{ + heim_w32_service_thread_detach(NULL); +} + +static void +create_pt_key(void) +{ + int ret; + + /* The main thread may not execute TLS destructors */ + atexit(atexit_del_tls_for_thread); + ret = pthread_key_create(&pt_key, heim_w32_service_thread_detach); + if (ret != 0) + err(1, "pthread_key_create() failed"); +} + +#endif + +int +heim_w32_key_create(HEIM_PRIV_thread_key *key, void (*dtor)(void *)) +{ + tls_keys *key_defs, *new_key_defs; + size_t i, k; + int ret = ENOMEM; + +#if !defined(WIN32) + (void) pthread_once(&pt_once, create_pt_key); + (void) pthread_setspecific(pt_key, dead_key); +#endif + + HEIMDAL_MUTEX_lock(&tls_key_defs_lock); + if (tls_key_defs == NULL) { + /* First key */ + new_key_defs = calloc(1, sizeof(*new_key_defs)); + if (new_key_defs == NULL) { + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + return ENOMEM; + } + new_key_defs->keys_num = 8; + new_key_defs->keys_dtors = calloc(new_key_defs->keys_num, + sizeof(*new_key_defs->keys_dtors)); + if (new_key_defs->keys_dtors == NULL) { + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + free(new_key_defs); + return ENOMEM; + } + tls_key_defs = new_key_defs; + new_key_defs->keys_dtors[0] = dtor; + for (i = 1; i < new_key_defs->keys_num; i++) + new_key_defs->keys_dtors[i] = NULL; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + return 0; + } + + for (key_defs = tls_key_defs; + key_defs != NULL; + key_defs = key_defs->keys_next) { + k = key_defs->keys_start_idx; + for (i = 0; i < key_defs->keys_num; i++, k++) { + if (key_defs->keys_dtors[i] == NULL) { + /* Found free slot; use it */ + key_defs->keys_dtors[i] = dtor; + *key = k; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + return 0; + } + } + if (key_defs->keys_next != NULL) + continue; + + /* Grow the registration array */ + /* XXX DRY */ + new_key_defs = calloc(1, sizeof(*new_key_defs)); + if (new_key_defs == NULL) + break; + + new_key_defs->keys_dtors = + calloc(key_defs->keys_num + key_defs->keys_num / 2, + sizeof(*new_key_defs->keys_dtors)); + if (new_key_defs->keys_dtors == NULL) { + free(new_key_defs); + break; + } + new_key_defs->keys_start_idx = key_defs->keys_start_idx + + key_defs->keys_num; + new_key_defs->keys_num = key_defs->keys_num + key_defs->keys_num / 2; + new_key_defs->keys_dtors[i] = dtor; + for (i = 1; i < new_key_defs->keys_num; i++) + new_key_defs->keys_dtors[i] = NULL; + key_defs->keys_next = new_key_defs; + ret = 0; + break; + } + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + return ret; +} + +static void +key_lookup(HEIM_PRIV_thread_key key, tls_keys **kd, + size_t *dtor_idx, void (**dtor)(void *)) +{ + tls_keys *key_defs; + + if (kd != NULL) + *kd = NULL; + if (dtor_idx != NULL) + *dtor_idx = 0; + if (dtor != NULL) + *dtor = NULL; + + HEIMDAL_MUTEX_lock(&tls_key_defs_lock); + key_defs = tls_key_defs; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + + while (key_defs != NULL) { + if (key >= key_defs->keys_start_idx && + key < key_defs->keys_start_idx + key_defs->keys_num) { + if (kd != NULL) + *kd = key_defs; + if (dtor_idx != NULL) + *dtor_idx = key - key_defs->keys_start_idx; + if (dtor != NULL) + *dtor = key_defs->keys_dtors[key - key_defs->keys_start_idx]; + return; + } + + HEIMDAL_MUTEX_lock(&tls_key_defs_lock); + key_defs = key_defs->keys_next; + HEIMDAL_MUTEX_unlock(&tls_key_defs_lock); + assert(key_defs != NULL); + assert(key >= key_defs->keys_start_idx); + } +} + +int +heim_w32_delete_key(HEIM_PRIV_thread_key key) +{ + tls_keys *key_defs; + size_t dtor_idx; + + key_lookup(key, &key_defs, &dtor_idx, NULL); + if (key_defs == NULL) + return EINVAL; + key_defs->keys_dtors[dtor_idx] = no_dtor; + return 0; +} + +int +heim_w32_setspecific(HEIM_PRIV_thread_key key, void *value) +{ + void **new_values; + size_t new_num; + void (*dtor)(void *); + size_t i; + +#if !defined(WIN32) + (void) pthread_setspecific(pt_key, dead_key); +#endif + + key_lookup(key, NULL, NULL, &dtor); + if (dtor == NULL) + return EINVAL; + + if (key >= values.values_num) { + if (values.values_num == 0) { + values.values = NULL; + new_num = 8; + } else { + new_num = (values.values_num + values.values_num / 2); + } + new_values = realloc(values.values, sizeof(void *) * new_num); + if (new_values == NULL) + return ENOMEM; + for (i = values.values_num; i < new_num; i++) + new_values[i] = NULL; + values.values = new_values; + values.values_num = new_num; + } + + assert(key < values.values_num); + + if (values.values[key] != NULL && dtor != NULL && dtor != no_dtor) + dtor(values.values[key]); + + values.values[key] = value; + return 0; +} + +void * +heim_w32_getspecific(HEIM_PRIV_thread_key key) +{ + if (key >= values.values_num) + return NULL; + return values.values[key]; +} + +#else +static char dummy; +#endif /* HEIM_WIN32_TLS */ diff --git a/third_party/heimdal/lib/base/error.c b/third_party/heimdal/lib/base/error.c new file mode 100644 index 0000000..bc289d3 --- /dev/null +++ b/third_party/heimdal/lib/base/error.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +struct heim_error { + int error_code; + heim_string_t msg; + struct heim_error *next; +}; + +static void HEIM_CALLCONV +error_dealloc(void *ptr) +{ + struct heim_error *p = ptr; + heim_release(p->msg); + heim_release(p->next); +} + +static int +error_cmp(void *a, void *b) +{ + struct heim_error *ap = a, *bp = b; + if (ap->error_code == bp->error_code) + return 0; + return heim_cmp(ap->msg, bp->msg); +} + +static uintptr_t +error_hash(void *ptr) +{ + struct heim_error *p = ptr; + return p->error_code; +} + +struct heim_type_data _heim_error_object = { + HEIM_TID_ERROR, + "error-object", + NULL, + error_dealloc, + NULL, + error_cmp, + error_hash, + NULL +}; + +heim_error_t +heim_error_create_enomem(void) +{ + /* This is an immediate object; see heim_number_create() */ + return (heim_error_t)heim_number_create(ENOMEM); +} + + +void +heim_error_create_opt(heim_error_t *error, int error_code, const char *fmt, ...) + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 3, 4)) +{ + if (error) { + va_list ap; + va_start(ap, fmt); + *error = heim_error_createv(error_code, fmt, ap); + va_end(ap); + } +} + +heim_error_t +heim_error_create(int error_code, const char *fmt, ...) + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 2, 3)) +{ + heim_error_t e; + va_list ap; + + va_start(ap, fmt); + e = heim_error_createv(error_code, fmt, ap); + va_end(ap); + + return e; +} + +heim_error_t +heim_error_createv(int error_code, const char *fmt, va_list ap) + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 2, 0)) +{ + heim_error_t e; + char *str; + int len; + int save_errno = errno; + + str = malloc(1024); + errno = save_errno; + if (str == NULL) + return heim_error_create_enomem(); + len = vsnprintf(str, 1024, fmt, ap); + errno = save_errno; + if (len < 0) { + free(str); + return NULL; /* XXX We should have a special heim_error_t for this */ + } + + e = _heim_alloc_object(&_heim_error_object, sizeof(struct heim_error)); + if (e) { + e->msg = heim_string_create(str); + e->error_code = error_code; + } + free(str); + + errno = save_errno; + return e; +} + +heim_string_t +heim_error_copy_string(heim_error_t error) +{ + if (heim_get_tid(error) != HEIM_TID_ERROR) { + if (heim_get_tid(error) == heim_number_get_type_id()) + return __heim_string_constant(strerror(heim_number_get_int((heim_number_t)error))); + heim_abort("invalid heim_error_t"); + } + /* XXX concat all strings */ + return heim_retain(error->msg); +} + +int +heim_error_get_code(heim_error_t error) +{ + if (error == NULL) + return -1; + if (heim_get_tid(error) != HEIM_TID_ERROR) { + if (heim_get_tid(error) == heim_number_get_type_id()) + return heim_number_get_int((heim_number_t)error); + heim_abort("invalid heim_error_t"); + } + return error->error_code; +} + +heim_error_t +heim_error_append(heim_error_t top, heim_error_t append) +{ + if (heim_get_tid(top) != HEIM_TID_ERROR) { + if (heim_get_tid(top) == heim_number_get_type_id()) + return top; + heim_abort("invalid heim_error_t"); + } + if (top->next) + heim_release(top->next); + top->next = heim_retain(append); + return top; +} diff --git a/third_party/heimdal/lib/base/error_string.c b/third_party/heimdal/lib/base/error_string.c new file mode 100644 index 0000000..a562833 --- /dev/null +++ b/third_party/heimdal/lib/base/error_string.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2001, 2003, 2005 - 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +#undef __attribute__ +#define __attribute__(x) + +void +heim_clear_error_message(heim_context context) +{ + if (!context) + return; + if (context->error_string) + free(context->error_string); + context->error_code = 0; + context->error_string = NULL; +} + +void +heim_set_error_message(heim_context context, heim_error_code ret, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) +{ + va_list ap; + + va_start(ap, fmt); + if (context) + heim_vset_error_message(context, ret, fmt, ap); + va_end(ap); +} + +void +heim_vset_error_message(heim_context context, heim_error_code ret, + const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + int r; + + if (context == NULL) + return; + if (context->error_string) { + free(context->error_string); + context->error_string = NULL; + } + context->error_code = ret; + r = vasprintf(&context->error_string, fmt, args); + if (r < 0) + context->error_string = NULL; + if (context->error_string) + heim_debug(context, 200, "error message: %s: %d", context->error_string, ret); +} + +void +heim_prepend_error_message(heim_context context, heim_error_code ret, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) +{ + va_list ap; + + va_start(ap, fmt); + heim_vprepend_error_message(context, ret, fmt, ap); + va_end(ap); +} + +void +heim_vprepend_error_message(heim_context context, heim_error_code ret, + const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + char *str = NULL, *str2 = NULL; + + if (context == NULL || context->error_code != ret || + vasprintf(&str, fmt, args) < 0 || str == NULL) + return; + if (context->error_string) { + int e; + + e = asprintf(&str2, "%s: %s", str, context->error_string); + free(context->error_string); + if (e < 0 || str2 == NULL) + context->error_string = NULL; + else + context->error_string = str2; + free(str); + } else + context->error_string = str; +} + +const char * +heim_get_error_message(heim_context context, heim_error_code code) +{ + const char *cstr = NULL; + char *str = NULL; + char buf[128]; + int free_context = 0; + + if (code == 0) + return strdup("Success"); + + /* + * The MIT version of this function ignores the krb5_context + * and several widely deployed applications call krb5_get_error_message() + * with a NULL context in order to translate an error code as a + * replacement for error_message(). Another reason a NULL context + * might be provided is if the krb5_init_context() call itself + * failed. + */ + if (context && + context->error_string && + (code == context->error_code || context->error_code == 0) && + (cstr = strdup(context->error_string))) + return cstr; + + if (context == NULL && (context = heim_context_init())) + free_context = 1; + if (context) + cstr = com_right_r(context->et_list, code, buf, sizeof(buf)); + if (free_context) + heim_context_free(&context); + + if (cstr || (cstr = error_message(code))) + return strdup(cstr); + if (asprintf(&str, "", (int)code) == -1 || str == NULL) + return NULL; + return str; +} + +const char * +heim_get_error_string(heim_context context) +{ + if (context && context->error_string) + return strdup(context->error_string); + return NULL; +} + +int +heim_have_error_string(heim_context context) +{ + return context && context->error_string != NULL; +} + +void +heim_free_error_message(heim_context context, const char *msg) +{ + free(rk_UNCONST(msg)); +} diff --git a/third_party/heimdal/lib/base/expand_path.c b/third_party/heimdal/lib/base/expand_path.c new file mode 100644 index 0000000..cf24991 --- /dev/null +++ b/third_party/heimdal/lib/base/expand_path.c @@ -0,0 +1,725 @@ + +/*********************************************************************** + * Copyright (c) 2009-2020, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include "baselocl.h" + +#include + +typedef int PTYPE; + +#ifdef _WIN32 +#include +#include + +/* + * Expand a %{TEMP} token + * + * The %{TEMP} token expands to the temporary path for the current + * user as returned by GetTempPath(). + * + * @note: Since the GetTempPath() function relies on the TMP or TEMP + * environment variables, this function will failover to the system + * temporary directory until the user profile is loaded. In addition, + * the returned path may or may not exist. + */ +static heim_error_code +expand_temp_folder(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + TCHAR tpath[MAX_PATH]; + size_t len; + + if (!GetTempPath(sizeof(tpath)/sizeof(tpath[0]), tpath)) { + heim_set_error_message(context, EINVAL, + "Failed to get temporary path (GLE=%d)", + GetLastError()); + return EINVAL; + } + + len = strlen(tpath); + + if (len > 0 && tpath[len - 1] == '\\') + tpath[len - 1] = '\0'; + + *ret = strdup(tpath); + + if (*ret == NULL) + return heim_enomem(context); + + return 0; +} + +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + +/* + * Expand a %{BINDIR} token + * + * This is also used to expand a few other tokens on Windows, since + * most of the executable binaries end up in the same directory. The + * "bin" directory is considered to be the directory in which the + * containing DLL is located. + */ +static heim_error_code +expand_bin_dir(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + TCHAR path[MAX_PATH]; + TCHAR *lastSlash; + DWORD nc; + + nc = GetModuleFileName((HINSTANCE)&__ImageBase, path, + sizeof(path)/sizeof(path[0])); + if (nc == 0 || + nc == sizeof(path)/sizeof(path[0])) { + return EINVAL; + } + + lastSlash = strrchr(path, '\\'); + if (lastSlash != NULL) { + TCHAR *fslash = strrchr(lastSlash, '/'); + + if (fslash != NULL) + lastSlash = fslash; + + *lastSlash = '\0'; + } + + if (postfix) { + if (strlcat(path, postfix, sizeof(path)/sizeof(path[0])) >= sizeof(path)/sizeof(path[0])) + return EINVAL; + } + + *ret = strdup(path); + if (*ret == NULL) + return heim_enomem(context); + + return 0; +} + +/* + * Expand a %{USERID} token + * + * The %{USERID} token expands to the string representation of the + * user's SID. The user account that will be used is the account + * corresponding to the current thread's security token. This means + * that: + * + * - If the current thread token has the anonymous impersonation + * level, the call will fail. + * + * - If the current thread is impersonating a token at + * SecurityIdentification level the call will fail. + * + */ +static heim_error_code +expand_userid(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + int rv = EINVAL; + HANDLE hThread = NULL; + HANDLE hToken = NULL; + PTOKEN_OWNER pOwner = NULL; + DWORD len = 0; + LPTSTR strSid = NULL; + + hThread = GetCurrentThread(); + + if (!OpenThreadToken(hThread, TOKEN_QUERY, + FALSE, /* Open the thread token as the + current thread user. */ + &hToken)) { + + DWORD le = GetLastError(); + + if (le == ERROR_NO_TOKEN) { + HANDLE hProcess = GetCurrentProcess(); + + le = 0; + if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) + le = GetLastError(); + } + + if (le != 0) { + heim_set_error_message(context, rv, + "Can't open thread token (GLE=%d)", le); + goto _exit; + } + } + + if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &len)) { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + heim_set_error_message(context, rv, + "Unexpected error reading token information (GLE=%d)", + GetLastError()); + goto _exit; + } + + if (len == 0) { + heim_set_error_message(context, rv, + "GetTokenInformation() returned truncated buffer"); + goto _exit; + } + + pOwner = malloc(len); + if (pOwner == NULL) { + heim_set_error_message(context, rv, "Out of memory"); + goto _exit; + } + } else { + heim_set_error_message(context, rv, "GetTokenInformation() returned truncated buffer"); + goto _exit; + } + + if (!GetTokenInformation(hToken, TokenOwner, pOwner, len, &len)) { + heim_set_error_message(context, rv, + "GetTokenInformation() failed. GLE=%d", + GetLastError()); + goto _exit; + } + + if (!ConvertSidToStringSid(pOwner->Owner, &strSid)) { + heim_set_error_message(context, rv, + "Can't convert SID to string. GLE=%d", + GetLastError()); + goto _exit; + } + + *ret = strdup(strSid); + if (*ret == NULL) + heim_set_error_message(context, rv, "Out of memory"); + + rv = 0; + + _exit: + if (hToken != NULL) + CloseHandle(hToken); + + if (pOwner != NULL) + free (pOwner); + + if (strSid != NULL) + LocalFree(strSid); + + return rv; +} + +/* + * Expand a folder identified by a CSIDL + */ + +static heim_error_code +expand_csidl(heim_context context, PTYPE folder, const char *postfix, + const char *arg, char **ret) +{ + TCHAR path[MAX_PATH]; + size_t len; + + if (SHGetFolderPath(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path) != S_OK) { + heim_set_error_message(context, EINVAL, "Unable to determine folder path"); + return EINVAL; + } + + len = strlen(path); + + if (len > 0 && path[len - 1] == '\\') + path[len - 1] = '\0'; + + if (postfix && + strlcat(path, postfix, sizeof(path)/sizeof(path[0])) >= sizeof(path)/sizeof(path[0])) + return heim_enomem(context); + + *ret = strdup(path); + if (*ret == NULL) + return heim_enomem(context); + return 0; +} + +#else + +static heim_error_code +expand_path(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + *ret = strdup(postfix); + if (*ret == NULL) + return heim_enomem(context); + return 0; +} + +static heim_error_code +expand_temp_folder(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + const char *p = NULL; + + p = secure_getenv("TEMP"); + + if (p) + *ret = strdup(p); + else + *ret = strdup("/tmp"); + if (*ret == NULL) + return heim_enomem(context); + return 0; +} + +static heim_error_code +expand_userid(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **str) +{ + int ret = asprintf(str, "%ld", (unsigned long)getuid()); + if (ret < 0 || *str == NULL) + return heim_enomem(context); + return 0; +} + +static heim_error_code +expand_euid(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **str) +{ + int ret = asprintf(str, "%ld", (unsigned long)geteuid()); + if (ret < 0 || *str == NULL) + return heim_enomem(context); + return 0; +} +#endif /* _WIN32 */ + +static heim_error_code +expand_home(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **str) +{ + char homedir[MAX_PATH]; + int ret; + + if (roken_get_homedir(homedir, sizeof(homedir))) + ret = asprintf(str, "%s", homedir); + else + ret = asprintf(str, "/unknown"); + if (ret < 0 || *str == NULL) + return heim_enomem(context); + return 0; +} + +static heim_error_code +expand_username(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **str) +{ + char user[128]; + const char *username = roken_get_username(user, sizeof(user)); + + if (username == NULL) { + heim_set_error_message(context, ENOTTY, + N_("unable to figure out current principal", + "")); + return ENOTTY; /* XXX */ + } + + *str = strdup(username); + if (*str == NULL) + return heim_enomem(context); + + return 0; +} + +static heim_error_code +expand_loginname(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **str) +{ + char user[128]; + const char *username = roken_get_loginname(user, sizeof(user)); + + if (username == NULL) { + heim_set_error_message(context, ENOTTY, + N_("unable to figure out current principal", + "")); + return ENOTTY; /* XXX */ + } + + *str = strdup(username); + if (*str == NULL) + return heim_enomem(context); + + return 0; +} + +static heim_error_code +expand_strftime(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + size_t len; + time_t t; + char buf[1024]; + + t = time(NULL); + len = strftime(buf, sizeof(buf), arg, localtime(&t)); + if (len == 0 || len >= sizeof(buf)) + return heim_enomem(context); + *ret = strdup(buf); + return 0; +} + +/** + * Expand an extra token + */ + +static heim_error_code +expand_extra_token(heim_context context, const char *value, char **ret) +{ + *ret = strdup(value); + if (*ret == NULL) + return heim_enomem(context); + return 0; +} + +/** + * Expand a %{null} token + * + * The expansion of a %{null} token is always the empty string. + */ + +static heim_error_code +expand_null(heim_context context, PTYPE param, const char *postfix, + const char *arg, char **ret) +{ + *ret = strdup(""); + if (*ret == NULL) + return heim_enomem(context); + return 0; +} + + +static const struct { + const char * tok; + int ftype; +#define FTYPE_CSIDL 0 +#define FTYPE_SPECIAL 1 + + PTYPE param; + const char * postfix; + + int (*exp_func)(heim_context, PTYPE, const char *, const char *, char **); + +#define SPECIALP(f, P) FTYPE_SPECIAL, 0, P, f +#define SPECIAL(f) SPECIALP(f, NULL) + +} tokens[] = { +#ifdef _WIN32 +#define CSIDLP(C,P) FTYPE_CSIDL, C, P, expand_csidl +#define CSIDL(C) CSIDLP(C, NULL) + + {"APPDATA", CSIDL(CSIDL_APPDATA)}, /* Roaming application data (for current user) */ + {"COMMON_APPDATA", CSIDL(CSIDL_COMMON_APPDATA)}, /* Application data (all users) */ + {"LOCAL_APPDATA", CSIDL(CSIDL_LOCAL_APPDATA)}, /* Local application data (for current user) */ + {"SYSTEM", CSIDL(CSIDL_SYSTEM)}, /* Windows System folder (e.g. %WINDIR%\System32) */ + {"WINDOWS", CSIDL(CSIDL_WINDOWS)}, /* Windows folder */ + {"USERCONFIG", CSIDLP(CSIDL_APPDATA, "\\" PACKAGE)}, /* Per user Heimdal configuration file path */ + {"COMMONCONFIG", CSIDLP(CSIDL_COMMON_APPDATA, "\\" PACKAGE)}, /* Common Heimdal configuration file path */ + {"LIBDIR", SPECIAL(expand_bin_dir)}, + {"BINDIR", SPECIAL(expand_bin_dir)}, + {"LIBEXEC", SPECIAL(expand_bin_dir)}, + {"SBINDIR", SPECIAL(expand_bin_dir)}, +#else + {"LOCALSTATEDIR", FTYPE_SPECIAL, 0, LOCALSTATEDIR, expand_path}, + {"LIBDIR", FTYPE_SPECIAL, 0, LIBDIR, expand_path}, + {"BINDIR", FTYPE_SPECIAL, 0, BINDIR, expand_path}, + {"LIBEXEC", FTYPE_SPECIAL, 0, LIBEXECDIR, expand_path}, + {"SBINDIR", FTYPE_SPECIAL, 0, SBINDIR, expand_path}, + {"USERCONFIG", SPECIAL(expand_home)}, /* same as %{HOME} on not-Windows */ + {"euid", SPECIAL(expand_euid)}, + {"ruid", SPECIAL(expand_userid)}, + {"loginname", SPECIAL(expand_loginname)}, +#endif + {"username", SPECIAL(expand_username)}, + {"TEMP", SPECIAL(expand_temp_folder)}, + {"USERID", SPECIAL(expand_userid)}, + {"uid", SPECIAL(expand_userid)}, + {"null", SPECIAL(expand_null)}, + {"strftime", SPECIAL(expand_strftime)}, + {"HOME", SPECIAL(expand_home)}, +}; + +static heim_error_code +expand_token(heim_context context, + const char *token, + const char *token_end, + char **extra_tokens, + char **ret) +{ + heim_error_code errcode; + size_t i; + char **p; + const char *colon; + + *ret = NULL; + + if (token[0] != '%' || token[1] != '{' || token_end[0] != '}' || + token_end - token <= 2) { + heim_set_error_message(context, EINVAL,"Invalid token."); + return EINVAL; + } + + for (p = extra_tokens; p && p[0]; p += 2) { + if (strncmp(token+2, p[0], (token_end - token) - 2) == 0) + return expand_extra_token(context, p[1], ret); + } + + for (colon=token+2; colon < token_end; colon++) + if (*colon == ':') + break; + + for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) + if (!strncmp(token+2, tokens[i].tok, (colon - token) - 2)) { + char *arg = NULL; + + errcode = 0; + if (*colon == ':') { + int asprintf_ret = asprintf(&arg, "%.*s", + (int)(token_end - colon - 1), + colon + 1); + if (asprintf_ret < 0 || !arg) + errcode = ENOMEM; + } + if (!errcode) + errcode = tokens[i].exp_func(context, tokens[i].param, + tokens[i].postfix, arg, ret); + free(arg); + return errcode; + } + + heim_set_error_message(context, EINVAL, "Invalid token."); + return EINVAL; +} + +/** + * Internal function to expand tokens in paths. + * + * Params: + * + * @context A heim_context + * @path_in The path to expand tokens from + * @filepath True if this is a filesystem path (converts slashes to + * backslashes on Windows) + * @ppath_out The expanded path + * @... Variable number of pairs of strings, the first of each + * being a token (e.g., "luser") and the second a string to + * replace it with. The list is terminated by a NULL. + */ +heim_error_code +heim_expand_path_tokens(heim_context context, + const char *path_in, + int filepath, + char **ppath_out, + ...) +{ + heim_error_code ret; + va_list ap; + + va_start(ap, ppath_out); + ret = heim_expand_path_tokensv(context, path_in, filepath, ppath_out, ap); + va_end(ap); + + return ret; +} + +static void +free_extra_tokens(char **extra_tokens) +{ + char **p; + + for (p = extra_tokens; p && *p; p++) + free(*p); + free(extra_tokens); +} + +/** + * Internal function to expand tokens in paths. + * + * Inputs: + * + * @context A heim_context + * @path_in The path to expand tokens from + * @filepath True if this is a filesystem path (converts slashes to + * backslashes on Windows) + * @ppath_out The expanded path + * @ap A NULL-terminated va_list of pairs of strings, the first of each + * being a token (e.g., "luser") and the second a string to replace + * it with. + * + * Outputs: + * + * @ppath_out Path with expanded tokens (caller must free() this) + */ +heim_error_code +heim_expand_path_tokensv(heim_context context, + const char *path_in, + int filepath, + char **ppath_out, va_list ap) +{ + char *tok_begin, *tok_end, *append; + char **extra_tokens = NULL; + const char *path_left; + size_t nargs = 0; + size_t len = 0; + va_list ap2; + + if (path_in == NULL || *path_in == '\0') { + *ppath_out = strdup(""); + return 0; + } + + *ppath_out = NULL; + +#if defined(_MSC_VER) + ap2 = ap; /* Come on! See SO #558223 */ +#else + va_copy(ap2, ap); +#endif + while (va_arg(ap2, const char *)) { + nargs++; + va_arg(ap2, const char *); + } + va_end(ap2); + nargs *= 2; + + /* Get extra tokens */ + if (nargs) { + size_t i; + + extra_tokens = calloc(nargs + 1, sizeof (*extra_tokens)); + if (extra_tokens == NULL) + return heim_enomem(context); + for (i = 0; i < nargs; i++) { + const char *s = va_arg(ap, const char *); /* token key */ + if (s == NULL) + break; + extra_tokens[i] = strdup(s); + if (extra_tokens[i++] == NULL) { + free_extra_tokens(extra_tokens); + return heim_enomem(context); + } + s = va_arg(ap, const char *); /* token value */ + if (s == NULL) + s = ""; + extra_tokens[i] = strdup(s); + if (extra_tokens[i] == NULL) { + free_extra_tokens(extra_tokens); + return heim_enomem(context); + } + } + } + + for (path_left = path_in; path_left && *path_left; ) { + + tok_begin = strstr(path_left, "%{"); + + if (tok_begin && tok_begin != path_left) { + + append = malloc((tok_begin - path_left) + 1); + if (append) { + memcpy(append, path_left, tok_begin - path_left); + append[tok_begin - path_left] = '\0'; + } + path_left = tok_begin; + + } else if (tok_begin) { + + tok_end = strchr(tok_begin, '}'); + if (tok_end == NULL) { + free_extra_tokens(extra_tokens); + if (*ppath_out) + free(*ppath_out); + *ppath_out = NULL; + heim_set_error_message(context, EINVAL, "variable missing }"); + return EINVAL; + } + + if (expand_token(context, tok_begin, tok_end, extra_tokens, + &append)) { + free_extra_tokens(extra_tokens); + if (*ppath_out) + free(*ppath_out); + *ppath_out = NULL; + return EINVAL; + } + + path_left = tok_end + 1; + } else { + + append = strdup(path_left); + path_left = NULL; + + } + + if (append == NULL) { + + free_extra_tokens(extra_tokens); + if (*ppath_out) + free(*ppath_out); + *ppath_out = NULL; + return heim_enomem(context); + + } + + { + size_t append_len = strlen(append); + char * new_str = realloc(*ppath_out, len + append_len + 1); + + if (new_str == NULL) { + free_extra_tokens(extra_tokens); + free(append); + if (*ppath_out) + free(*ppath_out); + *ppath_out = NULL; + return heim_enomem(context); + } + + *ppath_out = new_str; + memcpy(*ppath_out + len, append, append_len + 1); + len = len + append_len; + free(append); + } + } + +#ifdef _WIN32 + /* Also deal with slashes */ + if (filepath && *ppath_out) { + char * c; + + for (c = *ppath_out; *c; c++) + if (*c == '/') + *c = '\\'; + } +#endif + + free_extra_tokens(extra_tokens); + return 0; +} diff --git a/third_party/heimdal/lib/base/heim_err.et b/third_party/heimdal/lib/base/heim_err.et new file mode 100644 index 0000000..5532d9b --- /dev/null +++ b/third_party/heimdal/lib/base/heim_err.et @@ -0,0 +1,57 @@ +# +# Error messages for the krb5 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table heim + +prefix HEIM_ERR + +error_code LOG_PARSE, "Error parsing log destination" +error_code V4_PRINC_NO_CONV, "Failed to convert v4 principal" +error_code SALTTYPE_NOSUPP, "Salt type is not supported by enctype" +error_code NOHOST, "Host not found" +error_code OPNOTSUPP, "Operation not supported" +error_code EOF, "End of file" +error_code BAD_MKEY, "Failed to get the master key" +error_code SERVICE_NOMATCH, "Unacceptable service used" +error_code NOT_SEEKABLE, "File descriptor not seekable" +error_code TOO_BIG, "Offset too large" +error_code BAD_HDBENT_ENCODING, "Invalid HDB entry encoding" +error_code RANDOM_OFFLINE, "No random source available" +error_code CONFIG_BADFORMAT, "Improper format of configuration file" +error_code PA_CONTINUE_NEEDED, "Need to continue preauth stepping" +error_code PA_CANT_CONTINUE, "Can't continue with this preauth" +error_code NO_MORE_PA_MECHS, "No more PA mechanisms available" + +index 64 +prefix HEIM_PKINIT +error_code NO_CERTIFICATE, "Certificate missing" +error_code NO_PRIVATE_KEY, "Private key missing" +error_code NO_VALID_CA, "No valid certificate authority" +error_code CERTIFICATE_INVALID, "Certificate invalid" +error_code PRIVATE_KEY_INVALID, "Private key invalid" + +index 128 +prefix HEIM_EAI +#error_code NOERROR, "no error" +error_code UNKNOWN, "unknown error from getaddrinfo" +error_code ADDRFAMILY, "address family for nodename not supported" +error_code AGAIN, "temporary failure in name resolution" +error_code BADFLAGS, "invalid value for ai_flags" +error_code FAIL, "non-recoverable failure in name resolution" +error_code FAMILY, "ai_family not supported" +error_code MEMORY, "memory allocation failure" +error_code NODATA, "no address associated with nodename" +error_code NONAME, "nodename nor servname provided, or not known" +error_code SERVICE, "servname not supported for ai_socktype" +error_code SOCKTYPE, "ai_socktype not supported" +error_code SYSTEM, "system error returned in errno" + +index 192 +prefix HEIM_NET +error_code CONN_REFUSED, "connection refused" + +end diff --git a/third_party/heimdal/lib/base/heimbase-atomics.h b/third_party/heimdal/lib/base/heimbase-atomics.h new file mode 100644 index 0000000..e468a36 --- /dev/null +++ b/third_party/heimdal/lib/base/heimbase-atomics.h @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_BASE_ATOMICS_H +#define HEIM_BASE_ATOMICS_H 1 + +#include + +/* + * Atomic operations + * + * (#define HEIM_BASE_ATOMICS_FALLBACK to test fallbacks.) + */ + +#if !defined(HEIM_BASE_ATOMICS_FALLBACK) && defined(HAVE_STDATOMIC_H) + +#include + +#define heim_base_atomic_init(t, v) atomic_init(t, v) +#define heim_base_atomic_load(x) atomic_load((x)) +#define heim_base_atomic_store(t, v) atomic_store((t), (v)) + +#define heim_base_atomic(T) _Atomic(T) + +#define heim_base_atomic_inc_32(x) (atomic_fetch_add((x), 1) + 1) +#define heim_base_atomic_dec_32(x) (atomic_fetch_sub((x), 1) - 1) +#define heim_base_atomic_inc_64(x) (atomic_fetch_add((x), 1) + 1) +#define heim_base_atomic_dec_64(x) (atomic_fetch_sub((x), 1) - 1) + +#define heim_base_exchange_pointer(t,v) atomic_exchange((t), (v)) +#define heim_base_exchange_32(t,v) atomic_exchange((t), (v)) +#define heim_base_exchange_64(t,v) atomic_exchange((t), (v)) + +/* + * 's and AIX's CAS functions take a pointer to an expected value + * and return a boolean, setting the pointed-to variable to the old value of + * the target. + * + * Other CAS functions, like GCC's, Solaris'/Illumos', and Windows', return the + * old value and don't take a pointer to an expected value. + * + * We implement the latter semantics. + */ +static inline void * +heim_base_cas_pointer_(heim_base_atomic(void *)*t, void *e, void *d) +{ + return atomic_compare_exchange_strong(t, &e, d), e; +} + +static inline uint32_t +heim_base_cas_32_(heim_base_atomic(uint32_t)*t, uint32_t e, uint32_t d) +{ + return atomic_compare_exchange_strong(t, &e, d), e; +} + +static inline uint64_t +heim_base_cas_64_(heim_base_atomic(uint64_t)*t, uint64_t e, uint64_t d) +{ + return atomic_compare_exchange_strong(t, &e, d), e; +} + +#define heim_base_cas_pointer(t,e,d) heim_base_cas_pointer_((t), (e), (d)) +#define heim_base_cas_32(t,e,d) heim_base_cas_32_((t), (e), (d)) +#define heim_base_cas_64(t,e,d) heim_base_cas_64_((t), (e), (d)) + +#elif !defined(HEIM_BASE_ATOMICS_FALLBACK) && defined(__GNUC__) && defined(HAVE___SYNC_ADD_AND_FETCH) + +#define heim_base_atomic_barrier() __sync_synchronize() + +#define heim_base_atomic_inc_32(x) __sync_add_and_fetch((x), 1) +#define heim_base_atomic_dec_32(x) __sync_sub_and_fetch((x), 1) +#define heim_base_atomic_inc_64(x) __sync_add_and_fetch((x), 1) +#define heim_base_atomic_dec_64(x) __sync_sub_and_fetch((x), 1) + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__sync_swap) +#define heim_base_exchange_pointer(t,v) __sync_swap((t), (v)) +#else +/* FIXME: some targets may only write the value 1 into *t */ +#define heim_base_exchange_pointer(t,v) __sync_lock_test_and_set((t), (v)) +#endif + +#define heim_base_exchange_32(t,v) heim_base_exchange_pointer((t), (v)) +#define heim_base_exchange_64(t,v) heim_base_exchange_pointer((t), (v)) + +#define heim_base_cas_pointer(t,e,d) __sync_val_compare_and_swap((t), (e), (d)) +#define heim_base_cas_32(t,e,d) __sync_val_compare_and_swap((t), (e), (d)) +#define heim_base_cas_64(t,e,d) __sync_val_compare_and_swap((t), (e), (d)) + +#elif !defined(HEIM_BASE_ATOMICS_FALLBACK) && defined(__sun) + +#include +#include + +static inline void __heim_base_atomic_barrier(void) +{ + __machine_rw_barrier(); +} + +#define heim_base_atomic_barrier() __heim_base_atomic_barrier() + +#define heim_base_atomic(T) volatile T + +#define heim_base_atomic_inc_32(x) atomic_inc_32_nv((x)) +#define heim_base_atomic_dec_32(x) atomic_dec_32_nv((x)) +#define heim_base_atomic_inc_64(x) atomic_inc_64_nv((x)) +#define heim_base_atomic_dec_64(x) atomic_dec_64_nv((x)) + +#define heim_base_exchange_pointer(t,v) atomic_swap_ptr((t), (void *)(v)) +#define heim_base_exchange_32(t,v) atomic_swap_32((t), (v)) +#define heim_base_exchange_64(t,v) atomic_swap_64((t), (v)) + +#define heim_base_cas_pointer(t,e,d) atomic_cas_ptr((t), (e), (d)) +#define heim_base_cas_32(t,e,d) atomic_cas_32((t), (e), (d)) +#define heim_base_cas_64(t,e,d) atomic_cas_64((t), (e), (d)) + +#elif !defined(HEIM_BASE_ATOMICS_FALLBACK) && defined(_AIX) + +#include + +#define heim_base_atomic_barrier() __isync() + +#define heim_base_atomic_inc_32(x) (fetch_and_add((atomic_p)(x), 1) + 1) +#define heim_base_atomic_dec_32(x) (fetch_and_add((atomic_p)(x), -1) - 1) +#define heim_base_atomic_inc_64(x) (fetch_and_addlp((atomic_l)(x), 1) + 1) +#define heim_base_atomic_dec_64(x) (fetch_and_addlp((atomic_l)(x), -1) - 1) + +static inline void * +heim_base_exchange_pointer(void *p, void *newval) +{ + void *val = *(void **)p; + + while (!compare_and_swaplp((atomic_l)p, (long *)&val, (long)newval)) + ; + + return val; +} + +static inline uint32_t +heim_base_exchange_32(uint32_t *p, uint32_t newval) +{ + uint32_t val = *p; + + while (!compare_and_swap((atomic_p)p, (int *)&val, (int)newval)) + ; + + return val; +} + +static inline uint64_t +heim_base_exchange_64(uint64_t *p, uint64_t newval) +{ + uint64_t val = *p; + + while (!compare_and_swaplp((atomic_l)p, (long *)&val, (long)newval)) + ; + + return val; +} + +static inline void * +heim_base_cas_pointer_(heim_base_atomic(void *)*t, void *e, void *d) +{ + return compare_and_swaplp((atomic_l)t, &e, d), e; +} + +static inline uint32_t +heim_base_cas_32_(heim_base_atomic(uint32_t)*t, uint32_t e, uint32_t d) +{ + return compare_and_swap((atomic_p)t, &e, d), e; +} + +static inline uint64_t +heim_base_cas_64_(heim_base_atomic(uint64_t)*t, uint64_t e, uint64_t d) +{ + return compare_and_swaplp((atomic_l)t, &e, d), e; +} + +#define heim_base_cas_pointer(t,e,d) heim_base_cas_pointer_((t), (e), (d)) +#define heim_base_cas_32(t,e,d) heim_base_cas_32_((t), (e), (d)) +#define heim_base_cas_64(t,e,d) heim_base_cas_64_((t), (e), (d)) + +#elif !defined(HEIM_BASE_ATOMICS_FALLBACK) && defined(_WIN32) + +#define heim_base_atomic_barrier() MemoryBarrier() + +#define heim_base_atomic_inc_32(x) InterlockedIncrement(x) +#define heim_base_atomic_dec_32(x) InterlockedDecrement(x) +#define heim_base_atomic_inc_64(x) InterlockedIncrement64(x) +#define heim_base_atomic_dec_64(x) InterlockedDecrement64(x) + +#define heim_base_exchange_pointer(t,v) InterlockedExchangePointer((PVOID volatile *)(t), (PVOID)(v)) +#define heim_base_exchange_32(t,v) ((ULONG)InterlockedExchange((LONG volatile *)(t), (LONG)(v))) +#define heim_base_exchange_64(t,v) ((ULONG64)InterlockedExchange64((ULONG64 volatile *)(t), (LONG64)(v))) + +#define heim_base_cas_pointer(t,e,d) InterlockedCompareExchangePointer((PVOID volatile *)(t), (d), (e)) +#define heim_base_cas_32(t,e,d) InterlockedCompareExchange ((LONG volatile *)(t), (d), (e)) +#define heim_base_cas_64(t,e,d) InterlockedCompareExchange64((ULONG64 volatile *)(t), (d), (e)) + +#else + +#define heim_base_atomic(T) volatile T +#define heim_base_atomic_barrier() +#define heim_base_atomic_load(x) (*(x)) +#define heim_base_atomic_init(t, v) do { (*(t) = (v)); } while (0) +#define heim_base_atomic_store(t, v) do { (*(t) = (v)); } while (0) + +#include + +#define HEIM_BASE_NEED_ATOMIC_MUTEX 1 + +static inline uint32_t +heim_base_atomic_inc_32(heim_base_atomic(uint32_t) *x) +{ + uint32_t t; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + t = ++(*x); + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return t; +} + +static inline uint32_t +heim_base_atomic_dec_32(heim_base_atomic(uint32_t) *x) +{ + uint32_t t; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + t = --(*x); + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return t; +} + +static inline uint64_t +heim_base_atomic_inc_64(heim_base_atomic(uint64_t) *x) +{ + uint64_t t; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + t = ++(*x); + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return t; +} + +static inline uint64_t +heim_base_atomic_dec_64(heim_base_atomic(uint64_t) *x) +{ + uint64_t t; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + t = --(*x); + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return t; +} + +static inline void * +heim_base_exchange_pointer(heim_base_atomic(void *)target, void *value) +{ + void *old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + old = *(void **)target; + *(void **)target = value; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +static inline uint32_t +heim_base_exchange_32(heim_base_atomic(uint32_t) *target, uint32_t newval) +{ + uint32_t old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + old = *target; + *target = newval; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +static inline uint64_t +heim_base_exchange_64(heim_base_atomic(uint64_t) *target, uint64_t newval) +{ + uint64_t old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + old = *target; + *target = newval; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +static inline void * +heim_base_cas_pointer(heim_base_atomic(void *)target, void *expected, void *desired) +{ + void *old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + if ((old = *(void **)target) == expected) + *(void **)target = desired; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +static inline uint32_t +heim_base_cas_32(heim_base_atomic(uint32_t) *target, uint32_t expected, uint32_t desired) +{ + uint32_t old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + if ((old = *(uint32_t *)target) == expected) + *target = desired; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +static inline uint64_t +heim_base_cas_64(heim_base_atomic(uint64_t) *target, uint64_t expected,uint64_t desired) +{ + uint64_t old; + HEIMDAL_MUTEX_lock(heim_base_mutex()); + if ((old = *(uint64_t *)target) == expected) + *target = desired; + HEIMDAL_MUTEX_unlock(heim_base_mutex()); + return old; +} + +#endif /* defined(__GNUC__) && defined(HAVE___SYNC_ADD_AND_FETCH) */ + +#ifndef heim_base_atomic +#define heim_base_atomic(T) T +#endif + +#ifndef heim_base_atomic_barrier +static inline void heim_base_atomic_barrier(void) { return; } +#endif + +#ifndef heim_base_atomic_load +#define heim_base_atomic_load(x) (heim_base_atomic_barrier(), *(x)) +#endif + +#ifndef heim_base_atomic_init +#define heim_base_atomic_init(t, v) do { (*(t) = (v)); } while (0) +#endif + +#ifndef heim_base_atomic_store +#define heim_base_atomic_store(t, v) do { \ + (*(t) = (v)); \ + heim_base_atomic_barrier(); \ + } while (0) +#endif + +#if SIZEOF_TIME_T == 8 +#define heim_base_exchange_time_t(t,v) heim_base_exchange_64((t), (v)) +#elif SIZEOF_TIME_T == 4 +#define heim_base_exchange_time_t(t,v) heim_base_exchange_32((t), (v)) +#else +#error set SIZEOF_TIME_T for your platform +#endif + +#endif /* HEIM_BASE_ATOMICS_H */ diff --git a/third_party/heimdal/lib/base/heimbase-svc.h b/third_party/heimdal/lib/base/heimbase-svc.h new file mode 100644 index 0000000..6c2e02f --- /dev/null +++ b/third_party/heimdal/lib/base/heimbase-svc.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIMBASE_SVC_H +#define HEIMBASE_SVC_H 1 + +#include + +/* + * This file is meant to be included in services, which can + * + * #define heim_pcontext krb5_context + * + * or whatever is appropriate. + */ + +#define HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS \ + /* Input */ \ + heim_pcontext context; \ + heim_pconfig config; \ + heim_context hcontext; \ + heim_log_facility *logf; \ + const char *from; \ + struct sockaddr *addr; \ + int datagram_reply; \ + heim_octet_string request; \ + \ + /* Output */ \ + heim_octet_string *reply; \ + unsigned int use_request_t:1; \ + \ + /* Common state, to be freed in process.c */ \ + struct timeval tv_start; \ + struct timeval tv_end; \ + const char *reqtype; \ + char *cname; \ + char *sname; \ + const char *e_text; \ + heim_octet_string e_data; \ + char *e_text_buf; \ + heim_string_t reason; \ + /* auditing key/value store */ \ + heim_dict_t kv; \ + heim_dict_t attributes; \ + int32_t error_code + +#define HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(CONTEXT_TYPE) \ + int minor_version; \ + int (HEIM_LIB_CALL *init)(CONTEXT_TYPE, void **); \ + void (HEIM_LIB_CALL *fini)(void *) + +#endif /* HEIMBASE_SVC_H */ diff --git a/third_party/heimdal/lib/base/heimbase.c b/third_party/heimdal/lib/base/heimbase.c new file mode 100644 index 0000000..4e9ea1b --- /dev/null +++ b/third_party/heimdal/lib/base/heimbase.c @@ -0,0 +1,1104 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include "heimbase-atomics.h" +#include + +static heim_base_atomic(uint32_t) tidglobal = HEIM_TID_USER; + +struct heim_base { + heim_const_type_t isa; + heim_base_atomic(uint32_t) ref_cnt; + HEIM_TAILQ_ENTRY(heim_base) autorel; + heim_auto_release_t autorelpool; + uintptr_t isaextra[3]; +}; + +/* specialized version of base */ +struct heim_base_mem { + heim_const_type_t isa; + heim_base_atomic(uint32_t) ref_cnt; + HEIM_TAILQ_ENTRY(heim_base) autorel; + heim_auto_release_t autorelpool; + const char *name; + void (HEIM_CALLCONV *dealloc)(void *); + uintptr_t isaextra[1]; +}; + +#define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1) +#define BASE2PTR(ptr) ((void *)(((struct heim_base *)ptr) + 1)) + +HEIMDAL_MUTEX * HEIM_CALLCONV +heim_base_mutex(void) +{ + static HEIMDAL_MUTEX _heim_base_mutex = HEIMDAL_MUTEX_INITIALIZER; + return &_heim_base_mutex; +} + +/* + * Auto release structure + */ + +struct heim_auto_release { + HEIM_TAILQ_HEAD(, heim_base) pool; + HEIMDAL_MUTEX pool_mutex; + struct heim_auto_release *parent; +}; + + +/** + * Retain object (i.e., take a reference) + * + * @param object to be released, NULL is ok + * + * @return the same object as passed in + */ + +heim_object_t +heim_retain(heim_object_t ptr) +{ + struct heim_base *p; + + if (ptr == NULL || heim_base_is_tagged(ptr)) + return ptr; + + p = PTR2BASE(ptr); + + if (heim_base_atomic_load(&p->ref_cnt) == UINT32_MAX) + return ptr; + + if ((heim_base_atomic_inc_32(&p->ref_cnt) - 1) == 0) + heim_abort("resurection"); + return ptr; +} + +/** + * Release object, free if reference count reaches zero + * + * @param object to be released + */ + +void +heim_release(void *ptr) +{ + heim_base_atomic(uint32_t) old; + struct heim_base *p; + + if (ptr == NULL || heim_base_is_tagged(ptr)) + return; + + p = PTR2BASE(ptr); + + if (heim_base_atomic_load(&p->ref_cnt) == UINT32_MAX) + return; + + old = heim_base_atomic_dec_32(&p->ref_cnt) + 1; + + if (old > 1) + return; + + if (old == 1) { + heim_auto_release_t ar = p->autorelpool; + /* remove from autorel pool list */ + if (ar) { + p->autorelpool = NULL; + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); + } + if (p->isa->dealloc) + p->isa->dealloc(ptr); + free(p); + } else + heim_abort("over release"); +} + +/** + * If used require wrapped in autorelease pool + */ + +heim_string_t +heim_description(heim_object_t ptr) +{ + struct heim_base *p = PTR2BASE(ptr); + if (p->isa->desc == NULL) + return heim_auto_release(heim_string_ref_create(p->isa->name, NULL)); + return heim_auto_release(p->isa->desc(ptr)); +} + + +void +_heim_make_permanent(heim_object_t ptr) +{ + struct heim_base *p = PTR2BASE(ptr); + heim_base_atomic_store(&p->ref_cnt, UINT32_MAX); +} + + +static heim_type_t tagged_isa[9] = { + &_heim_number_object, + &_heim_null_object, + &_heim_bool_object, + + NULL, + NULL, + NULL, + + NULL, + NULL, + NULL +}; + +heim_const_type_t +_heim_get_isa(heim_object_t ptr) +{ + struct heim_base *p; + if (heim_base_is_tagged(ptr)) { + if (heim_base_is_tagged_object(ptr)) + return tagged_isa[heim_base_tagged_object_tid(ptr)]; + heim_abort("not a supported tagged type"); + } + p = PTR2BASE(ptr); + return p->isa; +} + +/** + * Get type ID of object + * + * @param object object to get type id of + * + * @return type id of object + */ + +heim_tid_t +heim_get_tid(heim_object_t ptr) +{ + heim_const_type_t isa = _heim_get_isa(ptr); + return isa->tid; +} + +/** + * Get hash value of object + * + * @param object object to get hash value for + * + * @return a hash value + */ + +uintptr_t +heim_get_hash(heim_object_t ptr) +{ + heim_const_type_t isa = _heim_get_isa(ptr); + if (isa->hash) + return isa->hash(ptr); + return (uintptr_t)ptr; +} + +/** + * Compare two objects, returns 0 if equal, can use used for qsort() + * and friends. + * + * @param a first object to compare + * @param b first object to compare + * + * @return 0 if objects are equal + */ + +int +heim_cmp(heim_object_t a, heim_object_t b) +{ + heim_tid_t ta, tb; + heim_const_type_t isa; + + ta = heim_get_tid(a); + tb = heim_get_tid(b); + + if (ta != tb) + return ta - tb; + + isa = _heim_get_isa(a); + + if (isa->cmp) + return isa->cmp(a, b); + + return (uintptr_t)a - (uintptr_t)b; +} + +/* + * Private - allocates an memory object + */ + +static void HEIM_CALLCONV +memory_dealloc(void *ptr) +{ + if (ptr) { + struct heim_base_mem *p = (struct heim_base_mem *)PTR2BASE(ptr); + + if (p->dealloc) + p->dealloc(ptr); + } +} + +static const struct heim_type_data memory_object = { + HEIM_TID_MEMORY, + "memory-object", + NULL, + memory_dealloc, + NULL, + NULL, + NULL, + NULL +}; + +/** + * Allocate memory for an object of anonymous type + * + * @param size size of object to be allocated + * @param name name of ad-hoc type + * @param dealloc destructor function + * + * Objects allocated with this interface do not serialize. + * + * @return allocated object + */ + +void * +heim_alloc(size_t size, const char *name, heim_type_dealloc dealloc) +{ + /* XXX use posix_memalign */ + + struct heim_base_mem *p = calloc(1, size + sizeof(*p)); + if (p == NULL) + return NULL; + p->isa = &memory_object; + p->ref_cnt = 1; + p->name = name; + p->dealloc = dealloc; + return BASE2PTR(p); +} + +heim_type_t +_heim_create_type(const char *name, + heim_type_init init, + heim_type_dealloc dealloc, + heim_type_copy copy, + heim_type_cmp cmp, + heim_type_hash hash, + heim_type_description desc) +{ + heim_type_t type; + + type = calloc(1, sizeof(*type)); + if (type == NULL) + return NULL; + + type->tid = heim_base_atomic_inc_32(&tidglobal); + type->name = name; + type->init = init; + type->dealloc = dealloc; + type->copy = copy; + type->cmp = cmp; + type->hash = hash; + type->desc = desc; + + return type; +} + +heim_object_t +_heim_alloc_object(heim_const_type_t type, size_t size) +{ + /* XXX should use posix_memalign */ + struct heim_base *p = calloc(1, size + sizeof(*p)); + if (p == NULL) + return NULL; + p->isa = type; + p->ref_cnt = 1; + + return BASE2PTR(p); +} + +void * +_heim_get_isaextra(heim_object_t ptr, size_t idx) +{ + struct heim_base *p; + + heim_assert(ptr != NULL, "internal error"); + p = (struct heim_base *)PTR2BASE(ptr); + if (p->isa == &memory_object) + return NULL; + heim_assert(idx < 3, "invalid private heim_base extra data index"); + return &p->isaextra[idx]; +} + +heim_tid_t +_heim_type_get_tid(heim_type_t type) +{ + return type->tid; +} + +#if !defined(WIN32) && !defined(HAVE_DISPATCH_DISPATCH_H) && defined(ENABLE_PTHREAD_SUPPORT) +static pthread_once_t once_arg_key_once = PTHREAD_ONCE_INIT; +static pthread_key_t once_arg_key; + +static void +once_arg_key_once_init(void) +{ + errno = pthread_key_create(&once_arg_key, NULL); + if (errno != 0) { + fprintf(stderr, + "Error: pthread_key_create() failed, cannot continue: %s\n", + strerror(errno)); + abort(); + } +} + +struct once_callback { + void (*fn)(void *); + void *data; +}; + +static void +once_callback_caller(void) +{ + struct once_callback *once_callback = pthread_getspecific(once_arg_key); + + if (once_callback == NULL) { + fprintf(stderr, "Error: pthread_once() calls callback on " + "different thread?! Cannot continue.\n"); + abort(); + } + once_callback->fn(once_callback->data); +} +#endif + +/** + * Call func once and only once + * + * @param once pointer to a heim_base_once_t + * @param ctx context passed to func + * @param func function to be called + */ + +void +heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *)) +{ +#if defined(WIN32) + /* + * With a libroken wrapper for some CAS function and a libroken yield() + * wrapper we could make this the default implementation when we have + * neither Grand Central nor POSX threads. + * + * We could also adapt the double-checked lock pattern with CAS + * providing the necessary memory barriers in the absence of + * portable explicit memory barrier APIs. + */ + /* + * We use CAS operations in large part to provide implied memory + * barriers. + * + * State 0 means that func() has never executed. + * State 1 means that func() is executing. + * State 2 means that func() has completed execution. + */ + if (InterlockedCompareExchange(once, 1L, 0L) == 0L) { + /* State is now 1 */ + (*func)(ctx); + (void)InterlockedExchange(once, 2L); + /* State is now 2 */ + } else { + /* + * The InterlockedCompareExchange is being used to fetch + * the current state under a full memory barrier. As long + * as the current state is 1 continue to spin. + */ + while (InterlockedCompareExchange(once, 2L, 0L) == 1L) + SwitchToThread(); + } +#elif defined(HAVE_DISPATCH_DISPATCH_H) + dispatch_once_f(once, ctx, func); +#elif defined(ENABLE_PTHREAD_SUPPORT) + struct once_callback once_callback; + + once_callback.fn = func; + once_callback.data = ctx; + + errno = pthread_once(&once_arg_key_once, once_arg_key_once_init); + if (errno != 0) { + fprintf(stderr, "Error: pthread_once() failed, cannot continue: %s\n", + strerror(errno)); + abort(); + } + errno = pthread_setspecific(once_arg_key, &once_callback); + if (errno != 0) { + fprintf(stderr, + "Error: pthread_setspecific() failed, cannot continue: %s\n", + strerror(errno)); + abort(); + } + errno = pthread_once(once, once_callback_caller); + if (errno != 0) { + fprintf(stderr, "Error: pthread_once() failed, cannot continue: %s\n", + strerror(errno)); + abort(); + } +#else + static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; + HEIMDAL_MUTEX_lock(&mutex); + if (*once == 0) { + *once = 1; + HEIMDAL_MUTEX_unlock(&mutex); + func(ctx); + HEIMDAL_MUTEX_lock(&mutex); + *once = 2; + HEIMDAL_MUTEX_unlock(&mutex); + } else if (*once == 2) { + HEIMDAL_MUTEX_unlock(&mutex); + } else { + HEIMDAL_MUTEX_unlock(&mutex); + while (1) { + struct timeval tv = { 0, 1000 }; + select(0, NULL, NULL, NULL, &tv); + HEIMDAL_MUTEX_lock(&mutex); + if (*once == 2) + break; + HEIMDAL_MUTEX_unlock(&mutex); + } + HEIMDAL_MUTEX_unlock(&mutex); + } +#endif +} + +/** + * Abort and log the failure (using syslog) + */ + +void +heim_abort(const char *fmt, ...) + HEIMDAL_NORETURN_ATTRIBUTE + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 1, 2)) +{ + va_list ap; + va_start(ap, fmt); + heim_abortv(fmt, ap); + va_end(ap); +} + +/** + * Abort and log the failure (using syslog) + */ + +void +heim_abortv(const char *fmt, va_list ap) + HEIMDAL_NORETURN_ATTRIBUTE + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 1, 0)) +{ + static char str[1024]; + + vsnprintf(str, sizeof(str), fmt, ap); + syslog(LOG_ERR, "heim_abort: %s", str); + abort(); +} + +/* + * + */ + +static int ar_created = 0; +static HEIMDAL_thread_key ar_key; + +struct ar_tls { + struct heim_auto_release *head; + struct heim_auto_release *current; + HEIMDAL_MUTEX tls_mutex; +}; + +static void +ar_tls_delete(void *ptr) +{ + struct ar_tls *tls = ptr; + heim_auto_release_t next = NULL; + + if (tls == NULL) + return; + for (; tls->current != NULL; tls->current = next) { + next = tls->current->parent; + heim_release(tls->current); + } + free(tls); +} + +static void +init_ar_tls(void *ptr) +{ + int ret; + HEIMDAL_key_create(&ar_key, ar_tls_delete, ret); + if (ret == 0) + ar_created = 1; +} + +static struct ar_tls * +autorel_tls(void) +{ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + struct ar_tls *arp; + int ret; + + heim_base_once_f(&once, NULL, init_ar_tls); + if (!ar_created) + return NULL; + + arp = HEIMDAL_getspecific(ar_key); + if (arp == NULL) { + + arp = calloc(1, sizeof(*arp)); + if (arp == NULL) + return NULL; + HEIMDAL_setspecific(ar_key, arp, ret); + if (ret) { + free(arp); + return NULL; + } + } + return arp; + +} + +static void HEIM_CALLCONV +autorel_dealloc(void *ptr) +{ + heim_auto_release_t ar = ptr; + struct ar_tls *tls; + + tls = autorel_tls(); + if (tls == NULL) + heim_abort("autorelease pool released on thread w/o autorelease inited"); + + heim_auto_release_drain(ar); + + if (!HEIM_TAILQ_EMPTY(&ar->pool)) + heim_abort("pool not empty after draining"); + + HEIMDAL_MUTEX_lock(&tls->tls_mutex); + if (tls->current != ptr) + heim_abort("autorelease not releaseing top pool"); + + tls->current = ar->parent; + HEIMDAL_MUTEX_unlock(&tls->tls_mutex); +} + +static int +autorel_cmp(void *a, void *b) +{ + return (a == b); +} + +static uintptr_t +autorel_hash(void *ptr) +{ + return (uintptr_t)ptr; +} + + +static struct heim_type_data _heim_autorel_object = { + HEIM_TID_AUTORELEASE, + "autorelease-pool", + NULL, + autorel_dealloc, + NULL, + autorel_cmp, + autorel_hash, + NULL +}; + +/** + * Create thread-specific object auto-release pool + * + * Objects placed on the per-thread auto-release pool (with + * heim_auto_release()) can be released in one fell swoop by calling + * heim_auto_release_drain(). + */ + +heim_auto_release_t +heim_auto_release_create(void) +{ + struct ar_tls *tls = autorel_tls(); + heim_auto_release_t ar; + + if (tls == NULL) + heim_abort("Failed to create/get autorelease head"); + + ar = _heim_alloc_object(&_heim_autorel_object, sizeof(struct heim_auto_release)); + if (ar) { + HEIMDAL_MUTEX_lock(&tls->tls_mutex); + if (tls->head == NULL) + tls->head = ar; + ar->parent = tls->current; + tls->current = ar; + HEIMDAL_MUTEX_unlock(&tls->tls_mutex); + } + + return ar; +} + +/** + * Place the current object on the thread's auto-release pool + * + * @param ptr object + */ + +heim_object_t +heim_auto_release(heim_object_t ptr) +{ + struct heim_base *p; + struct ar_tls *tls; + heim_auto_release_t ar; + + if (ptr == NULL || heim_base_is_tagged(ptr)) + return ptr; + + p = PTR2BASE(ptr); + tls = autorel_tls(); + + /* drop from old pool */ + if ((ar = p->autorelpool) != NULL) { + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_REMOVE(&ar->pool, p, autorel); + p->autorelpool = NULL; + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); + } + + if (tls == NULL || (ar = tls->current) == NULL) + heim_abort("no auto relase pool in place, would leak"); + + HEIMDAL_MUTEX_lock(&ar->pool_mutex); + HEIM_TAILQ_INSERT_HEAD(&ar->pool, p, autorel); + p->autorelpool = ar; + HEIMDAL_MUTEX_unlock(&ar->pool_mutex); + + return ptr; +} + +/** + * Release all objects on the given auto-release pool + */ + +void +heim_auto_release_drain(heim_auto_release_t autorel) +{ + heim_object_t obj; + + /* release all elements on the tail queue */ + + HEIMDAL_MUTEX_lock(&autorel->pool_mutex); + while(!HEIM_TAILQ_EMPTY(&autorel->pool)) { + obj = HEIM_TAILQ_FIRST(&autorel->pool); + HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); + heim_release(BASE2PTR(obj)); + HEIMDAL_MUTEX_lock(&autorel->pool_mutex); + } + HEIMDAL_MUTEX_unlock(&autorel->pool_mutex); +} + +/* + * Helper for heim_path_vget() and heim_path_delete(). On success + * outputs the node named by the path and the parent node and key + * (useful for heim_path_delete()). + */ + +static heim_object_t +heim_path_vget2(heim_object_t ptr, heim_object_t *parent, heim_object_t *key, + heim_error_t *error, va_list ap) +{ + heim_object_t path_element; + heim_object_t node, next_node; + heim_tid_t node_type; + + *parent = NULL; + *key = NULL; + if (ptr == NULL) + return NULL; + + for (node = ptr; node != NULL; ) { + path_element = va_arg(ap, heim_object_t); + if (path_element == NULL) { + *parent = node; + *key = path_element; + return node; + } + + node_type = heim_get_tid(node); + switch (node_type) { + case HEIM_TID_ARRAY: + case HEIM_TID_DICT: + case HEIM_TID_DB: + break; + default: + if (node == ptr) + heim_abort("heim_path_get() only operates on container types"); + return NULL; + } + + if (node_type == HEIM_TID_DICT) { + next_node = heim_dict_get_value(node, path_element); + } else if (node_type == HEIM_TID_DB) { + next_node = _heim_db_get_value(node, NULL, path_element, NULL); + } else { + int idx = -1; + + /* node_type == HEIM_TID_ARRAY */ + if (heim_get_tid(path_element) == HEIM_TID_NUMBER) + idx = heim_number_get_int(path_element); + if (idx < 0) { + if (error) + *error = heim_error_create(EINVAL, + "heim_path_get() path elements " + "for array nodes must be " + "numeric and positive"); + return NULL; + } + next_node = heim_array_get_value(node, idx); + } + node = next_node; + } + return NULL; +} + +/** + * Get a node in a heim_object tree by path + * + * @param ptr tree + * @param error error (output) + * @param ap NULL-terminated va_list of heim_object_ts that form a path + * + * @return object (not retained) if found + * + * @addtogroup heimbase + */ + +heim_object_t +heim_path_vget(heim_object_t ptr, heim_error_t *error, va_list ap) +{ + heim_object_t p, k; + + return heim_path_vget2(ptr, &p, &k, error, ap); +} + +/** + * Get a node in a tree by path, with retained reference + * + * @param ptr tree + * @param error error (output) + * @param ap NULL-terminated va_list of heim_object_ts that form a path + * + * @return retained object if found + * + * @addtogroup heimbase + */ + +heim_object_t +heim_path_vcopy(heim_object_t ptr, heim_error_t *error, va_list ap) +{ + heim_object_t p, k; + + return heim_retain(heim_path_vget2(ptr, &p, &k, error, ap)); +} + +/** + * Get a node in a tree by path + * + * @param ptr tree + * @param error error (output) + * @param ... NULL-terminated va_list of heim_object_ts that form a path + * + * @return object (not retained) if found + * + * @addtogroup heimbase + */ + +heim_object_t +heim_path_get(heim_object_t ptr, heim_error_t *error, ...) +{ + heim_object_t o; + heim_object_t p, k; + va_list ap; + + if (ptr == NULL) + return NULL; + + va_start(ap, error); + o = heim_path_vget2(ptr, &p, &k, error, ap); + va_end(ap); + return o; +} + +/** + * Get a node in a tree by path, with retained reference + * + * @param ptr tree + * @param error error (output) + * @param ... NULL-terminated va_list of heim_object_ts that form a path + * + * @return retained object if found + * + * @addtogroup heimbase + */ + +heim_object_t +heim_path_copy(heim_object_t ptr, heim_error_t *error, ...) +{ + heim_object_t o; + heim_object_t p, k; + va_list ap; + + if (ptr == NULL) + return NULL; + + va_start(ap, error); + o = heim_retain(heim_path_vget2(ptr, &p, &k, error, ap)); + va_end(ap); + return o; +} + +/** + * Create a path in a heim_object_t tree + * + * @param ptr the tree + * @param size the size of the heim_dict_t nodes to be created + * @param leaf leaf node to be added, if any + * @param error error (output) + * @param ap NULL-terminated of path component objects + * + * Create a path of heim_dict_t interior nodes in a given heim_object_t + * tree, as necessary, and set/replace a leaf, if given (if leaf is NULL + * then the leaf is not deleted). + * + * @return 0 on success, else a system error + * + * @addtogroup heimbase + */ + +int +heim_path_vcreate(heim_object_t ptr, size_t size, heim_object_t leaf, + heim_error_t *error, va_list ap) +{ + heim_object_t path_element = va_arg(ap, heim_object_t); + heim_object_t next_path_element = NULL; + heim_object_t node = ptr; + heim_object_t next_node = NULL; + heim_tid_t node_type; + int ret = 0; + + if (ptr == NULL) + heim_abort("heim_path_vcreate() does not create root nodes"); + + while (path_element != NULL) { + int idx = -1; + + next_path_element = va_arg(ap, heim_object_t); + node_type = heim_get_tid(node); + + if (node_type == HEIM_TID_DICT) { + next_node = heim_dict_get_value(node, path_element); + } else if (node_type == HEIM_TID_ARRAY) { + if (heim_get_tid(path_element) == HEIM_TID_NUMBER) + idx = heim_number_get_int(path_element); + if (idx < 0) { + if (error) + *error = heim_error_create(EINVAL, + "heim_path() path elements for " + "array nodes must be numeric " + "and positive"); + return EINVAL; + } + if (idx < heim_array_get_length(node)) { + next_node = heim_array_get_value(node, idx); + } else if (idx == heim_array_get_length(node)) { + next_node = NULL; + } else { + if (error) + *error = heim_error_create(EINVAL, + "Index for array in path is too large"); + return EINVAL; + } + } else if (node_type == HEIM_TID_DB && next_path_element != NULL) { + if (error) + *error = heim_error_create(EINVAL, "Interior node is a DB"); + return EINVAL; + } + + if (next_path_element == NULL) + break; + + /* Create missing interior node */ + if (next_node == NULL) { + heim_dict_t new_node; + + new_node = heim_dict_create(size); /* no arrays or DBs, just dicts */ + if (new_node == NULL) { + ret = ENOMEM; + goto err; + } + + if (node_type == HEIM_TID_DICT) { + ret = heim_dict_set_value(node, path_element, new_node); + next_node = heim_dict_get_value(node, path_element); + } else if (node_type == HEIM_TID_ARRAY && + heim_number_get_int(path_element) <= heim_array_get_length(node)) { + ret = heim_array_insert_value(node, + heim_number_get_int(path_element), + new_node); + next_node = heim_array_get_value(node, idx); + } else { + ret = EINVAL; + if (error) + *error = heim_error_create(ret, "Node in path not a " + "container"); + } + + heim_release(new_node); + if (ret) + goto err; + } + + path_element = next_path_element; + node = next_node; + next_node = NULL; + } + + if (path_element == NULL) + goto err; + + /* Add the leaf */ + if (leaf != NULL) { + if (node_type == HEIM_TID_DICT) + ret = heim_dict_set_value(node, path_element, leaf); + else + ret = heim_array_insert_value(node, + heim_number_get_int(path_element), + leaf); + } + return ret; + +err: + if (error && !*error) { + if (ret == ENOMEM) + *error = heim_error_create_enomem(); + else + *error = heim_error_create(ret, "Could not set " + "dict value"); + } + return ret; +} + +/** + * Create a path in a heim_object_t tree + * + * @param ptr the tree + * @param size the size of the heim_dict_t nodes to be created + * @param leaf leaf node to be added, if any + * @param error error (output) + * @param ... NULL-terminated list of path component objects + * + * Create a path of heim_dict_t interior nodes in a given heim_object_t + * tree, as necessary, and set/replace a leaf, if given (if leaf is NULL + * then the leaf is not deleted). + * + * @return 0 on success, else a system error + * + * @addtogroup heimbase + */ + +int +heim_path_create(heim_object_t ptr, size_t size, heim_object_t leaf, + heim_error_t *error, ...) +{ + va_list ap; + int ret; + + va_start(ap, error); + ret = heim_path_vcreate(ptr, size, leaf, error, ap); + va_end(ap); + return ret; +} + +/** + * Delete leaf node named by a path in a heim_object_t tree + * + * @param ptr the tree + * @param error error (output) + * @param ap NULL-terminated list of path component objects + * + * @addtogroup heimbase + */ + +void +heim_path_vdelete(heim_object_t ptr, heim_error_t *error, va_list ap) +{ + heim_object_t parent, key, child; + + child = heim_path_vget2(ptr, &parent, &key, error, ap); + if (child != NULL) { + if (heim_get_tid(parent) == HEIM_TID_DICT) + heim_dict_delete_key(parent, key); + else if (heim_get_tid(parent) == HEIM_TID_DB) + heim_db_delete_key(parent, NULL, key, error); + else if (heim_get_tid(parent) == HEIM_TID_ARRAY) + heim_array_delete_value(parent, heim_number_get_int(key)); + heim_release(child); + } +} + +/** + * Delete leaf node named by a path in a heim_object_t tree + * + * @param ptr the tree + * @param error error (output) + * @param ap NULL-terminated list of path component objects + * + * @addtogroup heimbase + */ + +void +heim_path_delete(heim_object_t ptr, heim_error_t *error, ...) +{ + va_list ap; + + va_start(ap, error); + heim_path_vdelete(ptr, error, ap); + va_end(ap); + return; +} + diff --git a/third_party/heimdal/lib/base/heimbase.h b/third_party/heimdal/lib/base/heimbase.h new file mode 100644 index 0000000..4546df9 --- /dev/null +++ b/third_party/heimdal/lib/base/heimbase.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_BASE_H +#define HEIM_BASE_H 1 + +#include +#ifndef _WIN32 +#include +#endif +#if !defined(WIN32) && !defined(HAVE_DISPATCH_DISPATCH_H) && defined(ENABLE_PTHREAD_SUPPORT) +#include +#endif +#include +#include +#ifdef _WIN32 +#include +#endif +#ifdef HAVE_STDBOOL_H +#include +#else +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif +#endif + +#include + +#include + +#ifdef _WIN32 +#define HEIM_CALLCONV __stdcall +#define HEIM_LIB_CALL __stdcall +#else +#define HEIM_CALLCONV +#define HEIM_LIB_CALL +#endif + +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(x) +#endif + +#define HEIM_BASE_API_VERSION 20130210 + +/* + * Generic facilities (moved from lib/krb5/. + */ + +typedef int32_t heim_error_code; +typedef struct heim_context_s *heim_context; +typedef struct heim_pcontext_s *heim_pcontext; + +typedef void (HEIM_CALLCONV *heim_log_log_func_t)(heim_context, + const char *, + const char *, + void *); +typedef void (HEIM_CALLCONV *heim_log_close_func_t)(void *); + +typedef struct heim_log_facility_s heim_log_facility; + +typedef uintptr_t +(HEIM_LIB_CALL *heim_get_instance_func_t)(const char *); + +#define HEIM_PLUGIN_INVOKE_ALL 1 + +struct heim_plugin_data { + const char *module; + const char *name; + int min_version; + const char *const *deps; + heim_get_instance_func_t get_instance; +}; + +/* + * heim_config_binding is identical to struct krb5_config_binding + * within krb5.h. Its format is public and used by callers of + * krb5_config_get_list() and krb5_config_vget_list(). + */ +enum heim_config_type { + heim_config_string, + heim_config_list, +}; +struct heim_config_binding { + enum heim_config_type type; + char *name; + struct heim_config_binding *next; + union { + char *string; + struct heim_config_binding *list; + void *generic; + } u; +}; +typedef struct heim_config_binding heim_config_binding; +typedef struct heim_config_binding heim_config_section; + +/* + * CF-like, JSON APIs + */ + +typedef enum heim_tid_enum { + HEIM_TID_NUMBER = 0, + HEIM_TID_NULL = 1, + HEIM_TID_BOOL = 2, + HEIM_TID_TAGGED_UNUSED2 = 3, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED3 = 4, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED4 = 5, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED5 = 6, /* reserved for tagged object types */ + HEIM_TID_TAGGED_UNUSED6 = 7, /* reserved for tagged object types */ + HEIM_TID_MEMORY = 128, + HEIM_TID_ARRAY = 129, + HEIM_TID_DICT = 130, + HEIM_TID_STRING = 131, + HEIM_TID_AUTORELEASE = 132, + HEIM_TID_ERROR = 133, + HEIM_TID_DATA = 134, + HEIM_TID_DB = 135, + HEIM_TID_PA_AUTH_MECH = 136, + HEIM_TID_PAC = 137, + HEIM_TID_USER = 255 +} heim_tid; + +typedef void * heim_object_t; +typedef unsigned int heim_tid_t; +typedef heim_object_t heim_bool_t; +typedef heim_object_t heim_null_t; +#ifdef WIN32 +typedef LONG heim_base_once_t; +#define HEIM_BASE_ONCE_INIT 0 +#elif defined(HAVE_DISPATCH_DISPATCH_H) +typedef long heim_base_once_t; /* XXX arch dependant */ +#define HEIM_BASE_ONCE_INIT 0 +#elif defined(ENABLE_PTHREAD_SUPPORT) +typedef pthread_once_t heim_base_once_t; +#define HEIM_BASE_ONCE_INIT PTHREAD_ONCE_INIT +#else +typedef long heim_base_once_t; /* XXX arch dependant */ +#define HEIM_BASE_ONCE_INIT 0 +#endif + +#if !defined(__has_extension) +#define __has_extension(x) 0 +#endif + +#define HEIM_REQUIRE_GNUC(m,n,p) \ + (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) >= \ + (((m) * 10000) + ((n) * 100) + (p))) + + +#if __has_extension(__builtin_expect) || HEIM_REQUIRE_GNUC(3,0,0) +#define heim_builtin_expect(_op,_res) __builtin_expect(_op,_res) +#else +#define heim_builtin_expect(_op,_res) (_op) +#endif + + +typedef void (HEIM_CALLCONV *heim_type_dealloc)(void *); + +#define heim_assert(e,t) \ + (heim_builtin_expect(!(e), 0) ? heim_abort(t ":" #e) : (void)0) + +/* + * + */ + +/* + * Array + */ + +typedef struct heim_array_data *heim_array_t; + +typedef void (*heim_array_iterator_f_t)(heim_object_t, void *, int *); +typedef int (*heim_array_filter_f_t)(heim_object_t, void *); + +/* + * Dict + */ + +typedef struct heim_dict_data *heim_dict_t; + +typedef void (*heim_dict_iterator_f_t)(heim_object_t, heim_object_t, void *); + +/* + * String + */ + +typedef struct heim_string_data *heim_string_t; +typedef void (*heim_string_free_f_t)(void *); + +#define HSTR(_str) (__heim_string_constant("" _str "")) +heim_string_t __heim_string_constant(const char *); + +/* + * Errors + */ + +typedef struct heim_error * heim_error_t; + +/* + * Path + */ + +/* + * Data (octet strings) + */ + +#ifndef __HEIM_BASE_DATA__ +#define __HEIM_BASE_DATA__ +struct heim_base_data { + size_t length; + void *data; +}; +typedef struct heim_base_data heim_octet_string; +#endif + +typedef struct heim_base_data * heim_data_t; +typedef void (*heim_data_free_f_t)(void *); + +/* + * DB + */ + +typedef struct heim_db_data *heim_db_t; + +typedef void (*heim_db_iterator_f_t)(heim_data_t, heim_data_t, void *); + +typedef int (*heim_db_plug_open_f_t)(void *, const char *, const char *, + heim_dict_t, void **, heim_error_t *); +typedef int (*heim_db_plug_clone_f_t)(void *, void **, heim_error_t *); +typedef int (*heim_db_plug_close_f_t)(void *, heim_error_t *); +typedef int (*heim_db_plug_lock_f_t)(void *, int, heim_error_t *); +typedef int (*heim_db_plug_unlock_f_t)(void *, heim_error_t *); +typedef int (*heim_db_plug_sync_f_t)(void *, heim_error_t *); +typedef int (*heim_db_plug_begin_f_t)(void *, int, heim_error_t *); +typedef int (*heim_db_plug_commit_f_t)(void *, heim_error_t *); +typedef int (*heim_db_plug_rollback_f_t)(void *, heim_error_t *); +typedef heim_data_t (*heim_db_plug_copy_value_f_t)(void *, heim_string_t, + heim_data_t, + heim_error_t *); +typedef int (*heim_db_plug_set_value_f_t)(void *, heim_string_t, heim_data_t, + heim_data_t, heim_error_t *); +typedef int (*heim_db_plug_del_key_f_t)(void *, heim_string_t, heim_data_t, + heim_error_t *); +typedef void (*heim_db_plug_iter_f_t)(void *, heim_string_t, void *, + heim_db_iterator_f_t, heim_error_t *); + +struct heim_db_type { + int version; + heim_db_plug_open_f_t openf; + heim_db_plug_clone_f_t clonef; + heim_db_plug_close_f_t closef; + heim_db_plug_lock_f_t lockf; + heim_db_plug_unlock_f_t unlockf; + heim_db_plug_sync_f_t syncf; + heim_db_plug_begin_f_t beginf; + heim_db_plug_commit_f_t commitf; + heim_db_plug_rollback_f_t rollbackf; + heim_db_plug_copy_value_f_t copyf; + heim_db_plug_set_value_f_t setf; + heim_db_plug_del_key_f_t delf; + heim_db_plug_iter_f_t iterf; +}; + +extern struct heim_db_type heim_sorted_text_file_dbtype; + +#define HEIM_DB_TYPE_VERSION_01 1 + +/* + * Number + */ + +typedef struct heim_number_data *heim_number_t; + +/* + * Autorelease + */ + +typedef struct heim_auto_release * heim_auto_release_t; + +/* + * JSON + */ +typedef enum heim_json_flags { + HEIM_JSON_F_NO_C_NULL = 1, + HEIM_JSON_F_STRICT_STRINGS = 2, + HEIM_JSON_F_NO_DATA = 4, + HEIM_JSON_F_NO_DATA_DICT = 8, + HEIM_JSON_F_STRICT_DICT = 16, + HEIM_JSON_F_STRICT = 31, + HEIM_JSON_F_CNULL2JSNULL = 32, + HEIM_JSON_F_TRY_DECODE_DATA = 64, + HEIM_JSON_F_ONE_LINE = 128, + HEIM_JSON_F_ESCAPE_NON_ASCII = 256, + HEIM_JSON_F_NO_ESCAPE_NON_ASCII = 512, + /* The default is to indent with one tab */ + HEIM_JSON_F_INDENT2 = 1024, + HEIM_JSON_F_INDENT4 = 2048, + HEIM_JSON_F_INDENT8 = 4096, +} heim_json_flags_t; + +/* + * Debug + */ + +/* + * Binary search. + * + * Note: these are private until integrated into the heimbase object system. + */ +typedef struct bsearch_file_handle *bsearch_file_handle; +int _bsearch_text(const char *buf, size_t buf_sz, const char *key, + char **value, size_t *location, size_t *loops); +int _bsearch_file_open(const char *fname, size_t max_sz, size_t page_sz, + bsearch_file_handle *bfh, size_t *reads); +int _bsearch_file(bsearch_file_handle bfh, const char *key, char **value, + size_t *location, size_t *loops, size_t *reads); +void _bsearch_file_info(bsearch_file_handle bfh, size_t *page_sz, + size_t *max_sz, int *blockwise); +void _bsearch_file_close(bsearch_file_handle *bfh); + +/* + * Thread-specific keys + */ + +#include +#include + +/* + * Service logging facility (moved from kdc/). + */ + +#define HEIM_SVC_AUDIT_EATWHITE 0x1 +#define HEIM_SVC_AUDIT_VIS 0x2 +#define HEIM_SVC_AUDIT_VISLAST 0x4 + +typedef struct heim_svc_req_desc_common_s *heim_svc_req_desc; + +#include + +#endif /* HEIM_BASE_H */ diff --git a/third_party/heimdal/lib/base/heimbasepriv.h b/third_party/heimdal/lib/base/heimbasepriv.h new file mode 100644 index 0000000..a431da4 --- /dev/null +++ b/third_party/heimdal/lib/base/heimbasepriv.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(HEIM_BASE_MAINTAINER) && defined(ENABLE_PTHREAD_SUPPORT) +#define HEIM_WIN32_TLS +#elif defined(WIN32) +#define HEIM_WIN32_TLS +#endif + +typedef void (*heim_type_init)(void *); +typedef heim_object_t (*heim_type_copy)(void *); +typedef int (*heim_type_cmp)(void *, void *); +typedef uintptr_t (*heim_type_hash)(void *); +typedef heim_string_t (*heim_type_description)(void *); + +typedef struct heim_type_data *heim_type_t; +typedef const struct heim_type_data *heim_const_type_t; + +struct heim_type_data { + heim_tid_t tid; + const char *name; + heim_type_init init; + heim_type_dealloc dealloc; + heim_type_copy copy; + heim_type_cmp cmp; + heim_type_hash hash; + heim_type_description desc; +}; + +heim_const_type_t _heim_get_isa(heim_object_t); + +heim_type_t +_heim_create_type(const char *name, + heim_type_init init, + heim_type_dealloc dealloc, + heim_type_copy copy, + heim_type_cmp cmp, + heim_type_hash hash, + heim_type_description desc); + +heim_object_t +_heim_alloc_object(heim_const_type_t type, size_t size); + +void * +_heim_get_isaextra(heim_object_t o, size_t idx); + +heim_tid_t +_heim_type_get_tid(heim_type_t type); + +void +_heim_make_permanent(heim_object_t ptr); + +heim_data_t +_heim_db_get_value(heim_db_t, heim_string_t, heim_data_t, heim_error_t *); + + +/* tagged tid */ +extern struct heim_type_data _heim_null_object; +extern struct heim_type_data _heim_bool_object; +extern struct heim_type_data _heim_number_object; +extern struct heim_type_data _heim_string_object; diff --git a/third_party/heimdal/lib/base/json.c b/third_party/heimdal/lib/base/json.c new file mode 100644 index 0000000..ed4ea68 --- /dev/null +++ b/third_party/heimdal/lib/base/json.c @@ -0,0 +1,1471 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include +#include + +#ifndef WIN32 +#include +#endif + +static heim_base_once_t heim_json_once = HEIM_BASE_ONCE_INIT; +static heim_string_t heim_tid_data_uuid_key = NULL; + +static void +json_init_once(void *arg) +{ + heim_tid_data_uuid_key = __heim_string_constant("heimdal-type-data-76d7fca2-d0da-4b20-a126-1a10f8a0eae6"); +} + +struct twojson { + void *ctx; + void (*out)(void *, const char *); + size_t indent; + heim_json_flags_t flags; + int ret; + int first; +}; + +struct heim_strbuf { + char *str; + size_t len; + size_t alloced; + int enomem; + heim_json_flags_t flags; +}; + +static int +base2json(heim_object_t, struct twojson *, int); + +static void +indent(struct twojson *j) +{ + size_t i = j->indent; + if (j->flags & HEIM_JSON_F_ONE_LINE) + return; + if (j->flags & HEIM_JSON_F_INDENT2) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT4) + while (i--) + j->out(j->ctx, " "); + else if (j->flags & HEIM_JSON_F_INDENT8) + while (i--) + j->out(j->ctx, " "); + else + while (i--) + j->out(j->ctx, "\t"); +} + +static void +array2json(heim_object_t value, void *ctx, int *stop) +{ + struct twojson *j = ctx; + if (j->ret) + return; + if (j->first) { + j->first = 0; + } else { + j->out(j->ctx, NULL); /* eat previous '\n' if possible */ + j->out(j->ctx, ",\n"); + } + j->ret = base2json(value, j, 0); +} + +static void +dict2json(heim_object_t key, heim_object_t value, void *ctx) +{ + struct twojson *j = ctx; + if (j->ret) + return; + if (j->first) { + j->first = 0; + } else { + j->out(j->ctx, NULL); /* eat previous '\n' if possible */ + j->out(j->ctx, ",\n"); + } + j->ret = base2json(key, j, 0); + if (j->ret) + return; + switch (heim_get_tid(value)) { + case HEIM_TID_ARRAY: + case HEIM_TID_DICT: + case HEIM_TID_DATA: + j->out(j->ctx, ":\n"); + j->indent++; + j->ret = base2json(value, j, 0); + if (j->ret) + return; + j->indent--; + break; + default: + j->out(j->ctx, ": "); + j->ret = base2json(value, j, 1); + break; + } +} + +#ifndef WIN32 +static void +init_is_utf8(void *ptr) +{ + *(int *)ptr = strcasecmp("utf-8", nl_langinfo(CODESET)) == 0; +} +#endif + +int +heim_locale_is_utf8(void) +{ +#ifdef WIN32 + return 0; /* XXX Implement */ +#else + static int locale_is_utf8 = -1; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + + heim_base_once_f(&once, &locale_is_utf8, init_is_utf8); + return locale_is_utf8; +#endif +} + +static void +out_escaped_bmp(struct twojson *j, const unsigned char *p, int nbytes) +{ + unsigned char e[sizeof("\\u0000")]; + unsigned codepoint; + + if (nbytes == 2) + codepoint = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f); + else if (nbytes == 3) + codepoint = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f); + else + abort(); + e[0] = '\\'; + e[1] = 'u'; + e[2] = codepoint >> 12; + e[2] += (e[2] < 10) ? '0' : ('A' - 10); + e[3] = (codepoint >> 8) & 0x0f; + e[3] += (e[3] < 10) ? '0' : ('A' - 10); + e[4] = (codepoint >> 4) & 0x0f; + e[4] += (e[4] < 10) ? '0' : ('A' - 10); + e[5] = codepoint & 0x0f; + e[5] += (e[5] < 10) ? '0' : ('A' - 10); + e[6] = '\0'; + j->out(j->ctx, (char *)e); +} + +static int +base2json(heim_object_t obj, struct twojson *j, int skip_indent) +{ + heim_tid_t type; + int first = 0; + + if (obj == NULL) { + if (j->flags & HEIM_JSON_F_CNULL2JSNULL) { + obj = heim_null_create(); + } else if (j->flags & HEIM_JSON_F_NO_C_NULL) { + return EINVAL; + } else { + indent(j); + j->out(j->ctx, "\n"); /* This is NOT valid JSON! */ + return 0; + } + } + + type = heim_get_tid(obj); + switch (type) { + case HEIM_TID_ARRAY: + indent(j); + j->out(j->ctx, "[\n"); + j->indent++; + first = j->first; + j->first = 1; + heim_array_iterate_f(obj, j, array2json); + j->indent--; + if (!j->first) + j->out(j->ctx, "\n"); + indent(j); + j->out(j->ctx, "]\n"); + j->first = first; + break; + + case HEIM_TID_DICT: + indent(j); + j->out(j->ctx, "{\n"); + j->indent++; + first = j->first; + j->first = 1; + heim_dict_iterate_f(obj, j, dict2json); + j->indent--; + if (!j->first) + j->out(j->ctx, "\n"); + indent(j); + j->out(j->ctx, "}\n"); + j->first = first; + break; + + case HEIM_TID_STRING: { + const unsigned char *s = (const unsigned char *)heim_string_get_utf8(obj); + const unsigned char *p; + unsigned int c, cp, ctop, cbot; + char e[sizeof("\\u0123\\u3210")]; + int good; + size_t i; + + if (!skip_indent) + indent(j); + j->out(j->ctx, "\""); + for (p = s; (c = *p); p++) { + switch (c) { + /* ASCII control characters w/ C-like escapes */ + case '\b': j->out(j->ctx, "\\b"); continue; + case '\f': j->out(j->ctx, "\\f"); continue; + case '\n': j->out(j->ctx, "\\n"); continue; + case '\r': j->out(j->ctx, "\\r"); continue; + case '\t': j->out(j->ctx, "\\t"); continue; + /* Other must-escape non-control ASCII characters */ + case '"': j->out(j->ctx, "\\\""); continue; + case '\\': j->out(j->ctx, "\\\\"); continue; + default: break; + } + + /* + * JSON string encoding is... complex. + * + * Invalid UTF-8 w/ HEIM_JSON_F_STRICT_STRINGS set -> return 1 + * + * Invalid UTF-8 w/o HEIM_JSON_F_STRICT_STRINGS set -> pass + * through, a sort of Heimdal WTF-8, but not _the_ WTF-8. + */ + if (c < 0x20) { + /* ASCII control character w/o C-like escape */ + e[0] = '\\'; + e[1] = 'u'; + e[2] = '0'; + e[3] = '0'; + e[4] = "0123456789ABCDEF"[c>>4]; + e[5] = "0123456789ABCDEF"[c & 0x0f]; + e[6] = '\0'; + j->out(j->ctx, e); + continue; + } + if (c < 0x80) { + /* ASCII */ + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + if ((c & 0xc0) == 0x80) { + /* UTF-8 bare non-leading byte */ + if (!(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + return 1; + } + if ((c & 0xe0) == 0xc0) { + /* UTF-8 leading byte of two-byte sequence */ + good = 1; + for (i = 1; i < 2 && good && p[i]; i++) { + if ((p[i] & 0xc0) != 0x80) + good = 0; + } + if (i != 2) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + if (j->flags & HEIM_JSON_F_ESCAPE_NON_ASCII) { + out_escaped_bmp(j, p, 2); + p += 1; + continue; + } + e[0] = c; + e[1] = p[1]; + e[2] = '\0'; + j->out(j->ctx, e); + p += 1; + continue; + } + if ((c & 0xf0) == 0xe0) { + /* UTF-8 leading byte of three-byte sequence */ + good = 1; + for (i = 1; i < 3 && good && p[i]; i++) { + if ((p[i] & 0xc0) != 0x80) + good = 0; + } + if (i != 3) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + if (j->flags & HEIM_JSON_F_ESCAPE_NON_ASCII) { + out_escaped_bmp(j, p, 3); + p += 2; + continue; + } + e[0] = c; + e[1] = p[1]; + e[2] = p[2]; + e[3] = '\0'; + j->out(j->ctx, e); + p += 2; + continue; + } + + if (c > 0xf7) { + /* Invalid UTF-8 leading byte */ + if (!(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } + return 1; + } + + /* + * A codepoint > U+FFFF, needs encoding a la UTF-16 surrogate + * pair because JSON takes after JS which uses UTF-16. Ugly. + */ + cp = c & 0x7; + good = 1; + for (i = 1; i < 4 && good && p[i]; i++) { + if ((p[i] & 0xc0) == 0x80) + cp = (cp << 6) | (p[i] & 0x3f); + else + good = 0; + } + if (i != 4) + good = 0; + if (!good && !(j->flags & HEIM_JSON_F_STRICT_STRINGS)) { + e[0] = c; + e[1] = '\0'; + j->out(j->ctx, e); + continue; + } else if (!good) { + return 1; + } + p += 3; + + cp -= 0x10000; + ctop = 0xD800 + (cp >> 10); + cbot = 0xDC00 + (cp & 0x3ff); + + e[0 ] = '\\'; + e[1 ] = 'u'; + e[2 ] = "0123456789ABCDEF"[(ctop ) >> 12]; + e[3 ] = "0123456789ABCDEF"[(ctop & 0x0f00) >> 8]; + e[4 ] = "0123456789ABCDEF"[(ctop & 0x00f0) >> 4]; + e[5 ] = "0123456789ABCDEF"[(ctop & 0x000f) ]; + e[6 ] = '\\'; + e[7 ] = 'u'; + e[8 ] = "0123456789ABCDEF"[(cbot ) >> 12]; + e[9 ] = "0123456789ABCDEF"[(cbot & 0x0f00) >> 8]; + e[10] = "0123456789ABCDEF"[(cbot & 0x00f0) >> 4]; + e[11] = "0123456789ABCDEF"[(cbot & 0x000f) ]; + e[12] = '\0'; + j->out(j->ctx, e); + continue; + } + j->out(j->ctx, "\""); + break; + } + + case HEIM_TID_DATA: { + heim_dict_t d; + heim_string_t v; + const heim_octet_string *data; + char *b64 = NULL; + int ret; + + if (j->flags & HEIM_JSON_F_NO_DATA) + return EINVAL; /* JSON doesn't do binary */ + + data = heim_data_get_data(obj); + ret = rk_base64_encode(data->data, data->length, &b64); + if (ret < 0 || b64 == NULL) + return ENOMEM; + + if (j->flags & HEIM_JSON_F_NO_DATA_DICT) { + indent(j); + j->out(j->ctx, "\""); + j->out(j->ctx, b64); /* base64-encode; hope there's no aliasing */ + j->out(j->ctx, "\""); + free(b64); + } else { + /* + * JSON has no way to represent binary data, therefore the + * following is a Heimdal-specific convention. + * + * We encode binary data as a dict with a single very magic + * key with a base64-encoded value. The magic key includes + * a uuid, so we're not likely to alias accidentally. + */ + d = heim_dict_create(2); + if (d == NULL) { + free(b64); + return ENOMEM; + } + v = heim_string_ref_create(b64, free); + if (v == NULL) { + free(b64); + heim_release(d); + return ENOMEM; + } + ret = heim_dict_set_value(d, heim_tid_data_uuid_key, v); + heim_release(v); + if (ret) { + heim_release(d); + return ENOMEM; + } + ret = base2json(d, j, 0); + heim_release(d); + if (ret) + return ret; + } + break; + } + + case HEIM_TID_NUMBER: { + char num[32]; + if (!skip_indent) + indent(j); + snprintf(num, sizeof (num), "%d", heim_number_get_int(obj)); + j->out(j->ctx, num); + break; + } + case HEIM_TID_NULL: + if (!skip_indent) + indent(j); + j->out(j->ctx, "null"); + break; + case HEIM_TID_BOOL: + if (!skip_indent) + indent(j); + j->out(j->ctx, heim_bool_val(obj) ? "true" : "false"); + break; + default: + return 1; + } + return 0; +} + +static int +heim_base2json(heim_object_t obj, void *ctx, heim_json_flags_t flags, + void (*out)(void *, const char *)) +{ + struct twojson j; + + heim_base_once_f(&heim_json_once, NULL, json_init_once); + + j.indent = 0; + j.ctx = ctx; + j.out = out; + j.flags = flags; + j.ret = 0; + j.first = 1; + + if (!(flags & HEIM_JSON_F_NO_ESCAPE_NON_ASCII) && + !heim_locale_is_utf8()) + j.flags |= HEIM_JSON_F_ESCAPE_NON_ASCII; + + return base2json(obj, &j, 0); +} + + +/* + * + */ + +struct parse_ctx { + unsigned long lineno; + const uint8_t *p; + const uint8_t *pstart; + const uint8_t *pend; + heim_error_t error; + size_t depth; + heim_json_flags_t flags; +}; + + +static heim_object_t +parse_value(struct parse_ctx *ctx); + +/* + * This function eats whitespace, but, critically, it also succeeds + * only if there's anything left to parse. + */ +static int +white_spaces(struct parse_ctx *ctx) +{ + while (ctx->p < ctx->pend) { + uint8_t c = *ctx->p; + if (c == ' ' || c == '\t' || c == '\r') { + + } else if (c == '\n') { + ctx->lineno++; + } else + return 0; + (ctx->p)++; + } + return -1; +} + +static int +is_number(uint8_t n) +{ + return ('0' <= n && n <= '9'); +} + +static heim_number_t +parse_number(struct parse_ctx *ctx) +{ + int number = 0, neg = 1; + + if (ctx->p >= ctx->pend) + return NULL; + + if (*ctx->p == '-') { + if (ctx->p + 1 >= ctx->pend) + return NULL; + neg = -1; + ctx->p += 1; + } + + while (ctx->p < ctx->pend) { + if (is_number(*ctx->p)) { + number = (number * 10) + (*ctx->p - '0'); + } else { + break; + } + ctx->p += 1; + } + + return heim_number_create(number * neg); +} + +/* + * Read 4 hex digits from ctx->p. + * + * If we don't have enough, rewind ctx->p and return -1 . + */ +static int +unescape_unicode(struct parse_ctx *ctx) +{ + int c = 0; + int i; + + for (i = 0; i < 4 && ctx->p < ctx->pend; i++, ctx->p++) { + if (*ctx->p >= '0' && *ctx->p <= '9') { + c = (c << 4) + (*ctx->p - '0'); + } else if (*ctx->p >= 'A' && *ctx->p <= 'F') { + c = (c << 4) + (10 + *ctx->p - 'A'); + } else if (*ctx->p >= 'a' && *ctx->p <= 'f') { + c = (c << 4) + (10 + *ctx->p - 'a'); + } else { + ctx->p -= i; + return -1; + } + } + return c; +} + +static int +encode_utf8(struct parse_ctx *ctx, char **pp, char *pend, int c) +{ + char *p = *pp; + + if (c < 0x80) { + /* ASCII */ + if (p >= pend) return 0; + *(p++) = c; + *pp = p; + return 1; + } + if (c < 0x800) { + /* 2 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xc0 | ((c >> 6) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c ) & 0x3f); + *pp = p; + return 1; + } + if (c < 0x10000) { + /* 3 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xe0 | ((c >> 12) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 6) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c) & 0x3f); + *pp = p; + return 1; + } + if (c < 0x110000) { + /* 4 code unit UTF-8 sequence */ + if (p >= pend) return 0; + *(p++) = 0xf0 | ((c >> 18) ); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 12) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c >> 6) & 0x3f); + if (p == pend) return 0; + *(p++) = 0x80 | ((c) & 0x3f); + *pp = p; + return 1; + } + return 0; +} + +static heim_string_t +parse_string_error(struct parse_ctx *ctx, + char *freeme, + const char *msg) +{ + free(freeme); + ctx->error = heim_error_create(EINVAL, "%s at %lu", msg, ctx->lineno); + return NULL; +} + +static heim_string_t +parse_string(struct parse_ctx *ctx) +{ + const uint8_t *start; + heim_object_t o; + size_t alloc_len = 0; + size_t need = 0; + char *p0, *p, *pend; + int strict = ctx->flags & HEIM_JSON_F_STRICT_STRINGS; + int binary = 0; + + if (*ctx->p != '"') + return parse_string_error(ctx, NULL, + "Expected a JSON string but found " + "something else"); + start = ++(ctx->p); + + /* Estimate how many bytes we need to allocate */ + p0 = p = pend = NULL; + for (need = 1; ctx->p < ctx->pend; ctx->p++) { + need++; + if (*ctx->p == '\\') + ctx->p++; + else if (*ctx->p == '"') + break; + } + if (ctx->p == ctx->pend) + return parse_string_error(ctx, NULL, "Unterminated JSON string"); + + ctx->p = start; + while (ctx->p < ctx->pend) { + const unsigned char *p_save; + int32_t ctop, cbot; + + if (*ctx->p == '"') { + ctx->p++; + break; + } + + /* Allocate or resize our output buffer if need be */ + if (need || p == pend) { + char *tmp; + + /* + * Work out how far p is into p0 to re-esablish p after + * the realloc() + */ + size_t p0_to_p_len = (p - p0); + + tmp = realloc(p0, alloc_len + need + 5 /* slop? */); + + if (tmp == NULL) { + ctx->error = heim_error_create_enomem(); + free(p0); + return NULL; + } + alloc_len += need + 5; + + /* + * We have two pointers, p and p0, we want to keep them + * pointing into the same memory after the realloc() + */ + p = tmp + p0_to_p_len; + p0 = tmp; + pend = p0 + alloc_len; + + need = 0; + } + + if (*ctx->p != '\\') { + unsigned char c = *ctx->p; + + /* + * Not backslashed -> consume now. + * + * NOTE: All cases in this block must continue or return w/ error. + */ + + /* Check for unescaped ASCII control characters */ + if (c == '\n') { + if (strict) + return parse_string_error(ctx, p0, + "Unescaped newline in JSON string"); + /* Count the newline but don't add it to the decoding */ + ctx->lineno++; + } else if (strict && *ctx->p <= 0x1f) { + return parse_string_error(ctx, p0, "Unescaped ASCII control character"); + } else if (c == 0) { + binary = 1; + } + if (!strict || c < 0x80) { + /* ASCII, or not strict -> no need to validate */ + *(p++) = c; + ctx->p++; + continue; + } + + /* + * Being strict for parsing means we want to detect malformed UTF-8 + * sequences. + * + * If not strict then we just go on below and add to `p' whatever + * bytes we find in `ctx->p' as we find them. + * + * For each two-byte sequence we need one more byte in `p[]'. For + * each three-byte sequence we need two more bytes in `p[]'. + * + * Setting `need' and looping will cause `p0' to be grown. + * + * NOTE: All cases in this block must continue or return w/ error. + */ + if ((c & 0xe0) == 0xc0) { + /* Two-byte UTF-8 encoding */ + if (pend - p < 2) { + need = 2; + continue; /* realloc p0 */ + } + + *(p++) = c; + ctx->p++; + if (ctx->p == ctx->pend) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + continue; + } + if ((c & 0xf0) == 0xe0) { + /* Three-byte UTF-8 encoding */ + if (pend - p < 3) { + need = 3; + continue; /* realloc p0 */ + } + + *(p++) = c; + ctx->p++; + if (ctx->p == ctx->pend) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + c = *(ctx->p++); + if ((c & 0xc0) != 0x80) + return parse_string_error(ctx, p0, "Truncated UTF-8"); + *(p++) = c; + continue; + } + if ((c & 0xf8) == 0xf0) + return parse_string_error(ctx, p0, "UTF-8 sequence not " + "encoded as escaped UTF-16"); + if ((c & 0xc0) == 0x80) + return parse_string_error(ctx, p0, + "Invalid UTF-8 " + "(bare continuation code unit)"); + + return parse_string_error(ctx, p0, "Not UTF-8"); + } + + /* Backslash-quoted character */ + ctx->p++; + if (ctx->p == ctx->pend) { + ctx->error = + heim_error_create(EINVAL, + "Unterminated JSON string at line %lu", + ctx->lineno); + free(p0); + return NULL; + } + switch (*ctx->p) { + /* Simple escapes */ + case 'b': *(p++) = '\b'; ctx->p++; continue; + case 'f': *(p++) = '\f'; ctx->p++; continue; + case 'n': *(p++) = '\n'; ctx->p++; continue; + case 'r': *(p++) = '\r'; ctx->p++; continue; + case 't': *(p++) = '\t'; ctx->p++; continue; + case '"': *(p++) = '"'; ctx->p++; continue; + case '\\': *(p++) = '\\'; ctx->p++; continue; + /* Escaped Unicode handled below */ + case 'u': + /* + * Worst case for !strict we need 11 bytes for a truncated non-BMP + * codepoint escape. Call it 12. + */ + if (strict) + need = 4; + else + need = 12; + if (pend - p < need) { + /* Go back to the backslash, realloc, try again */ + ctx->p--; + continue; + } + + need = 0; + ctx->p++; + break; + default: + if (!strict) { + *(p++) = *ctx->p; + ctx->p++; + continue; + } + ctx->error = + heim_error_create(EINVAL, + "Invalid backslash escape at line %lu", + ctx->lineno); + free(p0); + return NULL; + } + + /* Unicode code point */ + if (pend - p < 12) { + need = 12; + ctx->p -= 2; /* for "\\u" */ + continue; /* This will cause p0 to be realloc'ed */ + } + p_save = ctx->p; + cbot = -3; + ctop = unescape_unicode(ctx); + if (ctop == -1 && strict) + return parse_string_error(ctx, p0, "Invalid escaped Unicode"); + if (ctop == -1) { + /* + * Not strict; tolerate bad input. + * + * Output "\\u" and then loop to treat what we expected to be four + * digits as if they were not part of an escaped Unicode codepoint. + */ + ctx->p = p_save; + if (p < pend) + *(p++) = '\\'; + if (p < pend) + *(p++) = 'u'; + continue; + } + if (ctop == 0) { + *(p++) = '\0'; + binary = 1; + continue; + } + if (ctop < 0xd800) { + if (!encode_utf8(ctx, &p, pend, ctop)) + return parse_string_error(ctx, p0, + "Internal JSON string parse error"); + continue; + } + + /* + * We parsed the top escaped codepoint of a surrogate pair encoding + * of a non-BMP Unicode codepoint. What follows must be another + * escaped codepoint. + */ + if (ctx->p < ctx->pend && ctx->p[0] == '\\') + ctx->p++; + else + ctop = -1; + if (ctop > -1 && ctx->p < ctx->pend && ctx->p[0] == 'u') + ctx->p++; + else + ctop = -1; + if (ctop > -1) { + /* Parse the hex digits of the bottom half of the surrogate pair */ + cbot = unescape_unicode(ctx); + if (cbot == -1 || cbot < 0xdc00) + ctop = -1; + } + if (ctop == -1) { + if (strict) + return parse_string_error(ctx, p0, + "Invalid surrogate pair"); + + /* + * Output "\\u", rewind, output the digits of `ctop'. + * + * When we get to what should have been the bottom half of the + * pair we'll necessarily fail to parse it as a normal escaped + * Unicode codepoint, and once again, rewind and output its digits. + */ + if (p < pend) + *(p++) = '\\'; + if (p < pend) + *(p++) = 'u'; + ctx->p = p_save; + continue; + } + + /* Finally decode the surrogate pair then encode as UTF-8 */ + ctop -= 0xd800; + cbot -= 0xdc00; + if (!encode_utf8(ctx, &p, pend, 0x10000 + ((ctop << 10) | (cbot & 0x3ff)))) + return parse_string_error(ctx, p0, + "Internal JSON string parse error"); + } + + if (p0 == NULL) + return heim_string_create(""); + + /* NUL-terminate for rk_base64_decode() and plain paranoia */ + if (p0 != NULL && p == pend) { + /* + * Work out how far p is into p0 to re-establish p after + * the realloc() + */ + size_t p0_to_pend_len = (pend - p0); + char *tmp = realloc(p0, 1 + p0_to_pend_len); + + if (tmp == NULL) { + ctx->error = heim_error_create_enomem(); + free(p0); + return NULL; + } + /* + * We have three pointers, p, pend (which are the same) + * and p0, we want to keep them pointing into the same + * memory after the realloc() + */ + p = tmp + p0_to_pend_len; + + pend = p + 1; + p0 = tmp; + } + *(p++) = '\0'; + + /* If there's embedded NULs, it's not a C string */ + if (binary) { + o = heim_data_ref_create(p0, (p - 1) - p0, free); + return o; + } + + /* Sadly this will copy `p0' */ + o = heim_string_create_with_bytes(p0, p - p0); + free(p0); + return o; +} + +static int +parse_pair(heim_dict_t dict, struct parse_ctx *ctx) +{ + heim_string_t key; + heim_object_t value; + + if (white_spaces(ctx)) + return -1; + + if (*ctx->p == '}') { + ctx->p++; + return 0; + } + + if (ctx->flags & HEIM_JSON_F_STRICT_DICT) + /* JSON allows only string keys */ + key = parse_string(ctx); + else + /* heim_dict_t allows any heim_object_t as key */ + key = parse_value(ctx); + if (key == NULL) + /* Even heim_dict_t does not allow C NULLs as keys though! */ + return -1; + + if (white_spaces(ctx)) { + heim_release(key); + return -1; + } + + if (*ctx->p != ':') { + heim_release(key); + return -1; + } + + ctx->p += 1; /* safe because we call white_spaces() next */ + + if (white_spaces(ctx)) { + heim_release(key); + return -1; + } + + value = parse_value(ctx); + if (value == NULL && + (ctx->error != NULL || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) { + if (ctx->error == NULL) + ctx->error = heim_error_create(EINVAL, "Invalid JSON encoding"); + heim_release(key); + return -1; + } + heim_dict_set_value(dict, key, value); + heim_release(key); + heim_release(value); + + if (white_spaces(ctx)) + return -1; + + if (*ctx->p == '}') { + /* + * Return 1 but don't consume the '}' so we can count the one + * pair in a one-pair dict + */ + return 1; + } else if (*ctx->p == ',') { + ctx->p++; + return 1; + } + return -1; +} + +static heim_dict_t +parse_dict(struct parse_ctx *ctx) +{ + heim_dict_t dict; + size_t count = 0; + int ret; + + heim_assert(*ctx->p == '{', "string doesn't start with {"); + + dict = heim_dict_create(11); + if (dict == NULL) { + ctx->error = heim_error_create_enomem(); + return NULL; + } + + ctx->p += 1; /* safe because parse_pair() calls white_spaces() first */ + + while ((ret = parse_pair(dict, ctx)) > 0) + count++; + if (ret < 0) { + heim_release(dict); + return NULL; + } + if (count == 1 && !(ctx->flags & HEIM_JSON_F_NO_DATA_DICT)) { + heim_object_t v = heim_dict_copy_value(dict, heim_tid_data_uuid_key); + + /* + * Binary data encoded as a dict with a single magic key with + * base64-encoded value? Decode as heim_data_t. + */ + if (v != NULL && heim_get_tid(v) == HEIM_TID_STRING) { + void *buf; + size_t len; + + buf = malloc(strlen(heim_string_get_utf8(v))); + if (buf == NULL) { + heim_release(dict); + heim_release(v); + ctx->error = heim_error_create_enomem(); + return NULL; + } + len = rk_base64_decode(heim_string_get_utf8(v), buf); + heim_release(v); + if (len == -1) { + free(buf); + return dict; /* assume aliasing accident */ + } + heim_release(dict); + return (heim_dict_t)heim_data_ref_create(buf, len, free); + } + } + return dict; +} + +static int +parse_item(heim_array_t array, struct parse_ctx *ctx) +{ + heim_object_t value; + + if (white_spaces(ctx)) + return -1; + + if (*ctx->p == ']') { + ctx->p++; /* safe because parse_value() calls white_spaces() first */ + return 0; + } + + value = parse_value(ctx); + if (value == NULL && + (ctx->error || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) + return -1; + + heim_array_append_value(array, value); + heim_release(value); + + if (white_spaces(ctx)) + return -1; + + if (*ctx->p == ']') { + ctx->p++; + return 0; + } else if (*ctx->p == ',') { + ctx->p++; + return 1; + } + return -1; +} + +static heim_array_t +parse_array(struct parse_ctx *ctx) +{ + heim_array_t array = heim_array_create(); + int ret; + + heim_assert(*ctx->p == '[', "array doesn't start with ["); + ctx->p += 1; + + while ((ret = parse_item(array, ctx)) > 0) + ; + if (ret < 0) { + heim_release(array); + return NULL; + } + return array; +} + +static heim_object_t +parse_value(struct parse_ctx *ctx) +{ + size_t len; + heim_object_t o; + + if (white_spaces(ctx)) + return NULL; + + if (*ctx->p == '"') { + return parse_string(ctx); + } else if (*ctx->p == '{') { + if (ctx->depth-- == 1) { + ctx->error = heim_error_create(EINVAL, "JSON object too deep"); + return NULL; + } + o = parse_dict(ctx); + ctx->depth++; + return o; + } else if (*ctx->p == '[') { + if (ctx->depth-- == 1) { + ctx->error = heim_error_create(EINVAL, "JSON object too deep"); + return NULL; + } + o = parse_array(ctx); + ctx->depth++; + return o; + } else if (is_number(*ctx->p) || *ctx->p == '-') { + return parse_number(ctx); + } + + len = ctx->pend - ctx->p; + + if ((ctx->flags & HEIM_JSON_F_NO_C_NULL) == 0 && + len >= 6 && memcmp(ctx->p, "", 6) == 0) { + ctx->p += 6; + return heim_null_create(); + } else if (len >= 4 && memcmp(ctx->p, "null", 4) == 0) { + ctx->p += 4; + return heim_null_create(); + } else if (len >= 4 && strncasecmp((char *)ctx->p, "true", 4) == 0) { + ctx->p += 4; + return heim_bool_create(1); + } else if (len >= 5 && strncasecmp((char *)ctx->p, "false", 5) == 0) { + ctx->p += 5; + return heim_bool_create(0); + } + + ctx->error = heim_error_create(EINVAL, "unknown char %c at %lu line %lu", + (char)*ctx->p, + (unsigned long)(ctx->p - ctx->pstart), + ctx->lineno); + return NULL; +} + + +heim_object_t +heim_json_create(const char *string, size_t max_depth, heim_json_flags_t flags, + heim_error_t *error) +{ + return heim_json_create_with_bytes(string, strlen(string), max_depth, flags, + error); +} + +heim_object_t +heim_json_create_with_bytes(const void *data, size_t length, size_t max_depth, + heim_json_flags_t flags, heim_error_t *error) +{ + struct parse_ctx ctx; + heim_object_t o; + + heim_base_once_f(&heim_json_once, NULL, json_init_once); + + ctx.lineno = 1; + ctx.p = data; + ctx.pstart = data; + ctx.pend = ((uint8_t *)data) + length; + ctx.error = NULL; + ctx.flags = flags; + ctx.depth = max_depth; + + o = parse_value(&ctx); + + if (o == NULL && error) { + *error = ctx.error; + } else if (ctx.error) { + heim_release(ctx.error); + } + + return o; +} + + +static void +show_printf(void *ctx, const char *str) +{ + if (str == NULL) + return; + fprintf(ctx, "%s", str); +} + +/** + * Dump a heimbase object to stderr (useful from the debugger!) + * + * @param obj object to dump using JSON or JSON-like format + * + * @addtogroup heimbase + */ +void +heim_show(heim_object_t obj) +{ + heim_base2json(obj, stderr, HEIM_JSON_F_NO_DATA_DICT, show_printf); +} + +static void +strbuf_add(void *ctx, const char *str) +{ + struct heim_strbuf *strbuf = ctx; + size_t len; + + if (strbuf->enomem) + return; + + if (str == NULL) { + /* + * Eat the last '\n'; this is used when formatting dict pairs + * and array items so that the ',' separating them is never + * preceded by a '\n'. + */ + if (strbuf->len > 0 && strbuf->str[strbuf->len - 1] == '\n') + strbuf->len--; + return; + } + + len = strlen(str); + if ((len + 1) > (strbuf->alloced - strbuf->len)) { + size_t new_len = strbuf->alloced + (strbuf->alloced >> 2) + len + 1; + char *s; + + s = realloc(strbuf->str, new_len); + if (s == NULL) { + strbuf->enomem = 1; + return; + } + strbuf->str = s; + strbuf->alloced = new_len; + } + /* +1 so we copy the NUL */ + (void) memcpy(strbuf->str + strbuf->len, str, len + 1); + strbuf->len += len; + if (strbuf->str[strbuf->len - 1] == '\n' && + strbuf->flags & HEIM_JSON_F_ONE_LINE) + strbuf->len--; +} + +#define STRBUF_INIT_SZ 64 + +heim_string_t +heim_json_copy_serialize(heim_object_t obj, heim_json_flags_t flags, heim_error_t *error) +{ + heim_string_t str; + struct heim_strbuf strbuf; + int ret; + + if (error) + *error = NULL; + + memset(&strbuf, 0, sizeof (strbuf)); + strbuf.str = malloc(STRBUF_INIT_SZ); + if (strbuf.str == NULL) { + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + strbuf.len = 0; + strbuf.alloced = STRBUF_INIT_SZ; + strbuf.str[0] = '\0'; + strbuf.flags = flags; + + ret = heim_base2json(obj, &strbuf, flags, strbuf_add); + if (ret || strbuf.enomem) { + if (error) { + if (strbuf.enomem || ret == ENOMEM) + *error = heim_error_create_enomem(); + else + *error = heim_error_create(1, "Impossible to JSON-encode " + "object"); + } + free(strbuf.str); + return NULL; + } + if (flags & HEIM_JSON_F_ONE_LINE) { + strbuf.flags &= ~HEIM_JSON_F_ONE_LINE; + strbuf_add(&strbuf, "\n"); + } + str = heim_string_ref_create(strbuf.str, free); + if (str == NULL) { + if (error) + *error = heim_error_create_enomem(); + free(strbuf.str); + } + return str; +} + +struct heim_eq_f_ctx { + heim_dict_t other; + int ret; +}; + +static void +heim_eq_dict_iter_f(heim_object_t key, heim_object_t val, void *d) +{ + struct heim_eq_f_ctx *ctx = d; + heim_object_t other_val; + + if (!ctx->ret) + return; + + /* + * This doesn't work if the key is an array or a dict, which, anyways, + * isn't allowed in JSON, though we allow it. + */ + other_val = heim_dict_get_value(ctx->other, key); + ctx->ret = heim_json_eq(val, other_val); +} + +int +heim_json_eq(heim_object_t a, heim_object_t b) +{ + heim_tid_t atid, btid; + + if (a == b) + return 1; + if (a == NULL || b == NULL) + return 0; + atid = heim_get_tid(a); + btid = heim_get_tid(b); + if (atid != btid) + return 0; + switch (atid) { + case HEIM_TID_ARRAY: { + size_t len = heim_array_get_length(b); + size_t i; + + if (heim_array_get_length(a) != len) + return 0; + for (i = 0; i < len; i++) { + if (!heim_json_eq(heim_array_get_value(a, i), + heim_array_get_value(b, i))) + return 0; + } + return 1; + } + case HEIM_TID_DICT: { + struct heim_eq_f_ctx ctx; + + ctx.other = b; + ctx.ret = 1; + heim_dict_iterate_f(a, &ctx, heim_eq_dict_iter_f); + + if (ctx.ret) { + ctx.other = a; + heim_dict_iterate_f(b, &ctx, heim_eq_dict_iter_f); + } + return ctx.ret; + } + case HEIM_TID_STRING: + return strcmp(heim_string_get_utf8(a), heim_string_get_utf8(b)) == 0; + case HEIM_TID_DATA: { + return heim_data_get_length(a) == heim_data_get_length(b) && + memcmp(heim_data_get_ptr(a), heim_data_get_ptr(b), + heim_data_get_length(a)) == 0; + } + case HEIM_TID_NUMBER: + return heim_number_get_long(a) == heim_number_get_long(b); + case HEIM_TID_NULL: + case HEIM_TID_BOOL: + return heim_bool_val(a) == heim_bool_val(b); + default: + break; + } + return 0; +} diff --git a/third_party/heimdal/lib/base/log.c b/third_party/heimdal/lib/base/log.c new file mode 100644 index 0000000..9a97276 --- /dev/null +++ b/third_party/heimdal/lib/base/log.c @@ -0,0 +1,1079 @@ +/* + * Copyright (c) 1997-2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include "heim_threads.h" +#include "heimbase-atomics.h" +#include "heimbase.h" +#include "heimbase-svc.h" +#include +#include +#include +#include + +struct heim_log_facility_internal { + int min; + int max; + heim_log_log_func_t log_func; + heim_log_close_func_t close_func; + void *data; +}; + +struct heim_log_facility_s { + char *program; + heim_base_atomic(uint32_t) refs; + size_t len; + struct heim_log_facility_internal *val; +}; + +typedef struct heim_pcontext_s *heim_pcontext; +typedef struct heim_pconfig *heim_pconfig; +struct heim_svc_req_desc_common_s { + HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; +}; + +static struct heim_log_facility_internal * +log_realloc(heim_log_facility *f) +{ + struct heim_log_facility_internal *fp; + fp = realloc(f->val, (f->len + 1) * sizeof(*f->val)); + if (fp == NULL) + return NULL; + f->len++; + f->val = fp; + fp += f->len - 1; + return fp; +} + +struct s2i { + const char *s; + int val; +}; + +#define L(X) { #X, LOG_ ## X } + +static struct s2i syslogvals[] = { + L(EMERG), + L(ALERT), + L(CRIT), + L(ERR), + L(WARNING), + L(NOTICE), + L(INFO), + L(DEBUG), + + L(AUTH), +#ifdef LOG_AUTHPRIV + L(AUTHPRIV), +#endif +#ifdef LOG_CRON + L(CRON), +#endif + L(DAEMON), +#ifdef LOG_FTP + L(FTP), +#endif + L(KERN), + L(LPR), + L(MAIL), +#ifdef LOG_NEWS + L(NEWS), +#endif + L(SYSLOG), + L(USER), +#ifdef LOG_UUCP + L(UUCP), +#endif + L(LOCAL0), + L(LOCAL1), + L(LOCAL2), + L(LOCAL3), + L(LOCAL4), + L(LOCAL5), + L(LOCAL6), + L(LOCAL7), + { NULL, -1 } +}; + +static int +find_value(const char *s, struct s2i *table) +{ + while (table->s && strcasecmp(table->s, s) != 0) + table++; + return table->val; +} + +heim_error_code +heim_initlog(heim_context context, + const char *program, + heim_log_facility **fac) +{ + heim_log_facility *f = calloc(1, sizeof(*f)); + if (f == NULL) + return heim_enomem(context); + f->refs = 1; + f->program = strdup(program); + if (f->program == NULL) { + free(f); + return heim_enomem(context); + } + *fac = f; + return 0; +} + +heim_log_facility * +heim_log_ref(heim_log_facility *fac) +{ + if (fac) + (void) heim_base_atomic_inc_32(&fac->refs); + return fac; +} + +heim_error_code +heim_addlog_func(heim_context context, + heim_log_facility *fac, + int min, + int max, + heim_log_log_func_t log_func, + heim_log_close_func_t close_func, + void *data) +{ + struct heim_log_facility_internal *fp = log_realloc(fac); + if (fp == NULL) + return heim_enomem(context); + fp->min = min; + fp->max = max; + fp->log_func = log_func; + fp->close_func = close_func; + fp->data = data; + return 0; +} + + +struct _heimdal_syslog_data{ + int priority; +}; + +static void HEIM_CALLCONV +log_syslog(heim_context context, const char *timestr, + const char *msg, void *data) +{ + struct _heimdal_syslog_data *s = data; + syslog(s->priority, "%s", msg); +} + +static void HEIM_CALLCONV +close_syslog(void *data) +{ + free(data); + closelog(); +} + +static heim_error_code +open_syslog(heim_context context, + heim_log_facility *facility, int min, int max, + const char *sev, const char *fac) +{ + struct _heimdal_syslog_data *sd; + heim_error_code ret; + int i; + + if (facility == NULL) + return EINVAL; + if ((sd = calloc(1, sizeof(*sd))) == NULL) + return heim_enomem(context); + i = find_value(sev, syslogvals); + if (i == -1) + i = LOG_ERR; + sd->priority = i; + i = find_value(fac, syslogvals); + if (i == -1) + i = LOG_AUTH; + sd->priority |= i; + roken_openlog(facility->program, LOG_PID | LOG_NDELAY, i); + ret = heim_addlog_func(context, facility, min, max, log_syslog, + close_syslog, sd); + if (ret) + free(sd); + else + sd = NULL; + return ret; +} + +struct file_data { + char *filename; + const char *mode; + struct timeval tv; + FILE *fd; + int disp; +#define FILEDISP_KEEPOPEN 0x1 +#define FILEDISP_REOPEN 0x2 +#define FILEDISP_IFEXISTS 0x4 +}; + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +static void HEIM_CALLCONV +log_file(heim_context context, const char *timestr, const char *msg, void *data) +{ + struct timeval tv; + struct file_data *f = data; + FILE *logf = f->fd; + char *msgclean; + size_t i = 0; + size_t j; + + if (f->filename && (logf == NULL || (f->disp & FILEDISP_REOPEN))) { + int flags = O_WRONLY|O_APPEND; + int fd; + + if (f->mode[0] == 'e') { + flags |= O_CLOEXEC; + i = 1; + } + if (f->mode[i] == 'w') + flags |= O_TRUNC; + if (f->mode[i + 1] == '+') + flags |= O_RDWR; + + if (f->disp & FILEDISP_IFEXISTS) { + /* Cache failure for 1s */ + gettimeofday(&tv, NULL); + if (tv.tv_sec == f->tv.tv_sec) + return; + } else { + flags |= O_CREAT; + } + + fd = open(f->filename, flags, 0666); /* umask best be set */ + if (fd == -1) { + if (f->disp & FILEDISP_IFEXISTS) + gettimeofday(&f->tv, NULL); + return; + } + rk_cloexec(fd); + logf = fdopen(fd, f->mode); + } + if (f->fd == NULL && (f->disp & FILEDISP_KEEPOPEN)) + f->fd = logf; + if (logf == NULL) + return; + /* + * make sure the log doesn't contain special chars: + * we used to use strvisx(3) to encode the log, but this is + * inconsistent with our syslog(3) code which does not do this. + * It also makes it inelegant to write data which has already + * been quoted such as what krb5_unparse_principal() gives us. + * So, we change here to eat the special characters, instead. + */ + if (msg && (msgclean = strdup(msg))) { + for (i = 0, j = 0; msg[i]; i++) + if (msg[i] >= 32 || msg[i] == '\t') + msgclean[j++] = msg[i]; + fprintf(logf, "%s %s\n", timestr ? timestr : "", msgclean); + free(msgclean); + } + if (logf != f->fd) + fclose(logf); +} + +static void HEIM_CALLCONV +close_file(void *data) +{ + struct file_data *f = data; + if (f->fd && f->fd != stdout && f->fd != stderr) + fclose(f->fd); + free(f->filename); + free(data); +} + +static heim_error_code +open_file(heim_context context, heim_log_facility *fac, int min, int max, + const char *filename, const char *mode, FILE *f, int disp, + int exp_tokens) +{ + heim_error_code ret = 0; + struct file_data *fd; + + if ((fd = calloc(1, sizeof(*fd))) == NULL) + return heim_enomem(context); + + fd->filename = NULL; + fd->mode = mode; + fd->fd = f; + fd->disp = disp; + + if (filename) { + if (exp_tokens) + ret = heim_expand_path_tokens(context, filename, 1, &fd->filename, NULL); + else if ((fd->filename = strdup(filename)) == NULL) + ret = heim_enomem(context); + } + if (ret == 0) + ret = heim_addlog_func(context, fac, min, max, log_file, close_file, fd); + if (ret) { + free(fd->filename); + free(fd); + } else if (disp & FILEDISP_KEEPOPEN) { + log_file(context, NULL, NULL, fd); + fd = NULL; + } + return ret; +} + +heim_error_code +heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig) +{ + heim_error_code ret = 0; + int min = 0, max = 3, n; + char c; + const char *p = orig; +#ifdef _WIN32 + const char *q; +#endif + + n = sscanf(p, "%d%c%d/", &min, &c, &max); + if (n == 2) { + if (ISPATHSEP(c)) { + if (min < 0) { + max = -min; + min = 0; + } else { + max = min; + } + } + if (c == '-') + max = -1; + } + if (n) { +#ifdef _WIN32 + q = strrchr(p, '\\'); + if (q != NULL) + p = q; + else +#endif + p = strchr(p, '/'); + if (p == NULL) { + heim_set_error_message(context, EINVAL /*XXX HEIM_ERR_LOG_PARSE*/, + N_("failed to parse \"%s\"", ""), orig); + return EINVAL /*XXX HEIM_ERR_LOG_PARSE*/; + } + p++; + } + if (strcmp(p, "STDERR") == 0) { + ret = open_file(context, f, min, max, NULL, "a", stderr, + FILEDISP_KEEPOPEN, 0); + } else if (strcmp(p, "CONSOLE") == 0) { + /* XXX WIN32 */ + ret = open_file(context, f, min, max, "/dev/console", "w", NULL, + FILEDISP_KEEPOPEN, 0); + } else if (strncmp(p, "EFILE:", 5) == 0) { + ret = open_file(context, f, min, max, p + sizeof("EFILE:") - 1, "a", + NULL, FILEDISP_IFEXISTS | FILEDISP_REOPEN, 1); + } else if (strncmp(p, "EFILE=", 5) == 0) { + ret = open_file(context, f, min, max, p + sizeof("EFILE=") - 1, "a", + NULL, FILEDISP_IFEXISTS | FILEDISP_KEEPOPEN, 1); + } else if (strncmp(p, "FILE:", sizeof("FILE:") - 1) == 0) { + ret = open_file(context, f, min, max, p + sizeof("FILE:") - 1, "a", + NULL, FILEDISP_REOPEN, 1); + } else if (strncmp(p, "FILE=", sizeof("FILE=") - 1) == 0) { + ret = open_file(context, f, min, max, p + sizeof("FILE=") - 1, "a", + NULL, FILEDISP_KEEPOPEN, 1); + } else if (strncmp(p, "DEVICE:", sizeof("DEVICE:") - 1) == 0) { + ret = open_file(context, f, min, max, p + sizeof("DEVICE:") - 1, "a", + NULL, FILEDISP_REOPEN, 0); + } else if (strncmp(p, "DEVICE=", sizeof("DEVICE=") - 1) == 0) { + ret = open_file(context, f, min, max, p + sizeof("DEVICE=") - 1, "a", + NULL, FILEDISP_KEEPOPEN, 0); + } else if (strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')) { + char severity[128] = ""; + char facility[128] = ""; + p += 6; + if (*p != '\0') + p++; + if (strsep_copy(&p, ":", severity, sizeof(severity)) != -1) + strsep_copy(&p, ":", facility, sizeof(facility)); + if (*severity == '\0') + strlcpy(severity, "ERR", sizeof(severity)); + if (*facility == '\0') + strlcpy(facility, "AUTH", sizeof(facility)); + ret = open_syslog(context, f, min, max, severity, facility); + } else { + ret = EINVAL; /*XXX HEIM_ERR_LOG_PARSE*/ + heim_set_error_message(context, ret, + N_("unknown log type: %s", ""), p); + } + return ret; +} + +heim_error_code +heim_openlog(heim_context context, + const char *program, + const char **specs, + heim_log_facility **fac) +{ + heim_error_code ret; + + ret = heim_initlog(context, program, fac); + if (ret) + return ret; + + if (specs) { + size_t i; + for (i = 0; specs[i] && ret == 0; i++) + ret = heim_addlog_dest(context, *fac, specs[i]); + } else { + ret = heim_addlog_dest(context, *fac, "SYSLOG"); + } + return ret; +} + +void +heim_closelog(heim_context context, heim_log_facility *fac) +{ + int i; + + if (!fac || heim_base_atomic_dec_32(&fac->refs)) + return; + for (i = 0; i < fac->len; i++) + (*fac->val[i].close_func)(fac->val[i].data); + free(fac->val); + free(fac->program); + fac->val = NULL; + fac->len = 0; + fac->program = NULL; + free(fac); + return; +} + +static void +format_time(heim_context context, time_t t, char *s, size_t len) +{ + struct tm *tm = heim_context_get_log_utc(context) ? + gmtime(&t) : localtime(&t); + if (tm && strftime(s, len, heim_context_get_time_fmt(context), tm)) + return; + snprintf(s, len, "%ld", (long)t); +} + +#undef __attribute__ +#define __attribute__(X) + +heim_error_code +heim_vlog_msg(heim_context context, + heim_log_facility *fac, + char **reply, + int level, + const char *fmt, + va_list ap) +__attribute__ ((__format__ (__printf__, 5, 0))) +{ + + char *msg = NULL; + const char *actual = NULL; + char buf[64]; + time_t t = 0; + int i; + + if (!fac) + fac = context->log_dest; + for (i = 0; fac && i < fac->len; i++) + if (fac->val[i].min <= level && + (fac->val[i].max < 0 || fac->val[i].max >= level)) { + if (t == 0) { + t = time(NULL); + format_time(context, t, buf, sizeof(buf)); + } + if (actual == NULL) { + int ret = vasprintf(&msg, fmt, ap); + if (ret < 0 || msg == NULL) + actual = fmt; + else + actual = msg; + } + (*fac->val[i].log_func)(context, buf, actual, fac->val[i].data); + } + if (reply == NULL) + free(msg); + else + *reply = msg; + return 0; +} + +heim_error_code +heim_vlog(heim_context context, + heim_log_facility *fac, + int level, + const char *fmt, + va_list ap) +__attribute__ ((__format__ (__printf__, 4, 0))) +{ + return heim_vlog_msg(context, fac, NULL, level, fmt, ap); +} + +heim_error_code +heim_log_msg(heim_context context, + heim_log_facility *fac, + int level, + char **reply, + const char *fmt, + ...) +__attribute__ ((__format__ (__printf__, 5, 6))) +{ + va_list ap; + heim_error_code ret; + + va_start(ap, fmt); + ret = heim_vlog_msg(context, fac, reply, level, fmt, ap); + va_end(ap); + return ret; +} + + +heim_error_code +heim_log(heim_context context, + heim_log_facility *fac, + int level, + const char *fmt, + ...) +__attribute__ ((__format__ (__printf__, 4, 5))) +{ + va_list ap; + heim_error_code ret; + + va_start(ap, fmt); + ret = heim_vlog(context, fac, level, fmt, ap); + va_end(ap); + return ret; +} + +void +heim_debug(heim_context context, + int level, + const char *fmt, + ...) +__attribute__ ((__format__ (__printf__, 3, 4))) +{ + heim_log_facility *fac; + va_list ap; + + if (context == NULL || + (fac = heim_get_debug_dest(context)) == NULL) + return; + + va_start(ap, fmt); + heim_vlog(context, fac, level, fmt, ap); + va_end(ap); +} + +void +heim_vdebug(heim_context context, + int level, + const char *fmt, + va_list ap) +__attribute__ ((__format__ (__printf__, 3, 0))) +{ + heim_log_facility *fac; + + if (context == NULL || + (fac = heim_get_debug_dest(context)) == NULL) + return; + + heim_vlog(context, fac, level, fmt, ap); +} + +heim_error_code +heim_have_debug(heim_context context, int level) +{ + return (context != NULL && heim_get_debug_dest(context) != NULL); +} + +heim_error_code +heim_add_warn_dest(heim_context context, const char *program, + const char *log_spec) +{ + heim_log_facility *fac; + + heim_error_code ret; + + if ((fac = heim_get_warn_dest(context)) == NULL) { + ret = heim_initlog(context, program, &fac); + if (ret) + return ret; + heim_set_warn_dest(context, fac); + } + + ret = heim_addlog_dest(context, fac, log_spec); + if (ret) + return ret; + return 0; +} + +heim_error_code +heim_add_debug_dest(heim_context context, const char *program, + const char *log_spec) +{ + heim_log_facility *fac; + heim_error_code ret; + + if ((fac = heim_get_debug_dest(context)) == NULL) { + ret = heim_initlog(context, program, &fac); + if (ret) + return ret; + heim_set_debug_dest(context, fac); + } + + ret = heim_addlog_dest(context, fac, log_spec); + if (ret) + return ret; + return 0; +} + +struct heim_audit_kv_tuple { + heim_string_t key; + heim_object_t value; +}; + +static struct heim_audit_kv_tuple zero_tuple; + +static struct heim_audit_kv_tuple +fmtkv(int flags, const char *k, const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + size_t i; + ssize_t j; + struct heim_audit_kv_tuple kv; + char *value; + char *value_vis; + + j = vasprintf(&value, fmt, ap); + if (j < 0 || value == NULL) + return zero_tuple; + + /* We optionally eat the whitespace. */ + + if (flags & HEIM_SVC_AUDIT_EATWHITE) { + for (i=0, j=0; value[i]; i++) + if (value[i] != ' ' && value[i] != '\t') + value[j++] = value[i]; + value[j] = '\0'; + } + + if (flags & (HEIM_SVC_AUDIT_VIS | HEIM_SVC_AUDIT_VISLAST)) { + int vis_flags = VIS_CSTYLE | VIS_OCTAL | VIS_NL; + + if (flags & HEIM_SVC_AUDIT_VIS) + vis_flags |= VIS_WHITE; + value_vis = malloc((j + 1) * 4 + 1); + if (value_vis) + strvisx(value_vis, value, j, vis_flags); + free(value); + if (value_vis == NULL) + return zero_tuple; + } else + value_vis = value; + + if (k) + kv.key = heim_string_create(k); + else + kv.key = NULL; + kv.value = heim_string_ref_create(value_vis, free); + + return kv; +} + +void +heim_audit_vaddreason(heim_svc_req_desc r, const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 2, 0))) +{ + struct heim_audit_kv_tuple kv; + + kv = fmtkv(HEIM_SVC_AUDIT_VISLAST, NULL, fmt, ap); + if (kv.value == NULL) { + heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddreason: " + "failed to add reason (out of memory)"); + return; + } + + heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddreason(): " + "adding reason %s", heim_string_get_utf8(kv.value)); + if (r->reason) { + heim_string_t str2; + + str2 = heim_string_create_with_format("%s: %s", + heim_string_get_utf8(kv.value), + heim_string_get_utf8(r->reason)); + if (str2) { + heim_release(kv.value); + kv.value = str2; + } + } + heim_release(r->reason); + r->reason = kv.value; +} + +void +heim_audit_addreason(heim_svc_req_desc r, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))) +{ + va_list ap; + + va_start(ap, fmt); + heim_audit_vaddreason(r, fmt, ap); + va_end(ap); +} + +size_t +addkv(heim_svc_req_desc r, heim_object_t key, heim_object_t value) +{ + size_t index; + heim_object_t obj; + + obj = heim_dict_get_value(r->kv, key); + if (obj) { + if (heim_get_tid(obj) == HEIM_TID_ARRAY) { + index = heim_array_get_length(obj); + heim_array_append_value(obj, value); + } else { + heim_array_t array = heim_array_create(); + + index = 1; + heim_array_append_value(array, obj); + heim_array_append_value(array, value); + heim_dict_set_value(r->kv, key, array); + heim_release(array); /* retained by r->kv */ + } + } else { + index = 0; + heim_dict_set_value(r->kv, key, value); + } + + return index; +} + +/* + * add a key-value token. if the key already exists, the value is + * promoted to an array of values. + */ + +void +heim_audit_vaddkv(heim_svc_req_desc r, int flags, const char *k, + const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 4, 0))) +{ + struct heim_audit_kv_tuple kv; + size_t index; + + kv = fmtkv(flags, k, fmt, ap); + if (kv.key == NULL || kv.value == NULL) { + heim_log(r->hcontext, r->logf, 1, "heim_audit_vaddkv: " + "failed to add kv pair (out of memory)"); + heim_release(kv.key); + heim_release(kv.value); + return; + } + + index = addkv(r, kv.key, kv.value); + + heim_log(r->hcontext, r->logf, 7, "heim_audit_vaddkv(): " + "kv pair[%zu] %s=%s", index, + heim_string_get_utf8(kv.key), heim_string_get_utf8(kv.value)); + + heim_release(kv.key); + heim_release(kv.value); +} + +void +heim_audit_addkv(heim_svc_req_desc r, int flags, const char *k, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))) +{ + va_list ap; + + va_start(ap, fmt); + heim_audit_vaddkv(r, flags, k, fmt, ap); + va_end(ap); +} + +void +heim_audit_addkv_timediff(heim_svc_req_desc r, const char *k, + const struct timeval *start, + const struct timeval *end) +{ + time_t sec; + int usec; + const char *sign = ""; + + if (end->tv_sec > start->tv_sec || + (end->tv_sec == start->tv_sec && end->tv_usec >= start->tv_usec)) { + sec = end->tv_sec - start->tv_sec; + usec = end->tv_usec - start->tv_usec; + } else { + sec = start->tv_sec - end->tv_sec; + usec = start->tv_usec - end->tv_usec; + sign = "-"; + } + + if (usec < 0) { + usec += 1000000; + sec -= 1; + } + + heim_audit_addkv(r, 0, k, "%s%ld.%06d", sign, (long)sec, usec); +} + +void +heim_audit_setkv_bool(heim_svc_req_desc r, const char *k, int v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_bool(): " + "setting kv pair %s=%s", k, v ? "true" : "false"); + + value = heim_bool_create(v); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_addkv_number(heim_svc_req_desc r, const char *k, int64_t v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_number(): " + "adding kv pair %s=%lld", k, (long long)v); + + value = heim_number_create(v); + addkv(r, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_setkv_number(heim_svc_req_desc r, const char *k, int64_t v) +{ + heim_string_t key = heim_string_create(k); + heim_number_t value; + + if (key == NULL) + return; + + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_number(): " + "setting kv pair %s=%lld", k, (long long)v); + + value = heim_number_create(v); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(value); +} + +void +heim_audit_addkv_object(heim_svc_req_desc r, const char *k, heim_object_t value) +{ + heim_string_t key = heim_string_create(k); + heim_string_t descr; + + if (key == NULL) + return; + + descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL); + heim_log(r->hcontext, r->logf, 7, "heim_audit_addkv_object(): " + "adding kv pair %s=%s", + k, descr ? heim_string_get_utf8(descr) : ""); + addkv(r, key, value); + heim_release(key); + heim_release(descr); +} + +void +heim_audit_setkv_object(heim_svc_req_desc r, const char *k, heim_object_t value) +{ + heim_string_t key = heim_string_create(k); + heim_string_t descr; + + if (key == NULL) + return; + + descr = heim_json_copy_serialize(value, HEIM_JSON_F_NO_DATA_DICT, NULL); + heim_log(r->hcontext, r->logf, 7, "heim_audit_setkv_object(): " + "setting kv pair %s=%s", + k, descr ? heim_string_get_utf8(descr) : ""); + heim_dict_set_value(r->kv, key, value); + heim_release(key); + heim_release(descr); +} + +heim_object_t +heim_audit_getkv(heim_svc_req_desc r, const char *k) +{ + heim_string_t key; + heim_object_t value; + + key = heim_string_create(k); + if (key == NULL) + return NULL; + + value = heim_dict_get_value(r->kv, key); + heim_release(key); + return value; +} + +struct heim_audit_kv_buf { + char buf[1024]; + size_t pos; + heim_object_t iter; +}; + +static void +audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg); + +static void +audit_trail_iterator_array(heim_object_t value, void *arg, int *stop) +{ + struct heim_audit_kv_buf *kvb = arg; + + audit_trail_iterator(kvb->iter, value, kvb); +} + +static void +audit_trail_iterator(heim_object_t key, heim_object_t value, void *arg) +{ + struct heim_audit_kv_buf *kvb = arg; + char num[32]; + const char *k = heim_string_get_utf8(key), *v = NULL; + char *b64 = NULL; + + if (k == NULL || *k == '#') /* # keys are hidden */ + return; + + switch (heim_get_tid(value)) { + case HEIM_TID_STRING: + v = heim_string_get_utf8(value); + break; + case HEIM_TID_NUMBER: + snprintf(num, sizeof(num), "%lld", (long long)heim_number_get_long(value)); + v = num; + break; + case HEIM_TID_NULL: + v = "null"; + break; + case HEIM_TID_BOOL: + v = heim_bool_val(value) ? "true" : "false"; + break; + case HEIM_TID_ARRAY: + if (kvb->iter) + break; /* arrays cannot be nested */ + + kvb->iter = key; + heim_array_iterate_f(value, kvb, audit_trail_iterator_array); + kvb->iter = NULL; + break; + case HEIM_TID_DATA: { + const heim_octet_string *data = heim_data_get_data(value); + if (rk_base64_encode(data->data, data->length, &b64) >= 0) + v = b64; + break; + } + default: + break; + } + + if (v == NULL) + return; + + if (kvb->pos < sizeof(kvb->buf) - 1) + kvb->buf[kvb->pos++] = ' '; + for (; *k && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++) + kvb->buf[kvb->pos] = *k++; + if (kvb->pos < sizeof(kvb->buf) - 1) + kvb->buf[kvb->pos++] = '='; + for (; *v && kvb->pos < sizeof(kvb->buf) - 1; kvb->pos++) + kvb->buf[kvb->pos] = *v++; + + free(b64); +} + +void +heim_audit_trail(heim_svc_req_desc r, heim_error_code ret, const char *retname) +{ + const char *retval; + struct heim_audit_kv_buf kvb; + char retvalbuf[30]; /* Enough for UNKNOWN-%d */ + +#define CASE(x) case x : retval = #x; break + if (retname) { + retval = retname; + } else switch (ret ? ret : r->error_code) { + CASE(ENOMEM); + CASE(ENOENT); + CASE(EACCES); + case 0: + retval = "SUCCESS"; + break; + default: + /* Wish we had a com_err number->symbolic name function */ + (void) snprintf(retvalbuf, sizeof(retvalbuf), "UNKNOWN-%d", + ret ? ret : r->error_code); + retval = retvalbuf; + break; + } + + heim_audit_addkv_timediff(r, "elapsed", &r->tv_start, &r->tv_end); + if (r->e_text && r->kv) + heim_audit_addkv(r, HEIM_SVC_AUDIT_VIS, "e-text", "%s", r->e_text); + + memset(&kvb, 0, sizeof(kvb)); + if (r->kv) + heim_dict_iterate_f(r->kv, &kvb, audit_trail_iterator); + kvb.buf[kvb.pos] = '\0'; + + heim_log(r->hcontext, r->logf, 3, "%s %s %s %s %s%s%s%s", + r->reqtype, retval, r->from, + r->cname ? r->cname : "", + r->sname ? r->sname : "", + kvb.buf, r->reason ? " reason=" : "", + r->reason ? heim_string_get_utf8(r->reason) : ""); +} diff --git a/third_party/heimdal/lib/base/null.c b/third_party/heimdal/lib/base/null.c new file mode 100644 index 0000000..43bde96 --- /dev/null +++ b/third_party/heimdal/lib/base/null.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +struct heim_type_data _heim_null_object = { + HEIM_TID_NULL, + "null-object", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +heim_null_t +heim_null_create(void) +{ + return heim_base_make_tagged_object(0, HEIM_TID_NULL); +} diff --git a/third_party/heimdal/lib/base/number.c b/third_party/heimdal/lib/base/number.c new file mode 100644 index 0000000..8833c8b --- /dev/null +++ b/third_party/heimdal/lib/base/number.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" + +static void HEIM_CALLCONV +number_dealloc(void *ptr) +{ +} + +static int +number_cmp(void *a, void *b) +{ + int na, nb; + + if (heim_base_is_tagged_object(a)) + na = heim_base_tagged_object_value(a); + else + na = *(int *)a; + + if (heim_base_is_tagged_object(b)) + nb = heim_base_tagged_object_value(b); + else + nb = *(int *)b; + + return na - nb; +} + +static uintptr_t +number_hash(void *ptr) +{ + if (heim_base_is_tagged_object(ptr)) + return heim_base_tagged_object_value(ptr); + return (uintptr_t)*(int64_t *)ptr; +} + +struct heim_type_data _heim_number_object = { + HEIM_TID_NUMBER, + "number-object", + NULL, + number_dealloc, + NULL, + number_cmp, + number_hash, + NULL +}; + +/** + * Create a number object + * + * @param the number to contain in the object + * + * @return a number object + */ + +heim_number_t +heim_number_create(int64_t number) +{ + heim_number_t n; + + if (number < 0xffffff && number >= 0) + return heim_base_make_tagged_object(number, HEIM_TID_NUMBER); + + n = _heim_alloc_object(&_heim_number_object, sizeof(int64_t)); + if (n) + *((int64_t *)n) = number; + return n; +} + +/** + * Return the type ID of number objects + * + * @return type id of number objects + */ + +heim_tid_t +heim_number_get_type_id(void) +{ + return HEIM_TID_NUMBER; +} + +/** + * Get the int value of the content + * + * @param number the number object to get the value from + * + * @return an int + */ + +int +heim_number_get_int(heim_number_t number) +{ + if (heim_base_is_tagged_object(number)) + return heim_base_tagged_object_value(number); + return (int)(*(int64_t *)number); +} + +int64_t +heim_number_get_long(heim_number_t number) +{ + if (heim_base_is_tagged_object(number)) + return heim_base_tagged_object_value(number); + return *(int64_t *)number; +} diff --git a/third_party/heimdal/lib/base/plugin.c b/third_party/heimdal/lib/base/plugin.c new file mode 100644 index 0000000..87bb5f7 --- /dev/null +++ b/third_party/heimdal/lib/base/plugin.c @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2006 - 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2018 AuriStor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include "common_plugin.h" + +/* + * Documentation for the Heimdal plugin system is in lib/krb5/plugin.c and + * lib/krb5/krb5-plugin.7. + */ + +/* + * Definitions: + * + * module - a category of plugin module, identified by subsystem + * (e.g., "krb5") + * dso - a library for a module containing a map of plugin + * types to plugins (e.g. "service_locator") + * plugin - a set of callbacks and state that follows the + * common plugin module definition (version, init, fini) + * + * Obviously it would have been clearer to use the term "module" rather than + * "DSO" given there is an internal "DSO", but "module" was already taken... + * + * modules := { module: dsos } + * dsos := { path, dsohandle, plugins-by-name } + * plugins-by-name := { plugin-name: [plug] } + * plug := { ftable, ctx } + */ + +/* global module use, use copy_modules() accessor to access */ +static heim_dict_t __modules; + +static HEIMDAL_MUTEX modules_mutex = HEIMDAL_MUTEX_INITIALIZER; + +static void +copy_modules_once(void *context) +{ + heim_dict_t *modules = (heim_dict_t *)context; + + *modules = heim_dict_create(11); + heim_assert(*modules, "plugin modules array allocation failure"); +} + +/* returns global modules list, refcount +1 */ +static heim_dict_t +copy_modules(void) +{ + static heim_base_once_t modules_once = HEIM_BASE_ONCE_INIT; + + heim_base_once_f(&modules_once, &__modules, copy_modules_once); + + return heim_retain(__modules); +} + +/* returns named module, refcount +1 */ +static heim_dict_t +copy_module(const char *name) +{ + heim_string_t module_name = heim_string_create(name); + heim_dict_t modules = copy_modules(); + heim_dict_t module; + + module = heim_dict_copy_value(modules, module_name); + if (module == NULL) { + module = heim_dict_create(11); + heim_dict_set_value(modules, module_name, module); + } + + heim_release(modules); + heim_release(module_name); + + return module; +} + +/* DSO helpers */ +struct heim_dso { + heim_string_t path; + heim_dict_t plugins_by_name; + void *dsohandle; +}; + +static void HEIM_CALLCONV +dso_dealloc(void *ptr) +{ + struct heim_dso *p = ptr; + + heim_release(p->path); + heim_release(p->plugins_by_name); +#ifdef HAVE_DLOPEN + if (p->dsohandle) + dlclose(p->dsohandle); +#endif +} + +/* returns internal "DSO" for name, refcount +1 */ +static struct heim_dso * +copy_internal_dso(const char *name) +{ + heim_string_t dso_name = HSTR("__HEIMDAL_INTERNAL_DSO__"); + heim_dict_t module = copy_module(name); + struct heim_dso *dso; + + if (module == NULL) + return NULL; + + dso = heim_dict_copy_value(module, dso_name); + if (dso == NULL) { + dso = heim_alloc(sizeof(*dso), "heim-dso", dso_dealloc); + + dso->path = dso_name; + dso->plugins_by_name = heim_dict_create(11); + + heim_dict_set_value(module, dso_name, dso); + } + + heim_release(module); + + return dso; +} + +struct heim_plugin { + heim_plugin_common_ftable_const_p ftable; + void *ctx; +}; + +static void HEIM_CALLCONV +plugin_free(void *ptr) +{ + struct heim_plugin *pl = ptr; + + if (pl->ftable && pl->ftable->fini) + pl->ftable->fini(pl->ctx); +} + +struct heim_plugin_register_ctx { + const void *symbol; + int is_dup; +}; + +static void +plugin_register_check_dup(heim_object_t value, void *ctx, int *stop) +{ + struct heim_plugin_register_ctx *pc = ctx; + struct heim_plugin *pl = value; + + if (pl->ftable == pc->symbol) { + pc->is_dup = 1; + *stop = 1; + } +} + +/** + * Register a plugin symbol name of specific type. + * @param context a Keberos context + * @param module name of plugin module (e.g., "krb5") + * @param name name of plugin symbol (e.g., "krb5_plugin_kuserok") + * @param ftable a pointer to a function pointer table + * @return In case of error a non zero error com_err error is returned + * and the Kerberos error string is set. + * + * @ingroup heim_support + */ + +heim_error_code +heim_plugin_register(heim_context context, + heim_pcontext pcontext, + const char *module, + const char *name, + const void *ftable) +{ + heim_error_code ret; + heim_array_t plugins; + heim_string_t hname; + struct heim_dso *dso; + struct heim_plugin_register_ctx ctx; + + ctx.symbol = ftable; + ctx.is_dup = 0; + + HEIMDAL_MUTEX_lock(&modules_mutex); + + dso = copy_internal_dso(module); + hname = heim_string_create(name); + plugins = heim_dict_copy_value(dso->plugins_by_name, hname); + if (plugins != NULL) + heim_array_iterate_f(plugins, &ctx, plugin_register_check_dup); + else { + plugins = heim_array_create(); + heim_dict_set_value(dso->plugins_by_name, hname, plugins); + } + + ret = 0; + if (!ctx.is_dup) { + /* Note: refactored plugin API only supports common plugin layout */ + struct heim_plugin *pl; + + pl = heim_alloc(sizeof(*pl), "heim-plugin", plugin_free); + if (pl == NULL) { + ret = heim_enomem(context); + } else { + pl->ftable = ftable; + ret = pl->ftable->init(pcontext, &pl->ctx); + if (ret == 0) { + heim_array_append_value(plugins, pl); + heim_debug(context, 5, "Registered %s plugin", name); + } + heim_release(pl); + } + } + + HEIMDAL_MUTEX_unlock(&modules_mutex); + + heim_release(dso); + heim_release(hname); + heim_release(plugins); + + return ret; +} + +#ifdef HAVE_DLOPEN + +static char * +resolve_origin(const char *di, const char *module) +{ +#ifdef HAVE_DLADDR + Dl_info dl_info; + const char *dname; + char *path, *p; + + if (strncmp(di, "$ORIGIN/", sizeof("$ORIGIN/") - 1) != 0 && + strcmp(di, "$ORIGIN") != 0) + return strdup(di); + + di += sizeof("$ORIGIN") - 1; + + if (dladdr(heim_plugin_register, &dl_info) == 0) { + char *s = NULL; + + /* dladdr() failed */ + if (asprintf(&s, LIBDIR "/plugin/%s", module) == -1) + return NULL; + return s; + } + + dname = dl_info.dli_fname; +#ifdef _WIN32 + p = strrchr(dname, '\\'); + if (p == NULL) +#endif + p = strrchr(dname, '/'); + if (p) { + if (asprintf(&path, "%.*s%s", (int) (p - dname), dname, di) == -1) + return NULL; + } else { + if (asprintf(&path, "%s%s", dname, di) == -1) + return NULL; + } + + return path; +#else + char *s = NULL; + + if (strncmp(di, "$ORIGIN/", sizeof("$ORIGIN/") - 1) != 0 && + strcmp(di, "$ORIGIN") != 0) + return strdup(di); + if (asprintf(&s, LIBDIR "/plugin/%s", module) == -1) + return NULL; + return s; +#endif /* HAVE_DLADDR */ +} + +#endif /* HAVE_DLOPEN */ + +/** + * Load plugins (new system) for the given module @module from the given + * directory @paths. + * + * Inputs: + * + * @context A heim_context + * @module Name of plugin module (typically "krb5") + * @paths Array of directory paths where to look + */ +void +heim_load_plugins(heim_context context, + const char *module, + const char **paths) +{ +#ifdef HAVE_DLOPEN + heim_string_t s = heim_string_create(module); + heim_dict_t mod, modules; + struct dirent *entry; + heim_error_code ret; + const char **di; + char *dirname = NULL; + DIR *d; +#ifdef _WIN32 + char *plugin_prefix; + size_t plugin_prefix_len; + + if (asprintf(&plugin_prefix, "plugin_%s_", module) == -1) + return; + plugin_prefix_len = (plugin_prefix ? strlen(plugin_prefix) : 0); +#endif + + HEIMDAL_MUTEX_lock(&modules_mutex); + + modules = copy_modules(); + + mod = heim_dict_copy_value(modules, s); + if (mod == NULL) { + mod = heim_dict_create(11); + if (mod == NULL) { + HEIMDAL_MUTEX_unlock(&modules_mutex); + heim_release(s); + heim_release(modules); + heim_debug(context, 5, "Load plugins for module %s failed", module); + return; + } + heim_dict_set_value(modules, s, mod); + } + heim_release(s); + heim_release(modules); + + for (di = paths; *di != NULL; di++) { + free(dirname); + dirname = resolve_origin(*di, module); + if (dirname == NULL) { + heim_debug(context, 10, "Could not resolve %s", *di); + continue; + } + d = opendir(dirname); + if (d == NULL) { + heim_debug(context, 10, "No such directory %s", dirname); + continue; + } + rk_cloexec_dir(d); + + heim_debug(context, 10, "Load plugins for module %s; search %s (%s)", + module, *di, dirname); + + while ((entry = readdir(d)) != NULL) { + char *n = entry->d_name; + char *path = NULL; + heim_string_t spath; + struct heim_dso *p; + + /* skip . and .. */ + if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) + continue; + + ret = 0; +#ifdef _WIN32 + /* + * On Windows, plugins must be loaded from the same directory as + * heimdal.dll (typically the assembly directory) and must have + * the name form "plugin__.dll". + */ + { + char *ext; + + if (strnicmp(n, plugin_prefix, plugin_prefix_len) != 0) + continue; + ext = strrchr(n, '.'); + if (ext == NULL || stricmp(ext, ".dll") != 0) + continue; + + ret = asprintf(&path, "%s\\%s", dirname, n); + if (ret < 0 || path == NULL) + continue; + } +#endif +#ifdef __APPLE__ + { /* support loading bundles on MacOS */ + size_t len = strlen(n); + if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) + ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", dirname, n, (int)(len - 7), n); + } +#endif + if (ret < 0 || path == NULL) + ret = asprintf(&path, "%s/%s", dirname, n); + + if (ret < 0 || path == NULL) + continue; + + spath = heim_string_create(n); + if (spath == NULL) { + free(path); + continue; + } + + /* check if already cached */ + p = heim_dict_copy_value(mod, spath); + if (p == NULL) { + p = heim_alloc(sizeof(*p), "heim-dso", dso_dealloc); + if (p) + p->dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY|RTLD_GROUP); + if (p && p->dsohandle) { + p->path = heim_retain(spath); + p->plugins_by_name = heim_dict_create(11); + heim_dict_set_value(mod, spath, p); + heim_debug(context, 10, "Load plugins for module %s; " + "found DSO %s", module, path); + } + } + heim_release(p); + heim_release(spath); + free(path); + } + closedir(d); + } + free(dirname); + HEIMDAL_MUTEX_unlock(&modules_mutex); + heim_release(mod); +#ifdef _WIN32 + if (plugin_prefix) + free(plugin_prefix); +#endif +#endif /* HAVE_DLOPEN */ +} + +/** + * Unload plugins of the given @module name. + * + * Params: + * + * @module Name of module whose plusins to unload. + */ +void +heim_unload_plugins(heim_context context, const char *module) +{ + heim_string_t sname = heim_string_create(module); + heim_dict_t modules; + + HEIMDAL_MUTEX_lock(&modules_mutex); + + modules = copy_modules(); + heim_dict_delete_key(modules, sname); + + HEIMDAL_MUTEX_unlock(&modules_mutex); + + heim_release(modules); + heim_release(sname); +} + +struct iter_ctx { + heim_context context; + heim_pcontext pcontext; + heim_string_t n; + const struct heim_plugin_data *caller; + int flags; + heim_array_t result; + int32_t (HEIM_LIB_CALL *func)(void *, const void *, void *, void *); + void *userctx; + int32_t ret; + int32_t plugin_no_handle_retval; +}; + +#ifdef HAVE_DLOPEN +/* + * Add plugin from a DSO that exports the plugin structure directly. This is + * provided for backwards compatibility with prior versions of Heimdal, but it + * does not allow a module to export multiple plugins, nor does it allow + * instance validation. + */ +static heim_array_t +add_dso_plugin_struct(heim_context context, + heim_pcontext pcontext, + const char *dsopath, + void *dsohandle, + const char *name) +{ + heim_error_code ret; + heim_plugin_common_ftable_p cpm; + struct heim_plugin *pl; + heim_array_t plugins; + + if (dsohandle == NULL) + return NULL; + + /* suppress error here because we may be looking for a different plugin type */ + cpm = (heim_plugin_common_ftable_p)dlsym(dsohandle, name); + if (cpm == NULL) { + heim_debug(context, 15, "Symbol %s not found in %s", name, dsopath); + return NULL; + } + + heim_warnx(context, "plugin %s uses deprecated loading mechanism", dsopath); + + pl = heim_alloc(sizeof(*pl), "heim-plugin", plugin_free); + + ret = cpm->init(pcontext, &pl->ctx); + if (ret) { + heim_warn(context, ret, "plugin %s failed to initialize", dsopath); + heim_release(pl); + return NULL; + } + + pl->ftable = cpm; + + plugins = heim_array_create(); + heim_array_append_value(plugins, pl); + heim_release(pl); + + return plugins; +} + +static int +validate_plugin_deps(heim_context context, + const struct heim_plugin_data *caller, + const char *dsopath, + heim_get_instance_func_t get_instance) +{ + size_t i; + + if (get_instance == NULL) { + heim_warnx(context, "plugin %s omitted instance callback", + dsopath); + return FALSE; + } + + for (i = 0; caller->deps[i] != NULL; i++) { + uintptr_t heim_instance, plugin_instance; + + heim_instance = caller->get_instance(caller->deps[i]); + plugin_instance = get_instance(caller->deps[i]); + + if (heim_instance == 0 || plugin_instance == 0) + continue; + + if (heim_instance != plugin_instance) { + heim_warnx(context, "plugin %s library %s linked against different " + "instance of Heimdal (got %zu, us %zu)", + dsopath, caller->deps[i], + plugin_instance, heim_instance); + return FALSE; + } + heim_debug(context, 10, "Validated plugin library dependency %s for %s", + caller->deps[i], dsopath); + } + + return TRUE; +} + +/* + * New interface from Heimdal 8 where a DSO can export a load function + * that can return both a Heimdal instance identifier along with an + * array of plugins. + */ +static heim_array_t +add_dso_plugins_load_fn(heim_context context, + heim_pcontext pcontext, + const struct heim_plugin_data *caller, + const char *dsopath, + void *dsohandle) +{ + heim_error_code ret; + heim_array_t plugins; + heim_plugin_load_t load_fn; + char *sym = NULL; + size_t i; + heim_get_instance_func_t get_instance; + size_t n_ftables; + heim_plugin_common_ftable_cp *ftables; + + if (asprintf(&sym, "%s_plugin_load", caller->name) == -1 || sym == NULL) + return NULL; + + /* suppress error here because we may be looking for a different plugin type */ + load_fn = (heim_plugin_load_t)dlsym(dsohandle, sym); + if (load_fn == NULL) { + heim_debug(context, 15, "Symbol %s not found in %s", sym, dsopath); + free(sym); + return NULL; + } + + ret = load_fn(pcontext, &get_instance, &n_ftables, &ftables); + if (ret) { + heim_warn(context, ret, "plugin %s failed to load", dsopath); + free(sym); + + /* fallback to loading structure directly */ + return add_dso_plugin_struct(context, pcontext, dsopath, + dsohandle, caller->name); + } + + if (!validate_plugin_deps(context, caller, dsopath, get_instance)) { + free(sym); + return NULL; + } + + plugins = heim_array_create(); + + for (i = 0; i < n_ftables; i++) { + heim_plugin_common_ftable_cp cpm = ftables[i]; + struct heim_plugin *pl; + + pl = heim_alloc(sizeof(*pl), "heim-plugin", plugin_free); + + ret = cpm->init(pcontext, &pl->ctx); + if (ret) { + heim_warn(context, ret, "plugin %s[%zu] failed to initialize", + dsopath, i); + } else { + pl->ftable = cpm; + heim_array_append_value(plugins, pl); + } + heim_release(pl); + } + + heim_debug(context, 15, "DSO %s loaded (%s)", dsopath, sym); + free(sym); + return plugins; +} +#endif /* HAVE_DLOPEN */ + +static void +reduce_by_version(heim_object_t value, void *ctx, int *stop) +{ + struct iter_ctx *s = ctx; + struct heim_plugin *pl = value; + + if (pl->ftable && pl->ftable->minor_version >= s->caller->min_version) + heim_array_append_value(s->result, pl); +} + +static void +search_modules(heim_object_t key, heim_object_t value, void *ctx) +{ + struct iter_ctx *s = ctx; + struct heim_dso *p = value; + heim_array_t plugins = heim_dict_copy_value(p->plugins_by_name, s->n); + +#ifdef HAVE_DLOPEN + if (plugins == NULL && p->dsohandle) { + const char *path = heim_string_get_utf8(p->path); + + plugins = add_dso_plugins_load_fn(s->context, + s->pcontext, + s->caller, + path, + p->dsohandle); + if (plugins) { + heim_dict_set_value(p->plugins_by_name, s->n, plugins); + heim_debug(s->context, 5, "Loaded %zu %s %s plugin%s from %s", + heim_array_get_length(plugins), + s->caller->module, s->caller->name, + heim_array_get_length(plugins) > 1 ? "s" : "", + path); + } + } +#endif /* HAVE_DLOPEN */ + + if (plugins) { + heim_array_iterate_f(plugins, s, reduce_by_version); + heim_release(plugins); + } +} + +static void +eval_results(heim_object_t value, void *ctx, int *stop) +{ + struct heim_plugin *pl = value; + struct iter_ctx *s = ctx; + + if (s->ret != s->plugin_no_handle_retval) + return; + + s->ret = s->func(s->pcontext, pl->ftable, pl->ctx, s->userctx); + if (s->ret != s->plugin_no_handle_retval + && !(s->flags & HEIM_PLUGIN_INVOKE_ALL)) + *stop = 1; +} + +/** + * Run plugins for the given @module (e.g., "krb5") and @name (e.g., + * "kuserok"). Specifically, the @func is invoked once per-plugin with + * four arguments: the @context, the plugin symbol value (a pointer to a + * struct whose first three fields are the same as common_plugin_ftable), + * a context value produced by the plugin's init method, and @userctx. + * + * @func should unpack arguments for a plugin function and invoke it + * with arguments taken from @userctx. @func should save plugin + * outputs, if any, in @userctx. + * + * All loaded and registered plugins are invoked via @func until @func + * returns something other than @nohandle. Plugins that have nothing to + * do for the given arguments should return the same value as @nohandle. + * + * Inputs: + * + * @context A heim_context + * @pcontext A context for the plugin, such as a krb5_context + * @module Name of module (typically "krb5") + * @name Name of pluggable interface (e.g., "kuserok") + * @min_version Lowest acceptable plugin minor version number + * @flags Flags (none defined at this time) + * @nohandle Flags (none defined at this time) + * @userctx Callback data for the callback function @func + * @func A callback function, invoked once per-plugin + * + * Outputs: None, other than the return value and such outputs as are + * gathered by @func. + */ +heim_error_code +heim_plugin_run_f(heim_context context, + heim_pcontext pcontext, + const struct heim_plugin_data *caller, + int flags, + int32_t nohandle, + void *userctx, + int32_t (HEIM_LIB_CALL *func)(void *, const void *, void *, void *)) +{ + heim_string_t m = heim_string_create(caller->module); + heim_dict_t modules, dict = NULL; + struct iter_ctx s; + + s.context = context; + s.pcontext = pcontext; + s.caller = caller; + s.n = heim_string_create(caller->name); + s.flags = flags; + s.result = heim_array_create(); + s.func = func; + s.userctx = userctx; + s.plugin_no_handle_retval = nohandle; + s.ret = nohandle; + + HEIMDAL_MUTEX_lock(&modules_mutex); + + /* Get loaded plugins */ + modules = copy_modules(); + dict = heim_dict_copy_value(modules, m); + + /* Add loaded plugins to s.result array */ + if (dict) + heim_dict_iterate_f(dict, &s, search_modules); + + /* We don't need to hold modules_mutex during plugin invocation */ + HEIMDAL_MUTEX_unlock(&modules_mutex); + + /* Invoke loaded plugins */ + heim_array_iterate_f(s.result, &s, eval_results); + + heim_release(s.result); + heim_release(s.n); + heim_release(dict); + heim_release(m); + heim_release(modules); + + return s.ret; +} diff --git a/third_party/heimdal/lib/base/roken_rename.h b/third_party/heimdal/lib/base/roken_rename.h new file mode 100644 index 0000000..ea72098 --- /dev/null +++ b/third_party/heimdal/lib/base/roken_rename.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __heimbase_roken_rename_h__ +#define __heimbase_roken_rename_h__ + +#ifndef HAVE_VSNPRINTF +#define rk_vsnprintf heimbase_vsnprintf +#endif +#ifndef HAVE_ASPRINTF +#define rk_asprintf heimbase_asprintf +#endif +#ifndef HAVE_ASNPRINTF +#define rk_asnprintf heimbase_asnprintf +#endif +#ifndef HAVE_VASPRINTF +#define rk_vasprintf heimbase_vasprintf +#endif +#ifndef HAVE_VASNPRINTF +#define rk_vasnprintf heimbase_vasnprintf +#endif +#ifndef HAVE_STRDUP +#define rk_strdup heimbase_strdup +#endif +#ifndef HAVE_STRNDUP +#define rk_strndup heimbase_strndup +#endif + +#endif /* __heimbase_roken_rename_h__ */ diff --git a/third_party/heimdal/lib/base/string.c b/third_party/heimdal/lib/base/string.c new file mode 100644 index 0000000..5e79e00 --- /dev/null +++ b/third_party/heimdal/lib/base/string.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "baselocl.h" +#include + +static void HEIM_CALLCONV +string_dealloc(void *ptr) +{ + heim_string_t s = ptr; + heim_string_free_f_t *deallocp; + heim_string_free_f_t dealloc; + + if (*(const char *)ptr != '\0') + return; + + /* Possible string ref */ + deallocp = _heim_get_isaextra(s, 0); + dealloc = *deallocp; + if (dealloc != NULL) { + char **strp = _heim_get_isaextra(s, 1); + dealloc(*strp); + } +} + +static int +string_cmp(void *a, void *b) +{ + if (*(char *)a == '\0') { + char **strp = _heim_get_isaextra(a, 1); + + if (*strp != NULL) + a = *strp; /* a is a string ref */ + } + if (*(char *)b == '\0') { + char **strp = _heim_get_isaextra(b, 1); + + if (*strp != NULL) + b = *strp; /* b is a string ref */ + } + return strcmp(a, b); +} + +static uintptr_t +string_hash(void *ptr) +{ + const char *s = ptr; + uintptr_t n; + + for (n = 0; *s; ++s) + n += *s; + return n; +} + +struct heim_type_data _heim_string_object = { + HEIM_TID_STRING, + "string-object", + NULL, + string_dealloc, + NULL, + string_cmp, + string_hash, + NULL +}; + +/** + * Create a string object + * + * @param string the string to create, must be an utf8 string + * + * @return string object + */ + +heim_string_t +heim_string_create(const char *string) +{ + return heim_string_create_with_bytes(string, strlen(string)); +} + +/** + * Create a string object without copying the source. + * + * @param string the string to referenced, must be UTF-8 + * @param dealloc the function to use to release the referece to the string + * + * @return string object + */ + +heim_string_t +heim_string_ref_create(const char *string, heim_string_free_f_t dealloc) +{ + heim_string_t s; + heim_string_free_f_t *deallocp; + + s = _heim_alloc_object(&_heim_string_object, 1); + if (s) { + const char **strp; + + ((char *)s)[0] = '\0'; + deallocp = _heim_get_isaextra(s, 0); + *deallocp = dealloc; + strp = _heim_get_isaextra(s, 1); + *strp = string; + } + return s; +} + +/** + * Create a string object + * + * @param string the string to create, must be an utf8 string + * @param len the length of the string + * + * @return string object + */ + +heim_string_t +heim_string_create_with_bytes(const void *data, size_t len) +{ + heim_string_t s; + + s = _heim_alloc_object(&_heim_string_object, len + 1); + if (s) { + if (len) + memcpy(s, data, len); + ((char *)s)[len] = '\0'; + } + return s; +} + +/** + * Create a string object using a format string + * + * @param fmt format string + * @param ... + * + * @return string object + */ + +heim_string_t +heim_string_create_with_format(const char *fmt, ...) +{ + heim_string_t s; + char *str = NULL; + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + if (ret < 0 || str == NULL) + return NULL; + + s = heim_string_ref_create(str, free); + if (s == NULL) + free(str); + return s; +} + +/** + * Return the type ID of string objects + * + * @return type id of string objects + */ + +heim_tid_t +heim_string_get_type_id(void) +{ + return HEIM_TID_STRING; +} + +/** + * Get the string value of the content. + * + * @param string the string object to get the value from + * + * @return a utf8 string + */ + +const char * +heim_string_get_utf8(heim_string_t string) +{ + if (*(const char *)string == '\0') { + const char **strp; + + /* String ref */ + strp = _heim_get_isaextra(string, 1); + if (*strp != NULL) + return *strp; + } + return (const char *)string; +} + +/* + * + */ + +static void +init_string(void *ptr) +{ + heim_dict_t *dict = ptr; + *dict = heim_dict_create(101); + heim_assert(*dict != NULL, "__heim_string_constant"); +} + +heim_string_t +__heim_string_constant(const char *_str) +{ + static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + static heim_dict_t dict = NULL; + heim_string_t s, s2; + + heim_base_once_f(&once, &dict, init_string); + s = heim_string_create(_str); + + HEIMDAL_MUTEX_lock(&mutex); + s2 = heim_dict_get_value(dict, s); + if (s2) { + heim_release(s); + s = s2; + } else { + _heim_make_permanent(s); + heim_dict_set_value(dict, s, s); + } + HEIMDAL_MUTEX_unlock(&mutex); + + return s; +} diff --git a/third_party/heimdal/lib/base/test_base.c b/third_party/heimdal/lib/base/test_base.c new file mode 100644 index 0000000..cc875d7 --- /dev/null +++ b/third_party/heimdal/lib/base/test_base.c @@ -0,0 +1,1380 @@ +/* + * Copyright (c) 2010-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is a test of libheimbase functionality. If you make any changes + * to libheimbase or to this test you should run it under valgrind with + * the following options: + * + * -v --track-fds=yes --num-callers=30 --leak-check=full + * + * and make sure that there are no leaks that don't have + * __heim_string_constant() or heim_db_register() in their stack trace. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#endif +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "baselocl.h" +#include "heimbase-atomics.h" + +static void HEIM_CALLCONV +memory_free(heim_object_t obj) +{ +} + +static int +test_memory(void) +{ + void *ptr; + + ptr = heim_alloc(10, "memory", memory_free); + + heim_retain(ptr); + heim_release(ptr); + + heim_retain(ptr); + heim_release(ptr); + + heim_release(ptr); + + ptr = heim_alloc(10, "memory", NULL); + heim_release(ptr); + + return 0; +} + +static int +test_mutex(void) +{ + HEIMDAL_MUTEX m = HEIMDAL_MUTEX_INITIALIZER; + + HEIMDAL_MUTEX_lock(&m); + HEIMDAL_MUTEX_unlock(&m); + HEIMDAL_MUTEX_destroy(&m); + + HEIMDAL_MUTEX_init(&m); + HEIMDAL_MUTEX_lock(&m); + HEIMDAL_MUTEX_unlock(&m); + HEIMDAL_MUTEX_destroy(&m); + + return 0; +} + +static int +test_rwlock(void) +{ + HEIMDAL_RWLOCK l = HEIMDAL_RWLOCK_INITIALIZER; + + HEIMDAL_RWLOCK_rdlock(&l); + HEIMDAL_RWLOCK_unlock(&l); + HEIMDAL_RWLOCK_wrlock(&l); + HEIMDAL_RWLOCK_unlock(&l); + if (HEIMDAL_RWLOCK_trywrlock(&l) != 0) + err(1, "HEIMDAL_RWLOCK_trywrlock() failed with lock not held"); + HEIMDAL_RWLOCK_unlock(&l); + if (HEIMDAL_RWLOCK_tryrdlock(&l)) + err(1, "HEIMDAL_RWLOCK_tryrdlock() failed with lock not held"); + HEIMDAL_RWLOCK_unlock(&l); + HEIMDAL_RWLOCK_destroy(&l); + + HEIMDAL_RWLOCK_init(&l); + HEIMDAL_RWLOCK_rdlock(&l); + HEIMDAL_RWLOCK_unlock(&l); + HEIMDAL_RWLOCK_wrlock(&l); + HEIMDAL_RWLOCK_unlock(&l); + if (HEIMDAL_RWLOCK_trywrlock(&l)) + err(1, "HEIMDAL_RWLOCK_trywrlock() failed with lock not held"); + HEIMDAL_RWLOCK_unlock(&l); + if (HEIMDAL_RWLOCK_tryrdlock(&l)) + err(1, "HEIMDAL_RWLOCK_tryrdlock() failed with lock not held"); + HEIMDAL_RWLOCK_unlock(&l); + HEIMDAL_RWLOCK_destroy(&l); + + return 0; +} + +static int +test_dict(void) +{ + heim_dict_t dict; + heim_number_t a1 = heim_number_create(1); + heim_string_t a2 = heim_string_create("hejsan"); + heim_number_t a3 = heim_number_create(3); + heim_string_t a4 = heim_string_create("foosan"); + + dict = heim_dict_create(10); + + heim_dict_set_value(dict, a1, a2); + heim_dict_set_value(dict, a3, a4); + + heim_dict_delete_key(dict, a3); + heim_dict_delete_key(dict, a1); + + heim_release(a1); + heim_release(a2); + heim_release(a3); + heim_release(a4); + + heim_release(dict); + + return 0; +} + +static int +test_auto_release(void) +{ + heim_auto_release_t ar1, ar2; + heim_number_t n1; + heim_string_t s1; + + ar1 = heim_auto_release_create(); + + s1 = heim_string_create("hejsan"); + heim_auto_release(s1); + + n1 = heim_number_create(1); + heim_auto_release(n1); + + ar2 = heim_auto_release_create(); + + n1 = heim_number_create(1); + heim_auto_release(n1); + + heim_release(ar2); + heim_release(ar1); + + return 0; +} + +static int +test_string(void) +{ + heim_string_t s1, s2; + const char *string = "hejsan"; + + s1 = heim_string_create(string); + s2 = heim_string_create(string); + + if (heim_cmp(s1, s2) != 0) { + printf("the same string is not the same\n"); + exit(1); + } + + heim_release(s1); + heim_release(s2); + + return 0; +} + +static int +test_error(void) +{ + heim_error_t e; + heim_string_t s; + + e = heim_error_create(10, "foo: %s", "bar"); + heim_assert(heim_error_get_code(e) == 10, "error_code != 10"); + + s = heim_error_copy_string(e); + heim_assert(strcmp(heim_string_get_utf8(s), "foo: bar") == 0, "msg wrong"); + + heim_release(s); + heim_release(e); + + return 0; +} + +static int +test_json(void) +{ + static char *j[] = { + "{ \"k1\" : \"s1\", \"k2\" : \"s2\" }", + "{ \"k1\" : [\"s1\", \"s2\", \"s3\"], \"k2\" : \"s3\" }", + "{ \"k1\" : {\"k2\":\"s1\",\"k3\":\"s2\",\"k4\":\"s3\"}, \"k5\" : \"s4\" }", + ("[ \"v1\", \"v2\", [\"v3\",\"v4\",[\"v 5\",\" v 7 \"]], -123456789, " + "null, true, false, 123456789, \"\"]"), + " -1" + }; + char *s; + size_t i, k; + heim_object_t o, o2, o3; + heim_string_t k1 = heim_string_create("k1"); + + o = heim_json_create("\"string\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("string", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * Test string escaping: + * + * - C-like must-escapes + * - ASCII control character must-escapes + * - surrogate pairs + * + * We test round-tripping. First we parse, then we serialize, then parse, + * then compare the second parse to the first for equality. + * + * We do compare serialized forms in spite of their not being canonical. + * That means that some changes to serialization can cause failures here. + */ + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\\u00e1" /* á */ + "\\u07ff" + "\\u0801" + "\\u8001" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xa0\x81" + "\xE8\x80\x81" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * Test HEIM_JSON_F_ESCAPE_NON_ASCII. + * + * Also test that we get escaped non-ASCII because we're in a not-UTF-8 + * locale, since we setlocale(LC_ALL, "C"), so we should escape non-ASCII + * by default. + */ + o = heim_json_create("\"" + "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */ + "\x1e" /* ASCII control character w/o C-like escape */ + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xa0\x81" + "\xE8\x80\x81" + "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */ + "\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\b\f\n\r\t" + "\x1e" + "\xc3\xa1" + "\xdf\xbf" + "\xe0\xA0\x81" + "\xe8\x80\x81" + "\xf0\x9d\x84\x9e", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001" + "\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + heim_release(o2); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_STRICT, NULL); + heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001" + "\\uD834\\uDD1E\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test rejection of unescaped ASCII control characters */ + o = heim_json_create("\"\b\\f\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "strict parse accepted bad input"); + o = heim_json_create("\"\b\x1e\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "strict parse accepted bad input"); + + o = heim_json_create("\"\b\\f\"", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\b\f", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"\\b\\f\"", heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test bogus backslash escape */ + o = heim_json_create("\"" + "\\ " + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\\ " + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp(" ", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\" \"", heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test truncated surrogate encoding (bottom code unit) */ + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD834\\udd" + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD834\\udd" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\xe8\x80\x81" + "\\uD834\\udd", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"老\\\\uD834\\\\udd\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test truncated surrogate encodings (top code unit) */ + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD83" + "\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted"); + o = heim_json_create("\"" + "\xE8\x80\x81" + "\\uD83" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp( + "\xe8\x80\x81" + "\\uD83", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(strcmp("\"老\\\\uD83\"", + heim_string_get_utf8(o2)) == 0, + "JSON encoding changed; please check that it is till valid"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * Test handling of truncated UTF-8 multi-byte sequences. + */ + o = heim_json_create("\"" + "\xE8\x80" + "\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\xe8\x80", + heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, + HEIM_JSON_F_STRICT | + HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + heim_assert(o2 == NULL, "malformed string serialized"); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_NO_ESCAPE_NON_ASCII, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o3 == NULL, "malformed string accepted (not strict)"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(strcmp("\xe8\x80", + heim_string_get_utf8(o3)) == 0, "wrong string"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test handling of unescaped / embedded newline */ + o = heim_json_create("\"\n\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o == NULL, "malformed string accepted (strict)"); + o = heim_json_create("\"\n\"", 10, 0, NULL); + heim_assert(o != NULL, "malformed string rejected (not strict)"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("\n", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, HEIM_JSON_F_STRICT, NULL); + heim_assert(o2 != NULL, "string not serialized"); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o3 != NULL, "string not accepted"); + heim_assert(strcmp("\n", heim_string_get_utf8(o3)) == 0, "wrong string"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* Test handling of embedded NULs (must decode as data, not string) */ + o = heim_json_create("\"\\u0000\"", 10, HEIM_JSON_F_STRICT, NULL); + heim_assert(o != NULL, "string with NULs rejected"); + heim_assert(heim_get_tid(o) == heim_data_get_type_id(), "data-tid"); + heim_assert(heim_data_get_length(o) == 1, "wrong data length"); + heim_assert(((const char *)heim_data_get_ptr(o))[0] == '\0', + "wrong data NUL"); + o2 = heim_json_copy_serialize(o, 0, NULL); + heim_assert(o2 != NULL, "data not serialized"); + heim_release(o2); + heim_release(o); + + /* + * Note that the trailing ']' is not part of the JSON text (which is just a + * string). + */ + o = heim_json_create(" \"foo\\\"bar\" ]", 10, 0, NULL); + heim_assert(o != NULL, "string"); + heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid"); + heim_assert(strcmp("foo\"bar", heim_string_get_utf8(o)) == 0, "wrong string"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create(" { \"key\" : \"value\" }", 10, 0, NULL); + heim_assert(o != NULL, "dict"); + heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + /* + * heim_json_eq() can't handle dicts with dicts as keys, so we don't check + * for round-tripping here + */ + o = heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", " + "{ \"k3\" : \"s4\" } : -1 }", 10, 0, NULL); + heim_assert(o != NULL, "dict"); + heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + heim_release(o); + + o = heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", " + "{ \"k3\" : \"s4\" } : -1 }", 10, + HEIM_JSON_F_STRICT_DICT, NULL); + heim_assert(o == NULL, "dict"); + + o = heim_json_create(" { \"k1\" : \"s1\", \"k2\" : \"s2\" }", 10, 0, NULL); + heim_assert(o != NULL, "dict"); + heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + o2 = heim_dict_copy_value(o, k1); + heim_assert(heim_get_tid(o2) == heim_string_get_type_id(), "string-tid"); + heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create(" { \"k1\" : { \"k2\" : \"s2\" } }", 10, 0, NULL); + heim_assert(o != NULL, "dict"); + heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + o2 = heim_dict_copy_value(o, k1); + heim_assert(heim_get_tid(o2) == heim_dict_get_type_id(), "dict-tid"); + heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create("{ \"k1\" : 1 }", 10, 0, NULL); + heim_assert(o != NULL, "array"); + heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid"); + o2 = heim_dict_copy_value(o, k1); + heim_assert(heim_get_tid(o2) == heim_number_get_type_id(), "number-tid"); + heim_release(o2); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create("-10", 10, 0, NULL); + heim_assert(o != NULL, "number"); + heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create("99", 10, 0, NULL); + heim_assert(o != NULL, "number"); + heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create(" [ 1 ]", 10, 0, NULL); + heim_assert(o != NULL, "array"); + heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + o = heim_json_create(" [ -1 ]", 10, 0, NULL); + heim_assert(o != NULL, "array"); + heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid"); + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + + for (i = 0; i < (sizeof (j) / sizeof (j[0])); i++) { + o = heim_json_create(j[i], 10, 0, NULL); + if (o == NULL) { + fprintf(stderr, "Failed to parse this JSON: %s\n", j[i]); + return 1; + } + o2 = heim_json_copy_serialize(o, 0, NULL); + o3 = heim_json_create(heim_string_get_utf8(o2), 10, 0, NULL); + heim_assert(heim_json_eq(o, o3), "JSON text did not round-trip"); + heim_release(o3); + heim_release(o2); + heim_release(o); + /* Simple fuzz test */ + for (k = strlen(j[i]) - 1; k > 0; k--) { + o = heim_json_create_with_bytes(j[i], k, 10, 0, NULL); + if (o != NULL) { + fprintf(stderr, "Invalid JSON parsed: %.*s\n", (int)k, j[i]); + return EINVAL; + } + } + /* Again, but this time make it so valgrind can find invalid accesses */ + for (k = strlen(j[i]) - 1; k > 0; k--) { + s = strndup(j[i], k); + if (s == NULL) + return ENOMEM; + o = heim_json_create(s, 10, 0, NULL); + free(s); + if (o != NULL) { + fprintf(stderr, "Invalid JSON parsed: %s\n", j[i]); + return EINVAL; + } + } + /* Again, but with no NUL termination */ + for (k = strlen(j[i]) - 1; k > 0; k--) { + s = malloc(k); + if (s == NULL) + return ENOMEM; + memcpy(s, j[i], k); + o = heim_json_create_with_bytes(s, k, 10, 0, NULL); + free(s); + if (o != NULL) { + fprintf(stderr, "Invalid JSON parsed: %s\n", j[i]); + return EINVAL; + } + } + } + + heim_release(k1); + + return 0; +} + +static int +test_path(void) +{ + heim_dict_t dict = heim_dict_create(11); + heim_string_t p1 = heim_string_create("abc"); + heim_string_t p2a = heim_string_create("def"); + heim_string_t p2b = heim_string_create("DEF"); + heim_number_t p3 = heim_number_create(0); + heim_string_t p4a = heim_string_create("ghi"); + heim_string_t p4b = heim_string_create("GHI"); + heim_array_t a = heim_array_create(); + heim_number_t l1 = heim_number_create(42); + heim_number_t l2 = heim_number_create(813); + heim_number_t l3 = heim_number_create(1234); + heim_string_t k1 = heim_string_create("k1"); + heim_string_t k2 = heim_string_create("k2"); + heim_string_t k3 = heim_string_create("k3"); + heim_string_t k2_1 = heim_string_create("k2-1"); + heim_string_t k2_2 = heim_string_create("k2-2"); + heim_string_t k2_3 = heim_string_create("k2-3"); + heim_string_t k2_4 = heim_string_create("k2-4"); + heim_string_t k2_5 = heim_string_create("k2-5"); + heim_string_t k2_5_1 = heim_string_create("k2-5-1"); + heim_object_t o; + heim_object_t neg_num; + int ret; + + if (!dict || !p1 || !p2a || !p2b || !p4a || !p4b) + return ENOMEM; + + ret = heim_path_create(dict, 11, a, NULL, p1, p2a, NULL); + heim_release(a); + if (ret) + return ret; + ret = heim_path_create(dict, 11, l3, NULL, p1, p2b, NULL); + if (ret) + return ret; + o = heim_path_get(dict, NULL, p1, p2b, NULL); + if (o != l3) + return 1; + ret = heim_path_create(dict, 11, NULL, NULL, p1, p2a, p3, NULL); + if (ret) + return ret; + ret = heim_path_create(dict, 11, l1, NULL, p1, p2a, p3, p4a, NULL); + if (ret) + return ret; + ret = heim_path_create(dict, 11, l2, NULL, p1, p2a, p3, p4b, NULL); + if (ret) + return ret; + + o = heim_path_get(dict, NULL, p1, p2a, p3, p4a, NULL); + if (o != l1) + return 1; + o = heim_path_get(dict, NULL, p1, p2a, p3, p4b, NULL); + if (o != l2) + return 1; + + heim_release(dict); + + /* Test that JSON parsing works right by using heim_path_get() */ + dict = heim_json_create("{\"k1\":1," + "\"k2\":{\"k2-1\":21," + "\"k2-2\":null," + "\"k2-3\":true," + "\"k2-4\":false," + "\"k2-5\":[1,2,3,{\"k2-5-1\":-1},-2]}," + "\"k3\":[true,false,0,42]}", 10, 0, NULL); + heim_assert(dict != NULL, "dict"); + o = heim_path_get(dict, NULL, k1, NULL); + if (heim_cmp(o, heim_number_create(1))) return 1; + o = heim_path_get(dict, NULL, k2, NULL); + if (heim_get_tid(o) != heim_dict_get_type_id()) return 1; + o = heim_path_get(dict, NULL, k2, k2_1, NULL); + if (heim_cmp(o, heim_number_create(21))) return 1; + o = heim_path_get(dict, NULL, k2, k2_2, NULL); + if (heim_cmp(o, heim_null_create())) return 1; + o = heim_path_get(dict, NULL, k2, k2_3, NULL); + if (heim_cmp(o, heim_bool_create(1))) return 1; + o = heim_path_get(dict, NULL, k2, k2_4, NULL); + if (heim_cmp(o, heim_bool_create(0))) return 1; + o = heim_path_get(dict, NULL, k2, k2_5, NULL); + if (heim_get_tid(o) != heim_array_get_type_id()) return 1; + o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(0), NULL); + if (heim_cmp(o, heim_number_create(1))) return 1; + o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(1), NULL); + if (heim_cmp(o, heim_number_create(2))) return 1; + o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(3), k2_5_1, NULL); + if (heim_cmp(o, neg_num = heim_number_create(-1))) return 1; + heim_release(neg_num); + o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(4), NULL); + if (heim_cmp(o, neg_num = heim_number_create(-2))) return 1; + heim_release(neg_num); + o = heim_path_get(dict, NULL, k3, heim_number_create(3), NULL); + if (heim_cmp(o, heim_number_create(42))) return 1; + + heim_release(dict); + heim_release(p1); + heim_release(p2a); + heim_release(p2b); + heim_release(p4a); + heim_release(p4b); + heim_release(k1); + heim_release(k2); + heim_release(k3); + heim_release(k2_1); + heim_release(k2_2); + heim_release(k2_3); + heim_release(k2_4); + heim_release(k2_5); + heim_release(k2_5_1); + + return 0; +} + +typedef struct dict_db { + heim_dict_t dict; + int locked; +} *dict_db_t; + +static int +dict_db_open(void *plug, const char *dbtype, const char *dbname, + heim_dict_t options, void **db, heim_error_t *error) +{ + dict_db_t dictdb; + heim_dict_t contents = NULL; + + if (error) + *error = NULL; + if (dbtype && *dbtype && strcmp(dbtype, "dictdb") != 0) + return EINVAL; + if (dbname && *dbname && strcmp(dbname, "MEMORY") != 0) + return EINVAL; + dictdb = heim_alloc(sizeof (*dictdb), "dict_db", NULL); + if (dictdb == NULL) + return ENOMEM; + + if (contents != NULL) + dictdb->dict = contents; + else { + dictdb->dict = heim_dict_create(29); + if (dictdb->dict == NULL) { + heim_release(dictdb); + return ENOMEM; + } + } + + *db = dictdb; + return 0; +} + +static int +dict_db_close(void *db, heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + heim_release(dictdb->dict); + heim_release(dictdb); + return 0; +} + +static int +dict_db_lock(void *db, int read_only, heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + if (dictdb->locked) + return EWOULDBLOCK; + dictdb->locked = 1; + return 0; +} + +static int +dict_db_unlock(void *db, heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + dictdb->locked = 0; + return 0; +} + +static heim_data_t +dict_db_copy_value(void *db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + + return heim_retain(heim_path_get(dictdb->dict, error, table, key, NULL)); +} + +static int +dict_db_set_value(void *db, heim_string_t table, + heim_data_t key, heim_data_t value, heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + return heim_path_create(dictdb->dict, 29, value, error, table, key, NULL); +} + +static int +dict_db_del_key(void *db, heim_string_t table, heim_data_t key, + heim_error_t *error) +{ + dict_db_t dictdb = db; + + if (error) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + heim_path_delete(dictdb->dict, error, table, key, NULL); + return 0; +} + +struct dict_db_iter_ctx { + heim_db_iterator_f_t iter_f; + void *iter_ctx; +}; + +static void dict_db_iter_f(heim_object_t key, heim_object_t value, void *arg) +{ + struct dict_db_iter_ctx *ctx = arg; + + ctx->iter_f((heim_object_t)key, (heim_object_t)value, ctx->iter_ctx); +} + +static void +dict_db_iter(void *db, heim_string_t table, void *iter_data, + heim_db_iterator_f_t iter_f, heim_error_t *error) +{ + dict_db_t dictdb = db; + struct dict_db_iter_ctx ctx; + heim_dict_t table_dict; + + if (error) + *error = NULL; + + if (table == NULL) + table = HSTR(""); + + table_dict = heim_dict_copy_value(dictdb->dict, table); + if (table_dict == NULL) + return; + + ctx.iter_ctx = iter_data; + ctx.iter_f = iter_f; + + heim_dict_iterate_f(table_dict, &ctx, dict_db_iter_f); + heim_release(table_dict); +} + +static void +test_db_iter(heim_data_t k, heim_data_t v, void *arg) +{ + int *ret = arg; + const void *kptr, *vptr; + size_t klen, vlen; + + heim_assert(heim_get_tid(k) == heim_data_get_type_id(), "..."); + + kptr = heim_data_get_ptr(k); + klen = heim_data_get_length(k); + vptr = heim_data_get_ptr(v); + vlen = heim_data_get_length(v); + + if (klen == strlen("msg") && strncmp(kptr, "msg", strlen("msg")) == 0 && + vlen == strlen("abc") && strncmp(vptr, "abc", strlen("abc")) == 0) + *ret &= ~(1); + else if (klen == strlen("msg2") && + strncmp(kptr, "msg2", strlen("msg2")) == 0 && + vlen == strlen("FooBar") && + strncmp(vptr, "FooBar", strlen("FooBar")) == 0) + *ret &= ~(2); + else + *ret |= 4; +} + +static struct heim_db_type dbt = { + 1, dict_db_open, NULL, dict_db_close, + dict_db_lock, dict_db_unlock, NULL, NULL, NULL, NULL, + dict_db_copy_value, dict_db_set_value, + dict_db_del_key, dict_db_iter +}; + +static int +test_db(const char *dbtype, const char *dbname) +{ + heim_data_t k1, k2, v, v1, v2, v3; + heim_db_t db; + int ret; + + if (dbtype == NULL) { + ret = heim_db_register("dictdb", NULL, &dbt); + heim_assert(!ret, "..."); + db = heim_db_create("dictdb", "foo", NULL, NULL); + heim_assert(!db, "..."); + db = heim_db_create("foobar", "MEMORY", NULL, NULL); + heim_assert(!db, "..."); + db = heim_db_create("dictdb", "MEMORY", NULL, NULL); + heim_assert(db, "..."); + } else { + heim_dict_t options; + + options = heim_dict_create(11); + if (options == NULL) return ENOMEM; + if (heim_dict_set_value(options, HSTR("journal-filename"), + HSTR("json-journal"))) + return ENOMEM; + if (heim_dict_set_value(options, HSTR("create"), heim_null_create())) + return ENOMEM; + if (heim_dict_set_value(options, HSTR("truncate"), heim_null_create())) + return ENOMEM; + db = heim_db_create(dbtype, dbname, options, NULL); + heim_assert(db, "..."); + heim_release(options); + } + + k1 = heim_data_create("msg", strlen("msg")); + k2 = heim_data_create("msg2", strlen("msg2")); + v1 = heim_data_create("Hello world!", strlen("Hello world!")); + v2 = heim_data_create("FooBar", strlen("FooBar")); + v3 = heim_data_create("abc", strlen("abc")); + + ret = heim_db_set_value(db, NULL, k1, v1, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v1), "..."); + heim_release(v); + + ret = heim_db_set_value(db, NULL, k2, v2, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k2, NULL); + heim_assert(v && !heim_cmp(v, v2), "..."); + heim_release(v); + + ret = heim_db_set_value(db, NULL, k1, v3, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v3), "..."); + heim_release(v); + + ret = 3; + heim_db_iterate_f(db, NULL, &ret, test_db_iter, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_begin(db, 0, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_commit(db, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_begin(db, 0, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_rollback(db, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_begin(db, 0, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_set_value(db, NULL, k1, v1, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v1), "..."); + heim_release(v); + + ret = heim_db_rollback(db, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v3), "..."); + heim_release(v); + + ret = heim_db_begin(db, 0, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_set_value(db, NULL, k1, v1, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v1), "..."); + heim_release(v); + + ret = heim_db_commit(db, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v1), "..."); + heim_release(v); + + ret = heim_db_begin(db, 0, NULL); + heim_assert(!ret, "..."); + + ret = heim_db_delete_key(db, NULL, k1, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v == NULL, "..."); + heim_release(v); + + ret = heim_db_rollback(db, NULL); + heim_assert(!ret, "..."); + + v = heim_db_copy_value(db, NULL, k1, NULL); + heim_assert(v && !heim_cmp(v, v1), "..."); + heim_release(v); + + if (dbtype != NULL) { + heim_data_t k3 = heim_data_create("value-is-a-dict", strlen("value-is-a-dict")); + heim_dict_t vdict = heim_dict_create(11); + heim_db_t db2; + + heim_assert(k3 && vdict, "..."); + ret = heim_dict_set_value(vdict, HSTR("vdict-k1"), heim_number_create(11)); + heim_assert(!ret, "..."); + ret = heim_dict_set_value(vdict, HSTR("vdict-k2"), heim_null_create()); + heim_assert(!ret, "..."); + ret = heim_dict_set_value(vdict, HSTR("vdict-k3"), HSTR("a value")); + heim_assert(!ret, "..."); + ret = heim_db_set_value(db, NULL, k3, (heim_data_t)vdict, NULL); + heim_assert(!ret, "..."); + + heim_release(vdict); + + db2 = heim_db_create(dbtype, dbname, NULL, NULL); + heim_assert(db2, "..."); + + vdict = (heim_dict_t)heim_db_copy_value(db2, NULL, k3, NULL); + heim_release(db2); + heim_release(k3); + heim_assert(vdict, "..."); + heim_assert(heim_get_tid(vdict) == heim_dict_get_type_id(), "..."); + + v = heim_dict_copy_value(vdict, HSTR("vdict-k1")); + heim_assert(v && !heim_cmp(v, heim_number_create(11)), "..."); + heim_release(v); + + v = heim_dict_copy_value(vdict, HSTR("vdict-k2")); + heim_assert(v && !heim_cmp(v, heim_null_create()), "..."); + heim_release(v); + + v = heim_dict_copy_value(vdict, HSTR("vdict-k3")); + heim_assert(v && !heim_cmp(v, HSTR("a value")), "..."); + heim_release(v); + + heim_release(vdict); + } + + heim_release(db); + heim_release(k1); + heim_release(k2); + heim_release(v1); + heim_release(v2); + heim_release(v3); + + return 0; +} + +struct test_array_iter_ctx { + char buf[256]; +}; + +static void test_array_iter(heim_object_t elt, void *arg, int *stop) +{ + struct test_array_iter_ctx *iter_ctx = arg; + + strcat(iter_ctx->buf, heim_string_get_utf8((heim_string_t)elt)); +} + +static int +test_array() +{ + struct test_array_iter_ctx iter_ctx; + heim_string_t s1 = heim_string_create("abc"); + heim_string_t s2 = heim_string_create("def"); + heim_string_t s3 = heim_string_create("ghi"); + heim_string_t s4 = heim_string_create("jkl"); + heim_string_t s5 = heim_string_create("mno"); + heim_string_t s6 = heim_string_create("pqr"); + heim_array_t a = heim_array_create(); + + if (!s1 || !s2 || !s3 || !s4 || !s5 || !s6 || !a) + return ENOMEM; + + heim_array_append_value(a, s4); + heim_array_append_value(a, s5); + heim_array_insert_value(a, 0, s3); + heim_array_insert_value(a, 0, s2); + heim_array_append_value(a, s6); + heim_array_insert_value(a, 0, s1); + + iter_ctx.buf[0] = '\0'; + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "abcdefghijklmnopqr") != 0) + return 1; + + iter_ctx.buf[0] = '\0'; + heim_array_delete_value(a, 2); + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "abcdefjklmnopqr") != 0) + return 1; + + iter_ctx.buf[0] = '\0'; + heim_array_delete_value(a, 2); + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "abcdefmnopqr") != 0) + return 1; + + iter_ctx.buf[0] = '\0'; + heim_array_delete_value(a, 0); + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "defmnopqr") != 0) + return 1; + + iter_ctx.buf[0] = '\0'; + heim_array_delete_value(a, 2); + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "defmno") != 0) + return 1; + + heim_array_insert_value(a, 0, s1); + iter_ctx.buf[0] = '\0'; + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "abcdefmno") != 0) + return 1; + + heim_array_insert_value(a, 0, s2); + iter_ctx.buf[0] = '\0'; + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "defabcdefmno") != 0) + return 1; + + heim_array_append_value(a, s3); + iter_ctx.buf[0] = '\0'; + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "defabcdefmnoghi") != 0) + return 1; + + heim_array_append_value(a, s6); + iter_ctx.buf[0] = '\0'; + heim_array_iterate_f(a, &iter_ctx, test_array_iter); + if (strcmp(iter_ctx.buf, "defabcdefmnoghipqr") != 0) + return 1; + + heim_release(s1); + heim_release(s2); + heim_release(s3); + heim_release(s4); + heim_release(s5); + heim_release(s6); + heim_release(a); + + return 0; +} + +/* This function tests only that heimbase-atomics.h compiles */ +static int +test_atomics(void) +{ + heim_base_atomic(void *) tptr; + heim_base_atomic(uint32_t) tu32; + heim_base_atomic(uint64_t) tu64; + + heim_base_atomic_init(&tptr, NULL); + heim_base_atomic_init(&tu32, 0); + heim_base_atomic_init(&tu64, 0); + + if (heim_base_atomic_load(&tptr)) + return 1; + if (heim_base_atomic_load(&tu32)) + return 1; + if (heim_base_atomic_load(&tu64)) + return 1; + + heim_base_atomic_store(&tptr, &tptr); + heim_base_atomic_store(&tu32, 1); + heim_base_atomic_store(&tu64, 1); + + if (heim_base_atomic_load(&tptr) != &tptr) + return 1; + if (heim_base_atomic_load(&tu32) != 1) + return 1; + if (heim_base_atomic_load(&tu64) != 1) + return 1; + + if (heim_base_atomic_inc_32(&tu32) != 2 || + heim_base_atomic_load(&tu32) != 2) + return 1; + if (heim_base_atomic_inc_64(&tu64) != 2 || + heim_base_atomic_load(&tu64) != 2) + return 1; + + if (heim_base_atomic_dec_32(&tu32) != 1 || + heim_base_atomic_load(&tu32) != 1) + return 1; + if (heim_base_atomic_dec_64(&tu64) != 1 || + heim_base_atomic_load(&tu64) != 1) + return 1; + + heim_base_exchange_pointer(&tptr, (void *)&tu32); + if (heim_base_atomic_load(&tptr) != &tu32) + return 1; + heim_base_exchange_32(&tu32, 32); + if (heim_base_atomic_load(&tu32) != 32) + return 1; + heim_base_exchange_64(&tu64, 64); + if (heim_base_atomic_load(&tu64) != 64) + return 1; + + if (heim_base_cas_pointer(&tptr, (void *)&tu32, (void *)&tu64) != &tu32) + return 1; + if (heim_base_cas_pointer(&tptr, (void *)&tu32, (void *)&tptr) != &tu64) + return 1; + if (heim_base_atomic_load(&tptr) != (void *)&tu64) + return 1; + + if (heim_base_cas_32(&tu32, 32, 4) != 32) + return 1; + if (heim_base_cas_32(&tu32, 32, 4) != 4) + return 1; + if (heim_base_atomic_load(&tu32) != 4) + return 1; + + if (heim_base_cas_64(&tu64, 64, 4) != 64) + return 1; + if (heim_base_cas_64(&tu64, 64, 4) != 4) + return 1; + if (heim_base_atomic_load(&tu64) != 4) + return 1; + + return 0; +} + +int +main(int argc, char **argv) +{ + int res = 0; + +#ifndef WIN32 + setlocale(LC_ALL, "C"); + heim_assert(!heim_locale_is_utf8(), "setlocale(LC_ALL, \"C\") failed?"); +#endif + + res |= test_memory(); + res |= test_mutex(); + res |= test_rwlock(); + res |= test_dict(); + res |= test_auto_release(); + res |= test_string(); + res |= test_error(); + res |= test_json(); + res |= test_path(); + res |= test_db(NULL, NULL); + res |= test_db("json", argc > 1 ? argv[1] : "test_db.json"); + res |= test_array(); + res |= test_atomics(); + + return res ? 1 : 0; +} diff --git a/third_party/heimdal/lib/base/version-script.map b/third_party/heimdal/lib/base/version-script.map new file mode 100644 index 0000000..1ba8899 --- /dev/null +++ b/third_party/heimdal/lib/base/version-script.map @@ -0,0 +1,211 @@ +HEIMDAL_BASE_1.0 { + global: + _bsearch_file; + _bsearch_file_close; + _bsearch_file_info; + _bsearch_file_open; + _bsearch_text; + DllMain; + et_heim_error_table; + heim_abort; + heim_abortv; + heim_add_debug_dest; + heim_add_et_list; + heim_addlog_dest; + heim_addlog_func; + heim_add_warn_dest; + heim_alloc; + _heim_alloc_object; + heim_array_append_value; + heim_array_copy_value; + heim_array_create; + heim_array_delete_value; + heim_array_filter_f; + heim_array_get_length; + heim_array_get_type_id; + heim_array_get_value; + heim_array_insert_value; + heim_array_iterate_f; + heim_array_iterate_reverse_f; + heim_array_set_value; + heim_audit_addkv; + heim_audit_addkv_number; + heim_audit_addkv_object; + heim_audit_addkv_timediff; + heim_audit_setkv_bool; + heim_audit_setkv_number; + heim_audit_setkv_object; + heim_audit_addreason; + heim_audit_getkv; + heim_audit_trail; + heim_audit_vaddkv; + heim_audit_vaddreason; + heim_auto_release; + heim_auto_release_create; + heim_auto_release_drain; + heim_base_once_f; + heim_base_mutex; + heim_bool_create; + heim_bool_val; + heim_clear_error_message; + heim_closelog; + heim_cmp; + heim_config_copy; + heim_config_file_free; + heim_config_free_strings; + heim_config_get; + heim_config_get_bool; + heim_config_get_bool_default; + heim_config_get_entry; + heim_config_get_int; + heim_config_get_int_default; + heim_config_get_list; + heim_config_get_next; + heim_config_get_string; + heim_config_get_string_default; + heim_config_get_strings; + heim_config_get_time; + heim_config_get_time_default; + heim_config_parse_dir_multi; + heim_config_parse_file; + heim_config_parse_file_multi; + heim_config_parse_string_multi; + heim_config_vget; + heim_config_vget_bool; + heim_config_vget_bool_default; + heim_config_vget_int; + heim_config_vget_int_default; + heim_config_vget_list; + heim_config_vget_next; + heim_config_vget_string; + heim_config_vget_string_default; + heim_config_vget_strings; + heim_config_vget_time; + heim_config_vget_time_default; + heim_context_free; + heim_context_get_homedir_access; + heim_context_get_log_utc; + heim_context_get_time_fmt; + heim_context_init; + heim_context_set_homedir_access; + heim_context_set_log_utc; + heim_context_set_time_fmt; + _heim_create_type; + heim_data_create; + heim_data_get_data; + heim_data_get_length; + heim_data_get_ptr; + heim_data_get_type_id; + heim_data_ref_create; + heim_data_ref_get_type_id; + heim_db_begin; + heim_db_clone; + heim_db_commit; + heim_db_copy_value; + heim_db_create; + heim_db_delete_key; + heim_db_get_type_id; + _heim_db_get_value; + heim_db_iterate_f; + heim_db_register; + heim_db_rollback; + heim_db_set_value; + heim_debug; + heim_description; + heim_dict_copy_value; + heim_dict_create; + heim_dict_delete_key; + heim_dict_get_type_id; + heim_dict_get_value; + heim_dict_iterate_f; + heim_dict_set_value; + heim_enomem; + heim_error_append; + heim_error_copy_string; + heim_error_create; + heim_error_create_enomem; + heim_error_create_opt; + heim_error_createv; + heim_error_get_code; + heim_expand_path_tokens; + heim_expand_path_tokensv; + heim_free_config_files; + heim_free_error_message; + heim_get_debug_dest; + heim_get_default_config_files; + heim_get_error_message; + heim_get_error_string; + heim_get_hash; + _heim_get_isa; + _heim_get_isaextra; + heim_get_log_dest; + heim_get_tid; + heim_get_warn_dest; + heim_have_debug; + heim_have_error_string; + heim_initlog; + heim_json_copy_serialize; + heim_json_create; + heim_json_create_with_bytes; + heim_json_eq; + heim_load_plugins; + heim_locale_is_utf8; + heim_log; + heim_log_msg; + _heim_make_permanent; + heim_null_create; + heim_number_create; + heim_number_get_int; + heim_number_get_long; + heim_number_get_type_id; + heim_openlog; + heim_path_copy; + heim_path_create; + heim_path_delete; + heim_path_get; + heim_path_vcopy; + heim_path_vcreate; + heim_path_vdelete; + heim_path_vget; + heim_plugin_register; + heim_plugin_run_f; + heim_prepend_config_files; + heim_prepend_config_files_default; + heim_prepend_error_message; + heim_release; + heim_retain; + heim_set_config_files; + heim_set_debug_dest; + heim_set_error_message; + heim_set_log_dest; + heim_set_warn_dest; + heim_show; + heim_sorted_text_file_dbtype; + __heim_string_constant; + heim_string_create; + heim_string_create_with_bytes; + heim_string_create_with_format; + heim_string_get_type_id; + heim_string_get_utf8; + heim_string_ref_create; + _heim_type_get_tid; + heim_unload_plugins; + heim_vdebug; + heim_vlog; + heim_vlog_msg; + heim_vprepend_error_message; + heim_vset_error_message; + heim_vwarn; + heim_vwarnx; + heim_w32_delete_key; + heim_w32_getspecific; + heim_w32_key_create; + heim_w32_service_thread_detach; + heim_w32_setspecific; + heim_warn; + heim_warnx; + initialize_heim_error_table; + initialize_heim_error_table_r; + local: + *; +}; diff --git a/third_party/heimdal/lib/base/warn.c b/third_party/heimdal/lib/base/warn.c new file mode 100644 index 0000000..3dfed48 --- /dev/null +++ b/third_party/heimdal/lib/base/warn.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1997 - 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(_MSC_VER) +# pragma warning(disable: 4646) +# pragma warning(disable: 4716) +#endif + +#include "baselocl.h" +#include + +static heim_error_code _warnerr(heim_context context, int do_errtext, + heim_error_code code, int level, const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 5, 0))); + +static heim_error_code +_warnerr(heim_context context, int do_errtext, + heim_error_code code, int level, const char *fmt, va_list ap) +{ + char xfmt[7] = ""; + const char *args[2], **arg; + char *msg = NULL; + const char *err_str = NULL; + heim_error_code ret; + + args[0] = args[1] = NULL; + arg = args; + if(fmt){ + strlcat(xfmt, "%s", sizeof(xfmt)); + if(do_errtext) + strlcat(xfmt, ": ", sizeof(xfmt)); + ret = vasprintf(&msg, fmt, ap); + if(ret < 0 || msg == NULL) + return ENOMEM; + *arg++ = msg; + } + if (do_errtext) { + strlcat(xfmt, "%s", sizeof(xfmt)); + + err_str = heim_get_error_message(context, code); + if (err_str != NULL) { + *arg = err_str; + } else { + *arg= ""; + } + } + + if (context && heim_get_warn_dest(context)) + heim_log(context, heim_get_warn_dest(context), level, xfmt, args[0], + args[1]); + else + warnx(xfmt, args[0], args[1]); + free(msg); + heim_free_error_message(context, err_str); + return 0; +} + +#define FUNC(ETEXT, CODE, LEVEL) \ + heim_error_code ret; \ + va_list ap; \ + va_start(ap, fmt); \ + ret = _warnerr(context, ETEXT, CODE, LEVEL, fmt, ap); \ + va_end(ap); + +#undef __attribute__ +#define __attribute__(X) + +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup heim_error + */ + +heim_error_code +heim_vwarn(heim_context context, heim_error_code code, + const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + return _warnerr(context, 1, code, 1, fmt, ap); +} + +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup heim_error + */ + +heim_error_code +heim_warn(heim_context context, heim_error_code code, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) +{ + FUNC(1, code, 1); + return ret; +} + +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * @param ap arguments + * + * @ingroup heim_error + */ + +heim_error_code +heim_vwarnx(heim_context context, const char *fmt, va_list ap) + __attribute__ ((__format__ (__printf__, 2, 0))) +{ + return _warnerr(context, 0, 0, 1, fmt, ap); +} + +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * + * @ingroup heim_error + */ + +heim_error_code +heim_warnx(heim_context context, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))) +{ + FUNC(0, 0, 1); + return ret; +} diff --git a/third_party/heimdal/lib/com_err/ChangeLog b/third_party/heimdal/lib/com_err/ChangeLog new file mode 100644 index 0000000..ad8d3e9 --- /dev/null +++ b/third_party/heimdal/lib/com_err/ChangeLog @@ -0,0 +1,235 @@ +2007-07-17 Love Hörnquist Åstrand + + * Makefile.am: split source files in dist and nodist. + +2007-07-16 Love Hörnquist Åstrand + + * Makefile.am: Only do roken rename for the library. + +2007-07-15 Love Hörnquist Åstrand + + * Makefile.am: use version script. + + * version-script.map: use version script. + +2007-07-10 Love Hörnquist Åstrand + + * Makefile.am: New library version. + +2006-10-19 Love Hörnquist Åstrand + + * Makefile.am (compile_et_SOURCES): add lex.h + +2005-12-12 Love Hörnquist Åstrand + + * com_err.3: Document the _r functions. + +2005-07-07 Love Hörnquist Åstrand + + * com_err.h: Include for va_list to help AIX 5.2. + +2005-06-16 Love Hörnquist Åstrand + + * parse.y: rename base to base_id since flex defines a function + with the argument base + + * compile_et.h: rename base to base_id since flex defines a + function with the argument base + + * compile_et.c: rename base to base_id since flex defines a + function with the argument base + + * parse.y (name2number): rename base to num to avoid shadowing + + * compile_et.c: rename optind to optidx + +2005-05-16 Love Hörnquist Åstrand + + * parse.y: check allocation errors + + * lex.l: check allocation errors correctly + + * compile_et.h: include + + * (main): compile_et.c: use strlcpy + +2005-04-29 Dave Love + + * Makefile.am (LDADD): Add libcom_err.la + +2005-04-24 Love Hörnquist Åstrand + + * include strlcpy and *printf and use them + +2005-02-03 Love Hörnquist Åstrand + + * com_right.h: de-__P + + * com_err.h: de-__P + +2002-08-20 Johan Danielsson + + * compile_et.c: don't add comma after last enum member + +2002-08-12 Johan Danielsson + + * compile_et.c: just declare er_list directly instead of including + com_right in generated header files + +2002-03-11 Assar Westerlund + + * Makefile.am (libcom_err_la_LDFLAGS): set version to 2:1:1 + +2002-03-10 Assar Westerlund + + * com_err.c (error_message): do not call strerror with a negative error + +2001-05-17 Assar Westerlund + + * Makefile.am: bump version to 2:0:1 + +2001-05-11 Assar Westerlund + + * com_err.h (add_to_error_table): add prototype + * com_err.c (add_to_error_table): new function, from Derrick J + Brashear + +2001-05-06 Assar Westerlund + + * com_err.h: add printf formats for gcc + +2001-02-28 Johan Danielsson + + * error.c (initialize_error_table_r): put table at end of the list + +2001-02-15 Assar Westerlund + + * com_err.c (default_proc): add printf attributes + +2000-08-16 Assar Westerlund + + * Makefile.am: bump version to 1:1:0 + +2000-07-31 Assar Westerlund + + * com_right.h (initialize_error_table_r): fix prototype + +2000-04-05 Assar Westerlund + + * com_err.c (_et_lit): explicitly initialize it to NULL to make + dyld on Darwin/MacOS X happy + +2000-01-16 Assar Westerlund + + * com_err.h: remove __P definition (now in com_right.h). this + file always includes com_right.h so that's where it should reside. + * com_right.h: moved __P here and added it to the function + prototypes + * com_err.h (error_table_name): add __P + +1999-07-03 Assar Westerlund + + * parse.y (statement): use asprintf + +1999-06-13 Assar Westerlund + + * Makefile.in: make it solaris make vpath-safe + +Thu Apr 1 11:13:53 1999 Johan Danielsson + + * compile_et.c: use getargs + +Sat Mar 20 00:16:30 1999 Assar Westerlund + + * compile_et.c: static-ize + +Thu Mar 18 11:22:13 1999 Johan Danielsson + + * Makefile.am: include Makefile.am.common + +Tue Mar 16 22:30:05 1999 Assar Westerlund + + * parse.y: use YYACCEPT instead of return + +Sat Mar 13 22:22:56 1999 Assar Westerlund + + * compile_et.c (generate_h): cast when calling is* to get rid of a + warning + +Thu Mar 11 15:00:51 1999 Johan Danielsson + + * parse.y: prototype for error_message + +Sun Nov 22 10:39:02 1998 Assar Westerlund + + * compile_et.h: include ctype and roken + + * compile_et.c: include err.h + (generate_h): remove unused variable + + * Makefile.in (WFLAGS): set + +Fri Nov 20 06:58:59 1998 Assar Westerlund + + * lex.l: undef ECHO to work around AIX lex bug + +Sun Sep 27 02:23:59 1998 Johan Danielsson + + * com_err.c (error_message): try to pass code to strerror, to see + if it might be an errno code (this if broken, but some MIT code + seems to expect this behaviour) + +Sat Sep 26 17:42:39 1998 Johan Danielsson + + * compile_et.c: -> "foo_err.h" + +Tue Jun 30 17:17:36 1998 Assar Westerlund + + * Makefile.in: add str{cpy,cat}_truncate + +Mon May 25 05:24:39 1998 Assar Westerlund + + * Makefile.in (clean): try to remove shared library debris + +Sun Apr 19 09:50:17 1998 Assar Westerlund + + * Makefile.in: add symlink magic for linux + +Sun Apr 5 09:22:11 1998 Assar Westerlund + + * parse.y: define alloca to malloc in case we're using bison but + don't have alloca + +Tue Mar 24 05:13:01 1998 Assar Westerlund + + * Makefile.in: link with snprintf (From Derrick J Brashear + ) + +Fri Feb 27 05:01:42 1998 Assar Westerlund + + * parse.y: initialize ec->next + +Thu Feb 26 02:22:25 1998 Assar Westerlund + + * Makefile.am: @LEXLIB@ + +Sat Feb 21 15:18:54 1998 assar westerlund + + * Makefile.in: set YACC and LEX + +Tue Feb 17 22:20:27 1998 Bjoern Groenvall + + * com_right.h: Change typedefs so that one may mix MIT compile_et + generated code with krb4 dito. + +Tue Feb 17 16:30:55 1998 Johan Danielsson + + * compile_et.c (generate): Always return a value. + + * parse.y: Files don't have to end with `end'. + +Mon Feb 16 16:09:20 1998 Johan Danielsson + + * lex.l (getstring): Replace getc() with input(). + + * Makefile.am: Fixes for new compile_et. diff --git a/third_party/heimdal/lib/com_err/Makefile.am b/third_party/heimdal/lib/com_err/Makefile.am new file mode 100644 index 0000000..187e774 --- /dev/null +++ b/third_party/heimdal/lib/com_err/Makefile.am @@ -0,0 +1,50 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +AM_YFLAGS = -d -o parse.c +AM_LFLAGS = @FLEXNOUNPUTARGS@ + +lib_LTLIBRARIES = libcom_err.la +libcom_err_la_LDFLAGS = -version-info 2:3:1 + +if versionscript +libcom_err_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +libcom_err_la_LIBADD = $(LIB_libintl) + +noinst_PROGRAMS = compile_et + +include_HEADERS = com_err.h com_right.h + +compile_et_SOURCES = compile_et.c compile_et.h parse.y lex.l lex.h + +libcom_err_la_CPPFLAGS = $(ROKEN_RENAME) $(INCLUDE_libintl) +dist_libcom_err_la_SOURCES = error.c com_err.c roken_rename.h + +if do_roken_rename +nodist_libcom_err_la_SOURCES = snprintf.c strlcpy.c +endif + +libcom_err_la_DEPENDENCIES = version-script.map + +$(compile_et_OBJECTS): parse.h parse.c ## XXX broken automake 1.4s + +compile_et_LDADD = \ + libcom_err.la \ + $(LIB_roken) \ + $(LEXLIB) + +snprintf.c: + $(LN_S) $(srcdir)/../roken/snprintf.c . +strlcpy.c: + $(LN_S) $(srcdir)/../roken/strlcpy.c . + +EXTRA_DIST = \ + NTMakefile \ + com_err.3 \ + compile_et-version.rc \ + libcom_err-version.rc \ + libcom_err-exports.def \ + version-script.map diff --git a/third_party/heimdal/lib/com_err/NTMakefile b/third_party/heimdal/lib/com_err/NTMakefile new file mode 100644 index 0000000..531b8ab --- /dev/null +++ b/third_party/heimdal/lib/com_err/NTMakefile @@ -0,0 +1,91 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR = lib\com_err + +intcflags=-DBUILD_KRB5_LIB + +!include ../../windows/NTMakefile.w32 + +INCFILES=$(INCDIR)\com_err.h $(INCDIR)\com_right.h + +libcomerr_OBJs=$(OBJ)\error.obj $(OBJ)\com_err.obj + +COMERRDLL=$(BINDIR)\com_err.dll + +!ifdef STATICLIBS + +$(LIBCOMERR): $(libcomerr_OBJs) + $(LIBCON) + +!else + +$(LIBCOMERR): $(COMERRDLL) + +$(COMERRDLL): $(libcomerr_OBJs) $(OBJ)\libcom_err-version.res + $(DLLGUILINK_C) -out:$(COMERRDLL) -implib:$(LIBCOMERR) $** \ + $(LIBROKEN) \ + -def:libcom_err-exports.def + $(DLLPREP_NODIST) + +!endif + +$(BINDIR)\compile_et.exe: $(OBJ)\parse.obj $(OBJ)\lex.obj $(OBJ)\compile_et.obj $(OBJ)\compile_et-version.res + $(EXECONLINK) $(LIBROKEN) $(LIBVERS) + $(EXEPREP_NOHEIM) + +$(OBJ)\parse.obj: $(OBJ)\parse.c + $(C2OBJ) -I$(SRC)\$(RELDIR) + +$(OBJ)\lex.obj: $(OBJ)\lex.c + $(C2OBJ) -I$(SRC)\$(RELDIR) -DYY_NO_UNISTD_H + +$(OBJ)\compile_et.obj: compile_et.c + $(C2OBJ) -I$(OBJ) + +$(OBJ)\parse.c: parse.y + $(YACC) -o $@ --defines=$(OBJ)\parse.h parse.y + +$(OBJ)\lex.c: lex.l + $(LEX) -o$@ lex.l + +all:: $(INCFILES) $(LIBCOMERR) $(BINDIR)\compile_et.exe + +clean:: + -$(RM) $(LIBCOMERR) + -$(RM) $(INCFILES) + -$(RM) $(COMERRDLL:.dll=.*) + -$(RM) $(BINDIR)\compile_et.* + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libcom_err-exports.def + +test:: test-exports diff --git a/third_party/heimdal/lib/com_err/com_err.3 b/third_party/heimdal/lib/com_err/com_err.3 new file mode 100644 index 0000000..c768616 --- /dev/null +++ b/third_party/heimdal/lib/com_err/com_err.3 @@ -0,0 +1,246 @@ +.\" Copyright (c) 2005 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.\" This manpage was contributed by Gregory McGarry. +.\" +.Dd July 7, 2005 +.Dt COM_ERR 3 +.Os +.Sh NAME +.Nm com_err , +.Nm com_err_va , +.Nm error_message , +.Nm error_table_name , +.Nm init_error_table , +.Nm set_com_err_hook , +.Nm reset_com_err_hook , +.Nm add_to_error_table , +.Nm initialize_error_table_r , +.Nm free_error_table , +.Nm com_right +.Nd common error display library +.Sh LIBRARY +Common Error Library (libcom_err, -lcom_err) +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Fd #include \&"XXX_err.h\&" +.Pp +typedef void (*errf)(const char *, long, const char *, ...); +.Ft void +.Fn com_err "const char *whoami" "long code" "const char *format" "..." +.Ft void +.Fn com_err_va "const char *whoami" "long code" "const char *format" "..." +.Ft const char * +.Fn error_message "long code" +.Ft const char * +.Fn error_table_name "int num" +.Ft int +.Fn init_error_table "const char **msgs" "long base" "int count" +.Ft errf +.Fn set_com_err_hook "errf func" +.Ft errf +.Fn reset_com_err_hook "" +.Ft void +.Fn add_to_error_table "struct et_list *new_table" +.Ft void +.Fn initialize_error_table_r "struct et_list **et_list" "const char **msgs" "int base" "long count" +.Ft void +.Fn free_error_table "struct et_list *" +.Ft const char * +.Fn com_right "struct et_list *list" long code" +.Sh DESCRIPTION +The +.Nm +library provides a common error-reporting mechanism for defining and +accessing error codes and descriptions for application software +packages. Error descriptions are defined in a table and error codes +are used to index the table. The error table, the descriptions and +the error codes are generated using +.Xr compile_et 1 . +.Pp +The error table is registered with the +.Nm +library by calling its initialisation function defined in its header +file. The initialisation function is generally defined as +.Fn initialize__error_table , +where +.Em name +is the name of the error table. +.Pp +If a thread-safe version of the library is needed +.Fn initialize__error_table_r +that internally calls +.Fn initialize_error_table_r +instead be used. +.Pp +Any variable which is to contain an error code should be declared +.Em _error_number +where +.Em name +is the name of the error table. +.Sh FUNCTIONS +The following functions are available to the application developer: +.Bl -tag -width compact +.It Fn com_err "whoami" "code" "format" "..." +Displays an error message on standard error composed of the +.Fa whoami +string, which should specify the program name, followed by an error +message generated from +.Fa code , +and a string produced using the +.Xr printf 3 +.Fa format +string and any following arguments. If +.Fa format +is NULL, the formatted message will not be +printed. The argument +.Fa format +may not be omitted. +.It Fn com_err_va "whoami" "code" "format" "va_list args" +This routine provides an interface, equivalent to +.Fn com_err , +which may be used by higher-level variadic functions (functions which +accept variable numbers of arguments). +.It Fn error_message "code" +Returns the character string error message associated with +.Fa code . +If +.Fa code +is associated with an unknown error table, or if +.Fa code +is associated with a known error table but is not in the table, a +string of the form `Unknown code XXXX NN' is returned, where XXXX is +the error table name produced by reversing the compaction performed on +the error table number implied by that error code, and NN is the +offset from that base value. +.Pp +Although this routine is available for use when needed, its use should +be left to circumstances which render +.Fn com_err +unusable. +.Pp +.Fn com_right +returns the error string just like +.Fa com_err +but in a thread-safe way. +.Pp +.It Fn error_table_name "num" +Convert a machine-independent error table number +.Fa num +into an error table name. +.It Fn init_error_table "msgs" "base" "count" +Initialise the internal error table with the array of character string +error messages in +.Fa msgs +of length +.Fa count . +The error codes are assigned incrementally from +.Fa base . +This function is useful for using the error-reporting mechanism with +custom error tables that have not been generated with +.Xr compile_et 1 . +Although this routine is available for use when needed, its use should +be restricted. +.Pp +.Fn initialize_error_table_r +initialize the +.Fa et_list +in the same way as +.Fn init_error_table , +but in a thread-safe way. +.Pp +.It Fn set_com_err_hook "func" +Provides a hook into the +.Nm +library to allow the routine +.Fa func +to be dynamically substituted for +.Fn com_err . +After +.Fn set_com_err_hook + has been called, calls to +.Fn com_err +will turn into calls to the new hook routine. This function is +intended to be used in daemons to use a routine which calls +.Xr syslog 3 , +or in a window system application to pop up a dialogue box. +.It Fn reset_com_err_hook "" +Turns off the hook set in +.Fn set_com_err_hook . +.It Fn add_to_error_table "new_table" +Add the error table, its messages strings and error codes in +.Fa new_table +to the internal error table. +.El +.Sh EXAMPLES +The following is an example using the table defined in +.Xr compile_et 1 : +.Pp +.Bd -literal + #include + #include + #include + + #include "test_err.h" + + void + hook(const char *whoami, long code, + const char *format, va_list args) + { + char buffer[BUFSIZ]; + static int initialized = 0; + + if (!initialized) { + openlog(whoami, LOG_NOWAIT, LOG_DAEMON); + initialized = 1; + } + vsprintf(buffer, format, args); + syslog(LOG_ERR, "%s %s", error_message(code), buffer); + } + + int + main(int argc, char *argv[]) + { + char *whoami = argv[0]; + + initialize_test_error_table(); + com_err(whoami, TEST_INVAL, "before hook"); + set_com_err_hook(hook); + com_err(whoami, TEST_IO, "after hook"); + return (0); + } +.Ed +.Sh SEE ALSO +.Xr compile_et 1 diff --git a/third_party/heimdal/lib/com_err/com_err.c b/third_party/heimdal/lib/com_err/com_err.c new file mode 100644 index 0000000..d212e40 --- /dev/null +++ b/third_party/heimdal/lib/com_err/com_err.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include + +#include +#include +#include +#include +#include +#include "com_err.h" + +struct et_list *_et_list = NULL; + + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +error_message (long code) +{ + static char msg[128]; + const char *p = com_right(_et_list, code); + if (p == NULL) { + if (code < 0) + snprintf(msg, sizeof(msg), "Unknown error %ld", code); + else + p = strerror(code); + } + if (p != NULL && *p != '\0') { + strlcpy(msg, p, sizeof(msg)); + } else + snprintf(msg, sizeof(msg), "Unknown error %ld", code); + return msg; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +init_error_table(const char *const *msgs, long base, int count) +{ + initialize_error_table_r(&_et_list, msgs, count, base); + return 0; +} + +static void KRB5_CALLCONV +default_proc (const char *whoami, long code, const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))); + +static void KRB5_CALLCONV +default_proc (const char *whoami, long code, const char *fmt, va_list args) +{ + if (whoami) + fprintf(stderr, "%s: ", whoami); + if (code) + fprintf(stderr, "%s ", error_message(code)); + if (fmt) + vfprintf(stderr, fmt, args); + fprintf(stderr, "\r\n"); /* ??? */ +} + +static errf com_err_hook = default_proc; + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +com_err_va (const char *whoami, + long code, + const char *fmt, + va_list args) +{ + (*com_err_hook) (whoami, code, fmt, args); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +com_err (const char *whoami, + long code, + const char *fmt, + ...) +{ + va_list ap; + va_start(ap, fmt); + com_err_va (whoami, code, fmt, ap); + va_end(ap); +} + +KRB5_LIB_FUNCTION errf KRB5_LIB_CALL +set_com_err_hook (errf new) +{ + errf old = com_err_hook; + + if (new) + com_err_hook = new; + else + com_err_hook = default_proc; + + return old; +} + +KRB5_LIB_FUNCTION errf KRB5_LIB_CALL +reset_com_err_hook (void) +{ + return set_com_err_hook(NULL); +} + +#define ERRCODE_RANGE 8 /* # of bits to shift table number */ +#define BITS_PER_CHAR 6 /* # bits to shift per character in name */ + +static const char char_set[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + +static HEIMDAL_THREAD_LOCAL char buf[6]; + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +error_table_name(int num) +{ + int ch; + int i; + char *p; + + /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ + p = buf; + num >>= ERRCODE_RANGE; + /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ + num &= 077777777; + /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ + for (i = 4; i >= 0; i--) { + ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1); + if (ch != 0) + *p++ = char_set[ch-1]; + } + *p = '\0'; + return(buf); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +add_to_error_table(struct et_list *new_table) +{ + struct et_list *et; + + for (et = _et_list; et; et = et->next) { + if (et->table->base == new_table->table->base) + return; + } + + new_table->next = _et_list; + _et_list = new_table; +} diff --git a/third_party/heimdal/lib/com_err/com_err.h b/third_party/heimdal/lib/com_err/com_err.h new file mode 100644 index 0000000..0588fe0 --- /dev/null +++ b/third_party/heimdal/lib/com_err/com_err.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +/* MIT compatible com_err library */ + +#ifndef __COM_ERR_H__ +#define __COM_ERR_H__ + +#include +#include + +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(X) +#endif + +typedef void (KRB5_CALLCONV *errf) (const char *, long, const char *, va_list); + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +error_message (long); + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +init_error_table (const char *const *, long, int); + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +com_err_va (const char *, long, const char *, va_list) + __attribute__ ((__format__ (__printf__, 3, 0))); + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +com_err (const char *, long, const char *, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +KRB5_LIB_FUNCTION errf KRB5_LIB_CALL +set_com_err_hook (errf); + +KRB5_LIB_FUNCTION errf KRB5_LIB_CALL +reset_com_err_hook (void); + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +error_table_name (int num); + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +add_to_error_table (struct et_list *new_table); + +#endif /* __COM_ERR_H__ */ diff --git a/third_party/heimdal/lib/com_err/com_right.h b/third_party/heimdal/lib/com_err/com_right.h new file mode 100644 index 0000000..9efb633 --- /dev/null +++ b/third_party/heimdal/lib/com_err/com_right.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __COM_RIGHT_H__ +#define __COM_RIGHT_H__ + +#ifndef KRB5_LIB +#ifndef KRB5_LIB_FUNCTION +#if defined(_WIN32) +#define KRB5_LIB_FUNCTION __declspec(dllimport) +#define KRB5_LIB_CALL __stdcall +#define KRB5_LIB_VARIABLE __declspec(dllimport) +#else +#define KRB5_LIB_FUNCTION +#define KRB5_LIB_CALL +#define KRB5_LIB_VARIABLE +#endif +#endif +#endif + +#ifdef _WIN32 +#define KRB5_CALLCONV __stdcall +#else +#define KRB5_CALLCONV +#endif + +#ifdef __STDC__ +#include +#include +#endif + +struct error_table { + char const * const * msgs; + long base; + int n_msgs; +}; +struct et_list { + struct et_list *next; + struct error_table *table; +}; +extern struct et_list *_et_list; + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +com_right (struct et_list *list, long code); + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +com_right_r (struct et_list *list, long code, char *, size_t); + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +initialize_error_table_r (struct et_list **, const char *const *, int, long); + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +free_error_table (struct et_list *); + +#endif /* __COM_RIGHT_H__ */ diff --git a/third_party/heimdal/lib/com_err/compile_et-version.rc b/third_party/heimdal/lib/com_err/compile_et-version.rc new file mode 100644 index 0000000..5b0b91a --- /dev/null +++ b/third_party/heimdal/lib/com_err/compile_et-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "Error Table Compiler" +#define RC_FILE_ORIG_0409 "compile_et.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/com_err/compile_et.c b/third_party/heimdal/lib/com_err/compile_et.c new file mode 100644 index 0000000..033e0aa --- /dev/null +++ b/third_party/heimdal/lib/com_err/compile_et.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1998-2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#undef ROKEN_RENAME + +#include "config.h" + +#include "compile_et.h" +#include + +#include +#include +#include "parse.h" + +int numerror; +extern FILE *yyin; + +int yyparse(void); + +long base_id; +int number; +char *prefix; +char *id_str; + +char name[128]; +char Basename[128]; + +#ifdef YYDEBUG +extern int yydebug; +int yydebug = 1; +#endif + +char *filename; +char hfn[130]; +char cfn[130]; + +struct error_code *codes = NULL; + +static int +generate_c(void) +{ + int n; + struct error_code *ec; + + FILE *c_file = fopen(cfn, "w"); + if(c_file == NULL) + return 1; + + fprintf(c_file, "/* Generated from %s */\n", filename); + if(id_str) + fprintf(c_file, "/* %s */\n", id_str); + fprintf(c_file, "\n"); + fprintf(c_file, "#include \n"); + fprintf(c_file, "#include \n"); + fprintf(c_file, "#include \"%s\"\n", hfn); + fprintf(c_file, "\n"); + fprintf(c_file, "#define N_(x) (x)\n"); + fprintf(c_file, "\n"); + + fprintf(c_file, "static const char *const %s_error_strings[] = {\n", name); + + for(ec = codes, n = 0; ec; ec = ec->next, n++) { + while(n < ec->number) { + fprintf(c_file, "\t/* %03d */ \"Reserved %s error (%d)\",\n", + n, name, n); + n++; + + } + fprintf(c_file, "\t/* %03d */ N_(\"%s\"),\n", + ec->number, ec->string); + } + + fprintf(c_file, "\tNULL\n"); + fprintf(c_file, "};\n"); + fprintf(c_file, "\n"); + fprintf(c_file, "#define num_errors %d\n", number); + fprintf(c_file, "\n"); + fprintf(c_file, + "void initialize_%s_error_table_r(struct et_list **list)\n", + name); + fprintf(c_file, "{\n"); + fprintf(c_file, + " initialize_error_table_r(list, %s_error_strings, " + "num_errors, ERROR_TABLE_BASE_%s);\n", name, name); + fprintf(c_file, "}\n"); + fprintf(c_file, "\n"); + fprintf(c_file, "void initialize_%s_error_table(void)\n", name); + fprintf(c_file, "{\n"); + fprintf(c_file, + " init_error_table(%s_error_strings, ERROR_TABLE_BASE_%s, " + "num_errors);\n", name, name); + fprintf(c_file, "}\n"); + + fclose(c_file); + return 0; +} + +static int +generate_h(void) +{ + struct error_code *ec; + char fn[134]; + FILE *h_file = fopen(hfn, "w"); + char *p; + + if(h_file == NULL) + return 1; + + snprintf(fn, sizeof(fn), "__%s__", hfn); + for(p = fn; *p; p++) + if(!isalnum((unsigned char)*p)) + *p = '_'; + + fprintf(h_file, "/* Generated from %s */\n", filename); + if(id_str) + fprintf(h_file, "/* %s */\n", id_str); + fprintf(h_file, "\n"); + fprintf(h_file, "#ifndef %s\n", fn); + fprintf(h_file, "#define %s\n", fn); + fprintf(h_file, "\n"); + fprintf(h_file, "struct et_list;\n"); + fprintf(h_file, "\n"); + fprintf(h_file, + "void initialize_%s_error_table_r(struct et_list **);\n", + name); + fprintf(h_file, "\n"); + fprintf(h_file, "void initialize_%s_error_table(void);\n", name); + fprintf(h_file, "#define init_%s_err_tbl initialize_%s_error_table\n", + name, name); + fprintf(h_file, "\n"); + fprintf(h_file, "typedef enum %s_error_number{\n", name); + + for(ec = codes; ec; ec = ec->next) { + fprintf(h_file, "\t%s = %ld%s\n", ec->name, base_id + ec->number, + (ec->next != NULL) ? "," : ""); + } + + fprintf(h_file, "} %s_error_number;\n", name); + fprintf(h_file, "\n"); + fprintf(h_file, "#define ERROR_TABLE_BASE_%s %ld\n", name, base_id); + fprintf(h_file, "\n"); + fprintf(h_file, "#define COM_ERR_BINDDOMAIN_%s \"heim_com_err%ld\"\n", name, base_id); + fprintf(h_file, "\n"); + fprintf(h_file, "#endif /* %s */\n", fn); + + + fclose(h_file); + return 0; +} + +static int +generate(void) +{ + return generate_c() || generate_h(); +} + +int version_flag; +int help_flag; +struct getargs args[] = { + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "error-table"); + exit(code); +} + +int +main(int argc, char **argv) +{ + char *p; + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + + if(optidx == argc) + usage(1); + filename = argv[optidx]; + yyin = fopen(filename, "r"); + if(yyin == NULL) + err(1, "%s", filename); + + + p = strrchr(filename, rk_PATH_DELIM); + if(p) + p++; + else + p = filename; + strlcpy(Basename, p, sizeof(Basename)); + + Basename[strcspn(Basename, ".")] = '\0'; + + snprintf(hfn, sizeof(hfn), "%s.h", Basename); + snprintf(cfn, sizeof(cfn), "%s.c", Basename); + + yyparse(); + if(numerror) + return 1; + + return generate(); +} diff --git a/third_party/heimdal/lib/com_err/compile_et.h b/third_party/heimdal/lib/com_err/compile_et.h new file mode 100644 index 0000000..b0b8e21 --- /dev/null +++ b/third_party/heimdal/lib/com_err/compile_et.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __COMPILE_ET_H__ +#define __COMPILE_ET_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +extern long base_id; +extern int number; +extern char *prefix; +extern char name[128]; +extern char *id_str; +extern char *filename; +extern int numerror; + +struct error_code { + unsigned number; + char *name; + char *string; + struct error_code *next, **tail; +}; + +extern struct error_code *codes; + +#define APPEND(L, V) \ +do { \ + if((L) == NULL) { \ + (L) = (V); \ + (L)->tail = &(V)->next; \ + (L)->next = NULL; \ + }else{ \ + *(L)->tail = (V); \ + (L)->tail = &(V)->next; \ + } \ +}while(0) + +#endif /* __COMPILE_ET_H__ */ diff --git a/third_party/heimdal/lib/com_err/error.c b/third_party/heimdal/lib/com_err/error.c new file mode 100644 index 0000000..3ce714b --- /dev/null +++ b/third_party/heimdal/lib/com_err/error.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1997, 1998, 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include + +#include +#include +#include +#include +#include + +#ifdef LIBINTL +#include +#else +#define dgettext(d,s) (s) +#endif + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +com_right(struct et_list *list, long code) +{ + struct et_list *p; + for (p = list; p; p = p->next) + if (code >= p->table->base && code < p->table->base + p->table->n_msgs) + return p->table->msgs[code - p->table->base]; + return NULL; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +com_right_r(struct et_list *list, long code, char *str, size_t len) +{ + struct et_list *p; + for (p = list; p; p = p->next) { + if (code >= p->table->base && code < p->table->base + p->table->n_msgs) { + const char *msg = p->table->msgs[code - p->table->base]; +#ifdef LIBINTL + char domain[12 + 20]; + snprintf(domain, sizeof(domain), "heim_com_err%ld", p->table->base); +#endif + strlcpy(str, dgettext(domain, msg), len); + return str; + } + } + return NULL; +} + +struct foobar { + struct et_list etl; + struct error_table et; +}; + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +initialize_error_table_r(struct et_list **list, + const char *const *messages, + int num_errors, + long base) +{ + struct et_list *et, **end; + struct foobar *f; + for (end = list, et = *list; et; end = &et->next, et = et->next) + if (et->table->msgs == messages) + return; + f = malloc(sizeof(*f)); + if (f == NULL) + return; + et = &f->etl; + et->table = &f->et; + et->table->msgs = messages; + et->table->n_msgs = num_errors; + et->table->base = base; + et->next = NULL; + *end = et; +} + + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +free_error_table(struct et_list *et) +{ + while(et){ + struct et_list *p = et; + et = et->next; + free(p); + } +} diff --git a/third_party/heimdal/lib/com_err/lex.h b/third_party/heimdal/lib/com_err/lex.h new file mode 100644 index 0000000..dcf6e87 --- /dev/null +++ b/third_party/heimdal/lib/com_err/lex.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +void _lex_error_message (const char *, ...) +__attribute__ ((__format__ (__printf__, 1, 2))); + +int yylex(void); diff --git a/third_party/heimdal/lib/com_err/lex.l b/third_party/heimdal/lib/com_err/lex.l new file mode 100644 index 0000000..e812b32 --- /dev/null +++ b/third_party/heimdal/lib/com_err/lex.l @@ -0,0 +1,123 @@ +%{ +/* + * Copyright (c) 1998 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is to handle the definition of this symbol in some AIX + * headers, which will conflict with the definition that lex will + * generate for it. It's only a problem for AIX lex. + */ + +#undef ECHO + +#include "compile_et.h" +#include "parse.h" +#include "lex.h" + +static unsigned lineno = 1; +static int getstring(void); + +#define YY_NO_UNPUT + +#undef ECHO + +%} + +%% +et { return ET; } +error_table { return ET; } +ec { return EC; } +error_code { return EC; } +prefix { return PREFIX; } +index { return INDEX; } +id { return ID; } +end { return END; } +[0-9]+ { yylval.number = atoi(yytext); return NUMBER; } +#[^\n]* ; +[ \t] ; +\n { lineno++; } +\" { return getstring(); } +[a-zA-Z0-9_]+ { yylval.string = strdup(yytext); return STRING; } +. { return *yytext; } +%% + +int +yywrap () +{ + return 1; +} + +static int +getstring(void) +{ + char x[128]; + int i = 0; + int c; + int quote = 0; + while(i < sizeof(x) - 1 && (c = input()) != EOF){ + if(quote) { + x[i++] = c; + quote = 0; + continue; + } + if(c == '\n'){ + _lex_error_message("unterminated string"); + lineno++; + break; + } + if(c == '\\'){ + quote++; + continue; + } + if(c == '\"') + break; + x[i++] = c; + } + x[i] = '\0'; + yylval.string = strdup(x); + if (yylval.string == NULL) + err(1, "malloc"); + return STRING; +} + +void +_lex_error_message (const char *format, ...) +{ + va_list args; + + va_start (args, format); + fprintf (stderr, "%s:%d:", filename, lineno); + vfprintf (stderr, format, args); + va_end (args); + numerror++; +} diff --git a/third_party/heimdal/lib/com_err/libcom_err-exports.def b/third_party/heimdal/lib/com_err/libcom_err-exports.def new file mode 100644 index 0000000..a4db194 --- /dev/null +++ b/third_party/heimdal/lib/com_err/libcom_err-exports.def @@ -0,0 +1,14 @@ +EXPORTS + com_right + com_right_r + free_error_table + initialize_error_table_r + add_to_error_table + com_err + com_err_va + error_message + error_table_name + init_error_table + reset_com_err_hook + set_com_err_hook + _et_list DATA diff --git a/third_party/heimdal/lib/com_err/libcom_err-version.rc b/third_party/heimdal/lib/com_err/libcom_err-version.rc new file mode 100644 index 0000000..7fe6432 --- /dev/null +++ b/third_party/heimdal/lib/com_err/libcom_err-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2009, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_DLL +#define RC_FILE_DESC_0409 "Common Error Library" +#define RC_FILE_ORIG_0409 "com_err.dll" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/com_err/parse.y b/third_party/heimdal/lib/com_err/parse.y new file mode 100644 index 0000000..bcb9b05 --- /dev/null +++ b/third_party/heimdal/lib/com_err/parse.y @@ -0,0 +1,175 @@ +%{ +/* + * Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "compile_et.h" +#include "lex.h" + +void yyerror (const char *s); +#define yyerror yyerror +static long name2number(const char *str); + +extern char *yytext; + +/* This is for bison */ + +#if !defined(alloca) && !defined(HAVE_ALLOCA) +#define alloca(x) malloc(x) +#endif + +#define YYMALLOC malloc +#define YYFREE free + +%} + +%union { + char *string; + int number; +} + +%token ET INDEX PREFIX EC ID END +%token STRING +%token NUMBER + +%% + +file : /* */ + | header statements + ; + +header : id et + | et + ; + +id : ID STRING + { + id_str = $2; + } + ; + +et : ET STRING + { + base_id = name2number($2); + strlcpy(name, $2, sizeof(name)); + free($2); + } + | ET STRING STRING + { + base_id = name2number($2); + strlcpy(name, $3, sizeof(name)); + free($2); + free($3); + } + ; + +statements : statement + | statements statement + ; + +statement : INDEX NUMBER + { + number = $2; + } + | PREFIX STRING + { + free(prefix); + asprintf (&prefix, "%s_", $2); + if (prefix == NULL) + errx(1, "malloc"); + free($2); + } + | PREFIX + { + prefix = realloc(prefix, 1); + if (prefix == NULL) + errx(1, "malloc"); + *prefix = '\0'; + } + | EC STRING ',' STRING + { + struct error_code *ec = malloc(sizeof(*ec)); + + if (ec == NULL) + errx(1, "malloc"); + + ec->next = NULL; + ec->number = number; + if(prefix && *prefix != '\0') { + asprintf (&ec->name, "%s%s", prefix, $2); + if (ec->name == NULL) + errx(1, "malloc"); + free($2); + } else + ec->name = $2; + ec->string = $4; + APPEND(codes, ec); + number++; + } + | END + { + YYACCEPT; + } + ; + +%% + +static long +name2number(const char *str) +{ + const char *p; + long num = 0; + const char *x = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789_"; + if(strlen(str) > 4) { + yyerror("table name too long"); + return 0; + } + for(p = str; *p; p++){ + char *q = strchr(x, *p); + if(q == NULL) { + yyerror("invalid character in table name"); + return 0; + } + num = (num << 6) + (q - x) + 1; + } + num <<= 8; + if(num > 0x7fffffff) + num = -(0xffffffff - num + 1); + return num; +} + +void +yyerror (const char *s) +{ + _lex_error_message ("%s\n", s); +} diff --git a/third_party/heimdal/lib/com_err/roken_rename.h b/third_party/heimdal/lib/com_err/roken_rename.h new file mode 100644 index 0000000..3da2948 --- /dev/null +++ b/third_party/heimdal/lib/com_err/roken_rename.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __roken_rename_h__ +#define __roken_rename_h__ + +#ifndef HAVE_SNPRINTF +#define rk_snprintf _com_err_snprintf +#endif +#ifndef HAVE_VSNPRINTF +#define rk_vsnprintf _com_err_vsnprintf +#endif +#ifndef HAVE_ASPRINTF +#define rk_asprintf _com_err_asprintf +#endif +#ifndef HAVE_ASNPRINTF +#define rk_asnprintf _com_err_asnprintf +#endif +#ifndef HAVE_VASPRINTF +#define rk_vasprintf _com_err_vasprintf +#endif +#ifndef HAVE_VASNPRINTF +#define rk_vasnprintf _com_err_vasnprintf +#endif +#ifndef HAVE_STRLCPY +#define rk_strlcpy _com_err_strlcpy +#endif + + +#endif /* __roken_rename_h__ */ diff --git a/third_party/heimdal/lib/com_err/version-script.map b/third_party/heimdal/lib/com_err/version-script.map new file mode 100644 index 0000000..8da2fef --- /dev/null +++ b/third_party/heimdal/lib/com_err/version-script.map @@ -0,0 +1,20 @@ +# $Id$ + +HEIMDAL_COM_ERR_1.0 { + global: + com_right; + com_right_r; + free_error_table; + initialize_error_table_r; + add_to_error_table; + com_err; + com_err_va; + error_message; + error_table_name; + init_error_table; + reset_com_err_hook; + set_com_err_hook; + _et_list; + local: + *; +}; diff --git a/third_party/heimdal/lib/gss_preauth/Makefile.am b/third_party/heimdal/lib/gss_preauth/Makefile.am new file mode 100644 index 0000000..6503119 --- /dev/null +++ b/third_party/heimdal/lib/gss_preauth/Makefile.am @@ -0,0 +1,25 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +AM_CPPFLAGS += \ + -I$(srcdir)/../krb5 \ + -I$(srcdir)/../gssapi \ + -I$(srcdir)/../gssapi/mech \ + -I$(top_srcdir)/include/gssapi \ + -I$(top_builddir)/include/gssapi + +noinst_LTLIBRARIES = libgss_preauth.la +include_HEADERS = $(srcdir)/gss-preauth-protos.h $(srcdir)/gss-preauth-private.h + +libgss_preauth_la_SOURCES = pa_client.c pa_common.c + +ALL_OBJECTS = $(include_HEADERS) $(libgss_preauth_la_OBJECTS) + +$(libgss_preauth_la_OBJECTS): $(include_HEADERS) + +$(srcdir)/gss-preauth-protos.h: $(libgss_preauth_la_SOURCES) + cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -o gss-preauth-protos.h $(libgss_preauth_la_SOURCES) || rm -f gss-preauth-protos.h + +$(srcdir)/gss-preauth-private.h: $(libgss_preauth_la_SOURCES) + cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p gss-preauth-private.h $(libgss_preauth_la_SOURCES) || rm -f gss-preauth-private.h diff --git a/third_party/heimdal/lib/gss_preauth/NTMakefile b/third_party/heimdal/lib/gss_preauth/NTMakefile new file mode 100644 index 0000000..60c963b --- /dev/null +++ b/third_party/heimdal/lib/gss_preauth/NTMakefile @@ -0,0 +1,70 @@ +######################################################################## +# +# Copyright (c) 2021, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\gss_preauth + +intcflags=-I$(SRCDIR) \ + -I$(SRCDIR)\..\krb5 \ + -I$(SRCDIR)\..\gssapi \ + -I$(SRCDIR)\..\gssapi\mech \ + -I$(OBJ) \ + -I$(OBJDIR)\lib\gssapi \ + -I$(OBJDIR)\lib\gssapi\gssapi \ + -I$(INCDIR) \ + -I$(INCDIR)\gssapi \ + +!include ../../windows/NTMakefile.w32 + +INCFILES= \ + $(OBJ)\gss-preauth-protos.h \ + $(OBJ)\gss-preauth-private.h + +libgss_preauth_SOURCES = \ + pa_client.c \ + pa_common.c + +libgss_preauth_OBJS = \ + $(OBJ)\pa_client.obj \ + $(OBJ)\pa_common.obj + +$(LIBGSS_PREAUTH): $(libgss_preauth_OBJS) + $(LIBCON) + +$(OBJ)\gss-preauth-protos.h: $(libgss_preauth_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -E KRB5_LIB -q -P remove -o $(OBJ)\gss-preauth-protos.h $(libgss_preauth_SOURCES) || $(RM) -f $(OBJ)\gss-preauth-protos.h + +$(OBJ)\gss-preauth-private.h: $(libgss_preauth_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\gss-preauth-private.h $(libgss_preauth_SOURCES) || $(RM) -f $(OBJ)\gss-preauth-private.h + +all:: $(INCFILES) $(LIBGSS_PREAUTH) + +clean:: + -$(RM) $(INCFILES) $(LIBGSS_PREAUTH) diff --git a/third_party/heimdal/lib/gss_preauth/README.md b/third_party/heimdal/lib/gss_preauth/README.md new file mode 100644 index 0000000..2a3b142 --- /dev/null +++ b/third_party/heimdal/lib/gss_preauth/README.md @@ -0,0 +1,110 @@ +# GSS-API Pre-authentication in Heimdal + +GSS-API pre-authentication in Heimdal is based on +[draft-perez-krb-wg-gss-preauth](https://datatracker.ietf.org/doc/html/draft-perez-krb-wg-gss-preauth) +but with some simplifications to the protocol. + +The following text assumes the reader is familiar with the draft. + +## Client side + +Because libkrb5 cannot have a recursive dependency on libgssapi, it instead +exports the function `_krb5_init_creds_init_gss()` which allows libgssapi to +register a set of function pointers for: + + - Generating context tokens + - Finalizing a context (inquiring the initiator name and reply key) + - Releasing context and credential handles + +This is a private API. + +This architecture also means that the libkrb5 implementation could be used with +an alternative GSS-API implementation such as SSPI, without too much work. The +bulk of the pre-authentication logic remains in libkrb5, however, in +[`init_creds_pw.c`](../../krb5/init_creds_pw.c). + +libgssapi itself exports `krb5_gss_set_init_creds()`, which is the public +interface for GSS-API pre-authentication. + +`krb5_gss_set_init_creds()` enables GSS-API pre-authentication on an initial +credentials context, taking a GSS-API credential handle and mechanism. Both are +optional; defaults will be used if absent. These two parameters are exposed as +the `--gss-name` and `--gss-mech` options to `kinit` (see +[kinit(1)](../../../kuser/kinit.1) for further details). `kinit` supports +acquiring anonymous, keytab- and password-based GSS-API credentials using the +same arguments as regular Kerberos. + +The selected GSS-API mechanism must support mutual authentication (ie. +authenticating the KDC) as it replaces the AS-REP reply key, However, if FAST +was used, and we know that the KDC was verified, then this requirement is +removed. + +If the client does not know its initiator name, it can specify the last +arugment to `kinit` as `@REALM`, and the initiator name will be filled in when +the authentication is complete. (The realm is required to select a KDC.) + +## KDC side + +The KDC implements the acceptor side of the GSS-API authentication exchange. +The selected GSS-API mechanism must allow `gss_export_sec_context()` to be +called by the acceptor before the context is established, if it needs more than +a single round trip of token exchanges. + +### Configuration + +Configuration directives live in the [kdc] section of +[krb5.conf(5)](../../krb5/krb5.conf.5). + +The `enable_gss_preauth` krb5.conf option must be set in order to enable +GSS-API pre-authentication in the KDC. When authenticating federated principals +which may not exist in the KDC, the `synthetic_clients` option should also be +set. + +The `gss_mechanisms_allowed` option can be used to limit the set of GSS-API +mechanisms which are allowed to perform pre-authentication. Mechanisms are +specified as dot-separated OIDs or by a short name, such as `sanon-x25519`. + +The `enable_gss_auth_data` option will include a composite GSS name in the +authorization data of returned tickets. + +### Authorization + +The default is that the initiator is permitted to authenticate to the Kerberos +principal that directly corresponds to it. The correspondence is governed as +follows: if the authenticating mechanism is in the list of mechanisms in the +`gss_cross_realm_mechanisms_allowed` configuration option, then the principal +is mapped identically: an initiator named `lukeh@AAA.PADL.COM` will be mapped +to the Kerberos principal `lukeh@AAA.PADL.COM`. + +If the authenticating mechanism is not in this list, then the initiator will be +mapped to an enterprise principal in the service realm. For example, +`lukeh@AAA.PADL.COM` might be mapped to `lukeh\@AAA.PADL.COM@PADL.COM` +(enterprise principal name type); + +This mapping has no effect for principals that exist in the HDB, because +enterprise principal names are always looked up by their first component (as if +they were an ordinary principal name). This logic is instead useful when +synthetic principals are enabled as we wish to avoid issuing tickets with a +client name in a foreign Kerberos realm, as that would conflate GSS-API +"realms" with Kerberos realms. + +A custom authorization plugin installed in `$prefix/lib/plugin/kdc` will +replace this mapping and authorization logic. The plugin interface is defined in +[`gss_preauth_authorizer_plugin.h`](../../../kdc/gss_preauth_authorizer_plugin.h)). + +### Anonymous authentication + +A further note on the interaction of anonymous GSS-API authentication and +pre-authentication. Initiator contexts that set `GSS_C_ANON_FLAG` and a +`GSS_C_NT_ANONYMOUS` name are mapped to the unauthenticated anonymous Kerberos +principal, `WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS`. However, the local +`WELLKNOWN/ANONYMOUS` HDB entry is used to perform any authorization decisions +(as it would be for anonymous PKINIT). The AP-REP will contain the well-known +anonymous realm. + +If `GSS_C_NT_ANONYMOUS` was set but a different name type was returned, then +the initiator is treated as authenticated anonymous, and the client realm will +be present in the AP-REP. + +The `request-anonymous` AP-REQ flag must also be set for GSS-API anonymous +authentication to succeed. diff --git a/third_party/heimdal/lib/gss_preauth/pa_client.c b/third_party/heimdal/lib/gss_preauth/pa_client.c new file mode 100644 index 0000000..de2d7b5 --- /dev/null +++ b/third_party/heimdal/lib/gss_preauth/pa_client.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2021, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "gss-preauth-protos.h" +#include "gss-preauth-private.h" + +static krb5_error_code +pa_gss_acquire_initiator_cred(krb5_context context, + krb5_gss_init_ctx gssic, + const krb5_creds *kcred, + gss_cred_id_t *cred) +{ + krb5_error_code ret; + + OM_uint32 major, minor; + gss_const_OID mech; + gss_OID_set_desc mechs; + gss_name_t initiator_name = GSS_C_NO_NAME; + OM_uint32 time_req; + krb5_timestamp now; + + *cred = GSS_C_NO_CREDENTIAL; + + mech = _krb5_init_creds_get_gss_mechanism(context, gssic); + + mechs.count = 1; + mechs.elements = (gss_OID)mech; + + ret = _krb5_gss_pa_unparse_name(context, kcred->client, &initiator_name); + if (ret) + return ret; + + krb5_timeofday(context, &now); + if (kcred->times.endtime && kcred->times.endtime > now) + time_req = kcred->times.endtime - now; + else + time_req = GSS_C_INDEFINITE; + + major = gss_acquire_cred(&minor, initiator_name, time_req, &mechs, + GSS_C_INITIATE, cred, NULL, NULL); + ret = _krb5_gss_map_error(major, minor); + + gss_release_name(&major, &initiator_name); + + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +pa_gss_step(krb5_context context, + krb5_gss_init_ctx gssic, + const krb5_creds *kcred, + gss_ctx_id_t *ctx, + KDCOptions flags, + krb5_data *enc_as_req, + krb5_data *in, + krb5_data *out) +{ + krb5_error_code ret; + krb5_principal tgs_name = NULL; + + OM_uint32 major, minor; + gss_cred_id_t cred; + gss_name_t target_name = GSS_C_NO_NAME; + OM_uint32 req_flags = GSS_C_MUTUAL_FLAG; + OM_uint32 ret_flags; + struct gss_channel_bindings_struct cb; + gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; + + memset(&cb, 0, sizeof(cb)); + krb5_data_zero(out); + + if (flags.request_anonymous) + req_flags |= GSS_C_ANON_FLAG; + + cred = (gss_cred_id_t)_krb5_init_creds_get_gss_cred(context, gssic); + + if (cred == GSS_C_NO_CREDENTIAL) { + ret = pa_gss_acquire_initiator_cred(context, gssic, kcred, &cred); + if (ret) + goto out; + + _krb5_init_creds_set_gss_cred(context, gssic, cred); + } + + ret = krb5_make_principal(context, &tgs_name, kcred->server->realm, + KRB5_TGS_NAME, kcred->server->realm, NULL); + if (ret) + goto out; + + ret = _krb5_gss_pa_unparse_name(context, tgs_name, &target_name); + if (ret) + goto out; + + _krb5_gss_data_to_buffer(enc_as_req, &cb.application_data); + _krb5_gss_data_to_buffer(in, &input_token); + + major = gss_init_sec_context(&minor, + cred, + ctx, + target_name, + (gss_OID)_krb5_init_creds_get_gss_mechanism(context, gssic), + req_flags, + GSS_C_INDEFINITE, + &cb, + &input_token, + NULL, + &output_token, + &ret_flags, + NULL); + + _krb5_gss_buffer_to_data(&output_token, out); + + if (major == GSS_S_COMPLETE) { + if ((ret_flags & GSS_C_MUTUAL_FLAG) == 0) + ret = KRB5_MUTUAL_FAILED; + else if ((ret_flags & req_flags) != req_flags) + ret = KRB5KDC_ERR_BADOPTION; + else + ret = 0; + } else + ret = _krb5_gss_map_error(major, minor); + +out: + gss_release_name(&minor, &target_name); + krb5_free_principal(context, tgs_name); + + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +pa_gss_finish(krb5_context context, + krb5_gss_init_ctx gssic, + const krb5_creds *kcred, + gss_ctx_id_t ctx, + krb5int32 nonce, + krb5_enctype enctype, + krb5_principal *client_p, + krb5_keyblock **reply_key_p) +{ + krb5_error_code ret; + krb5_principal client = NULL; + krb5_keyblock *reply_key = NULL; + + OM_uint32 major, minor; + gss_name_t initiator_name = GSS_C_NO_NAME; + + *client_p = NULL; + *reply_key_p = NULL; + + major = gss_inquire_context(&minor, + ctx, + &initiator_name, + NULL, /* target_name */ + NULL, /* lifetime_req */ + NULL, /* mech_type */ + NULL, /* ctx_flags */ + NULL, /* locally_initiated */ + NULL); /* open */ + + if (GSS_ERROR(major)) + return _krb5_gss_map_error(major, minor); + + ret = _krb5_gss_pa_parse_name(context, initiator_name, 0, &client); + if (ret) + goto out; + + ret = _krb5_gss_pa_derive_key(context, ctx, nonce, enctype, &reply_key); + if (ret) + goto out; + + *client_p = client; + client = NULL; + + *reply_key_p = reply_key; + reply_key = NULL; + +out: + krb5_free_principal(context, client); + if (reply_key) + krb5_free_keyblock(context, reply_key); + gss_release_name(&minor, &initiator_name); + + return ret; +} + +static void KRB5_LIB_CALL +pa_gss_delete_sec_context(krb5_context context, + krb5_gss_init_ctx gssic, + gss_ctx_id_t ctx) +{ + OM_uint32 minor; + + gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER); +} + +static void KRB5_LIB_CALL +pa_gss_release_cred(krb5_context context, + krb5_gss_init_ctx gssic, + gss_cred_id_t cred) +{ + OM_uint32 minor; + + gss_release_cred(&minor, &cred); +} + +krb5_error_code +krb5_gss_set_init_creds(krb5_context context, + krb5_init_creds_context ctx, + gss_const_cred_id_t gss_cred, + gss_const_OID gss_mech) +{ + return _krb5_init_creds_init_gss(context,ctx, + pa_gss_step, + pa_gss_finish, + pa_gss_release_cred, + pa_gss_delete_sec_context, + gss_cred, + gss_mech, + 0); +} diff --git a/third_party/heimdal/lib/gss_preauth/pa_common.c b/third_party/heimdal/lib/gss_preauth/pa_common.c new file mode 100644 index 0000000..00efde7 --- /dev/null +++ b/third_party/heimdal/lib/gss_preauth/pa_common.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "gss-preauth-protos.h" +#include "gss-preauth-private.h" + +krb5_error_code +_krb5_gss_map_error(OM_uint32 major, OM_uint32 minor) +{ + krb5_error_code ret; + + if (minor != 0) + return (krb5_error_code)minor; + + switch (major) { + case GSS_S_COMPLETE: + ret = 0; + break; + case GSS_S_CONTINUE_NEEDED: + ret = HEIM_ERR_PA_CONTINUE_NEEDED; + break; + case GSS_S_BAD_NAME: + case GSS_S_BAD_NAMETYPE: + ret = KRB5_PRINC_NOMATCH; + break; + case GSS_S_NO_CRED: + ret = KRB5_CC_NOTFOUND; + break; + case GSS_S_BAD_MIC: + case GSS_S_DEFECTIVE_CREDENTIAL: + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + break; + case GSS_S_FAILURE: + default: + ret = KRB5KDC_ERR_PREAUTH_FAILED; + break; + } + + return ret; +} + +krb5_error_code +_krb5_gss_pa_derive_key(krb5_context context, + gss_ctx_id_t ctx, + krb5int32 nonce, + krb5_enctype enctype, + krb5_keyblock **keyblock) +{ + krb5_error_code ret; + u_char saltdata[12] = "KRB-GSS"; + krb5_keyblock kdkey; + size_t keysize; + + OM_uint32 major, minor; + gss_buffer_desc salt, dkey = GSS_C_EMPTY_BUFFER; + + *keyblock = NULL; + + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret) + return ret; + + saltdata[ 8] = (nonce >> 0 ) & 0xFF; + saltdata[ 9] = (nonce >> 8 ) & 0xFF; + saltdata[10] = (nonce >> 16) & 0xFF; + saltdata[11] = (nonce >> 24) & 0xFF; + + salt.value = saltdata; + salt.length = sizeof(saltdata); + + major = gss_pseudo_random(&minor, ctx, GSS_C_PRF_KEY_FULL, + &salt, keysize, &dkey); + if (GSS_ERROR(major)) + return KRB5_PREAUTH_NO_KEY; + + kdkey.keytype = enctype; + kdkey.keyvalue.data = dkey.value; + kdkey.keyvalue.length = dkey.length; + + ret = krb5_copy_keyblock(context, &kdkey, keyblock); + + if (dkey.value) { + memset_s(dkey.value, dkey.length, 0, dkey.length); + gss_release_buffer(&minor, &dkey); + } + + return ret; +} + +krb5_error_code +_krb5_gss_pa_unparse_name(krb5_context context, + krb5_const_principal principal, + gss_name_t *namep) +{ + krb5_error_code ret; + char *name = NULL; + + OM_uint32 major, minor; + gss_buffer_desc name_buf; + + *namep = GSS_C_NO_NAME; + + if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + if (principal->name.name_string.len != 1) + return EINVAL; + + name = principal->name.name_string.val[0]; + } else { + ret = krb5_unparse_name(context, principal, &name); + if (ret) + return ret; + } + + name_buf.length = strlen(name); + name_buf.value = name; + + major = gss_import_name(&minor, &name_buf, + GSS_KRB5_NT_PRINCIPAL_NAME, namep); + if (major == GSS_S_BAD_NAMETYPE) { + gss_OID name_type = GSS_C_NO_OID; + int flags = 0; + + if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + name_type = GSS_C_NT_USER_NAME; + } else if (principal->name.name_type == KRB5_NT_PRINCIPAL) { + flags = KRB5_PRINCIPAL_UNPARSE_SHORT; + name_type = GSS_C_NT_USER_NAME; + } else if ((principal->name.name_type == KRB5_NT_SRV_HST || + principal->name.name_type == KRB5_NT_SRV_INST) && + principal->name.name_string.len == 2) { + flags = KRB5_PRINCIPAL_UNPARSE_NO_REALM; + name_type = GSS_C_NT_HOSTBASED_SERVICE; + } + + if (flags) { + krb5_xfree(name); + + ret = krb5_unparse_name_flags(context, principal, flags, &name); + if (ret) + return ret; + + if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) { + char *inst = strchr(name, '/'); + if (inst) + *inst = '@'; + } + + name_buf.length = strlen(name); + name_buf.value = name; + } + + if (name_type) + major = gss_import_name(&minor, &name_buf, name_type, namep); + } + + if (name != principal->name.name_string.val[0]) + krb5_xfree(name); + + return _krb5_gss_map_error(major, minor); +} + +krb5_error_code +_krb5_gss_pa_parse_name(krb5_context context, + gss_const_name_t name, + int flags, + krb5_principal *principal) +{ + krb5_error_code ret; + char *displayed_name0; + + OM_uint32 major, minor; + gss_OID name_type = GSS_C_NO_OID; + gss_buffer_desc displayed_name = GSS_C_EMPTY_BUFFER; + + major = gss_display_name(&minor, name, &displayed_name, &name_type); + if (GSS_ERROR(major)) + return _krb5_gss_map_error(major, minor); + + if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) { + ret = krb5_make_principal(context, principal, KRB5_ANON_REALM, + KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); + if (ret == 0) + (*principal)->name.name_type = KRB5_NT_WELLKNOWN; + } else { + displayed_name0 = malloc(displayed_name.length + 1); + if (displayed_name0 == NULL) + return krb5_enomem(context); + + memcpy(displayed_name0, displayed_name.value, displayed_name.length); + displayed_name0[displayed_name.length] = '\0'; + + ret = krb5_parse_name_flags(context, displayed_name0, flags, principal); + gss_release_buffer(&minor, &displayed_name); + free(displayed_name0); + } + + gss_release_buffer(&minor, &displayed_name); + + return ret; +} + +void +_krb5_gss_data_to_buffer(const krb5_data *data, gss_buffer_t buffer) +{ + if (data) { + buffer->length = data->length; + buffer->value = data->data; + } else { + _mg_buffer_zero(buffer); + } +} + +void +_krb5_gss_buffer_to_data(gss_const_buffer_t buffer, krb5_data *data) +{ + if (buffer) { + data->length = buffer->length; + data->data = buffer->value; + } else { + krb5_data_zero(data); + } +} diff --git a/third_party/heimdal/lib/gssapi/ChangeLog b/third_party/heimdal/lib/gssapi/ChangeLog new file mode 100644 index 0000000..5c25d69 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ChangeLog @@ -0,0 +1,2970 @@ +2008-08-14 Love Hornquist Astrand + + * krb5/accept_sec_context.c: If there is a initiator subkey, copy + that to acceptor subkey to match windows behavior. From Metze. + +2008-08-02 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: Catch error + + * krb5/inquire_sec_context_by_oid.c: Catch store failure. + + * mech/gss_canonicalize_name.c: Not init m, return never + used (overwritten later). + +2008-07-25 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: Use krb5_cc_get_config. + +2008-07-25 Love Hörnquist Åstrand + + * krb5/init_sec_context.c: Match the orignal patch I got from + metze, seems that DCE-STYLE is even more weirer then what I though + when I merged the patch. + +2008-06-02 Love Hörnquist Åstrand + + * krb5/init_sec_context.c: Don't add asn1 wrapping to token when + using DCE_STYLE. Patch from Stefan Metzmacher. + +2008-05-27 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: use krb5_get_error_message + +2008-05-05 Love Hörnquist Åstrand + + * spnego/spnego_locl.h: Add back "mech/utils.h", its needed for + oid/buffer functions. + +2008-05-02 Love Hörnquist Åstrand + + * spnego: Changes from doug barton to make spnego indepedant of + the heimdal version of the plugin system. + +2008-04-27 Love Hörnquist Åstrand + + * krb5: use DES_set_key_unchecked() + +2008-04-17 Love Hörnquist Åstrand + + * add __declspec() for windows. + +2008-04-15 Love Hörnquist Åstrand + + * krb5/import_sec_context.c: Use tmp to read ac->flags value to + avoid warning. + +2008-04-07 Love Hörnquist Åstrand + + * mech/gss_mech_switch.c: Use unsigned where appropriate. + +2008-03-14 Love Hörnquist Åstrand + + * test_context.c: Add test for gsskrb5_register_acceptor_identity. + +2008-03-09 Love Hörnquist Åstrand + + * krb5/init_sec_context.c (init_auth): use right variable to + detect if we want to free or not. + +2008-02-26 Love Hörnquist Åstrand + + * Makefile.am: add missing \ + + * Makefile.am: reshuffle depenencies + + * Add flag to krb5 to not add GSS-API INT|CONF to the negotiation + +2008-02-21 Love Hörnquist Åstrand + + * make the SPNEGO mech store the error itself instead, works for + everything except other stackable mechs + +2008-02-18 Love Hörnquist Åstrand + + * spnego/init_sec_context.c (spnego_reply): if the reply token was + of length 0, make it the same as no token. Pointed out by Zeqing + Xia. + + * krb5/acquire_cred.c (acquire_initiator_cred): handle the + credential cache better, use destroy/close when appriate and for + all cases. Thanks to Michael Allen for point out the memory-leak + that I also fixed. + +2008-02-03 Love Hörnquist Åstrand + + * spnego/accept_sec_context.c: Make error reporting somewhat more + correct for SPNEGO. + +2008-01-27 Love Hörnquist Åstrand + + * test_common.c: Improve the error message. + +2008-01-24 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: Avoid free-ing type1 message before + its allocated. + +2008-01-13 Love Hörnquist Åstrand + + * test_ntlm.c: Test source name (and make the acceptor in ntlm gss + mech useful). + +2007-12-30 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: Don't confuse target name and source + name, make regressiont tests pass again. + +2007-12-29 Love Hörnquist Åstrand + + * ntlm: clean up name handling + +2007-12-04 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: Use credential if it was passed in. + + * ntlm/acquire_cred.c: Check if there is initial creds with + _gss_ntlm_get_user_cred(). + + * ntlm/init_sec_context.c: Add _gss_ntlm_get_user_info() that + return the user info so it can be used by external modules. + + * ntlm/inquire_cred.c: use the right error code. + + * ntlm/inquire_cred.c: Return GSS_C_NO_CREDENTIAL if there is no + credential, ntlm have (not yet) a default credential. + + * mech/gss_release_oid_set.c: Avoid trying to deref NULL, from + Phil Fisher. + +2007-12-03 Love Hörnquist Åstrand + + * test_acquire_cred.c: Always try to fetch cred (even with + GSS_C_NO_NAME). + +2007-08-09 Love Hörnquist Åstrand + + * mech/gss_krb5.c: Readd gss_krb5_get_tkt_flags. + +2007-08-08 Love Hörnquist Åstrand + + * spnego/compat.c (_gss_spnego_internal_delete_sec_context): + release ctx->target_name too From Rafal Malinowski. + +2007-07-26 Love Hörnquist Åstrand + + * mech/gss_mech_switch.c: Don't try to do dlopen if system doesn't + have dlopen. From Rune of Chalmers. + +2007-07-10 Love Hörnquist Åstrand + + * mech/gss_duplicate_name.c: New signature of _gss_find_mn. + + * mech/gss_init_sec_context.c: New signature of _gss_find_mn. + + * mech/gss_acquire_cred.c: New signature of _gss_find_mn. + + * mech/name.h: New signature of _gss_find_mn. + + * mech/gss_canonicalize_name.c: New signature of _gss_find_mn. + + * mech/gss_compare_name.c: New signature of _gss_find_mn. + + * mech/gss_add_cred.c: New signature of _gss_find_mn. + + * mech/gss_names.c (_gss_find_mn): Return an error code for + caller. + + * spnego/accept_sec_context.c: remove checks that are done by the + previous function. + + * Makefile.am: New library version. + +2007-07-04 Love Hörnquist Åstrand + + * mech/gss_oid_to_str.c: Refuse to print GSS_C_NULL_OID, from + Rafal Malinowski. + + * spnego/spnego.asn1: Indent and make NegTokenInit and + NegTokenResp extendable. + +2007-06-21 Love Hörnquist Åstrand + + * ntlm/inquire_cred.c: Implement _gss_ntlm_inquire_cred. + + * mech/gss_display_status.c: Provide message for GSS_S_COMPLETE. + + * mech/context.c: If the canned string is "", its no use to the + user, make it fall back to the default error string. + +2007-06-20 Love Hörnquist Åstrand + + * mech/gss_display_name.c (gss_display_name): no name -> + fail. From Rafal Malinswski. + + * spnego/accept_sec_context.c: Wrap name in a spnego_name instead + of just a copy of the underlaying object. From Rafal Malinswski. + + * spnego/accept_sec_context.c: Handle underlaying mech not + returning mn. + + * mech/gss_accept_sec_context.c: Handle underlaying mech not + returning mn. + + * spnego/accept_sec_context.c: Make sure src_name is always set to + GSS_C_NO_NAME when returning. + + * krb5/acquire_cred.c (acquire_acceptor_cred): don't claim + everything is well on failure. From Phil Fisher. + + * mech/gss_duplicate_name.c: catch error (and ignore it) + + * ntlm/init_sec_context.c: Use heim_ntlm_calculate_ntlm2_sess. + + * mech/gss_accept_sec_context.c: Only wrap the delegated cred if + we got a delegated mech cred. From Rafal Malinowski. + + * spnego/accept_sec_context.c: Only wrap the delegated cred if we + are going to return it to the consumer. From Rafal Malinowski. + + * spnego/accept_sec_context.c: Fixed memory leak pointed out by + Rafal Malinowski, also while here moved to use NegotiationToken + for decoding. + +2007-06-18 Love Hörnquist Åstrand + + * krb5/prf.c (_gsskrb5_pseudo_random): add missing break. + + * krb5/release_name.c: Set *minor_status unconditionallty, its + done later anyway. + + * spnego/accept_sec_context.c: Init get_mic to 0. + + * mech/gss_set_cred_option.c: Free memory in failure case, found + by beam. + + * mech/gss_inquire_context.c: Handle mech_type being NULL. + + * mech/gss_inquire_cred_by_mech.c: Handle cred_name being NULL. + + * mech/gss_krb5.c: Free memory in error case, found by beam. + +2007-06-12 Love Hörnquist Åstrand + + * ntlm/inquire_context.c: Use ctx->gssflags for flags. + + * krb5/display_name.c: Use KRB5_PRINCIPAL_UNPARSE_DISPLAY, this is + not ment for machine consumption. + +2007-06-09 Love Hörnquist Åstrand + + * ntlm/digest.c (kdc_alloc): free memory on failure, pointed out + by Rafal Malinowski. + + * ntlm/digest.c (kdc_destroy): free context when done, pointed out + by Rafal Malinowski. + + * spnego/context_stubs.c (_gss_spnego_display_name): if input_name + is null, fail. From Rafal Malinowski. + +2007-06-04 Love Hörnquist Åstrand + + * ntlm/digest.c: Free memory when done. + +2007-06-02 Love Hörnquist Åstrand + + * test_ntlm.c: Test both with and without keyex. + + * ntlm/digest.c: If we didn't set session key, don't expect one + back. + + * test_ntlm.c: Set keyex flag and calculate session key. + +2007-05-31 Love Hörnquist Åstrand + + * spnego/accept_sec_context.c: Use the return value before is + overwritten by later calls. From Rafal Malinowski + + * krb5/release_cred.c: Give an minor_status argument to + gss_release_oid_set. From Rafal Malinowski + +2007-05-30 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: Catch errors and return the up the + stack. + + * test_kcred.c: more testing of lifetimes + +2007-05-17 Love Hörnquist Åstrand + + * Makefile.am: Drop the gss oid_set function for the krb5 mech, + use the mech glue versions instead. Pointed out by Rafal + Malinowski. + + * krb5: Use gss oid_set functions from mechglue + +2007-05-14 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: Set session key only if we are + returned a session key. Found by David Love. + +2007-05-13 Love Hörnquist Åstrand + + * krb5/prf.c: switched MIN to min to make compile on solaris, + pointed out by David Love. + +2007-05-09 Love Hörnquist Åstrand + + * krb5/inquire_cred_by_mech.c: Fill in all of the variables if + they are passed in. Pointed out by Phil Fisher. + +2007-05-08 Love Hörnquist Åstrand + + * krb5/inquire_cred.c: Fix copy and paste error, bug spotted by + from Phil Fisher. + + * mech: dont keep track of gc_usage, just figure it out at + gss_inquire_cred() time + + * mech/gss_mech_switch.c (add_builtin): ok for + __gss_mech_initialize() to return NULL + + * test_kcred.c: more correct tests + + * spnego/cred_stubs.c (gss_inquire_cred*): wrap the name with a + spnego_name. + + * ntlm/inquire_cred.c: make ntlm gss_inquire_cred fail for now, + need to find default cred and friends. + + * krb5/inquire_cred_by_mech.c: reimplement + +2007-05-07 Love Hörnquist Åstrand + + * ntlm/acquire_cred.c: drop unused variable. + + * ntlm/acquire_cred.c: Reimplement. + + * Makefile.am: add ntlm/digest.c + + * ntlm: split out backend ntlm server processing + +2007-04-24 Love Hörnquist Åstrand + + * ntlm/delete_sec_context.c (_gss_ntlm_delete_sec_context): free + credcache when done + +2007-04-22 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: ntlm-key credential entry is prefix with @ + + * ntlm/init_sec_context.c (get_user_ccache): pick up the ntlm + creds from the krb5 credential cache. + +2007-04-21 Love Hörnquist Åstrand + + * ntlm/delete_sec_context.c: free the key stored in the context + + * ntlm/ntlm.h: switch password for a key + + * test_oid.c: Switch oid to one that is exported. + +2007-04-20 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: move where hash is calculated to make + it easier to add ccache support. + + * Makefile.am: Add version-script.map to EXTRA_DIST. + +2007-04-19 Love Hörnquist Åstrand + + * Makefile.am: Unconfuse newer versions of automake that doesn't + know the diffrence between depenences and setting variables. foo: + vs foo=. + + * test_ntlm.c: delete sec context when done. + + * version-script.map: export more symbols. + + * Makefile.am: add version script if ld supports it + + * version-script.map: add version script if ld supports it + +2007-04-18 Love Hörnquist Åstrand + + * Makefile.am: test_acquire_cred need test_common.[ch] + + * test_acquire_cred.c: add more test options. + + * krb5/external.c: add GSS_KRB5_CCACHE_NAME_X + + * gssapi/gssapi_krb5.h: add GSS_KRB5_CCACHE_NAME_X + + * krb5/set_sec_context_option.c: refactor code, implement + GSS_KRB5_CCACHE_NAME_X + + * mech/gss_krb5.c: reimplement gss_krb5_ccache_name + +2007-04-17 Love Hörnquist Åstrand + + * spnego/cred_stubs.c: Need to import spnego name before we can + use it as a gss_name_t. + + * test_acquire_cred.c: use this test as part of the regression + suite. + + * mech/gss_acquire_cred.c (gss_acquire_cred): dont init + cred->gc_mc every time in the loop. + +2007-04-15 Love Hörnquist Åstrand + + * Makefile.am: add test_common.h + +2007-02-16 Love Hörnquist Åstrand + + * gss_acquire_cred.3: Add link for + gsskrb5_register_acceptor_identity. + +2007-02-08 Love Hörnquist Åstrand + + * krb5/copy_ccache.c: Try to leak less memory in the failure case. + +2007-01-31 Love Hörnquist Åstrand + + * mech/gss_display_status.c: Use right printf formater. + + * test_*.[ch]: split out the error printing function and try to + return better errors + +2007-01-30 Love Hörnquist Åstrand + + * krb5/init_sec_context.c: revert 1.75: (init_auth): only turn on + GSS_C_CONF_FLAG and GSS_C_INT_FLAG if the caller requseted it. + + This is because Kerberos always support INT|CONF, matches behavior + with MS and MIT. The creates problems for the GSS-SPNEGO mech. + +2007-01-24 Love Hörnquist Åstrand + + * krb5/prf.c: constrain desired_output_len + + * krb5/external.c (krb5_mech): add _gsskrb5_pseudo_random + + * mech/gss_pseudo_random.c: Catch error from underlaying mech on + failure. + + * Makefile.am: Add krb5/prf.c + + * krb5/prf.c: gss_pseudo_random for krb5 + + * test_context.c: Checks for gss_pseudo_random. + + * krb5/gkrb5_err.et: add KG_INPUT_TOO_LONG + + * Makefile.am: Add mech/gss_pseudo_random.c + + * gssapi/gssapi.h: try to load pseudo_random + + * mech/gss_mech_switch.c: try to load pseudo_random + + * mech/gss_pseudo_random.c: Add gss_pseudo_random. + + * gssapi_mech.h: Add hook for gm_pseudo_random. + +2007-01-17 Love Hörnquist Åstrand + + * test_context.c: Don't assume bufer from gss_display_status is + ok. + + * mech/gss_wrap_size_limit.c: Reset out variables. + + * mech/gss_wrap.c: Reset out variables. + + * mech/gss_verify_mic.c: Reset out variables. + + * mech/gss_utils.c: Reset out variables. + + * mech/gss_release_oid_set.c: Reset out variables. + + * mech/gss_release_cred.c: Reset out variables. + + * mech/gss_release_buffer.c: Reset variables. + + * mech/gss_oid_to_str.c: Reset out variables. + + * mech/gss_inquire_sec_context_by_oid.c: Fix reset out variables. + + * mech/gss_mech_switch.c: Reset out variables. + + * mech/gss_inquire_sec_context_by_oid.c: Reset out variables. + + * mech/gss_inquire_names_for_mech.c: Reset out variables. + + * mech/gss_inquire_cred_by_oid.c: Reset out variables. + + * mech/gss_inquire_cred_by_oid.c: Reset out variables. + + * mech/gss_inquire_cred_by_mech.c: Reset out variables. + + * mech/gss_inquire_cred.c: Reset out variables, fix memory leak. + + * mech/gss_inquire_context.c: Reset out variables. + + * mech/gss_init_sec_context.c: Zero out outbuffer on failure. + + * mech/gss_import_name.c: Reset out variables. + + * mech/gss_import_name.c: Reset out variables. + + * mech/gss_get_mic.c: Reset out variables. + + * mech/gss_export_name.c: Reset out variables. + + * mech/gss_encapsulate_token.c: Reset out variables. + + * mech/gss_duplicate_oid.c: Reset out variables. + + * mech/gss_duplicate_oid.c: Reset out variables. + + * mech/gss_duplicate_name.c: Reset out variables. + + * mech/gss_display_status.c: Reset out variables. + + * mech/gss_display_name.c: Reset out variables. + + * mech/gss_delete_sec_context.c: Reset out variables using propper + macros. + + * mech/gss_decapsulate_token.c: Reset out variables using propper + macros. + + * mech/gss_add_cred.c: Reset out variables. + + * mech/gss_acquire_cred.c: Reset out variables. + + * mech/gss_accept_sec_context.c: Reset out variables using propper + macros. + + * mech/gss_init_sec_context.c: Reset out variables. + + * mech/mech_locl.h (_mg_buffer_zero): new macro that zaps a + gss_buffer_t + +2007-01-16 Love Hörnquist Åstrand + + * mech: sprinkel _gss_mg_error + + * mech/gss_display_status.c (gss_display_status): use + _gss_mg_get_error to fetch the error from underlaying mech, if it + failes, let do the regular dance for GSS-CODE version and a + generic print-the-error code for MECH-CODE. + + * mech/gss_oid_to_str.c: Don't include the NUL in the length of + the string. + + * mech/context.h: Protoypes for _gss_mg_. + + * mech/context.c: Glue to catch the error from the lower gss-api + layer and save that for later so gss_display_status() can show the + error. + + * gss.c: Detect NTLM. + +2007-01-11 Love Hörnquist Åstrand + + * mech/gss_accept_sec_context.c: spelling + +2007-01-04 Love Hörnquist Åstrand + + * Makefile.am: Include build (private) prototypes header files. + + * Makefile.am (ntlmsrc): add ntlm/ntlm-private.h + +2006-12-28 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: Pass signseal argument to + _gss_ntlm_set_key. + + * ntlm/init_sec_context.c: Pass signseal argument to + _gss_ntlm_set_key. + + * ntlm/crypto.c (_gss_ntlm_set_key): add signseal argument + + * test_ntlm.c: add ntlmv2 test + + * ntlm/ntlm.h: break out struct ntlmv2_key; + + * ntlm/crypto.c (_gss_ntlm_set_key): set ntlm v2 keys. + + * ntlm/accept_sec_context.c: Set dummy ntlmv2 keys and Check TI. + + * ntlm/ntlm.h: NTLMv2 keys. + + * ntlm/crypto.c: NTLMv2 sign and verify. + +2006-12-20 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: Don't send targetinfo now. + + * ntlm/init_sec_context.c: Build ntlmv2 answer buffer. + + * ntlm/init_sec_context.c: Leak less memory. + + * ntlm/init_sec_context.c: Announce that we support key exchange. + + * ntlm/init_sec_context.c: Add NTLM_NEG_NTLM2_SESSION, NTLMv2 + session security (disable because missing sign and seal). + +2006-12-19 Love Hörnquist Åstrand + + * ntlm/accept_sec_context.c: split RC4 send and recv keystreams + + * ntlm/init_sec_context.c: split RC4 send and recv keystreams + + * ntlm/ntlm.h: split RC4 send and recv keystreams + + * ntlm/crypto.c: Implement SEAL. + + * ntlm/crypto.c: move gss_wrap/gss_unwrap here + + * test_context.c: request INT and CONF from the gss layer, test + get and verify MIC. + + * ntlm/ntlm.h: add crypto bits. + + * ntlm/accept_sec_context.c: Save session master key. + + * Makefile.am: Move get and verify mic to the same file (crypto.c) + since they share code. + + * ntlm/crypto.c: Move get and verify mic to the same file since + they share code, implement NTLM v1 and dummy signatures. + + * ntlm/init_sec_context.c: pass on GSS_C_CONF_FLAG and + GSS_C_INTEG_FLAG, save the session master key + + * spnego/accept_sec_context.c: try using gss_accept_sec_context() + on the opportunistic token instead of guessing the acceptor name + and do gss_acquire_cred, this make SPNEGO work like before. + +2006-12-18 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c: Calculate the NTLM version 1 "master" + key. + + * spnego/accept_sec_context.c: Resurect negHints for the acceptor + sends first packet. + + * Makefile.am: Add "windows" versions of the NegTokenInitWin and + friends. + + * test_context.c: add --wrapunwrap flag + + * spnego/compat.c: move _gss_spnego_indicate_mechtypelist() to + compat.c, use the sequence types of MechTypeList, make + add_mech_type() static. + + * spnego/accept_sec_context.c: move + _gss_spnego_indicate_mechtypelist() to compat.c + + * Makefile.am: Generate sequence code for MechTypeList + + * spnego: check that the generated acceptor mechlist is acceptable too + + * spnego/init_sec_context.c: Abstract out the initiator filter + function, it will be needed for the acceptor too. + + * spnego/accept_sec_context.c: Abstract out the initiator filter + function, it will be needed for the acceptor too. Remove negHints. + + * test_context.c: allow asserting return mech + + * ntlm/accept_sec_context.c: add _gss_ntlm_allocate_ctx + + * ntlm/acquire_cred.c: Check that the KDC seem to there and + answering us, we can't do better then that wen checking if we will + accept the credential. + + * ntlm/get_mic.c: return GSS_S_UNAVAILABLE + + * mech/utils.h: add _gss_free_oid, reverse of _gss_copy_oid + + * mech/gss_utils.c: add _gss_free_oid, reverse of _gss_copy_oid + + * spnego/spnego.asn1: Its very sad, but NegHints its are not part + of the NegTokenInit, this makes SPNEGO acceptor life a lot harder. + + * spnego: try harder to handle names better. handle missing + acceptor and initator creds better (ie dont propose/accept mech + that there are no credentials for) split NegTokenInit and + NegTokenResp in acceptor + +2006-12-16 Love Hörnquist Åstrand + + * ntlm/import_name.c: Allocate the buffer from the right length. + +2006-12-15 Love Hörnquist Åstrand + + * ntlm/init_sec_context.c (init_sec_context): Tell the other side + what domain we think we are talking to. + + * ntlm/delete_sec_context.c: free username and password + + * ntlm/release_name.c (_gss_ntlm_release_name): free name. + + * ntlm/import_name.c (_gss_ntlm_import_name): add support for + GSS_C_NT_HOSTBASED_SERVICE names + + * ntlm/ntlm.h: Add ntlm_name. + + * test_context.c: allow testing of ntlm. + + * gssapi_mech.h: add __gss_ntlm_initialize + + * ntlm/accept_sec_context.c (handle_type3): verify that the kdc + approved of the ntlm exchange too + + * mech/gss_mech_switch.c: Add the builtin ntlm mech + + * test_ntlm.c: NTLM test app. + + * mech/gss_accept_sec_context.c: Add detection of NTLMSSP. + + * gssapi/gssapi.h: add ntlm mech oid + + * ntlm/external.c: Switch OID to the ms ntlmssp oid + + * Makefile.am: Add ntlm gss-api module. + + * ntlm/accept_sec_context.c: Catch more error errors. + + * ntlm/accept_sec_context.c: Check after a credential to use. + +2006-12-14 Love Hörnquist Åstrand + + * krb5/set_sec_context_option.c (GSS_KRB5_SET_DEFAULT_REALM_X): + don't fail on success. Bug report from Stefan Metzmacher. + +2006-12-13 Love Hörnquist Åstrand + + * krb5/init_sec_context.c (init_auth): only turn on + GSS_C_CONF_FLAG and GSS_C_INT_FLAG if the caller requseted it. + From Stefan Metzmacher. + +2006-12-11 Love Hörnquist Åstrand + + * Makefile.am (libgssapi_la_OBJECTS): depends on gssapi_asn1.h + spnego_asn1.h. + +2006-11-20 Love Hörnquist Åstrand + + * krb5/acquire_cred.c: Make krb5_get_init_creds_opt_free take a + context argument. + +2006-11-16 Love Hörnquist Åstrand + + * test_context.c: Test that token keys are the same, return + actual_mech. + +2006-11-15 Love Hörnquist Åstrand + + * spnego/spnego_locl.h: Make bitfields unsigned, add maybe_open. + + * spnego/accept_sec_context.c: Use ASN.1 encoder functions to + encode CHOICE structure now that we can handle it. + + * spnego/init_sec_context.c: Use ASN.1 encoder functions to encode + CHOICE structure now that we can handle it. + + * spnego/accept_sec_context.c (_gss_spnego_accept_sec_context): + send back ad accept_completed when the security context is ->open, + w/o this the client doesn't know that the server have completed + the transaction. + + * test_context.c: Add delegate flag and check that the delegated + cred works. + + * spnego/init_sec_context.c: Keep track of the opportunistic token + in the inital message, it might be a complete gss-api context, in + that case we'll get back accept_completed without any token. With + this change, krb5 w/o mutual authentication works. + + * spnego/accept_sec_context.c: Use ASN.1 encoder functions to + encode CHOICE structure now that we can handle it. + + * spnego/accept_sec_context.c: Filter out SPNEGO from the out + supported mechs list and make sure we don't select that for the + preferred mechamism. + +2006-11-14 Love Hörnquist Åstrand + + * mech/gss_init_sec_context.c (_gss_mech_cred_find): break out the + cred finding to its own function + + * krb5/wrap.c: Better error strings, from Andrew Bartlet. + +2006-11-13 Love Hörnquist Åstrand + + * test_context.c: Create our own krb5_context. + + * krb5: Switch from using a specific error message context in the + TLS to have a whole krb5_context in TLS. This have some + interestion side-effekts for the configruration setting options + since they operate on per-thread basis now. + + * mech/gss_set_cred_option.c: When calling ->gm_set_cred_option + and checking for success, use GSS_S_COMPLETE. From Andrew Bartlet. + +2006-11-12 Love Hörnquist Åstrand + + * Makefile.am: Help solaris make even more. + + * Makefile.am: Help solaris make. + +2006-11-09 Love Hörnquist Åstrand + + * Makefile.am: remove include $(srcdir)/Makefile-digest.am for now + + * mech/gss_accept_sec_context.c: Try better guessing what is mech + we are going to select by looking harder at the input_token, idea + from Luke Howard's mechglue branch. + + * Makefile.am: libgssapi_la_OBJECTS: add depency on gkrb5_err.h + + * gssapi/gssapi_krb5.h: add GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X + + * mech/gss_krb5.c: implement gss_krb5_set_allowable_enctypes + + * gssapi/gssapi.h: GSS_KRB5_S_ + + * krb5/gsskrb5_locl.h: Include . + + * gssapi/gssapi_krb5.h: Add gss_krb5_set_allowable_enctypes. + + * Makefile.am: Build and install gkrb5_err.h + + * krb5/gkrb5_err.et: Move the GSS_KRB5_S error here. + +2006-11-08 Love Hörnquist Åstrand + + * mech/gss_krb5.c: Add gsskrb5_set_default_realm. + + * krb5/set_sec_context_option.c: Support + GSS_KRB5_SET_DEFAULT_REALM_X. + + * gssapi/gssapi_krb5.h: add GSS_KRB5_SET_DEFAULT_REALM_X + + * krb5/external.c: add GSS_KRB5_SET_DEFAULT_REALM_X + +2006-11-07 Love Hörnquist Åstrand + + * test_context.c: rename krb5_[gs]et_time_wrap to + krb5_[gs]et_max_time_skew + + * krb5/copy_ccache.c: _gsskrb5_extract_authz_data_from_sec_context + no longer used, bye bye + + * mech/gss_krb5.c: No depenency of the krb5 gssapi mech. + + * mech/gss_krb5.c (gsskrb5_extract_authtime_from_sec_context): use + _gsskrb5_decode_om_uint32. From Andrew Bartlet. + + * mech/gss_krb5.c: Add dummy gss_krb5_set_allowable_enctypes for + now. + + * spnego/spnego_locl.h: Include for compatiblity. + + * krb5/arcfour.c: Use IS_DCE_STYLE flag. There is no padding in + DCE-STYLE, don't try to use to. From Andrew Bartlett. + + * test_context.c: test wrap/unwrap, add flag for dce-style and + mutual auth, also support multi-roundtrip sessions + + * krb5/gsskrb5_locl.h: Add IS_DCE_STYLE macro. + + * krb5/accept_sec_context.c (gsskrb5_acceptor_start): use + krb5_rd_req_ctx + + * mech/gss_krb5.c (gsskrb5_get_subkey): return the per message + token subkey + + * krb5/inquire_sec_context_by_oid.c: check if there is any key at + all + +2006-11-06 Love Hörnquist Åstrand + + * krb5/inquire_sec_context_by_oid.c: Set more error strings, use + right enum for acceptor subkey. From Andrew Bartlett. + +2006-11-04 Love Hörnquist Åstrand + + * test_context.c: Test gsskrb5_extract_service_keyblock, needed in + PAC valication. From Andrew Bartlett + + * mech/gss_krb5.c: Add gsskrb5_extract_authz_data_from_sec_context + and keyblock extraction functions. + + * gssapi/gssapi_krb5.h: Add extraction of keyblock function, from + Andrew Bartlett. + + * krb5/external.c: Add GSS_KRB5_GET_SERVICE_KEYBLOCK_X + +2006-11-03 Love Hörnquist Åstrand + + * test_context.c: Rename various routines and constants from + canonize to canonicalize. From Andrew Bartlett + + * mech/gss_krb5.c: Rename various routines and constants from + canonize to canonicalize. From Andrew Bartlett + + * krb5/set_sec_context_option.c: Rename various routines and + constants from canonize to canonicalize. From Andrew Bartlett + + * krb5/external.c: Rename various routines and constants from + canonize to canonicalize. From Andrew Bartlett + + * gssapi/gssapi_krb5.h: Rename various routines and constants from + canonize to canonicalize. From Andrew Bartlett + +2006-10-25 Love Hörnquist Åstrand + + * krb5/accept_sec_context.c (gsskrb5_accept_delegated_token): need + to free ccache + +2006-10-24 Love Hörnquist Åstrand + + * test_context.c (loop): free target_name + + * mech/gss_accept_sec_context.c: SLIST_INIT the ->gc_mc' + + * mech/gss_acquire_cred.c : SLIST_INIT the ->gc_mc' + + * krb5/init_sec_context.c: Avoid leaking memory. + + * mech/gss_buffer_set.c (gss_release_buffer_set): don't leak the + ->elements memory. + + * test_context.c: make compile + + * krb5/cfx.c (_gssapi_verify_mic_cfx): always free crypto context. + + * krb5/set_cred_option.c (import_cred): free sp + +2006-10-22 Love Hörnquist Åstrand + + * mech/gss_add_oid_set_member.c: Use old implementation of + gss_add_oid_set_member, it leaks less memory. + + * krb5/test_cfx.c: free krb5_crypto. + + * krb5/test_cfx.c: free krb5_context + + * mech/gss_release_name.c (gss_release_name): free input_name + it-self. + +2006-10-21 Love Hörnquist Åstrand + + * test_context.c: Call setprogname. + + * mech/gss_krb5.c: Add gsskrb5_extract_authtime_from_sec_context. + + * gssapi/gssapi_krb5.h: add + gsskrb5_extract_authtime_from_sec_context + +2006-10-20 Love Hörnquist Åstrand + + * krb5/inquire_sec_context_by_oid.c: Add get_authtime. + + * krb5/external.c: add GSS_KRB5_GET_AUTHTIME_X + + * gssapi/gssapi_krb5.h: add GSS_KRB5_GET_AUTHTIME_X + + * krb5/set_sec_context_option.c: Implement GSS_KRB5_SEND_TO_KDC_X. + + * mech/gss_krb5.c: Add gsskrb5_set_send_to_kdc + + * gssapi/gssapi_krb5.h: Add GSS_KRB5_SEND_TO_KDC_X and + gsskrb5_set_send_to_kdc + + * krb5/external.c: add GSS_KRB5_SEND_TO_KDC_X + + * Makefile.am: more files + +2006-10-19 Love Hörnquist Åstrand + + * Makefile.am: remove spnego/gssapi_spnego.h, its now in gssapi/ + + * test_context.c: Allow specifing mech. + + * krb5/external.c: add GSS_SASL_DIGEST_MD5_MECHANISM (for now) + + * gssapi/gssapi.h: Rename GSS_DIGEST_MECHANISM to + GSS_SASL_DIGEST_MD5_MECHANISM + +2006-10-18 Love Hörnquist Åstrand + + * mech/gssapi.asn1: Make it into a heim_any_set, its doesn't + except a tag. + + * mech/gssapi.asn1: GSSAPIContextToken is IMPLICIT SEQUENCE + + * gssapi/gssapi_krb5.h: add GSS_KRB5_GET_ACCEPTOR_SUBKEY_X + + * krb5/external.c: Add GSS_KRB5_GET_ACCEPTOR_SUBKEY_X. + + * gssapi/gssapi_krb5.h: add GSS_KRB5_GET_INITIATOR_SUBKEY_X and + GSS_KRB5_GET_SUBKEY_X + + * krb5/external.c: add GSS_KRB5_GET_INITIATOR_SUBKEY_X, + GSS_KRB5_GET_SUBKEY_X + +2006-10-17 Love Hörnquist Åstrand + + * test_context.c: Support switching on name type oid's + + * test_context.c: add test for dns canon flag + + * mech/gss_krb5.c: Add gsskrb5_set_dns_canonlize. + + * gssapi/gssapi_krb5.h: remove gss_krb5_compat_des3_mic + + * gssapi/gssapi_krb5.h: Add gsskrb5_set_dns_canonlize. + + * krb5/set_sec_context_option.c: implement + GSS_KRB5_SET_DNS_CANONIZE_X + + * gssapi/gssapi_krb5.h: add GSS_KRB5_SET_DNS_CANONIZE_X + + * krb5/external.c: add GSS_KRB5_SET_DNS_CANONIZE_X + + * mech/gss_krb5.c: add bits to make lucid context work + +2006-10-14 Love Hörnquist Åstrand + + * mech/gss_oid_to_str.c: Prefix der primitives with der_. + + * krb5/inquire_sec_context_by_oid.c: Prefix der primitives with + der_. + + * krb5/encapsulate.c: Prefix der primitives with der_. + + * mech/gss_oid_to_str.c: New der_print_heim_oid signature. + +2006-10-12 Love Hörnquist Åstrand + + * Makefile.am: add test_context + + * krb5/inquire_sec_context_by_oid.c: Make it work. + + * test_oid.c: Test lucid oid. + + * gssapi/gssapi.h: Add OM_uint64_t. + + * krb5/inquire_sec_context_by_oid.c: Add lucid interface. + + * krb5/external.c: Add lucid interface, renumber oids to my + delegated space. + + * mech/gss_krb5.c: Add lucid interface. + + * gssapi/gssapi_krb5.h: Add lucid interface. + + * spnego/spnego_locl.h: Maybe include . + +2006-10-09 Love Hörnquist Åstrand + + * mech/gss_mech_switch.c: define RTLD_LOCAL to 0 if not defined. + +2006-10-08 Love Hörnquist Åstrand + + * Makefile.am: install gssapi_krb5.H and gssapi_spnego.h + + * gssapi/gssapi_krb5.h: Move krb5 stuff to . + + * gssapi/gssapi.h: Move krb5 stuff to . + + * Makefile.am: Drop some -I no longer needed. + + * gssapi/gssapi_spnego.h: Move gssapi_spengo.h over here. + + * krb5: reference all include files using 'krb5/' + +2006-10-07 Love Hörnquist Åstrand + + * gssapi.h: Add file inclusion protection. + + * gssapi/gssapi.h: Correct header file inclusion protection. + + * gssapi/gssapi.h: Move the gssapi.h from lib/gssapi/ to + lib/gssapi/gssapi/ to please automake. + + * spnego/spnego_locl.h: Maybe include . + + * mech/mech_locl.h: Include . + + * Makefile.am: split build files into dist_ and noinst_ SOURCES + +2006-10-06 Love Hörnquist Åstrand + + * gss.c: #if 0 out unused code. + + * mech/gss_mech_switch.c: Cast argument to ctype(3) functions + to (unsigned char). + +2006-10-05 Love Hörnquist Åstrand + + * mech/name.h: remove + + * mech/mech_switch.h: remove + + * mech/cred.h: remove + +2006-10-02 Love Hörnquist Åstrand + + * krb5/arcfour.c: Thinker more with header lengths. + + * krb5/arcfour.c: Improve the calcucation of header + lengths. DCE-STYLE data is also padded so remove if (1 || ...) + code. + + * krb5/wrap.c (_gsskrb5_wrap_size_limit): use + _gssapi_wrap_size_arcfour for arcfour + + * krb5/arcfour.c: Move _gssapi_wrap_size_arcfour here. + + * Makefile.am: Split all mech to diffrent mechsrc variables. + + * spnego/context_stubs.c: Make internal function static (and + rename). + +2006-10-01 Love Hörnquist Åstrand + + * krb5/inquire_cred.c: Fix "if (x) lock(y)" bug. From Harald + Barth. + + * spnego/spnego_locl.h: Include for MAXHOSTNAMELEN. + +2006-09-25 Love Hörnquist Åstrand + + * krb5/arcfour.c: Add wrap support, interrop with itself but not + w2k3s-sp1 + + * krb5/gsskrb5_locl.h: move the arcfour specific stuff to the + arcfour header. + + * krb5/arcfour.c: Support DCE-style unwrap, tested with + w2k3server-sp1. + + * mech/gss_accept_sec_context.c (gss_accept_sec_context): if the + token doesn't start with [APPLICATION 0] SEQUENCE, lets assume its + a DCE-style kerberos 5 connection. XXX this needs to be made + better in cause we get another GSS-API protocol violating + protocol. It should be possible to detach the Kerberos DCE-style + since it starts with a AP-REQ PDU, but that have to wait for now. + +2006-09-22 Love Hörnquist Åstrand + + * gssapi.h: Add GSS_C flags from + draft-brezak-win2k-krb-rc4-hmac-04.txt. + + * krb5/delete_sec_context.c: Free service_keyblock and fwd_data, + indent. + + * krb5/accept_sec_context.c: Merge of the acceptor part from the + samba patch by Stefan Metzmacher and Andrew Bartlet. + + * krb5/init_sec_context.c: Add GSS_C_DCE_STYLE. + + * krb5/{init_sec_context.c,gsskrb5_locl.h}: merge most of the + initiator part from the samba patch by Stefan Metzmacher and + Andrew Bartlet (still missing DCE/RPC support) + +2006-08-28 Love Hörnquist Åstrand + + * gss.c (help): use sl_slc_help(). + +2006-07-22 Love Hörnquist Åstrand + + * gss-commands.in: rename command to supported-mechanisms + + * Makefile.am: Make gss objects depend on the slc built + gss-commands.h + +2006-07-20 Love Hörnquist Åstrand + + * gss-commands.in: add slc commands for gss + + * krb5/gsskrb5_locl.h: Remove dup prototype of _gsskrb5_init() + + * Makefile.am: Add test_cfx + + * krb5/external.c: add GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X + + * krb5/set_sec_context_option.c: catch + GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X + + * krb5/accept_sec_context.c: reimplement + gsskrb5_register_acceptor_identity + + * mech/gss_krb5.c: implement gsskrb5_register_acceptor_identity + + * mech/gss_inquire_mechs_for_name.c: call _gss_load_mech + + * mech/gss_inquire_cred.c (gss_inquire_cred): call _gss_load_mech + + * mech/gss_mech_switch.c: Make _gss_load_mech() atomic and run + only once, this have the side effect that _gss_mechs and + _gss_mech_oids is only initialized once, so if just the users of + these two global variables calls _gss_load_mech() first, it will + act as a barrier and make sure the variables are never changed and + we don't need to lock them. + + * mech/utils.h: no need to mark functions extern. + + * mech/name.h: no need to mark _gss_find_mn extern. + +2006-07-19 Love Hörnquist Åstrand + + * krb5/cfx.c: Redo the wrap length calculations. + + * krb5/test_cfx.c: test max_wrap_size in cfx.c + + * mech/gss_display_status.c: Handle more error codes. + +2006-07-07 Love Hörnquist Åstrand + + * mech/mech_locl.h: Include and "mechqueue.h" + + * mech/mechqueue.h: Add SLIST macros. + + * krb5/inquire_context.c: Don't free return values on success. + + * krb5/inquire_cred.c (_gsskrb5_inquire_cred): When cred provided + is the default cred, acquire the acceptor cred and initator cred + in two diffrent steps and then query them for the information, + this way, the code wont fail if there are no keytab, but there is + a credential cache. + + * mech/gss_inquire_cred.c: move the check if we found any cred + where it matter for both cases + (default cred and provided cred) + + * mech/gss_init_sec_context.c: If the desired mechanism can't + convert the name to a MN, fail with GSS_S_BAD_NAME rather then a + NULL de-reference. + +2006-07-06 Love Hörnquist Åstrand + + * spnego/external.c: readd gss_spnego_inquire_names_for_mech + + * spnego/spnego_locl.h: reimplement + gss_spnego_inquire_names_for_mech add support function + _gss_spnego_supported_mechs + + * spnego/context_stubs.h: reimplement + gss_spnego_inquire_names_for_mech add support function + _gss_spnego_supported_mechs + + * spnego/context_stubs.c: drop gss_spnego_indicate_mechs + + * mech/gss_indicate_mechs.c: if the underlaying mech doesn't + support gss_indicate_mechs, use the oid in the mechswitch + structure + + * spnego/external.c: let the mech glue layer implement + gss_indicate_mechs + + * spnego/cred_stubs.c (gss_spnego_acquire_cred): don't care about + desired_mechs, get our own list with indicate_mechs and remove + ourself. + +2006-07-05 Love Hörnquist Åstrand + + * spnego/external.c: remove gss_spnego_inquire_names_for_mech, let + the mechglue layer implement it + + * spnego/context_stubs.c: remove gss_spnego_inquire_names_for_mech, let + the mechglue layer implement it + + * spnego/spnego_locl.c: remove gss_spnego_inquire_names_for_mech, let + the mechglue layer implement it + +2006-07-01 Love Hörnquist Åstrand + + * mech/gss_set_cred_option.c: fix argument to gss_release_cred + +2006-06-30 Love Hörnquist Åstrand + + * krb5/init_sec_context.c: Make work on compilers that are + somewhat more picky then gcc4 (like gcc2.95) + + * krb5/init_sec_context.c (do_delegation): use KDCOptions2int to + convert fwd_flags to an integer, since otherwise int2KDCOptions in + krb5_get_forwarded_creds wont do the right thing. + + * mech/gss_set_cred_option.c (gss_set_cred_option): free memory on + failure + + * krb5/set_sec_context_option.c (_gsskrb5_set_sec_context_option): + init global kerberos context + + * krb5/set_cred_option.c (_gsskrb5_set_cred_option): init global + kerberos context + + * mech/gss_accept_sec_context.c: Insert the delegated sub cred on + the delegated cred handle, not cred handle + + * mech/gss_accept_sec_context.c (gss_accept_sec_context): handle + the case where ret_flags == NULL + + * mech/gss_mech_switch.c (add_builtin): set + _gss_mech_switch->gm_mech_oid + + * mech/gss_set_cred_option.c (gss_set_cred_option): laod mechs + + * test_cred.c (gss_print_errors): don't try to print error when + gss_display_status failed + + * Makefile.am: Add mech/gss_release_oid.c + + * mech/gss_release_oid.c: Add gss_release_oid, reverse of + gss_duplicate_oid + + * spnego/compat.c: preferred_mech_type was allocated with + gss_duplicate_oid in one place and assigned static varianbles a + the second place. change that static assignement to + gss_duplicate_oid and bring back gss_release_oid. + + * spnego/compat.c (_gss_spnego_delete_sec_context): don't release + preferred_mech_type and negotiated_mech_type, they where never + allocated from the begining. + +2006-06-29 Love Hörnquist Åstrand + + * mech/gss_import_name.c (gss_import_name): avoid + type-punned/strict aliasing rules + + * mech/gss_add_cred.c: avoid type-punned/strict aliasing rules + + * gssapi.h: Make gss_name_t an opaque type. + + * krb5: make gss_name_t an opaque type + + * krb5/set_cred_option.c: Add + + * mech/gss_set_cred_option.c (gss_set_cred_option): support the + case where *cred_handle == NULL + + * mech/gss_krb5.c (gss_krb5_import_cred): make sure cred is + GSS_C_NO_CREDENTIAL on failure. + + * mech/gss_acquire_cred.c (gss_acquire_cred): if desired_mechs is + NO_OID_SET, there is a need to load the mechs, so always do that. + +2006-06-28 Love Hörnquist Åstrand + + * krb5/inquire_cred_by_oid.c: Reimplement GSS_KRB5_COPY_CCACHE_X + to instead pass a fullname to the credential, then resolve and + copy out the content, and then close the cred. + + * mech/gss_krb5.c: Reimplement GSS_KRB5_COPY_CCACHE_X to instead + pass a fullname to the credential, then resolve and copy out the + content, and then close the cred. + + * krb5/inquire_cred_by_oid.c: make "work", GSS_KRB5_COPY_CCACHE_X + interface needs to be re-done, currently its utterly broken. + + * mech/gss_set_cred_option.c: Make work. + + * krb5/external.c: Add _gsskrb5_set_{sec_context,cred}_option + + * mech/gss_krb5.c (gss_krb5_import_cred): implement + + * Makefile.am: Add gss_set_{sec_context,cred}_option and sort + + * mech/gss_set_{sec_context,cred}_option.c: add + + * gssapi.h: Add GSS_KRB5_IMPORT_CRED_X + + * test_*.c: make compile again + + * Makefile.am: Add lib dependencies and test programs + + * spnego: remove dependency on libkrb5 + + * mech: Bug fixes, cleanup, compiler warnings, restructure code. + + * spnego: Rename gss_context_id_t and gss_cred_id_t to local names + + * krb5: repro copy the krb5 files here + + * mech: import Doug Rabson mechglue from freebsd + + * spnego: Import Luke Howard's SPNEGO from the mechglue branch + +2006-06-22 Love Hörnquist Åstrand + + * gssapi.h: Add oid_to_str. + + * Makefile.am: add oid_to_str and test_oid + + * oid_to_str.c: Add gss_oid_to_str + + * test_oid.c: Add test for gss_oid_to_str() + +2006-05-13 Love Hörnquist Åstrand + + * verify_mic.c: Less pointer signedness warnings. + + * unwrap.c: Less pointer signedness warnings. + + * arcfour.c: Less pointer signedness warnings. + + * gssapi_locl.h: Use const void * to instead of unsigned char * to + avoid pointer signedness warnings. + + * encapsulate.c: Use const void * to instead of unsigned char * to + avoid pointer signedness warnings. + + * decapsulate.c: Use const void * to instead of unsigned char * to + avoid pointer signedness warnings. + + * decapsulate.c: Less pointer signedness warnings. + + * cfx.c: Less pointer signedness warnings. + + * init_sec_context.c: Less pointer signedness warnings (partly by + using the new asn.1 CHOICE decoder) + + * import_sec_context.c: Less pointer signedness warnings. + +2006-05-09 Love Hörnquist Åstrand + + * accept_sec_context.c (gsskrb5_is_cfx): always set is_cfx. From + Andrew Abartlet. + +2006-05-08 Love Hörnquist Åstrand + + * get_mic.c (mic_des3): make sure message_buffer doesn't point to + free()ed memory on failure. Pointed out by IBM checker. + +2006-05-05 Love Hörnquist Åstrand + + * Rename u_intXX_t to uintXX_t + +2006-05-04 Love Hörnquist Åstrand + + * cfx.c: Less pointer signedness warnings. + + * arcfour.c: Avoid pointer signedness warnings. + + * gssapi_locl.h (gssapi_decode_*): make data argument const void * + + * 8003.c (gssapi_decode_*): make data argument const void * + +2006-04-12 Love Hörnquist Åstrand + + * export_sec_context.c: Export sequence order element. From Wynn + Wilkes . + + * import_sec_context.c: Import sequence order element. From Wynn + Wilkes . + + * sequence.c (_gssapi_msg_order_import,_gssapi_msg_order_export): + New functions, used by {import,export}_sec_context. From Wynn + Wilkes . + + * test_sequence.c: Add test for import/export sequence. + +2006-04-09 Love Hörnquist Åstrand + + * add_cred.c: Check that cred != GSS_C_NO_CREDENTIAL, this is a + standard conformance failure, but much better then a crash. + +2006-04-02 Love Hörnquist Åstrand + + * get_mic.c (get_mic*)_: make sure message_token is cleaned on + error, found by IBM checker. + + * wrap.c (wrap*): Reset output_buffer on error, found by IBM + checker. + +2006-02-15 Love Hörnquist Åstrand + + * import_name.c: Accept both GSS_C_NT_HOSTBASED_SERVICE and + GSS_C_NT_HOSTBASED_SERVICE_X as nametype for hostbased names. + +2006-01-16 Love Hörnquist Åstrand + + * delete_sec_context.c (gss_delete_sec_context): if the context + handle is GSS_C_NO_CONTEXT, don't fall over. + +2005-12-12 Love Hörnquist Åstrand + + * gss_acquire_cred.3: Replace gss_krb5_import_ccache with + gss_krb5_import_cred and add more references + +2005-12-05 Love Hörnquist Åstrand + + * gssapi.h: Change gss_krb5_import_ccache to gss_krb5_import_cred, + it can handle keytabs too. + + * add_cred.c (gss_add_cred): avoid deadlock + + * context_time.c (gssapi_lifetime_left): define the 0 lifetime as + GSS_C_INDEFINITE. + +2005-12-01 Love Hörnquist Åstrand + + * acquire_cred.c (acquire_acceptor_cred): only check if principal + exists if we got called with principal as an argument. + + * acquire_cred.c (acquire_acceptor_cred): check that the acceptor + exists in the keytab before returning ok. + +2005-11-29 Love Hörnquist Åstrand + + * copy_ccache.c (gss_krb5_import_cred): fix buglet, from Andrew + Bartlett. + +2005-11-25 Love Hörnquist Åstrand + + * test_kcred.c: Rename gss_krb5_import_ccache to + gss_krb5_import_cred. + + * copy_ccache.c: Rename gss_krb5_import_ccache to + gss_krb5_import_cred and let it grow code to handle keytabs too. + +2005-11-02 Love Hörnquist Åstrand + + * init_sec_context.c: Change sematics of ok-as-delegate to match + windows if + [gssapi]realm/ok-as-delegate=true is set, otherwise keep old + sematics. + + * release_cred.c (gss_release_cred): use + GSS_CF_DESTROY_CRED_ON_RELEASE to decide if the cache should be + krb5_cc_destroy-ed + + * acquire_cred.c (acquire_initiator_cred): + GSS_CF_DESTROY_CRED_ON_RELEASE on created credentials. + + * accept_sec_context.c (gsskrb5_accept_delegated_token): rewrite + to use gss_krb5_import_ccache + +2005-11-01 Love Hörnquist Åstrand + + * arcfour.c: Remove signedness warnings. + +2005-10-31 Love Hörnquist Åstrand + + * gss_acquire_cred.3: Document that gss_krb5_import_ccache is copy + by reference. + + * copy_ccache.c (gss_krb5_import_ccache): Instead of making a copy + of the ccache, make a reference by getting the name and resolving + the name. This way the cache is shared, this flipp side is of + course that if someone calls krb5_cc_destroy the cache is lost for + everyone. + + * test_kcred.c: Remove memory leaks. + +2005-10-26 Love Hörnquist Åstrand + + * Makefile.am: build test_kcred + + * gss_acquire_cred.3: Document gss_krb5_import_ccache + + * gssapi.3: Sort and add gss_krb5_import_ccache. + + * acquire_cred.c (_gssapi_krb5_ccache_lifetime): break out code + used to extract lifetime from a credential cache + + * gssapi_locl.h: Add _gssapi_krb5_ccache_lifetime, used to extract + lifetime from a credential cache. + + * gssapi.h: add gss_krb5_import_ccache, reverse of + gss_krb5_copy_ccache + + * copy_ccache.c: add gss_krb5_import_ccache, reverse of + gss_krb5_copy_ccache + + * test_kcred.c: test gss_krb5_import_ccache + +2005-10-21 Love Hörnquist Åstrand + + * acquire_cred.c (acquire_initiator_cred): use krb5_cc_cache_match + to find a matching creditial cache, if that failes, fallback to + the default cache. + +2005-10-12 Love Hörnquist Åstrand + + * gssapi_locl.h: Add gssapi_krb5_set_status and + gssapi_krb5_clear_status + + * init_sec_context.c (spnego_reply): Don't pass back raw Kerberos + errors, use GSS-API errors instead. From Michael B Allen. + + * display_status.c: Add gssapi_krb5_clear_status, + gssapi_krb5_set_status for handling error messages. + +2005-08-23 Love Hörnquist Åstrand + + * external.c: Use rk_UNCONST to avoid const warning. + + * display_status.c: Constify strings to avoid warnings. + +2005-08-11 Love Hörnquist Åstrand + + * init_sec_context.c: avoid warnings, update (c) + +2005-07-13 Love Hörnquist Åstrand + + * init_sec_context.c (spnego_initial): use NegotiationToken + encoder now that we have one with the new asn1. compiler. + + * Makefile.am: the new asn.1 compiler includes the modules name in + the depend file + +2005-06-16 Love Hörnquist Åstrand + + * decapsulate.c: use rk_UNCONST + + * ccache_name.c: rename to avoid shadowing + + * gssapi_locl.h: give kret in GSSAPI_KRB5_INIT a more unique name + + * process_context_token.c: use rk_UNCONST to unconstify + + * test_cred.c: rename optind to optidx + +2005-05-30 Love Hörnquist Åstrand + + * init_sec_context.c (init_auth): honor ok-as-delegate if local + configuration approves + + * gssapi_locl.h: prototype for _gss_check_compat + + * compat.c: export check_compat as _gss_check_compat + +2005-05-29 Love Hörnquist Åstrand + + * init_sec_context.c: Prefix Der_class with ASN1_C_ to avoid + problems with system headerfiles that pollute the name space. + + * accept_sec_context.c: Prefix Der_class with ASN1_C_ to avoid + problems with system headerfiles that pollute the name space. + +2005-05-17 Love Hörnquist Åstrand + + * init_sec_context.c (init_auth): set + KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED (for java compatibility), + also while here, use krb5_auth_con_addflags + +2005-05-06 Love Hörnquist Åstrand + + * arcfour.c (_gssapi_wrap_arcfour): fix calculating the encap + length. From: Tom Maher + +2005-05-02 Dave Love + + * test_cred.c (main): Call setprogname. + +2005-04-27 Love Hörnquist Åstrand + + * prefix all sequence symbols with _, they are not part of the + GSS-API api. By comment from Wynn Wilkes + +2005-04-10 Love Hörnquist Åstrand + + * accept_sec_context.c: break out the processing of the delegated + credential to a separate function to make error handling easier, + move the credential handling to after other setup is done + + * test_sequence.c: make less verbose in case of success + + * Makefile.am: add test_sequence to TESTS + +2005-04-01 Love Hörnquist Åstrand + + * 8003.c (gssapi_krb5_verify_8003_checksum): check that cksum + isn't NULL From: Nicolas Pouvesle + +2005-03-21 Love Hörnquist Åstrand + + * Makefile.am: use $(LIB_roken) + +2005-03-16 Love Hörnquist Åstrand + + * display_status.c (gssapi_krb5_set_error_string): pass in the + krb5_context to krb5_free_error_string + +2005-03-15 Love Hörnquist Åstrand + + * display_status.c (gssapi_krb5_set_error_string): don't misuse + the krb5_get_error_string api + +2005-03-01 Love Hörnquist Åstrand + + * compat.c (_gss_DES3_get_mic_compat): don't unlock mutex + here. Bug reported by Stefan Metzmacher + +2005-02-21 Luke Howard + + * init_sec_context.c: don't call krb5_get_credentials() with + KRB5_TC_MATCH_KEYTYPE, it can lead to the credentials cache + growing indefinitely as no key is found with KEYTYPE_NULL + + * compat.c: remove GSS_C_EXPECTING_MECH_LIST_MIC_FLAG, it is + no longer used (however the mechListMIC behaviour is broken, + rfc2478bis support requires the code in the mechglue branch) + + * init_sec_context.c: remove GSS_C_EXPECTING_MECH_LIST_MIC_FLAG + + * gssapi.h: remove GSS_C_EXPECTING_MECH_LIST_MIC_FLAG + +2005-01-05 Luke Howard + + * 8003.c: use symbolic name for checksum type + + * accept_sec_context.c: allow client to indicate + that subkey should be used + + * acquire_cred.c: plug leak + + * get_mic.c: use gss_krb5_get_subkey() instead + of gss_krb5_get_{local,remote}key(), support + KEYTYPE_ARCFOUR_56 + + * gssapi_local.c: use gss_krb5_get_subkey(), + support KEYTYPE_ARCFOUR_56 + + * import_sec_context.c: plug leak + + * unwrap.c: use gss_krb5_get_subkey(), + support KEYTYPE_ARCFOUR_56 + + * verify_mic.c: use gss_krb5_get_subkey(), + support KEYTYPE_ARCFOUR_56 + + * wrap.c: use gss_krb5_get_subkey(), + support KEYTYPE_ARCFOUR_56 + +2004-11-30 Love Hörnquist Åstrand + + * inquire_cred.c: Reverse order of HEIMDAL_MUTEX_unlock and + gss_release_cred to avoid deadlock, from Luke Howard + . + +2004-09-06 Love Hörnquist Åstrand + + * gss_acquire_cred.3: gss_krb5_extract_authz_data_from_sec_context + was renamed to gsskrb5_extract_authz_data_from_sec_context + +2004-08-07 Love Hörnquist Åstrand + + * unwrap.c: mutex buglet, From: Luke Howard + + * arcfour.c: mutex buglet, From: Luke Howard + +2004-05-06 Love Hörnquist Åstrand + + * gssapi.3: spelling from Josef El-Rayes while + here, write some text about the SPNEGO situation + +2004-04-08 Love Hörnquist Åstrand + + * cfx.c: s/CTXAcceptorSubkey/CFXAcceptorSubkey/ + +2004-04-07 Love Hörnquist Åstrand + + * gssapi.h: add GSS_C_EXPECTING_MECH_LIST_MIC_FLAG From: Luke + Howard + + * init_sec_context.c (spnego_reply): use + _gss_spnego_require_mechlist_mic to figure out if we need to check + MechListMIC; From: Luke Howard + + * accept_sec_context.c (send_accept): use + _gss_spnego_require_mechlist_mic to figure out if we need to send + MechListMIC; From: Luke Howard + + * gssapi_locl.h: add _gss_spnego_require_mechlist_mic + From: Luke Howard + + * compat.c: add _gss_spnego_require_mechlist_mic for compatibility + with MS SPNEGO, From: Luke Howard + +2004-04-05 Love Hörnquist Åstrand + + * accept_sec_context.c (gsskrb5_is_cfx): krb5_keyblock->keytype is + an enctype, not keytype + + * accept_sec_context.c: use ASN1_MALLOC_ENCODE + + * init_sec_context.c: avoid the malloc loop and just allocate the + propper amount of data + + * init_sec_context.c (spnego_initial): handle mech_token better + +2004-03-19 Love Hörnquist Åstrand + + * gssapi.h: add gss_krb5_get_tkt_flags + + * Makefile.am: add ticket_flags.c + + * ticket_flags.c: Get ticket-flags from acceptor ticket From: Luke + Howard + + * gss_acquire_cred.3: document gss_krb5_get_tkt_flags + +2004-03-14 Love Hörnquist Åstrand + + * acquire_cred.c (gss_acquire_cred): check usage before even + bothering to process it, add both keytab and initial tgt if + requested + + * wrap.c: support cfx, try to handle acceptor asserted subkey + + * unwrap.c: support cfx, try to handle acceptor asserted subkey + + * verify_mic.c: support cfx + + * get_mic.c: support cfx + + * test_sequence.c: handle changed signature of + gssapi_msg_order_create + + * import_sec_context.c: handle acceptor asserted subkey + + * init_sec_context.c: handle acceptor asserted subkey + + * accept_sec_context.c: handle acceptor asserted subkey + + * sequence.c: add dummy use_64 argument to gssapi_msg_order_create + + * gssapi_locl.h: add partial support for CFX + + * Makefile.am (noinst_PROGRAMS) += test_cred + + * test_cred.c: gssapi credential testing + + * test_acquire_cred.c: fix comment + +2004-03-07 Love Hörnquist Åstrand + + * arcfour.h: drop structures for message formats, no longer used + + * arcfour.c: comment describing message formats + + * accept_sec_context.c (spnego_accept_sec_context): make sure the + length of the choice element doesn't overrun us + + * init_sec_context.c (spnego_reply): make sure the length of the + choice element doesn't overrun us + + * spnego.asn1: move NegotiationToken to avoid warning + + * spnego.asn1: uncomment NegotiationToken + + * Makefile.am: spnego_files += asn1_NegotiationToken.x + +2004-01-25 Love Hörnquist Åstrand + + * gssapi.h: add gss_krb5_ccache_name + + * Makefile.am (libgssapi_la_SOURCES): += ccache_name.c + + * ccache_name.c (gss_krb5_ccache_name): help function enable to + set krb5 name, using out_name argument makes function no longer + thread-safe + + * gssapi.3: add missing gss_krb5_ references + + * gss_acquire_cred.3: document gss_krb5_ccache_name + +2003-12-12 Love Hörnquist Åstrand + + * cfx.c: make rrc a modulus operation if its longer then the + length of the message, noticed by Sam Hartman + +2003-12-07 Love Hörnquist Åstrand + + * accept_sec_context.c: use krb5_auth_con_addflags + +2003-12-05 Love Hörnquist Åstrand + + * cfx.c: Wrap token id was in wrong order, found by Sam Hartman + +2003-12-04 Love Hörnquist Åstrand + + * cfx.c: add AcceptorSubkey (but no code understand it yet) ignore + unknown token flags + +2003-11-22 Love Hörnquist Åstrand + + * accept_sec_context.c: Don't require timestamp to be set on + delegated token, its already protected by the outer token (and + windows doesn't alway send it) Pointed out by Zi-Bin Yang + on heimdal-discuss + +2003-11-14 Love Hörnquist Åstrand + + * cfx.c: fix {} error, pointed out by Liqiang Zhu + +2003-11-10 Love Hörnquist Åstrand + + * cfx.c: Sequence number should be stored in bigendian order From: + Luke Howard + +2003-11-09 Love Hörnquist Åstrand + + * delete_sec_context.c (gss_delete_sec_context): don't free + ticket, krb5_free_ticket does that now + +2003-11-06 Love Hörnquist Åstrand + + * cfx.c: checksum the header last in MIC token, update to -03 + From: Luke Howard + +2003-10-07 Love Hörnquist Åstrand + + * add_cred.c: If its a MEMORY cc, make a copy. We need to do this + since now gss_release_cred will destroy the cred. This should be + really be solved a better way. + + * acquire_cred.c (gss_release_cred): if its a mcc, destroy it + rather the just release it Found by: "Zi-Bin Yang" + + + * acquire_cred.c (acquire_initiator_cred): use kret instead of ret + where appropriate + +2003-09-30 Love Hörnquist Åstrand + + * gss_acquire_cred.3: spelling + From: jmc + +2003-09-23 Love Hörnquist Åstrand + + * cfx.c: - EC and RRC are big-endian, not little-endian - The + default is now to rotate regardless of GSS_C_DCE_STYLE. There are + no longer any references to GSS_C_DCE_STYLE. - rrc_rotate() + avoids allocating memory on the heap if rrc <= 256 + From: Luke Howard + +2003-09-22 Love Hörnquist Åstrand + + * cfx.[ch]: rrc_rotate() was untested and broken, fix it. + Set and verify wrap Token->Filler. + Correct token ID for wrap tokens, + were accidentally swapped with delete tokens. + From: Luke Howard + +2003-09-21 Love Hörnquist Åstrand + + * cfx.[ch]: no ASN.1-ish header on per-message tokens + From: Luke Howard + +2003-09-19 Love Hörnquist Åstrand + + * arcfour.h: remove depenency on gss_arcfour_mic_token and + gss_arcfour_warp_token + + * arcfour.c: remove depenency on gss_arcfour_mic_token and + gss_arcfour_warp_token + +2003-09-18 Love Hörnquist Åstrand + + * 8003.c: remove #if 0'ed code + +2003-09-17 Love Hörnquist Åstrand + + * accept_sec_context.c (gsskrb5_accept_sec_context): set sequence + number when not requesting mutual auth From: Luke Howard + + + * init_sec_context.c (init_auth): set sequence number when not + requesting mutual auth From: Luke Howard + +2003-09-16 Love Hörnquist Åstrand + + * arcfour.c (*): set minor_status + (gss_wrap): set conf_state to conf_req_flags on success + From: Luke Howard + + * wrap.c (gss_wrap_size_limit): use existing function From: Luke + Howard + +2003-09-12 Love Hörnquist Åstrand + + * indicate_mechs.c (gss_indicate_mechs): in case of error, free + mech_set + + * indicate_mechs.c (gss_indicate_mechs): add SPNEGO + +2003-09-10 Love Hörnquist Åstrand + + * init_sec_context.c (spnego_initial): catch errors and return + them + + * init_sec_context.c (spnego_initial): add #if 0 out version of + the CHOICE branch encoding, also where here, free no longer used + memory + +2003-09-09 Love Hörnquist Åstrand + + * gss_acquire_cred.3: support GSS_SPNEGO_MECHANISM + + * accept_sec_context.c: SPNEGO doesn't include gss wrapping on + SubsequentContextToken like the Kerberos 5 mech does. + + * init_sec_context.c (spnego_reply): SPNEGO doesn't include gss + wrapping on SubsequentContextToken like the Kerberos 5 mech + does. Lets check for it anyway. + + * accept_sec_context.c: Add support for SPNEGO on the initator + side. Implementation initially from Assar Westerlund, passes + though quite a lot of hands before I commited it. + + * init_sec_context.c: Add support for SPNEGO on the initator side. + Tested with ldap server on a Windows 2000 DC. Implementation + initially from Assar Westerlund, passes though quite a lot of + hands before I commited it. + + * gssapi.h: export GSS_SPNEGO_MECHANISM + + * gssapi_locl.h: include spnego_as.h add prototype for + gssapi_krb5_get_mech + + * decapsulate.c (gssapi_krb5_get_mech): make non static + + * Makefile.am: build SPNEGO file + +2003-09-08 Love Hörnquist Åstrand + + * external.c: SPENGO and IAKERB oids + + * spnego.asn1: SPENGO ASN1 + +2003-09-05 Love Hörnquist Åstrand + + * cfx.c: RRC also need to be zero before wraping them + From: Luke Howard + +2003-09-04 Love Hörnquist Åstrand + + * encapsulate.c (gssapi_krb5_encap_length): don't return void + +2003-09-03 Love Hörnquist Åstrand + + * verify_mic.c: switch from the des_ to the DES_ api + + * get_mic.c: switch from the des_ to the DES_ api + + * unwrap.c: switch from the des_ to the DES_ api + + * wrap.c: switch from the des_ to the DES_ api + + * cfx.c: EC is not included in the checksum since the length might + change depending on the data. From: Luke Howard + + * acquire_cred.c: use + krb5_get_init_creds_opt_alloc/krb5_get_init_creds_opt_free + +2003-09-01 Love Hörnquist Åstrand + + * copy_ccache.c: rename + gss_krb5_extract_authz_data_from_sec_context to + gsskrb5_extract_authz_data_from_sec_context + + * gssapi.h: rename gss_krb5_extract_authz_data_from_sec_context to + gsskrb5_extract_authz_data_from_sec_context + +2003-08-31 Love Hörnquist Åstrand + + * copy_ccache.c (gss_krb5_extract_authz_data_from_sec_context): + check that we have a ticket before we start to use it + + * gss_acquire_cred.3: document + gss_krb5_extract_authz_data_from_sec_context + + * gssapi.h (gss_krb5_extract_authz_data_from_sec_context): + return the kerberos authorizationdata, from idea of Luke Howard + + * copy_ccache.c (gss_krb5_extract_authz_data_from_sec_context): + return the kerberos authorizationdata, from idea of Luke Howard + + * verify_mic.c (gss_verify_mic_internal): switch type and key + argument + +2003-08-30 Love Hörnquist Åstrand + + * cfx.[ch]: draft-ietf-krb-wg-gssapi-cfx-01.txt implemetation + From: Luke Howard + +2003-08-28 Love Hörnquist Åstrand + + * arcfour.c (arcfour_mic_cksum): use free_Checksum to free the + checksum + + * arcfour.h: swap two last arguments to verify_mic for consistency + with des3 + + * wrap.c,unwrap.c,get_mic.c,verify_mic.c,cfx.c,cfx.h: + prefix cfx symbols with _gssapi_ + + * arcfour.c: release the right buffer + + * arcfour.c: rename token structure in consistency with rest of + GSS-API From: Luke Howard + + * unwrap.c (unwrap_des3): use _gssapi_verify_pad + (unwrap_des): use _gssapi_verify_pad + + * arcfour.c (_gssapi_wrap_arcfour): set the correct padding + (_gssapi_unwrap_arcfour): verify and strip padding + + * gssapi_locl.h: added _gssapi_verify_pad + + * decapsulate.c (_gssapi_verify_pad): verify padding of a gss + wrapped message and return its length + + * arcfour.c: support KEYTYPE_ARCFOUR_56 keys, from Luke Howard + + + * arcfour.c: use right seal alg, inherit keytype from parent key + + * arcfour.c: include the confounder in the checksum use the right + key usage number for warped/unwraped tokens + + * gssapi.h: add gss_krb5_nt_general_name as an mit compat glue + (same as GSS_KRB5_NT_PRINCIPAL_NAME) + + * unwrap.c: hook in arcfour unwrap + + * wrap.c: hook in arcfour wrap + + * verify_mic.c: hook in arcfour verify_mic + + * get_mic.c: hook in arcfour get_mic + + * arcfour.c: implement wrap/unwarp + + * gssapi_locl.h: add gssapi_{en,de}code_be_om_uint32 + + * 8003.c: add gssapi_{en,de}code_be_om_uint32 + +2003-08-27 Love Hörnquist Åstrand + + * arcfour.c (_gssapi_verify_mic_arcfour): Do the checksum on right + area. Swap filler check, it was reversed. + + * Makefile.am (libgssapi_la_SOURCES): += arcfour.c + + * gssapi_locl.h: include "arcfour.h" + + * arcfour.c: arcfour gss-api mech, get_mic/verify_mic working + + * arcfour.h: arcfour gss-api mech, get_mic/verify_mic working + +2003-08-26 Love Hörnquist Åstrand + + * gssapi_locl.h: always include cfx.h add prototype for + _gssapi_decapsulate + + * cfx.[ch]: Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt + from Luke Howard + + * decapsulate.c: add _gssapi_decapsulate, from Luke Howard + + +2003-08-25 Love Hörnquist Åstrand + + * unwrap.c: encap/decap now takes a oid if the enctype/keytype is + arcfour, return error add hook for cfx + + * verify_mic.c: encap/decap now takes a oid if the enctype/keytype + is arcfour, return error add hook for cfx + + * get_mic.c: encap/decap now takes a oid if the enctype/keytype is + arcfour, return error add hook for cfx + + * accept_sec_context.c: encap/decap now takes a oid + + * init_sec_context.c: encap/decap now takes a oid + + * gssapi_locl.h: include cfx.h if we need it lifetime is a + OM_uint32, depend on gssapi interface add all new encap/decap + functions + + * decapsulate.c: add decap functions that doesn't take the token + type also make all decap function take the oid mech that they + should use + + * encapsulate.c: add encap functions that doesn't take the token + type also make all encap function take the oid mech that they + should use + + * sequence.c (elem_insert): fix a off by one index counter + + * inquire_cred.c (gss_inquire_cred): handle cred_handle being + GSS_C_NO_CREDENTIAL and use the default cred then. + +2003-08-19 Love Hörnquist Åstrand + + * gss_acquire_cred.3: break out extensions and document + gsskrb5_register_acceptor_identity + +2003-08-18 Love Hörnquist Åstrand + + * test_acquire_cred.c (print_time): time is returned in seconds + from now, not unix time + +2003-08-17 Love Hörnquist Åstrand + + * compat.c (check_compat): avoid leaking principal when finding a + match + + * address_to_krb5addr.c: sa_size argument to krb5_addr2sockaddr is + a krb5_socklen_t + + * acquire_cred.c (gss_acquire_cred): 4th argument to + gss_test_oid_set_member is a int + +2003-07-22 Love Hörnquist Åstrand + + * init_sec_context.c (repl_mutual): don't set kerberos error where + there was no kerberos error + + * gssapi_locl.h: Add destruction/creation prototypes and structure + for the thread specific storage. + + * display_status.c: use thread specific storage to set/get the + kerberos error message + + * init.c: Provide locking around the creation of the global + krb5_context. Add destruction/creation functions for the thread + specific storage that the error string handling is using. + +2003-07-20 Love Hörnquist Åstrand + + * gss_acquire_cred.3: add missing prototype and missing .Ft + arguments + +2003-06-17 Love Hörnquist Åstrand + + * verify_mic.c: reorder code so sequence numbers can can be used + + * unwrap.c: reorder code so sequence numbers can can be used + + * sequence.c: remove unused function, indent, add + gssapi_msg_order_f that filter gss flags to gss_msg_order flags + + * gssapi_locl.h: prototypes for + gssapi_{encode_om_uint32,decode_om_uint32} add sequence number + verifier prototypes + + * delete_sec_context.c: destroy sequence number verifier + + * init_sec_context.c: remember to free data use sequence number + verifier + + * accept_sec_context.c: don't clear output_token twice remember to + free data use sequence number verifier + + * 8003.c: export and rename encode_om_uint32/decode_om_uint32 and + start to use them + +2003-06-09 Johan Danielsson + + * Makefile.am: can't have sequence.c in two different places + +2003-06-06 Love Hörnquist Åstrand + + * test_sequence.c: check rollover, print summery + + * wrap.c (sub_wrap_size): gss_wrap_size_limit() has + req_output_size and max_input_size around the wrong way -- it + returns the output token size for a given input size, rather than + the maximum input size for a given output token size. + + From: Luke Howard + +2003-06-05 Love Hörnquist Åstrand + + * gssapi_locl.h: add prototypes for sequence.c + + * Makefile.am (libgssapi_la_SOURCES): add sequence.c + (test_sequence): build + + * sequence.c: sequence number checks, order and replay + * test_sequence.c: sequence number checks, order and replay + +2003-06-03 Love Hörnquist Åstrand + + * accept_sec_context.c (gss_accept_sec_context): make sure time is + returned in seconds from now, not in kerberos time + + * acquire_cred.c (gss_aquire_cred): make sure time is returned in + seconds from now, not in kerberos time + + * init_sec_context.c (init_auth): if the cred is expired before we + tries to create a token, fail so the peer doesn't need reject us + (*): make sure time is returned in seconds from now, + not in kerberos time + (repl_mutual): remember to unlock the context mutex + + * context_time.c (gss_context_time): remove unused variable + + * verify_mic.c: make sure minor_status is always set, pointed out + by Luke Howard + +2003-05-21 Love Hörnquist Åstrand + + * *.[ch]: do some basic locking (no reference counting so contexts + can be removed while still used) + - don't export gss_ctx_id_t_desc_struct and gss_cred_id_t_desc_struct + - make sure all lifetime are returned in seconds left until expired, + not in unix epoch + + * gss_acquire_cred.3: document argument lifetime_rec to function + gss_inquire_context + +2003-05-17 Love Hörnquist Åstrand + + * test_acquire_cred.c: test gss_add_cred more then once + +2003-05-06 Love Hörnquist Åstrand + + * gssapi.h: if __cplusplus, wrap the extern variable (just to be + safe) and functions in extern "C" { } + +2003-04-30 Love Hörnquist Åstrand + + * gssapi.3: more about the des3 mic mess + + * verify_mic.c (verify_mic_des3): always check if the mic is the + correct mic or the mic that old heimdal would have generated + +2003-04-28 Jacques Vidrine + + * verify_mic.c (verify_mic_des3): If MIC verification fails, + retry using the `old' MIC computation (with zero IV). + +2003-04-26 Love Hörnquist Åstrand + + * gss_acquire_cred.3: more about difference between comparing IN + and MN + + * gss_acquire_cred.3: more about name type and access control + +2003-04-25 Love Hörnquist Åstrand + + * gss_acquire_cred.3: document gss_context_time + + * context_time.c: if lifetime of context have expired, set + time_rec to 0 and return GSS_S_CONTEXT_EXPIRED + + * gssapi.3: document [gssapi]correct_des3_mic + [gssapi]broken_des3_mic + + * gss_acquire_cred.3: document gss_krb5_compat_des3_mic + + * compat.c (gss_krb5_compat_des3_mic): enable turning on/off des3 + mic compat + (_gss_DES3_get_mic_compat): handle [gssapi]correct_des3_mic too + + * gssapi.h (gss_krb5_compat_des3_mic): new function, turn on/off + des3 mic compat + (GSS_C_KRB5_COMPAT_DES3_MIC): cpp symbol that exists if + gss_krb5_compat_des3_mic exists + +2003-04-24 Love Hörnquist Åstrand + + * Makefile.am: (libgssapi_la_LDFLAGS): update major + version of gssapi for incompatiblity in 3des getmic support + +2003-04-23 Love Hörnquist Åstrand + + * Makefile.am: test_acquire_cred_LDADD: use libgssapi.la not + ./libgssapi.la (make make -jN work) + +2003-04-16 Love Hörnquist Åstrand + + * gssapi.3: spelling + + * gss_acquire_cred.3: Change .Fd #include to .In + header.h, from Thomas Klausner + + +2003-04-06 Love Hörnquist Åstrand + + * gss_acquire_cred.3: spelling + + * Makefile.am: remove stuff that sneaked in with last commit + + * acquire_cred.c (acquire_initiator_cred): if the requested name + isn't in the ccache, also check keytab. Extact the krbtgt for the + default realm to check how long the credentials will last. + + * add_cred.c (gss_add_cred): don't create a new ccache, just open + the old one; better check if output handle is compatible with new + (copied) handle + + * test_acquire_cred.c: test gss_add_cred too + +2003-04-03 Love Hörnquist Åstrand + + * Makefile.am: build test_acquire_cred + + * test_acquire_cred.c: simple gss_acquire_cred test + +2003-04-02 Love Hörnquist Åstrand + + * gss_acquire_cred.3: s/gssapi/GSS-API/ + +2003-03-19 Love Hörnquist Åstrand + + * gss_acquire_cred.3: document v1 interface (and that they are + obsolete) + +2003-03-18 Love Hörnquist Åstrand + + * gss_acquire_cred.3: list supported mechanism and nametypes + +2003-03-16 Love Hörnquist Åstrand + + * gss_acquire_cred.3: text about gss_display_name + + * Makefile.am (libgssapi_la_LDFLAGS): bump to 3:6:2 + (libgssapi_la_SOURCES): add all new functions + + * gssapi.3: now that we have a functions, uncomment the missing + ones + + * gss_acquire_cred.3: now that we have a functions, uncomment the + missing ones + + * process_context_token.c: implement gss_process_context_token + + * inquire_names_for_mech.c: implement gss_inquire_names_for_mech + + * inquire_mechs_for_name.c: implement gss_inquire_mechs_for_name + + * inquire_cred_by_mech.c: implement gss_inquire_cred_by_mech + + * add_cred.c: implement gss_add_cred + + * acquire_cred.c (gss_acquire_cred): more testing of input + argument, make sure output arguments are ok, since we don't know + the time_rec (for now), set it to time_req + + * export_sec_context.c: send lifetime, also set minor_status + + * get_mic.c: set minor_status + + * import_sec_context.c (gss_import_sec_context): add error + checking, pick up lifetime (if there is no lifetime, use + GSS_C_INDEFINITE) + + * init_sec_context.c: take care to set export value to something + sane before we start so caller will have harmless values in them + if then function fails + + * release_buffer.c (gss_release_buffer): set minor_status + + * wrap.c: make sure minor_status get set + + * verify_mic.c (gss_verify_mic_internal): rename verify_mic to + gss_verify_mic_internal and let it take the type as an argument, + (gss_verify_mic): call gss_verify_mic_internal + set minor_status + + * unwrap.c: set minor_status + + * test_oid_set_member.c (gss_test_oid_set_member): use + gss_oid_equal + + * release_oid_set.c (gss_release_oid_set): set minor_status + + * release_name.c (gss_release_name): set minor_status + + * release_cred.c (gss_release_cred): set minor_status + + * add_oid_set_member.c (gss_add_oid_set_member): set minor_status + + * compare_name.c (gss_compare_name): set minor_status + + * compat.c (check_compat): make sure ret have a defined value + + * context_time.c (gss_context_time): set minor_status + + * copy_ccache.c (gss_krb5_copy_ccache): set minor_status + + * create_emtpy_oid_set.c (gss_create_empty_oid_set): set + minor_status + + * delete_sec_context.c (gss_delete_sec_context): set minor_status + + * display_name.c (gss_display_name): set minor_status + + * display_status.c (gss_display_status): use gss_oid_equal, handle + supplementary errors + + * duplicate_name.c (gss_duplicate_name): set minor_status + + * inquire_context.c (gss_inquire_context): set lifetime_rec now + when we know it, set minor_status + + * inquire_cred.c (gss_inquire_cred): take care to set export value + to something sane before we start so caller will have harmless + values in them if the function fails + + * accept_sec_context.c (gss_accept_sec_context): take care to set + export value to something sane before we start so caller will have + harmless values in them if then function fails, set lifetime from + ticket expiration date + + * indicate_mechs.c (gss_indicate_mechs): use + gss_create_empty_oid_set and gss_add_oid_set_member + + * gssapi.h (gss_ctx_id_t_desc): store the lifetime in the cred, + since there is no ticket transfered in the exported context + + * export_name.c (gss_export_name): export name with + GSS_C_NT_EXPORT_NAME wrapping, not just the principal + + * import_name.c (import_export_name): new function, parses a + GSS_C_NT_EXPORT_NAME + (import_krb5_name): factor out common code of parsing krb5 name + (gss_oid_equal): rename from oid_equal + + * gssapi_locl.h: add prototypes for gss_oid_equal and + gss_verify_mic_internal + + * gssapi.h: comment out the argument names + +2003-03-15 Love Hörnquist Åstrand + + * gssapi.3: add LIST OF FUNCTIONS and copyright/license + + * Makefile.am: s/gss_aquire_cred.3/gss_acquire_cred.3/ + + * Makefile.am: man_MANS += gss_aquire_cred.3 + +2003-03-14 Love Hörnquist Åstrand + + * gss_aquire_cred.3: the gssapi api manpage + +2003-03-03 Love Hörnquist Åstrand + + * inquire_context.c: (gss_inquire_context): rename argument open + to open_context + + * gssapi.h (gss_inquire_context): rename argument open to open_context + +2003-02-27 Love Hörnquist Åstrand + + * init_sec_context.c (do_delegation): remove unused variable + subkey + + * gssapi.3: all 0.5.x version had broken token delegation + +2003-02-21 Love Hörnquist Åstrand + + * (init_auth): only generate one subkey + +2003-01-27 Love Hörnquist Åstrand + + * verify_mic.c (verify_mic_des3): fix 3des verify_mic to conform + to rfc (and mit kerberos), provide backward compat hook + + * get_mic.c (mic_des3): fix 3des get_mic to conform to rfc (and + mit kerberos), provide backward compat hook + + * init_sec_context.c (init_auth): check if we need compat for + older get_mic/verify_mic + + * gssapi_locl.h: add prototype for _gss_DES3_get_mic_compat + + * gssapi.h (more_flags): add COMPAT_OLD_DES3 + + * Makefile.am: add gssapi.3 and compat.c + + * gssapi.3: add gssapi COMPATIBILITY documentation + + * accept_sec_context.c (gss_accept_sec_context): check if we need + compat for older get_mic/verify_mic + + * compat.c: check for compatiblity with other heimdal's 3des + get_mic/verify_mic + +2002-10-31 Johan Danielsson + + * check return value from gssapi_krb5_init + + * 8003.c (gssapi_krb5_verify_8003_checksum): check size of input + +2002-09-03 Johan Danielsson + + * wrap.c (wrap_des3): use ETYPE_DES3_CBC_NONE + + * unwrap.c (unwrap_des3): use ETYPE_DES3_CBC_NONE + +2002-09-02 Johan Danielsson + + * init_sec_context.c: we need to generate a local subkey here + +2002-08-20 Jacques Vidrine + + * acquire_cred.c, inquire_cred.c, release_cred.c: Use default + credential resolution if gss_acquire_cred is called with + GSS_C_NO_NAME. + +2002-06-20 Jacques Vidrine + + * import_name.c: Compare name types by value if pointers do + not match. Reported by: "Douglas E. Engert" + +2002-05-20 Jacques Vidrine + + * verify_mic.c (gss_verify_mic), unwrap.c (gss_unwrap): initialize + the qop_state parameter. from Doug Rabson + +2002-05-09 Jacques Vidrine + + * acquire_cred.c: handle GSS_C_INITIATE/GSS_C_ACCEPT/GSS_C_BOTH + +2002-05-08 Jacques Vidrine + + * acquire_cred.c: initialize gssapi; handle null desired_name + +2002-03-22 Johan Danielsson + + * Makefile.am: remove non-functional stuff accidentally committed + +2002-03-11 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): bump version to 3:5:2 + * 8003.c (gssapi_krb5_verify_8003_checksum): handle zero channel + bindings + +2001-10-31 Jacques Vidrine + + * get_mic.c (mic_des3): MIC computation using DES3/SHA1 + was bogusly appending the message buffer to the result, + overwriting a heap buffer in the process. + +2001-08-29 Assar Westerlund + + * 8003.c (gssapi_krb5_verify_8003_checksum, + gssapi_krb5_create_8003_checksum): make more consistent by always + returning an gssapi error and setting minor status. update + callers + +2001-08-28 Jacques Vidrine + + * accept_sec_context.c: Create a cache for delegated credentials + when needed. + +2001-08-28 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): set version to 3:4:2 + +2001-08-23 Assar Westerlund + + * *.c: handle minor_status more consistently + + * display_status.c (gss_display_status): handle krb5_get_err_text + failing + +2001-08-15 Johan Danielsson + + * gssapi_locl.h: fix prototype for gssapi_krb5_init + +2001-08-13 Johan Danielsson + + * accept_sec_context.c (gsskrb5_register_acceptor_identity): init + context and check return value from kt_resolve + + * init.c: return error code + +2001-07-19 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): update to 3:3:2 + +2001-07-12 Assar Westerlund + + * Makefile.am (libgssapi_la_LIBADD): add required library + dependencies + +2001-07-06 Assar Westerlund + + * accept_sec_context.c (gsskrb5_register_acceptor_identity): set + the keytab to be used for gss_acquire_cred too' + +2001-07-03 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): set version to 3:2:2 + +2001-06-18 Assar Westerlund + + * wrap.c: replace gss_krb5_getsomekey with gss_krb5_get_localkey + and gss_krb5_get_remotekey + * verify_mic.c: update krb5_auth_con function names use + gss_krb5_get_remotekey + * unwrap.c: replace gss_krb5_getsomekey with gss_krb5_get_localkey + and gss_krb5_get_remotekey + * gssapi_locl.h (gss_krb5_get_remotekey, gss_krb5_get_localkey): + add prototypes + * get_mic.c: update krb5_auth_con function names. use + gss_krb5_get_localkey + * accept_sec_context.c: update krb5_auth_con function names + +2001-05-17 Assar Westerlund + + * Makefile.am: bump version to 3:1:2 + +2001-05-14 Assar Westerlund + + * address_to_krb5addr.c: adapt to new address functions + +2001-05-11 Assar Westerlund + + * try to return the error string from libkrb5 where applicable + +2001-05-08 Assar Westerlund + + * delete_sec_context.c (gss_delete_sec_context): remember to free + the memory used by the ticket itself. from + +2001-05-04 Assar Westerlund + + * gssapi_locl.h: add config.h for completeness + * gssapi.h: remove config.h, this is an installed header file + sys/types.h is not needed either + +2001-03-12 Assar Westerlund + + * acquire_cred.c (gss_acquire_cred): remove memory leaks. from + Jason R Thorpe + +2001-02-18 Assar Westerlund + + * accept_sec_context.c (gss_accept_sec_context): either return + gss_name NULL-ed or set + + * import_name.c: set minor_status in some cases where it was not + done + +2001-02-15 Assar Westerlund + + * wrap.c: use krb5_generate_random_block for the confounders + +2001-01-30 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): bump version to 3:0:2 + * acquire_cred.c, init_sec_context.c, release_cred.c: add support + for getting creds from a keytab, from fvdl@netbsd.org + + * copy_ccache.c: add gss_krb5_copy_ccache + +2001-01-27 Assar Westerlund + + * get_mic.c: cast parameters to des function to non-const pointers + to handle the case where these functions actually take non-const + des_cblock * + +2001-01-09 Assar Westerlund + + * accept_sec_context.c (gss_accept_sec_context): use krb5_rd_cred2 + instead of krb5_rd_cred + +2000-12-11 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): bump to 2:3:1 + +2000-12-08 Assar Westerlund + + * wrap.c (wrap_des3): use the checksum as ivec when encrypting the + sequence number + * unwrap.c (unwrap_des3): use the checksum as ivec when encrypting + the sequence number + * init_sec_context.c (init_auth): always zero fwd_data + +2000-12-06 Johan Danielsson + + * accept_sec_context.c: de-pointerise auth_context parameter to + krb5_mk_rep + +2000-11-15 Assar Westerlund + + * init_sec_context.c (init_auth): update to new + krb5_build_authenticator + +2000-09-19 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): bump to 2:2:1 + +2000-08-27 Assar Westerlund + + * init_sec_context.c: actually pay attention to `time_req' + * init_sec_context.c: re-organize. leak less memory. + * gssapi_locl.h (gssapi_krb5_encapsulate, gss_krb5_getsomekey): + update prototypes add assert.h + * gssapi.h (GSS_KRB5_CONF_C_QOP_DES, GSS_KRB5_CONF_C_QOP_DES3_KD): + add + * verify_mic.c: re-organize and add 3DES code + * wrap.c: re-organize and add 3DES code + * unwrap.c: re-organize and add 3DES code + * get_mic.c: re-organize and add 3DES code + * encapsulate.c (gssapi_krb5_encapsulate): do not free `in_data', + let the caller do that. fix the callers. + +2000-08-16 Assar Westerlund + + * Makefile.am: bump version to 2:1:1 + +2000-07-29 Assar Westerlund + + * decapsulate.c (gssapi_krb5_verify_header): sanity-check length + +2000-07-25 Johan Danielsson + + * Makefile.am: bump version to 2:0:1 + +2000-07-22 Assar Westerlund + + * gssapi.h: update OID for GSS_C_NT_HOSTBASED_SERVICE and other + details from rfc2744 + +2000-06-29 Assar Westerlund + + * address_to_krb5addr.c (gss_address_to_krb5addr): actually use + `int' instead of `sa_family_t' for the address family. + +2000-06-21 Assar Westerlund + + * add support for token delegation. From Daniel Kouril + and Miroslav Ruda + +2000-05-15 Assar Westerlund + + * Makefile.am (libgssapi_la_LDFLAGS): set version to 1:1:1 + +2000-04-12 Assar Westerlund + + * release_oid_set.c (gss_release_oid_set): clear set for + robustness. From GOMBAS Gabor + * release_name.c (gss_release_name): reset input_name for + robustness. From GOMBAS Gabor + * release_buffer.c (gss_release_buffer): set value to NULL to be + more robust. From GOMBAS Gabor + * add_oid_set_member.c (gss_add_oid_set_member): actually check if + the oid is a member first. leave the oid_set unchanged if realloc + fails. + +2000-02-13 Assar Westerlund + + * Makefile.am: set version to 1:0:1 + +2000-02-12 Assar Westerlund + + * gssapi_locl.h: add flags for import/export + * import_sec_context.c (import_sec_context: add flags for what + fields are included. do not include the authenticator for now. + * export_sec_context.c (export_sec_context: add flags for what + fields are included. do not include the authenticator for now. + * accept_sec_context.c (gss_accept_sec_context): set target in + context_handle + +2000-02-11 Assar Westerlund + + * delete_sec_context.c (gss_delete_sec_context): set context to + GSS_C_NO_CONTEXT + + * Makefile.am: add {export,import}_sec_context.c + * export_sec_context.c: new file + * import_sec_context.c: new file + * accept_sec_context.c (gss_accept_sec_context): set trans flag + +2000-02-07 Assar Westerlund + + * Makefile.am: set version to 0:5:0 + +2000-01-26 Assar Westerlund + + * delete_sec_context.c (gss_delete_sec_context): handle a NULL + output_token + + * wrap.c: update to pseudo-standard APIs for md4,md5,sha. some + changes to libdes calls to make them more portable. + * verify_mic.c: update to pseudo-standard APIs for md4,md5,sha. + some changes to libdes calls to make them more portable. + * unwrap.c: update to pseudo-standard APIs for md4,md5,sha. some + changes to libdes calls to make them more portable. + * get_mic.c: update to pseudo-standard APIs for md4,md5,sha. some + changes to libdes calls to make them more portable. + * 8003.c: update to pseudo-standard APIs for md4,md5,sha. + +2000-01-06 Assar Westerlund + + * Makefile.am: set version to 0:4:0 + +1999-12-26 Assar Westerlund + + * accept_sec_context.c (gss_accept_sec_context): always set + `output_token' + * init_sec_context.c (init_auth): always initialize `output_token' + * delete_sec_context.c (gss_delete_sec_context): always set + `output_token' + +1999-12-06 Assar Westerlund + + * Makefile.am: bump version to 0:3:0 + +1999-10-20 Assar Westerlund + + * Makefile.am: set version to 0:2:0 + +1999-09-21 Assar Westerlund + + * init_sec_context.c (gss_init_sec_context): initialize `ticket' + + * gssapi.h (gss_ctx_id_t_desc): add ticket in here. ick. + + * delete_sec_context.c (gss_delete_sec_context): free ticket + + * accept_sec_context.c (gss_accept_sec_context): stove away + `krb5_ticket' in context so that ugly programs such as + gss_nt_server can get at it. uck. + +1999-09-20 Johan Danielsson + + * accept_sec_context.c: set minor_status + +1999-08-04 Assar Westerlund + + * display_status.c (calling_error, routine_error): right shift the + code to make it possible to index into the arrays + +1999-07-28 Assar Westerlund + + * gssapi.h (GSS_C_AF_INET6): add + + * import_name.c (import_hostbased_name): set minor_status + +1999-07-26 Assar Westerlund + + * Makefile.am: set version to 0:1:0 + +Wed Apr 7 14:05:15 1999 Johan Danielsson + + * display_status.c: set minor_status + + * init_sec_context.c: set minor_status + + * lib/gssapi/init.c: remove donep (check gssapi_krb5_context + directly) + diff --git a/third_party/heimdal/lib/gssapi/Makefile.am b/third_party/heimdal/lib/gssapi/Makefile.am new file mode 100644 index 0000000..3cb8437 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/Makefile.am @@ -0,0 +1,470 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AUTOMAKE_OPTIONS = subdir-objects + +AM_CPPFLAGS += \ + -I$(top_srcdir)/lib \ + -I$(srcdir)/../krb5 \ + -I$(srcdir) \ + -I$(srcdir)/gssapi \ + -I$(srcdir)/mech \ + -I$(srcdir)/ntlm \ + -I$(srcdir)/krb5 \ + -I$(srcdir)/spnego \ + -I$(srcdir)/sanon \ + $(INCLUDE_libintl) + +lib_LTLIBRARIES = libgssapi.la test_negoex_mech.la + +krb5src = \ + krb5/8003.c \ + krb5/accept_sec_context.c \ + krb5/acquire_cred.c \ + krb5/add_cred.c \ + krb5/address_to_krb5addr.c \ + krb5/aeap.c \ + krb5/arcfour.c \ + krb5/canonicalize_name.c \ + krb5/creds.c \ + krb5/ccache_name.c \ + krb5/cfx.c \ + krb5/cfx.h \ + krb5/compare_name.c \ + krb5/compat.c \ + krb5/context_time.c \ + krb5/copy_ccache.c \ + krb5/decapsulate.c \ + krb5/delete_sec_context.c \ + krb5/display_name.c \ + krb5/display_status.c \ + krb5/duplicate_cred.c \ + krb5/duplicate_name.c \ + krb5/encapsulate.c \ + krb5/export_name.c \ + krb5/export_sec_context.c \ + krb5/external.c \ + krb5/get_mic.c \ + krb5/gsskrb5_locl.h \ + $(srcdir)/krb5/gsskrb5-private.h \ + krb5/import_name.c \ + krb5/import_sec_context.c \ + krb5/indicate_mechs.c \ + krb5/init.c \ + krb5/init_sec_context.c \ + krb5/inquire_context.c \ + krb5/inquire_cred.c \ + krb5/inquire_cred_by_mech.c \ + krb5/inquire_cred_by_oid.c \ + krb5/inquire_mechs_for_name.c \ + krb5/inquire_names_for_mech.c \ + krb5/inquire_sec_context_by_oid.c \ + krb5/name_attrs.c \ + krb5/pname_to_uid.c \ + krb5/process_context_token.c \ + krb5/prf.c \ + krb5/release_buffer.c \ + krb5/release_cred.c \ + krb5/release_name.c \ + krb5/sequence.c \ + krb5/store_cred.c \ + krb5/set_cred_option.c \ + krb5/set_sec_context_option.c \ + krb5/ticket_flags.c \ + krb5/unwrap.c \ + krb5/authorize_localname.c \ + krb5/verify_mic.c \ + krb5/wrap.c + +mechsrc = \ + mech/context.h \ + mech/context.c \ + mech/cred.h \ + mech/cred.c \ + mech/compat.h \ + mech/doxygen.c \ + mech/gss_accept_sec_context.c \ + mech/gss_acquire_cred.c \ + mech/gss_acquire_cred_from.c \ + mech/gss_acquire_cred_impersonate_name.c \ + mech/gss_acquire_cred_with_password.c \ + mech/gss_add_cred.c \ + mech/gss_add_cred_from.c \ + mech/gss_add_cred_with_password.c \ + mech/gss_add_oid_set_member.c \ + mech/gss_aeap.c \ + mech/gss_buffer_set.c \ + mech/gss_canonicalize_name.c \ + mech/gss_compare_name.c \ + mech/gss_context_time.c \ + mech/gss_create_empty_oid_set.c \ + mech/gss_cred.c \ + mech/gss_decapsulate_token.c \ + mech/gss_delete_name_attribute.c \ + mech/gss_delete_sec_context.c \ + mech/gss_destroy_cred.c \ + mech/gss_display_name.c \ + mech/gss_display_name_ext.c \ + mech/gss_display_status.c \ + mech/gss_duplicate_cred.c \ + mech/gss_duplicate_name.c \ + mech/gss_duplicate_oid.c \ + mech/gss_duplicate_oid_set.c \ + mech/gss_encapsulate_token.c \ + mech/gss_export_name.c \ + mech/gss_export_name_composite.c \ + mech/gss_export_sec_context.c \ + mech/gss_get_mic.c \ + mech/gss_get_neg_mechs.c \ + mech/gss_get_name_attribute.c \ + mech/gss_import_name.c \ + mech/gss_import_sec_context.c \ + mech/gss_indicate_mechs.c \ + mech/gss_init_sec_context.c \ + mech/gss_inquire_context.c \ + mech/gss_inquire_cred.c \ + mech/gss_inquire_cred_by_mech.c \ + mech/gss_inquire_cred_by_oid.c \ + mech/gss_inquire_mechs_for_name.c \ + mech/gss_inquire_name.c \ + mech/gss_inquire_names_for_mech.c \ + mech/gss_krb5.c \ + mech/gss_mech_switch.c \ + mech/gss_mo.c \ + mech/gss_names.c \ + mech/gss_oid.c \ + mech/gss_oid_equal.c \ + mech/gss_oid_to_str.c \ + mech/gss_pname_to_uid.c \ + mech/gss_process_context_token.c \ + mech/gss_pseudo_random.c \ + mech/gss_release_buffer.c \ + mech/gss_release_cred.c \ + mech/gss_release_name.c \ + mech/gss_release_oid.c \ + mech/gss_release_oid_set.c \ + mech/gss_rfc4121.c \ + mech/gss_seal.c \ + mech/gss_set_cred_option.c \ + mech/gss_set_name_attribute.c \ + mech/gss_set_neg_mechs.c \ + mech/gss_set_sec_context_option.c \ + mech/gss_sign.c \ + mech/gss_store_cred.c \ + mech/gss_store_cred_into.c \ + mech/gss_test_oid_set_member.c \ + mech/gss_unseal.c \ + mech/gss_unwrap.c \ + mech/gss_authorize_localname.c \ + mech/gss_utils.c \ + mech/gss_verify.c \ + mech/gss_verify_mic.c \ + mech/gss_wrap.c \ + mech/gss_wrap_size_limit.c \ + mech/gss_inquire_sec_context_by_oid.c \ + mech/gssspi_exchange_meta_data.c \ + mech/gssspi_query_mechanism_info.c \ + mech/gssspi_query_meta_data.c \ + mech/mech_switch.h \ + mech/mech_locl.h \ + mech/name.h \ + mech/utils.h + +spnegosrc = \ + spnego/accept_sec_context.c \ + spnego/compat.c \ + spnego/context_storage.c \ + spnego/context_stubs.c \ + spnego/external.c \ + spnego/init_sec_context.c \ + spnego/negoex_ctx.c \ + spnego/negoex_util.c \ + spnego/spnego_locl.h \ + spnego/negoex_locl.h \ + $(srcdir)/spnego/spnego-private.h + +ntlmsrc = \ + ntlm/accept_sec_context.c \ + ntlm/acquire_cred.c \ + ntlm/add_cred.c \ + ntlm/canonicalize_name.c \ + ntlm/compare_name.c \ + ntlm/context_time.c \ + ntlm/creds.c \ + ntlm/crypto.c \ + ntlm/delete_sec_context.c \ + ntlm/display_name.c \ + ntlm/display_status.c \ + ntlm/duplicate_name.c \ + ntlm/export_name.c \ + ntlm/export_sec_context.c \ + ntlm/external.c \ + ntlm/ntlm.h \ + ntlm/import_name.c \ + ntlm/import_sec_context.c \ + ntlm/indicate_mechs.c \ + ntlm/init_sec_context.c \ + ntlm/inquire_context.c \ + ntlm/inquire_cred_by_mech.c \ + ntlm/inquire_mechs_for_name.c \ + ntlm/inquire_names_for_mech.c \ + ntlm/inquire_sec_context_by_oid.c \ + ntlm/iter_cred.c \ + ntlm/process_context_token.c \ + ntlm/release_cred.c \ + ntlm/release_name.c \ + ntlm/set_sec_context_option.c \ + ntlm/kdc.c + +$(srcdir)/ntlm/ntlm-private.h: $(ntlmsrc) + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p ntlm/ntlm-private.h $(ntlmsrc) || rm -f ntlm/ntlm-private.h + +sanonsrc = \ + sanon/accept_sec_context.c \ + sanon/acquire_cred.c \ + sanon/add_cred.c \ + sanon/canonicalize_name.c \ + sanon/compare_name.c \ + sanon/context_time.c \ + sanon/crypto.c \ + sanon/delete_sec_context.c \ + sanon/display_name.c \ + sanon/display_status.c \ + sanon/duplicate_cred.c \ + sanon/duplicate_name.c \ + sanon/export_name.c \ + sanon/export_cred.c \ + sanon/export_sec_context.c \ + sanon/external.c \ + sanon/import_cred.c \ + sanon/import_name.c \ + sanon/import_sec_context.c \ + sanon/init_sec_context.c \ + sanon/inquire_context.c \ + sanon/inquire_cred.c \ + sanon/inquire_cred_by_mech.c \ + sanon/inquire_mechs_for_name.c \ + sanon/inquire_names_for_mech.c \ + sanon/inquire_sec_context_by_oid.c \ + sanon/negoex.c \ + sanon/process_context_token.c \ + sanon/release_cred.c \ + sanon/release_name.c \ + sanon/sanon_locl.h \ + sanon/sanon-private.h + +dist_libgssapi_la_SOURCES = \ + $(krb5src) \ + $(mechsrc) \ + $(ntlmsrc) \ + $(spnegosrc) \ + $(sanonsrc) + +nodist_libgssapi_la_SOURCES = \ + $(BUILT_SOURCES) + +libgssapi_la_DEPENDENCIES = version-script.map + +libgssapi_la_LDFLAGS = -version-info 3:0:0 + +if versionscript +libgssapi_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +libgssapi_la_LIBADD = \ + $(top_builddir)/lib/ntlm/libheimntlm.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_com_err) \ + $(LIB_hcrypto) \ + $(LIBADD_roken) + +man_MANS = gssapi.3 gss_acquire_cred.3 mech/mech.5 gss-token.1 + +include_HEADERS = gssapi.h +noinst_HEADERS = \ + gssapi_asn1.h \ + gssapi_mech.h \ + $(srcdir)/ntlm/ntlm-private.h \ + $(srcdir)/spnego/spnego-private.h \ + $(srcdir)/sanon/sanon-private.h \ + $(srcdir)/krb5/gsskrb5-private.h + +nobase_include_HEADERS = \ + gssapi/gssapi.h \ + gssapi/gssapi_krb5.h \ + gssapi/gssapi_ntlm.h \ + gssapi/gssapi_oid.h \ + gssapi/gssapi_spnego.h + +gssapidir = $(includedir)/gssapi +nodist_gssapi_HEADERS = gkrb5_err.h negoex_err.h + +gssapi_files = \ + asn1_GSSAPIContextToken.c + +spnego_files = \ + asn1_ContextFlags.c \ + asn1_MechType.c \ + asn1_MechTypeList.c \ + asn1_NegHints.c \ + asn1_NegStateEnum.c \ + asn1_NegTokenInit.c \ + asn1_NegTokenInit2.c \ + asn1_NegTokenResp.c \ + asn1_NegotiationToken.c \ + asn1_NegotiationToken2.c + +BUILTHEADERS = \ + $(srcdir)/krb5/gsskrb5-private.h \ + $(srcdir)/spnego/spnego-private.h \ + $(srcdir)/sanon/sanon-private.h \ + $(srcdir)/ntlm/ntlm-private.h + +$(libgssapi_la_OBJECTS): $(BUILTHEADERS) +$(test_context_OBJECTS): $(BUILTHEADERS) + +$(libgssapi_la_OBJECTS): $(srcdir)/version-script.map + +BUILT_SOURCES = \ + $(spnego_files) \ + $(gssapi_files) \ + gkrb5_err.c \ + gkrb5_err.h \ + negoex_err.c \ + negoex_err.h + +$(libgssapi_la_OBJECTS): gkrb5_err.h negoex_err.h +gkrb5_err.h: $(srcdir)/krb5/gkrb5_err.et +negoex_err.h: $(srcdir)/spnego/negoex_err.et + +CLEANFILES = $(BUILT_SOURCES) \ + gkrb5_err.[ch] negoex_err.[ch] \ + $(spnego_files) spnego_asn1*.h* spnego_asn1_files spnego_asn1-template.[cx] \ + $(gssapi_files) gssapi_asn1*.h* gssapi_asn1_files gssapi_asn1-template.[cx] \ + gss-commands.h gss-commands.c \ + gssapi_asn1.json gssapi_asn1_oids.c gssapi_asn1_syms.c \ + spnego_asn1.json spnego_asn1_oids.c spnego_asn1_syms.c + +$(spnego_files) spnego_asn1.h spnego_asn1-priv.h: spnego_asn1_files + for genfile in '$(spnego_files)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done + +$(gssapi_files) gssapi_asn1.h gssapi_asn1-priv.h: gssapi_asn1_files + for genfile in '$(gssapi_files)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done + +spnego_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/spnego/spnego.asn1 $(srcdir)/spnego/spnego.opt + $(ASN1_COMPILE) --option-file=$(srcdir)/spnego/spnego.opt $(srcdir)/spnego/spnego.asn1 spnego_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat spnego_asn1_files) + +gssapi_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/mech/gssapi.asn1 + $(ASN1_COMPILE) $(srcdir)/mech/gssapi.asn1 gssapi_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat gssapi_asn1_files) + +$(srcdir)/krb5/gsskrb5-private.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p krb5/gsskrb5-private.h $(krb5src) || rm -f krb5/gsskrb5-private.h + +$(srcdir)/spnego/spnego-private.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p spnego/spnego-private.h $(spnegosrc) || rm -f spnego/spnego-private.h + +$(srcdir)/sanon/sanon-private.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p sanon/sanon-private.h $(sanonsrc) || rm -f sanon/sanon-private.h + +TESTS = test_oid test_names test_cfx +# test_sequence + +test_cfx_SOURCES = krb5/test_cfx.c + +check_PROGRAMS = test_acquire_cred $(TESTS) + +bin_PROGRAMS = gsstool gss-token +noinst_PROGRAMS = test_cred test_kcred test_context test_ntlm test_add_store_cred + +test_context_SOURCES = test_context.c test_common.c test_common.h +test_ntlm_SOURCES = test_ntlm.c test_common.c test_common.h +test_acquire_cred_SOURCES = test_acquire_cred.c test_common.c test_common.h + +test_add_store_cred_SOURCES = test_add_store_cred.c + +test_ntlm_LDADD = \ + $(top_builddir)/lib/ntlm/libheimntlm.la \ + $(LDADD) + +LDADD = libgssapi.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_roken) + +test_names_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la +test_context_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la $(top_builddir)/lib/wind/libwind.la + +# gss + +dist_gsstool_SOURCES = gsstool.c +nodist_gsstool_SOURCES = gss-commands.c gss-commands.h +dist_gss_token_SOURCES = gss-token.c + +gsstool_LDADD = libgssapi.la \ + $(top_builddir)/lib/sl/libsl.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_readline) \ + $(LIB_roken) + +gss_token_LDADD = libgssapi.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_roken) + +gss-commands.c gss-commands.h: gss-commands.in + $(SLC) $(srcdir)/gss-commands.in + +$(gsstool_OBJECTS): gss-commands.h + +EXTRA_DIST = \ + NTMakefile \ + libgssapi-version.rc \ + libgssapi-exports.def \ + $(man_MANS) \ + gen-oid.pl \ + gssapi/gssapi_netlogon.h \ + krb5/test_acquire_cred.c \ + krb5/test_cred.c \ + krb5/test_kcred.c \ + krb5/test_oid.c \ + oid.txt \ + krb5/gkrb5_err.et \ + mech/gssapi.asn1 \ + spnego/spnego.asn1 \ + spnego/spnego.opt \ + spnego/negoex_err.et \ + test_negoex_mech.c \ + version-script.map \ + gss-commands.in + +$(libgssapi_la_OBJECTS): gkrb5_err.h gssapi_asn1.h gssapi_asn1-priv.h +$(libgssapi_la_OBJECTS): spnego_asn1.h spnego_asn1-priv.h +$(libgssapi_la_OBJECTS): $(srcdir)/gssapi/gssapi_oid.h + +gkrb5_err.h gkrb5_err.c: $(srcdir)/krb5/gkrb5_err.et + $(COMPILE_ET) $(srcdir)/krb5/gkrb5_err.et + +negoex_err.h negoex_err.c: $(srcdir)/spnego/negoex_err.et + $(COMPILE_ET) $(srcdir)/spnego/negoex_err.et + +$(srcdir)/gssapi/gssapi_oid.h $(srcdir)/mech/gss_oid.c: + perl $(srcdir)/gen-oid.pl -b base -h $(srcdir)/oid.txt > $(srcdir)/gssapi/gssapi_oid.h + perl $(srcdir)/gen-oid.pl -b base $(srcdir)/oid.txt > $(srcdir)/mech/gss_oid.c + +# +# NegoEx test mechanism, uses decode_GSSAPIContextToken +# + +test_negoex_mech_la_SOURCES = test_negoex_mech.c $(gssapi_files) +test_negoex_mech_la_LDFLAGS = -module +test_negoex_mech_la_LIBADD = \ + $(top_builddir)/lib/asn1/libasn1.la \ + libgssapi.la diff --git a/third_party/heimdal/lib/gssapi/NTMakefile b/third_party/heimdal/lib/gssapi/NTMakefile new file mode 100644 index 0000000..ffba9d5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/NTMakefile @@ -0,0 +1,747 @@ +######################################################################## +# +# Copyright (c) 2009-2011 Secure Endpoints Inc. +# Copyright (c) 2018 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\gssapi + +intcflags=-DASN1_LIB + +!include ../../windows/NTMakefile.w32 + +krb5src = \ + krb5/8003.c \ + krb5/accept_sec_context.c \ + krb5/acquire_cred.c \ + krb5/add_cred.c \ + krb5/address_to_krb5addr.c \ + krb5/aeap.c \ + krb5/arcfour.c \ + krb5/authorize_localname.c \ + krb5/canonicalize_name.c \ + krb5/creds.c \ + krb5/ccache_name.c \ + krb5/cfx.c \ + krb5/cfx.h \ + krb5/compare_name.c \ + krb5/compat.c \ + krb5/context_time.c \ + krb5/copy_ccache.c \ + krb5/decapsulate.c \ + krb5/delete_sec_context.c \ + krb5/display_name.c \ + krb5/display_status.c \ + krb5/duplicate_name.c \ + krb5/duplicate_cred.c \ + krb5/encapsulate.c \ + krb5/export_name.c \ + krb5/export_sec_context.c \ + krb5/external.c \ + krb5/get_mic.c \ + krb5/gsskrb5_locl.h \ + krb5/import_name.c \ + krb5/import_sec_context.c \ + krb5/indicate_mechs.c \ + krb5/init.c \ + krb5/init_sec_context.c \ + krb5/inquire_context.c \ + krb5/inquire_cred.c \ + krb5/inquire_cred_by_mech.c \ + krb5/inquire_cred_by_oid.c \ + krb5/inquire_mechs_for_name.c \ + krb5/inquire_names_for_mech.c \ + krb5/inquire_sec_context_by_oid.c \ + krb5/name_attrs.c \ + krb5/pname_to_uid.c \ + krb5/process_context_token.c \ + krb5/prf.c \ + krb5/release_buffer.c \ + krb5/release_cred.c \ + krb5/release_name.c \ + krb5/sequence.c \ + krb5/store_cred.c \ + krb5/set_cred_option.c \ + krb5/set_sec_context_option.c \ + krb5/ticket_flags.c \ + krb5/unwrap.c \ + krb5/verify_mic.c \ + krb5/wrap.c + +mechsrc = \ + mech/context.h \ + mech/context.c \ + mech/cred.h \ + mech/cred.c \ + mech/gss_accept_sec_context.c \ + mech/gss_acquire_cred.c \ + mech/gss_acquire_cred_from.c \ + mech/gss_acquire_cred_impersonate_name.c \ + mech/gss_acquire_cred_with_password.c \ + mech/gss_add_cred.c \ + mech/gss_add_cred_from.c \ + mech/gss_add_cred_with_password.c \ + mech/gss_add_oid_set_member.c \ + mech/gss_aeap.c \ + mech/gss_authorize_localname.c \ + mech/gss_buffer_set.c \ + mech/gss_canonicalize_name.c \ + mech/gss_compare_name.c \ + mech/gss_context_time.c \ + mech/gss_create_empty_oid_set.c \ + mech/gss_cred.c \ + mech/gss_decapsulate_token.c \ + mech/gss_delete_name_attribute.c \ + mech/gss_delete_sec_context.c \ + mech/gss_destroy_cred.c \ + mech/gss_display_name.c \ + mech/gss_display_name_ext.c \ + mech/gss_display_status.c \ + mech/gss_duplicate_name.c \ + mech/gss_duplicate_cred.c \ + mech/gss_duplicate_oid.c \ + mech/gss_duplicate_oid_set.c \ + mech/gss_encapsulate_token.c \ + mech/gss_export_name.c \ + mech/gss_export_name_composite.c \ + mech/gss_export_sec_context.c \ + mech/gss_get_mic.c \ + mech/gss_get_neg_mechs.c \ + mech/gss_get_name_attribute.c \ + mech/gss_import_name.c \ + mech/gss_import_sec_context.c \ + mech/gss_indicate_mechs.c \ + mech/gss_init_sec_context.c \ + mech/gss_inquire_context.c \ + mech/gss_inquire_cred.c \ + mech/gss_inquire_cred_by_mech.c \ + mech/gss_inquire_cred_by_oid.c \ + mech/gss_inquire_mechs_for_name.c \ + mech/gss_inquire_name.c \ + mech/gss_inquire_names_for_mech.c \ + mech/gss_krb5.c \ + mech/gss_mech_switch.c \ + mech/gss_mo.c \ + mech/gss_names.c \ + mech/gss_oid.c \ + mech/gss_oid_equal.c \ + mech/gss_oid_to_str.c \ + mech/gss_pname_to_uid.c \ + mech/gss_process_context_token.c \ + mech/gss_pseudo_random.c \ + mech/gss_release_buffer.c \ + mech/gss_release_cred.c \ + mech/gss_release_name.c \ + mech/gss_release_oid.c \ + mech/gss_release_oid_set.c \ + mech/gss_rfc4121.c \ + mech/gss_seal.c \ + mech/gss_set_cred_option.c \ + mech/gss_set_name_attribute.c \ + mech/gss_set_neg_mechs.c \ + mech/gss_set_sec_context_option.c \ + mech/gss_sign.c \ + mech/gss_store_cred.c \ + mech/gss_store_cred_into.c \ + mech/gss_test_oid_set_member.c \ + mech/gss_unseal.c \ + mech/gss_unwrap.c \ + mech/gss_utils.c \ + mech/gss_verify.c \ + mech/gss_verify_mic.c \ + mech/gss_wrap.c \ + mech/gss_wrap_size_limit.c \ + mech/gss_inquire_sec_context_by_oid.c \ + mech/gssspi_exchange_meta_data.c \ + mech/gssspi_query_mechanism_info.c \ + mech/gssspi_query_meta_data.c \ + mech/mech_switch.h \ + mech/mech_locl.h \ + mech/name.h \ + mech/utils.h + +spnegosrc = \ + spnego/accept_sec_context.c \ + spnego/compat.c \ + spnego/context_storage.c \ + spnego/context_stubs.c \ + spnego/external.c \ + spnego/init_sec_context.c \ + spnego/negoex_ctx.c \ + spnego/negoex_util.c \ + spnego/spnego_locl.h \ + spnego/negoex_locl.h + +ntlmsrc = \ + ntlm/accept_sec_context.c \ + ntlm/acquire_cred.c \ + ntlm/add_cred.c \ + ntlm/canonicalize_name.c \ + ntlm/compare_name.c \ + ntlm/context_time.c \ + ntlm/creds.c \ + ntlm/crypto.c \ + ntlm/delete_sec_context.c \ + ntlm/display_name.c \ + ntlm/display_status.c \ + ntlm/duplicate_name.c \ + ntlm/duplicate_cred.c \ + ntlm/export_name.c \ + ntlm/export_sec_context.c \ + ntlm/external.c \ + ntlm/ntlm.h \ + ntlm/import_name.c \ + ntlm/import_sec_context.c \ + ntlm/indicate_mechs.c \ + ntlm/init_sec_context.c \ + ntlm/inquire_context.c \ + ntlm/inquire_cred_by_mech.c \ + ntlm/inquire_mechs_for_name.c \ + ntlm/inquire_names_for_mech.c \ + ntlm/inquire_sec_context_by_oid.c \ + ntlm/iter_cred.c \ + ntlm/process_context_token.c \ + ntlm/release_cred.c \ + ntlm/release_name.c \ + ntlm/set_sec_context_option.c \ + ntlm/kdc.c + +sanonsrc = \ + sanon/accept_sec_context.c \ + sanon/acquire_cred.c \ + sanon/add_cred.c \ + sanon/canonicalize_name.c \ + sanon/compare_name.c \ + sanon/context_time.c \ + sanon/crypto.c \ + sanon/delete_sec_context.c \ + sanon/display_name.c \ + sanon/display_status.c \ + sanon/duplicate_cred.c \ + sanon/duplicate_name.c \ + sanon/export_cred.c \ + sanon/export_name.c \ + sanon/export_sec_context.c \ + sanon/external.c \ + sanon/import_cred.c \ + sanon/import_name.c \ + sanon/import_sec_context.c \ + sanon/init_sec_context.c \ + sanon/inquire_context.c \ + sanon/inquire_cred.c \ + sanon/inquire_cred_by_mech.c \ + sanon/inquire_mechs_for_name.c \ + sanon/inquire_names_for_mech.c \ + sanon/inquire_sec_context_by_oid.c \ + sanon/negoex.c \ + sanon/process_context_token.c \ + sanon/release_cred.c \ + sanon/release_name.c + +$(OBJ)\ntlm\ntlm-private.h: $(ntlmsrc) + $(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(ntlmsrc) + +$(OBJ)\krb5\gsskrb5-private.h: $(krb5src) + $(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(krb5src) + +$(OBJ)\spnego\spnego-private.h: $(spnegosrc) + $(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(spnegosrc) + +$(OBJ)\sanon\sanon-private.h: $(sanonsrc) + $(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(sanonsrc) + +$(OBJ)\gssapi\asn1_gssapi_asn1.c $(OBJ)\gssapi\gssapi_asn1.h $(OBJ)\gssapi\gssapi_asn1-priv.h: \ +$(BINDIR)\asn1_compile.exe mech\gssapi.asn1 + cd $(OBJ)\gssapi + $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\mech\gssapi.asn1 gssapi_asn1 \ + || ( $(RM) $(OBJ)\gssapi\gssapi_asn1.h ; exit /b 1 ) + cd $(SRCDIR) + +$(OBJ)\spnego\asn1_spnego_asn1.c $(OBJ)\spnego\spnego_asn1.h $(OBJ)\spnego\spnego_asn1-priv.h: \ +$(BINDIR)\asn1_compile.exe spnego\spnego.asn1 + cd $(OBJ)\spnego + $(BINDIR)\asn1_compile --one-code-file --sequence=MechTypeList \ + $(SRCDIR)\spnego\spnego.asn1 spnego_asn1 \ + || ( $(RM) $(OBJ)\spnego\spnego_asn1.h ; exit /b 1 ) + cd $(SRCDIR) + +$(OBJ)\gkrb5_err.c $(OBJ)\gkrb5_err.h: krb5\gkrb5_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\krb5\gkrb5_err.et + cd $(SRCDIR) + +$(OBJ)\negoex_err.c $(OBJ)\negoex_err.h: spnego\negoex_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\spnego\negoex_err.et + cd $(SRCDIR) + +INCFILES= \ + $(INCDIR)\gssapi.h \ + $(INCDIR)\gssapi\gssapi.h \ + $(INCDIR)\gssapi\gssapi_krb5.h \ + $(INCDIR)\gssapi\gssapi_oid.h \ + $(INCDIR)\gssapi\gssapi_ntlm.h \ + $(INCDIR)\gssapi\gssapi_spnego.h \ + $(INCDIR)\gssapi\gkrb5_err.h \ + $(OBJ)\ntlm\ntlm-private.h \ + $(OBJ)\spnego\spnego-private.h \ + $(OBJ)\sanon\sanon-private.h \ + $(OBJ)\krb5\gsskrb5-private.h \ + $(OBJ)\gkrb5_err.h \ + $(OBJ)\negoex_err.h \ + $(OBJ)\gssapi\gssapi_asn1.h \ + $(OBJ)\gssapi\gssapi_asn1-priv.h \ + $(OBJ)\spnego\spnego_asn1.h \ + $(OBJ)\spnego\spnego_asn1-priv.h + +all:: $(INCFILES) + +libgssapi_OBJs = \ + $(OBJ)\krb5/8003.obj \ + $(OBJ)\krb5/accept_sec_context.obj \ + $(OBJ)\krb5/acquire_cred.obj \ + $(OBJ)\krb5/add_cred.obj \ + $(OBJ)\krb5/address_to_krb5addr.obj \ + $(OBJ)\krb5/authorize_localname.obj \ + $(OBJ)\krb5/aeap.obj \ + $(OBJ)\krb5/arcfour.obj \ + $(OBJ)\krb5/canonicalize_name.obj \ + $(OBJ)\krb5/creds.obj \ + $(OBJ)\krb5/ccache_name.obj \ + $(OBJ)\krb5/cfx.obj \ + $(OBJ)\krb5/compare_name.obj \ + $(OBJ)\krb5/compat.obj \ + $(OBJ)\krb5/context_time.obj \ + $(OBJ)\krb5/copy_ccache.obj \ + $(OBJ)\krb5/decapsulate.obj \ + $(OBJ)\krb5/delete_sec_context.obj \ + $(OBJ)\krb5/display_name.obj \ + $(OBJ)\krb5/display_status.obj \ + $(OBJ)\krb5/duplicate_cred.obj \ + $(OBJ)\krb5/duplicate_name.obj \ + $(OBJ)\krb5/encapsulate.obj \ + $(OBJ)\krb5/export_name.obj \ + $(OBJ)\krb5/export_sec_context.obj \ + $(OBJ)\krb5/external.obj \ + $(OBJ)\krb5/get_mic.obj \ + $(OBJ)\krb5/import_name.obj \ + $(OBJ)\krb5/import_sec_context.obj \ + $(OBJ)\krb5/indicate_mechs.obj \ + $(OBJ)\krb5/init.obj \ + $(OBJ)\krb5/init_sec_context.obj \ + $(OBJ)\krb5/inquire_context.obj \ + $(OBJ)\krb5/inquire_cred.obj \ + $(OBJ)\krb5/inquire_cred_by_mech.obj \ + $(OBJ)\krb5/inquire_cred_by_oid.obj \ + $(OBJ)\krb5/inquire_mechs_for_name.obj \ + $(OBJ)\krb5/inquire_names_for_mech.obj \ + $(OBJ)\krb5/inquire_sec_context_by_oid.obj \ + $(OBJ)\krb5/name_attrs.obj \ + $(OBJ)\krb5/pname_to_uid.obj \ + $(OBJ)\krb5/process_context_token.obj \ + $(OBJ)\krb5/prf.obj \ + $(OBJ)\krb5/release_buffer.obj \ + $(OBJ)\krb5/release_cred.obj \ + $(OBJ)\krb5/release_name.obj \ + $(OBJ)\krb5/sequence.obj \ + $(OBJ)\krb5/store_cred.obj \ + $(OBJ)\krb5/set_cred_option.obj \ + $(OBJ)\krb5/set_sec_context_option.obj \ + $(OBJ)\krb5/ticket_flags.obj \ + $(OBJ)\krb5/unwrap.obj \ + $(OBJ)\krb5/verify_mic.obj \ + $(OBJ)\krb5/wrap.obj \ + $(OBJ)\mech/context.obj \ + $(OBJ)\mech/cred.obj \ + $(OBJ)\mech/gss_accept_sec_context.obj \ + $(OBJ)\mech/gss_acquire_cred.obj \ + $(OBJ)\mech/gss_acquire_cred_from.obj \ + $(OBJ)\mech/gss_acquire_cred_impersonate_name.obj \ + $(OBJ)\mech/gss_acquire_cred_with_password.obj \ + $(OBJ)\mech/gss_add_cred.obj \ + $(OBJ)\mech/gss_add_cred_from.obj \ + $(OBJ)\mech/gss_add_cred_with_password.obj \ + $(OBJ)\mech/gss_add_oid_set_member.obj \ + $(OBJ)\mech/gss_aeap.obj \ + $(OBJ)\mech/gss_authorize_localname.obj \ + $(OBJ)\mech/gss_buffer_set.obj \ + $(OBJ)\mech/gss_canonicalize_name.obj \ + $(OBJ)\mech/gss_compare_name.obj \ + $(OBJ)\mech/gss_context_time.obj \ + $(OBJ)\mech/gss_create_empty_oid_set.obj \ + $(OBJ)\mech/gss_cred.obj \ + $(OBJ)\mech/gss_decapsulate_token.obj \ + $(OBJ)\mech/gss_delete_name_attribute.obj \ + $(OBJ)\mech/gss_delete_sec_context.obj \ + $(OBJ)\mech/gss_destroy_cred.obj \ + $(OBJ)\mech/gss_display_name.obj \ + $(OBJ)\mech/gss_display_name_ext.obj \ + $(OBJ)\mech/gss_display_status.obj \ + $(OBJ)\mech/gss_duplicate_cred.obj \ + $(OBJ)\mech/gss_duplicate_name.obj \ + $(OBJ)\mech/gss_duplicate_oid.obj \ + $(OBJ)\mech/gss_duplicate_oid_set.obj \ + $(OBJ)\mech/gss_encapsulate_token.obj \ + $(OBJ)\mech/gss_export_name.obj \ + $(OBJ)\mech/gss_export_name_composite.obj \ + $(OBJ)\mech/gss_export_sec_context.obj \ + $(OBJ)\mech/gss_get_mic.obj \ + $(OBJ)\mech/gss_get_neg_mechs.obj \ + $(OBJ)\mech/gss_get_name_attribute.obj \ + $(OBJ)\mech/gss_import_name.obj \ + $(OBJ)\mech/gss_import_sec_context.obj \ + $(OBJ)\mech/gss_indicate_mechs.obj \ + $(OBJ)\mech/gss_init_sec_context.obj \ + $(OBJ)\mech/gss_inquire_context.obj \ + $(OBJ)\mech/gss_inquire_cred.obj \ + $(OBJ)\mech/gss_inquire_cred_by_mech.obj \ + $(OBJ)\mech/gss_inquire_cred_by_oid.obj \ + $(OBJ)\mech/gss_inquire_mechs_for_name.obj \ + $(OBJ)\mech/gss_inquire_name.obj \ + $(OBJ)\mech/gss_inquire_names_for_mech.obj \ + $(OBJ)\mech/gss_krb5.obj \ + $(OBJ)\mech/gss_mech_switch.obj \ + $(OBJ)\mech/gss_mo.obj \ + $(OBJ)\mech/gss_names.obj \ + $(OBJ)\mech/gss_oid.obj \ + $(OBJ)\mech/gss_oid_equal.obj \ + $(OBJ)\mech/gss_oid_to_str.obj \ + $(OBJ)\mech/gss_pname_to_uid.obj \ + $(OBJ)\mech/gss_process_context_token.obj \ + $(OBJ)\mech/gss_pseudo_random.obj \ + $(OBJ)\mech/gss_release_buffer.obj \ + $(OBJ)\mech/gss_release_cred.obj \ + $(OBJ)\mech/gss_release_name.obj \ + $(OBJ)\mech/gss_release_oid.obj \ + $(OBJ)\mech/gss_release_oid_set.obj \ + $(OBJ)\mech/gss_rfc4121.obj \ + $(OBJ)\mech/gss_seal.obj \ + $(OBJ)\mech/gss_set_cred_option.obj \ + $(OBJ)\mech/gss_set_name_attribute.obj \ + $(OBJ)\mech/gss_set_neg_mechs.obj \ + $(OBJ)\mech/gss_set_sec_context_option.obj \ + $(OBJ)\mech/gss_sign.obj \ + $(OBJ)\mech/gss_store_cred.obj \ + $(OBJ)\mech/gss_store_cred_into.obj \ + $(OBJ)\mech/gss_test_oid_set_member.obj \ + $(OBJ)\mech/gss_unseal.obj \ + $(OBJ)\mech/gss_unwrap.obj \ + $(OBJ)\mech/gss_utils.obj \ + $(OBJ)\mech/gss_verify.obj \ + $(OBJ)\mech/gss_verify_mic.obj \ + $(OBJ)\mech/gss_wrap.obj \ + $(OBJ)\mech/gss_wrap_size_limit.obj \ + $(OBJ)\mech/gss_inquire_sec_context_by_oid.obj \ + $(OBJ)\mech/gssspi_exchange_meta_data.obj \ + $(OBJ)\mech/gssspi_query_mechanism_info.obj \ + $(OBJ)\mech/gssspi_query_meta_data.obj \ + $(OBJ)\spnego/accept_sec_context.obj \ + $(OBJ)\spnego/compat.obj \ + $(OBJ)\spnego/context_storage.obj \ + $(OBJ)\spnego/context_stubs.obj \ + $(OBJ)\spnego/external.obj \ + $(OBJ)\spnego/init_sec_context.obj \ + $(OBJ)\spnego/negoex_ctx.obj \ + $(OBJ)\spnego/negoex_util.obj \ + $(OBJ)\ntlm/accept_sec_context.obj \ + $(OBJ)\ntlm/acquire_cred.obj \ + $(OBJ)\ntlm/add_cred.obj \ + $(OBJ)\ntlm/canonicalize_name.obj \ + $(OBJ)\ntlm/compare_name.obj \ + $(OBJ)\ntlm/context_time.obj \ + $(OBJ)\ntlm/creds.obj \ + $(OBJ)\ntlm/crypto.obj \ + $(OBJ)\ntlm/delete_sec_context.obj \ + $(OBJ)\ntlm/display_name.obj \ + $(OBJ)\ntlm/display_status.obj \ + $(OBJ)\ntlm/duplicate_cred.obj \ + $(OBJ)\ntlm/duplicate_name.obj \ + $(OBJ)\ntlm/export_name.obj \ + $(OBJ)\ntlm/export_sec_context.obj \ + $(OBJ)\ntlm/external.obj \ + $(OBJ)\ntlm/import_name.obj \ + $(OBJ)\ntlm/import_sec_context.obj \ + $(OBJ)\ntlm/indicate_mechs.obj \ + $(OBJ)\ntlm/init_sec_context.obj \ + $(OBJ)\ntlm/inquire_context.obj \ + $(OBJ)\ntlm/inquire_cred_by_mech.obj \ + $(OBJ)\ntlm/inquire_mechs_for_name.obj \ + $(OBJ)\ntlm/inquire_names_for_mech.obj \ + $(OBJ)\ntlm/inquire_sec_context_by_oid.obj \ + $(OBJ)\ntlm/iter_cred.obj \ + $(OBJ)\ntlm/process_context_token.obj \ + $(OBJ)\ntlm/release_cred.obj \ + $(OBJ)\ntlm/release_name.obj \ + $(OBJ)\ntlm/set_sec_context_option.obj \ + $(OBJ)\ntlm/kdc.obj \ + $(OBJ)\sanon/accept_sec_context.obj \ + $(OBJ)\sanon/acquire_cred.obj \ + $(OBJ)\sanon/add_cred.obj \ + $(OBJ)\sanon/canonicalize_name.obj \ + $(OBJ)\sanon/compare_name.obj \ + $(OBJ)\sanon/context_time.obj \ + $(OBJ)\sanon/crypto.obj \ + $(OBJ)\sanon/delete_sec_context.obj \ + $(OBJ)\sanon/display_name.obj \ + $(OBJ)\sanon/display_status.obj \ + $(OBJ)\sanon/duplicate_cred.obj \ + $(OBJ)\sanon/duplicate_name.obj \ + $(OBJ)\sanon/export_cred.obj \ + $(OBJ)\sanon/export_name.obj \ + $(OBJ)\sanon/export_sec_context.obj \ + $(OBJ)\sanon/external.obj \ + $(OBJ)\sanon/import_cred.obj \ + $(OBJ)\sanon/import_name.obj \ + $(OBJ)\sanon/import_sec_context.obj \ + $(OBJ)\sanon/init_sec_context.obj \ + $(OBJ)\sanon/inquire_context.obj \ + $(OBJ)\sanon/inquire_cred.obj \ + $(OBJ)\sanon/inquire_cred_by_mech.obj \ + $(OBJ)\sanon/inquire_mechs_for_name.obj \ + $(OBJ)\sanon/inquire_names_for_mech.obj \ + $(OBJ)\sanon/inquire_sec_context_by_oid.obj \ + $(OBJ)\sanon/negoex.obj \ + $(OBJ)\sanon/process_context_token.obj \ + $(OBJ)\sanon/release_cred.obj \ + $(OBJ)\sanon/release_name.obj \ + $(OBJ)\gkrb5_err.obj \ + $(OBJ)\negoex_err.obj \ + $(OBJ)\spnego\asn1_spnego_asn1.obj \ + $(OBJ)\gssapi\asn1_gssapi_asn1.obj + +GCOPTS=-I$(SRCDIR) -I$(OBJ) -Igssapi -DBUILD_GSSAPI_LIB + +{$(OBJ)\krb5}.c{$(OBJ)\krb5}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\krb5\ -Fd$(OBJ)\krb5\ -I$(OBJ)\krb5 $(GCOPTS) + +{krb5}.c{$(OBJ)\krb5}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\krb5\ -Fd$(OBJ)\krb5\ -I$(OBJ)\krb5 $(GCOPTS) -DASN1_LIB + +{$(OBJ)\mech}.c{$(OBJ)\mech}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\mech\ -Fd$(OBJ)\mech\ -I$(OBJ)\mech $(GCOPTS) + +{mech}.c{$(OBJ)\mech}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\mech\ -Fd$(OBJ)\mech\ -I$(OBJ)\mech -I$(OBJ)\gssapi $(GCOPTS) -DASN1_LIB + +{$(OBJ)\ntlm}.c{$(OBJ)\ntlm}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\ntlm\ -Fd$(OBJ)\ntlm\ -I$(OBJ)\ntlm $(GCOPTS) + +{ntlm}.c{$(OBJ)\ntlm}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\ntlm\ -Fd$(OBJ)\ntlm\ -I$(OBJ)\ntlm $(GCOPTS) -DASN1_LIB + +{$(OBJ)\spnego}.c{$(OBJ)\spnego}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\spnego\ -Fd$(OBJ)\spnego\ -I$(OBJ)\spnego $(GCOPTS) + +{spnego}.c{$(OBJ)\spnego}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\spnego\ -Fd$(OBJ)\spnego\ -I$(OBJ)\spnego -Imech $(GCOPTS) -DASN1_LIB + +{$(OBJ)\sanon}.c{$(OBJ)\sanon}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\sanon\ -Fd$(OBJ)\sanon\ -I$(OBJ)\sanon -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) + +{sanon}.c{$(OBJ)\sanon}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\sanon\ -Fd$(OBJ)\sanon\ -I$(OBJ)\sanon -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) -DASN1_LIB + +{$(OBJ)\gssapi}.c{$(OBJ)\gssapi}.obj:: + $(C2OBJ_NP) -Fo$(OBJ)\gssapi\ -Fd$(OBJ)\gssapi\ -I$(OBJ)\gssapi $(GCOPTS) + +{$(OBJ)}.c{$(OBJ)}.obj:: + $(C2OBJ_P) $(GCOPTS) + +{gssapi}.h{$(INCDIR)\gssapi}.h: + $(CP) $** $@ + +{$(OBJ)}.h{$(INCDIR)\gssapi}.h: + $(CP) $** $@ + +LIBGSSAPI_LIBS=\ + $(LIBHEIMBASE) \ + $(LIBROKEN) \ + $(LIBHEIMDAL) \ + $(LIBHEIMNTLM) \ + $(LIBCOMERR) + +LIBGSSAPI_SDKLIBS=\ + $(PTHREAD_LIB) \ + Secur32.lib Shell32.lib Advapi32.lib + +!ifndef STATICLIBS + +RES=$(OBJ)\libgssapi-version.res + +$(BINDIR)\gssapi.dll: $(libgssapi_OBJs) $(RES) + $(DLLGUILINK_C) -implib:$(LIBGSSAPI) \ + -out:$(BINDIR)\gssapi.dll \ + -def:libgssapi-exports.def \ + $(LIBGSSAPI_LIBS) $(RES) $(LIBGSSAPI_SDKLIBS) @<< +$(libgssapi_OBJs: = +) +<< + $(DLLPREP_NODIST) + +$(LIBGSSAPI): $(BINDIR)\gssapi.dll + +clean:: + -$(RM) $(BINDIR)\gssapi.* + +!else + +$(LIBGSSAPI): $(libgssapi_OBJs) + $(LIBCON_C) -OUT:$@ $(LIBGSSAPI_LIBS) $(LIBGSSAPI_SDKLIBS) @<< +$(libgssapi_OBJs: = +) +<< + +!endif + +all:: $(LIBGSSAPI) + +clean:: + -$(RM) $(LIBGSSAPI) + +prep:: mkdirs-gss + +mkdirs-gss: +!if !exist($(OBJ)\ntlm) + $(MKDIR) $(OBJ)\ntlm +!endif +!if !exist($(OBJ)\krb5) + $(MKDIR) $(OBJ)\krb5 +!endif +!if !exist($(OBJ)\spnego) + $(MKDIR) $(OBJ)\spnego +!endif +!if !exist($(OBJ)\sanon) + $(MKDIR) $(OBJ)\sanon +!endif +!if !exist($(OBJ)\mech) + $(MKDIR) $(OBJ)\mech +!endif +!if !exist($(OBJ)\gssapi) + $(MKDIR) $(OBJ)\gssapi +!endif + +clean:: + -$(RM) $(OBJ)\ntlm\*.* + -$(RM) $(OBJ)\krb5\*.* + -$(RM) $(OBJ)\spnego\*.* + -$(RM) $(OBJ)\mech\*.* + -$(RM) $(OBJ)\sanon\*.* + -$(RM) $(OBJ)\gssapi\*.* + +all-tools:: $(BINDIR)\gsstool.exe + +$(BINDIR)\gsstool.exe: $(OBJ)\gsstool.obj $(OBJ)\gss-commands.obj $(LIBGSSAPI) $(LIBROKEN) $(LIBSL) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP) + +$(OBJ)\gss-commands.c $(OBJ)\gss-commands.h: gss-commands.in + cd $(OBJ) + $(CP) $(SRCDIR)\gss-commands.in gss-commands.in + $(BINDIR)\slc.exe gss-commands.in + cd $(SRCDIR) + +!ifdef ELISP +# This macro invocation is used to update the libgssapi_OBJs +# definition below (generate-obj-macro is defined in maint.el): + +(generate-obj-macro "libgssapi_OBJs" + (concat "\t$(OBJ)\\gkrb5_err.obj \\\n" + "\t$(OBJ)\\negoex_err.obj \\\n" + "\t$(OBJ)\\spnego\\asn1_spnego_asn1.obj \\\n" + "\t$(OBJ)\\gssapi\\asn1_gssapi_asn1.obj") + "krb5src" "mechsrc" "spnegosrc" "ntlmsrc") +!endif + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libgssapi-exports.def + +test:: test-exports + + +TEST_BINARIES=\ + $(OBJ)\test_oid.exe \ + $(OBJ)\test_names.exe \ + $(OBJ)\test_cfx.exe \ + $(OBJ)\test_acquire_cred.exe \ + $(OBJ)\test_cred.exe \ + $(OBJ)\test_kcred.exe \ + $(OBJ)\test_context.exe \ + $(OBJ)\test_ntlm.exe + +$(OBJ)\test_oid.exe: $(OBJ)\test_oid.obj $(LIBGSSAPI) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_names.exe: $(OBJ)\test_names.obj $(LIBGSSAPI) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_cfx.exe: $(OBJ)\krb5\test_cfx.obj $(LIBHEIMDAL) $(LIBGSSAPI) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_acquire_cred.exe: $(OBJ)\test_acquire_cred.obj $(OBJ)\test_common.obj \ + $(LIBGSSAPI) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_cred.exe: $(OBJ)\test_cred.obj $(LIBGSSAPI) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_kcred.exe: $(OBJ)\test_kcred.obj $(LIBGSSAPI) $(LIBHEIMDAL) \ + $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_context.exe: $(OBJ)\test_context.obj $(OBJ)\test_common.obj \ + $(LIBGSSAPI) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_ntlm.exe: $(OBJ)\test_ntlm.obj $(OBJ)\test_common.obj \ + $(LIBGSSAPI) $(LIBHEIMNTLM) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +{}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -I$(OBJ)\krb5 -I$(OBJ) -I$(SRCDIR) -I$(SRCDIR)\gssapi + +test-binaries: $(LIBGSSAPI) $(TEST_BINARIES) + +run-test: + cd $(OBJ) + -test_oid + -test_names + -test_cfx + -test_kcred + cd $(SRCDIR) + +test:: test-binaries run-test diff --git a/third_party/heimdal/lib/gssapi/gen-oid.pl b/third_party/heimdal/lib/gssapi/gen-oid.pl new file mode 100644 index 0000000..d635f28 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gen-oid.pl @@ -0,0 +1,149 @@ +#!/usr/bin/perl +# +# Copyright (c) 2010 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +use Getopt::Std; + +my $output; +my $CFILE, $HFILE; +my $onlybase; +my $header = 0; + +getopts('b:h') || die "USAGE: ./gen-oid [-b BASE] [-h HEADER]"; + +if($opt_b) { + $onlybase = $opt_b; +} + +$header = 1 if ($opt_h); + +printf "/* Generated file */\n"; +if ($header) { + printf "#ifndef GSSAPI_GSSAPI_OID\n"; + printf "#define GSSAPI_GSSAPI_OID 1\n\n"; +} else { + printf "#include \"mech_locl.h\"\n\n"; +} + +my %tables; +my %types; + +while(<>) { + + if (/^\w*#(.*)/) { + my $comment = $1; + + if ($header) { + printf("$comment\n"); + } + + } elsif (/^oid\s+([\w\.]+)\s+(\w+)\s+([\w\.]+)/) { + my ($base, $name, $oid) = ($1, $2, $3); + + next if (defined $onlybase and $onlybase ne $base); + + my $store = "__" . lc($name) . "_oid_desc"; + + # encode oid + + my @array = split(/\./, $oid); + my $length = 0; + my $data = ""; + + my $num; + + $n = $#array; + while ($n > 1) { + $num = $array[$n]; + + my $p = int($num % 128); + $data = sprintf("\\x%02x", $p) . $data; + + $num = int($num / 128); + + $length += 1; + + while ($num > 0) { + $p = int($num % 128) + 128; + $num = int($num / 128); + $data = sprintf("\\x%02x", $p) . $data; + $length += 1; + } + $n--; + } + $num = int($array[0] * 40 + $array[1]); + + $data = sprintf("\\x%x", $num) . $data; + $length += 1; + + if ($header) { + printf "extern GSSAPI_LIB_VARIABLE gss_OID_desc $store;\n"; + printf "#define $name (&$store)\n\n"; + } else { + printf "/* $name - $oid */\n"; + printf "gss_OID_desc GSSAPI_LIB_VARIABLE $store = { $length, rk_UNCONST(\"$data\") };\n\n"; + } + push(@oidstorage, $store); + } elsif (/^desc\s+([\w]+)\s+(\w+)\s+(\"[^\"]*\")\s+(\"[^\"]*\")/) { + my ($type, $oid, $short, $long) = ($1, $2, $3, $4); + my $object = { type=> $type, oid => $oid, short => $short, long => $long }; + + $tables{$oid} = \$object; + $types{$type} = 1; + } + +} + +foreach my $k (sort keys %types) { + if (!$header) { + print "struct _gss_oid_name_table _gss_ont_" . $k . "[] = {\n"; + foreach my $m (sort {$$a->{oid} cmp $$b->{oid}} values %tables) { + if ($$m->{type} eq $k) { + printf " { %s, \"%s\", %s, %s },\n", $$m->{oid}, $$m->{oid}, $$m->{short}, $$m->{long}; + } + } + printf " { NULL, NULL, NULL, NULL }\n"; + printf "};\n\n"; + + } +} + +if ($header) { + printf "#endif /* GSSAPI_GSSAPI_OID */\n"; +} else { + printf "gss_OID _gss_ot_internal[] = {\n"; + foreach my $k (@oidstorage) { + print " &$k,\n"; + } + printf "};\n\n"; + printf "size_t _gss_ot_internal_count = sizeof(_gss_ot_internal) / sizeof(_gss_ot_internal[0]);\n"; +} diff --git a/third_party/heimdal/lib/gssapi/gss-commands.in b/third_party/heimdal/lib/gssapi/gss-commands.in new file mode 100644 index 0000000..25ec1c8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gss-commands.in @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* $Id$ */ + +command = { + name = "mechanisms" + name = "supported-mechanisms" + help = "Print the supported mechanisms" +} +command = { + name = "attributes" + name = "attrs-for-mech" + help = "Print the attributes for mechs" + option = { + long = "all" + type = "flag" + } + option = { + long = "mech" + type = "string" + argument = "mechanism" + } +} +command = { + name = "help" + name = "?" + argument = "[command]" + min_args = "0" + max_args = "1" + help = "Help! I need somebody." +} diff --git a/third_party/heimdal/lib/gssapi/gss-token.1 b/third_party/heimdal/lib/gssapi/gss-token.1 new file mode 100644 index 0000000..7bd50b0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gss-token.1 @@ -0,0 +1,108 @@ +.\" +.\" +.Dd May 12, 2014 +.Os +.Dt GSS-TOKEN 1 +.Sh NAME +.Nm gss-token +.Nd generate and consume base64 GSS tokens +.Sh SYNOPSIS +.Nm +.Op Fl DNn +.Op Fl c count +.Ar service@host +.Nm +.Fl r +.Op Fl MNln +.Op Fl C Ar ccache +.Op Fl S Ar maxsize +.Op Fl c count +.Op Fl m mech +.Op Ar service@host +.Sh DESCRIPTION +.Nm +generates and consumes base64 encoded GSS tokens. +By default, it runs as an initiator and with the +.Fl r +flag it becomes an acceptor. +.Pp +.Nm +supports the following options: +.Bl -tag -width indentxxxx +.It Fl C Ar ccache +write an accepted delegated credential into +.Ar ccache . +This only makes sense if +.Fl r +is specified. +.It Fl D +delegate credentials. +This only makes sense as a client, that is when +.Fl r +is not specified. +.It Fl M +copy the default ccache to a MEMORY: ccache before each +separate write operation. +The default ccache will not pick up any obtained service +tickets. +If specified with +.Fl c , +the cache will revert to its original state before each +new token is written. +This can be used to load test the KDC. +.It Fl N +prepend +.Dq Negotiate\ +to generated tokens and expect it on consumed tokens. +.It Fl S Ar maxsize +split each token that is generated into components of maximum +size +.Ar maxsize . +Each token is base64 encoded and output separately. +.It Fl c Ar count +repeat the operation +.Ar count +times. +This flag only changes the behaviour when operating in initiator mode. +This is good for very basic benchmarking. +.It Fl l +loop indefinitely in acceptor mode. +.It Fl m Ar mech +specifies the GSS mechanism that will be used in initiator mode. +If a mechanism name of +.Do ? Dc +is specified, a list of supported mechanisms will be output and +.Nm +will exit. +.It Fl n +do not output the generated tokens. +.It Fl r +run in acceptor mode. +.El +.Pp +.Nm +takes one argument, a +.Ar host@service +specifier. +The argument is required when running as an initiator but is optional as +an acceptor. +.Pp +.Nm +will try to read a token whenever the GSS mechanism expects one +and will output a token whenever the GSS mechanism provides one. +Tokens are base64 encoded and terminated by either two successive +newlines or one newline and EOF. +The base64 encoding may be broken up by single newlines which will +be ignored when read. No extra whitespace will be ignored. +.Sh EXAMPLES +To test a simple GSS mechanism which doesn't require a round trip, +a single +.Pa /bin/sh +pipeline will suffice: +.Bd -literal -offset indent +$ export KRB5_KTNAME=/path/to/keytab +$ gss-token HTTP@$(hostname) | gss-token -r +.Ed +.Sh SEE ALSO +.Xr gssapi 3 , +.Xr kerberos 8 . diff --git a/third_party/heimdal/lib/gssapi/gss-token.c b/third_party/heimdal/lib/gssapi/gss-token.c new file mode 100644 index 0000000..a4c0296 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gss-token.c @@ -0,0 +1,684 @@ +/* */ + +/*- + * Copyright (c) 1997-2011 Roland C. Dowdeswell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer and + * dedication in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#ifdef __APPLE__ +#include +#elif HAVE_MALLOC_H +#include +#endif +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define GBAIL(x, _maj, _min) do { \ + if (GSS_ERROR(_maj)) { \ + char *the_gss_err; \ + \ + ret = 1; \ + the_gss_err = gss_mk_err(_maj, _min, x); \ + if (the_gss_err) \ + fprintf(stderr, "%s\n", the_gss_err); \ + else \ + fprintf(stderr, "err making err\n"); \ + free(the_gss_err); \ + goto bail; \ + } \ + } while (0) + +#define K5BAIL(x) do { \ + kret = x; \ + if (kret) { \ + const char *k5err; \ + \ + k5err = krb5_get_error_message(kctx, kret); \ + if (k5err) { \ + fprintf(stderr, "%s in %s:%s\n", k5err, \ + #x, __func__); \ + krb5_free_error_message(kctx, k5err); \ + } else { \ + fprintf(stderr, "unknown error %d in " \ + "%s:%s\n", kret, #x, __func__); \ + } \ + exit(1); /* XXXrcd: shouldn't exit */ \ + } \ + } while (0) + + +/* + * global variables + */ + +int Sflag = 0; +int nflag = 0; +gss_OID global_mech = GSS_C_NO_OID; + +static char * +gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble) +{ + gss_buffer_desc status; + OM_uint32 new_stat; + OM_uint32 cur_stat; + OM_uint32 msg_ctx = 0; + OM_uint32 ret; + int type; + size_t newlen; + char *str = NULL; + char *tmp = NULL; + + cur_stat = maj_stat; + type = GSS_C_GSS_CODE; + + for (;;) { + + /* + * GSS_S_FAILURE produces a rather unhelpful message, so + * we skip straight to the mech specific error in this case. + */ + + if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) { + type = GSS_C_MECH_CODE; + cur_stat = min_stat; + } + + ret = gss_display_status(&new_stat, cur_stat, type, + GSS_C_NO_OID, &msg_ctx, &status); + + if (GSS_ERROR(ret)) + return str; /* XXXrcd: hmmm, not quite?? */ + + if (str) + newlen = strlen(str); + else + newlen = strlen(preamble); + + newlen += status.length + 3; + + tmp = str; + str = malloc(newlen); + + if (!str) { + gss_release_buffer(&new_stat, &status); + return tmp; /* XXXrcd: hmmm, not quite?? */ + } + + snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble, + tmp?", ":": ", (int)status.length, (char *)status.value); + + gss_release_buffer(&new_stat, &status); + free(tmp); + + /* + * If we are finished processing for maj_stat, then + * move onto min_stat. + */ + + if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) { + type = GSS_C_MECH_CODE; + cur_stat = min_stat; + continue; + } + + if (msg_ctx == 0) + break; + } + + return str; +} + +static char * +read_buffer(FILE *fp) +{ + char buf[65536]; + char *p; + char *ret = NULL; + size_t buflen; + size_t retlen = 0; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((p = strchr(buf, '\n')) == NULL) { + fprintf(stderr, "Long line, exiting.\n"); + exit(1); + } + *p = '\0'; + buflen = strlen(buf); + if (buflen == 0) + break; + + ret = realloc(ret, retlen + buflen + 1); + if (!ret) { + perror("realloc"); + exit(1); + } + memcpy(ret + retlen, buf, buflen); + ret[retlen + buflen] = '\0'; + retlen += buflen; + } + + if (ferror(stdin)) { + perror("fgets"); + exit(1); + } + + return ret; +} + +static int +write_and_free_token(gss_buffer_t out, int negotiate) +{ + OM_uint32 min; + char *outstr = NULL; + char *p = out->value; + size_t len = out->length; + size_t inc; + int ret = 0; + int first = 1; + + if (nflag) + goto bail; + + /* + * According to RFC 2744 page 25, we simply don't output + * zero length output tokens. + */ + if (len == 0) + goto bail; + + inc = len; + if (Sflag) + inc = Sflag; + + do { + if (first) + first = 0; + else + printf("\n"); + if (len < inc) + inc = len; + if (rk_base64_encode(p, inc, &outstr) < 0) { + fprintf(stderr, "Out of memory.\n"); + ret = errno; + goto bail; + } + ret = 0; + printf("%s%s\n", negotiate?"Negotiate ":"", outstr); + free(outstr); + p += inc; + len -= inc; + } while (len > 0); + ret = 0; + +bail: + gss_release_buffer(&min, out); + return ret; +} + +static int +read_token(gss_buffer_t in, int negotiate) +{ + char *inbuf = NULL; + char *tmp; + size_t len; + int ret = 0; + + /* We must flush before we block wanting input */ + fflush(stdout); + + *in = (gss_buffer_desc)GSS_C_EMPTY_BUFFER; + inbuf = read_buffer(stdin); + if (!inbuf) + /* Just a couple of \n's in a row or EOF, no error. */ + return 0; + + tmp = inbuf; + if (negotiate) { + if (strncasecmp("Negotiate ", inbuf, 10) != 0) { + fprintf(stderr, "Token doesn't begin with " + "\"Negotiate \"\n"); + ret = -1; + goto bail; + } + + tmp += 10; + } + + len = strlen(tmp); + in->value = malloc(len + 1); + if (!in->value) { + fprintf(stderr, "Out of memory.\n"); + ret = -1; + goto bail; + } + ret = rk_base64_decode(tmp, in->value); + if (ret < 0) { + free(in->value); + in->value = NULL; + if (errno == EOVERFLOW) + fprintf(stderr, "Token is too big\n"); + else + fprintf(stderr, "Token encoding is not valid " + "base64\n"); + goto bail; + } else { + in->length = ret; + } + ret = 0; + +bail: + free(inbuf); + return ret; +} + +static int +initiate_one(gss_name_t service, int delegate, int negotiate) +{ + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc in; + gss_buffer_desc out; + OM_uint32 maj; + OM_uint32 min; + OM_uint32 flags = 0; + int first = 1; + int ret = 0; + + if (delegate) + flags |= GSS_C_DELEG_FLAG; + + do { + out.length = 0; + out.value = 0; + + if (first) { + in.length = 0; + in.value = 0; + first = 0; + } else { + printf("\n"); + ret = read_token(&in, negotiate); + if (ret) + return ret; + if (feof(stdin)) + return -1; + } + + maj = gss_init_sec_context(&min, GSS_C_NO_CREDENTIAL, &ctx, + service, global_mech, flags, 0, + GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out, + NULL, NULL); + + ret = write_and_free_token(&out, negotiate); + if (ret) + return ret; + + GBAIL("gss_init_sec_context", maj, min); + } while (maj & GSS_S_CONTINUE_NEEDED); + +bail: + if (ctx != GSS_C_NO_CONTEXT) { + /* + * XXXrcd: here we ignore the fact that we might have an + * output token as this program doesn't do terribly + * well in that case. + */ + gss_delete_sec_context(&min, &ctx, NULL); + } + + return ret; +} + +static krb5_error_code +copy_cache(krb5_context kctx, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code kret; + krb5_principal princ = NULL; + krb5_cc_cursor cursor; + krb5_creds cred; + + K5BAIL(krb5_cc_get_principal(kctx, from, &princ)); + K5BAIL(krb5_cc_initialize(kctx, to, princ)); + K5BAIL(krb5_cc_start_seq_get(kctx, from, &cursor)); + for (;;) { + kret = krb5_cc_next_cred(kctx, from, &cursor, &cred); + if (kret) + break; + kret = krb5_cc_store_cred(kctx, to, &cred); + krb5_free_cred_contents(kctx, &cred); + if (kret) + break; + } + krb5_cc_end_seq_get(kctx, from, &cursor); + + if (kret == KRB5_CC_END) + kret = 0; + K5BAIL(kret); + + if (princ) + krb5_free_principal(kctx, princ); + + return kret; +} + +static int +initiate_many(gss_name_t service, int delegate, int negotiate, int memcache, + size_t count) +{ + krb5_error_code kret = 0; + krb5_context kctx = NULL; + krb5_ccache def_cache = NULL; + krb5_ccache mem_cache = NULL; + size_t i; + + if (memcache) { + K5BAIL(krb5_init_context(&kctx)); + K5BAIL(krb5_cc_default(kctx, &def_cache)); + K5BAIL(krb5_cc_resolve(kctx, "MEMORY:mem_cache", &mem_cache)); + putenv("KRB5CCNAME=MEMORY:mem_cache"); + } + + for (i=0; i < count; i++) { + if (memcache) + K5BAIL(copy_cache(kctx, def_cache, mem_cache)); + kret = initiate_one(service, delegate, negotiate); + + if (!nflag && i < count - 1) + printf("\n"); + } + + if (kctx) + krb5_free_context(kctx); + if (def_cache) + krb5_cc_close(kctx, def_cache); + if (mem_cache) + krb5_cc_close(kctx, mem_cache); + + return kret; +} + +static int +accept_one(gss_name_t service, const char *ccname, int negotiate) +{ + gss_cred_id_t cred = NULL; + gss_cred_id_t deleg_creds = NULL; + gss_name_t client; + gss_OID mech_oid; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc in = GSS_C_EMPTY_BUFFER; + gss_buffer_desc out; + gss_buffer_desc dname = GSS_C_EMPTY_BUFFER; + krb5_context kctx = NULL; + krb5_ccache ccache = NULL; + krb5_error_code kret; + OM_uint32 maj, min; + int ret = 0; + + if (service) { + maj = gss_acquire_cred(&min, service, 0, NULL, GSS_C_ACCEPT, + &cred, NULL, NULL); + GBAIL("gss_acquire_cred", maj, min); + } + + do { + if (feof(stdin)) + return -1; + ret = read_token(&in, negotiate); + if (ret) + return ret; + + out.length = 0; + out.value = 0; + + maj = gss_accept_sec_context(&min, &ctx, cred, &in, + GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_oid, &out, + NULL, NULL, &deleg_creds); + + ret = write_and_free_token(&out, negotiate); + if (ret) { + OM_uint32 junk; + + (void) gss_delete_sec_context(&junk, &ctx, + GSS_C_NO_BUFFER); + return ret; + } + GBAIL("gss_accept_sec_context", maj, min); + } while (maj & GSS_S_CONTINUE_NEEDED); + + /* + * XXXrcd: not bothering to clean up because we're about to exit. + * Probably should fix this in case the code is used as + * an example by someone. + */ + + maj = gss_display_name(&min, client, &dname, NULL); + GBAIL("gss_display_name", maj, min); + + if (!nflag) + printf("Authenticated: %.*s\n", (int)dname.length, + (char *)dname.value); + (void) gss_release_buffer(&min, &dname); + (void) gss_release_name(&min, &client); + (void) gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER); + + if (ccname) { +#ifdef HAVE_GSS_STORE_CRED_INTO + gss_key_value_set_desc store; + gss_key_value_element_desc elem; + int overwrite_cred = 1; + int default_cred = 0; + + elem.key = "ccache"; + elem.value = ccname; + store.count = 1; + store.elements = &elem; + + maj = gss_store_cred_into(&min, deleg_creds, GSS_C_INITIATE, + GSS_C_NO_OID, overwrite_cred, default_cred, &store, NULL, + NULL); + GBAIL("gss_store_cred_into", maj, min); +#else + K5BAIL(krb5_init_context(&kctx)); + K5BAIL(krb5_cc_resolve(kctx, ccname, &ccache)); + + maj = gss_krb5_copy_ccache(&min, deleg_creds, ccache); + GBAIL("gss_krb5_copy_ccache", maj, min); +#endif + } + +bail: + if (kctx) + krb5_free_context(kctx); + if (ccache) + krb5_cc_close(kctx, ccache); + if (cred) + gss_release_cred(&min, &cred); + if (deleg_creds) + gss_release_cred(&min, &deleg_creds); + + free(in.value); + + return ret; +} + +static gss_name_t +import_service(char *service) +{ + gss_buffer_desc name; + gss_name_t svc = NULL; + OM_uint32 maj; + OM_uint32 min; + int ret = 0; + + name.length = strlen(service); + name.value = service; + + maj = gss_import_name(&min, &name, GSS_C_NT_HOSTBASED_SERVICE, &svc); + + GBAIL("gss_import_name", maj, min); + +bail: + if (ret) + exit(1); + return svc; +} + +static void +print_all_mechs(void) +{ + OM_uint32 maj, min; + gss_OID_set mech_set; + size_t i; + int ret = 0; + + maj = gss_indicate_mechs(&min, &mech_set); + GBAIL("gss_indicate_mechs", maj, min); + + for (i=0; i < mech_set->count; i++) + printf("%s\n", gss_oid_to_name(&mech_set->elements[i])); + + (void) gss_release_oid_set(&min, &mech_set); + +bail: + exit(ret); +} + +static void +usage(int ecode) +{ + FILE *f = ecode == 0 ? stdout : stderr; + fprintf(f, "Usage: gss-token [-DNn] [-c count] service@host\n"); + fprintf(f, " gss-token -r [-Nln] [-C ccache] [-c count] " + "[service@host]\n"); + exit(ecode); +} + +int +main(int argc, char **argv) +{ + OM_uint32 min; + gss_name_t service = NULL; + size_t count = 1; + int Dflag = 0; + int Mflag = 0; + int Nflag = 0; + int hflag = 0; + int lflag = 0; + int rflag = 0; + int version_flag = 0; + int ret = 0; + int optidx = 0; + char *ccname = NULL; + char *mech = NULL; + struct getargs args[] = { + { "help", 'h', arg_flag, &hflag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { NULL, 'C', arg_string, &ccname, NULL, NULL }, + { NULL, 'D', arg_flag, &Dflag, NULL, NULL }, + { NULL, 'M', arg_flag, &Mflag, NULL, NULL }, + { NULL, 'N', arg_flag, &Nflag, NULL, NULL }, + { NULL, 'S', arg_integer, &Sflag, NULL, NULL }, + { NULL, 'c', arg_integer, &count, NULL, NULL }, + { NULL, 'l', arg_flag, &lflag, NULL, NULL }, + { NULL, 'm', arg_string, &mech, NULL, NULL }, + { NULL, 'n', arg_flag, &nflag, NULL, NULL }, + { NULL, 'r', arg_flag, &rflag, NULL, NULL }, + }; + + setprogname(argv[0]); + if (argc == 1 || + getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx)) + usage(1); + if (hflag) + usage(0); + if (version_flag) { + print_version(NULL); + return 0; + } + + argc -= optidx; + argv += optidx; + + if (mech) { + if (mech[0] == '?' && mech[1] == '\0') { + print_all_mechs(); + exit(0); + } + global_mech = gss_name_to_oid(mech); + if (!global_mech) { + fprintf(stderr, "Invalid mech \"%s\".\n", mech); + usage(1); + } + } + + if (argc > 0) + service = import_service(*argv); + + if (!rflag) { + if (!argc) { + fprintf(stderr, "Without -r, hostbased_service must " + "be provided.\n"); + usage(1); + } + if (ccname) { + fprintf(stderr, "Specifying a target ccache doesn't " + "make sense without -r.\n"); + usage(1); + } + ret = initiate_many(service, Dflag, Nflag, Mflag, count); + goto done; + } + + if (Dflag) { + fprintf(stderr, "Delegating credentials (-D) doesn't make " + "sense when reading tokens (-r).\n"); + usage(1); + } + + do { + ret = accept_one(service, ccname, Nflag); + } while (lflag && !ret && !feof(stdin)); + +done: + if (service) + gss_release_name(&min, &service); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/gss_acquire_cred.3 b/third_party/heimdal/lib/gssapi/gss_acquire_cred.3 new file mode 100644 index 0000000..de58ecd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gss_acquire_cred.3 @@ -0,0 +1,688 @@ +.\" Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd October 26, 2005 +.Dt GSS_ACQUIRE_CRED 3 +.Os HEIMDAL +.Sh NAME +.Nm gss_accept_sec_context , +.Nm gss_acquire_cred , +.Nm gss_add_cred , +.Nm gss_add_oid_set_member , +.Nm gss_canonicalize_name , +.Nm gss_compare_name , +.Nm gss_context_time , +.Nm gss_create_empty_oid_set , +.Nm gss_delete_sec_context , +.Nm gss_display_name , +.Nm gss_display_status , +.Nm gss_duplicate_name , +.Nm gss_export_name , +.Nm gss_export_sec_context , +.Nm gss_get_mic , +.Nm gss_import_name , +.Nm gss_import_sec_context , +.Nm gss_indicate_mechs , +.Nm gss_init_sec_context , +.Nm gss_inquire_context , +.Nm gss_inquire_cred , +.Nm gss_inquire_cred_by_mech , +.Nm gss_inquire_mechs_for_name , +.Nm gss_inquire_names_for_mech , +.Nm gss_krb5_ccache_name , +.Nm gss_krb5_compat_des3_mic , +.Nm gss_krb5_copy_ccache , +.Nm gss_krb5_import_cred +.Nm gsskrb5_extract_authz_data_from_sec_context , +.Nm gsskrb5_register_acceptor_identity , +.Nm gss_krb5_import_ccache , +.Nm gss_krb5_get_tkt_flags , +.Nm gss_process_context_token , +.Nm gss_release_buffer , +.Nm gss_release_cred , +.Nm gss_release_name , +.Nm gss_release_oid_set , +.Nm gss_seal , +.Nm gss_sign , +.Nm gss_test_oid_set_member , +.Nm gss_unseal , +.Nm gss_unwrap , +.Nm gss_verify , +.Nm gss_verify_mic , +.Nm gss_wrap , +.Nm gss_wrap_size_limit +.Nd Generic Security Service Application Program Interface library +.Sh LIBRARY +GSS-API library (libgssapi, -lgssapi) +.Sh SYNOPSIS +.In gssapi.h +.Pp +.Ft OM_uint32 +.Fo gss_accept_sec_context +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t * context_handle" +.Fa "gss_const_cred_id_t acceptor_cred_handle" +.Fa "const gss_buffer_t input_token_buffer" +.Fa "const gss_channel_bindings_t input_chan_bindings" +.Fa "gss_name_t * src_name" +.Fa "gss_OID * mech_type" +.Fa "gss_buffer_t output_token" +.Fa "OM_uint32 * ret_flags" +.Fa "OM_uint32 * time_rec" +.Fa "gss_cred_id_t * delegated_cred_handle" +.Fc +.Pp +.Ft OM_uint32 +.Fo gss_acquire_cred +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t desired_name" +.Fa "OM_uint32 time_req" +.Fa "const gss_OID_set desired_mechs" +.Fa "gss_cred_usage_t cred_usage" +.Fa "gss_cred_id_t * output_cred_handle" +.Fa "gss_OID_set * actual_mechs" +.Fa "OM_uint32 * time_rec" +.Fc +.Ft OM_uint32 +.Fo gss_add_cred +.Fa "OM_uint32 *minor_status" +.Fa "gss_const_cred_id_t input_cred_handle" +.Fa "gss_const_name_t desired_name" +.Fa "const gss_OID desired_mech" +.Fa "gss_cred_usage_t cred_usage" +.Fa "OM_uint32 initiator_time_req" +.Fa "OM_uint32 acceptor_time_req" +.Fa "gss_cred_id_t *output_cred_handle" +.Fa "gss_OID_set *actual_mechs" +.Fa "OM_uint32 *initiator_time_rec" +.Fa "OM_uint32 *acceptor_time_rec" +.Fc +.Ft OM_uint32 +.Fo gss_add_oid_set_member +.Fa "OM_uint32 * minor_status" +.Fa "const gss_OID member_oid" +.Fa "gss_OID_set * oid_set" +.Fc +.Ft OM_uint32 +.Fo gss_canonicalize_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t input_name" +.Fa "const gss_OID mech_type" +.Fa "gss_name_t * output_name" +.Fc +.Ft OM_uint32 +.Fo gss_compare_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t name1" +.Fa "gss_const_name_t name2" +.Fa "int * name_equal" +.Fc +.Ft OM_uint32 +.Fo gss_context_time +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "OM_uint32 * time_rec" +.Fc +.Ft OM_uint32 +.Fo gss_create_empty_oid_set +.Fa "OM_uint32 * minor_status" +.Fa "gss_OID_set * oid_set" +.Fc +.Ft OM_uint32 +.Fo gss_delete_sec_context +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t * context_handle" +.Fa "gss_buffer_t output_token" +.Fc +.Ft OM_uint32 +.Fo gss_display_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t input_name" +.Fa "gss_buffer_t output_name_buffer" +.Fa "gss_OID * output_name_type" +.Fc +.Ft OM_uint32 +.Fo gss_display_status +.Fa "OM_uint32 *minor_status" +.Fa "OM_uint32 status_value" +.Fa "int status_type" +.Fa "const gss_OID mech_type" +.Fa "OM_uint32 *message_context" +.Fa "gss_buffer_t status_string" +.Fc +.Ft OM_uint32 +.Fo gss_duplicate_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t src_name" +.Fa "gss_name_t * dest_name" +.Fc +.Ft OM_uint32 +.Fo gss_export_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t input_name" +.Fa "gss_buffer_t exported_name" +.Fc +.Ft OM_uint32 +.Fo gss_export_sec_context +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t * context_handle" +.Fa "gss_buffer_t interprocess_token" +.Fc +.Ft OM_uint32 +.Fo gss_get_mic +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "gss_qop_t qop_req" +.Fa "const gss_buffer_t message_buffer" +.Fa "gss_buffer_t message_token" +.Fc +.Ft OM_uint32 +.Fo gss_import_name +.Fa "OM_uint32 * minor_status" +.Fa "const gss_buffer_t input_name_buffer" +.Fa "const gss_OID input_name_type" +.Fa "gss_name_t * output_name" +.Fc +.Ft OM_uint32 +.Fo gss_import_sec_context +.Fa "OM_uint32 * minor_status" +.Fa "const gss_buffer_t interprocess_token" +.Fa "gss_ctx_id_t * context_handle" +.Fc +.Ft OM_uint32 +.Fo gss_indicate_mechs +.Fa "OM_uint32 * minor_status" +.Fa "gss_OID_set * mech_set" +.Fc +.Ft OM_uint32 +.Fo gss_init_sec_context +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_cred_id_t initiator_cred_handle" +.Fa "gss_ctx_id_t * context_handle" +.Fa "gss_const_name_t target_name" +.Fa "const gss_OID mech_type" +.Fa "OM_uint32 req_flags" +.Fa "OM_uint32 time_req" +.Fa "const gss_channel_bindings_t input_chan_bindings" +.Fa "const gss_buffer_t input_token" +.Fa "gss_OID * actual_mech_type" +.Fa "gss_buffer_t output_token" +.Fa "OM_uint32 * ret_flags" +.Fa "OM_uint32 * time_rec" +.Fc +.Ft OM_uint32 +.Fo gss_inquire_context +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "gss_name_t * src_name" +.Fa "gss_name_t * targ_name" +.Fa "OM_uint32 * lifetime_rec" +.Fa "gss_OID * mech_type" +.Fa "OM_uint32 * ctx_flags" +.Fa "int * locally_initiated" +.Fa "int * open_context" +.Fc +.Ft OM_uint32 +.Fo gss_inquire_cred +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_cred_id_t cred_handle" +.Fa "gss_name_t * name" +.Fa "OM_uint32 * lifetime" +.Fa "gss_cred_usage_t * cred_usage" +.Fa "gss_OID_set * mechanisms" +.Fc +.Ft OM_uint32 +.Fo gss_inquire_cred_by_mech +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_cred_id_t cred_handle" +.Fa "const gss_OID mech_type" +.Fa "gss_name_t * name" +.Fa "OM_uint32 * initiator_lifetime" +.Fa "OM_uint32 * acceptor_lifetime" +.Fa "gss_cred_usage_t * cred_usage" +.Fc +.Ft OM_uint32 +.Fo gss_inquire_mechs_for_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_name_t input_name" +.Fa "gss_OID_set * mech_types" +.Fc +.Ft OM_uint32 +.Fo gss_inquire_names_for_mech +.Fa "OM_uint32 * minor_status" +.Fa "const gss_OID mechanism" +.Fa "gss_OID_set * name_types" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_ccache_name +.Fa "OM_uint32 *minor" +.Fa "const char *name" +.Fa "const char **old_name" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_copy_ccache +.Fa "OM_uint32 *minor" +.Fa "gss_cred_id_t cred" +.Fa "krb5_ccache out" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_import_cred +.Fa "OM_uint32 *minor_status" +.Fa "krb5_ccache id" +.Fa "krb5_principal keytab_principal" +.Fa "krb5_keytab keytab" +.Fa "gss_cred_id_t *cred" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_compat_des3_mic +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "int onoff" +.Fc +.Ft OM_uint32 +.Fo gsskrb5_extract_authz_data_from_sec_context +.Fa "OM_uint32 *minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "int ad_type" +.Fa "gss_buffer_t ad_data" +.Fc +.Ft OM_uint32 +.Fo gsskrb5_register_acceptor_identity +.Fa "const char *identity" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_import_cache +.Fa "OM_uint32 *minor" +.Fa "krb5_ccache id" +.Fa "krb5_keytab keytab" +.Fa "gss_cred_id_t *cred" +.Fc +.Ft OM_uint32 +.Fo gss_krb5_get_tkt_flags +.Fa "OM_uint32 *minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "OM_uint32 *tkt_flags" +.Fc +.Ft OM_uint32 +.Fo gss_process_context_token +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "const gss_buffer_t token_buffer" +.Fc +.Ft OM_uint32 +.Fo gss_release_buffer +.Fa "OM_uint32 * minor_status" +.Fa "gss_buffer_t buffer" +.Fc +.Ft OM_uint32 +.Fo gss_release_cred +.Fa "OM_uint32 * minor_status" +.Fa "gss_cred_id_t * cred_handle" +.Fc +.Ft OM_uint32 +.Fo gss_release_name +.Fa "OM_uint32 * minor_status" +.Fa "gss_name_t * input_name" +.Fc +.Ft OM_uint32 +.Fo gss_release_oid_set +.Fa "OM_uint32 * minor_status" +.Fa "gss_OID_set * set" +.Fc +.Ft OM_uint32 +.Fo gss_seal +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "int conf_req_flag" +.Fa "int qop_req" +.Fa "gss_buffer_t input_message_buffer" +.Fa "int * conf_state" +.Fa "gss_buffer_t output_message_buffer" +.Fc +.Ft OM_uint32 +.Fo gss_sign +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "int qop_req" +.Fa "gss_buffer_t message_buffer" +.Fa "gss_buffer_t message_token" +.Fc +.Ft OM_uint32 +.Fo gss_test_oid_set_member +.Fa "OM_uint32 * minor_status" +.Fa "const gss_OID member" +.Fa "const gss_OID_set set" +.Fa "int * present" +.Fc +.Ft OM_uint32 +.Fo gss_unseal +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "gss_buffer_t input_message_buffer" +.Fa "gss_buffer_t output_message_buffer" +.Fa "int * conf_state" +.Fa "int * qop_state" +.Fc +.Ft OM_uint32 +.Fo gss_unwrap +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "const gss_buffer_t input_message_buffer" +.Fa "gss_buffer_t output_message_buffer" +.Fa "int * conf_state" +.Fa "gss_qop_t * qop_state" +.Fc +.Ft OM_uint32 +.Fo gss_verify +.Fa "OM_uint32 * minor_status" +.Fa "gss_ctx_id_t context_handle" +.Fa "gss_buffer_t message_buffer" +.Fa "gss_buffer_t token_buffer" +.Fa "int * qop_state" +.Fc +.Ft OM_uint32 +.Fo gss_verify_mic +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "const gss_buffer_t message_buffer" +.Fa "const gss_buffer_t token_buffer" +.Fa "gss_qop_t * qop_state" +.Fc +.Ft OM_uint32 +.Fo gss_wrap +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "int conf_req_flag" +.Fa "gss_qop_t qop_req" +.Fa "const gss_buffer_t input_message_buffer" +.Fa "int * conf_state" +.Fa "gss_buffer_t output_message_buffer" +.Fc +.Ft OM_uint32 +.Fo gss_wrap_size_limit +.Fa "OM_uint32 * minor_status" +.Fa "gss_const_ctx_id_t context_handle" +.Fa "int conf_req_flag" +.Fa "gss_qop_t qop_req" +.Fa "OM_uint32 req_output_size" +.Fa "OM_uint32 * max_input_size" +.Fc +.Sh DESCRIPTION +Generic Security Service API (GSS-API) version 2, and its C binding, +is described in +.Li RFC2743 +and +.Li RFC2744 . +Version 1 (deprecated) of the C binding is described in +.Li RFC1509 . +.Pp +Heimdals GSS-API implementation supports the following mechanisms +.Bl -bullet +.It +.Li GSS_KRB5_MECHANISM +.It +.Li GSS_SPNEGO_MECHANISM +.El +.Pp +GSS-API have generic name types that all mechanism are supposed to +implement (if possible): +.Bl -bullet +.It +.Li GSS_C_NT_USER_NAME +.It +.Li GSS_C_NT_MACHINE_UID_NAME +.It +.Li GSS_C_NT_STRING_UID_NAME +.It +.Li GSS_C_NT_HOSTBASED_SERVICE +.It +.Li GSS_C_NT_ANONYMOUS +.It +.Li GSS_C_NT_EXPORT_NAME +.El +.Pp +GSS-API implementations that supports Kerberos 5 have some additional +name types: +.Bl -bullet +.It +.Li GSS_KRB5_NT_PRINCIPAL_NAME +.It +.Li GSS_KRB5_NT_USER_NAME +.It +.Li GSS_KRB5_NT_MACHINE_UID_NAME +.It +.Li GSS_KRB5_NT_STRING_UID_NAME +.El +.Pp +In GSS-API, names have two forms, internal names and contiguous string +names. +.Bl -bullet +.It +.Li Internal name and mechanism name +.Pp +Internal names are implementation specific representation of +a GSS-API name. +.Li Mechanism names +special form of internal names corresponds to one and only one mechanism. +.Pp +In GSS-API an internal name is stored in a +.Dv gss_name_t . +.It +.Li Contiguous string name and exported name +.Pp +Contiguous string names are gssapi names stored in a +.Dv OCTET STRING +that together with a name type identifier (OID) uniquely specifies a +gss-name. +A special form of the contiguous string name is the exported name that +have a OID embedded in the string to make it unique. +Exported name have the nametype +.Dv GSS_C_NT_EXPORT_NAME . +.Pp +In GSS-API an contiguous string name is stored in a +.Dv gss_buffer_t . +.Pp +Exported names also have the property that they are specified by the +mechanism itself and compatible between different GSS-API +implementations. +.El +.Sh ACCESS CONTROL +There are two ways of comparing GSS-API names, either comparing two +internal names with each other or two contiguous string names with +either other. +.Pp +To compare two internal names with each other, import (if needed) the +names with +.Fn gss_import_name +into the GSS-API implementation and the compare the imported name with +.Fn gss_compare_name . +.Pp +Importing names can be slow, so when its possible to store exported +names in the access control list, comparing contiguous string name +might be better. +.Pp +when comparing contiguous string name, first export them into a +.Dv GSS_C_NT_EXPORT_NAME +name with +.Fn gss_export_name +and then compare with +.Xr memcmp 3 . +.Pp +Note that there are might be a difference between the two methods of +comparing names. +The first (using +.Fn gss_compare_name ) +will compare to (unauthenticated) names are the same. +The second will compare if a mechanism will authenticate them as the +same principal. +.Pp +For example, if +.Fn gss_import_name +name was used with +.Dv GSS_C_NO_OID +the default syntax is used for all mechanism the GSS-API +implementation supports. +When compare the imported name of +.Dv GSS_C_NO_OID +it may match several mechanism names (MN). +.Pp +The resulting name from +.Fn gss_display_name +must not be used for access control. +.Sh FUNCTIONS +.Fn gss_display_name +takes the gss name in +.Fa input_name +and puts a printable form in +.Fa output_name_buffer . +.Fa output_name_buffer +should be freed when done using +.Fn gss_release_buffer . +.Fa output_name_type +can either be +.Dv NULL +or a pointer to a +.Li gss_OID +and will in the latter case contain the OID type of the name. +The name must only be used for printing. +If access control is needed, see section +.Sx ACCESS CONTROL . +.Pp +.Fn gss_inquire_context +returns information about the context. +Information is available even after the context have expired. +.Fa lifetime_rec +argument is set to +.Dv GSS_C_INDEFINITE +(don't expire) or the number of seconds that the context is still valid. +A value of 0 means that the context is expired. +.Fa mech_type +argument should be considered readonly and must not be released. +.Fa src_name +and +.Fn dest_name +are both mechanims names and must be released with +.Fn gss_release_name +when no longer used. +.Pp +.Nm gss_context_time +will return the amount of time (in seconds) of the context is still +valid. +If its expired +.Fa time_rec +will be set to 0 and +.Dv GSS_S_CONTEXT_EXPIRED +returned. +.Pp +.Fn gss_sign , +.Fn gss_verify , +.Fn gss_seal , +and +.Fn gss_unseal +are part of the GSS-API V1 interface and are obsolete. +The functions should not be used for new applications. +They are provided so that version 1 applications can link against the +library. +.Sh EXTENSIONS +.Fn gss_krb5_ccache_name +sets the internal kerberos 5 credential cache name to +.Fa name . +The old name is returned in +.Fa old_name , +and must not be freed. +The data allocated for +.Fa old_name +is free upon next call to +.Fn gss_krb5_ccache_name . +This function is not threadsafe if +.Fa old_name +argument is used. +.Pp +.Fn gss_krb5_copy_ccache +will extract the krb5 credentials that are transferred from the +initiator to the acceptor when using token delegation in the Kerberos +mechanism. +The acceptor receives the delegated token in the last argument to +.Fn gss_accept_sec_context . +.Pp +.Fn gss_krb5_import_cred +will import the krb5 credentials (both keytab and/or credential cache) +into gss credential so it can be used withing GSS-API. +The +.Fa ccache +is copied by reference and thus shared, so if the credential is destroyed +with +.Fa krb5_cc_destroy , +all users of thep +.Fa gss_cred_id_t +returned by +.Fn gss_krb5_import_ccache +will fail. +.Pp +.Fn gsskrb5_register_acceptor_identity +sets the Kerberos 5 filebased keytab that the acceptor will use. The +.Fa identifier +is the file name. +.Pp +.Fn gsskrb5_extract_authz_data_from_sec_context +extracts the Kerberos authorizationdata that may be stored within the +context. +Tha caller must free the returned buffer +.Fa ad_data +with +.Fn gss_release_buffer +upon success. +.Pp +.Fn gss_krb5_get_tkt_flags +return the ticket flags for the kerberos ticket receive when +authenticating the initiator. +Only valid on the acceptor context. +.Pp +.Fn gss_krb5_compat_des3_mic +turns on or off the compatibility with older version of Heimdal using +des3 get and verify mic, this is way to programmatically set the +[gssapi]broken_des3_mic and [gssapi]correct_des3_mic flags (see +COMPATIBILITY section in +.Xr gssapi 3 ) . +If the CPP symbol +.Dv GSS_C_KRB5_COMPAT_DES3_MIC +is present, +.Fn gss_krb5_compat_des3_mic +exists. +.Fn gss_krb5_compat_des3_mic +will be removed in a later version of the GSS-API library. +.Sh SEE ALSO +.Xr gssapi 3 , +.Xr krb5 3 , +.Xr krb5_ccache 3 , +.Xr kerberos 8 diff --git a/third_party/heimdal/lib/gssapi/gssapi.3 b/third_party/heimdal/lib/gssapi/gssapi.3 new file mode 100644 index 0000000..089f751 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi.3 @@ -0,0 +1,172 @@ +.\" Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd April 20, 2005 +.Dt GSSAPI 3 +.Os +.Sh NAME +.Nm gssapi +.Nd Generic Security Service Application Program Interface library +.Sh LIBRARY +GSS-API Library (libgssapi, -lgssapi) +.Sh DESCRIPTION +The Generic Security Service Application Program Interface (GSS-API) +provides security services to callers in a generic fashion, +supportable with a range of underlying mechanisms and technologies and +hence allowing source-level portability of applications to different +environments. +.Pp +The GSS-API implementation in Heimdal implements the Kerberos 5 and +the SPNEGO GSS-API security mechanisms. +.Sh LIST OF FUNCTIONS +These functions constitute the gssapi library, +.Em libgssapi . +Declarations for these functions may be obtained from the include file +.Pa gssapi.h . +.Bl -column -compact +.It Sy Name/Page +.It Xr gss_accept_sec_context 3 +.It Xr gss_acquire_cred 3 +.It Xr gss_add_cred 3 +.It Xr gss_add_oid_set_member 3 +.It Xr gss_canonicalize_name 3 +.It Xr gss_compare_name 3 +.It Xr gss_context_time 3 +.It Xr gss_create_empty_oid_set 3 +.It Xr gss_delete_sec_context 3 +.It Xr gss_display_name 3 +.It Xr gss_display_status 3 +.It Xr gss_duplicate_name 3 +.It Xr gss_export_name 3 +.It Xr gss_export_sec_context 3 +.It Xr gss_get_mic 3 +.It Xr gss_import_name 3 +.It Xr gss_import_sec_context 3 +.It Xr gss_indicate_mechs 3 +.It Xr gss_init_sec_context 3 +.It Xr gss_inquire_context 3 +.It Xr gss_inquire_cred 3 +.It Xr gss_inquire_cred_by_mech 3 +.It Xr gss_inquire_mechs_for_name 3 +.It Xr gss_inquire_names_for_mech 3 +.It Xr gss_krb5_ccache_name 3 +.It Xr gss_krb5_compat_des3_mic 3 +.It Xr gss_krb5_copy_ccache 3 +.It Xr gss_krb5_extract_authz_data_from_sec_context 3 +.It Xr gss_krb5_import_ccache 3 +.It Xr gss_process_context_token 3 +.It Xr gss_release_buffer 3 +.It Xr gss_release_cred 3 +.It Xr gss_release_name 3 +.It Xr gss_release_oid_set 3 +.It Xr gss_seal 3 +.It Xr gss_sign 3 +.It Xr gss_test_oid_set_member 3 +.It Xr gss_unseal 3 +.It Xr gss_unwrap 3 +.It Xr gss_verify 3 +.It Xr gss_verify_mic 3 +.It Xr gss_wrap 3 +.It Xr gss_wrap_size_limit 3 +.El +.Sh COMPATIBILITY +The +.Nm Heimdal +GSS-API implementation had a bug in releases before 0.6 that made it +fail to inter-operate when using DES3 with other GSS-API +implementations when using +.Fn gss_get_mic +/ +.Fn gss_verify_mic . +It is possible to modify the behavior of the generator of the MIC with +the +.Pa krb5.conf +configuration file so that old clients/servers will still +work. +.Pp +New clients/servers will try both the old and new MIC in Heimdal 0.6. +In 0.7 it will check only if configured - the compatibility code will +be removed in 0.8. +.Pp +Heimdal 0.6 still generates by default the broken GSS-API DES3 mic, +this will change in 0.7 to generate correct des3 mic. +.Pp +To turn on compatibility with older clients and servers, change the +.Nm [gssapi] +.Ar broken_des3_mic +in +.Pa krb5.conf +that contains a list of globbing expressions that will be matched +against the server name. +To turn off generation of the old (incompatible) mic of the MIC use +.Nm [gssapi] +.Ar correct_des3_mic . +.Pp +If a match for a entry is in both +.Nm [gssapi] +.Ar correct_des3_mic +and +.Nm [gssapi] +.Ar broken_des3_mic , +the later will override. +.Pp +This config option modifies behaviour for both clients and servers. +.Pp +Microsoft implemented SPNEGO to Windows2000, however, they managed to +get it wrong, their implementation didn't fill in the MechListMIC in +the reply token with the right content. +There is a work around for this problem, but not all implementation +support it. +.Pp +Heimdal defaults to correct SPNEGO when the the kerberos +implementation uses CFX, or when it is configured by the user. +To turn on compatibility with peers, use option +.Nm [gssapi] +.Ar require_mechlist_mic . +.Sh EXAMPLES +.Bd -literal -offset indent +[gssapi] + broken_des3_mic = cvs/*@SU.SE + broken_des3_mic = host/*@E.KTH.SE + correct_des3_mic = host/*@SU.SE + require_mechlist_mic = host/*@SU.SE +.Ed +.Sh BUGS +All of 0.5.x versions of +.Nm heimdal +had broken token delegations in the client side, the server side was +correct. +.Sh SEE ALSO +.Xr krb5 3 , +.Xr krb5.conf 5 , +.Xr kerberos 8 diff --git a/third_party/heimdal/lib/gssapi/gssapi.h b/third_party/heimdal/lib/gssapi/gssapi.h new file mode 100644 index 0000000..d2f039a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_H_ +#define GSSAPI_H_ + +#include + +#endif diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi.h new file mode 100644 index 0000000..726543f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi.h @@ -0,0 +1,1281 @@ +/* + * Copyright (c) 1997 - 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef GSSAPI_GSSAPI_H_ +#define GSSAPI_GSSAPI_H_ + +/* + * First, include stddef.h to get size_t defined. + */ +#include +#include + +#include + +#ifndef BUILD_GSSAPI_LIB +#if defined(_WIN32) +#define GSSAPI_LIB_FUNCTION __declspec(dllimport) +#define GSSAPI_LIB_CALL __stdcall +#define GSSAPI_LIB_VARIABLE __declspec(dllimport) +#else +#define GSSAPI_LIB_FUNCTION +#define GSSAPI_LIB_CALL +#define GSSAPI_LIB_VARIABLE +#endif +#endif + +#ifndef GSSAPI_DEPRECATED_FUNCTION +#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) +#define GSSAPI_DEPRECATED_FUNCTION(X) __attribute__((deprecated)) +#else +#define GSSAPI_DEPRECATED_FUNCTION(X) +#endif +#endif + +/* Compatiblity with MIT Kerberos on the Mac */ +#if defined(__APPLE__) && (defined(__ppc__) || defined(__ppc64__) || defined(__i386__) || defined(__x86_64__)) +#pragma pack(push,2) +#endif + +#ifdef __cplusplus +#define GSSAPI_CPP_START extern "C" { +#define GSSAPI_CPP_END } +#else +#define GSSAPI_CPP_START +#define GSSAPI_CPP_END +#endif + +#ifdef _WIN32 +#define GSSAPI_CALLCONV __stdcall +#else +#define GSSAPI_CALLCONV +#endif + +/* + * Now define the three implementation-dependent types. + */ + +typedef uint32_t OM_uint32; +typedef uint64_t OM_uint64; + +typedef uint32_t gss_uint32; + +struct gss_name_t_desc_struct; +typedef struct gss_name_t_desc_struct *gss_name_t; +typedef const struct gss_name_t_desc_struct *gss_const_name_t; + +struct gss_ctx_id_t_desc_struct; +typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t; +typedef const struct gss_ctx_id_t_desc_struct *gss_const_ctx_id_t; + +typedef struct gss_OID_desc_struct { + OM_uint32 length; + void *elements; +} gss_OID_desc, *gss_OID; +typedef const gss_OID_desc * gss_const_OID; + +typedef struct gss_OID_set_desc_struct { + size_t count; + gss_OID elements; +} gss_OID_set_desc, *gss_OID_set; +typedef const gss_OID_set_desc * gss_const_OID_set; + +typedef int gss_cred_usage_t; + +struct gss_cred_id_t_desc_struct; +typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t; +typedef const struct gss_cred_id_t_desc_struct *gss_const_cred_id_t; + +typedef struct gss_buffer_desc_struct { + size_t length; + void *value; +} gss_buffer_desc, *gss_buffer_t; +typedef const gss_buffer_desc * gss_const_buffer_t; + +typedef struct gss_channel_bindings_struct { + OM_uint32 initiator_addrtype; + gss_buffer_desc initiator_address; + OM_uint32 acceptor_addrtype; + gss_buffer_desc acceptor_address; + gss_buffer_desc application_data; +} *gss_channel_bindings_t; +typedef const struct gss_channel_bindings_struct *gss_const_channel_bindings_t; + +/* GGF extension data types */ +typedef struct gss_buffer_set_desc_struct { + size_t count; + gss_buffer_desc *elements; +} gss_buffer_set_desc, *gss_buffer_set_t; + +typedef struct gss_iov_buffer_desc_struct { + OM_uint32 type; + gss_buffer_desc buffer; +} gss_iov_buffer_desc, *gss_iov_buffer_t; + +/* Credential store extensions */ +typedef struct gss_key_value_element_struct { + const char *key; + const char *value; +} gss_key_value_element_desc; + +typedef struct gss_key_value_set_struct { + OM_uint32 count; /* should be size_t, but for MIT compat */ + gss_key_value_element_desc *elements; +} gss_key_value_set_desc, *gss_key_value_set_t; + +typedef const gss_key_value_set_desc *gss_const_key_value_set_t; + +/* + * For now, define a QOP-type as an OM_uint32 + */ +typedef OM_uint32 gss_qop_t; + + +/* + * Flag bits for context-level services. + */ +#define GSS_C_DELEG_FLAG 1 +#define GSS_C_MUTUAL_FLAG 2 +#define GSS_C_REPLAY_FLAG 4 +#define GSS_C_SEQUENCE_FLAG 8 +#define GSS_C_CONF_FLAG 16 +#define GSS_C_INTEG_FLAG 32 +#define GSS_C_ANON_FLAG 64 +#define GSS_C_PROT_READY_FLAG 128 +#define GSS_C_TRANS_FLAG 256 + +#define GSS_C_CHANNEL_BOUND_FLAG 2048 +#define GSS_C_DCE_STYLE 4096 +#define GSS_C_IDENTIFY_FLAG 8192 +#define GSS_C_EXTENDED_ERROR_FLAG 16384 +#define GSS_C_DELEG_POLICY_FLAG 32768 + +/* + * Credential usage options + */ +#define GSS_C_BOTH 0 +#define GSS_C_INITIATE 1 +#define GSS_C_ACCEPT 2 + +/* + * Status code types for gss_display_status + */ +#define GSS_C_GSS_CODE 1 +#define GSS_C_MECH_CODE 2 + +/* + * The constant definitions for channel-bindings address families + */ +#define GSS_C_AF_UNSPEC 0 +#define GSS_C_AF_LOCAL 1 +#define GSS_C_AF_INET 2 +#define GSS_C_AF_IMPLINK 3 +#define GSS_C_AF_PUP 4 +#define GSS_C_AF_CHAOS 5 +#define GSS_C_AF_NS 6 +#define GSS_C_AF_NBS 7 +#define GSS_C_AF_ECMA 8 +#define GSS_C_AF_DATAKIT 9 +#define GSS_C_AF_CCITT 10 +#define GSS_C_AF_SNA 11 +#define GSS_C_AF_DECnet 12 +#define GSS_C_AF_DLI 13 +#define GSS_C_AF_LAT 14 +#define GSS_C_AF_HYLINK 15 +#define GSS_C_AF_APPLETALK 16 +#define GSS_C_AF_BSC 17 +#define GSS_C_AF_DSS 18 +#define GSS_C_AF_OSI 19 +#define GSS_C_AF_X25 21 +#define GSS_C_AF_INET6 24 + +#define GSS_C_AF_NULLADDR 255 + +/* + * Various Null values + */ +#define GSS_C_NO_NAME ((gss_name_t) 0) +#define GSS_C_NO_BUFFER ((gss_buffer_t) 0) +#define GSS_C_NO_BUFFER_SET ((gss_buffer_set_t) 0) +#define GSS_C_NO_OID ((gss_OID) 0) +#define GSS_C_NO_OID_SET ((gss_OID_set) 0) +#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0) +#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0) +#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0) +#define GSS_C_EMPTY_BUFFER {0, NULL} +#define GSS_C_EMPTY_BUFFER_SET {0, NULL} +#define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0) +#define GSS_C_NO_CRED_STORE ((gss_key_value_set_t)0) + +/* + * Some alternate names for a couple of the above + * values. These are defined for V1 compatibility. + */ +#define GSS_C_NULL_OID GSS_C_NO_OID +#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET + +/* + * Define the default Quality of Protection for per-message + * services. Note that an implementation that offers multiple + * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero + * (as done here) to mean "default protection", or to a specific + * explicit QOP value. However, a value of 0 should always be + * interpreted by a GSSAPI implementation as a request for the + * default protection level. + */ +#define GSS_C_QOP_DEFAULT 0 + +#define GSS_KRB5_CONF_C_QOP_DES 0x0100 +#define GSS_KRB5_CONF_C_QOP_DES3_KD 0x0200 + +/* + * Expiration time of 2^32-1 seconds means infinite lifetime for a + * credential or security context + */ +#define GSS_C_INDEFINITE 0xfffffffful + +/* + * Type of gss_wrap_iov()/gss_unwrap_iov(). + */ + +#define GSS_IOV_BUFFER_TYPE_EMPTY 0 +#define GSS_IOV_BUFFER_TYPE_DATA 1 +#define GSS_IOV_BUFFER_TYPE_HEADER 2 +#define GSS_IOV_BUFFER_TYPE_MECH_PARAMS 3 + +#define GSS_IOV_BUFFER_TYPE_TRAILER 7 +#define GSS_IOV_BUFFER_TYPE_PADDING 9 +#define GSS_IOV_BUFFER_TYPE_STREAM 10 +#define GSS_IOV_BUFFER_TYPE_SIGN_ONLY 11 + +#define GSS_IOV_BUFFER_TYPE_FLAG_MASK 0xffff0000 +#define GSS_IOV_BUFFER_FLAG_ALLOCATE 0x00010000 +#define GSS_IOV_BUFFER_FLAG_ALLOCATED 0x00020000 + +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE 0x00010000 /* old name */ +#define GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED 0x00020000 /* old name */ + +#define GSS_IOV_BUFFER_TYPE(_t) ((_t) & ~GSS_IOV_BUFFER_TYPE_FLAG_MASK) +#define GSS_IOV_BUFFER_FLAGS(_t) ((_t) & GSS_IOV_BUFFER_TYPE_FLAG_MASK) + +GSSAPI_CPP_START + +#include + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_user_name_oid_desc; +#define GSS_C_NT_USER_NAME (&__gss_c_nt_user_name_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_machine_uid_name_oid_desc; +#define GSS_C_NT_MACHINE_UID_NAME (&__gss_c_nt_machine_uid_name_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_string_uid_name_oid_desc; +#define GSS_C_NT_STRING_UID_NAME (&__gss_c_nt_string_uid_name_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_hostbased_service_x_oid_desc; +#define GSS_C_NT_HOSTBASED_SERVICE_X (&__gss_c_nt_hostbased_service_x_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_hostbased_service_oid_desc; +#define GSS_C_NT_HOSTBASED_SERVICE (&__gss_c_nt_hostbased_service_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_anonymous_oid_desc; +#define GSS_C_NT_ANONYMOUS (&__gss_c_nt_anonymous_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_export_name_oid_desc; +#define GSS_C_NT_EXPORT_NAME (&__gss_c_nt_export_name_oid_desc) + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x06"}, corresponding to an + * object-identifier value of {iso(1) identified-organization(3) dod(6) + * internet(1) security(5) nametypes(6) gss-composite-export(6)}. + * The constant GSS_C_NT_COMPOSITE_EXPORT [RFC6680] should be initialized to + * point to that gss_OID_desc. + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_composite_export_oid_desc; +#define GSS_C_NT_COMPOSITE_EXPORT (&__gss_c_nt_composite_export_oid_desc) + +/* Major status codes */ + +#define GSS_S_COMPLETE 0 + +/* + * Some "helper" definitions to make the status code macros obvious. + */ +#define GSS_C_CALLING_ERROR_OFFSET 24 +#define GSS_C_ROUTINE_ERROR_OFFSET 16 +#define GSS_C_SUPPLEMENTARY_OFFSET 0 +#define GSS_C_CALLING_ERROR_MASK 0377ul +#define GSS_C_ROUTINE_ERROR_MASK 0377ul +#define GSS_C_SUPPLEMENTARY_MASK 0177777ul + +/* + * The macros that test status codes for error conditions. + * Note that the GSS_ERROR() macro has changed slightly from + * the V1 GSSAPI so that it now evaluates its argument + * only once. + */ +#define GSS_CALLING_ERROR(x) \ + (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)) +#define GSS_ROUTINE_ERROR(x) \ + (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)) +#define GSS_SUPPLEMENTARY_INFO(x) \ + (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET)) +#define GSS_ERROR(x) \ + (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \ + (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))) + +/* + * Now the actual status code definitions + */ + +/* + * Calling errors: + */ +#define GSS_S_CALL_INACCESSIBLE_READ \ + (1ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_INACCESSIBLE_WRITE \ + (2ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_BAD_STRUCTURE \ + (3ul << GSS_C_CALLING_ERROR_OFFSET) + +/* + * Routine errors: + */ +#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET) + +#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MIC GSS_S_BAD_SIG +#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MECH_ATTR (19ul << GSS_C_ROUTINE_ERROR_OFFSET) + +/* + * Apparently awating spec fix. + */ +#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE + +/* + * Supplementary info bits: + */ +#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) +#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) +#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) +#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) + +/* + * Finally, function prototypes for the GSS-API routines. + */ + +#define GSS_C_OPTION_MASK 0xffff +#define GSS_C_CRED_NO_UI 0x10000 + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_acquire_cred + (OM_uint32 * /*minor_status*/, + gss_const_name_t /*desired_name*/, + OM_uint32 /*time_req*/, + const gss_OID_set /*desired_mechs*/, + gss_cred_usage_t /*cred_usage*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_cred + (OM_uint32 * /*minor_status*/, + gss_cred_id_t * /*cred_handle*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_init_sec_context + (OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*initiator_cred_handle*/, + gss_ctx_id_t * /*context_handle*/, + gss_const_name_t /*target_name*/, + const gss_OID /*mech_type*/, + OM_uint32 /*req_flags*/, + OM_uint32 /*time_req*/, + const gss_channel_bindings_t /*input_chan_bindings*/, + const gss_buffer_t /*input_token*/, + gss_OID * /*actual_mech_type*/, + gss_buffer_t /*output_token*/, + OM_uint32 * /*ret_flags*/, + OM_uint32 * /*time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_accept_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + gss_const_cred_id_t /*acceptor_cred_handle*/, + const gss_buffer_t /*input_token_buffer*/, + const gss_channel_bindings_t /*input_chan_bindings*/, + gss_name_t * /*src_name*/, + gss_OID * /*mech_type*/, + gss_buffer_t /*output_token*/, + OM_uint32 * /*ret_flags*/, + OM_uint32 * /*time_rec*/, + gss_cred_id_t * /*delegated_cred_handle*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_process_context_token + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + const gss_buffer_t /*token_buffer*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_delete_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + gss_buffer_t /*output_token*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_context_time + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + OM_uint32 * /*time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_get_mic + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + gss_qop_t /*qop_req*/, + const gss_buffer_t /*message_buffer*/, + gss_buffer_t /*message_token*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_verify_mic + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + const gss_buffer_t /*message_buffer*/, + const gss_buffer_t /*token_buffer*/, + gss_qop_t * /*qop_state*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_wrap + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + int /*conf_req_flag*/, + gss_qop_t /*qop_req*/, + const gss_buffer_t /*input_message_buffer*/, + int * /*conf_state*/, + gss_buffer_t /*output_message_buffer*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_unwrap + (OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + const gss_buffer_t /*input_message_buffer*/, + gss_buffer_t /*output_message_buffer*/, + int * /*conf_state*/, + gss_qop_t * /*qop_state*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_display_status + (OM_uint32 * /*minor_status*/, + OM_uint32 /*status_value*/, + int /*status_type*/, + const gss_OID /*mech_type*/, + OM_uint32 * /*message_context*/, + gss_buffer_t /*status_string*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_indicate_mechs + (OM_uint32 * /*minor_status*/, + gss_OID_set * /*mech_set*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_compare_name + (OM_uint32 * /*minor_status*/, + gss_const_name_t /*name1*/, + gss_const_name_t /*name2*/, + int * /*name_equal*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_display_name + (OM_uint32 * /*minor_status*/, + gss_const_name_t /*input_name*/, + gss_buffer_t /*output_name_buffer*/, + gss_OID * /*output_name_type*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_import_name + (OM_uint32 * /*minor_status*/, + const gss_buffer_t /*input_name_buffer*/, + const gss_OID /*input_name_type*/, + gss_name_t * /*output_name*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_export_name + (OM_uint32 * /*minor_status*/, + gss_const_name_t /*input_name*/, + gss_buffer_t /*exported_name*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_name + (OM_uint32 * /*minor_status*/, + gss_name_t * /*input_name*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_buffer + (OM_uint32 * /*minor_status*/, + gss_buffer_t /*buffer*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_oid_set + (OM_uint32 * /*minor_status*/, + gss_OID_set * /*set*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_cred + (OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*cred_handle*/, + gss_name_t * /*name*/, + OM_uint32 * /*lifetime*/, + gss_cred_usage_t * /*cred_usage*/, + gss_OID_set * /*mechanisms*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_context ( + OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + gss_name_t * /*src_name*/, + gss_name_t * /*targ_name*/, + OM_uint32 * /*lifetime_rec*/, + gss_OID * /*mech_type*/, + OM_uint32 * /*ctx_flags*/, + int * /*locally_initiated*/, + int * /*open_context*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_wrap_size_limit ( + OM_uint32 * /*minor_status*/, + gss_const_ctx_id_t /*context_handle*/, + int /*conf_req_flag*/, + gss_qop_t /*qop_req*/, + OM_uint32 /*req_output_size*/, + OM_uint32 * /*max_input_size*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_add_cred ( + OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*input_cred_handle*/, + gss_const_name_t /*desired_name*/, + const gss_OID /*desired_mech*/, + gss_cred_usage_t /*cred_usage*/, + OM_uint32 /*initiator_time_req*/, + OM_uint32 /*acceptor_time_req*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*initiator_time_rec*/, + OM_uint32 * /*acceptor_time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_cred_by_mech ( + OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*cred_handle*/, + const gss_OID /*mech_type*/, + gss_name_t * /*name*/, + OM_uint32 * /*initiator_lifetime*/, + OM_uint32 * /*acceptor_lifetime*/, + gss_cred_usage_t * /*cred_usage*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_export_sec_context ( + OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + gss_buffer_t /*interprocess_token*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_import_sec_context ( + OM_uint32 * /*minor_status*/, + const gss_buffer_t /*interprocess_token*/, + gss_ctx_id_t * /*context_handle*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_create_empty_oid_set ( + OM_uint32 * /*minor_status*/, + gss_OID_set * /*oid_set*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_add_oid_set_member ( + OM_uint32 * /*minor_status*/, + const gss_OID /*member_oid*/, + gss_OID_set * /*oid_set*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_test_oid_set_member ( + OM_uint32 * /*minor_status*/, + const gss_OID /*member*/, + const gss_OID_set /*set*/, + int * /*present*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_names_for_mech ( + OM_uint32 * /*minor_status*/, + const gss_OID /*mechanism*/, + gss_OID_set * /*name_types*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_mechs_for_name ( + OM_uint32 * /*minor_status*/, + gss_const_name_t /*input_name*/, + gss_OID_set * /*mech_types*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_canonicalize_name ( + OM_uint32 * /*minor_status*/, + gss_const_name_t /*input_name*/, + const gss_OID /*mech_type*/, + gss_name_t * /*output_name*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_duplicate_name ( + OM_uint32 * /*minor_status*/, + gss_const_name_t /*src_name*/, + gss_name_t * /*dest_name*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_duplicate_oid ( + OM_uint32 * /* minor_status */, + gss_OID /* src_oid */, + gss_OID * /* dest_oid */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_duplicate_oid_set ( + OM_uint32 * /* minor_status */, + gss_OID_set /* src_oid */, + gss_OID_set * /* dest_oid */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_oid + (OM_uint32 * /*minor_status*/, + gss_OID * /* oid */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_oid_to_str( + OM_uint32 * /*minor_status*/, + gss_OID /* oid */, + gss_buffer_t /* str */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_sec_context_by_oid( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_sec_context_option (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_cred_option (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID object, + const gss_buffer_t value); + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_oid_equal(gss_const_OID a, gss_const_OID b); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_create_empty_buffer_set + (OM_uint32 * minor_status, + gss_buffer_set_t *buffer_set); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_buffer_set_member + (OM_uint32 * minor_status, + const gss_buffer_t member_buffer, + gss_buffer_set_t *buffer_set); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_buffer_set + (OM_uint32 * minor_status, + gss_buffer_set_t *buffer_set); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_cred_by_oid(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set); + +/* + * RFC 4401 + */ + +#define GSS_C_PRF_KEY_FULL 0 +#define GSS_C_PRF_KEY_PARTIAL 1 + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_pseudo_random + (OM_uint32 *minor_status, + gss_ctx_id_t context, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred(OM_uint32 * /* minor_status */, + gss_cred_id_t /* input_cred_handle */, + gss_cred_usage_t /* cred_usage */, + const gss_OID /* desired_mech */, + OM_uint32 /* overwrite_cred */, + OM_uint32 /* default_cred */, + gss_OID_set * /* elements_stored */, + gss_cred_usage_t * /* cred_usage_stored */); + + +/* + * Query functions + */ + +typedef struct { + size_t header; /**< size of header */ + size_t trailer; /**< size of trailer */ + size_t max_msg_size; /**< maximum message size */ + size_t buffers; /**< extra GSS_IOV_BUFFER_TYPE_EMPTY buffer to pass */ + size_t blocksize; /**< Specificed optimal size of messages, also + is the maximum padding size + (GSS_IOV_BUFFER_TYPE_PADDING) */ +} gss_context_stream_sizes; + +extern gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_attr_stream_sizes_oid_desc; +#define GSS_C_ATTR_STREAM_SIZES (&__gss_c_attr_stream_sizes_oid_desc) + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_context_query_attributes(OM_uint32 * /* minor_status */, + gss_const_ctx_id_t /* context_handle */, + const gss_OID /* attribute */, + void * /*data*/, + size_t /* len */); +/* + * The following routines are obsolete variants of gss_get_mic, + * gss_verify_mic, gss_wrap and gss_unwrap. They should be + * provided by GSSAPI V2 implementations for backwards + * compatibility with V1 applications. Distinct entrypoints + * (as opposed to #defines) should be provided, both to allow + * GSSAPI V1 applications to link against GSSAPI V2 implementations, + * and to retain the slight parameter type differences between the + * obsolete versions of these routines and their current forms. + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_sign + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*qop_req*/, + gss_buffer_t /*message_buffer*/, + gss_buffer_t /*message_token*/ + ) GSSAPI_DEPRECATED_FUNCTION("Use gss_get_mic"); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_verify + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + gss_buffer_t /*message_buffer*/, + gss_buffer_t /*token_buffer*/, + int * /*qop_state*/ + ) GSSAPI_DEPRECATED_FUNCTION("Use gss_verify_mic"); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_seal + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*conf_req_flag*/, + int /*qop_req*/, + gss_buffer_t /*input_message_buffer*/, + int * /*conf_state*/, + gss_buffer_t /*output_message_buffer*/ + ) GSSAPI_DEPRECATED_FUNCTION("Use gss_wrap"); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_unseal + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + gss_buffer_t /*input_message_buffer*/, + gss_buffer_t /*output_message_buffer*/, + int * /*conf_state*/, + int * /*qop_state*/ + ) GSSAPI_DEPRECATED_FUNCTION("Use gss_unwrap"); + +/** + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_encapsulate_token(gss_const_buffer_t /* input_token */, + gss_const_OID /* oid */, + gss_buffer_t /* output_token */); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_decapsulate_token(gss_const_buffer_t /* input_token */, + gss_const_OID /* oid */, + gss_buffer_t /* output_token */); + + + +/* + * AEAD support + */ + +/* + * GSS_IOV + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_iov(OM_uint32 *, gss_ctx_id_t, int, gss_qop_t, int *, + gss_iov_buffer_desc *, int); + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap_iov(OM_uint32 *, gss_ctx_id_t, int *, gss_qop_t *, + gss_iov_buffer_desc *, int); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_iov_length(OM_uint32 *, gss_ctx_id_t, int, gss_qop_t, int *, + gss_iov_buffer_desc *, int); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_iov_buffer(OM_uint32 *, gss_iov_buffer_desc *, int); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_aead(OM_uint32 *, gss_ctx_id_t, int, gss_qop_t, + gss_buffer_t, gss_buffer_t, int *, gss_buffer_t); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap_aead(OM_uint32 *, gss_ctx_id_t, gss_buffer_t, + gss_buffer_t, gss_buffer_t, int *, gss_qop_t *); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_cred(OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred_handle */, + gss_buffer_t /* cred_token */); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_import_cred(OM_uint32 * /* minor_status */, + gss_buffer_t /* cred_token */, + gss_cred_id_t * /* cred_handle */); + +/* + * mech option + */ + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_mo_set(gss_const_OID mech, gss_const_OID option, + int enable, gss_buffer_t value); + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_mo_get(gss_const_OID mech, gss_const_OID option, gss_buffer_t value); + +GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL +gss_mo_list(gss_const_OID mech, gss_OID_set *options); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_mo_name(gss_const_OID mech, gss_const_OID options, gss_buffer_t name); + +/* + * SASL glue functions and mech inquire + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_mech_for_saslname(OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_attrs_for_mech(OM_uint32 * minor_status, + gss_const_OID mech, + gss_OID_set *mech_attr, + gss_OID_set *known_mech_attrs); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_mech_attr(OM_uint32 * minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc); + +/* + * Solaris compat + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_acquire_cred_with_password + (OM_uint32 * /*minor_status*/, + gss_const_name_t /*desired_name*/, + const gss_buffer_t /*password*/, + OM_uint32 /*time_req*/, + const gss_OID_set /*desired_mechs*/, + gss_cred_usage_t /*cred_usage*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_add_cred_with_password ( + OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*input_cred_handle*/, + gss_const_name_t /*desired_name*/, + const gss_OID /*desired_mech*/, + const gss_buffer_t /*password*/, + gss_cred_usage_t /*cred_usage*/, + OM_uint32 /*initiator_time_req*/, + OM_uint32 /*acceptor_time_req*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*initiator_time_rec*/, + OM_uint32 * /*acceptor_time_rec*/ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_localname( + OM_uint32 *minor, + gss_const_name_t name, + const gss_OID mech_type, + gss_buffer_t localname); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_pname_to_uid( + OM_uint32 *minor, + gss_const_name_t name, + const gss_OID mech_type, + uid_t *uidOut); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_authorize_localname( + OM_uint32 *minor, + gss_const_name_t name, + gss_const_name_t user); + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_userok(gss_const_name_t name, + const char *user); + +extern GSSAPI_LIB_VARIABLE gss_buffer_desc __gss_c_attr_local_login_user; +#define GSS_C_ATTR_LOCAL_LOGIN_USER (&__gss_c_attr_local_login_user) + +/* + * Naming extensions + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_display_name_ext ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_OID, /* display_as_name_type */ + gss_buffer_t /* display_name */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_name ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int *, /* name_is_MN */ + gss_OID *, /* MN_mech */ + gss_buffer_set_t * /* attrs */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_get_name_attribute ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* attr */ + int *, /* authenticated */ + int *, /* complete */ + gss_buffer_t, /* value */ + gss_buffer_t, /* display_value */ + int * /* more */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_set_name_attribute ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* complete */ + gss_buffer_t, /* attr */ + gss_buffer_t /* value */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_delete_name_attribute ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* attr */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_export_name_composite ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* exp_composite_name */ + ); + +/* + * Other extensions + */ + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_duplicate_cred ( + OM_uint32 * /*minor_status*/, + gss_const_cred_id_t /*input_cred_handle*/, + gss_cred_id_t * /*output_cred_handle*/ + ); + +/* Return a mechanism short name from an OID */ +GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL +gss_oid_to_name(gss_const_OID oid); + +/* Return a mechanism OID from a short name or dotted OID */ +GSSAPI_LIB_FUNCTION gss_OID GSSAPI_LIB_CALL +gss_name_to_oid(const char *name); + +/* + * Credential store extensions + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_from( + OM_uint32 * /* minor_status */, + gss_const_name_t /* desired_name */, + OM_uint32 /* time_req */, + const gss_OID_set /* desired_mechs */, + gss_cred_usage_t /* cred_usage */, + gss_const_key_value_set_t /* cred_store */, + gss_cred_id_t * /* output_cred_handle */, + gss_OID_set * /* actual_mechs */, + OM_uint32 * /* time_rec */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_cred_from( + OM_uint32 * /* minor_status */, + gss_cred_id_t /* input_cred_handle */, + gss_const_name_t /* desired_name */, + const gss_OID /* desired_mech */, + gss_cred_usage_t /* cred_usage */, + OM_uint32 /* initiator_time_req */, + OM_uint32 /* acceptor_time_req */, + gss_const_key_value_set_t /* cred_store */, + gss_cred_id_t * /* output_cred_handle */, + gss_OID_set * /* actual_mechs */, + OM_uint32 * /* initiator_time_rec */, + OM_uint32 * /*acceptor_time_rec */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into( + OM_uint32 * /* minor_status */, + gss_const_cred_id_t /* input_cred_handle */, + gss_cred_usage_t /* input_usage */, + const gss_OID /* desired_mech */, + OM_uint32 /* overwrite_cred */, + OM_uint32 /* default_cred */, + gss_const_key_value_set_t /* cred_store */, + gss_OID_set * /* elements_stored */, + gss_cred_usage_t * /* cred_usage_stored */ + ); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into2( + OM_uint32 * /* minor_status */, + gss_const_cred_id_t /* input_cred_handle */, + gss_cred_usage_t /* input_usage */, + const gss_OID /* desired_mech */, + OM_uint32 /* store_cred_flags */, + gss_const_key_value_set_t /* cred_store */, + gss_OID_set * /* elements_stored */, + gss_cred_usage_t * /* cred_usage_stored */, + gss_buffer_set_t * /* env */ + ); + +enum gss_store_cred_flags { + GSS_C_STORE_CRED_DEFAULT = 1, + GSS_C_STORE_CRED_OVERWRITE = 2, + GSS_C_STORE_CRED_SET_PROCESS = 4, +}; +#define GSS_C_STORE_CRED_DEFAULT GSS_C_STORE_CRED_DEFAULT +#define GSS_C_STORE_CRED_OVERWRITE GSS_C_STORE_CRED_OVERWRITE +#define GSS_C_STORE_CRED_SET_PROCESS GSS_C_STORE_CRED_SET_PROCESS + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_CALLCONV +gss_set_neg_mechs( + OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred_handle */, + const gss_OID_set /* mech_list */); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_CALLCONV +gss_get_neg_mechs( + OM_uint32 * /* minor_status */, + gss_const_cred_id_t /* cred_handle */, + gss_OID_set * /* mech_list */); + +GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL +gss_set_log_function(void *ctx, void (*func)(void * ctx, int level, const char *fmt, va_list)); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_destroy_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle); + +/* + * S4UProxy and S4USelf extensions. + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_CALLCONV +gss_acquire_cred_impersonate_name( + OM_uint32 * /* minor_status */, + gss_const_cred_id_t /* icred */, + gss_const_name_t /* desired_name */, + OM_uint32 /* time_req */, + gss_OID_set /* desired_mechs */, + gss_cred_usage_t /* cred_usage */, + gss_cred_id_t * /* output_cred */, + gss_OID_set * /* actual_mechs */, + OM_uint32 * /* time_rec */ + ); + +GSSAPI_CPP_END + +#if defined(__APPLE__) && (defined(__ppc__) || defined(__ppc64__) || defined(__i386__) || defined(__x86_64__)) +#pragma pack(pop) +#endif + +#undef GSSAPI_DEPRECATED_FUNCTION + +#endif /* GSSAPI_GSSAPI_H_ */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h new file mode 100644 index 0000000..818042f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_krb5.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_KRB5_H_ +#define GSSAPI_KRB5_H_ + +#include +#include + +GSSAPI_CPP_START + +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(x) +#endif + +#ifndef GSSKRB5_FUNCTION_DEPRECATED +#define GSSKRB5_FUNCTION_DEPRECATED __attribute__((deprecated)) +#endif + + +/* + * This is for kerberos5 names. + */ + +extern gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_oid_desc; +#define GSS_KRB5_NT_PRINCIPAL_NAME (&__gss_krb5_nt_principal_name_oid_desc) + +#define GSS_KRB5_NT_USER_NAME (&__gss_c_nt_user_name_oid_desc) +#define GSS_KRB5_NT_MACHINE_UID_NAME (&__gss_c_nt_machine_uid_name_oid_desc) +#define GSS_KRB5_NT_STRING_UID_NAME (&__gss_c_nt_string_uid_name_oid_desc) + +/* for compatibility with MIT api */ + +#define gss_mech_krb5 GSS_KRB5_MECHANISM +#define gss_krb5_nt_general_name GSS_KRB5_NT_PRINCIPAL_NAME + +/* + * kerberos mechanism specific functions + */ + +struct krb5_keytab_data; +struct krb5_ccache_data; +struct Principal; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_ccache_name(OM_uint32 * /*minor_status*/, + const char * /*name */, + const char ** /*out_name */); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gsskrb5_register_acceptor_identity + (const char * /*identity*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL krb5_gss_register_acceptor_identity + (const char * /*identity*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_krb5_copy_ccache + (OM_uint32 * /*minor*/, + gss_cred_id_t /*cred*/, + struct krb5_ccache_data * /*out*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_import_cred(OM_uint32 * /*minor*/, + struct krb5_ccache_data * /*in*/, + struct Principal * /*keytab_principal*/, + struct krb5_keytab_data * /*keytab*/, + gss_cred_id_t * /*out*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_krb5_get_tkt_flags + (OM_uint32 * /*minor*/, + gss_ctx_id_t /*context_handle*/, + OM_uint32 * /*tkt_flags*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_authz_data_from_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*ad_type*/, + gss_buffer_t /*ad_data*/); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_dns_canonicalize(int); + +struct gsskrb5_send_to_kdc { + void *func; + void *ptr; +}; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *) + GSSKRB5_FUNCTION_DEPRECATED; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_default_realm(const char *); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_authtime_from_sec_context(OM_uint32 *, gss_ctx_id_t, time_t *); + +struct EncryptionKey; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_service_keyblock(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + struct EncryptionKey **out); +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_initiator_subkey(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + struct EncryptionKey **out); +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_subkey(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + struct EncryptionKey **out); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_time_offset(int); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_time_offset(int *); + +struct gsskrb5_krb5_plugin { + int type; + char *name; + void *symbol; +}; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *); + + +/* + * Lucid - NFSv4 interface to GSS-API KRB5 to expose key material to + * do GSS content token handling in-kernel. + */ + +typedef struct gss_krb5_lucid_key { + OM_uint32 type; + OM_uint32 length; + void * data; +} gss_krb5_lucid_key_t; + +typedef struct gss_krb5_rfc1964_keydata { + OM_uint32 sign_alg; + OM_uint32 seal_alg; + gss_krb5_lucid_key_t ctx_key; +} gss_krb5_rfc1964_keydata_t; + +typedef struct gss_krb5_cfx_keydata { + OM_uint32 have_acceptor_subkey; + gss_krb5_lucid_key_t ctx_key; + gss_krb5_lucid_key_t acceptor_subkey; +} gss_krb5_cfx_keydata_t; + +typedef struct gss_krb5_lucid_context_v1 { + OM_uint32 version; + OM_uint32 initiate; + OM_uint32 endtime; + OM_uint64 send_seq; + OM_uint64 recv_seq; + OM_uint32 protocol; + gss_krb5_rfc1964_keydata_t rfc1964_kd; + gss_krb5_cfx_keydata_t cfx_kd; +} gss_krb5_lucid_context_v1_t; + +typedef struct gss_krb5_lucid_context_version { + OM_uint32 version; /* Structure version number */ +} gss_krb5_lucid_context_version_t; + +/* + * Function declarations + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + OM_uint32 version, + void **kctx); + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, + void *kctx); + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, + gss_cred_id_t cred, + OM_uint32 num_enctypes, + int32_t *enctypes); + +#define GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "urn:ietf:kerberos:nameattr-" + +GSSAPI_CPP_END + +#endif /* GSSAPI_SPNEGO_H_ */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_netlogon.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_netlogon.h new file mode 100644 index 0000000..52201a6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_netlogon.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006 - 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_NETLOGON_H_ +#define GSSAPI_NETLOGON_H_ + +#include + +GSSAPI_CPP_START + +extern GSSAPI_LIB_VARIABLE gss_OID GSS_NETLOGON_MECHANISM; +extern GSSAPI_LIB_VARIABLE gss_OID GSS_NETLOGON_NT_NETBIOS_DNS_NAME; +extern GSSAPI_LIB_VARIABLE gss_OID GSS_NETLOGON_SET_SESSION_KEY_X; +extern GSSAPI_LIB_VARIABLE gss_OID GSS_NETLOGON_SET_SIGN_ALGORITHM_X; + +GSSAPI_CPP_END + +#endif /* GSSAPI_NETLOGON_H_ */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_ntlm.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_ntlm.h new file mode 100644 index 0000000..e37c003 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_ntlm.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006 - 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_NTLM_H_ +#define GSSAPI_NTLM_H_ + +#include + +#endif /* GSSAPI_NTLM_H_ */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_oid.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_oid.h new file mode 100644 index 0000000..fabd090 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_oid.h @@ -0,0 +1,262 @@ +/* Generated file */ +#ifndef GSSAPI_GSSAPI_OID +#define GSSAPI_GSSAPI_OID 1 + + /* contact Love Hörnquist Åstrand for new oid arcs */ + /* + * 1.2.752.43.13 Heimdal GSS-API Extensions + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_copy_ccache_x_oid_desc; +#define GSS_KRB5_COPY_CCACHE_X (&__gss_krb5_copy_ccache_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_tkt_flags_x_oid_desc; +#define GSS_KRB5_GET_TKT_FLAGS_X (&__gss_krb5_get_tkt_flags_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_extract_authz_data_from_sec_context_x_oid_desc; +#define GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X (&__gss_krb5_extract_authz_data_from_sec_context_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_compat_des3_mic_x_oid_desc; +#define GSS_KRB5_COMPAT_DES3_MIC_X (&__gss_krb5_compat_des3_mic_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_register_acceptor_identity_x_oid_desc; +#define GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X (&__gss_krb5_register_acceptor_identity_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_export_lucid_context_x_oid_desc; +#define GSS_KRB5_EXPORT_LUCID_CONTEXT_X (&__gss_krb5_export_lucid_context_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_export_lucid_context_v1_x_oid_desc; +#define GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X (&__gss_krb5_export_lucid_context_v1_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_set_dns_canonicalize_x_oid_desc; +#define GSS_KRB5_SET_DNS_CANONICALIZE_X (&__gss_krb5_set_dns_canonicalize_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_subkey_x_oid_desc; +#define GSS_KRB5_GET_SUBKEY_X (&__gss_krb5_get_subkey_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_initiator_subkey_x_oid_desc; +#define GSS_KRB5_GET_INITIATOR_SUBKEY_X (&__gss_krb5_get_initiator_subkey_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_acceptor_subkey_x_oid_desc; +#define GSS_KRB5_GET_ACCEPTOR_SUBKEY_X (&__gss_krb5_get_acceptor_subkey_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_send_to_kdc_x_oid_desc; +#define GSS_KRB5_SEND_TO_KDC_X (&__gss_krb5_send_to_kdc_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_authtime_x_oid_desc; +#define GSS_KRB5_GET_AUTHTIME_X (&__gss_krb5_get_authtime_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_service_keyblock_x_oid_desc; +#define GSS_KRB5_GET_SERVICE_KEYBLOCK_X (&__gss_krb5_get_service_keyblock_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_set_allowable_enctypes_x_oid_desc; +#define GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X (&__gss_krb5_set_allowable_enctypes_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_set_default_realm_x_oid_desc; +#define GSS_KRB5_SET_DEFAULT_REALM_X (&__gss_krb5_set_default_realm_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_ccache_name_x_oid_desc; +#define GSS_KRB5_CCACHE_NAME_X (&__gss_krb5_ccache_name_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_set_time_offset_x_oid_desc; +#define GSS_KRB5_SET_TIME_OFFSET_X (&__gss_krb5_set_time_offset_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_get_time_offset_x_oid_desc; +#define GSS_KRB5_GET_TIME_OFFSET_X (&__gss_krb5_get_time_offset_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_plugin_register_x_oid_desc; +#define GSS_KRB5_PLUGIN_REGISTER_X (&__gss_krb5_plugin_register_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_ntlm_get_session_key_x_oid_desc; +#define GSS_NTLM_GET_SESSION_KEY_X (&__gss_ntlm_get_session_key_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_ntlm_oid_desc; +#define GSS_C_NT_NTLM (&__gss_c_nt_ntlm_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_nt_dn_oid_desc; +#define GSS_C_NT_DN (&__gss_c_nt_dn_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_nt_principal_name_referral_oid_desc; +#define GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL (&__gss_krb5_nt_principal_name_referral_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_avguest_oid_desc; +#define GSS_C_NTLM_AVGUEST (&__gss_c_ntlm_avguest_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_v1_oid_desc; +#define GSS_C_NTLM_V1 (&__gss_c_ntlm_v1_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_v2_oid_desc; +#define GSS_C_NTLM_V2 (&__gss_c_ntlm_v2_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_session_key_oid_desc; +#define GSS_C_NTLM_SESSION_KEY (&__gss_c_ntlm_session_key_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_force_v1_oid_desc; +#define GSS_C_NTLM_FORCE_V1 (&__gss_c_ntlm_force_v1_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_cred_no_ci_flags_x_oid_desc; +#define GSS_KRB5_CRED_NO_CI_FLAGS_X (&__gss_krb5_cred_no_ci_flags_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_import_cred_x_oid_desc; +#define GSS_KRB5_IMPORT_CRED_X (&__gss_krb5_import_cred_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_import_rfc4121_context_x_oid_desc; +#define GSS_KRB5_IMPORT_RFC4121_CONTEXT_X (&__gss_krb5_import_rfc4121_context_x_oid_desc) + + /* glue for gss_inquire_saslname_for_mech */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_sasl_mech_name_oid_desc; +#define GSS_C_MA_SASL_MECH_NAME (&__gss_c_ma_sasl_mech_name_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_name_oid_desc; +#define GSS_C_MA_MECH_NAME (&__gss_c_ma_mech_name_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_description_oid_desc; +#define GSS_C_MA_MECH_DESCRIPTION (&__gss_c_ma_mech_description_oid_desc) + +/* Heimdal mechanisms - 1.2.752.43.14 */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_sasl_digest_md5_mechanism_oid_desc; +#define GSS_SASL_DIGEST_MD5_MECHANISM (&__gss_sasl_digest_md5_mechanism_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_netlogon_mechanism_oid_desc; +#define GSS_NETLOGON_MECHANISM (&__gss_netlogon_mechanism_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_netlogon_set_session_key_x_oid_desc; +#define GSS_NETLOGON_SET_SESSION_KEY_X (&__gss_netlogon_set_session_key_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_netlogon_set_sign_algorithm_x_oid_desc; +#define GSS_NETLOGON_SET_SIGN_ALGORITHM_X (&__gss_netlogon_set_sign_algorithm_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_netlogon_nt_netbios_dns_name_oid_desc; +#define GSS_NETLOGON_NT_NETBIOS_DNS_NAME (&__gss_netlogon_nt_netbios_dns_name_oid_desc) + +/* GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X.128 */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_win2k_pac_x_oid_desc; +#define GSS_C_INQ_WIN2K_PAC_X (&__gss_c_inq_win2k_pac_x_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_sspi_session_key_oid_desc; +#define GSS_C_INQ_SSPI_SESSION_KEY (&__gss_c_inq_sspi_session_key_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_negoex_key_oid_desc; +#define GSS_C_INQ_NEGOEX_KEY (&__gss_c_inq_negoex_key_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_negoex_verify_key_oid_desc; +#define GSS_C_INQ_NEGOEX_VERIFY_KEY (&__gss_c_inq_negoex_verify_key_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_require_mechlist_mic_oid_desc; +#define GSS_C_INQ_REQUIRE_MECHLIST_MIC (&__gss_c_inq_require_mechlist_mic_oid_desc) + +/* + * "Standard" mechs + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_mechanism_oid_desc; +#define GSS_KRB5_MECHANISM (&__gss_krb5_mechanism_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_ntlm_mechanism_oid_desc; +#define GSS_NTLM_MECHANISM (&__gss_ntlm_mechanism_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_spnego_mechanism_oid_desc; +#define GSS_SPNEGO_MECHANISM (&__gss_spnego_mechanism_oid_desc) + + /* From Luke Howard */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_inq_peer_has_buggy_spnego_oid_desc; +#define GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO (&__gss_c_inq_peer_has_buggy_spnego_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ntlm_reset_crypto_oid_desc; +#define GSS_C_NTLM_RESET_CRYPTO (&__gss_c_ntlm_reset_crypto_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_negoex_mechanism_oid_desc; +#define GSS_NEGOEX_MECHANISM (&__gss_negoex_mechanism_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_sanon_x25519_mechanism_oid_desc; +#define GSS_SANON_X25519_MECHANISM (&__gss_sanon_x25519_mechanism_oid_desc) + +/* + * OID mappings with name and short description and and slightly longer description + */ +/* + * RFC5587 + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_concrete_oid_desc; +#define GSS_C_MA_MECH_CONCRETE (&__gss_c_ma_mech_concrete_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_pseudo_oid_desc; +#define GSS_C_MA_MECH_PSEUDO (&__gss_c_ma_mech_pseudo_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_composite_oid_desc; +#define GSS_C_MA_MECH_COMPOSITE (&__gss_c_ma_mech_composite_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_nego_oid_desc; +#define GSS_C_MA_MECH_NEGO (&__gss_c_ma_mech_nego_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mech_glue_oid_desc; +#define GSS_C_MA_MECH_GLUE (&__gss_c_ma_mech_glue_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_not_mech_oid_desc; +#define GSS_C_MA_NOT_MECH (&__gss_c_ma_not_mech_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_deprecated_oid_desc; +#define GSS_C_MA_DEPRECATED (&__gss_c_ma_deprecated_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_not_dflt_mech_oid_desc; +#define GSS_C_MA_NOT_DFLT_MECH (&__gss_c_ma_not_dflt_mech_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_itok_framed_oid_desc; +#define GSS_C_MA_ITOK_FRAMED (&__gss_c_ma_itok_framed_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_init_oid_desc; +#define GSS_C_MA_AUTH_INIT (&__gss_c_ma_auth_init_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_targ_oid_desc; +#define GSS_C_MA_AUTH_TARG (&__gss_c_ma_auth_targ_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_init_init_oid_desc; +#define GSS_C_MA_AUTH_INIT_INIT (&__gss_c_ma_auth_init_init_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_targ_init_oid_desc; +#define GSS_C_MA_AUTH_TARG_INIT (&__gss_c_ma_auth_targ_init_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_init_anon_oid_desc; +#define GSS_C_MA_AUTH_INIT_ANON (&__gss_c_ma_auth_init_anon_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_auth_targ_anon_oid_desc; +#define GSS_C_MA_AUTH_TARG_ANON (&__gss_c_ma_auth_targ_anon_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_deleg_cred_oid_desc; +#define GSS_C_MA_DELEG_CRED (&__gss_c_ma_deleg_cred_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_integ_prot_oid_desc; +#define GSS_C_MA_INTEG_PROT (&__gss_c_ma_integ_prot_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_conf_prot_oid_desc; +#define GSS_C_MA_CONF_PROT (&__gss_c_ma_conf_prot_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_mic_oid_desc; +#define GSS_C_MA_MIC (&__gss_c_ma_mic_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_wrap_oid_desc; +#define GSS_C_MA_WRAP (&__gss_c_ma_wrap_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_prot_ready_oid_desc; +#define GSS_C_MA_PROT_READY (&__gss_c_ma_prot_ready_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_replay_det_oid_desc; +#define GSS_C_MA_REPLAY_DET (&__gss_c_ma_replay_det_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_oos_det_oid_desc; +#define GSS_C_MA_OOS_DET (&__gss_c_ma_oos_det_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_cbindings_oid_desc; +#define GSS_C_MA_CBINDINGS (&__gss_c_ma_cbindings_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_pfs_oid_desc; +#define GSS_C_MA_PFS (&__gss_c_ma_pfs_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_compress_oid_desc; +#define GSS_C_MA_COMPRESS (&__gss_c_ma_compress_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_ctx_trans_oid_desc; +#define GSS_C_MA_CTX_TRANS (&__gss_c_ma_ctx_trans_oid_desc) + +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_negoex_and_spnego_oid_desc; +#define GSS_C_MA_NEGOEX_AND_SPNEGO (&__gss_c_ma_negoex_and_spnego_oid_desc) + +#endif /* GSSAPI_GSSAPI_OID */ diff --git a/third_party/heimdal/lib/gssapi/gssapi/gssapi_spnego.h b/third_party/heimdal/lib/gssapi/gssapi/gssapi_spnego.h new file mode 100644 index 0000000..8b4519e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi/gssapi_spnego.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_SPNEGO_H_ +#define GSSAPI_SPNEGO_H_ + +#include + +GSSAPI_CPP_START + +/* + * RFC2478, SPNEGO: + * The security mechanism of the initial + * negotiation token is identified by the Object Identifier + * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2). + */ +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_spnego_mechanism_oid_desc; +#define GSS_SPNEGO_MECHANISM (&__gss_spnego_mechanism_oid_desc) +#define gss_mech_spnego GSS_SPNEGO_MECHANISM + +/* + * NegoEx extensions, to be implemented by mechanisms + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_mechanism_info( + OM_uint32 * /* minor_status */, + gss_const_OID /* mech_oid */, + unsigned char[16] /* auth_scheme */ +); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_meta_data( + OM_uint32 * /* minor_status */, + gss_const_OID /* mech_oid */, + gss_cred_id_t /* cred_handle */, + gss_ctx_id_t * /* context_handle */, + gss_const_name_t /* targ_name */, + OM_uint32 /* req_flags */, + gss_buffer_t /* meta_data */ +); + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_exchange_meta_data( + OM_uint32 * /* minor_status */, + gss_const_OID /* mech_oid */, + gss_cred_id_t /* cred_handle */, + gss_ctx_id_t * /* context_handle */, + gss_const_name_t /* targ_name */, + OM_uint32 /* req_flags */, + gss_const_buffer_t /* meta_data */ +); + +GSSAPI_CPP_END + +#endif /* GSSAPI_SPNEGO_H_ */ diff --git a/third_party/heimdal/lib/gssapi/gssapi_mech.h b/third_party/heimdal/lib/gssapi/gssapi_mech.h new file mode 100644 index 0000000..ced27b5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gssapi_mech.h @@ -0,0 +1,725 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/mech_switch.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#ifndef GSSAPI_MECH_H +#define GSSAPI_MECH_H 1 + +#include + +typedef OM_uint32 GSSAPI_CALLCONV _gss_acquire_cred_t + (OM_uint32 *, /* minor_status */ + gss_const_name_t, /* desired_name */ + OM_uint32, /* time_req */ + const gss_OID_set, /* desired_mechs */ + gss_cred_usage_t, /* cred_usage */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 * /* time_rec */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_release_cred_t + (OM_uint32 *, /* minor_status */ + gss_cred_id_t * /* cred_handle */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_init_sec_context_t + (OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* initiator_cred_handle */ + gss_ctx_id_t *, /* context_handle */ + gss_const_name_t, /* target_name */ + const gss_OID, /* mech_type */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + const gss_channel_bindings_t, + /* input_chan_bindings */ + const gss_buffer_t, /* input_token */ + gss_OID *, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 * /* time_rec */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_accept_sec_context_t + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_const_cred_id_t, /* acceptor_cred_handle */ + const gss_buffer_t, /* input_token_buffer */ + const gss_channel_bindings_t, + /* input_chan_bindings */ + gss_name_t *, /* src_name */ + gss_OID *, /* mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 *, /* ret_flags */ + OM_uint32 *, /* time_rec */ + gss_cred_id_t * /* delegated_cred_handle */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_process_context_token_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + const gss_buffer_t /* token_buffer */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_delete_sec_context_t + (OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* output_token */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_context_time_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + OM_uint32 * /* time_rec */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_get_mic_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + gss_qop_t, /* qop_req */ + const gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_verify_mic_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + const gss_buffer_t, /* message_buffer */ + const gss_buffer_t, /* token_buffer */ + gss_qop_t * /* qop_state */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_wrap_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + const gss_buffer_t, /* input_message_buffer */ + int *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_unwrap_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + const gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int *, /* conf_state */ + gss_qop_t * /* qop_state */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_display_status_t + (OM_uint32 *, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + const gss_OID, /* mech_type */ + OM_uint32 *, /* message_context */ + gss_buffer_t /* status_string */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_indicate_mechs_t + (OM_uint32 *, /* minor_status */ + gss_OID_set * /* mech_set */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_compare_name_t + (OM_uint32 *, /* minor_status */ + gss_const_name_t, /* name1 */ + gss_const_name_t, /* name2 */ + int * /* name_equal */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_display_name_t + (OM_uint32 *, /* minor_status */ + gss_const_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID * /* output_name_type */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_import_name_t + (OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* input_name_buffer */ + const gss_OID, /* input_name_type */ + gss_name_t * /* output_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_export_name_t + (OM_uint32 *, /* minor_status */ + gss_const_name_t, /* input_name */ + gss_buffer_t /* exported_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_release_name_t + (OM_uint32 *, /* minor_status */ + gss_name_t * /* input_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_cred_t + (OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* cred_handle */ + gss_name_t *, /* name */ + OM_uint32 *, /* lifetime */ + gss_cred_usage_t *, /* cred_usage */ + gss_OID_set * /* mechanisms */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_context_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + gss_name_t *, /* src_name */ + gss_name_t *, /* targ_name */ + OM_uint32 *, /* lifetime_rec */ + gss_OID *, /* mech_type */ + OM_uint32 *, /* ctx_flags */ + int *, /* locally_initiated */ + int * /* open */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_wrap_size_limit_t + (OM_uint32 *, /* minor_status */ + gss_const_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + OM_uint32, /* req_output_size */ + OM_uint32 * /* max_input_size */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_add_cred_t ( + OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* input_cred_handle */ + gss_const_name_t, /* desired_name */ + const gss_OID, /* desired_mech */ + gss_cred_usage_t, /* cred_usage */ + OM_uint32, /* initiator_time_req */ + OM_uint32, /* acceptor_time_req */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 *, /* initiator_time_rec */ + OM_uint32 * /* acceptor_time_rec */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_duplicate_cred_t ( + OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* input_cred_handle */ + gss_cred_id_t * /* output_cred_handle */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_cred_by_mech_t ( + OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* cred_handle */ + const gss_OID, /* mech_type */ + gss_name_t *, /* name */ + OM_uint32 *, /* initiator_lifetime */ + OM_uint32 *, /* acceptor_lifetime */ + gss_cred_usage_t * /* cred_usage */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_export_sec_context_t ( + OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* interprocess_token */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_import_sec_context_t ( + OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* interprocess_token */ + gss_ctx_id_t * /* context_handle */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_names_for_mech_t ( + OM_uint32 *, /* minor_status */ + const gss_OID, /* mechanism */ + gss_OID_set * /* name_types */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_mechs_for_name_t ( + OM_uint32 *, /* minor_status */ + gss_const_name_t, /* input_name */ + gss_OID_set * /* mech_types */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_canonicalize_name_t ( + OM_uint32 *, /* minor_status */ + gss_const_name_t, /* input_name */ + const gss_OID, /* mech_type */ + gss_name_t * /* output_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_duplicate_name_t ( + OM_uint32 *, /* minor_status */ + gss_const_name_t, /* src_name */ + gss_name_t * /* dest_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_sec_context_by_oid_t ( + OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_cred_by_oid_t ( + OM_uint32 *minor_status, + gss_const_cred_id_t cred, + const gss_OID desired_object, + gss_buffer_set_t *data_set + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_set_sec_context_option_t ( + OM_uint32 *minor_status, + gss_ctx_id_t *cred_handle, + const gss_OID desired_object, + const gss_buffer_t value + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_set_cred_option_t ( + OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID desired_object, + const gss_buffer_t value + ); + + +typedef OM_uint32 GSSAPI_CALLCONV _gss_pseudo_random_t ( + OM_uint32 *minor_status, + gss_ctx_id_t context, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out + ); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_wrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_unwrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_wrap_iov_length_t(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_store_cred_t(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_export_cred_t(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_buffer_t cred_token); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_import_cred_t(OM_uint32 * minor_status, + gss_buffer_t cred_token, + gss_cred_id_t * cred_handle); + +typedef void GSSAPI_CALLCONV +_gss_iter_creds_t(OM_uint32 /* flags */, + void * /* userctx */, + void (* /*cred_iter */ )(void *, gss_OID, gss_cred_id_t)); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_destroy_cred_t(OM_uint32 * /* minor_status */, + gss_cred_id_t * /* cred */); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_cred_hold_t(OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred */); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_cred_unhold_t(OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred */); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_cred_label_set_t(OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred */, + const char * /* label */, + gss_buffer_t /* value */); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_cred_label_get_t(OM_uint32 * /* minor_status */, + gss_cred_id_t /* cred */, + const char * /* label */, + gss_buffer_t /* value */); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_display_name_ext_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_OID, /* display_as_name_type */ + gss_buffer_t /* display_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_name_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int *, /* name_is_MN */ + gss_OID *, /* MN_mech */ + gss_buffer_set_t * /* attrs */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_get_name_attribute_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t, /* attr */ + int *, /* authenticated */ + int *, /* complete */ + gss_buffer_t, /* value */ + gss_buffer_t, /* display_value */ + int * /* more */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_set_name_attribute_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + int, /* complete */ + gss_buffer_t, /* attr */ + gss_buffer_t /* value */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_delete_name_attribute_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* attr */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_export_name_composite_t ( + OM_uint32 *, /* minor_status */ + gss_name_t, /* name */ + gss_buffer_t /* exp_composite_name */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_acquire_cred_from_t(OM_uint32 *minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_acquire_cred_impersonate_name_t(OM_uint32 *minor_status, + gss_const_cred_id_t icred, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_add_cred_from_t(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_store_cred_into_t(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_store_cred_into2_t(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + gss_OID desired_mech, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored, + gss_buffer_set_t *env); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_query_mechanism_info_t(OM_uint32 *minor_status, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_query_meta_data_t(OM_uint32 *minor_status, + gss_const_OID mech_oid, + gss_cred_id_t cred_handle, + gss_ctx_id_t *ctx_handle, + gss_const_name_t targ_name, + OM_uint32 req_flags, + gss_buffer_t meta_data); + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_exchange_meta_data_t(OM_uint32 *minor_status, + gss_const_OID mech_oid, + gss_cred_id_t cred_handle, + gss_ctx_id_t *ctx_handle, + gss_const_name_t targ_name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data); + +/* + * + */ + +typedef struct gss_mo_desc_struct gss_mo_desc; + +typedef OM_uint32 GSSAPI_CALLCONV +_gss_mo_init (OM_uint32 *, gss_OID, gss_mo_desc **, size_t *); + + +struct gss_mo_desc_struct { + gss_OID option; + OM_uint32 flags; +#define GSS_MO_MA 1 +#define GSS_MO_MA_CRITICAL 2 + const char *name; + void *ctx; + int (*get)(gss_const_OID, gss_mo_desc *, gss_buffer_t); + int (*set)(gss_const_OID, gss_mo_desc *, int, gss_buffer_t); +}; + +typedef OM_uint32 GSSAPI_CALLCONV _gss_localname_t ( + OM_uint32 *, /* minor_status */ + gss_const_name_t, /* name */ + const gss_OID, /* mech_type */ + gss_buffer_t /* localname */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_authorize_localname_t ( + OM_uint32 *, /* minor_status */ + gss_const_name_t, /* name */ + gss_const_buffer_t, /* user */ + gss_const_OID /* user_name_type */ + ); + +struct _gss_name; +struct _gss_cred; + +/* mechglue internal */ +struct gss_mech_compat_desc_struct; + +#define GMI_VERSION 6 + +/* gm_flags */ +#define GM_USE_MG_CRED 1 /* uses mech glue credentials */ +#define GM_USE_MG_NAME 2 /* uses mech glue names */ + +typedef struct gssapi_mech_interface_desc { + unsigned gm_version; + const char *gm_name; + gss_OID_desc gm_mech_oid; + unsigned gm_flags; + _gss_acquire_cred_t *gm_acquire_cred; + _gss_release_cred_t *gm_release_cred; + _gss_init_sec_context_t *gm_init_sec_context; + _gss_accept_sec_context_t *gm_accept_sec_context; + _gss_process_context_token_t *gm_process_context_token; + _gss_delete_sec_context_t *gm_delete_sec_context; + _gss_context_time_t *gm_context_time; + _gss_get_mic_t *gm_get_mic; + _gss_verify_mic_t *gm_verify_mic; + _gss_wrap_t *gm_wrap; + _gss_unwrap_t *gm_unwrap; + _gss_display_status_t *gm_display_status; + _gss_indicate_mechs_t *gm_indicate_mechs; + _gss_compare_name_t *gm_compare_name; + _gss_display_name_t *gm_display_name; + _gss_import_name_t *gm_import_name; + _gss_export_name_t *gm_export_name; + _gss_release_name_t *gm_release_name; + _gss_inquire_cred_t *gm_inquire_cred; + _gss_inquire_context_t *gm_inquire_context; + _gss_wrap_size_limit_t *gm_wrap_size_limit; + _gss_add_cred_t *gm_add_cred; + _gss_inquire_cred_by_mech_t *gm_inquire_cred_by_mech; + _gss_export_sec_context_t *gm_export_sec_context; + _gss_import_sec_context_t *gm_import_sec_context; + _gss_inquire_names_for_mech_t *gm_inquire_names_for_mech; + _gss_inquire_mechs_for_name_t *gm_inquire_mechs_for_name; + _gss_canonicalize_name_t *gm_canonicalize_name; + _gss_duplicate_name_t *gm_duplicate_name; + _gss_inquire_sec_context_by_oid_t *gm_inquire_sec_context_by_oid; + _gss_inquire_cred_by_oid_t *gm_inquire_cred_by_oid; + _gss_set_sec_context_option_t *gm_set_sec_context_option; + _gss_set_cred_option_t *gm_set_cred_option; + _gss_pseudo_random_t *gm_pseudo_random; + _gss_wrap_iov_t *gm_wrap_iov; + _gss_unwrap_iov_t *gm_unwrap_iov; + _gss_wrap_iov_length_t *gm_wrap_iov_length; + _gss_store_cred_t *gm_store_cred; + _gss_export_cred_t *gm_export_cred; + _gss_import_cred_t *gm_import_cred; + _gss_acquire_cred_from_t *gm_acquire_cred_from; /* was acquire_cred_ext */ + _gss_acquire_cred_impersonate_name_t *gm_acquire_cred_impersonate_name; + _gss_iter_creds_t *gm_iter_creds; + _gss_destroy_cred_t *gm_destroy_cred; + _gss_cred_hold_t *gm_cred_hold; + _gss_cred_unhold_t *gm_cred_unhold; + _gss_cred_label_get_t *gm_cred_label_get; + _gss_cred_label_set_t *gm_cred_label_set; + gss_mo_desc *gm_mo; + size_t gm_mo_num; + _gss_localname_t *gm_localname; + _gss_authorize_localname_t *gm_authorize_localname; + _gss_display_name_ext_t *gm_display_name_ext; + _gss_inquire_name_t *gm_inquire_name; + _gss_get_name_attribute_t *gm_get_name_attribute; + _gss_set_name_attribute_t *gm_set_name_attribute; + _gss_delete_name_attribute_t *gm_delete_name_attribute; + _gss_export_name_composite_t *gm_export_name_composite; + _gss_duplicate_cred_t *gm_duplicate_cred; + _gss_add_cred_from_t *gm_add_cred_from; + _gss_store_cred_into_t *gm_store_cred_into; + _gss_query_mechanism_info_t *gm_query_mechanism_info; + _gss_query_meta_data_t *gm_query_meta_data; + _gss_exchange_meta_data_t *gm_exchange_meta_data; + _gss_store_cred_into2_t *gm_store_cred_into2; + struct gss_mech_compat_desc_struct *gm_compat; +} gssapi_mech_interface_desc, *gssapi_mech_interface; + +gssapi_mech_interface +__gss_get_mechanism(gss_const_OID /* oid */); + +gss_OID +_gss_mg_support_mechanism(gss_const_OID mech); + +gssapi_mech_interface __gss_spnego_initialize(void); +gssapi_mech_interface __gss_krb5_initialize(void); +gssapi_mech_interface __gss_ntlm_initialize(void); +gssapi_mech_interface __gss_sanon_initialize(void); + +void gss_mg_collect_error(gss_OID, OM_uint32, OM_uint32); + +int _gss_mo_get_option_1(gss_const_OID, gss_mo_desc *, gss_buffer_t); +int _gss_mo_get_option_0(gss_const_OID, gss_mo_desc *, gss_buffer_t); +int _gss_mo_get_ctx_as_string(gss_const_OID, gss_mo_desc *, gss_buffer_t); + +struct _gss_name_type { + gss_OID gnt_name_type; + OM_uint32 (*gnt_parse)(OM_uint32 *, gss_const_OID, const gss_buffer_t, + gss_const_OID, gss_name_t *); +}; + +struct _gss_oid_name_table { + gss_OID oid; + const char *name; + const char *short_desc; + const char *long_desc; +}; + +extern struct _gss_oid_name_table _gss_ont_mech[]; +extern struct _gss_oid_name_table _gss_ont_ma[]; + +int +_gss_mg_log_level(int level); + +void +_gss_mg_log(int level, const char *fmt, ...) + HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 3)); + +void +_gss_mg_log_name(int level, + struct _gss_name *name, + gss_OID mech_type, + const char *fmt, ...); + +void +_gss_mg_log_cred(int level, + struct _gss_cred *cred, + const char *fmt, ...); + + +void +_gss_load_plugins(void); + +gss_iov_buffer_desc * +_gss_mg_find_buffer(gss_iov_buffer_desc *iov, + int iov_count, + OM_uint32 type); + +OM_uint32 +_gss_mg_allocate_buffer(OM_uint32 *minor_status, + gss_iov_buffer_desc *buffer, + size_t size); + +OM_uint32 +gss_mg_set_error_string(gss_OID mech, + OM_uint32 maj, OM_uint32 min, + const char *fmt, ...); + +gss_cred_id_t +_gss_mg_find_mech_cred(gss_const_cred_id_t cred_handle, + gss_const_OID mech_type); + +#include + +/* + * Mechglue krb5 context for use by NegoEx. This is not shared with the + * krb5 GSS mechanism so we don't clobber its error state. + */ +krb5_context +_gss_mg_krb5_context(void); + +#endif /* GSSAPI_MECH_H */ diff --git a/third_party/heimdal/lib/gssapi/gsstool.c b/third_party/heimdal/lib/gssapi/gsstool.c new file mode 100644 index 0000000..8df3953 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/gsstool.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int version_flag = 0; +static int help_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + +#define COL_OID "OID" +#define COL_NAME "Name" +#define COL_DESC "Description" +#define COL_VALUE "Value" +#define COL_MECH "Mech" +#define COL_EXPIRE "Expire" +#define COL_SASL "SASL" + +int +mechanisms(void *argptr, int argc, char **argv) +{ + OM_uint32 maj_stat, min_stat; + gss_OID_set mechs; + rtbl_t ct; + size_t i; + + maj_stat = gss_indicate_mechs(&min_stat, &mechs); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_indicate_mechs failed"); + + printf("Supported mechanisms:\n"); + + ct = rtbl_create(); + if (ct == NULL) + errx(1, "rtbl_create"); + + rtbl_set_separator(ct, " "); + rtbl_add_column(ct, COL_OID, 0); + rtbl_add_column(ct, COL_NAME, 0); + rtbl_add_column(ct, COL_DESC, 0); + rtbl_add_column(ct, COL_SASL, 0); + + for (i = 0; i < mechs->count; i++) { + gss_buffer_desc str, sasl_name, mech_name, mech_desc; + + maj_stat = gss_oid_to_str(&min_stat, &mechs->elements[i], &str); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_oid_to_str failed"); + + rtbl_add_column_entryv(ct, COL_OID, "%.*s", + (int)str.length, (char *)str.value); + gss_release_buffer(&min_stat, &str); + + (void)gss_inquire_saslname_for_mech(&min_stat, + &mechs->elements[i], + &sasl_name, + &mech_name, + &mech_desc); + + rtbl_add_column_entryv(ct, COL_NAME, "%.*s", + (int)mech_name.length, (char *)mech_name.value); + rtbl_add_column_entryv(ct, COL_DESC, "%.*s", + (int)mech_desc.length, (char *)mech_desc.value); + rtbl_add_column_entryv(ct, COL_SASL, "%.*s", + (int)sasl_name.length, (char *)sasl_name.value); + + gss_release_buffer(&min_stat, &mech_name); + gss_release_buffer(&min_stat, &mech_desc); + gss_release_buffer(&min_stat, &sasl_name); + + } + gss_release_oid_set(&min_stat, &mechs); + + rtbl_format(ct, stdout); + rtbl_destroy(ct); + + return 0; +} + +static void +print_mech_attr(const char *mechname, gss_const_OID mech, gss_OID_set set) +{ + gss_buffer_desc name, desc; + OM_uint32 major, minor; + rtbl_t ct; + size_t n; + + ct = rtbl_create(); + if (ct == NULL) + errx(1, "rtbl_create"); + + rtbl_set_separator(ct, " "); + rtbl_add_column(ct, COL_OID, 0); + rtbl_add_column(ct, COL_DESC, 0); + if (mech) + rtbl_add_column(ct, COL_VALUE, 0); + + for (n = 0; n < set->count; n++) { + major = gss_display_mech_attr(&minor, &set->elements[n], &name, &desc, NULL); + if (major) + continue; + + rtbl_add_column_entryv(ct, COL_OID, "%.*s", + (int)name.length, (char *)name.value); + rtbl_add_column_entryv(ct, COL_DESC, "%.*s", + (int)desc.length, (char *)desc.value); + if (mech) { + gss_buffer_desc value; + + if (gss_mo_get(mech, &set->elements[n], &value) != 0) + value.length = 0; + + if (value.length) + rtbl_add_column_entryv(ct, COL_VALUE, "%.*s", + (int)value.length, (char *)value.value); + else + rtbl_add_column_entryv(ct, COL_VALUE, "<>"); + gss_release_buffer(&minor, &value); + } + + gss_release_buffer(&minor, &name); + gss_release_buffer(&minor, &desc); + } + + printf("attributes for: %s\n", mechname); + rtbl_format(ct, stdout); + rtbl_destroy(ct); +} + + +int +attributes(struct attributes_options *opt, int argc, char **argv) +{ + gss_OID_set mech_attr = NULL, known_mech_attrs = NULL; + gss_OID mech = GSS_C_NO_OID; + OM_uint32 major, minor; + + if (opt->mech_string) { + mech = gss_name_to_oid(opt->mech_string); + if (mech == NULL) + errx(1, "mech %s is unknown", opt->mech_string); + } + + major = gss_inquire_attrs_for_mech(&minor, mech, &mech_attr, &known_mech_attrs); + if (major) + errx(1, "gss_inquire_attrs_for_mech"); + + if (mech) { + print_mech_attr(opt->mech_string, mech, mech_attr); + } + + if (opt->all_flag) { + print_mech_attr("all mechs", NULL, known_mech_attrs); + } + + gss_release_oid_set(&minor, &mech_attr); + gss_release_oid_set(&minor, &known_mech_attrs); + + return 0; +} + + +/* + * + */ + +int +help(void *opt, int argc, char **argv) +{ + sl_slc_help(commands, argc, argv); + return 0; +} + +int +main(int argc, char **argv) +{ + int exit_status = 0, ret, optidx = 0; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc != 0) { + ret = sl_command(commands, argc, argv); + if(ret == -1) + sl_did_you_mean(commands, argv[0]); + else if (ret == -2) + ret = 0; + if(ret != 0) + exit_status = 1; + } else { + sl_slc_help(commands, argc, argv); + exit_status = 1; + } + + return exit_status; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/8003.c b/third_party/heimdal/lib/gssapi/krb5/8003.c new file mode 100644 index 0000000..0b91cf8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/8003.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static krb5_error_code +hash_input_chan_bindings (const gss_channel_bindings_t b, + u_char *p) +{ + u_char num[4]; + EVP_MD_CTX *ctx; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_md5(), NULL); + + _gss_mg_encode_le_uint32 (b->initiator_addrtype, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + _gss_mg_encode_le_uint32 (b->initiator_address.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->initiator_address.length) + EVP_DigestUpdate(ctx, + b->initiator_address.value, + b->initiator_address.length); + _gss_mg_encode_le_uint32 (b->acceptor_addrtype, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + _gss_mg_encode_le_uint32 (b->acceptor_address.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->acceptor_address.length) + EVP_DigestUpdate(ctx, + b->acceptor_address.value, + b->acceptor_address.length); + _gss_mg_encode_le_uint32 (b->application_data.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->application_data.length) + EVP_DigestUpdate(ctx, + b->application_data.value, + b->application_data.length); + EVP_DigestFinal_ex(ctx, p, NULL); + EVP_MD_CTX_destroy(ctx); + + return 0; +} + +/* + * create a checksum over the chanel bindings in + * `input_chan_bindings', `flags' and `fwd_data' and return it in + * `result' + */ + +OM_uint32 +_gsskrb5_create_8003_checksum ( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + OM_uint32 flags, + const krb5_data *fwd_data, + Checksum *result) +{ + u_char *p; + + /* + * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value + * field's format) */ + result->cksumtype = CKSUMTYPE_GSSAPI; + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) + result->checksum.length = 24 + 4 + fwd_data->length; + else + result->checksum.length = 24; + result->checksum.data = malloc (result->checksum.length); + if (result->checksum.data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = result->checksum.data; + _gss_mg_encode_le_uint32 (16, p); + p += 4; + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) { + memset (p, 0, 16); + } else { + hash_input_chan_bindings (input_chan_bindings, p); + } + p += 16; + _gss_mg_encode_le_uint32 (flags, p); + p += 4; + + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) { + + *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */ + *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */ + *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */ + *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */ + memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length); + + /* p += fwd_data->length; */ /* commented out to quiet warning */ + } + + return GSS_S_COMPLETE; +} + +static krb5_error_code +check_ap_options_cbt(void *ad_data, size_t ad_len, + krb5_boolean *client_asserted_cb) +{ + uint32_t ad_ap_options; + + *client_asserted_cb = FALSE; + + if (ad_len != sizeof(uint32_t)) + return KRB5KRB_AP_ERR_MSG_TYPE; + + _gss_mg_decode_le_uint32(ad_data, &ad_ap_options); + + if (ad_ap_options & KERB_AP_OPTIONS_CBT) + *client_asserted_cb = TRUE; + + return 0; +} + +static krb5_error_code +find_ap_options(krb5_context context, + krb5_authenticator authenticator, + krb5_boolean *client_asserted_cb) +{ + krb5_error_code ret; + krb5_authdata *ad; + krb5_data data; + + *client_asserted_cb = FALSE; + + ad = authenticator->authorization_data; + if (ad == NULL) + return 0; + + ret = _krb5_get_ad(context, ad, NULL, KRB5_AUTHDATA_AP_OPTIONS, &data); + if (ret) + return ret == ENOENT ? 0 : ret; + + ret = check_ap_options_cbt(data.data, data.length, client_asserted_cb); + krb5_data_free(&data); + + return ret; +} + +/* + * verify the checksum in `cksum' over `input_chan_bindings' + * returning `flags' and `fwd_data' + */ + +OM_uint32 +_gsskrb5_verify_8003_checksum( + krb5_context context, + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + krb5_authenticator authenticator, + OM_uint32 *flags, + krb5_data *fwd_data) +{ + unsigned char hash[16]; + unsigned char *p; + OM_uint32 length; + int DlgOpt; + static unsigned char zeros[16]; + krb5_boolean channel_bound = FALSE; + const Checksum *cksum = authenticator->cksum; + krb5_boolean client_asserted_cb; + krb5_error_code ret; + + /* XXX should handle checksums > 24 bytes */ + if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p = cksum->checksum.data; + _gss_mg_decode_le_uint32(p, &length); + if(length != sizeof(hash)) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p += 4; + + ret = find_ap_options(context, authenticator, &client_asserted_cb); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS + && (ct_memcmp(p, zeros, sizeof(zeros)) != 0 || client_asserted_cb)) { + if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + if(ct_memcmp(hash, p, sizeof(hash)) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + channel_bound = TRUE; + } + + p += sizeof(hash); + + _gss_mg_decode_le_uint32(p, flags); + p += 4; + + if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) { + if(cksum->checksum.length < 28) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + DlgOpt = (p[0] << 0) | (p[1] << 8); + p += 2; + if (DlgOpt != 1) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + fwd_data->length = (p[0] << 0) | (p[1] << 8); + p += 2; + if(cksum->checksum.length < 28 + fwd_data->length) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + fwd_data->data = malloc(fwd_data->length); + if (fwd_data->data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(fwd_data->data, p, fwd_data->length); + } + + if (channel_bound) { + *flags |= GSS_C_CHANNEL_BOUND_FLAG; + } else { + *flags &= ~GSS_C_CHANNEL_BOUND_FLAG; + } + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c new file mode 100644 index 0000000..3f8e274 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c @@ -0,0 +1,978 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; +krb5_keytab _gsskrb5_keytab; + +static krb5_error_code +validate_keytab(krb5_context context, const char *name, krb5_keytab *id) +{ + krb5_error_code ret; + + ret = krb5_kt_resolve(context, name, id); + if (ret) + return ret; + + ret = krb5_kt_have_content(context, *id); + if (ret) { + krb5_kt_close(context, *id); + *id = NULL; + } + + return ret; +} + +OM_uint32 +_gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity) +{ + krb5_context context; + krb5_error_code ret; + + *min_stat = 0; + + ret = _gsskrb5_init(&context); + if(ret) + return GSS_S_FAILURE; + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if(_gsskrb5_keytab != NULL) { + krb5_kt_close(context, _gsskrb5_keytab); + _gsskrb5_keytab = NULL; + } + if (identity == NULL) { + ret = krb5_kt_default(context, &_gsskrb5_keytab); + } else { + /* + * First check if we can the keytab as is and if it has content... + */ + ret = validate_keytab(context, identity, &_gsskrb5_keytab); + /* + * if it doesn't, lets prepend FILE: and try again + */ + if (ret) { + char *p = NULL; + ret = asprintf(&p, "FILE:%s", identity); + if(ret < 0 || p == NULL) { + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + return GSS_S_FAILURE; + } + ret = validate_keytab(context, p, &_gsskrb5_keytab); + free(p); + } + } + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + if(ret) { + *min_stat = ret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} + +void +_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) +{ + krb5_keyblock *key; + + if (acceptor) { + if (ctx->auth_context->local_subkey) + key = ctx->auth_context->local_subkey; + else + key = ctx->auth_context->remote_subkey; + } else { + if (ctx->auth_context->remote_subkey) + key = ctx->auth_context->remote_subkey; + else + key = ctx->auth_context->local_subkey; + } + if (key == NULL) + key = ctx->auth_context->keyblock; + + if (key == NULL) + return; + + switch (key->keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + case ETYPE_DES3_CBC_MD5: + case ETYPE_OLD_DES3_CBC_SHA1: + case ETYPE_DES3_CBC_SHA1: + case ETYPE_ARCFOUR_HMAC_MD5: + case ETYPE_ARCFOUR_HMAC_MD5_56: + break; + default : + ctx->more_flags |= IS_CFX; + + if ((acceptor && ctx->auth_context->local_subkey) || + (!acceptor && ctx->auth_context->remote_subkey)) + ctx->more_flags |= ACCEPTOR_SUBKEY; + break; + } + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); + /* XXX We really shouldn't ignore this; will come back to this */ + (void) krb5_crypto_init(context, key, 0, &ctx->crypto); +} + + +static OM_uint32 +gsskrb5_accept_delegated_token(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_cred_id_t *delegated_cred_handle) +{ + krb5_ccache ccache = NULL; + krb5_error_code kret; + int32_t ac_flags, ret = GSS_S_COMPLETE; + gsskrb5_cred handle; + + *minor_status = 0; + + /* XXX Create a new delegated_cred_handle? */ + if (delegated_cred_handle == NULL) + return GSS_S_COMPLETE; + + *delegated_cred_handle = NULL; + kret = krb5_cc_resolve(context, "MEMORY:anonymous", &ccache); + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, ctx->source); + if (kret == 0) { + (void) krb5_auth_con_removeflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &ac_flags); + kret = krb5_rd_cred2(context, + ctx->auth_context, + ccache, + &ctx->fwd_data); + (void) krb5_auth_con_setflags(context, + ctx->auth_context, + ac_flags); + } + if (kret) { + ctx->flags &= ~GSS_C_DELEG_FLAG; + ret = GSS_S_FAILURE; + *minor_status = kret; + goto out; + } + + ret = _gsskrb5_krb5_import_cred(minor_status, + &ccache, + NULL, + NULL, + delegated_cred_handle); + if (ret != GSS_S_COMPLETE) + goto out; + + handle = (gsskrb5_cred) *delegated_cred_handle; + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + /* + * A root TGT is one of the form krbtgt/REALM@SAME-REALM. + * + * A destination TGT is a root TGT for the same realm as the acceptor + * service's realm. + * + * Normally clients delegate a root TGT for the client's realm. + * + * In some deployments clients may want to delegate destination TGTs as + * a form of constrained delegation: so that the destination service + * cannot use the delegated credential to impersonate the client + * principal to services in its home realm (due to KDC lineage/transit + * checks). In those deployments there may not even be a route back to + * the KDCs of the client's realm, and attempting to use a + * non-destination TGT might even lead to timeouts. + * + * We could simply pretend not to have obtained a credential, except + * that a) we don't (yet) have an app name here for the appdefault we + * need to check, b) the application really wants to be able to log a + * message about the delegated credential being no good. + * + * Thus we leave it to _gsskrb5_store_cred_into2() to decide what to do + * with non-destination TGTs. To do that, it needs the realm of the + * acceptor service, which we record here. + */ + handle->destination_realm = + strdup(krb5_principal_get_realm(context, ctx->target)); + if (handle->destination_realm == NULL) { + _gsskrb5_release_cred(minor_status, delegated_cred_handle); + *minor_status = krb5_enomem(context); + ret = GSS_S_FAILURE; + goto out; + } + +out: + if (ccache) { + krb5_cc_close(context, ccache); + } + return ret; +} + +static OM_uint32 +gsskrb5_acceptor_ready(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + + krb5_auth_con_getremoteseqnumber (context, + ctx->auth_context, + &seq_number); + + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); + + ret = _gssapi_msg_order_create(minor_status, + &ctx->order, + _gssapi_msg_order_f(ctx->flags), + seq_number, 0, is_cfx); + if (ret) + return ret; + + /* + * If requested, set local sequence num to remote sequence if this + * isn't a mutual authentication context + */ + if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + seq_number); + } + + /* + * We should handle the delegation ticket, in case it's there + */ + if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { + ret = gsskrb5_accept_delegated_token(minor_status, + ctx, + context, + delegated_cred_handle); + if (ret != GSS_S_COMPLETE) + return ret; + } else { + /* Well, looks like it wasn't there after all */ + ctx->flags &= ~GSS_C_DELEG_FLAG; + } + + ctx->state = ACCEPTOR_READY; + ctx->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +send_error_token(OM_uint32 *minor_status, + krb5_context context, + krb5_error_code kret, + krb5_principal server, + krb5_data *indata, + gss_buffer_t output_token) +{ + krb5_principal ap_req_server = NULL; + krb5_error_code ret; + krb5_data outbuf; + /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which + tells windows to try again with the corrected timestamp. See + [MS-KILE] 2.2.1 KERB-ERROR-DATA */ + krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") }; + + /* build server from request if the acceptor had not selected one */ + if (server == NULL) { + AP_REQ ap_req; + + ret = krb5_decode_ap_req(context, indata, &ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = _krb5_principalname2krb5_principal(context, + &ap_req_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + free_AP_REQ(&ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + server = ap_req_server; + } + + ret = krb5_mk_error(context, kret, NULL, &e_data, NULL, + server, NULL, NULL, &outbuf); + if (ap_req_server) + krb5_free_principal(context, ap_req_server); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = _gsskrb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x03\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + return ret; + + *minor_status = 0; + return GSS_S_CONTINUE_NEEDED; +} + + +static OM_uint32 +gsskrb5_acceptor_start(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_error_code kret; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data indata; + krb5_flags ap_options; + krb5_keytab keytab = NULL; + int is_cfx = 0; + int close_kt = 0; + const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; + + /* + * We may, or may not, have an escapsulation. + */ + ret = _gsskrb5_decapsulate (minor_status, + input_token_buffer, + &indata, + "\x01\x00", + GSS_KRB5_MECHANISM); + + if (ret) { + /* Could be a raw AP-REQ (check for APPLICATION tag) */ + if (input_token_buffer->length == 0 || + ((const uint8_t *)input_token_buffer->value)[0] != 0x6E) { + *minor_status = ASN1_MISPLACED_FIELD; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Assume that there is no OID wrapping. */ + indata.length = input_token_buffer->length; + indata.data = input_token_buffer->value; + } + + /* + * We need to get our keytab + */ + if (acceptor_cred == NULL) { + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + if (_gsskrb5_keytab != NULL) { + char *name = NULL; + kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name); + if (kret == 0) { + kret = krb5_kt_resolve(context, name, &keytab); + krb5_xfree(name); + } + if (kret == 0) + close_kt = 1; + else + keytab = NULL; + } + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + } else if (acceptor_cred->keytab != NULL) { + keytab = acceptor_cred->keytab; + } + + /* + * We need to check the ticket and create the AP-REP packet + */ + + { + krb5_rd_req_in_ctx in = NULL; + krb5_rd_req_out_ctx out = NULL; + krb5_principal server = NULL; + + if (acceptor_cred) + server = acceptor_cred->principal; + + kret = krb5_rd_req_in_ctx_alloc(context, &in); + if (kret == 0) + kret = krb5_rd_req_in_set_keytab(context, in, keytab); + if (kret) { + if (in) + krb5_rd_req_in_ctx_free(context, in); + if (close_kt) + krb5_kt_close(context, keytab); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_rd_req_ctx(context, + &ctx->auth_context, + &indata, + server, + in, &out); + krb5_rd_req_in_ctx_free(context, in); + if (close_kt) + krb5_kt_close(context, keytab); + if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) { + /* + * No reply in non-MUTUAL mode, but we don't know that its + * non-MUTUAL mode yet, thats inside the 8003 checksum, so + * lets only send the error token on clock skew, that + * limit when send error token for non-MUTUAL. + */ + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + ctx->deleg_auth_context = NULL; + ctx->auth_context = NULL; + return send_error_token(minor_status, context, kret, + server, &indata, output_token); + } else if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* + * we need to remember some data on the context_handle. + */ + kret = krb5_rd_req_out_get_ap_req_options(context, out, + &ap_options); + if (kret == 0) + kret = krb5_rd_req_out_get_ticket(context, out, + &ctx->ticket); + if (kret == 0) + kret = krb5_rd_req_out_get_keyblock(context, out, + &ctx->service_keyblock); + ctx->endtime = ctx->ticket->ticket.endtime; + + krb5_rd_req_out_ctx_free(context, out); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + } + + + /* + * We need to copy the principal names to the context and the + * calling layer. + */ + kret = krb5_copy_principal(context, + ctx->ticket->client, + &ctx->source); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + kret = krb5_copy_principal(context, + ctx->ticket->server, + &ctx->target); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + /* + * We need to setup some compat stuff, this assumes that + * context_handle->target is already set. + */ + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); + if (ret) + return ret; + + if (src_name != NULL) { + kret = krb5_copy_principal (context, + ctx->ticket->client, + (gsskrb5_name*)src_name); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + } + + /* + * We need to get the flags out of the 8003 checksum. + */ + + { + krb5_authenticator authenticator; + + kret = krb5_auth_con_getauthenticator(context, + ctx->auth_context, + &authenticator); + if(kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + if (authenticator->cksum != NULL + && authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { + ret = _gsskrb5_verify_8003_checksum(context, + minor_status, + input_chan_bindings, + authenticator, + &ctx->flags, + &ctx->fwd_data); + + if (ret) { + krb5_free_authenticator(context, &authenticator); + return ret; + } + } else { + if (authenticator->cksum != NULL) { + krb5_crypto crypto; + + kret = krb5_crypto_init(context, + ctx->auth_context->keyblock, + 0, &crypto); + if (kret) { + krb5_free_authenticator(context, &authenticator); + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + /* + * Windows accepts Samba3's use of a kerberos, rather than + * GSSAPI checksum here + */ + + _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM); + kret = krb5_verify_checksum(context, + crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, + authenticator->cksum); + krb5_crypto_destroy(context, crypto); + + if (kret) { + krb5_free_authenticator(context, &authenticator); + ret = GSS_S_BAD_SIG; + *minor_status = kret; + return ret; + } + } + + /* + * If there is no checksum or a kerberos checksum (which Windows + * and Samba accept), we use the ap_options to guess the mutual + * flag. + */ + + ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; + if (ap_options & AP_OPTS_MUTUAL_REQUIRED) + ctx->flags |= GSS_C_MUTUAL_FLAG; + } + krb5_free_authenticator(context, &authenticator); + } + + if(ctx->flags & GSS_C_MUTUAL_FLAG) { + krb5_data outbuf; + int use_subkey = 0; + + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); + + if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { + use_subkey = 1; + } else { + krb5_keyblock *rkey; + + /* + * If there is a initiator subkey, copy that to acceptor + * subkey to match Windows behavior + */ + kret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + &rkey); + if (kret == 0) { + kret = krb5_auth_con_setlocalsubkey(context, + ctx->auth_context, + rkey); + if (kret == 0) + use_subkey = 1; + } + krb5_free_keyblock(context, rkey); + } + if (use_subkey) { + ctx->more_flags |= ACCEPTOR_SUBKEY; + krb5_auth_con_addflags(context, ctx->auth_context, + KRB5_AUTH_CONTEXT_USE_SUBKEY, + NULL); + } + + kret = krb5_mk_rep(context, + ctx->auth_context, + &outbuf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(ctx)) { + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } else { + ret = _gsskrb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x02\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + return ret; + } + } + + ctx->flags |= GSS_C_TRANS_FLAG; + + /* Remember the flags */ + + ctx->endtime = ctx->ticket->ticket.endtime; + ctx->more_flags |= OPEN; + + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (time_rec) { + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + time_rec); + if (ret) { + return ret; + } + } + + /* + * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from + * the client. + */ + if (IS_DCE_STYLE(ctx)) { + /* + * Return flags to caller, but we haven't processed + * delgations yet + */ + if (ret_flags) + *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); + + ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; + return GSS_S_CONTINUE_NEEDED; + } + + ret = gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); + + if (ret_flags) + *ret_flags = ctx->flags; + + return ret; +} + +static OM_uint32 +acceptor_wait_for_dcestyle(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data inbuf; + int32_t r_seq_number, l_seq_number; + + /* + * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP + */ + + inbuf.length = input_token_buffer->length; + inbuf.data = input_token_buffer->value; + + /* + * We need to remeber the old remote seq_number, then check if the + * client has replied with our local seq_number, and then reset + * the remote seq_number to the old value + */ + { + kret = krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &l_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getremoteseqnumber(context, + ctx->auth_context, + &r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_setremoteseqnumber(context, + ctx->auth_context, + l_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* + * We need to verify the AP_REP, but we need to flag that this is + * DCE_STYLE, so don't check the timestamps this time, but put the + * flag DO_TIME back afterward. + */ + { + krb5_ap_rep_enc_part *repl; + int32_t auth_flags; + + krb5_auth_con_removeflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &auth_flags); + + kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + krb5_free_ap_rep_enc_part(context, repl); + krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); + } + + /* We need to check the liftime */ + { + OM_uint32 lifetime_rec; + + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + &lifetime_rec); + if (ret) { + return ret; + } + if (lifetime_rec == 0) { + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + } + + /* We need to give the caller the flags which are in use */ + if (ret_flags) *ret_flags = ctx->flags; + + if (src_name) { + kret = krb5_copy_principal(context, + ctx->source, + (gsskrb5_name*)src_name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* + * After the krb5_rd_rep() the remote and local seq_number should + * be the same, because the client just replies the seq_number + * from our AP-REP in its AP-REP, but then the client uses the + * seq_number from its AP-REQ for GSS_wrap() + */ + { + int32_t tmp_r_seq_number, tmp_l_seq_number; + + kret = krb5_auth_con_getremoteseqnumber(context, + ctx->auth_context, + &tmp_r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &tmp_l_seq_number); + if (kret) { + + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* + * Here we check if the client has responsed with our local seq_number, + */ + if (tmp_r_seq_number != tmp_l_seq_number) { + return GSS_S_UNSEQ_TOKEN; + } + } + + /* + * We need to reset the remote seq_number, because the client will use, + * the old one for the GSS_wrap() calls + */ + { + kret = krb5_auth_con_setremoteseqnumber(context, + ctx->auth_context, + r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + return gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); +} + + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_accept_sec_context(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT(&context); + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = NULL; + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gsskrb5_create_ctx(minor_status, + context_handle, + context, + input_chan_bindings, + ACCEPTOR_START); + if (ret) + return ret; + } + + ctx = (gsskrb5_ctx)*context_handle; + + + /* + * TODO: check the channel_bindings + * (above just sets them to krb5 layer) + */ + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + switch (ctx->state) { + case ACCEPTOR_START: + ret = gsskrb5_acceptor_start(minor_status, + ctx, + context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_WAIT_FOR_DCESTYLE: + ret = acceptor_wait_for_dcestyle(minor_status, + ctx, + context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_READY: + /* + * If we get there, the caller have called + * gss_accept_sec_context() one time too many. + */ + ret = GSS_S_BAD_STATUS; + break; + default: + /* TODO: is this correct here? --metze */ + ret = GSS_S_BAD_STATUS; + break; + } + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (GSS_ERROR(ret)) { + OM_uint32 min2; + _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); + } + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c new file mode 100644 index 0000000..211dcaa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * Find an element in a cred store. Returns GSS_S_COMPLETE if the cred store + * is absent or well formed, irrespective of whether the element exists. The + * caller should check for *value != NULL before using; values are typically + * optional, hence this behavior. (The caller should validate the return + * value at least once though, to check it is well-formed.) + */ +OM_uint32 +__gsskrb5_cred_store_find(OM_uint32 *minor_status, + gss_const_key_value_set_t cred_store, + const char *key, + const char **value) +{ + size_t i; + + *value = NULL; + + if (cred_store == GSS_C_NO_CRED_STORE) + return GSS_S_COMPLETE; + else if (cred_store->count == 0) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_NO_CRED; + } + + for (i = 0; i < cred_store->count; i++) { + if (strcmp(key, cred_store->elements[i].key) == 0) { + if (*value) { + *value = NULL; + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_DUPLICATE_ELEMENT; + } + *value = cred_store->elements[i].value; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +__gsskrb5_ccache_lifetime(OM_uint32 *minor_status, + krb5_context context, + krb5_ccache id, + krb5_principal principal, + OM_uint32 *lifetime) +{ + krb5_error_code kret; + time_t left; + + kret = krb5_cc_get_lifetime(context, id, &left); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + *lifetime = left; + + return GSS_S_COMPLETE; +} + + + + +static krb5_error_code +get_system_keytab(krb5_context context, + gss_const_key_value_set_t cred_store, + krb5_keytab *keytab) +{ + krb5_error_code kret; + const char *cs_ktname; + OM_uint32 tmp; + + __gsskrb5_cred_store_find(&tmp, cred_store, "keytab", &cs_ktname); + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if (cs_ktname) + kret = krb5_kt_resolve(context, cs_ktname, keytab); + else if (_gsskrb5_keytab != NULL) { + char *name = NULL; + + kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name); + if (kret == 0) { + kret = krb5_kt_resolve(context, name, keytab); + krb5_xfree(name); + } + } else + kret = krb5_kt_default(context, keytab); + + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + + return (kret); +} + +static krb5_error_code +get_client_keytab(krb5_context context, + gss_const_key_value_set_t cred_store, + krb5_const_principal principal, + krb5_keytab *keytab) +{ + krb5_error_code ret; + const char *cs_ktname; + OM_uint32 tmp; + + __gsskrb5_cred_store_find(&tmp, cred_store, "client_keytab", &cs_ktname); + + if (cs_ktname) + ret = krb5_kt_resolve(context, cs_ktname, keytab); + else { + char *name = NULL; + ret = _krb5_kt_client_default_name(context, &name); + if (ret == 0) + ret = krb5_kt_resolve(context, name, keytab); + krb5_xfree(name); + } + + if (ret == 0 && principal) { + krb5_keytab_entry entry; + + ret = krb5_kt_get_entry(context, *keytab, principal, + 0, 0, &entry); + if (ret == 0) + krb5_kt_free_entry(context, &entry); + } + + if (ret) { + if (*keytab) { + krb5_kt_close(context, *keytab); + *keytab = NULL; + } + + ret = get_system_keytab(context, GSS_C_NO_CRED_STORE, keytab); + } + + return ret; +} + +static krb5_boolean +is_valid_password_cred_store(gss_const_key_value_set_t cred_store) +{ + size_t i; + + if (cred_store == GSS_C_NO_CRED_STORE) + return TRUE; + + /* XXX don't check keytab, someday we will allow password+acceptor creds */ + for (i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "ccache") == 0 || + strcmp(cred_store->elements[i].key, "client_keytab") == 0) + return FALSE; + } + + return TRUE; +} + +/* + * This function produces a cred with a MEMORY ccache containing a TGT + * acquired with a password. + */ +static OM_uint32 +acquire_cred_with_password(OM_uint32 *minor_status, + krb5_context context, + const char *password, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_creds cred; + krb5_init_creds_context ctx = NULL; + krb5_get_init_creds_opt *opt = NULL; + krb5_ccache ccache = NULL; + krb5_error_code kret; + time_t now; + OM_uint32 left; + const char *realm; + + if (!is_valid_password_cred_store(cred_store)) { + *minor_status = GSS_KRB5_S_G_BAD_PASSWORD_CRED_STORE; + return GSS_S_NO_CRED; + } + + if (cred_usage == GSS_C_ACCEPT) { + /* + * TODO: Here we should eventually support user2user (when we get + * support for that via an extension to the mechanism + * allowing for more than two security context tokens), + * and/or new unique MEMORY keytabs (we have MEMORY keytab + * support, but we don't have a keytab equivalent of + * krb5_cc_new_unique()). Either way, for now we can't + * support this. + */ + *minor_status = ENOTSUP; /* XXX Better error? */ + return GSS_S_FAILURE; + } + + memset(&cred, 0, sizeof(cred)); + + if (handle->principal == NULL) { + kret = krb5_get_default_principal(context, &handle->principal); + if (kret) + goto end; + } + realm = krb5_principal_get_realm(context, handle->principal); + + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret == 0) { + krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm, + opt); + kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, 0, + opt, &ctx); + } + if (kret == 0) + kret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx); + if (kret == 0) + kret = krb5_init_creds_set_password(context, ctx, password); + + /* + * Get the current time before the AS exchange so we don't + * accidentally end up returning a value that puts advertised + * expiration past the real expiration. + * + * We need to do this because krb5_cc_get_lifetime() returns a + * relative time that we need to add to the current time. We ought + * to have a version of krb5_cc_get_lifetime() that returns absolute + * time... + */ + krb5_timeofday(context, &now); + + if (kret == 0) + kret = krb5_init_creds_get(context, ctx); + if (kret == 0) + kret = krb5_init_creds_get_creds(context, ctx, &cred); + if (kret == 0) + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret == 0) + kret = krb5_init_creds_store(context, ctx, ccache); + if (kret == 0) + kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret) + goto end; + + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, + handle->principal, &left); + if (ret != GSS_S_COMPLETE) + goto end; + handle->endtime = now + left; + handle->ccache = ccache; + ccache = NULL; + ret = GSS_S_COMPLETE; + +end: + krb5_get_init_creds_opt_free(context, opt); + if (ctx) + krb5_init_creds_free(context, ctx); + if (ccache != NULL) + krb5_cc_destroy(context, ccache); + if (cred.client != NULL) + krb5_free_cred_contents(context, &cred); + if (ret != GSS_S_COMPLETE) + *minor_status = kret; + return (ret); +} + +/* + * Acquires an initiator credential from a ccache or using a keytab. + */ +static OM_uint32 +acquire_initiator_cred(OM_uint32 *minor_status, + krb5_context context, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret; + krb5_creds cred; + krb5_get_init_creds_opt *opt; + krb5_principal def_princ = NULL; + krb5_ccache def_ccache = NULL; + krb5_ccache ccache = NULL; /* we may store into this ccache */ + krb5_keytab keytab = NULL; + krb5_error_code kret = 0; + OM_uint32 left; + const char *cs_ccache_name; + time_t lifetime = 0; + time_t now; + + memset(&cred, 0, sizeof(cred)); + + ret = __gsskrb5_cred_store_find(minor_status, cred_store, + "ccache", &cs_ccache_name); + if (GSS_ERROR(ret)) + return ret; + + ret = GSS_S_FAILURE; + + /* + * Get current time early so we can set handle->endtime to a value that + * cannot accidentally be past the real endtime. We need a variant of + * krb5_cc_get_lifetime() that returns absolute endtime. + */ + krb5_timeofday(context, &now); + + /* + * First look for a ccache that has the desired_name (which may be + * the default credential name), unless a specific credential cache + * was included in cred_store. + * + * If we don't have an unexpired credential, acquire one with a + * keytab. + * + * If we acquire one with a keytab, save it in the ccache we found + * with the expired credential, if any. + * + * If we don't have any such ccache, then use a MEMORY ccache. + */ + + if (handle->principal != NULL && cs_ccache_name == NULL) { + /* + * Not default credential case. See if we can find a ccache in + * the cccol for the desired_name. + */ + kret = krb5_cc_cache_match(context, + handle->principal, + &ccache); + if (kret == 0) { + kret = krb5_cc_get_lifetime(context, ccache, &lifetime); + if (kret == 0) { + if (lifetime > 0) + goto found; + else + goto try_keytab; + } + } + /* + * Fall through. We shouldn't find this in the default ccache + * either, but we'll give it a try, then we'll try using a keytab. + */ + } + + /* + * Either desired_name was GSS_C_NO_NAME (default cred) or + * krb5_cc_cache_match() failed (or found expired). + */ + if (cs_ccache_name) + kret = krb5_cc_resolve(context, cs_ccache_name, &def_ccache); + else + kret = krb5_cc_default(context, &def_ccache); + if (kret != 0) + goto try_keytab; + kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime); + if (kret != 0) + lifetime = 0; + kret = krb5_cc_get_principal(context, def_ccache, &def_princ); + if (kret != 0) + goto try_keytab; + /* + * Have a default ccache; see if it matches desired_name. + */ + if (handle->principal == NULL || + krb5_principal_compare(context, handle->principal, + def_princ) == TRUE) { + /* + * It matches. + * + * If we end up trying a keytab then we can write the result to + * the default ccache. + */ + if (handle->principal == NULL) { + kret = krb5_copy_principal(context, def_princ, &handle->principal); + if (kret) + goto end; + } + if (ccache != NULL) + krb5_cc_close(context, ccache); + ccache = def_ccache; + def_ccache = NULL; + if (lifetime > 0) + goto found; + /* else we fall through and try using a keytab */ + } + +try_keytab: + if (handle->principal == NULL) { + /* We need to know what client principal to use */ + kret = krb5_get_default_principal(context, &handle->principal); + if (kret) + goto end; + } + kret = get_client_keytab(context, cred_store, handle->principal, &keytab); + if (kret) + goto end; + + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret) + goto end; + krb5_timeofday(context, &now); + kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, + keytab, 0, NULL, opt); + krb5_get_init_creds_opt_free(context, opt); + if (kret) + goto end; + + /* + * We got a credential with a keytab. Save it if we can. + */ + if (ccache == NULL) { + /* + * There's no ccache we can overwrite with the credentials we acquired + * with a keytab. We'll use a MEMORY ccache then. + * + * Note that an application that falls into this repeatedly will do an + * AS exchange every time it acquires a credential handle. Hopefully + * this doesn't happen much. A workaround is to kinit -k once so that + * we always re-initialize the matched/default ccache here. I.e., once + * there's a FILE/DIR ccache, we'll keep it frash automatically if we + * have a keytab, but if there's no FILE/DIR ccache, then we'll + * get a fresh credential *every* time we're asked. + */ + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret) + goto end; + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + } /* else we'll re-initialize whichever ccache we matched above */ + + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret) + goto end; + kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret) + goto end; + +found: + assert(handle->principal != NULL); + ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, + handle->principal, &left); + if (ret != GSS_S_COMPLETE) + goto end; + handle->endtime = now + left; + handle->ccache = ccache; + ccache = NULL; + ret = GSS_S_COMPLETE; + kret = 0; + +end: + if (ccache != NULL) { + if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0) + krb5_cc_destroy(context, ccache); + else + krb5_cc_close(context, ccache); + } + if (def_ccache != NULL) + krb5_cc_close(context, def_ccache); + if (cred.client != NULL) + krb5_free_cred_contents(context, &cred); + if (def_princ != NULL) + krb5_free_principal(context, def_princ); + if (keytab != NULL) + krb5_kt_close(context, keytab); + if (ret != GSS_S_COMPLETE && kret != 0) + *minor_status = kret; + return (ret); +} + +static OM_uint32 +acquire_acceptor_cred(OM_uint32 * minor_status, + krb5_context context, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret; + krb5_error_code kret; + + ret = GSS_S_FAILURE; + + kret = get_system_keytab(context, cred_store, &handle->keytab); + if (kret) + goto end; + + /* check that the requested principal exists in the keytab */ + if (handle->principal) { + krb5_keytab_entry entry; + + kret = krb5_kt_get_entry(context, handle->keytab, + handle->principal, 0, 0, &entry); + if (kret) + goto end; + krb5_kt_free_entry(context, &entry); + ret = GSS_S_COMPLETE; + } else { + /* + * Check if there is at least one entry in the keytab before + * declaring it as an useful keytab. + */ + krb5_keytab_entry tmp; + krb5_kt_cursor c; + + kret = krb5_kt_start_seq_get (context, handle->keytab, &c); + if (kret) + goto end; + if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) { + krb5_kt_free_entry(context, &tmp); + ret = GSS_S_COMPLETE; /* ok found one entry */ + } + krb5_kt_end_seq_get (context, handle->keytab, &c); + } +end: + if (ret != GSS_S_COMPLETE) { + if (handle->keytab != NULL) + krb5_kt_close(context, handle->keytab); + if (kret != 0) { + *minor_status = kret; + } + } + return (ret); +} + + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from +(OM_uint32 * minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t * output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec + ) +{ + krb5_context context; + gsskrb5_cred handle; + OM_uint32 ret; + const char *password = NULL; + + if (desired_mechs) { + int present = 0; + + ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + desired_mechs, &present); + if (ret) + return ret; + if (!present) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + } + + cred_usage &= GSS_C_OPTION_MASK; + + if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && + cred_usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + + ret = __gsskrb5_cred_store_find(minor_status, cred_store, + "password", &password); + if (GSS_ERROR(ret)) + return ret; + + GSSAPI_KRB5_INIT(&context); + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + handle->destination_realm = NULL; + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + if (desired_name != GSS_C_NO_NAME) { + ret = _gsskrb5_canon_name(minor_status, context, + desired_name, &handle->principal); + if (ret) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + return ret; + } + } + + if (password) { + ret = acquire_cred_with_password(minor_status, context, password, time_req, + desired_mechs, cred_usage, cred_store, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } else { + /* + * Acquire a credential from the specified or background credential + * store (ccache, keytab). + */ + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { + ret = acquire_initiator_cred(minor_status, context, time_req, + desired_mechs, cred_usage, + cred_store, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { + ret = acquire_acceptor_cred(minor_status, context, time_req, + desired_mechs, cred_usage, + cred_store, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } + } + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + handle->usage = cred_usage; + if (ret == GSS_S_COMPLETE) + ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle, + NULL, time_rec, NULL, actual_mechs); + if (ret != GSS_S_COMPLETE) { + if (handle->mechanisms != NULL) + gss_release_oid_set(NULL, &handle->mechanisms); + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + *minor_status = 0; + *output_cred_handle = (gss_cred_id_t)handle; + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/krb5/add_cred.c b/third_party/heimdal/lib/gssapi/krb5/add_cred.c new file mode 100644 index 0000000..0bc61a7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/add_cred.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred_from ( + OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + krb5_context context; + OM_uint32 major, lifetime; + gsskrb5_cred cred, handle; + krb5_const_principal dname; + + handle = NULL; + cred = (gsskrb5_cred)input_cred_handle; + dname = (krb5_const_principal)desired_name; + + if (cred == NULL && output_cred_handle == NULL) { + *minor_status = EINVAL; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + GSSAPI_KRB5_INIT (&context); + + if (desired_mech != GSS_C_NO_OID && + gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + if (cred == NULL) { + /* + * Acquire a credential; output_cred_handle can't be NULL, see above. + */ + heim_assert(output_cred_handle != NULL, + "internal error in _gsskrb5_add_cred()"); + + major = _gsskrb5_acquire_cred_from(minor_status, desired_name, + min(initiator_time_req, + acceptor_time_req), + GSS_C_NO_OID_SET, + cred_usage, + cred_store, + output_cred_handle, + actual_mechs, &lifetime); + if (major != GSS_S_COMPLETE) + goto failure; + + } else { + /* + * Check that we're done or copy input to output if + * output_cred_handle != NULL. + */ + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + /* Check if requested output usage is compatible with output usage */ + if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return(GSS_S_FAILURE); + } + + /* Check that we have the same name */ + if (dname != NULL && + krb5_principal_compare(context, dname, + cred->principal) != FALSE) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; + return GSS_S_BAD_NAME; + } + + if (output_cred_handle == NULL) { + /* + * This case is basically useless as we implement a single + * mechanism here, so we can't add elements to the + * input_cred_handle. + */ + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; + return GSS_S_COMPLETE; + } + + /* + * Copy input to output -- this works as if we were a + * GSS_Duplicate_cred() for one mechanism element. + */ + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + if (cred != NULL) + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + handle->usage = cred_usage; + handle->endtime = cred->endtime; + handle->principal = NULL; + handle->destination_realm = NULL; + handle->keytab = NULL; + handle->ccache = NULL; + handle->mechanisms = NULL; + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + major = GSS_S_FAILURE; + + *minor_status = krb5_copy_principal(context, cred->principal, + &handle->principal); + if (*minor_status) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + free(handle); + return GSS_S_FAILURE; + } + + if (cred->keytab) { + char *name = NULL; + + *minor_status = krb5_kt_get_full_name(context, cred->keytab, + &name); + if (*minor_status) + goto failure; + + *minor_status = krb5_kt_resolve(context, name, &handle->keytab); + krb5_xfree(name); + if (*minor_status) + goto failure; + } + + if (cred->ccache) { + const char *type, *name; + char *type_name = NULL; + + type = krb5_cc_get_type(context, cred->ccache); + if (type == NULL){ + *minor_status = ENOMEM; + goto failure; + } + + if (strcmp(type, "MEMORY") == 0) { + *minor_status = krb5_cc_new_unique(context, type, + NULL, &handle->ccache); + if (*minor_status) + goto failure; + + *minor_status = krb5_cc_copy_cache(context, cred->ccache, + handle->ccache); + if (*minor_status) + goto failure; + + } else { + name = krb5_cc_get_name(context, cred->ccache); + if (name == NULL) { + *minor_status = ENOMEM; + goto failure; + } + + if (asprintf(&type_name, "%s:%s", type, name) == -1 || + type_name == NULL) { + *minor_status = ENOMEM; + goto failure; + } + + *minor_status = krb5_cc_resolve(context, type_name, + &handle->ccache); + free(type_name); + if (*minor_status) + goto failure; + } + } + major = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (major != GSS_S_COMPLETE) + goto failure; + + major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (major != GSS_S_COMPLETE) + goto failure; + + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + + major = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, + NULL, &lifetime, NULL, actual_mechs); + if (major != GSS_S_COMPLETE) + goto failure; + + *output_cred_handle = (gss_cred_id_t)handle; + } + + if (initiator_time_rec) + *initiator_time_rec = lifetime; + if (acceptor_time_rec) + *acceptor_time_rec = lifetime; + + *minor_status = 0; + return major; + +failure: + if (handle) { + if (handle->principal) + krb5_free_principal(context, handle->principal); + if (handle->keytab) + krb5_kt_close(context, handle->keytab); + if (handle->ccache) + krb5_cc_destroy(context, handle->ccache); + if (handle->mechanisms) + gss_release_oid_set(NULL, &handle->mechanisms); + free(handle); + } + if (cred && output_cred_handle) + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c b/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c new file mode 100644 index 0000000..fa115d9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#include + +krb5_error_code +_gsskrb5i_address_to_krb5addr(krb5_context context, + OM_uint32 gss_addr_type, + gss_buffer_desc *gss_addr, + int16_t port, + krb5_address *address) +{ + int addr_type; + struct sockaddr sa; + krb5_socklen_t sa_size = sizeof(sa); + krb5_error_code problem; + + if (gss_addr == NULL) + return GSS_S_FAILURE; + + switch (gss_addr_type) { +#ifdef HAVE_IPV6 + case GSS_C_AF_INET6: addr_type = AF_INET6; + break; +#endif /* HAVE_IPV6 */ + + case GSS_C_AF_INET: addr_type = AF_INET; + break; + default: + return GSS_S_FAILURE; + } + + problem = krb5_h_addr2sockaddr (context, + addr_type, + gss_addr->value, + &sa, + &sa_size, + port); + if (problem) + return GSS_S_FAILURE; + + problem = krb5_sockaddr2address (context, &sa, address); + + return problem; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/aeap.c b/third_party/heimdal/lib/gssapi/krb5/aeap.c new file mode 100644 index 0000000..fe95ecf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/aeap.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#include + +OM_uint32 GSSAPI_CALLCONV +_gk_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 ret; + krb5_keyblock *key; + krb5_keytype keytype; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx_iov(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count, key); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gk_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, + conf_state, qop_state, iov, iov_count); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context, + conf_state, qop_state, + iov, iov_count, key); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gk_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_iov_length_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, conf_state, + iov, iov_count); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context, + conf_req_flag, qop_req, conf_state, + iov, iov_count); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/arcfour.c b/third_party/heimdal/lib/gssapi/krb5/arcfour.c new file mode 100644 index 0000000..787a8d3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/arcfour.c @@ -0,0 +1,1391 @@ +/* + * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt + * + * The arcfour message have the following formats: + * + * MIC token + * TOK_ID[2] = 01 01 + * SGN_ALG[2] = 11 00 + * Filler[4] + * SND_SEQ[8] + * SGN_CKSUM[8] + * + * WRAP token + * TOK_ID[2] = 02 01 + * SGN_ALG[2]; + * SEAL_ALG[2] + * Filler[2] + * SND_SEQ[2] + * SGN_CKSUM[8] + * Confounder[8] + */ + +/* + * WRAP in DCE-style have a fixed size header, the oid and length over + * the WRAP header is a total of + * GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE + + * GSS_ARCFOUR_WRAP_TOKEN_SIZE byte (ie total of 45 bytes overhead, + * remember the 2 bytes from APPL [0] SEQ). + */ + +#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32 +#define GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE 13 + + +static krb5_error_code +arcfour_mic_key(krb5_context context, krb5_keyblock *key, + const void *cksum_data, size_t cksum_size, + void *key6_data, size_t key6_size) +{ + krb5_error_code ret; + + Checksum cksum_k5; + krb5_keyblock key5; + char k5_data[16]; + + Checksum cksum_k6; + + char T[4]; + + memset(T, 0, 4); + cksum_k5.checksum.data = k5_data; + cksum_k5.checksum.length = sizeof(k5_data); + + if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) { + char L40[14] = "fortybits"; + + memcpy(L40 + 10, T, sizeof(T)); + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + L40, 14, 0, key, &cksum_k5); + memset(&k5_data[7], 0xAB, 9); + } else { + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + T, 4, 0, key, &cksum_k5); + } + if (ret) + return ret; + + key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5; + key5.keyvalue = cksum_k5.checksum; + + cksum_k6.checksum.data = key6_data; + cksum_k6.checksum.length = key6_size; + + return krb5_hmac(context, CKSUMTYPE_RSA_MD5, + cksum_data, cksum_size, 0, &key5, &cksum_k6); +} + + +static krb5_error_code +arcfour_mic_cksum_iov(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const gss_iov_buffer_desc *iov, + int iov_count, + const gss_iov_buffer_desc *padding) +{ + Checksum CKSUM; + u_char *ptr; + size_t len; + size_t ofs = 0; + int i; + krb5_crypto crypto; + krb5_error_code ret; + + assert(sgn_cksum_sz == 8); + + len = l1 + l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + len += iov[i].buffer.length; + } + + if (padding) { + len += padding->buffer.length; + } + + ptr = malloc(len); + if (ptr == NULL) + return ENOMEM; + + memcpy(ptr + ofs, v1, l1); + ofs += l1; + memcpy(ptr + ofs, v2, l2); + ofs += l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + if (iov[i].buffer.length > 0) { + assert(iov[i].buffer.value != NULL); + memcpy(ptr + ofs, + iov[i].buffer.value, + iov[i].buffer.length); + ofs += iov[i].buffer.length; + } + } + + if (padding) { + memcpy(ptr + ofs, + padding->buffer.value, + padding->buffer.length); + /* ofs += padding->buffer.length; */ + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free(ptr); + return ret; + } + + ret = krb5_create_checksum(context, + crypto, + usage, + 0, + ptr, len, + &CKSUM); + memset(ptr, 0, len); + free(ptr); + if (ret == 0) { + memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); + free_Checksum(&CKSUM); + } + krb5_crypto_destroy(context, crypto); + + return ret; +} + +static krb5_error_code +arcfour_mic_cksum(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) +{ + gss_iov_buffer_desc iov; + + iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov.buffer.value = rk_UNCONST(v3); + iov.buffer.length = l3; + + return arcfour_mic_cksum_iov(context, key, usage, + sgn_cksum, sgn_cksum_sz, + v1, l1, v2, l2, + &iov, 1, NULL); +} + + +OM_uint32 +_gssapi_get_mic_arcfour(OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) +{ + krb5_error_code ret; + int32_t seq_number; + size_t len, total_len; + u_char k6_data[16], *p0, *p; + EVP_CIPHER_CTX rc4_key; + + _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(message_token->value, + len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x01; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + + p = NULL; + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, Filer */ + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + _gsskrb5_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + _gsskrb5_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + context_handle->auth_context, + &seq_number); + p = p0 + 8; /* SND_SEQ */ + _gss_mg_encode_be_uint32(seq_number, p); + + krb5_auth_con_setlocalseqnumber (context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4); + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p, p, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gssapi_verify_mic_arcfour(OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type) +{ + krb5_error_code ret; + uint32_t seq_number; + OM_uint32 omret; + u_char SND_SEQ[8], cksum_data[8], *p; + char k6_data[16]; + int cmp; + + if (qop_state) + *qop_state = 0; + + p = token_buffer->value; + omret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, + cksum_data, sizeof(cksum_data), + p - 8, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(context, key, + cksum_data, sizeof(cksum_data), + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = (ct_memcmp(cksum_data, p + 8, 8) != 0); + if (cmp) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL, 0); + EVP_Cipher(&rc4_key, SND_SEQ, p, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + _gss_mg_decode_be_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + else + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + + memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ)); + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_arcfour(OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key) +{ + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t len, total_len, datalen; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + + if (conf_state) + *conf_state = 0; + + datalen = input_message_buffer->length; + + if (IS_DCE_STYLE(context_handle)) { + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + } else { + datalen += 1; /* padding */ + len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(output_message_buffer->value, + len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x02; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + if (conf_req_flag) { + *p++ = 0x10; /* SEAL_ALG */ + *p++ = 0x00; + } else { + *p++ = 0xff; /* SEAL_ALG */ + *p++ = 0xff; + } + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + + p = NULL; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + context_handle->auth_context, + &seq_number); + + _gss_mg_encode_be_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber (context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p0 + 8 + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* p points to data */ + p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + memcpy(p, input_message_buffer->value, input_message_buffer->length); + + if (!IS_DCE_STYLE(context_handle)) + p[input_message_buffer->length] = 1; /* padding */ + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + if (ret) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + + { + int i; + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + + if(conf_req_flag) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8 + datalen); + EVP_CIPHER_CTX_cleanup(&rc4_key); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key) +{ + u_char Klocaldata[16]; + krb5_keyblock Klocal; + krb5_error_code ret; + uint32_t seq_number; + size_t datalen; + OM_uint32 omret; + u_char k6_data[16], SND_SEQ[8], Confounder[8]; + u_char cksum_data[8]; + u_char *p, *p0; + int cmp; + int conf_flag; + size_t padlen = 0, len; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + p0 = input_message_buffer->value; + + if (IS_DCE_STYLE(context_handle)) { + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + + GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + } else { + len = input_message_buffer->length; + } + + omret = _gssapi_verify_mech_header(&p0, + len, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + + /* length of mech header */ + len = (p0 - (u_char *)input_message_buffer->value) + + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (len > input_message_buffer->length) + return GSS_S_BAD_MECH; + + /* length of data */ + datalen = input_message_buffer->length - len; + + p = p0; + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x10\x00", 2) == 0) + conf_flag = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_flag = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, SND_SEQ, p0 + 8, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + } + + _gss_mg_decode_be_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + else + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + int i; + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(context, &Klocal, + SND_SEQ, 4, + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_message_buffer->value = malloc(datalen); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_message_buffer->length = datalen; + + if(conf_flag) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); + EVP_Cipher(&rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); + EVP_CIPHER_CTX_cleanup(&rc4_key); + } else { + memcpy(Confounder, p0 + 24, 8); /* Confounder */ + memcpy(output_message_buffer->value, + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + } + memset(k6_data, 0, sizeof(k6_data)); + + if (!IS_DCE_STYLE(context_handle)) { + ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return ret; + } + output_message_buffer->length -= padlen; + } + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + output_message_buffer->value, + output_message_buffer->length + padlen); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + if (conf_state) + *conf_state = conf_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +max_wrap_length_arcfour(const gsskrb5_ctx ctx, + krb5_crypto crypto, + size_t input_length, + OM_uint32 *max_input_size) +{ + /* + * if GSS_C_DCE_STYLE is in use: + * - we only need to encapsulate the WRAP token + * However, since this is a fixed since, we just + */ + if (IS_DCE_STYLE(ctx)) { + size_t len, total_len; + + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + if (input_length < len) + *max_input_size = 0; + else + *max_input_size = input_length - len; + + } else { + size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + size_t blocksize = 8; + size_t len, total_len; + + len = 8 + input_length + blocksize + extrasize; + + _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + total_len -= input_length; /* token length */ + if (total_len < input_length) { + *max_input_size = (input_length - total_len); + (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); + } else { + *max_input_size = 0; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_size_arcfour(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_crypto crypto; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = max_wrap_length_arcfour(ctx, crypto, + req_output_size, max_input_size); + if (ret != 0) { + *minor_status = ret; + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + + krb5_crypto_destroy(context, crypto); + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status; + size_t data_len = 0; + int i; + gss_iov_buffer_desc *header = NULL; + gss_iov_buffer_desc *padding = NULL; + gss_iov_buffer_desc *trailer = NULL; + + *minor_status = 0; + + for (i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + data_len += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + if (header != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + header = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + if (trailer != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + trailer = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + padding = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (IS_DCE_STYLE(ctx)) { + size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + size_t total_len; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len; + } else { + size_t len; + size_t total_len; + if (padding) { + data_len += 1; /* padding */ + } + len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len - data_len; + } + + if (trailer) { + trailer->buffer.length = 0; + } + + if (padding) { + padding->buffer.length = 1; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_error_code kret; + int32_t seq_number; + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t make_len = 0; + size_t header_len = 0; + size_t data_len = 0; + krb5_keyblock Klocal; + int i; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + data_len += iov[i].buffer.length; + } + + if (padding) { + data_len += 1; + } + + if (IS_DCE_STYLE(ctx)) { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + } else { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + header_len -= data_len; + } + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, header, + header_len); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < header_len) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + header->buffer.length = header_len; + } + + if (padding) { + if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, padding, 1); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (padding->buffer.length < 1) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + padding->buffer.length = 1; + } + memset(padding->buffer.value, 1, 1); + } + + if (trailer) { + trailer->buffer.length = 0; + trailer->buffer.value = NULL; + } + + p0 = _gssapi_make_mech_header(header->buffer.value, + make_len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x02; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + if (conf_req_flag) { + *p++ = 0x10; /* SEAL_ALG */ + *p++ = 0x00; + } else { + *p++ = 0xff; /* SEAL_ALG */ + *p++ = 0xff; + } + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + + p = NULL; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gss_mg_encode_be_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + memset(p0 + 8 + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* Sign Data */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + iov, iov_count, /* Data + SignOnly */ + padding); /* padding */ + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + kret = arcfour_mic_key(context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8); + + /* Seal Data */ + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } + memset(k6_data, 0, sizeof(k6_data)); + + kret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + return major_status; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; + +failure: + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *pconf_state, + gss_qop_t *pqop_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_keyblock Klocal; + uint8_t Klocaldata[16]; + uint8_t k6_data[16], snd_seq[8], Confounder[8]; + uint8_t cksum_data[8]; + uint8_t *_p = NULL; + const uint8_t *p, *p0; + size_t verify_len = 0; + uint32_t seq_number; + size_t hlen = 0; + int conf_state; + int cmp; + size_t i; + krb5_error_code kret; + OM_uint32 ret; + + if (pconf_state != NULL) { + *pconf_state = 0; + } + if (pqop_state != NULL) { + *pqop_state = 0; + } + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + /* Check if the packet is correct */ + major_status = _gk_verify_buffers(minor_status, + ctx, + header, + padding, + trailer, + FALSE); /* behaves as stream cipher */ + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (padding != NULL && padding->buffer.length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + verify_len = header->buffer.length; + + if (!IS_DCE_STYLE(ctx)) { + for (i = 0; i < iov_count; i++) { + /* length in header also includes data and padding */ + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) + verify_len += iov[i].buffer.length; + } + + if (padding) + verify_len += padding->buffer.length; + } + + _p = header->buffer.value; + + ret = _gssapi_verify_mech_header(&_p, + verify_len, + GSS_KRB5_MECHANISM); + if (ret) { + return ret; + } + p0 = _p; + + /* length of mech header */ + hlen = (p0 - (uint8_t *)header->buffer.value); + hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (hlen > header->buffer.length) { + return GSS_S_BAD_MECH; + } + + p = p0; + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x10\x00", 2) == 0) + conf_state = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_state = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + kret = arcfour_mic_key(context, + key, + p0 + 16, /* SGN_CKSUM */ + 8, /* SGN_CKSUM_LEN */ + k6_data, + sizeof(k6_data)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + _gss_mg_decode_be_uint32(snd_seq, &seq_number); + + if (ctx->more_flags & LOCAL) { + cmp = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0); + } else { + cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0); + } + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + /* keyblock */ + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + + kret = arcfour_mic_key(context, + &Klocal, + snd_seq, + 4, + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (conf_state == 1) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); + + /* Data */ + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } else { + /* Confounder */ + memcpy(Confounder, p0 + 24, 8); + } + memset(k6_data, 0, sizeof(k6_data)); + + /* Prepare the buffer for signing */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + iov, iov_count, + padding); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + cmp = (ct_memcmp(cksum_data, p0 + 16, 8) != 0); /* SGN_CKSUM */ + if (cmp) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + if (padding) { + size_t plen; + + ret = _gssapi_verify_pad(&padding->buffer, 1, &plen); + if (ret) { + *minor_status = 0; + return ret; + } + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret != 0) { + return ret; + } + + if (pconf_state) { + *pconf_state = conf_state; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c b/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c new file mode 100644 index 0000000..5621c1f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_authorize_localname(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_const_buffer_t user_name, + gss_const_OID user_name_type) +{ + krb5_context context; + krb5_principal princ = (krb5_principal)input_name; + char *user; + int user_ok; + + if (!gss_oid_equal(user_name_type, GSS_C_NT_USER_NAME)) + return GSS_S_BAD_NAMETYPE; + + GSSAPI_KRB5_INIT(&context); + + user = malloc(user_name->length + 1); + if (user == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(user, user_name->value, user_name->length); + user[user_name->length] = '\0'; + + *minor_status = 0; + user_ok = krb5_kuserok(context, princ, user); + + free(user); + + return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c b/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c new file mode 100644 index 0000000..62de423 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_canonicalize_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t * output_name + ) +{ + krb5_context context; + krb5_principal name; + OM_uint32 ret; + + *output_name = NULL; + + GSSAPI_KRB5_INIT (&context); + + ret = _gsskrb5_canon_name(minor_status, context, input_name, &name); + if (ret) + return ret; + + *output_name = (gss_name_t)name; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/ccache_name.c b/third_party/heimdal/lib/gssapi/krb5/ccache_name.c new file mode 100644 index 0000000..0a2d596 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/ccache_name.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static heim_base_atomic(char *) last_out_name; /* XXX should be thread-specific */ + +OM_uint32 +_gsskrb5_krb5_ccache_name(OM_uint32 *minor_status, + const char *name, + const char **out_name) +{ + krb5_context context; + krb5_error_code kret; + + *minor_status = 0; + + GSSAPI_KRB5_INIT(&context); + + if (out_name) { + const char *def_name; + + *out_name = NULL; + + def_name = krb5_cc_default_name(context); + if (def_name) { + char *s = strdup(def_name); + if (s) { + s = heim_base_exchange_pointer(&last_out_name, s); + free(s); + + *out_name = last_out_name; + } + } + + if (*out_name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + } + + kret = krb5_cc_set_default_name(context, name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/cfx.c b/third_party/heimdal/lib/gssapi/krb5/cfx.c new file mode 100644 index 0000000..cb9ea77 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/cfx.c @@ -0,0 +1,1797 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * Implementation of RFC 4121 + */ + +#define CFXSentByAcceptor (1 << 0) +#define CFXSealed (1 << 1) +#define CFXAcceptorSubkey (1 << 2) + +krb5_error_code +_gsskrb5cfx_wrap_length_cfx(krb5_context context, + krb5_crypto crypto, + int conf_req_flag, + int dce_style, + size_t input_length, + size_t *output_length, + size_t *cksumsize, + uint16_t *padlength) +{ + krb5_error_code ret; + krb5_cksumtype type; + + /* 16-byte header is always first */ + *output_length = sizeof(gss_cfx_wrap_token_desc); + *padlength = 0; + + ret = krb5_crypto_get_checksum_type(context, crypto, &type); + if (ret) + return ret; + + ret = krb5_checksumsize(context, type, cksumsize); + if (ret) + return ret; + + if (conf_req_flag) { + size_t padsize; + + /* Header is concatenated with data before encryption */ + input_length += sizeof(gss_cfx_wrap_token_desc); + + if (dce_style) { + ret = krb5_crypto_getblocksize(context, crypto, &padsize); + } else { + ret = krb5_crypto_getpadsize(context, crypto, &padsize); + } + if (ret) { + return ret; + } + if (padsize > 1) { + /* XXX check this */ + *padlength = padsize - (input_length % padsize); + + /* We add the pad ourselves (noted here for completeness only) */ + input_length += *padlength; + } + + *output_length += krb5_get_wrapped_length(context, + crypto, input_length); + } else { + /* Checksum is concatenated with data */ + *output_length += input_length + *cksumsize; + } + + assert(*output_length > input_length); + + return 0; +} + +OM_uint32 +_gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + krb5_error_code ret; + + *max_input_size = 0; + + /* 16-byte header is always first */ + if (req_output_size < 16) + return 0; + req_output_size -= 16; + + if (conf_req_flag) { + size_t wrapped_size, sz; + + wrapped_size = req_output_size + 1; + do { + wrapped_size--; + sz = krb5_get_wrapped_length(context, + ctx->crypto, wrapped_size); + } while (wrapped_size && sz > req_output_size); + if (wrapped_size == 0) + return 0; + + /* inner header */ + if (wrapped_size < 16) + return 0; + + wrapped_size -= 16; + + *max_input_size = wrapped_size; + } else { + krb5_cksumtype type; + size_t cksumsize; + + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type); + if (ret) + return ret; + + ret = krb5_checksumsize(context, type, &cksumsize); + if (ret) + return ret; + + if (req_output_size < cksumsize) + return 0; + + /* Checksum is concatenated with data */ + *max_input_size = req_output_size - cksumsize; + } + + return 0; +} + +/* + * Rotate "rrc" bytes to the front or back + */ + +static krb5_error_code +rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) +{ + u_char *tmp, buf[256]; + size_t left; + + if (len == 0) + return 0; + + rrc %= len; + + if (rrc == 0) + return 0; + + left = len - rrc; + + if (rrc <= sizeof(buf)) { + tmp = buf; + } else { + tmp = malloc(rrc); + if (tmp == NULL) + return ENOMEM; + } + + if (unrotate) { + memcpy(tmp, data, rrc); + memmove(data, (u_char *)data + rrc, left); + memcpy((u_char *)data + left, tmp, rrc); + } else { + memcpy(tmp, (u_char *)data + left, rrc); + memmove((u_char *)data + rrc, data, left); + memcpy(data, tmp, rrc); + } + + if (rrc > sizeof(buf)) + free(tmp); + + return 0; +} + +gss_iov_buffer_desc * +_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type) +{ + int i; + gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER; + + if (iov == GSS_C_NO_IOV_BUFFER) + return GSS_C_NO_IOV_BUFFER; + + /* + * This function is used to find header, padding or trailer buffers + * which are singletons; return NULL if multiple instances are found. + */ + for (i = 0; i < iov_count; i++) { + if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) { + if (iovp == GSS_C_NO_IOV_BUFFER) + iovp = &iov[i]; + else + return GSS_C_NO_IOV_BUFFER; + } + } + + /* + * For compatibility with SSPI, an empty padding buffer is treated + * equivalent to an absent padding buffer (unless the caller is + * requesting that a padding buffer be allocated). + */ + if (iovp && + iovp->buffer.length == 0 && + type == GSS_IOV_BUFFER_TYPE_PADDING && + (GSS_IOV_BUFFER_FLAGS(iovp->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) == 0) + iovp = NULL; + + return iovp; +} + +OM_uint32 +_gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size) +{ + if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { + if (buffer->buffer.length == size) + return GSS_S_COMPLETE; + free(buffer->buffer.value); + } + + buffer->buffer.value = malloc(size); + buffer->buffer.length = size; + if (buffer->buffer.value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED; + + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gk_verify_buffers(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + const gss_iov_buffer_desc *header, + const gss_iov_buffer_desc *padding, + const gss_iov_buffer_desc *trailer, + int block_cipher) +{ + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(ctx)) { + /* + * In DCE style mode we reject having a padding or trailer buffer + */ + if (padding || trailer) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } else { + /* + * In non-DCE style mode we require having a padding buffer for + * encryption types that do not behave as stream ciphers. This + * check is superfluous for now, as only RC4 and RFC4121 enctypes + * are presently implemented for the IOV APIs; be defensive. + */ + if (block_cipher && padding == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_cfx_iov(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *trailer, *padding; + size_t gsshsize, k5hsize; + size_t gsstsize, k5tsize; + size_t rrc = 0, ec = 0; + int i; + gss_cfx_wrap_token token; + krb5_error_code ret; + int32_t seq_number; + unsigned usage; + krb5_crypto_iov *data = NULL; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL) { + padding->buffer.length = 0; + } + + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (conf_req_flag) { + size_t k5psize = 0; + size_t k5pbase = 0; + size_t k5bsize = 0; + size_t size = 0; + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + size += iov[i].buffer.length; + break; + default: + break; + } + } + + size += sizeof(gss_cfx_wrap_token_desc); + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_HEADER, + &k5hsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_TRAILER, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_PADDING, + &k5pbase); + if (*minor_status) + return GSS_S_FAILURE; + + if (k5pbase > 1) { + k5psize = k5pbase - (size % k5pbase); + } else { + k5psize = 0; + } + + if (k5psize == 0 && IS_DCE_STYLE(ctx)) { + *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, + &k5bsize); + if (*minor_status) + return GSS_S_FAILURE; + ec = k5bsize; + } else { + ec = k5psize; + } + + gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; + gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; + } else { + if (IS_DCE_STYLE(ctx)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + k5hsize = 0; + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_CHECKSUM, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + gsshsize = sizeof(gss_cfx_wrap_token_desc); + gsstsize = k5tsize; + } + + /* + * + */ + + if (trailer == NULL) { + rrc = gsstsize; + if (IS_DCE_STYLE(ctx)) + rrc -= ec; + gsshsize += gsstsize; + } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize); + if (major_status) + goto failure; + } else if (trailer->buffer.length < gsstsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + trailer->buffer.length = gsstsize; + + /* + * + */ + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, header, gsshsize); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < gsshsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + header->buffer.length = gsshsize; + + token = (gss_cfx_wrap_token)header->buffer.value; + + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + + if (ctx->more_flags & LOCAL) + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + else + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + + if (conf_req_flag) { + /* + * In Wrap tokens with confidentiality, the EC field is + * used to encode the size (in bytes) of the random filler. + */ + token->Flags |= CFXSealed; + token->EC[0] = (ec >> 8) & 0xFF; + token->EC[1] = (ec >> 0) & 0xFF; + + } else { + /* + * In Wrap tokens without confidentiality, the EC field is + * used to encode the size (in bytes) of the trailing + * checksum. + * + * This is not used in the checksum calcuation itself, + * because the checksum length could potentially vary + * depending on the data length. + */ + token->EC[0] = 0; + token->EC[1] = 0; + } + + /* + * In Wrap tokens that provide for confidentiality, the RRC + * field in the header contains the hex value 00 00 before + * encryption. + * + * In Wrap tokens that do not provide for confidentiality, + * both the EC and RRC fields in the appended checksum + * contain the hex value 00 00 for the purpose of calculating + * the checksum. + */ + token->RRC[0] = 0; + token->RRC[1] = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]); + _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + /* + plain packet: + + {"header" | encrypt(plaintext-data | ec-padding | E"header")} + + Expanded, this is with with RRC = 0: + + {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer } + + In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer) + + {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data } + */ + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + + for (i = 1; i < iov_count + 1; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i - 1].buffer.length; + data[i].data.data = iov[i - 1].buffer.value; + } + + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + */ + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) + data[i].data.data = trailer->buffer.value; + else + data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token); + + data[i].data.length = ec + sizeof(*token); + memset(data[i].data.data, 0xFF, ec); + memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token)); + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (rrc) { + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + } + + } else { + /* + plain packet: + + {data | "header" | gss-trailer (krb5 checksum) + + don't do RRC != 0 + + */ + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = sizeof(gss_cfx_wrap_token_desc); + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = (uint8_t *)header->buffer.value + + sizeof(gss_cfx_wrap_token_desc); + } + data[i].data.length = k5tsize; + i++; + + ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (rrc) { + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + } + + token->EC[0] = (k5tsize >> 8) & 0xFF; + token->EC[1] = (k5tsize >> 0) & 0xFF; + } + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +/* This is slowpath */ +static OM_uint32 +unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count) +{ + uint8_t *p, *q; + size_t len = 0, skip; + int i; + + for (i = 0; i < iov_count; i++) + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + len += iov[i].buffer.length; + + p = malloc(len); + if (p == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + q = p; + + /* copy up */ + + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + memcpy(q, iov[i].buffer.value, iov[i].buffer.length); + q += iov[i].buffer.length; + } + } + assert((size_t)(q - p) == len); + + /* unrotate first part */ + q = p + rrc; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + if (iov[i].buffer.length <= skip) { + skip -= iov[i].buffer.length; + } else { + /* copy back to original buffer */ + memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip); + q += iov[i].buffer.length - skip; + skip = 0; + } + } + } + /* copy trailer */ + q = p; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + memcpy(iov[i].buffer.value, q, min(iov[i].buffer.length, skip)); + if (iov[i].buffer.length > skip) + break; + skip -= iov[i].buffer.length; + q += iov[i].buffer.length; + } + } + free(p); + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 seq_number_lo, seq_number_hi, major_status, junk; + gss_iov_buffer_desc *header, *trailer, *padding; + gss_cfx_wrap_token token, ttoken; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + uint16_t ec, rrc; + krb5_crypto_iov *data = NULL; + int i, j; + + *minor_status = 0; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (header->buffer.length < sizeof(*token)) /* we check exact below */ + return GSS_S_DEFECTIVE_TOKEN; + + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL && padding->buffer.length != 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + token = (gss_cfx_wrap_token)header->buffer.value; + + if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) + return GSS_S_DEFECTIVE_TOKEN; + + /* Ignore unknown flags */ + token_flags = token->Flags & + (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (token->Filler != 0xFF) + return GSS_S_DEFECTIVE_TOKEN; + + if (conf_state != NULL) + *conf_state = (token_flags & CFXSealed) ? 1 : 0; + + ec = (token->EC[0] << 8) | token->EC[1]; + rrc = (token->RRC[0] << 8) | token->RRC[1]; + + /* + * Check sequence number + */ + _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + /* no support for 64-bit sequence numbers */ + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (token_flags & CFXSealed) { + size_t k5tsize, k5hsize; + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize); + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize); + + /* Rotate by RRC; bogus to do this in-place XXX */ + /* Check RRC */ + + if (trailer == NULL) { + size_t gsstsize = k5tsize + sizeof(*token); + size_t gsshsize = k5hsize + sizeof(*token); + + if (rrc != gsstsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + if (IS_DCE_STYLE(ctx)) + gsstsize += ec; + + gsshsize += gsstsize; + + if (header->buffer.length != gsshsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + } else if (trailer->buffer.length != sizeof(*token) + k5tsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (header->buffer.length != sizeof(*token) + k5hsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (rrc != 0) { + /* go though slowpath */ + major_status = unrotate_iov(minor_status, rrc, iov, iov_count); + if (major_status) + goto failure; + } + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + i++; + + for (j = 0; j < iov_count; i++, j++) { + switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[j].buffer.length; + data[i].data.data = iov[j].buffer.value; + } + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = ((uint8_t *)header->buffer.value) + + header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token); + } + + data[i].data.length = ec + sizeof(*token); + ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec); + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + ttoken->RRC[0] = token->RRC[0]; + ttoken->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) { + major_status = GSS_S_BAD_MIC; + goto failure; + } + } else { + size_t gsstsize = ec; + size_t gsshsize = sizeof(*token); + + if (trailer == NULL) { + /* Check RRC */ + if (rrc != gsstsize) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + gsshsize += gsstsize; + } else if (trailer->buffer.length != gsstsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (rrc != 0) { + /* Check RRC */ + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (header->buffer.length != gsshsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = sizeof(*token); + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = (uint8_t *)header->buffer.value + + sizeof(*token); + } + data[i].data.length = ec; + i++; + + token = (gss_cfx_wrap_token)header->buffer.value; + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + } + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status; + size_t size; + int i; + gss_iov_buffer_desc *header = NULL; + gss_iov_buffer_desc *padding = NULL; + gss_iov_buffer_desc *trailer = NULL; + size_t gsshsize = 0; + size_t gsstsize = 0; + size_t k5hsize = 0; + size_t k5tsize = 0; + + GSSAPI_KRB5_INIT (&context); + *minor_status = 0; + + for (size = 0, i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + if (header != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + header = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + if (trailer != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + trailer = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + padding = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (conf_req_flag) { + size_t k5psize = 0; + size_t k5pbase = 0; + size_t k5bsize = 0; + size_t ec = 0; + + size += sizeof(gss_cfx_wrap_token_desc); + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_HEADER, + &k5hsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_TRAILER, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_PADDING, + &k5pbase); + if (*minor_status) + return GSS_S_FAILURE; + + if (k5pbase > 1) { + k5psize = k5pbase - (size % k5pbase); + } else { + k5psize = 0; + } + + if (k5psize == 0 && IS_DCE_STYLE(ctx)) { + *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, + &k5bsize); + if (*minor_status) + return GSS_S_FAILURE; + + ec = k5bsize; + } else { + ec = k5psize; + } + + gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; + gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; + } else { + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_CHECKSUM, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + gsshsize = sizeof(gss_cfx_wrap_token_desc); + gsstsize = k5tsize; + } + + if (trailer != NULL) { + trailer->buffer.length = gsstsize; + } else { + gsshsize += gsstsize; + } + + header->buffer.length = gsshsize; + + if (padding) { + /* padding is done via EC and is contained in the header or trailer */ + padding->buffer.length = 0; + } + + if (conf_state) { + *conf_state = conf_req_flag; + } + + return GSS_S_COMPLETE; +} + + + + +OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + const gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + gss_cfx_wrap_token token; + krb5_error_code ret; + unsigned usage; + krb5_data cipher; + size_t wrapped_len, cksumsize; + uint16_t padlength, rrc = 0; + int32_t seq_number; + u_char *p; + + ret = _gsskrb5cfx_wrap_length_cfx(context, + ctx->crypto, conf_req_flag, + IS_DCE_STYLE(ctx), + input_message_buffer->length, + &wrapped_len, &cksumsize, &padlength); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* Always rotate encrypted token (if any) and checksum to header */ + rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize; + + output_message_buffer->length = wrapped_len; + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = output_message_buffer->value; + token = (gss_cfx_wrap_token)p; + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + if (conf_req_flag) { + /* + * In Wrap tokens with confidentiality, the EC field is + * used to encode the size (in bytes) of the random filler. + */ + token->Flags |= CFXSealed; + token->EC[0] = (padlength >> 8) & 0xFF; + token->EC[1] = (padlength >> 0) & 0xFF; + } else { + /* + * In Wrap tokens without confidentiality, the EC field is + * used to encode the size (in bytes) of the trailing + * checksum. + * + * This is not used in the checksum calcuation itself, + * because the checksum length could potentially vary + * depending on the data length. + */ + token->EC[0] = 0; + token->EC[1] = 0; + } + + /* + * In Wrap tokens that provide for confidentiality, the RRC + * field in the header contains the hex value 00 00 before + * encryption. + * + * In Wrap tokens that do not provide for confidentiality, + * both the EC and RRC fields in the appended checksum + * contain the hex value 00 00 for the purpose of calculating + * the checksum. + */ + token->RRC[0] = 0; + token->RRC[1] = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]); + _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * If confidentiality is requested, the token header is + * appended to the plaintext before encryption; the resulting + * token is {"header" | encrypt(plaintext | pad | "header")}. + * + * If no confidentiality is requested, the checksum is + * calculated over the plaintext concatenated with the + * token header. + */ + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } + + if (conf_req_flag) { + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + * + * The specification does not require that the padding + * bytes are initialized. + */ + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memset(p + input_message_buffer->length, 0xFF, padlength); + memcpy(p + input_message_buffer->length + padlength, + token, sizeof(*token)); + + ret = krb5_encrypt(context, ctx->crypto, + usage, p, + input_message_buffer->length + padlength + + sizeof(*token), + &cipher); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + assert(sizeof(*token) + cipher.length == wrapped_len); + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(ctx)) { + ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE); + } else { + ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); + } + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(p, cipher.data, cipher.length); + krb5_data_free(&cipher); + } else { + char *buf; + Checksum cksum; + + buf = malloc(input_message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(buf, input_message_buffer->value, input_message_buffer->length); + memcpy(buf + input_message_buffer->length, token, sizeof(*token)); + + ret = krb5_create_checksum(context, ctx->crypto, + usage, 0, buf, + input_message_buffer->length + + sizeof(*token), + &cksum); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + free(buf); + return GSS_S_FAILURE; + } + + free(buf); + + assert(cksum.checksum.length == cksumsize); + token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; + token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memcpy(p + input_message_buffer->length, + cksum.checksum.data, cksum.checksum.length); + + ret = rrc_rotate(p, + input_message_buffer->length + cksum.checksum.length, rrc, FALSE); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + free_Checksum(&cksum); + return GSS_S_FAILURE; + } + free_Checksum(&cksum); + } + + if (conf_state != NULL) { + *conf_state = conf_req_flag; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + gss_cfx_wrap_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + krb5_data data; + uint16_t ec, rrc; + OM_uint32 seq_number_lo, seq_number_hi; + size_t len; + u_char *p; + + *minor_status = 0; + + if (input_message_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = input_message_buffer->value; + + token = (gss_cfx_wrap_token)p; + + if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Ignore unknown flags */ + token_flags = token->Flags & + (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (token->Filler != 0xFF) { + return GSS_S_DEFECTIVE_TOKEN; + } + + if (conf_state != NULL) { + *conf_state = (token_flags & CFXSealed) ? 1 : 0; + } + + ec = (token->EC[0] << 8) | token->EC[1]; + rrc = (token->RRC[0] << 8) | token->RRC[1]; + + /* + * Check sequence number + */ + _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + /* no support for 64-bit sequence numbers */ + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + p += sizeof(*token); + len = input_message_buffer->length; + len -= (p - (u_char *)input_message_buffer->value); + + if (token_flags & CFXSealed) { + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(ctx)) { + *minor_status = rrc_rotate(p, len, rrc+ec, TRUE); + } else { + *minor_status = rrc_rotate(p, len, rrc, TRUE); + } + if (*minor_status != 0) { + return GSS_S_FAILURE; + } + + ret = krb5_decrypt(context, ctx->crypto, usage, + p, len, &data); + if (ret != 0) { + *minor_status = ret; + return GSS_S_BAD_MIC; + } + + /* Check that there is room for the pad and token header */ + if (data.length < ec + sizeof(*token)) { + krb5_data_free(&data); + return GSS_S_DEFECTIVE_TOKEN; + } + p = data.data; + p += data.length - sizeof(*token); + + /* RRC is unprotected; don't modify input buffer */ + ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; + ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (ct_memcmp(p, token, sizeof(*token)) != 0) { + krb5_data_free(&data); + return GSS_S_BAD_MIC; + } + + output_message_buffer->value = data.data; + output_message_buffer->length = data.length - ec - sizeof(*token); + } else { + Checksum cksum; + + /* Rotate by RRC; bogus to do this in-place XXX */ + *minor_status = rrc_rotate(p, len, rrc, TRUE); + if (*minor_status != 0) { + return GSS_S_FAILURE; + } + + /* Determine checksum type */ + ret = krb5_crypto_get_checksum_type(context, + ctx->crypto, + &cksum.cksumtype); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cksum.checksum.length = ec; + + /* Check we have at least as much data as the checksum */ + if (len < cksum.checksum.length) { + *minor_status = ERANGE; + return GSS_S_BAD_MIC; + } + + /* Length now is of the plaintext only, no checksum */ + len -= cksum.checksum.length; + cksum.checksum.data = p + len; + + output_message_buffer->length = len; /* for later */ + output_message_buffer->value = malloc(len + sizeof(*token)); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* Checksum is over (plaintext-data | "header") */ + memcpy(output_message_buffer->value, p, len); + memcpy((u_char *)output_message_buffer->value + len, + token, sizeof(*token)); + + /* EC is not included in checksum calculation */ + token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + + len); + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum(context, ctx->crypto, + usage, + output_message_buffer->value, + len + sizeof(*token), + &cksum); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_BAD_MIC; + } + } + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + gss_cfx_mic_token token; + krb5_error_code ret; + unsigned usage; + Checksum cksum; + u_char *buf; + size_t len; + int32_t seq_number; + + len = message_buffer->length + sizeof(*token); + buf = malloc(len); + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (message_buffer->length) + memcpy(buf, message_buffer->value, message_buffer->length); + else + memset(buf, 0, len); + + token = (gss_cfx_mic_token)(buf + message_buffer->length); + token->TOK_ID[0] = 0x04; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + memset(token->Filler, 0xFF, 5); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gss_mg_encode_be_uint32(0, &token->SND_SEQ[0]); + _gss_mg_encode_be_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } + + ret = krb5_create_checksum(context, ctx->crypto, + usage, 0, buf, len, &cksum); + if (ret != 0) { + *minor_status = ret; + free(buf); + return GSS_S_FAILURE; + } + + /* Determine MIC length */ + message_token->length = sizeof(*token) + cksum.checksum.length; + message_token->value = malloc(message_token->length); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + free_Checksum(&cksum); + free(buf); + return GSS_S_FAILURE; + } + + /* Token is { "header" | get_mic("header" | plaintext-data) } */ + memcpy(message_token->value, token, sizeof(*token)); + memcpy((u_char *)message_token->value + sizeof(*token), + cksum.checksum.data, cksum.checksum.length); + + free_Checksum(&cksum); + free(buf); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state) +{ + gss_cfx_mic_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + OM_uint32 seq_number_lo, seq_number_hi; + u_char *buf, *p; + Checksum cksum; + + *minor_status = 0; + + if (token_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = token_buffer->value; + + token = (gss_cfx_mic_token)p; + + if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Ignore unknown flags */ + token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* + * Check sequence number + */ + _gss_mg_decode_be_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gss_mg_decode_be_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Verify checksum + */ + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, + &cksum.cksumtype); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cksum.checksum.data = p + sizeof(*token); + cksum.checksum.length = token_buffer->length - sizeof(*token); + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } + + buf = malloc(message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + if (message_buffer->length) + memcpy(buf, message_buffer->value, message_buffer->length); + memcpy(buf + message_buffer->length, token, sizeof(*token)); + + ret = krb5_verify_checksum(context, ctx->crypto, + usage, + buf, + sizeof(*token) + message_buffer->length, + &cksum); + if (ret != 0) { + *minor_status = ret; + free(buf); + return GSS_S_BAD_MIC; + } + + free(buf); + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/cfx.h b/third_party/heimdal/lib/gssapi/krb5/cfx.h new file mode 100644 index 0000000..c30ed07 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/cfx.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSAPI_CFX_H_ +#define GSSAPI_CFX_H_ 1 + +/* + * Implementation of draft-ietf-krb-wg-gssapi-cfx-01.txt + */ + +typedef struct gss_cfx_mic_token_desc_struct { + u_char TOK_ID[2]; /* 04 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_mic_token_desc, *gss_cfx_mic_token; + +typedef struct gss_cfx_wrap_token_desc_struct { + u_char TOK_ID[2]; /* 04 05 */ + u_char Flags; + u_char Filler; + u_char EC[2]; + u_char RRC[2]; + u_char SND_SEQ[8]; +} gss_cfx_wrap_token_desc, *gss_cfx_wrap_token; + +typedef struct gss_cfx_delete_token_desc_struct { + u_char TOK_ID[2]; /* 05 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_delete_token_desc, *gss_cfx_delete_token; + +#endif /* GSSAPI_CFX_H_ */ diff --git a/third_party/heimdal/lib/gssapi/krb5/compare_name.c b/third_party/heimdal/lib/gssapi/krb5/compare_name.c new file mode 100644 index 0000000..4a37e87 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/compare_name.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_compare_name + (OM_uint32 * minor_status, + gss_const_name_t name1, + gss_const_name_t name2, + int * name_equal + ) +{ + krb5_const_principal princ1 = (krb5_const_principal)name1; + krb5_const_principal princ2 = (krb5_const_principal)name2; + krb5_context context; + + GSSAPI_KRB5_INIT(&context); + + *name_equal = krb5_principal_compare (context, + princ1, princ2); + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/compat.c b/third_party/heimdal/lib/gssapi/krb5/compat.c new file mode 100644 index 0000000..3381dff --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/compat.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static krb5_error_code +check_compat(OM_uint32 *minor_status, + krb5_context context, krb5_const_principal name, + const char *option, krb5_boolean *compat, + krb5_boolean match_val) +{ + krb5_error_code ret = 0; + char **p, **q; + krb5_principal match; + + + p = krb5_config_get_strings(context, NULL, "gssapi", + option, NULL); + if(p == NULL) + return 0; + + match = NULL; + for(q = p; *q; q++) { + ret = krb5_parse_name(context, *q, &match); + if (ret) + break; + + if (krb5_principal_match(context, name, match)) { + *compat = match_val; + break; + } + + krb5_free_principal(context, match); + match = NULL; + } + if (match) + krb5_free_principal(context, match); + krb5_config_free_strings(p); + + if (ret) { + if (minor_status) + *minor_status = ret; + return GSS_S_FAILURE; + } + + return 0; +} + +/* + * ctx->ctx_id_mutex is assumed to be locked + */ + +OM_uint32 +_gss_DES3_get_mic_compat(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context) +{ + krb5_boolean use_compat = FALSE; + OM_uint32 ret; + + if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) { + ret = check_compat(minor_status, context, ctx->target, + "broken_des3_mic", &use_compat, TRUE); + if (ret) + return ret; + ret = check_compat(minor_status, context, ctx->target, + "correct_des3_mic", &use_compat, FALSE); + if (ret) + return ret; + + if (use_compat) + ctx->more_flags |= COMPAT_OLD_DES3; + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + } + return 0; +} + +#if 0 +OM_uint32 +gss_krb5_compat_des3_mic(OM_uint32 *minor_status, gss_ctx_id_t ctx, int on) +{ + *minor_status = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (on) { + ctx->more_flags |= COMPAT_OLD_DES3; + } else { + ctx->more_flags &= ~COMPAT_OLD_DES3; + } + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return 0; +} +#endif diff --git a/third_party/heimdal/lib/gssapi/krb5/context_time.c b/third_party/heimdal/lib/gssapi/krb5/context_time.c new file mode 100644 index 0000000..58249cb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/context_time.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 +_gsskrb5_lifetime_left(OM_uint32 *minor_status, + krb5_context context, + OM_uint32 endtime, + OM_uint32 *lifetime_rec) +{ + krb5_timestamp now; + krb5_error_code kret; + + if (endtime == 0) { + *lifetime_rec = GSS_C_INDEFINITE; + return GSS_S_COMPLETE; + } + + kret = krb5_timeofday(context, &now); + if (kret) { + *lifetime_rec = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (endtime < now) + *lifetime_rec = 0; + else + *lifetime_rec = endtime - now; + + return GSS_S_COMPLETE; +} + + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_context_time + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 * time_rec + ) +{ + krb5_context context; + OM_uint32 endtime; + OM_uint32 major_status; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + endtime = ctx->endtime; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + major_status = _gsskrb5_lifetime_left(minor_status, context, + endtime, time_rec); + if (major_status != GSS_S_COMPLETE) + return major_status; + + *minor_status = 0; + + if (*time_rec == 0) + return GSS_S_CONTEXT_EXPIRED; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c new file mode 100644 index 0000000..fc0b9b1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000 - 2001, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#if 0 +OM_uint32 +gss_krb5_copy_ccache(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t cred, + krb5_ccache out) +{ + krb5_error_code kret; + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (cred->ccache == NULL) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + kret = krb5_cc_copy_cache(context, cred->ccache, out); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} +#endif + + +/* + * WARNING: Takes ownership of `id'. Because MEMORY:anonymous is now not + * linked into to the MEMORY ccache namespace, we can't use krb5_cc_resolve() + * with the cache's name anymore. We need a krb5_cc_clone() or some such, with + * attendant new method for ccops. Or we could create a new MEMORY:anonymous + * ccache and copy all the creds from `id' into it. But we know callers of + * this function don't need `id' after calling it, so for now we'll just take + * ownershipd of it. + */ +OM_uint32 +_gsskrb5_krb5_import_cred(OM_uint32 *minor_status, + krb5_ccache *id, + krb5_principal keytab_principal, + krb5_keytab keytab, + gss_cred_id_t *cred) +{ + krb5_context context; + krb5_error_code kret; + gsskrb5_cred handle; + OM_uint32 ret; + int id_given = (*id != NULL); + + *cred = NULL; + + GSSAPI_KRB5_INIT (&context); + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + _gsskrb5_clear_status (); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + handle->usage = 0; + handle->destination_realm = NULL; + + if (*id) { + time_t now; + OM_uint32 left; + + handle->usage |= GSS_C_INITIATE; + + kret = krb5_cc_get_principal(context, *id, + &handle->principal); + if (kret) { + free(handle); + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (keytab_principal) { + krb5_boolean match; + + match = krb5_principal_compare(context, + handle->principal, + keytab_principal); + if (match == FALSE) { + krb5_free_principal(context, handle->principal); + free(handle); + _gsskrb5_clear_status (); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + krb5_timeofday(context, &now); + ret = __gsskrb5_ccache_lifetime(minor_status, + context, + *id, + handle->principal, + &left); + if (ret != GSS_S_COMPLETE) { + krb5_free_principal(context, handle->principal); + free(handle); + return ret; + } + handle->endtime = now + left; + + handle->ccache = *id; + *id = NULL; + } + + + if (keytab) { + char *str; + + handle->usage |= GSS_C_ACCEPT; + + if (keytab_principal && handle->principal == NULL) { + kret = krb5_copy_principal(context, + keytab_principal, + &handle->principal); + if (kret) + goto out; + } + + kret = krb5_kt_get_full_name(context, keytab, &str); + if (kret) + goto out; + + kret = krb5_kt_resolve(context, str, &handle->keytab); + free(str); + if (kret) + goto out; + } + + + if (id_given || keytab) { + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret != GSS_S_COMPLETE) { + kret = *minor_status; + goto out; + } + } + + *minor_status = 0; + *cred = (gss_cred_id_t)handle; + return GSS_S_COMPLETE; + +out: + gss_release_oid_set(minor_status, &handle->mechanisms); + if (handle->ccache) + krb5_cc_close(context, handle->ccache); + if (handle->keytab) + krb5_kt_close(context, handle->keytab); + if (handle->principal) + krb5_free_principal(context, handle->principal); + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + *minor_status = kret; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/creds.c b/third_party/heimdal/lib/gssapi/krb5/creds.c new file mode 100644 index 0000000..036d9fa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/creds.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_cred(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_buffer_t cred_token) +{ + OM_uint32 major_status; + gsskrb5_cred handle = (gsskrb5_cred)cred_handle; + krb5_context context; + krb5_error_code ret; + krb5_storage *sp; + krb5_data data; + const char *type; + char *str; + + GSSAPI_KRB5_INIT (&context); + + if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + type = krb5_cc_get_type(context, handle->ccache); + if (strcmp(type, "MEMORY") == 0) { + krb5_creds *creds; + krb5_data config_start_realm; + char *start_realm; + + ret = krb5_store_uint32(sp, 0); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_config(context, handle->ccache, NULL, "start_realm", + &config_start_realm); + if (ret == 0) { + start_realm = strndup(config_start_realm.data, + config_start_realm.length); + krb5_data_free(&config_start_realm); + } else { + start_realm = strdup(krb5_principal_get_realm(context, + handle->principal)); + } + if (start_realm == NULL) { + *minor_status = krb5_enomem(context); + krb5_storage_free(sp); + return GSS_S_FAILURE; + } + + ret = _krb5_get_krbtgt(context, handle->ccache, start_realm, &creds); + free(start_realm); + start_realm = NULL; + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_store_creds(sp, creds); + krb5_free_creds(context, creds); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + } else { + ret = krb5_store_uint32(sp, 1); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_full_name(context, handle->ccache, &str); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_store_string(sp, str); + free(str); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + } + ret = krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_data_free(&data); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = _gss_mg_store_oid(minor_status, sp, GSS_KRB5_MECHANISM); + if (major_status != GSS_S_COMPLETE) { + krb5_data_free(&data); + krb5_storage_free(sp); + return major_status; + } + + ret = krb5_store_data(sp, data); + krb5_data_free(&data); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cred_token->value = data.data; + cred_token->length = data.length; + + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_import_cred(OM_uint32 * minor_status, + gss_buffer_t cred_token, + gss_cred_id_t * cred_handle) +{ + krb5_context context; + krb5_error_code ret; + gsskrb5_cred handle; + krb5_ccache id; + krb5_storage *sp; + char *str; + uint32_t type; + int flags = 0; + + *cred_handle = GSS_C_NO_CREDENTIAL; + + GSSAPI_KRB5_INIT (&context); + + sp = krb5_storage_from_mem(cred_token->value, cred_token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = krb5_ret_uint32(sp, &type); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + switch (type) { + case 0: { + krb5_creds creds; + + ret = krb5_ret_creds(sp, &creds); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_initialize(context, id, creds.client); + if (ret) { + krb5_cc_destroy(context, id); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_store_cred(context, id, &creds); + krb5_free_cred_contents(context, &creds); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + break; + } + case 1: + ret = krb5_ret_string(sp, &str); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_resolve(context, str, &id); + krb5_xfree(str); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + break; + + default: + krb5_storage_free(sp); + *minor_status = 0; + return GSS_S_NO_CRED; + } + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + krb5_cc_close(context, id); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *minor_status = krb5_cc_get_principal(context, id, &handle->principal); + if (*minor_status) { + free(handle); + krb5_cc_close(context, id); + return GSS_S_FAILURE; + } + + handle->usage = GSS_C_INITIATE; + handle->destination_realm = NULL; + handle->ccache = id; + handle->cred_flags = flags; + + *cred_handle = (gss_cred_id_t)handle; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c new file mode 100644 index 0000000..d7b75a6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * return the length of the mechanism in token or -1 + * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN + */ + +ssize_t +_gsskrb5_get_mech (const u_char *ptr, + size_t total_len, + const u_char **mech_ret) +{ + size_t len, len_len, mech_len, foo; + const u_char *p = ptr; + int e; + + if (total_len < 1) + return -1; + if (*p++ != 0x60) + return -1; + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return -1; + if (total_len < 1 + len_len + 1) + return -1; + p += len_len; + if (*p++ != 0x06) + return -1; + e = der_get_length (p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return -1; + p += foo; + *mech_ret = p; + return mech_len; +} + +OM_uint32 +_gssapi_verify_mech_header(u_char **str, + size_t total_len, + gss_OID mech) +{ + const u_char *p; + ssize_t mech_len; + + mech_len = _gsskrb5_get_mech (*str, total_len, &p); + if (mech_len < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (mech_len != mech->length) + return GSS_S_BAD_MECH; + if (mech_len > total_len) + return GSS_S_BAD_MECH; + if (p - *str > total_len - mech_len) + return GSS_S_BAD_MECH; + if (ct_memcmp(p, + mech->elements, + mech->length) != 0) + return GSS_S_BAD_MECH; + p += mech_len; + *str = rk_UNCONST(p); + return GSS_S_COMPLETE; +} + +OM_uint32 +_gsskrb5_verify_header(u_char **str, + size_t total_len, + const void *type, + gss_OID oid) +{ + OM_uint32 ret; + size_t len; + u_char *p = *str; + + ret = _gssapi_verify_mech_header(str, total_len, oid); + if (ret) + return ret; + + len = total_len - (*str - p); + + if (len < 2) + return GSS_S_DEFECTIVE_TOKEN; + + if (ct_memcmp (*str, type, 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + *str += 2; + + return 0; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +_gssapi_decapsulate( + OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const gss_OID mech +) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = _gssapi_verify_mech_header(&p, + input_token_buffer->length, + mech); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +_gsskrb5_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const void *type, + gss_OID oid) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = _gsskrb5_verify_header(&p, + input_token_buffer->length, + type, + oid); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Verify padding of a gss wrapped message and return its length. + */ + +OM_uint32 +_gssapi_verify_pad(gss_buffer_t wrapped_token, + size_t datalen, + size_t *padlen) +{ + u_char *pad; + size_t padlength; + int i; + + if (wrapped_token->length < 1) + return GSS_S_BAD_MECH; + + pad = (u_char *)wrapped_token->value + wrapped_token->length; + padlength = pad[-1]; + + if (padlength > datalen) + return GSS_S_BAD_MECH; + + for (i = padlength; i > 0 && *--pad == padlength; i--) + ; + if (i != 0) + return GSS_S_BAD_MIC; + + *padlen = padlength; + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c new file mode 100644 index 0000000..a480079 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_delete_sec_context(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token) +{ + krb5_context context; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT (&context); + + *minor_status = 0; + + if (output_token) { + output_token->length = 0; + output_token->value = NULL; + } + + if (*context_handle == GSS_C_NO_CONTEXT) + return GSS_S_COMPLETE; + + ctx = (gsskrb5_ctx) *context_handle; + *context_handle = GSS_C_NO_CONTEXT; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + krb5_auth_con_free (context, ctx->auth_context); + krb5_auth_con_free (context, ctx->deleg_auth_context); + if (ctx->kcred) + krb5_free_creds(context, ctx->kcred); + if(ctx->source) + krb5_free_principal (context, ctx->source); + if(ctx->target) + krb5_free_principal (context, ctx->target); + if (ctx->ticket) + krb5_free_ticket (context, ctx->ticket); + if(ctx->order) + _gssapi_msg_order_destroy(&ctx->order); + if (ctx->service_keyblock) + krb5_free_keyblock (context, ctx->service_keyblock); + krb5_data_free(&ctx->fwd_data); + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + memset(ctx, 0, sizeof(*ctx)); + free (ctx); + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/display_name.c b/third_party/heimdal/lib/gssapi/krb5/display_name.c new file mode 100644 index 0000000..67cb61e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/display_name.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type + ) +{ + krb5_context context; + krb5_const_principal name = (krb5_const_principal)input_name; + krb5_error_code kret; + char *buf; + size_t len; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name_flags (context, name, + KRB5_PRINCIPAL_UNPARSE_DISPLAY, &buf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + len = strlen (buf); + output_name_buffer->length = len; + output_name_buffer->value = malloc(len + 1); + if (output_name_buffer->value == NULL) { + free (buf); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (output_name_buffer->value, buf, len); + ((char *)output_name_buffer->value)[len] = '\0'; + free (buf); + if (output_name_type) + *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/display_status.c b/third_party/heimdal/lib/gssapi/krb5/display_status.c new file mode 100644 index 0000000..cca5f67 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/display_status.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static const char * +calling_error(OM_uint32 v) +{ + static const char *msgs[] = { + NULL, /* 0 */ + "A required input parameter could not be read.", /* */ + "A required output parameter could not be written.", /* */ + "A parameter was malformed" + }; + + v >>= GSS_C_CALLING_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown calling error"; + else + return msgs[v]; +} + +static const char * +routine_error(OM_uint32 v) +{ + static const char *msgs[] = { + NULL, /* 0 */ + "An unsupported mechanism was requested", + "An invalid name was supplied", + "A supplied name was of an unsupported type", + "Incorrect channel bindings were supplied", + "An invalid status code was supplied", + "A token had an invalid MIC", + "No credentials were supplied, or the credentials were unavailable or inaccessible.", + "No context has been established", + "A token was invalid", + "A credential was invalid", + "The referenced credentials have expired", + "The context has expired", + "Miscellaneous failure (see text)", + "The quality-of-protection requested could not be provide", + "The operation is forbidden by local security policy", + "The operation or option is not available", + "The requested credential element already exists", + "The provided name was not a mechanism name.", + }; + + v >>= GSS_C_ROUTINE_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +static const char * +supplementary_error(OM_uint32 v) +{ + static const char *msgs[] = { + "normal completion", + "continuation call to routine required", + "duplicate per-message token detected", + "timed-out per-message token detected", + "reordered (early) per-message token detected", + "skipped predecessor token(s) detected" + }; + + v >>= GSS_C_SUPPLEMENTARY_OFFSET; + + if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +void +_gsskrb5_clear_status (void) +{ + krb5_context context; + + if (_gsskrb5_init (&context) != 0) + return; + krb5_clear_error_message(context); +} + +void +_gsskrb5_set_status (int ret, const char *fmt, ...) +{ + krb5_context context; + va_list args; + char *str; + int e; + + if (_gsskrb5_init (&context) != 0) + return; + + va_start(args, fmt); + e = vasprintf(&str, fmt, args); + va_end(args); + if (e >= 0 && str) { + krb5_set_error_message(context, ret, "%s", str); + free(str); + } +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_status +(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + krb5_context context; + char *buf = NULL; + int e = 0; + + GSSAPI_KRB5_INIT (&context); + + status_string->length = 0; + status_string->value = NULL; + + if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && + gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + if (status_type == GSS_C_GSS_CODE) { + if (GSS_SUPPLEMENTARY_INFO(status_value)) + e = asprintf(&buf, "%s", + supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value))); + else + e = asprintf (&buf, "%s %s", + calling_error(GSS_CALLING_ERROR(status_value)), + routine_error(GSS_ROUTINE_ERROR(status_value))); + } else if (status_type == GSS_C_MECH_CODE) { + const char *buf2 = krb5_get_error_message(context, status_value); + if (buf2) { + buf = strdup(buf2); + krb5_free_error_message(context, buf2); + } else { + e = asprintf(&buf, "unknown mech error-code %u", + (unsigned)status_value); + } + } else { + *minor_status = EINVAL; + return GSS_S_BAD_STATUS; + } + + if (e < 0 || buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *message_context = 0; + *minor_status = 0; + + status_string->length = strlen(buf); + status_string->value = buf; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c b/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c new file mode 100644 index 0000000..a44ec3b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_cred ( + OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + krb5_context context; + gsskrb5_cred cred, dup; + OM_uint32 major, junk; + + dup = NULL; + + if (output_cred_handle == NULL) { + *minor_status = EINVAL; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + GSSAPI_KRB5_INIT (&context); + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + /* Duplicate the default credential */ + return _gsskrb5_acquire_cred_from(minor_status, GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_BOTH, + GSS_C_NO_CRED_STORE, + output_cred_handle, + NULL, NULL); + } + + /* Duplicate the input credential */ + + dup = calloc(1, sizeof(*dup)); + if (dup == NULL) { + *minor_status = krb5_enomem(context); + return (GSS_S_FAILURE); + } + + *output_cred_handle = (gss_cred_id_t)dup; /* making sure to release on error */ + + cred = (gsskrb5_cred)input_cred_handle; + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + dup->destination_realm = NULL; + dup->usage = cred->usage; + dup->endtime = cred->endtime; + dup->principal = NULL; + dup->keytab = NULL; + dup->ccache = NULL; + dup->mechanisms = NULL; + + major = GSS_S_FAILURE; + + HEIMDAL_MUTEX_init(&dup->cred_id_mutex); + if (cred->destination_realm && + (dup->destination_realm = strdup(cred->destination_realm)) == NULL) { + *minor_status = krb5_enomem(context); + goto fail; + } + *minor_status = krb5_copy_principal(context, cred->principal, + &dup->principal); + if (*minor_status) + goto fail; + + if (cred->keytab) { + char *name = NULL; + + *minor_status = krb5_kt_get_full_name(context, cred->keytab, &name); + if (*minor_status) + goto fail; + *minor_status = krb5_kt_resolve(context, name, &dup->keytab); + krb5_xfree(name); + if (*minor_status) + goto fail; + } + + if (cred->ccache) { + const char *type, *name; + char *type_name = NULL; + + type = krb5_cc_get_type(context, cred->ccache); /* can't fail */ + if (strcmp(type, "MEMORY") == 0) { + *minor_status = krb5_cc_new_unique(context, type, NULL, + &dup->ccache); + if (*minor_status) + goto fail; + + *minor_status = krb5_cc_copy_cache(context, cred->ccache, + dup->ccache); + if (*minor_status) + goto fail; + + } else { + name = krb5_cc_get_name(context, cred->ccache); + if (name == NULL) { + *minor_status = ENOMEM; + goto fail; + } + + if (asprintf(&type_name, "%s:%s", type, name) == -1 || + type_name == NULL) { + *minor_status = ENOMEM; + goto fail; + } + + *minor_status = krb5_cc_resolve(context, type_name, + &dup->ccache); + free(type_name); + if (*minor_status) + goto fail; + } + } + + major = gss_create_empty_oid_set(minor_status, &dup->mechanisms); + if (major != GSS_S_COMPLETE) + goto fail; + + major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &dup->mechanisms); + if (major != GSS_S_COMPLETE) + goto fail; + + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *output_cred_handle = (gss_cred_id_t)dup; + *minor_status = 0; + return major; + +fail: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *output_cred_handle = (gss_cred_id_t)dup; + _gsskrb5_release_cred(&junk, output_cred_handle); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c b/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c new file mode 100644 index 0000000..43519d6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_name ( + OM_uint32 * minor_status, + gss_const_name_t src_name, + gss_name_t * dest_name + ) +{ + krb5_const_principal src = (krb5_const_principal)src_name; + krb5_context context; + krb5_principal dest; + krb5_error_code kret; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_copy_principal (context, src, &dest); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } else { + *dest_name = (gss_name_t)dest; + *minor_status = 0; + return GSS_S_COMPLETE; + } +} diff --git a/third_party/heimdal/lib/gssapi/krb5/encapsulate.c b/third_party/heimdal/lib/gssapi/krb5/encapsulate.c new file mode 100644 index 0000000..3b390ce --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/encapsulate.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +void +_gssapi_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + size_t len_len; + + *len = 1 + 1 + mech->length + data_len; + + len_len = der_length_len(*len); + + *total_len = 1 + len_len + *len; +} + +void +_gsskrb5_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + _gssapi_encap_length(data_len + 2, len, total_len, mech); +} + +void * +_gssapi_make_mech_header(void *ptr, + size_t len, + const gss_OID mech) +{ + u_char *p = ptr; + int e; + size_t len_len, foo; + + *p++ = 0x60; + len_len = der_length_len(len); + e = der_put_length (p + len_len - 1, len_len, len, &foo); + if(e || foo != len_len) + abort (); + p += len_len; + *p++ = 0x06; + *p++ = mech->length; + memcpy (p, mech->elements, mech->length); + p += mech->length; + return p; +} + +void * +_gsskrb5_make_header (void *ptr, + size_t len, + const void *type, + const gss_OID mech) +{ + u_char *p = ptr; + p = _gssapi_make_mech_header(p, len, mech); + memcpy (p, type, 2); + p += 2; + return p; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. + */ + +OM_uint32 +_gssapi_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const gss_OID mech +) +{ + size_t len, outer_len; + void *p; + + _gssapi_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gssapi_make_mech_header (output_token->value, len, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API krb5 + * wrappings. + */ + +OM_uint32 +_gsskrb5_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const void *type, + const gss_OID mech +) +{ + size_t len, outer_len; + u_char *p; + + _gsskrb5_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header (output_token->value, len, type, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/export_name.c b/third_party/heimdal/lib/gssapi/krb5/export_name.c new file mode 100644 index 0000000..1686a65 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/export_name.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997, 1999, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_export_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name + ) +{ + krb5_context context; + krb5_const_principal princ = (krb5_const_principal)input_name; + krb5_error_code kret; + char *buf, *name; + size_t len; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name (context, princ, &name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + len = strlen (name); + + exported_name->length = 10 + len + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + free (name); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + memcpy(buf, "\x04\x01", 2); + buf += 2; + buf[0] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[1] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf+= 2; + buf[0] = 0x06; + buf[1] = (GSS_KRB5_MECHANISM->length) & 0xFF; + buf+= 2; + + memcpy(buf, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += GSS_KRB5_MECHANISM->length; + + buf[0] = (len >> 24) & 0xff; + buf[1] = (len >> 16) & 0xff; + buf[2] = (len >> 8) & 0xff; + buf[3] = (len) & 0xff; + buf += 4; + + memcpy (buf, name, len); + + free (name); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c new file mode 100644 index 0000000..c298415 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token + ) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle; + krb5_storage *sp; + krb5_auth_context ac; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data data; + int flags; + OM_uint32 minor; + krb5_error_code kret; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (!(ctx->flags & GSS_C_TRANS_FLAG)) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + sp = krb5_storage_emem (); + if (sp == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ac = ctx->auth_context; + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + krb5_storage_set_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE); + + /* flagging included fields */ + + flags = 0; + if (ac->local_address) + flags |= SC_LOCAL_ADDRESS; + if (ac->remote_address) + flags |= SC_REMOTE_ADDRESS; + if (ac->keyblock) + flags |= SC_KEYBLOCK; + if (ac->local_subkey) + flags |= SC_LOCAL_SUBKEY; + if (ac->remote_subkey) + flags |= SC_REMOTE_SUBKEY; + if (ac->authenticator) + flags |= SC_AUTHENTICATOR; + if (ctx->source) + flags |= SC_SOURCE_NAME; + if (ctx->target) + flags |= SC_TARGET_NAME; + if (ctx->order) + flags |= SC_ORDER; + + kret = krb5_store_int32 (sp, flags); + if (kret) { + *minor_status = kret; + goto failure; + } + + /* marshall auth context */ + + kret = krb5_store_int32 (sp, ac->flags); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->local_address) { + kret = krb5_store_address (sp, *ac->local_address); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->remote_address) { + kret = krb5_store_address (sp, *ac->remote_address); + if (kret) { + *minor_status = kret; + goto failure; + } + } + kret = krb5_store_int16 (sp, ac->local_port); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int16 (sp, ac->remote_port); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->keyblock) { + kret = krb5_store_keyblock (sp, *ac->keyblock); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->local_subkey) { + kret = krb5_store_keyblock (sp, *ac->local_subkey); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->remote_subkey) { + kret = krb5_store_keyblock (sp, *ac->remote_subkey); + if (kret) { + *minor_status = kret; + goto failure; + } + } + kret = krb5_store_int32 (sp, ac->local_seqnumber); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ac->remote_seqnumber); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->authenticator) { + kret = krb5_store_int64(sp, ac->authenticator->ctime); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32(sp, ac->authenticator->cusec); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_store_int32 (sp, ac->keytype); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ac->cksumtype); + if (kret) { + *minor_status = kret; + goto failure; + } + + /* names */ + if (ctx->source) { + kret = krb5_store_principal(sp, ctx->source); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + if (ctx->target) { + kret = krb5_store_principal(sp, ctx->target); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_store_int32 (sp, ctx->flags); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ctx->more_flags); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ctx->state); + if (kret) { + *minor_status = kret; + goto failure; + } + /* + * XXX We should put a 64-bit int here, but we don't have a + * krb5_store_int64() yet. + */ + kret = krb5_store_int32 (sp, ctx->endtime); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ctx->order) { + kret = _gssapi_msg_order_export(sp, ctx->order); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_storage_to_data (sp, &data); + krb5_storage_free (sp); + if (kret) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = kret; + return GSS_S_FAILURE; + } + interprocess_token->length = data.length; + interprocess_token->value = data.data; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + ret = _gsskrb5_delete_sec_context (minor_status, context_handle, + GSS_C_NO_BUFFER); + if (ret != GSS_S_COMPLETE) + _gss_secure_release_buffer (&minor, interprocess_token); + *minor_status = 0; + return ret; + failure: + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + krb5_storage_free (sp); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/external.c b/third_party/heimdal/lib/gssapi/krb5/external.c new file mode 100644 index 0000000..e58df18 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/external.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1997 - 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_user_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x01")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_machine_uid_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x02")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_string_uid_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x03")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_hostbased_service_x_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x02")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_hostbased_service_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x04")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_anonymous_oid_desc = + {6, rk_UNCONST("\x2b\x06\01\x05\x06\x03")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_export_name_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x04") }; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * krb5(2) krb5_name(1)}. The recommended symbolic name for this type + * is "GSS_KRB5_NT_PRINCIPAL_NAME". + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01") }; + +/* + * GSS_C_NT_COMPOSITE_EXPORT [RFC6680], OID {iso(1) identified-organization(3) + * dod(6) internet(1) security(5) nametypes(6) gss-composite-export(6)}. + */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_composite_export_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x06")}; + +/* + * draft-ietf-cat-iakerb-09, IAKERB: + * The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance + * with the mechanism proposed by SPNEGO [7] for negotiating protocol + * variations, is: {iso(1) org(3) dod(6) internet(1) security(5) + * mechanisms(5) iakerb(10) iakerbProxyProtocol(1)}. The proposed + * mechanism ID for IAKERB minimum messages GSS-API Kerberos, in + * accordance with the mechanism proposed by SPNEGO for negotiating + * protocol variations, is: {iso(1) org(3) dod(6) internet(1) + * security(5) mechanisms(5) iakerb(10) + * iakerbMinimumMessagesProtocol(2)}. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_iakerb_proxy_mechanism_oid_desc = + {7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0a\x01")}; + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_iakerb_min_msg_mechanism_oid_desc = + {7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0a\x02") }; + +/* + * Context for krb5 calls. + */ + +static gss_mo_desc krb5_mo[] = { + { + GSS_C_MA_SASL_MECH_NAME, + GSS_MO_MA, + "SASL mech name", + rk_UNCONST("GS2-KRB5"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_NAME, + GSS_MO_MA, + "Mechanism name", + rk_UNCONST("KRB5"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_DESCRIPTION, + GSS_MO_MA, + "Mechanism description", + rk_UNCONST("Heimdal Kerberos 5 mech"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_CONCRETE, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_ITOK_FRAMED, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_INIT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_TARG, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_DELEG_CRED, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_INTEG_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CONF_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_MIC, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_WRAP, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_PROT_READY, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_REPLAY_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_OOS_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CBINDINGS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_PFS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CTX_TRANS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + } +}; + +/* + * + */ + +static gssapi_mech_interface_desc krb5_mech = { + GMI_VERSION, + "krb5", + {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }, + 0, + NULL, /* gm_acquire_cred */ + _gsskrb5_release_cred, + _gsskrb5_init_sec_context, + _gsskrb5_accept_sec_context, + _gsskrb5_process_context_token, + _gsskrb5_delete_sec_context, + _gsskrb5_context_time, + _gsskrb5_get_mic, + _gsskrb5_verify_mic, + _gsskrb5_wrap, + _gsskrb5_unwrap, + _gsskrb5_display_status, + _gsskrb5_indicate_mechs, + _gsskrb5_compare_name, + _gsskrb5_display_name, + _gsskrb5_import_name, + _gsskrb5_export_name, + _gsskrb5_release_name, + _gsskrb5_inquire_cred, + _gsskrb5_inquire_context, + _gsskrb5_wrap_size_limit, + NULL, /* gm_add_cred */ + _gsskrb5_inquire_cred_by_mech, + _gsskrb5_export_sec_context, + _gsskrb5_import_sec_context, + _gsskrb5_inquire_names_for_mech, + _gsskrb5_inquire_mechs_for_name, + _gsskrb5_canonicalize_name, + _gsskrb5_duplicate_name, + _gsskrb5_inquire_sec_context_by_oid, + _gsskrb5_inquire_cred_by_oid, + _gsskrb5_set_sec_context_option, + _gsskrb5_set_cred_option, + _gsskrb5_pseudo_random, + _gk_wrap_iov, + _gk_unwrap_iov, + _gk_wrap_iov_length, + NULL, /* gm_store_cred */ + _gsskrb5_export_cred, + _gsskrb5_import_cred, + _gsskrb5_acquire_cred_from, + NULL, /* gm_acquire_cred_impersonate_name */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + krb5_mo, + sizeof(krb5_mo) / sizeof(krb5_mo[0]), + _gsskrb5_localname, + _gsskrb5_authorize_localname, + _gsskrb5_display_name_ext, + _gsskrb5_inquire_name, + _gsskrb5_get_name_attribute, + _gsskrb5_set_name_attribute, + _gsskrb5_delete_name_attribute, + _gsskrb5_export_name_composite, + _gsskrb5_duplicate_cred, + _gsskrb5_add_cred_from, + _gsskrb5_store_cred_into, + NULL, /* gm_query_mechanism_info */ + NULL, /* gm_query_meta_data */ + NULL, /* gm_exchange_meta_data */ + _gsskrb5_store_cred_into2, + NULL /* gm_compat */ +}; + +gssapi_mech_interface +__gss_krb5_initialize(void) +{ + return &krb5_mech; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/get_mic.c b/third_party/heimdal/lib/gssapi/krb5/get_mic.c new file mode 100644 index 0000000..d9cf9d7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/get_mic.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +mic_des + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16]; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock deskey; + DES_cblock zero; + int32_t seq_number; + size_t len, total_len; + + _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x00\x00", 2); /* SGN_ALG = DES MAC MD5 */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */ + p += 4; + + /* Fill in later (SND-SEQ) */ + memset (p, 0, 16); + p += 16; + + /* checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); /* SGN_CKSUM */ + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + p -= 16; /* SND_SEQ */ + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +mic_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + Checksum cksum; + u_char seq[8]; + + int32_t seq_number; + size_t len, total_len; + + krb5_crypto crypto; + krb5_error_code kret; + krb5_data encdata; + char *tmp; + char ivec[8]; + + _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK-ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x04\x00", 2); /* SGN_ALG = HMAC SHA1 DES3-KD */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* filler */ + p += 4; + + /* this should be done in parts */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + kret = krb5_crypto_init(context, key, 0, &crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + free (tmp); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_create_checksum (context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + tmp, + message_buffer->length + 8, + &cksum); + free (tmp); + krb5_crypto_destroy (context, crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + kret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (ctx->more_flags & COMPAT_OLD_DES3) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + kret = krb5_encrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, ivec); + krb5_crypto_destroy (context, crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + free_Checksum (&cksum); + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_keyblock *key; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_mic_cfx (minor_status, ctx, context, qop_req, + message_buffer, message_token); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : +#ifdef HEIM_WEAK_CRYPTO + ret = mic_des (minor_status, ctx, context, qop_req, + message_buffer, message_token, key); +#else + ret = GSS_S_FAILURE; +#endif + break; + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : + ret = mic_des3 (minor_status, ctx, context, qop_req, + message_buffer, message_token, key); + break; + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: + ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req, + message_buffer, message_token, key); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et b/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et new file mode 100644 index 0000000..109876e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et @@ -0,0 +1,33 @@ +# +# extended gss krb5 error messages +# + +id "$Id$" + +error_table gk5 + +prefix GSS_KRB5_S + +error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string" +error_code G_BAD_STRING_UID, "STRING-UID-NAME contains nondigits" +error_code G_NOUSER, "UID does not resolve to username" +error_code G_VALIDATE_FAILED, "Validation error" +error_code G_BUFFER_ALLOC, "Couldn't allocate gss_buffer_t data" +error_code G_BAD_MSG_CTX, "Message context invalid" +error_code G_WRONG_SIZE, "Buffer is the wrong size" +error_code G_BAD_USAGE, "Credential usage type is unknown" +error_code G_UNKNOWN_QOP, "Unknown quality of protection specified" +error_code G_UNKNOWN_CRED_STORE_ELEMENT, "Credential store contained unknown elements" +error_code G_BAD_PASSWORD_CRED_STORE, "Credential store cannot contain both a password and a credentials cache or client keytab" + +index 128 + +error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name" +error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name" +error_code KG_TGT_MISSING, "Credential cache has no TGT" +error_code KG_NO_SUBKEY, "Authenticator has no subkey" +error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established" +error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token" +error_code KG_BAD_LENGTH, "Invalid field length in token" +error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context" +error_code KG_INPUT_TOO_LONG, "Input too long" diff --git a/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h new file mode 100644 index 0000000..fbbb168 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef GSSKRB5_LOCL_H +#define GSSKRB5_LOCL_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "cfx.h" + +/* + * + */ + +struct gss_msg_order; + +typedef struct gsskrb5_ctx { + struct krb5_auth_context_data *auth_context; + struct krb5_auth_context_data *deleg_auth_context; + krb5_principal source, target; + OM_uint32 flags; + enum { LOCAL = 1, OPEN = 2, + COMPAT_OLD_DES3 = 4, + COMPAT_OLD_DES3_SELECTED = 8, + ACCEPTOR_SUBKEY = 16, + RETRIED = 32, + CLOSE_CCACHE = 64, + IS_CFX = 128 + } more_flags; + enum gss_ctx_id_t_state { + /* initiator states */ + INITIATOR_START, + INITIATOR_RESTART, + INITIATOR_WAIT_FOR_MUTUAL, + INITIATOR_READY, + /* acceptor states */ + ACCEPTOR_START, + ACCEPTOR_WAIT_FOR_DCESTYLE, + ACCEPTOR_READY + } state; + krb5_creds *kcred; + krb5_ccache ccache; + struct krb5_ticket *ticket; + time_t endtime; + HEIMDAL_MUTEX ctx_id_mutex; + struct gss_msg_order *order; + krb5_keyblock *service_keyblock; + krb5_data fwd_data; + krb5_crypto crypto; +} *gsskrb5_ctx; + +static inline krb5_boolean +IS_DCE_STYLE(gsskrb5_ctx ctx) +{ + return (ctx->flags & GSS_C_DCE_STYLE) != 0; +} + +typedef struct { + krb5_principal principal; + char *destination_realm; /* Realm of acceptor service, if delegated */ + int cred_flags; +#define GSS_CF_DESTROY_CRED_ON_RELEASE 1 +#define GSS_CF_NO_CI_FLAGS 2 + struct krb5_keytab_data *keytab; + time_t endtime; + gss_cred_usage_t usage; + gss_OID_set mechanisms; + struct krb5_ccache_data *ccache; + HEIMDAL_MUTEX cred_id_mutex; + krb5_enctype *enctypes; +} *gsskrb5_cred; + +typedef struct Principal *gsskrb5_name; + +/* + * + */ + +extern krb5_keytab _gsskrb5_keytab; +extern HEIMDAL_MUTEX gssapi_keytab_mutex; + +/* + * Prototypes + */ + +#include "krb5/gsskrb5-private.h" + +#define GSSAPI_KRB5_INIT(ctx) do { \ + krb5_error_code kret_gss_init; \ + if((kret_gss_init = _gsskrb5_init (ctx)) != 0) { \ + *minor_status = kret_gss_init; \ + return GSS_S_FAILURE; \ + } \ +} while (0) + +/* sec_context flags */ + +#define SC_LOCAL_ADDRESS 0x0001 +#define SC_REMOTE_ADDRESS 0x0002 +#define SC_KEYBLOCK 0x0004 +#define SC_LOCAL_SUBKEY 0x0008 +#define SC_REMOTE_SUBKEY 0x0010 +#define SC_SOURCE_NAME 0x0020 +#define SC_TARGET_NAME 0x0040 +#define SC_ORDER 0x0080 +#define SC_AUTHENTICATOR 0x0100 + +struct gsskrb5_ccache_name_args { + const char *name; + const char *out_name; +}; + +#endif diff --git a/third_party/heimdal/lib/gssapi/krb5/import_name.c b/third_party/heimdal/lib/gssapi/krb5/import_name.c new file mode 100644 index 0000000..f4ee231 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/import_name.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static OM_uint32 +parse_krb5_name (OM_uint32 *minor_status, + krb5_context context, + const char *name, + gss_name_t *output_name) +{ + krb5_principal princ; + krb5_error_code kerr; + + kerr = krb5_parse_name (context, name, &princ); + + if (kerr == 0) { + *output_name = (gss_name_t)princ; + return GSS_S_COMPLETE; + } + *minor_status = kerr; + + if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) + return GSS_S_BAD_NAME; + + return GSS_S_FAILURE; +} + +static OM_uint32 +import_krb5_name (OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + OM_uint32 ret; + char *tmp; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + ret = parse_krb5_name(minor_status, context, tmp, output_name); + free(tmp); + + return ret; +} + +OM_uint32 +_gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, + gss_const_name_t targetname, krb5_principal *out) +{ + krb5_const_principal p = (krb5_const_principal)targetname; + krb5_error_code ret; + char *hostname = NULL, *service; + int type; + const char *comp; + + *minor_status = 0; + + /* If its not a hostname */ + type = krb5_principal_get_type(context, p); + comp = krb5_principal_get_comp_string(context, p, 0); + if (type == KRB5_NT_SRV_HST || type == KRB5_NT_SRV_HST_NEEDS_CANON || + (type == KRB5_NT_UNKNOWN && comp != NULL && strcmp(comp, "host") == 0)) { + if (p->name.name_string.len == 0) + return GSS_S_BAD_NAME; + else if (p->name.name_string.len > 1) + hostname = p->name.name_string.val[1]; + + service = p->name.name_string.val[0]; + + ret = krb5_sname_to_principal(context, + hostname, + service, + KRB5_NT_SRV_HST, + out); + if (ret == 0) { + const char *in_realm = krb5_principal_get_realm(context, + p); + const char *out_realm = krb5_principal_get_realm(context, + *out); + + /* + * Avoid loss of information, check for the "referral + * realm" and set back what was specified. + */ + if (out_realm != NULL && out_realm[0] == '\0') { + ret = krb5_principal_set_realm(context, *out, in_realm); + } + } + } else { + ret = krb5_copy_principal(context, p, out); + } + + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + return 0; +} + + +static OM_uint32 +import_hostbased_name(OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + krb5_principal princ = NULL; + krb5_error_code kerr; + char *tmp, *p, *host = NULL; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + p = strchr (tmp, '@'); + if (p != NULL) { + *p = '\0'; + host = p + 1; + } + + kerr = krb5_make_principal(context, &princ, "", tmp, host, NULL); + free (tmp); + *minor_status = kerr; + if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) + return GSS_S_BAD_NAME; + else if (kerr) + return GSS_S_FAILURE; + + krb5_principal_set_type(context, princ, KRB5_NT_SRV_HST); + *output_name = (gss_name_t)princ; + + return 0; +} + +static OM_uint32 +import_export_name (OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + CompositePrincipal *composite; + unsigned char *p; + uint32_t length; + size_t sz; + OM_uint32 ret; + int is_composite; + char *name; + + if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + p = input_name_buffer->value; + + if (p[0] != 0x04 || + (p[1] != 0x01 && p[1] != 0x02) || + p[2] != 0x00 || + p[3] != GSS_KRB5_MECHANISM->length + 2 || + p[4] != 0x06 || + p[5] != GSS_KRB5_MECHANISM->length || + memcmp(&p[6], GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length) != 0) + return GSS_S_BAD_NAME; + + is_composite = p[1] == 0x02; + + p += 6 + GSS_KRB5_MECHANISM->length; + + length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + + if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + if (is_composite) { + if ((composite = calloc(1, sizeof(*composite))) == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = decode_CompositePrincipal(p, length, composite, &sz); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + if (sz != length) { + free_CompositePrincipal(composite); + free(composite); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + *output_name = (void *)composite; + return GSS_S_COMPLETE; + } + + name = malloc(length + 1); + if (name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(name, p, length); + name[length] = '\0'; + + ret = parse_krb5_name(minor_status, context, name, output_name); + free(name); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name + (OM_uint32 * minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t * output_name + ) +{ + krb5_context context; + + *minor_status = 0; + *output_name = GSS_C_NO_NAME; + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) || + gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X)) + return import_hostbased_name (minor_status, + context, + input_name_buffer, + output_name); + else if (input_name_type == GSS_C_NO_OID + || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME) + || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) + /* default printable syntax */ + return import_krb5_name (minor_status, + context, + input_name_buffer, + output_name); + else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) { + return import_export_name(minor_status, + context, + input_name_buffer, + output_name); + } else { + *minor_status = 0; + return GSS_S_BAD_NAMETYPE; + } +} diff --git a/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c new file mode 100644 index 0000000..2255a71 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_import_sec_context ( + OM_uint32 * minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t * context_handle + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_context context; + krb5_error_code kret; + krb5_storage *sp; + krb5_auth_context ac; + krb5_address local, remote; + krb5_address *localp, *remotep; + krb5_keyblock keyblock; + int32_t flags, tmp; + int64_t tmp64; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT (&context); + + *context_handle = GSS_C_NO_CONTEXT; + + localp = remotep = NULL; + + sp = krb5_storage_from_mem (interprocess_token->value, + interprocess_token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + krb5_storage_set_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + krb5_storage_free (sp); + return GSS_S_FAILURE; + } + HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); + + kret = krb5_auth_con_init (context, + &ctx->auth_context); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + /* flags */ + + *minor_status = 0; + + if (krb5_ret_int32 (sp, &flags) != 0) + goto failure; + + /* retrieve the auth context */ + + ac = ctx->auth_context; + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->flags = tmp; + if (flags & SC_LOCAL_ADDRESS) { + if (krb5_ret_address (sp, localp = &local) != 0) + goto failure; + } + + if (flags & SC_REMOTE_ADDRESS) { + if (krb5_ret_address (sp, remotep = &remote) != 0) + goto failure; + } + + krb5_auth_con_setaddrs (context, ac, localp, remotep); + if (localp) + krb5_free_address (context, localp); + if (remotep) + krb5_free_address (context, remotep); + localp = remotep = NULL; + + if (krb5_ret_int16 (sp, &ac->local_port) != 0) + goto failure; + + if (krb5_ret_int16 (sp, &ac->remote_port) != 0) + goto failure; + if (flags & SC_KEYBLOCK) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (flags & SC_LOCAL_SUBKEY) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setlocalsubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (flags & SC_REMOTE_SUBKEY) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setremotesubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) + goto failure; + if (krb5_ret_uint32 (sp, &ac->remote_seqnumber)) + goto failure; + + if (flags & SC_AUTHENTICATOR) { + if (krb5_ret_int64(sp, &tmp64)) + goto failure; + ac->authenticator->ctime = tmp64; + if (krb5_ret_int32(sp, &tmp)) + goto failure; + ac->authenticator->cusec = tmp; + } + + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->keytype = tmp; + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->cksumtype = tmp; + + /* names */ + if (flags & SC_SOURCE_NAME) { + if (krb5_ret_principal(sp, &ctx->source)) + goto failure; + } + + if (flags & SC_TARGET_NAME) { + if (krb5_ret_principal(sp, &ctx->target)) + goto failure; + } + + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->flags = tmp; + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->more_flags = tmp; + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->state = tmp; + /* + * XXX endtime should be a 64-bit int, but we don't have + * krb5_ret_int64() yet. + */ + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->endtime = tmp; + + if (flags & SC_ORDER) { + ret = _gssapi_msg_order_import(minor_status, sp, &ctx->order); + if (ret) + goto failure; + } + + krb5_storage_free (sp); + + _gsskrb5i_is_cfx(context, ctx, (ctx->more_flags & LOCAL) == 0); + + *context_handle = (gss_ctx_id_t)ctx; + + return GSS_S_COMPLETE; + +failure: + krb5_auth_con_free (context, + ctx->auth_context); + if (ctx->source != NULL) + krb5_free_principal(context, ctx->source); + if (ctx->target != NULL) + krb5_free_principal(context, ctx->target); + if (localp) + krb5_free_address (context, localp); + if (remotep) + krb5_free_address (context, remotep); + if(ctx->order) + _gssapi_msg_order_destroy(&ctx->order); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + krb5_storage_free (sp); + free (ctx); + *context_handle = GSS_C_NO_CONTEXT; + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c b/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c new file mode 100644 index 0000000..6201378 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_indicate_mechs + (OM_uint32 * minor_status, + gss_OID_set * mech_set + ) +{ + OM_uint32 ret, junk; + + ret = gss_create_empty_oid_set(minor_status, mech_set); + if (ret) + return ret; + + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, mech_set); + if (ret) { + gss_release_oid_set(&junk, mech_set); + return ret; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/init.c b/third_party/heimdal/lib/gssapi/krb5/init.c new file mode 100644 index 0000000..325b2c4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/init.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1997 - 2001, 2003, 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; +static int created_key; +static HEIMDAL_thread_key context_key; + +static void +destroy_context(void *ptr) +{ + krb5_context context = ptr; + + if (context == NULL) + return; + krb5_free_context(context); +} + +krb5_error_code +_gsskrb5_init (krb5_context *context) +{ + krb5_error_code ret = 0; + + HEIMDAL_MUTEX_lock(&context_mutex); + + if (!created_key) { + HEIMDAL_key_create(&context_key, destroy_context, ret); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_mutex); + return ret; + } + created_key = 1; + } + HEIMDAL_MUTEX_unlock(&context_mutex); + + *context = HEIMDAL_getspecific(context_key); + if (*context == NULL) { + + ret = krb5_init_context(context); + if (ret == 0) { + krb5_add_et_list(*context, initialize_gk5_error_table_r); + HEIMDAL_setspecific(context_key, *context, ret); + if (ret) { + krb5_free_context(*context); + *context = NULL; + } + } + } + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c new file mode 100644 index 0000000..7749fc6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *, + krb5_context, + krb5_auth_context, + gss_const_name_t); + +/* + * copy the addresses from `input_chan_bindings' (if any) to + * the auth context `ac' + */ + +static OM_uint32 +set_addresses (krb5_context context, + krb5_auth_context ac, + const gss_channel_bindings_t input_chan_bindings) +{ + /* Port numbers are expected to be in application_data.value, + * initator's port first */ + + krb5_address initiator_addr, acceptor_addr; + krb5_error_code kret; + + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS + || input_chan_bindings->application_data.length != + 2 * sizeof(ac->local_port)) + return 0; + + memset(&initiator_addr, 0, sizeof(initiator_addr)); + memset(&acceptor_addr, 0, sizeof(acceptor_addr)); + + ac->local_port = + *(int16_t *) input_chan_bindings->application_data.value; + + ac->remote_port = + *((int16_t *) input_chan_bindings->application_data.value + 1); + + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->acceptor_addrtype, + &input_chan_bindings->acceptor_address, + ac->remote_port, + &acceptor_addr); + if (kret) + return kret; + + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->initiator_addrtype, + &input_chan_bindings->initiator_address, + ac->local_port, + &initiator_addr); + if (kret) { + krb5_free_address (context, &acceptor_addr); + return kret; + } + + kret = krb5_auth_con_setaddrs(context, + ac, + &initiator_addr, /* local address */ + &acceptor_addr); /* remote address */ + + krb5_free_address (context, &initiator_addr); + krb5_free_address (context, &acceptor_addr); + +#if 0 + free(input_chan_bindings->application_data.value); + input_chan_bindings->application_data.value = NULL; + input_chan_bindings->application_data.length = 0; +#endif + + return kret; +} + +OM_uint32 +_gsskrb5_create_ctx( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + krb5_context context, + const gss_channel_bindings_t input_chan_bindings, + enum gss_ctx_id_t_state state) +{ + krb5_error_code kret; + gsskrb5_ctx ctx; + + *context_handle = NULL; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ctx->auth_context = NULL; + ctx->deleg_auth_context = NULL; + ctx->source = NULL; + ctx->target = NULL; + ctx->kcred = NULL; + ctx->ccache = NULL; + ctx->state = state; + ctx->flags = 0; + ctx->more_flags = 0; + ctx->service_keyblock = NULL; + ctx->ticket = NULL; + krb5_data_zero(&ctx->fwd_data); + ctx->endtime = 0; + ctx->order = NULL; + ctx->crypto = NULL; + HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); + + kret = krb5_auth_con_init (context, &ctx->auth_context); + if (kret) { + *minor_status = kret; + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_init (context, &ctx->deleg_auth_context); + if (kret) { + *minor_status = kret; + krb5_auth_con_free(context, ctx->auth_context); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_FAILURE; + } + + kret = set_addresses(context, ctx->auth_context, input_chan_bindings); + if (kret) { + *minor_status = kret; + + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_BAD_BINDINGS; + } + + kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings); + if (kret) { + *minor_status = kret; + + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_BAD_BINDINGS; + } + + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE | + KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, + NULL); + + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(context, + ctx->deleg_auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE | + KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, + NULL); + + *context_handle = (gss_ctx_id_t)ctx; + + return GSS_S_COMPLETE; +} + + +static OM_uint32 +gsskrb5_get_creds( + OM_uint32 * minor_status, + krb5_context context, + krb5_ccache ccache, + gsskrb5_ctx ctx, + gss_const_name_t target_name, + OM_uint32 time_req, + OM_uint32 * time_rec) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_creds this_cred; + OM_uint32 lifetime_rec; + + if (ctx->target) { + krb5_free_principal(context, ctx->target); + ctx->target = NULL; + } + if (ctx->kcred) { + krb5_free_creds(context, ctx->kcred); + ctx->kcred = NULL; + } + + ret = _gsskrb5_canon_name(minor_status, context, target_name, + &ctx->target); + if (ret) + return ret; + + memset(&this_cred, 0, sizeof(this_cred)); + this_cred.client = ctx->source; + this_cred.server = ctx->target; + + if (time_req && time_req != GSS_C_INDEFINITE) { + krb5_timestamp ts; + + krb5_timeofday (context, &ts); + this_cred.times.endtime = ts + time_req; + } else { + this_cred.times.endtime = 0; + } + + this_cred.session.keytype = KEYTYPE_NULL; + + kret = krb5_get_credentials(context, + 0, + ccache, + &this_cred, + &ctx->kcred); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + krb5_free_principal(context, ctx->target); + kret = krb5_copy_principal(context, ctx->kcred->server, &ctx->target); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + ctx->endtime = ctx->kcred->times.endtime; + + ret = _gsskrb5_lifetime_left(minor_status, context, + ctx->endtime, &lifetime_rec); + if (ret) return ret; + + if (lifetime_rec == 0) { + *minor_status = 0; + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gsskrb5_initiator_ready( + OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + OM_uint32 flags = ctx->flags; + + krb5_free_creds(context, ctx->kcred); + ctx->kcred = NULL; + + if (ctx->more_flags & CLOSE_CCACHE) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number); + + _gsskrb5i_is_cfx(context, ctx, 0); + is_cfx = (ctx->more_flags & IS_CFX); + + ret = _gssapi_msg_order_create(minor_status, + &ctx->order, + _gssapi_msg_order_f(flags), + seq_number, 0, is_cfx); + if (ret) return ret; + + ctx->state = INITIATOR_READY; + ctx->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +/* + * handle delegated creds in init-sec-context + */ + +static void +do_delegation (krb5_context context, + krb5_auth_context ac, + krb5_ccache ccache, + krb5_creds *cred, + krb5_data *fwd_data, + uint32_t flagmask, + uint32_t *flags) +{ + krb5_error_code kret; + krb5_principal client; + const char *host; + + krb5_data_zero (fwd_data); + + kret = krb5_cc_get_principal(context, ccache, &client); + if (kret) + goto out; + + /* We can't generally enforce server.name_type == KRB5_NT_SRV_HST */ + if (cred->server->name.name_string.len < 2) + goto out; + host = krb5_principal_get_comp_string(context, cred->server, 1); + +#define FWDABLE 1 + kret = krb5_fwd_tgt_creds(context, ac, host, client, cred->server, ccache, + FWDABLE, fwd_data); + + out: + if (kret) + *flags &= ~flagmask; + else + *flags |= flagmask; + + if (client) + krb5_free_principal(context, client); +} + +/* + * first stage of init-sec-context + */ + +static OM_uint32 +init_auth +(OM_uint32 * minor_status, + gsskrb5_cred cred, + gsskrb5_ctx ctx, + krb5_context context, + gss_const_name_t name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_data fwd_data; + OM_uint32 lifetime_rec; + + krb5_data_zero(&fwd_data); + + *minor_status = 0; + + if (actual_mech_type) + *actual_mech_type = GSS_KRB5_MECHANISM; + + if (cred == NULL) { + kret = krb5_cc_default (context, &ctx->ccache); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + ctx->more_flags |= CLOSE_CCACHE; + } else + ctx->ccache = cred->ccache; + + kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + /* + * This is hideous glue for (NFS) clients that wants to limit the + * available enctypes to what it can support (encryption in + * kernel). + */ + if (cred && cred->enctypes) + krb5_set_default_in_tkt_etypes(context, cred->enctypes); + + ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, + ctx, name, time_req, time_rec); + if (ret) + goto failure; + + ret = gsskrb5_set_authorization_data(minor_status, context, + ctx->auth_context, name); + if (ret) + goto failure; + + ctx->endtime = ctx->kcred->times.endtime; + + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); + if (ret) + goto failure; + + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + &lifetime_rec); + if (ret) + goto failure; + + if (lifetime_rec == 0) { + *minor_status = 0; + ret = GSS_S_CONTEXT_EXPIRED; + goto failure; + } + + krb5_auth_con_setkey(context, + ctx->auth_context, + &ctx->kcred->session); + + kret = krb5_auth_con_generatelocalsubkey(context, + ctx->auth_context, + &ctx->kcred->session); + if(kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + return GSS_S_COMPLETE; + +failure: + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + return ret; + +} + +static OM_uint32 +init_auth_restart +(OM_uint32 * minor_status, + gsskrb5_cred cred, + gsskrb5_ctx ctx, + krb5_context context, + OM_uint32 req_flags, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_flags ap_options; + krb5_data outbuf; + uint32_t flags; + krb5_data authenticator; + Checksum cksum; + krb5_enctype enctype; + krb5_data fwd_data, timedata; + int32_t offset = 0, oldoffset = 0; + uint32_t flagmask; + + krb5_data_zero(&outbuf); + krb5_data_zero(&fwd_data); + + *minor_status = 0; + + /* + * Check if our configuration requires us to follow the KDC's + * guidance. If so, we transmogrify the GSS_C_DELEG_FLAG into + * the GSS_C_DELEG_POLICY_FLAG. + */ + if ((context->flags & KRB5_CTX_F_ENFORCE_OK_AS_DELEGATE) + && (req_flags & GSS_C_DELEG_FLAG)) { + req_flags &= ~GSS_C_DELEG_FLAG; + req_flags |= GSS_C_DELEG_POLICY_FLAG; + } + + /* + * If the credential doesn't have ok-as-delegate, check if there + * is a realm setting and use that. + */ + if (!ctx->kcred->flags.b.ok_as_delegate) { + krb5_data data; + + ret = krb5_cc_get_config(context, ctx->ccache, NULL, + "realm-config", &data); + if (ret == 0) { + /* XXX 1 is use ok-as-delegate */ + if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0) + req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); + krb5_data_free(&data); + } + } + + flagmask = 0; + + /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */ + if ((req_flags & GSS_C_DELEG_POLICY_FLAG) + && ctx->kcred->flags.b.ok_as_delegate) + flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG; + /* if there still is a GSS_C_DELEG_FLAG, use that */ + if (req_flags & GSS_C_DELEG_FLAG) + flagmask |= GSS_C_DELEG_FLAG; + + + flags = 0; + ap_options = 0; + if (flagmask & GSS_C_DELEG_FLAG) { + do_delegation (context, + ctx->deleg_auth_context, + ctx->ccache, ctx->kcred, + &fwd_data, flagmask, &flags); + } + + if (req_flags & GSS_C_MUTUAL_FLAG) { + flags |= GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + + if (req_flags & GSS_C_REPLAY_FLAG) + flags |= GSS_C_REPLAY_FLAG; + if (req_flags & GSS_C_SEQUENCE_FLAG) + flags |= GSS_C_SEQUENCE_FLAG; +#if 0 + if (req_flags & GSS_C_ANON_FLAG) + ; /* XXX */ +#endif + if (req_flags & GSS_C_DCE_STYLE) { + /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ + flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + if (req_flags & GSS_C_IDENTIFY_FLAG) + flags |= GSS_C_IDENTIFY_FLAG; + if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) + flags |= GSS_C_EXTENDED_ERROR_FLAG; + + if (req_flags & GSS_C_CONF_FLAG) { + flags |= GSS_C_CONF_FLAG; + } + if (req_flags & GSS_C_INTEG_FLAG) { + flags |= GSS_C_INTEG_FLAG; + } + if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) { + flags |= GSS_C_CONF_FLAG; + flags |= GSS_C_INTEG_FLAG; + } + flags |= GSS_C_TRANS_FLAG; + + if (ret_flags) + *ret_flags = flags; + ctx->flags = flags; + ctx->more_flags |= LOCAL; + + ret = _gsskrb5_create_8003_checksum (minor_status, + input_chan_bindings, + flags, + &fwd_data, + &cksum); + krb5_data_free (&fwd_data); + if (ret) + goto failure; + + enctype = ctx->auth_context->keyblock->keytype; + + ret = krb5_cc_get_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + if (ret == 0) { + if (timedata.length == 4) { + const u_char *p = timedata.data; + offset = ((uint32_t)p[0] << 24) + | ((uint32_t)p[1] << 16) + | ((uint32_t)p[2] << 8) + | ((uint32_t)p[3] << 0); + } + krb5_data_free(&timedata); + } + + if (offset) { + krb5_get_kdc_sec_offset (context, &oldoffset, NULL); + krb5_set_kdc_sec_offset (context, offset, -1); + } + + kret = _krb5_build_authenticator(context, + ctx->auth_context, + enctype, + ctx->kcred, + &cksum, + &authenticator, + KRB5_KU_AP_REQ_AUTH); + + if (kret) { + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + kret = krb5_build_ap_req (context, + enctype, + ctx->kcred, + ap_options, + authenticator, + &outbuf); + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + if (flags & GSS_C_DCE_STYLE) { + output_token->value = outbuf.data; + output_token->length = outbuf.length; + } else { + ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, + (u_char *)(intptr_t)"\x01\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + goto failure; + } + + free_Checksum(&cksum); + + if (flags & GSS_C_MUTUAL_FLAG) { + ctx->state = INITIATOR_WAIT_FOR_MUTUAL; + return GSS_S_CONTINUE_NEEDED; + } + + return gsskrb5_initiator_ready(minor_status, ctx, context); +failure: + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + return ret; +} + +static krb5_error_code +handle_error_packet(krb5_context context, + gsskrb5_ctx ctx, + krb5_data indata) +{ + krb5_error_code kret; + KRB_ERROR error; + + kret = krb5_rd_error(context, &indata, &error); + if (kret == 0) { + kret = krb5_error_from_rd_error(context, &error, NULL); + + /* save the time skrew for this host */ + if (kret == KRB5KRB_AP_ERR_SKEW) { + krb5_data timedata; + unsigned char p[4]; + int32_t t = error.stime - time(NULL); + + p[0] = (t >> 24) & 0xFF; + p[1] = (t >> 16) & 0xFF; + p[2] = (t >> 8) & 0xFF; + p[3] = (t >> 0) & 0xFF; + + timedata.data = p; + timedata.length = sizeof(p); + + krb5_cc_set_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + + if ((ctx->more_flags & RETRIED) == 0) + ctx->state = INITIATOR_RESTART; + ctx->more_flags |= RETRIED; + } + free_KRB_ERROR (&error); + } + return kret; +} + + +static OM_uint32 +repl_mutual +(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data indata; + krb5_ap_rep_enc_part *repl; + + output_token->length = 0; + output_token->value = NULL; + + if (input_token == GSS_C_NO_BUFFER) + return GSS_S_FAILURE; + + if (actual_mech_type) + *actual_mech_type = GSS_KRB5_MECHANISM; + + if (IS_DCE_STYLE(ctx)) { + /* There is no OID wrapping. */ + indata.length = input_token->length; + indata.data = input_token->value; + kret = krb5_rd_rep(context, + ctx->auth_context, + &indata, + &repl); + if (kret) { + ret = _gsskrb5_decapsulate(minor_status, + input_token, + &indata, + "\x03\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + *minor_status = handle_error_packet(context, ctx, indata); + } else { + *minor_status = kret; + } + return GSS_S_FAILURE; + } + } else { + ret = _gsskrb5_decapsulate (minor_status, + input_token, + &indata, + "\x02\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_DEFECTIVE_TOKEN) { + /* check if there is an error token sent instead */ + ret = _gsskrb5_decapsulate (minor_status, + input_token, + &indata, + "\x03\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + *minor_status = handle_error_packet(context, ctx, indata); + return GSS_S_FAILURE; + } + } + kret = krb5_rd_rep (context, + ctx->auth_context, + &indata, + &repl); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + krb5_free_ap_rep_enc_part (context, + repl); + + *minor_status = 0; + if (time_rec) + (void) _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + time_rec); + if (ret_flags) + *ret_flags = ctx->flags; + + if (req_flags & GSS_C_DCE_STYLE) { + int32_t local_seq, remote_seq; + krb5_data outbuf; + + /* + * So DCE_STYLE is strange. The client echos the seq number + * that the server used in the server's mk_rep in its own + * mk_rep(). After when done, it resets to it's own seq number + * for the gss_wrap calls. + */ + + krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq); + krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq); + krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq); + + kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* reset local seq number */ + krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq); + + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + + return gsskrb5_initiator_ready(minor_status, ctx, context); +} + +/* + * gss_init_sec_context + */ + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context +(OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + krb5_context context; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + gsskrb5_ctx ctx; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + output_token->length = 0; + output_token->value = NULL; + + if (context_handle == NULL) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + + if (target_name == GSS_C_NO_NAME) { + if (actual_mech_type) + *actual_mech_type = GSS_C_NO_OID; + *minor_status = 0; + return GSS_S_BAD_NAME; + } + + if (mech_type != GSS_C_NO_OID && + !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) + return GSS_S_BAD_MECH; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + OM_uint32 ret1; + + if (*context_handle != GSS_C_NO_CONTEXT) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + ret1 = _gsskrb5_create_ctx(minor_status, + context_handle, + context, + input_chan_bindings, + INITIATOR_START); + if (ret1) + return ret1; + } + + if (*context_handle == GSS_C_NO_CONTEXT) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + ctx = (gsskrb5_ctx) *context_handle; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + again: + switch (ctx->state) { + case INITIATOR_START: + ret = init_auth(minor_status, + cred, + ctx, + context, + target_name, + mech_type, + req_flags, + time_req, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ret != GSS_S_COMPLETE) + break; + HEIM_FALLTHROUGH; + case INITIATOR_RESTART: + ret = init_auth_restart(minor_status, + cred, + ctx, + context, + req_flags, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + break; + case INITIATOR_WAIT_FOR_MUTUAL: + ret = repl_mutual(minor_status, + ctx, + context, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ctx->state == INITIATOR_RESTART) + goto again; + break; + case INITIATOR_READY: + /* + * If we get there, the caller have called + * gss_init_sec_context() one time too many. + */ + _gsskrb5_set_status(EINVAL, "init_sec_context " + "called one time too many"); + *minor_status = EINVAL; + ret = GSS_S_BAD_STATUS; + break; + default: + _gsskrb5_set_status(EINVAL, "init_sec_context " + "invalid state %d for client", + (int)ctx->state); + *minor_status = EINVAL; + ret = GSS_S_BAD_STATUS; + break; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* destroy context in case of error */ + if (GSS_ERROR(ret)) { + OM_uint32 min2; + _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); + } + + return ret; + +} + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *minor_status, + krb5_context context, + krb5_auth_context auth_context, + gss_const_name_t gn) +{ + const CompositePrincipal *name = (const void *)gn; + AuthorizationData *ad; + krb5_error_code kret = 0; + size_t i; + + if (name->nameattrs == NULL || name->nameattrs->want_ad == NULL) + return GSS_S_COMPLETE; + + ad = name->nameattrs->want_ad; + for (i = 0; kret == 0 && i < ad->len; i++) { + kret = krb5_auth_con_add_AuthorizationData(context, auth_context, + ad->val[0].ad_type, + &ad->val[0].ad_data); + } + + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_context.c b/third_party/heimdal/lib/gssapi/krb5/inquire_context.c new file mode 100644 index 0000000..e225c33 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_context.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1997, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t * src_name, + gss_name_t * targ_name, + OM_uint32 * lifetime_rec, + gss_OID * mech_type, + OM_uint32 * ctx_flags, + int * locally_initiated, + int * open_context + ) +{ + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle; + gss_name_t name; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (targ_name) + *targ_name = GSS_C_NO_NAME; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (src_name) { + name = (gss_name_t)ctx->source; + ret = _gsskrb5_duplicate_name (minor_status, name, src_name); + if (ret) + goto failed; + } + + if (targ_name) { + name = (gss_name_t)ctx->target; + ret = _gsskrb5_duplicate_name (minor_status, name, targ_name); + if (ret) + goto failed; + } + + if (lifetime_rec) { + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + lifetime_rec); + if (ret) + goto failed; + } + + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (ctx_flags) + *ctx_flags = ctx->flags; + + if (locally_initiated) + *locally_initiated = ctx->more_flags & LOCAL; + + if (open_context) + *open_context = ctx->more_flags & OPEN; + + *minor_status = 0; + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_COMPLETE; + +failed: + if (src_name) + _gsskrb5_release_name(NULL, src_name); + if (targ_name) + _gsskrb5_release_name(NULL, targ_name); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c new file mode 100644 index 0000000..b7b67f7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1997, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred +(OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t * output_name, + OM_uint32 * lifetime, + gss_cred_usage_t * cred_usage, + gss_OID_set * mechanisms + ) +{ + krb5_context context; + gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL; + gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + gss_OID_set amechs = GSS_C_NO_OID_SET; + gss_OID_set imechs = GSS_C_NO_OID_SET; + OM_uint32 junk; + OM_uint32 aminor; + OM_uint32 ret; + OM_uint32 aret; + OM_uint32 alife = GSS_C_INDEFINITE; + OM_uint32 ilife = GSS_C_INDEFINITE; + + /* + * XXX This function is more complex than it has to be. It should call + * _gsskrb5_inquire_cred_by_mech() twice and merge the results in the + * cred_handle == GSS_C_NO_CREDENTIAL case, but since + * _gsskrb5_inquire_cred_by_mech() is implemented in terms of this + * function, first we must fix _gsskrb5_inquire_cred_by_mech(). + */ + + *minor_status = 0; + + if (output_name) + *output_name = GSS_C_NO_NAME; + if (cred_usage) + *cred_usage = GSS_C_BOTH; /* There's no NONE */ + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + GSSAPI_KRB5_INIT (&context); + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * From here to the end of this if we should refactor into a separate + * function. + */ + /* Get the info for the default ACCEPT credential */ + aret = _gsskrb5_acquire_cred_from(&aminor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + GSS_C_NO_CRED_STORE, + &aqcred_accept, + NULL, + NULL); + if (aret == GSS_S_COMPLETE) { + aret = _gsskrb5_inquire_cred(&aminor, + aqcred_accept, + output_name, + &alife, + NULL, + &amechs); + (void) _gsskrb5_release_cred(&junk, &aqcred_accept); + if (aret == GSS_S_COMPLETE) { + output_name = NULL; /* Can't merge names; output only one */ + if (cred_usage) + *cred_usage = GSS_C_ACCEPT; + if (lifetime) + *lifetime = alife; + if (mechanisms) { + *mechanisms = amechs; + amechs = GSS_C_NO_OID_SET; + } + (void) gss_release_oid_set(&junk, &amechs); + } else if (aret != GSS_S_NO_CRED) { + *minor_status = aminor; + return aret; + } else { + alife = GSS_C_INDEFINITE; + } + } + + /* Get the info for the default INITIATE credential */ + ret = _gsskrb5_acquire_cred_from(minor_status, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + GSS_C_NO_CRED_STORE, + &aqcred_init, + NULL, + NULL); + if (ret == GSS_S_COMPLETE) { + ret = _gsskrb5_inquire_cred(minor_status, + aqcred_init, + output_name, + &ilife, + NULL, + &imechs); + (void) _gsskrb5_release_cred(&junk, &aqcred_init); + if (ret == GSS_S_COMPLETE) { + /* + * Merge results for INITIATE with ACCEPT if we had ACCEPT and + * for those outputs that are desired. + */ + if (cred_usage) { + *cred_usage = (*cred_usage == GSS_C_ACCEPT) ? + GSS_C_BOTH : GSS_C_INITIATE; + } + if (lifetime) + *lifetime = min(alife, ilife); + if (mechanisms) { + /* + * This is just one mechanism (IAKERB and such would live + * elsewhere). imechs will be equal to amechs, though not + * ==. + */ + if (aret != GSS_S_COMPLETE) { + *mechanisms = imechs; + imechs = GSS_C_NO_OID_SET; + } + } + (void) gss_release_oid_set(&junk, &amechs); + } else if (ret != GSS_S_NO_CRED) { + *minor_status = aminor; + return aret; + } + } + + if (aret != GSS_S_COMPLETE && ret != GSS_S_COMPLETE) { + *minor_status = aminor; + return aret; + } + *minor_status = 0; /* Even though 0 is not specified to be special */ + return GSS_S_COMPLETE; + } + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (output_name != NULL) { + if (cred->principal != NULL) { + gss_name_t name = (gss_name_t)cred->principal; + ret = _gsskrb5_duplicate_name(minor_status, name, output_name); + if (ret) + goto out; + } else if (cred->usage == GSS_C_ACCEPT) { + /* + * Keytab case, princ may not be set (yet, ever, whatever). + * + * We used to unconditionally output the krb5_sname_to_principal() + * of the host service for the hostname, but we didn't know if we + * had keytab entries for it, so it was incorrect. We can't be + * breaking anything in tree by outputting GSS_C_NO_NAME, but we + * might be breaking other callers. + */ + *output_name = GSS_C_NO_NAME; + } else { + /* This shouldn't happen */ + *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ + ret = GSS_S_NO_CRED; + goto out; + } + } + if (lifetime != NULL) { + ret = _gsskrb5_lifetime_left(minor_status, + context, + cred->endtime, + lifetime); + if (ret) + goto out; + } + if (cred_usage != NULL) + *cred_usage = cred->usage; + if (mechanisms != NULL) { + ret = gss_create_empty_oid_set(minor_status, mechanisms); + if (ret) + goto out; + ret = gss_add_oid_set_member(minor_status, + &cred->mechanisms->elements[0], + mechanisms); + if (ret) + goto out; + } + ret = GSS_S_COMPLETE; + +out: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c new file mode 100644 index 0000000..6ce4994 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003, 2006, 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_mech ( + OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t * name, + OM_uint32 * initiator_lifetime, + OM_uint32 * acceptor_lifetime, + gss_cred_usage_t * cred_usage + ) +{ + gss_cred_usage_t usage; + OM_uint32 maj_stat; + OM_uint32 lifetime; + + /* + * XXX This is busted. _gsskrb5_inquire_cred() should be implemented in + * terms of _gsskrb5_inquire_cred_by_mech(), NOT the other way around. + */ + maj_stat = + _gsskrb5_inquire_cred (minor_status, cred_handle, + name, &lifetime, &usage, NULL); + if (maj_stat) + return maj_stat; + + if (initiator_lifetime) { + if (usage == GSS_C_INITIATE || usage == GSS_C_BOTH) + *initiator_lifetime = lifetime; + else + *initiator_lifetime = 0; + } + + if (acceptor_lifetime) { + if (usage == GSS_C_ACCEPT || usage == GSS_C_BOTH) + *acceptor_lifetime = lifetime; + else + *acceptor_lifetime = 0; + } + + if (cred_usage) + *cred_usage = usage; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c new file mode 100644 index 0000000..7dae3d2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_oid + (OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_context context; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + krb5_error_code ret; + gss_buffer_desc buffer; + char *str; + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(desired_object, GSS_KRB5_COPY_CCACHE_X) == 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (cred->ccache == NULL) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_full_name(context, cred->ccache, &str); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + buffer.value = str; + buffer.length = strlen(str); + + ret = gss_add_buffer_set_member(minor_status, &buffer, data_set); + if (ret != GSS_S_COMPLETE) + _gsskrb5_clear_status (); + + free(str); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c new file mode 100644 index 0000000..c6c6746 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_OID_set * mech_types + ) +{ + OM_uint32 ret; + + ret = gss_create_empty_oid_set(minor_status, mech_types); + if (ret) + return ret; + + ret = gss_add_oid_set_member(minor_status, + GSS_KRB5_MECHANISM, + mech_types); + if (ret) + gss_release_oid_set(NULL, mech_types); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c new file mode 100644 index 0000000..65bd49c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static gss_OID name_list[] = { + GSS_C_NT_HOSTBASED_SERVICE, + GSS_C_NT_USER_NAME, + GSS_KRB5_NT_PRINCIPAL_NAME, + GSS_C_NT_EXPORT_NAME, + NULL +}; + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_names_for_mech ( + OM_uint32 * minor_status, + const gss_OID mechanism, + gss_OID_set * name_types + ) +{ + OM_uint32 ret; + int i; + + *minor_status = 0; + + if (gss_oid_equal(mechanism, GSS_KRB5_MECHANISM) == 0 && + gss_oid_equal(mechanism, GSS_C_NULL_OID) == 0) { + *name_types = GSS_C_NO_OID_SET; + return GSS_S_BAD_MECH; + } + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + for (i = 0; name_list[i] != NULL; i++) { + ret = gss_add_oid_set_member(minor_status, + name_list[i], + name_types); + if (ret != GSS_S_COMPLETE) + break; + } + + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(NULL, name_types); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c new file mode 100644 index 0000000..49d86d1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static int +oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix) +{ + int ret; + heim_oid oid; + heim_oid prefix; + + *suffix = 0; + + ret = der_get_oid(oid_enc->elements, oid_enc->length, + &oid, NULL); + if (ret) { + return 0; + } + + ret = der_get_oid(prefix_enc->elements, prefix_enc->length, + &prefix, NULL); + if (ret) { + der_free_oid(&oid); + return 0; + } + + ret = 0; + + if (oid.length - 1 == prefix.length) { + *suffix = oid.components[oid.length - 1]; + oid.length--; + ret = (der_heim_oid_cmp(&oid, &prefix) == 0); + oid.length++; + } + + der_free_oid(&oid); + der_free_oid(&prefix); + + return ret; +} + +static OM_uint32 inquire_sec_context_tkt_flags + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + gss_buffer_set_t *data_set) +{ + OM_uint32 tkt_flags; + unsigned char buf[4]; + gss_buffer_desc value; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + _gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags"); + *minor_status = EINVAL; + return GSS_S_BAD_MECH; + } + + tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + _gss_mg_encode_le_uint32(tkt_flags, buf); + value.length = sizeof(buf); + value.value = buf; + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); +} + +enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY }; + +static OM_uint32 inquire_sec_context_get_subkey + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + enum keytype keytype, + gss_buffer_set_t *data_set) +{ + krb5_keyblock *key = NULL; + krb5_storage *sp = NULL; + krb5_data data; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret; + + krb5_data_zero(&data); + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + ret = ENOMEM; + goto out; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + switch(keytype) { + case ACCEPTOR_KEY: + ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key); + break; + case INITIATOR_KEY: + ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key); + break; + case TOKEN_KEY: + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + break; + default: + _gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype); + ret = EINVAL; + break; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) + goto out; + if (key == NULL) { + _gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype); + ret = EINVAL; + goto out; + } + + ret = krb5_store_keyblock(sp, *key); + if (ret) + goto out; + + ret = krb5_storage_to_data(sp, &data); + if (ret) + goto out; + + { + gss_buffer_desc value; + + value.length = data.length; + value.value = data.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + } + +out: + krb5_free_keyblock(context, key); + krb5_data_free(&data); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} + +static OM_uint32 inquire_sec_context_get_sspi_session_key + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + gss_buffer_set_t *data_set) +{ + krb5_keyblock *key; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret; + gss_buffer_desc value; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + if (ret) + goto out; + if (key == NULL) { + ret = EINVAL; + goto out; + } + + value.length = key->keyvalue.length; + value.value = key->keyvalue.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + krb5_free_keyblock(context, key); + + /* MIT also returns the enctype encoded as an OID in data_set[1] */ + +out: + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} + +static OM_uint32 inquire_sec_context_authz_data + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + unsigned ad_type, + gss_buffer_set_t *data_set) +{ + krb5_data data; + gss_buffer_desc ad_data; + OM_uint32 ret; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = EINVAL; + _gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from"); + return GSS_S_NO_CONTEXT; + } + + ret = krb5_ticket_get_authorization_data_type(context, + context_handle->ticket, + ad_type, + &data); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ad_data.value = data.data; + ad_data.length = data.length; + + ret = gss_add_buffer_set_member(minor_status, + &ad_data, + data_set); + + krb5_data_free(&data); + + return ret; +} + +static OM_uint32 inquire_sec_context_has_buggy_spnego + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + gss_buffer_set_t *data_set) +{ + uint8_t old_enctype; + gss_buffer_desc buffer; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + + /* + * For Windows SPNEGO implementations, the initiator or acceptor + * are presumed to be "buggy" (Windows 2003 or earlier) if an + * "older" (i.e. pre-AES per RFC 4121) encryption type was used. + */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + old_enctype = ((context_handle->more_flags & IS_CFX) == 0); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + buffer.value = &old_enctype; + buffer.length = sizeof(old_enctype); + + return gss_add_buffer_set_member(minor_status, &buffer, data_set); +} + +/* + * + */ + +static OM_uint32 +export_lucid_sec_context_v1(OM_uint32 *minor_status, + gsskrb5_ctx context_handle, + krb5_context context, + gss_buffer_set_t *data_set) +{ + krb5_storage *sp = NULL; + OM_uint32 major_status = GSS_S_COMPLETE; + krb5_error_code ret; + krb5_keyblock *key = NULL; + int32_t number; + int is_cfx; + krb5_data data; + + *minor_status = 0; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + is_cfx = (context_handle->more_flags & IS_CFX); + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + ret = ENOMEM; + goto out; + } + + ret = krb5_store_int32(sp, 1); + if (ret) goto out; + ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0); + if (ret) goto out; + /* XXX need krb5_store_int64() */ + ret = krb5_store_int32(sp, context_handle->endtime); + if (ret) goto out; + krb5_auth_con_getlocalseqnumber (context, + context_handle->auth_context, + &number); + ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ + if (ret) goto out; + ret = krb5_store_uint32(sp, (uint32_t)number); + if (ret) goto out; + krb5_auth_con_getremoteseqnumber (context, + context_handle->auth_context, + &number); + ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ + if (ret) goto out; + ret = krb5_store_uint32(sp, (uint32_t)number); + if (ret) goto out; + ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0); + if (ret) goto out; + + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + if (ret) goto out; + + if (is_cfx == 0) { + int sign_alg, seal_alg; + + switch (key->keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + sign_alg = 0; + seal_alg = 0; + break; + case ETYPE_DES3_CBC_MD5: + case ETYPE_DES3_CBC_SHA1: + sign_alg = 4; + seal_alg = 2; + break; + case ETYPE_ARCFOUR_HMAC_MD5: + case ETYPE_ARCFOUR_HMAC_MD5_56: + sign_alg = 17; + seal_alg = 16; + break; + default: + sign_alg = -1; + seal_alg = -1; + break; + } + ret = krb5_store_int32(sp, sign_alg); + if (ret) goto out; + ret = krb5_store_int32(sp, seal_alg); + if (ret) goto out; + /* ctx_key */ + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + } else { + int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0; + + /* have_acceptor_subkey */ + ret = krb5_store_int32(sp, subkey_p); + if (ret) goto out; + /* ctx_key */ + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + /* acceptor_subkey */ + if (subkey_p) { + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + } + } + ret = krb5_storage_to_data(sp, &data); + if (ret) goto out; + + { + gss_buffer_desc ad_data; + + ad_data.value = data.data; + ad_data.length = data.length; + + ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set); + krb5_data_free(&data); + if (ret) + goto out; + } + +out: + if (key) + krb5_free_keyblock (context, key); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return major_status; +} + +static OM_uint32 +get_authtime(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + gss_buffer_set_t *data_set) + +{ + gss_buffer_desc value; + unsigned char buf[SIZEOF_TIME_T]; + time_t authtime; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (ctx->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + authtime = ctx->ticket->ticket.authtime; + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + +#if SIZEOF_TIME_T == 8 + _gss_mg_encode_le_uint64(authtime, buf); +#elif SIZEOF_TIME_T == 4 + _gss_mg_encode_le_uint32(authtime, buf); +#else +#error set SIZEOF_TIME_T for your platform +#endif + value.length = sizeof(buf); + value.value = buf; + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); +} + + +static OM_uint32 +get_service_keyblock + (OM_uint32 *minor_status, + gsskrb5_ctx ctx, + gss_buffer_set_t *data_set) +{ + krb5_storage *sp = NULL; + krb5_data data; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret = EINVAL; + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (ctx->service_keyblock == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + krb5_storage_free(sp); + _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + krb5_data_zero(&data); + + ret = krb5_store_keyblock(sp, *ctx->service_keyblock); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (ret) + goto out; + + ret = krb5_storage_to_data(sp, &data); + if (ret) + goto out; + + { + gss_buffer_desc value; + + value.length = data.length; + value.value = data.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + } + +out: + krb5_data_free(&data); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid + (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + unsigned suffix; + + if (ctx == NULL) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) { + return inquire_sec_context_tkt_flags(minor_status, + ctx, + data_set); + } else if (gss_oid_equal(desired_object, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) { + return inquire_sec_context_has_buggy_spnego(minor_status, + ctx, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + TOKEN_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + INITIATOR_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + ACCEPTOR_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) { + return inquire_sec_context_get_sspi_session_key(minor_status, + ctx, + context, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) { + return get_authtime(minor_status, ctx, data_set); + } else if (oid_prefix_equal(desired_object, + GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X, + &suffix)) { + return inquire_sec_context_authz_data(minor_status, + ctx, + context, + suffix, + data_set); + } else if (oid_prefix_equal(desired_object, + GSS_KRB5_EXPORT_LUCID_CONTEXT_X, + &suffix)) { + if (suffix == 1) + return export_lucid_sec_context_v1(minor_status, + ctx, + context, + data_set); + *minor_status = 0; + return GSS_S_FAILURE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) { + return get_service_keyblock(minor_status, ctx, data_set); + } else { + *minor_status = 0; + return GSS_S_FAILURE; + } +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/name_attrs.c b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c new file mode 100644 index 0000000..11fc2ef --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * (Not-yet-)Standard name attributes for Kerberos MNs, + * GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "...". + * + * I.e., "urn:ietf:kerberos:nameattr-...". (XXX Register this URN namespace + * with IANA.) + * + * Note that we do use URN fragments. + * + * Specific attributes below the base URN: + * + * - name access attributes: + * - "realm" -> realm of name + * - "name-ncomp" -> count of name components + * - "name-ncomp#" -> name component N (0 <= N <= 9) + * + * Ticket and Authenticator access attributes: + * + * - "transit-path" -> encoding of the transited path + * - "authenticator-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Authenticator + * - "ticket-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Ticket + * - "ticket-authz-data#pac" -> the PAC + * - "authz-data#" -> encoding of all of a specific auth-data + * element type N (e.g., 2, meaning + * AD-INTENDED-FOR-SERVER) + * + * Misc. attributes: + * + * - "peer-realm" -> name of peer's realm (if this is an MN + * resulting for establishing a security + * context) + * - "canonical-name" -> exported name token and RFC1964 display + * syntax of the name's canonical name + * + * Compatibility with MIT: + * + * - "urn:mspac:" -> the PAC and its individual info buffers + * + * TODO: + * + * - Add some sort of display syntax for transit path + * - Add support for URN q-components or attribute prefixes to specify + * alternative raw and/or display value encodings (JSON?) + * - Add support for attributes for accessing other parts of the Ticket / KDC + * reply enc-parts, like auth times + * - Add support for getting PAC logon fields, including SIDs (one at a time) + * - Add support for CAMMAC? + */ + +static int +attr_eq(gss_const_buffer_t attr, const char *aname, size_t aname_len, \ + int prefix_check) +{ + if (attr->length < aname_len) + return 0; + + if (strncmp((char *)attr->value, aname, aname_len) != 0) + return 0; + + return prefix_check || attr->length == aname_len; +} + +#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1, FALSE)) +#define ATTR_EQ_PREFIX(a, an) (attr_eq(a, an, sizeof(an) - 1, TRUE)) + +/* Split attribute into prefix, suffix, and fragment. See RFC6680. */ +static void +split_attr(gss_const_buffer_t orig, + gss_buffer_t prefix, + gss_buffer_t attr, + gss_buffer_t frag, + int *is_urn) +{ + char *last = NULL; + char *p = orig->value; + + *attr = *orig; + prefix->value = orig->value; + prefix->length = 0; + frag->length = 0; + frag->value = NULL; + + /* FIXME We don't have a memrchr() in lib/roken */ + for (p = memchr(p, ' ', orig->length); + p; + p = memchr(p + 1, ' ', orig->length)) { + last = p; + prefix->length = last - (const char *)orig->value; + attr->value = last + 1; + attr->length = orig->length - (prefix->length + 1); + } + if (prefix->length == 0) + prefix->value = NULL; + + if ((*is_urn = (strncmp(attr->value, "urn:", sizeof("urn:") - 1) == 0)) && + (p = memchr((char *)attr->value + 1, '#', attr->length - 1))) { + frag->value = ++p; + frag->length = attr->length - (p - (const char *)attr->value); + attr->length = --p - (const char *)attr->value; + } +} + +typedef OM_uint32 get_name_attr_f(OM_uint32 *, + const CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int *, + int *, + gss_buffer_t, + gss_buffer_t, + int *); + +typedef OM_uint32 set_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int, + gss_buffer_t); + +typedef OM_uint32 del_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t); +typedef get_name_attr_f *get_name_attr_fp; +typedef set_name_attr_f *set_name_attr_fp; +typedef del_name_attr_f *del_name_attr_fp; + +static get_name_attr_f get_realm; +static get_name_attr_f get_ncomps; +static get_name_attr_f get_peer_realm; +static get_name_attr_f get_pac; +static get_name_attr_f get_pac_buffer; +static get_name_attr_f get_authz_data; +static get_name_attr_f get_ticket_authz_data; +static get_name_attr_f get_authenticator_authz_data; +static set_name_attr_f set_authenticator_authz_data; +static get_name_attr_f get_transited; +static get_name_attr_f get_canonical_name; + +#define NB(n) \ + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n, n, \ + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n) - 1, \ + sizeof(n) - 1 +#define NM(n) \ + "urn:mspac:" n, n, sizeof("urn:mspac:" n) - 1, sizeof(n) - 1 + +static struct krb5_name_attrs { + const char *fullname; + const char *name; + size_t fullnamelen; + size_t namelen; + get_name_attr_fp getter; + set_name_attr_fp setter; + del_name_attr_fp deleter; + unsigned int indicate:1; + unsigned int is_krb5_name_attr_urn:1; +} name_attrs[] = { + /* XXX We should sort these so we can binary search them */ + { NB("realm"), get_realm, NULL, NULL, 1, 1 }, + { NB("name-ncomp"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#0"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#1"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#2"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#3"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#4"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#5"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#6"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#7"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#8"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#9"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("peer-realm"), get_peer_realm, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data#pac"), get_pac, NULL, NULL, 1, 1 }, + { NM(""), get_pac, NULL, NULL, 1, 0 }, + { NM("logon-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("credentials-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("server-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("privsvr-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("client-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("delegation-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("upn-dns-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("ticket-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("attributes-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("requestor-sid"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NB("ticket-authz-data#kdc-issued"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("authenticator-authz-data"), + get_authenticator_authz_data, + set_authenticator_authz_data, NULL, 1, 1 }, + { NB("authz-data"), get_authz_data, NULL, NULL, 1, 1 }, + { NB("transit-path"), get_transited, NULL, NULL, 1, 1 }, + { NB("canonical-name"), get_canonical_name, NULL, NULL, 1, 1 }, +}; + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 0; + if (more) + *more = 0; + if (value) { + value->length = 0; + value->value = NULL; + } + if (display_value) { + display_value->length = 0; + display_value->value = NULL; + } + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].getter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, authenticated, + complete, value, display_value, more); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t original_attr, + gss_buffer_t value) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].setter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else + continue; + + return name_attrs[i].setter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag, complete, value); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].deleter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].deleter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + gss_buffer_desc prefix, attr, frag, a; + OM_uint32 major = GSS_S_UNAVAILABLE; + size_t i; + int authenticated, is_urn; + + *minor_status = 0; + if (name_is_MN) + *name_is_MN = 1; + if (MN_mech) + *MN_mech = GSS_KRB5_MECHANISM; + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ; + if (attrs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].indicate) + continue; + a.value = (void *)(uintptr_t)name_attrs[i].fullname; + a.length = name_attrs[i].fullnamelen; + split_attr(&a, &prefix, &attr, &frag, &is_urn); + major = name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, &authenticated, + NULL, NULL, NULL, NULL); + if (major == GSS_S_UNAVAILABLE) + continue; + if (major != GSS_S_COMPLETE) + break; + major = gss_add_buffer_set_member(minor_status, &a, attrs); + } + if (major == GSS_S_UNAVAILABLE) + major = GSS_S_COMPLETE; + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ + krb5_const_principal p = (void *)name; + char *s = NULL; + + *minor_status = 0; + if (display_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + display_name->length = 0; + display_name->value = NULL; + + if (gss_oid_equal(display_as_name_type, GSS_C_NT_USER_NAME)) { + if (p->name.name_string.len != 1) + return GSS_S_UNAVAILABLE; + return _gsskrb5_localname(minor_status, name, GSS_KRB5_MECHANISM, + display_name); + } + if (!gss_oid_equal(display_as_name_type, GSS_C_NT_HOSTBASED_SERVICE) || + p->name.name_string.len != 2 || + strchr(p->name.name_string.val[0], '@') || + strchr(p->name.name_string.val[1], '.') == NULL) + return GSS_S_UNAVAILABLE; + if (asprintf(&s, "%s@%s", p->name.name_string.val[0], + p->name.name_string.val[1]) == -1 || s == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + display_name->length = strlen(s); + display_name->value = s; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exported_name) +{ + krb5_error_code kret; + gss_buffer_desc inner = GSS_C_EMPTY_BUFFER; + unsigned char *buf; + size_t sz; + + if (name == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + if (exported_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length, + (void *)name, &sz, kret); + if (kret != 0) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + free(inner.value); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + buf[0] = 0x04; + buf[1] = 0x02; + buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf[4] = 0x06; + buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF; + + memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += 6 + GSS_KRB5_MECHANISM->length; + + buf[0] = (inner.length >> 24) & 0xff; + buf[1] = (inner.length >> 16) & 0xff; + buf[2] = (inner.length >> 8) & 0xff; + buf[3] = (inner.length) & 0xff; + buf += 4; + + memcpy(buf, inner.value, inner.length); + free(inner.value); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +#define CHECK_ENOMEM(v, dv) \ + do { \ + if (((v) && !(v)->value) || ((dv) && !(dv)->value)) { \ + if ((v) && (v)->value) { \ + free((v)->value); \ + (v)->length = 0; \ + (v)->value = NULL; \ + } \ + *minor_status = ENOMEM; \ + return GSS_S_FAILURE; \ + } \ + } while (0) + +static OM_uint32 +get_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !name->realm) + return GSS_S_UNAVAILABLE; + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(name->realm))) + value->length = strlen(name->realm); + if (display_value && (display_value->value = strdup(name->realm))) + display_value->length = strlen(name->realm); + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_ncomps(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + int n = -1; + + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (frag->length == 1 && + ((const char *)frag->value)[0] >= '0' && + ((const char *)frag->value)[0] <= '9') { + n = ((const char *)frag->value)[0] - '0'; + } else if (frag->length == sizeof("all") - 1 && + strncmp(frag->value, "all", sizeof("all") - 1) == 0) { + if (!more || *more < -1 || *more == 0 || *more > CHAR_MAX || + *more > (int)name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (*more == -1) { + *more = name->name.name_string.len - 1; + n = 0; + } else { + n = name->name.name_string.len - *more; + (*more)--; + } + } + + if (frag->length == 0) { + char *s = NULL; + + /* Outut count of components */ + if (value && (value->value = malloc(sizeof(size_t)))) { + *((size_t *)value->value) = name->name.name_string.len; + value->length = sizeof(size_t); + } + if (display_value && + asprintf(&s, "%u", (unsigned int)name->name.name_string.len) > 0) { + display_value->value = s; + display_value->length = strlen(display_value->value); + } + } else { + /* + * Output a component. The value and the display value are the same in + * this case. + */ + if (n < 0 || n >= name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (value && (value->value = strdup(name->name.name_string.val[n]))) + value->length = strlen(name->name.name_string.val[n]); + if (display_value && + (display_value->value = strdup(name->name.name_string.val[n]))) + display_value->length = strlen(name->name.name_string.val[n]); + } + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_peer_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !nameattrs || !nameattrs->peer_realm) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(nameattrs->peer_realm[0]))) + value->length = strlen(value->value); + if (display_value && + (display_value->value = strdup(nameattrs->peer_realm[0]))) + display_value->length = strlen(display_value->value); + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_pac(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + + krb5_data_zero(&data); + + if (src == NULL || + src->element != choice_PrincipalNameAttrSrc_enc_ticket_part) + return GSS_S_UNAVAILABLE; + + ticket = &src->u.enc_ticket_part; + + if (prefix->length || !authenticated || !ticket) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_pac_buffer(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + krb5_data suffix; + + krb5_data_zero(&data); + + if (prefix->length || !authenticated || + !nameattrs || !nameattrs->pac) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + if (ATTR_EQ_PREFIX(attr, "urn:mspac:")) { + suffix.length = attr->length - (sizeof("urn:mspac:") - 1); + suffix.data = (char *)attr->value + sizeof("urn:mspac:") - 1; + } else if (ATTR_EQ_PREFIX(frag, "pac-")) { + suffix.length = frag->length - sizeof("pac-") - 1; + suffix.data = (char *)frag->value + sizeof("pac-") - 1; + } else + return GSS_S_UNAVAILABLE; /* should not be reached */ + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_pac_get_buffer_by_name(context, nameattrs->pac, &suffix, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + krb5_context context; + krb5_data data; + char s[22]; + char *end; + int64_t n; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs || !frag->length || frag->length > sizeof(s) - 1) + return GSS_S_UNAVAILABLE; + + /* Output a specific AD element from the ticket or authenticator */ + krb5_data_zero(&data); + memcpy(s, frag->value, frag->length); + s[frag->length] = '\0'; + errno = 0; + n = strtoll(s, &end, 10); + if (end[0] == '\0' && (errno || n > INT_MAX || n < INT_MIN)) { + *minor_status = ERANGE; + return GSS_S_UNAVAILABLE; + } + if (end[0] != '\0') { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + GSSAPI_KRB5_INIT(&context); + + kret = ENOENT; + if (ticket && ticket->authorization_data) { + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, n, value ? &data : NULL); + + /* If it's from the ticket, it _may_ be authenticated: */ + if (kret == 0 && authenticated) { + if (n == KRB5_AUTHDATA_KDC_ISSUED) + *authenticated = nameattrs->kdc_issued_verified; + else if (n == KRB5_AUTHDATA_WIN2K_PAC) + *authenticated = nameattrs->pac_verified; + } + } + if (kret == ENOENT && nameattrs->authenticator_ad && + n != KRB5_AUTHDATA_KDC_ISSUED && + n != KRB5_AUTHDATA_WIN2K_PAC) { + kret = _krb5_get_ad(context, nameattrs->authenticator_ad, + NULL, n, value ? &data : NULL); + } + + if (value) { + value->length = data.length; + value->value = data.data; + } + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_ticket_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!ticket) + return GSS_S_UNAVAILABLE; + + if (complete) + *complete = 1; + + if (frag->length == sizeof("kdc-issued") - 1 && + strncmp(frag->value, "kdc-issued", sizeof("kdc-issued") - 1) == 0) { + krb5_context context; + krb5_data data; + + GSSAPI_KRB5_INIT(&context); + if (authenticated) + *authenticated = nameattrs->kdc_issued_verified; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_KDC_ISSUED, + value ? &data : NULL); + if (value) { + value->length = data.length; + value->value = data.data; + } + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; + } else if (frag->length) { + return GSS_S_UNAVAILABLE; + } + + /* Just because it's in the Ticket doesn't make it authenticated */ + if (authenticated) + *authenticated = 0; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + ticket->authorization_data, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authenticator_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + size_t sz; + + if (!nameattrs || !nameattrs->authenticator_ad) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + nameattrs->authenticator_ad, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +set_authenticator_authz_data(OM_uint32 *minor_status, + CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int complete, + gss_buffer_t value) +{ + AuthorizationDataElement e; + krb5_error_code kret; + size_t sz; + + if (!value) + return GSS_S_CALL_INACCESSIBLE_READ; + if (frag->length && + !ATTR_EQ(frag, "if-relevant")) + return GSS_S_UNAVAILABLE; + + if ((name->nameattrs == NULL && + (name->nameattrs = calloc(1, sizeof(*name->nameattrs))) == NULL) || + (name->nameattrs->want_ad == NULL && + (name->nameattrs->want_ad = + calloc(1, sizeof(*name->nameattrs->want_ad))) == NULL)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memset(&e, 0, sizeof(e)); + kret = decode_AuthorizationDataElement(value->value, value->length, &e, + &sz); + if (kret == 0) { + if (frag->length) { + AuthorizationData ir; + + ir.len = 0; + ir.val = NULL; + kret = add_AuthorizationData(&ir, &e); + free_AuthorizationDataElement(&e); + if (kret == 0) { + e.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + ASN1_MALLOC_ENCODE(AuthorizationData, e.ad_data.data, + e.ad_data.length, &ir, &sz, kret); + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + } + free_AuthorizationData(&ir); + } else { + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + free_AuthorizationDataElement(&e); + } + } + + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_transited(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs && !ticket) + return GSS_S_UNAVAILABLE; + if (nameattrs && !nameattrs->transited && !ticket) + return GSS_S_UNAVAILABLE; + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (value && ticket) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + &ticket->transited, &sz, kret); + else if (value && nameattrs->transited) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + nameattrs->transited, &sz, kret); + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_canonical_name(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + krb5_principal p = NULL; + krb5_context context; + EncTicketPart *ticket = NULL; + EncKDCRepPart *kdcrep = NULL; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + kdcrep = &src->u.enc_kdc_rep_part; + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + GSSAPI_KRB5_INIT(&context); + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (kdcrep) { + kret = _krb5_principalname2krb5_principal(context, &p, + kdcrep->sname, + kdcrep->srealm); + } else if (nameattrs && nameattrs->pac && + (_krb5_pac_get_canon_principal(context, nameattrs->pac, &p)) == 0) { + if (authenticated) + *authenticated = nameattrs->pac_verified; + } else if (ticket) { + krb5_data data; + krb5_pac pac = NULL; + + krb5_data_zero(&data); + + /* Use canonical name from PAC if available */ + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, &data); + if (kret == 0) + kret = krb5_pac_parse(context, data.data, data.length, &pac); + if (kret == 0) + kret = _krb5_pac_get_canon_principal(context, pac, &p); + if (kret == 0 && authenticated) + *authenticated = nameattrs->pac_verified; + else if (kret == ENOENT) + kret = _krb5_principalname2krb5_principal(context, &p, + ticket->cname, + ticket->crealm); + + krb5_data_free(&data); + krb5_pac_free(context, pac); + } else + return GSS_S_UNAVAILABLE; + if (kret == 0 && value) { + OM_uint32 major; + /* + * Value is exported name token (exported composite name token + * should also work). + */ + major = _gsskrb5_export_name(minor_status, (gss_name_t)p, value); + if (major != GSS_S_COMPLETE) { + krb5_free_principal(context, p); + return major; + } + } + if (kret == 0 && display_value) { + /* Display value is principal name display form */ + kret = krb5_unparse_name(context, p, + (char **)&display_value->value); + if (kret == 0) + display_value->length = strlen(display_value->value); + } + + krb5_free_principal(context, p); + if (kret) { + if (value) { + free(value->value); + value->length = 0; + value->value = NULL; + } + *minor_status = kret; + return GSS_S_UNAVAILABLE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c b/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c new file mode 100644 index 0000000..dca7464 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_localname(OM_uint32 *minor_status, + gss_const_name_t pname, + const gss_OID mech_type, + gss_buffer_t localname) +{ + krb5_error_code ret; + krb5_context context; + krb5_const_principal princ = (krb5_const_principal)pname; + char lnamebuf[256]; + + GSSAPI_KRB5_INIT(&context); + + *minor_status = 0; + + ret = krb5_aname_to_localname(context, princ, + sizeof(lnamebuf), lnamebuf); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + localname->length = strlen(lnamebuf); + + localname->value = malloc(localname->length + 1); + if (localname->value == NULL) { + localname->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(localname->value, lnamebuf, localname->length + 1); + *minor_status = 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/prf.c b/third_party/heimdal/lib/gssapi/krb5/prf.c new file mode 100644 index 0000000..941d21a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/prf.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle; + krb5_context context; + krb5_error_code ret; + krb5_crypto crypto; + krb5_data input, output; + uint32_t num; + OM_uint32 junk; + unsigned char *p; + krb5_keyblock *key = NULL; + size_t dol; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + if (desired_output_len <= 0 || prf_in->length + 4 < prf_in->length) { + *minor_status = 0; + return GSS_S_FAILURE; + } + dol = desired_output_len; + + GSSAPI_KRB5_INIT (&context); + + switch(prf_key) { + case GSS_C_PRF_KEY_FULL: + _gsskrb5i_get_acceptor_subkey(ctx, context, &key); + break; + case GSS_C_PRF_KEY_PARTIAL: + _gsskrb5i_get_initiator_subkey(ctx, context, &key); + break; + default: + _gsskrb5_set_status(EINVAL, "unknown kerberos prf_key"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (key == NULL) { + _gsskrb5_set_status(EINVAL, "no prf_key found"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + krb5_free_keyblock (context, key); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + prf_out->value = malloc(dol); + if (prf_out->value == NULL) { + _gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory"); + *minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG; + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + prf_out->length = dol; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + input.length = prf_in->length + 4; + input.data = malloc(prf_in->length + 4); + if (input.data == NULL) { + _gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory"); + *minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG; + gss_release_buffer(&junk, prf_out); + krb5_crypto_destroy(context, crypto); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_FAILURE; + } + memcpy(((uint8_t *)input.data) + 4, prf_in->value, prf_in->length); + + num = 0; + p = prf_out->value; + while(dol > 0) { + size_t tsize; + + _gss_mg_encode_be_uint32(num, input.data); + + ret = krb5_crypto_prf(context, crypto, &input, &output); + if (ret) { + *minor_status = ret; + free(input.data); + gss_release_buffer(&junk, prf_out); + krb5_crypto_destroy(context, crypto); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_FAILURE; + } + + tsize = min(dol, output.length); + memcpy(p, output.data, tsize); + p += tsize; + dol -= tsize; + krb5_data_free(&output); + num++; + } + free(input.data); + + krb5_crypto_destroy(context, crypto); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/process_context_token.c b/third_party/heimdal/lib/gssapi/krb5/process_context_token.c new file mode 100644 index 0000000..601b0e8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/process_context_token.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_process_context_token ( + OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer + ) +{ + krb5_context context; + OM_uint32 ret = GSS_S_FAILURE; + gss_buffer_desc empty_buffer; + + empty_buffer.length = 0; + empty_buffer.value = NULL; + + GSSAPI_KRB5_INIT (&context); + + ret = _gsskrb5_verify_mic_internal(minor_status, + (gsskrb5_ctx)context_handle, + context, + token_buffer, &empty_buffer, + GSS_C_QOP_DEFAULT, + "\x01\x02"); + + if (ret == GSS_S_COMPLETE) + ret = _gsskrb5_delete_sec_context(minor_status, + rk_UNCONST(&context_handle), + GSS_C_NO_BUFFER); + if (ret == GSS_S_COMPLETE) + *minor_status = 0; + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/release_buffer.c b/third_party/heimdal/lib/gssapi/krb5/release_buffer.c new file mode 100644 index 0000000..b704e00 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_buffer.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1997 - 2000, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 _gsskrb5_release_buffer + (OM_uint32 * minor_status, + gss_buffer_t buffer + ) +{ + *minor_status = 0; + free (buffer->value); + buffer->value = NULL; + buffer->length = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/release_cred.c b/third_party/heimdal/lib/gssapi/krb5/release_cred.c new file mode 100644 index 0000000..e1bb870 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_cred.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_release_cred + (OM_uint32 * minor_status, + gss_cred_id_t * cred_handle + ) +{ + krb5_context context; + gsskrb5_cred cred; + OM_uint32 junk; + + *minor_status = 0; + + if (*cred_handle == NULL) + return GSS_S_COMPLETE; + + cred = (gsskrb5_cred)*cred_handle; + *cred_handle = GSS_C_NO_CREDENTIAL; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + free(cred->destination_realm); + if (cred->principal != NULL) + krb5_free_principal(context, cred->principal); + if (cred->keytab != NULL) + krb5_kt_close(context, cred->keytab); + if (cred->ccache != NULL) { + if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) + krb5_cc_destroy(context, cred->ccache); + else + krb5_cc_close(context, cred->ccache); + } + gss_release_oid_set(&junk, &cred->mechanisms); + if (cred->enctypes) + free(cred->enctypes); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + HEIMDAL_MUTEX_destroy(&cred->cred_id_mutex); + memset(cred, 0, sizeof(*cred)); + free(cred); + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/release_name.c b/third_party/heimdal/lib/gssapi/krb5/release_name.c new file mode 100644 index 0000000..57fc8a4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_name.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_release_name + (OM_uint32 * minor_status, + gss_name_t * input_name + ) +{ + krb5_context context; + krb5_principal name = (krb5_principal)*input_name; + + *minor_status = 0; + + GSSAPI_KRB5_INIT (&context); + + *input_name = GSS_C_NO_NAME; + + krb5_free_principal(context, name); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/sequence.c b/third_party/heimdal/lib/gssapi/krb5/sequence.c new file mode 100644 index 0000000..2e0e7b2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/sequence.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#define DEFAULT_JITTER_WINDOW 20 + +struct gss_msg_order { + OM_uint32 flags; + OM_uint32 start; + OM_uint32 length; + OM_uint32 jitter_window; + OM_uint32 first_seq; + OM_uint32 elem[1]; +}; + + +/* + * + */ + +static OM_uint32 +msg_order_alloc(OM_uint32 *minor_status, + struct gss_msg_order **o, + OM_uint32 jitter_window) +{ + size_t len; + + len = jitter_window * sizeof((*o)->elem[0]); + len += sizeof(**o); + len -= sizeof((*o)->elem[0]); + + *o = calloc(1, len); + if (*o == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * + */ + +OM_uint32 +_gssapi_msg_order_create(OM_uint32 *minor_status, + struct gss_msg_order **o, + OM_uint32 flags, + OM_uint32 seq_num, + OM_uint32 jitter_window, + int use_64) +{ + OM_uint32 ret; + + if (jitter_window == 0) + jitter_window = DEFAULT_JITTER_WINDOW; + + ret = msg_order_alloc(minor_status, o, jitter_window); + if(ret != GSS_S_COMPLETE) + return ret; + + (*o)->flags = flags; + (*o)->length = 0; + (*o)->first_seq = seq_num; + (*o)->jitter_window = jitter_window; + (*o)->elem[0] = seq_num - 1; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_msg_order_destroy(struct gss_msg_order **m) +{ + free(*m); + *m = NULL; + return GSS_S_COMPLETE; +} + +static void +elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val) +{ + o->elem[slot % o->jitter_window] = val; +} + +static void +elem_insert(struct gss_msg_order *o, + unsigned int after_slot, + OM_uint32 seq_num) +{ + assert(o->jitter_window > after_slot); + + if (o->length > after_slot) + memmove(&o->elem[after_slot + 1], &o->elem[after_slot], + (o->length - after_slot - 1) * sizeof(o->elem[0])); + + elem_set(o, after_slot, seq_num); + + if (o->length < o->jitter_window) + o->length++; +} + +/* rule 1: expected sequence number */ +/* rule 2: > expected sequence number */ +/* rule 3: seqnum < seqnum(first) */ +/* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */ + +OM_uint32 +_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num) +{ + OM_uint32 r; + size_t i; + + if (o == NULL) + return GSS_S_COMPLETE; + + if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0) + return GSS_S_COMPLETE; + + /* check if the packet is the next in order */ + if (o->elem[0] == seq_num - 1) { + elem_insert(o, 0, seq_num); + return GSS_S_COMPLETE; + } + + r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG; + + /* sequence number larger then largest sequence number + * or smaller then the first sequence number */ + if (seq_num > o->elem[0] + || seq_num < o->first_seq + || o->length == 0) + { + elem_insert(o, 0, seq_num); + if (r) { + return GSS_S_COMPLETE; + } else { + return GSS_S_GAP_TOKEN; + } + } + + assert(o->length > 0); + + /* sequence number smaller the first sequence number */ + if (seq_num < o->elem[o->length - 1]) { + if (r) + return(GSS_S_OLD_TOKEN); + else + return(GSS_S_UNSEQ_TOKEN); + } + + if (seq_num == o->elem[o->length - 1]) { + return GSS_S_DUPLICATE_TOKEN; + } + + for (i = 0; i < o->length - 1; i++) { + if (o->elem[i] == seq_num) + return GSS_S_DUPLICATE_TOKEN; + if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) { + elem_insert(o, i, seq_num); + if (r) + return GSS_S_COMPLETE; + else + return GSS_S_UNSEQ_TOKEN; + } + } + + return GSS_S_FAILURE; +} + +OM_uint32 +_gssapi_msg_order_f(OM_uint32 flags) +{ + return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG); +} + +/* + * Translate `o` into inter-process format and export in to `sp'. + */ + +krb5_error_code +_gssapi_msg_order_export(krb5_storage *sp, struct gss_msg_order *o) +{ + krb5_error_code kret; + OM_uint32 i; + + kret = krb5_store_int32(sp, o->flags); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->start); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->length); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->jitter_window); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->first_seq); + if (kret) + return kret; + + for (i = 0; i < o->jitter_window; i++) { + kret = krb5_store_int32(sp, o->elem[i]); + if (kret) + return kret; + } + + return 0; +} + +OM_uint32 +_gssapi_msg_order_import(OM_uint32 *minor_status, + krb5_storage *sp, + struct gss_msg_order **o) +{ + OM_uint32 ret; + krb5_error_code kret; + int32_t i, flags, start, length, jitter_window, first_seq; + + kret = krb5_ret_int32(sp, &flags); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &start); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &length); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &jitter_window); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &first_seq); + if (kret) + goto failed; + + ret = msg_order_alloc(minor_status, o, jitter_window); + if (ret != GSS_S_COMPLETE) + return ret; + + (*o)->flags = flags; + (*o)->start = start; + (*o)->length = length; + (*o)->jitter_window = jitter_window; + (*o)->first_seq = first_seq; + + for( i = 0; i < jitter_window; i++ ) { + kret = krb5_ret_int32(sp, (int32_t*)&((*o)->elem[i])); + if (kret) + goto failed; + } + + *minor_status = 0; + return GSS_S_COMPLETE; + +failed: + _gssapi_msg_order_destroy(o); + *minor_status = kret; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c b/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c new file mode 100644 index 0000000..ef177a0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static OM_uint32 +import_cred(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + OM_uint32 major_stat; + krb5_error_code ret; + krb5_principal keytab_principal = NULL; + krb5_keytab keytab = NULL; + krb5_storage *sp = NULL; + krb5_ccache id = NULL; + char *str; + + if (cred_handle == NULL || *cred_handle != GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + sp = krb5_storage_from_mem(value->value, value->length); + if (sp == NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + /* credential cache name */ + ret = krb5_ret_string(sp, &str); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + if (str[0]) { + ret = krb5_cc_resolve(context, str, &id); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + } + free(str); + str = NULL; + + /* keytab principal name */ + ret = krb5_ret_string(sp, &str); + if (ret == 0 && str[0]) + ret = krb5_parse_name(context, str, &keytab_principal); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + free(str); + str = NULL; + + /* keytab principal */ + ret = krb5_ret_string(sp, &str); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + if (str[0]) { + ret = krb5_kt_resolve(context, str, &keytab); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + } + free(str); + str = NULL; + + major_stat = _gsskrb5_krb5_import_cred(minor_status, &id, keytab_principal, + keytab, cred_handle); +out: + if (id) + krb5_cc_close(context, id); + if (keytab_principal) + krb5_free_principal(context, keytab_principal); + if (keytab) + krb5_kt_close(context, keytab); + if (str) + free(str); + if (sp) + krb5_storage_free(sp); + + return major_stat; +} + + +static OM_uint32 +allowed_enctypes(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + OM_uint32 major_stat; + krb5_error_code ret; + size_t len, i; + krb5_enctype *enctypes = NULL; + krb5_storage *sp = NULL; + gsskrb5_cred cred; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + cred = (gsskrb5_cred)*cred_handle; + + if ((value->length % 4) != 0) { + *minor_status = 0; + major_stat = GSS_S_FAILURE; + goto out; + } + + /* serialized as int32_t[], but stored as krb5_enctype[] */ + len = value->length / 4; + enctypes = malloc((len + 1) * sizeof(krb5_enctype)); + if (enctypes == NULL) { + *minor_status = ENOMEM; + major_stat = GSS_S_FAILURE; + goto out; + } + + sp = krb5_storage_from_mem(value->value, value->length); + if (sp == NULL) { + *minor_status = ENOMEM; + major_stat = GSS_S_FAILURE; + goto out; + } + + for (i = 0; i < len; i++) { + int32_t e; + + ret = krb5_ret_int32(sp, &e); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + enctypes[i] = e; + } + enctypes[i] = KRB5_ENCTYPE_NULL; + + if (cred->enctypes) + free(cred->enctypes); + cred->enctypes = enctypes; + + krb5_storage_free(sp); + + return GSS_S_COMPLETE; + +out: + if (sp) + krb5_storage_free(sp); + if (enctypes) + free(enctypes); + + return major_stat; +} + +static OM_uint32 +no_ci_flags(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + gsskrb5_cred cred; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + cred = (gsskrb5_cred)*cred_handle; + cred->cred_flags |= GSS_CF_NO_CI_FLAGS; + + *minor_status = 0; + return GSS_S_COMPLETE; + +} + + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_cred_option + (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + krb5_context context; + + GSSAPI_KRB5_INIT (&context); + + if (value == GSS_C_NO_BUFFER) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_CRED_X)) + return import_cred(minor_status, context, cred_handle, value); + + if (gss_oid_equal(desired_object, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X)) + return allowed_enctypes(minor_status, context, cred_handle, value); + + if (gss_oid_equal(desired_object, GSS_KRB5_CRED_NO_CI_FLAGS_X)) { + return no_ci_flags(minor_status, context, cred_handle, value); + } + + + *minor_status = EINVAL; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c b/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c new file mode 100644 index 0000000..3a6f86b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * glue routine for _gsskrb5_inquire_sec_context_by_oid + */ + +#include "gsskrb5_locl.h" + +static OM_uint32 +get_bool(OM_uint32 *minor_status, + const gss_buffer_t value, + int *flag) +{ + if (value->value == NULL || value->length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + *flag = *((const char *)value->value) != 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_string(OM_uint32 *minor_status, + const gss_buffer_t value, + char **str) +{ + if (value == NULL || value->length == 0) { + *str = NULL; + } else { + *str = malloc(value->length + 1); + if (*str == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + memcpy(*str, value->value, value->length); + (*str)[value->length] = '\0'; + } + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 *ret) +{ + *minor_status = 0; + if (value == NULL || value->length == 0) + *ret = 0; + else if (value->length == sizeof(*ret)) + memcpy(ret, value->value, sizeof(*ret)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +set_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 set) +{ + *minor_status = 0; + if (value->length == sizeof(set)) + memcpy(value->value, &set, sizeof(set)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +/* + * GSS_KRB5_IMPORT_RFC4121_CONTEXT_X is an internal, private interface + * to allow SAnon to create a skeletal context for using RFC4121 message + * protection services. + * + * rfc4121_args ::= initiator_flag || flags || enctype || session key + */ +static OM_uint32 +make_rfc4121_context(OM_uint32 *minor, + krb5_context context, + gss_ctx_id_t *context_handle, + gss_const_buffer_t rfc4121_args) +{ + OM_uint32 major = GSS_S_FAILURE, tmp; + krb5_error_code ret; + krb5_storage *sp = NULL; + gsskrb5_ctx ctx = NULL; + uint8_t initiator_flag; + int32_t enctype; + size_t keysize; + krb5_keyblock *key; + + *minor = 0; + + sp = krb5_storage_from_readonly_mem(rfc4121_args->value, rfc4121_args->length); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + ret = ENOMEM; + goto out; + } + + ret = krb5_ret_uint8(sp, &initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_ret_uint32(sp, &ctx->flags); + if (ret != 0) + goto out; + + ctx->more_flags = IS_CFX | ACCEPTOR_SUBKEY | OPEN; + if (initiator_flag) + ctx->more_flags |= LOCAL; + + ctx->state = initiator_flag ? INITIATOR_READY : ACCEPTOR_READY; + + ret = krb5_ret_int32(sp, &enctype); + if (ret != 0) + goto out; + + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret != 0) + goto out; + + ctx->auth_context = calloc(1, sizeof(*ctx->auth_context)); + if (ctx->auth_context == NULL) { + ret = ENOMEM; + goto out; + } + + key = calloc(1, sizeof(*key)); + if (key == NULL) { + ret = ENOMEM; + goto out; + } + if (initiator_flag) + ctx->auth_context->remote_subkey = key; + else + ctx->auth_context->local_subkey = key; + + key->keytype = enctype; + key->keyvalue.data = malloc(keysize); + if (key->keyvalue.data == NULL) { + ret = ENOMEM; + goto out; + } + + if (krb5_storage_read(sp, key->keyvalue.data, keysize) != keysize) { + ret = EINVAL; + goto out; + } + key->keyvalue.length = keysize; + + ret = krb5_crypto_init(context, key, 0, &ctx->crypto); + if (ret != 0) + goto out; + + major = _gssapi_msg_order_create(minor, &ctx->order, + _gssapi_msg_order_f(ctx->flags), + 0, 0, 1); + if (major != GSS_S_COMPLETE) + goto out; + +out: + krb5_storage_free(sp); + + if (major != GSS_S_COMPLETE) { + if (*minor == 0) + *minor = ret; + _gsskrb5_delete_sec_context(&tmp, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + } else { + *context_handle = (gss_ctx_id_t)ctx; + } + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_sec_context_option + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + krb5_context context; + OM_uint32 maj_stat; + + GSSAPI_KRB5_INIT (&context); + + if (value == GSS_C_NO_BUFFER) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) { + gsskrb5_ctx ctx; + int flag; + + if (*context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + + maj_stat = get_bool(minor_status, value, &flag); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + ctx = (gsskrb5_ctx)*context_handle; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (flag) + ctx->more_flags |= COMPAT_OLD_DES3; + else + ctx->more_flags &= ~COMPAT_OLD_DES3; + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) { + int flag; + + maj_stat = get_bool(minor_status, value, &flag); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + krb5_set_dns_canonicalize_hostname(context, flag); + return GSS_S_COMPLETE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) { + char *str; + + maj_stat = get_string(minor_status, value, &str); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + maj_stat = _gsskrb5_register_acceptor_identity(minor_status, str); + free(str); + + return maj_stat; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) { + char *str; + + maj_stat = get_string(minor_status, value, &str); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + if (str == NULL) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_READ; + } + + krb5_set_default_realm(context, str); + free(str); + + *minor_status = 0; + return GSS_S_COMPLETE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) { + + *minor_status = EINVAL; + return GSS_S_FAILURE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) { + OM_uint32 offset; + time_t t; + + maj_stat = get_int32(minor_status, value, &offset); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + t = time(NULL) + offset; + + krb5_set_real_time(context, t, 0); + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) { + krb5_timestamp sec; + int32_t usec; + time_t t; + + t = time(NULL); + + krb5_us_timeofday (context, &sec, &usec); + + maj_stat = set_int32(minor_status, value, sec - t); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_PLUGIN_REGISTER_X)) { + struct gsskrb5_krb5_plugin c; + + if (value->length != sizeof(c)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + memcpy(&c, value->value, sizeof(c)); + krb5_plugin_register(context, c.type, c.name, c.symbol); + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) { + struct gsskrb5_ccache_name_args *args = value->value; + + if (value->length != sizeof(*args)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + return _gsskrb5_krb5_ccache_name(minor_status, args->name, &args->out_name); + } else if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_RFC4121_CONTEXT_X)) { + return make_rfc4121_context(minor_status, context, context_handle, value); + } + + *minor_status = EINVAL; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/store_cred.c b/third_party/heimdal/lib/gssapi/krb5/store_cred.c new file mode 100644 index 0000000..6d727b4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/store_cred.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +static int +same_princ(krb5_context context, krb5_ccache id1, krb5_ccache id2) +{ + krb5_error_code ret; + krb5_principal p1 = NULL; + krb5_principal p2 = NULL; + int same = 0; + + ret = krb5_cc_get_principal(context, id1, &p1); + if (ret == 0) + ret = krb5_cc_get_principal(context, id2, &p2); + /* If either principal is absent, it's the same for our purposes */ + same = ret ? 1 : krb5_principal_compare(context, p1, p2); + krb5_free_principal(context, p1); + krb5_free_principal(context, p2); + return same; +} + +static OM_uint32 +add_env(OM_uint32 *minor, + gss_buffer_set_t *env, + const char *var, + const char *val) +{ + OM_uint32 major; + gss_buffer_desc b; + char *varval = NULL; + + if (asprintf(&varval, "%s=%s", var, val) == -1 || varval == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + b.value = varval; + b.length = strlen(varval) + 1; + major = gss_add_buffer_set_member(minor, &b, env); + free(varval); + return major; +} + +static OM_uint32 +set_proc(OM_uint32 *minor, gss_buffer_set_t env) +{ + /* + * XXX On systems with setpag(), call setpag(). On WIN32... create a + * session, set the access token, ...? + */ +#ifndef WIN32 + size_t i; + + for (i = 0; i < env->count; i++) + putenv(env->elements[i].value); +#endif + return GSS_S_COMPLETE; +} + +/* + * A principal is the best principal for a user IFF + * + * - it has one component + * - the one component is the same as the user's name + * - the real is the user_realm from configuration + */ +static int +principal_is_best_for_user(krb5_context context, + const char *app, + krb5_const_principal p, + const char *user) +{ + char *default_realm = NULL; + char *user_realm = NULL; + int ret; + + (void) krb5_get_default_realm(context, &default_realm); + krb5_appdefault_string(context, app, NULL, "user_realm", default_realm, + &user_realm); + ret = user_realm && + krb5_principal_get_num_comp(context, p) == 1 && + strcmp(user_realm, krb5_principal_get_realm(context, p)) == 0 && + (!user || + strcmp(user, krb5_principal_get_comp_string(context, p, 0)) == 0); + free(default_realm); + free(user_realm); + return ret; +} + +static krb5_error_code +check_destination_tgt_policy(krb5_context context, + const char *appname, + gsskrb5_cred input_cred) +{ + krb5_error_code ret; + krb5_boolean want_dst_tgt = 0; + krb5_data v; + + if (input_cred->destination_realm == NULL) + /* + * Not a delegated credential, so we can't check the destination TGT + * policy for the realm of the service -- we don't know the realm of + * the service. + */ + return 0; + + krb5_appdefault_boolean(context, appname, input_cred->destination_realm, + "require_delegate_destination_tgt", FALSE, + &want_dst_tgt); + if (!want_dst_tgt) + return 0; + + krb5_data_zero(&v); + ret = krb5_cc_get_config(context, input_cred->ccache, NULL, + "start_realm", &v); + if (ret == 0 && + v.length != strlen(input_cred->destination_realm)) + ret = KRB5_CC_NOTFOUND; + if (ret == 0 && + strncmp(input_cred->destination_realm, v.data, v.length) != 0) + ret = KRB5_CC_NOTFOUND; + if (ret) + krb5_set_error_message(context, ret, + "Delegated TGT is not a destination TGT for " + "realm \"%s\" but for \"%.*s\"", + input_cred->destination_realm, + (int)(v.length ? v.length : sizeof("") - 1), + v.data ? (const char *)v.data : ""); + krb5_data_free(&v); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_store_cred_into2(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored, + gss_buffer_set_t *envp) +{ + krb5_context context; + krb5_error_code ret; + gsskrb5_cred input_cred; + krb5_ccache id = NULL; + time_t exp_current; + time_t exp_new; + gss_buffer_set_t env = GSS_C_NO_BUFFER_SET; + const char *cs_unique_ccache = NULL; + const char *cs_ccache_name = NULL; + const char *cs_user_name = NULL; + const char *cs_app_name = NULL; + char *ccache_name = NULL; + OM_uint32 major_status = GSS_S_FAILURE; + OM_uint32 junk; + OM_uint32 overwrite_cred = store_cred_flags & GSS_C_STORE_CRED_OVERWRITE; + int default_for = 0; + + *minor_status = 0; + + /* Sanity check inputs */ + if (cred_usage != GSS_C_INITIATE) { + /* It'd be nice if we could also do accept, writing a keytab */ + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + if (desired_mech != GSS_C_NO_OID && + gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) + return GSS_S_BAD_MECH; + if (input_cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_CALL_INACCESSIBLE_READ; + input_cred = (gsskrb5_cred)input_cred_handle; + + /* Sanity check the input_cred */ + if (input_cred->usage != cred_usage && input_cred->usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_NO_CRED; + } + if (input_cred->principal == NULL) { + *minor_status = GSS_KRB5_S_KG_TGT_MISSING; + return GSS_S_NO_CRED; + } + + /* Extract the ccache name from the store if given */ + if (cred_store != GSS_C_NO_CRED_STORE) { + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "unique_ccache_type", + &cs_unique_ccache); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "ccache", &cs_ccache_name); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "username", &cs_user_name); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "appname", &cs_app_name); + if (GSS_ERROR(major_status)) + return major_status; + } + + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&input_cred->cred_id_mutex); + + if (cs_ccache_name && strchr(cs_ccache_name, '%')) { + ret = _krb5_expand_default_cc_name(context, cs_ccache_name, + &ccache_name); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + return GSS_S_FAILURE; + } + cs_ccache_name = ccache_name; + } + + /* More sanity checking of the input_cred (good to fail early) */ + ret = krb5_cc_get_lifetime(context, input_cred->ccache, &exp_new); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return GSS_S_NO_CRED; + } + + ret = check_destination_tgt_policy(context, cs_app_name, input_cred); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return GSS_S_NO_CRED; + } + + /* + * Find an appropriate ccache, which will be one of: + * + * - the one given in the cred_store, if given + * - a new unique one for some ccache type in the cred_store, if given + * - a subsidiary cache named for the principal in the default collection, + * if the principal is the "best principal for the user" + * - the default ccache + */ + if (cs_ccache_name) { + ret = krb5_cc_resolve(context, cs_ccache_name, &id); + } else if (cs_unique_ccache) { + overwrite_cred = 1; + ret = krb5_cc_new_unique(context, cs_unique_ccache, NULL, &id); + } else if (principal_is_best_for_user(context, cs_app_name, + input_cred->principal, + cs_user_name)) { + ret = krb5_cc_default(context, &id); + if (ret == 0 && !same_princ(context, id, input_cred->ccache)) { + krb5_cc_close(context, id); + ret = krb5_cc_default_for(context, input_cred->principal, &id); + default_for = 1; + } + } else { + ret = krb5_cc_default_for(context, input_cred->principal, &id); + default_for = 1; + } + + if (ret || id == NULL) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return ret == 0 ? GSS_S_NO_CRED : GSS_S_FAILURE; + } + + /* + * If we're using a subsidiary ccache for this principal and it has some + * other principal's tickets in it -> overwrite. + */ + if (!overwrite_cred && default_for && + !same_princ(context, id, input_cred->ccache)) + overwrite_cred = 1; + if (!overwrite_cred && same_princ(context, id, input_cred->ccache)) { + /* + * If current creds are for the same princ as we already had creds for, + * and the new creds live longer than the old, overwrite. + */ + ret = krb5_cc_get_lifetime(context, id, &exp_current); + if (ret != 0 || exp_new > exp_current) + overwrite_cred = 1; + } + + if (overwrite_cred) { + ret = krb5_cc_initialize(context, id, input_cred->principal); + if (ret == 0) + ret = krb5_cc_copy_match_f(context, input_cred->ccache, id, NULL, NULL, + NULL); + } + + if ((store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) && envp == NULL) + envp = &env; + if (envp != NULL) { + char *fullname = NULL; + + if ((ret = krb5_cc_get_full_name(context, id, &fullname)) == 0) { + major_status = add_env(minor_status, envp, "KRB5CCNAME", fullname); + free(fullname); + if (major_status) + ret = *minor_status; + } + } + (void) krb5_cc_close(context, id); + + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + if (ret == 0 && (store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) && + (major_status = set_proc(minor_status, *envp)) != GSS_S_COMPLETE) + ret = *minor_status; + (void) gss_release_buffer_set(&junk, &env); + free(ccache_name); + *minor_status = ret; + return ret ? major_status : GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_store_cred_into(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + OM_uint32 store_cred_flags = + (overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) | + (default_cred ? GSS_C_STORE_CRED_DEFAULT : 0); + + return _gsskrb5_store_cred_into2(minor_status, input_cred_handle, + cred_usage, desired_mech, + store_cred_flags, cred_store, + elements_stored, cred_usage_stored, NULL); +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c new file mode 100644 index 0000000..812fce6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include + +static void +print_time(OM_uint32 time_rec) +{ + if (time_rec == GSS_C_INDEFINITE) { + printf("cred never expire\n"); + } else { + time_t t = time_rec + time(NULL); + printf("expiration time: %s", ctime(&t)); + } +} + +static void +test_add(gss_cred_id_t cred_handle) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t copy_cred; + OM_uint32 time_rec; + + major_status = gss_add_cred (&minor_status, + cred_handle, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_INITIATE, + 0, + 0, + ©_cred, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major_status)) + errx(1, "add_cred failed"); + + print_time(time_rec); + + major_status = gss_release_cred(&minor_status, + ©_cred); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} + +static void +test_add_mutate(gss_cred_id_t cred_handle) +{ + OM_uint32 major_status, minor_status; + OM_uint32 time_rec; + + major_status = gss_add_cred (&minor_status, + cred_handle, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_INITIATE, + 0, + 0, + NULL, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major_status)) + errx(1, "add_cred failed"); + + print_time(time_rec); +} + +static void +copy_cred(void) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + + major_status = gss_acquire_cred(&minor_status, + GSS_C_NO_NAME, + 0, + NULL, + GSS_C_INITIATE, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) + errx(1, "acquire_cred failed"); + + print_time(time_rec); + + test_add(cred_handle); + test_add(cred_handle); + test_add(cred_handle); + test_add_mutate(cred_handle); + + major_status = gss_release_cred(&minor_status, + &cred_handle); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} + +static void +acquire_cred_service(const char *service) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + gss_buffer_desc name_buffer; + gss_name_t name; + + name_buffer.value = rk_UNCONST(service); + name_buffer.length = strlen(service); + + major_status = gss_import_name(&minor_status, + &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (GSS_ERROR(major_status)) + errx(1, "import_name failed"); + + + major_status = gss_acquire_cred(&minor_status, + name, + 0, + NULL, + GSS_C_ACCEPT, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) + errx(1, "acquire_cred failed"); + + print_time(time_rec); + + major_status = gss_release_cred(&minor_status, + &cred_handle); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); + + + major_status = gss_release_name(&minor_status, + &name); + if (GSS_ERROR(major_status)) + errx(1, "release_name failed"); + +} + +int +main(int argc, char **argv) +{ + copy_cred(); + + acquire_cred_service("host@xen2-heimdal-linux.lab.it.su.se"); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_cfx.c b/third_party/heimdal/lib/gssapi/krb5/test_cfx.c new file mode 100644 index 0000000..15f853c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_cfx.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +struct range { + size_t lower; + size_t upper; +}; + +struct range tests[] = { + { 0, 1040 }, + { 2040, 2080 }, + { 4080, 5000 }, + { 8180, 8292 }, + { 9980, 10010 } +}; + +static void +test_range(const struct range *r, int integ, + krb5_context context, krb5_crypto crypto) +{ + krb5_error_code ret; + size_t size, rsize; + struct gsskrb5_ctx ctx; + + for (size = r->lower; size < r->upper; size++) { + size_t cksumsize; + uint16_t padsize; + OM_uint32 minor; + OM_uint32 max_wrap_size; + + ctx.crypto = crypto; + + ret = _gssapi_wrap_size_cfx(&minor, + &ctx, + context, + integ, + 0, + size, + &max_wrap_size); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + if (max_wrap_size == 0) + continue; + + ret = _gsskrb5cfx_wrap_length_cfx(context, + crypto, + integ, + 0, + max_wrap_size, + &rsize, &cksumsize, &padsize); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_wrap_length_cfx: %d", ret); + + if (size < rsize) + krb5_errx(context, 1, + "size (%d) < rsize (%d) for max_wrap_size %d", + (int)size, (int)rsize, (int)max_wrap_size); + } +} + +static void +test_special(krb5_context context, krb5_crypto crypto, + int integ, size_t testsize) +{ + krb5_error_code ret; + size_t rsize; + OM_uint32 max_wrap_size; + size_t cksumsize; + uint16_t padsize; + struct gsskrb5_ctx ctx; + OM_uint32 minor; + + ctx.crypto = crypto; + + ret = _gssapi_wrap_size_cfx(&minor, + &ctx, + context, + integ, + 0, + testsize, + &max_wrap_size); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + + ret = _gsskrb5cfx_wrap_length_cfx(context, + crypto, + integ, + 0, + max_wrap_size, + &rsize, &cksumsize, &padsize); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_wrap_length_cfx: %d", ret); + + if (testsize < rsize) + krb5_errx(context, 1, + "testsize (%d) < rsize (%d) for max_wrap_size %d", + (int)testsize, (int)rsize, (int)max_wrap_size); +} + + + + +int +main(int argc, char **argv) +{ + krb5_keyblock keyblock; + krb5_error_code ret; + krb5_context context; + krb5_crypto crypto; + int i; + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_context_init: %d", ret); + + ret = krb5_generate_random_keyblock(context, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + &keyblock); + if (ret) + krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); + + ret = krb5_crypto_init(context, &keyblock, 0, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init"); + + test_special(context, crypto, 1, 60); + test_special(context, crypto, 0, 60); + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + test_range(&tests[i], 1, context, crypto); + test_range(&tests[i], 0, context, crypto); + } + + krb5_free_keyblock_contents(context, &keyblock); + krb5_crypto_destroy(context, crypto); + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_cred.c b/third_party/heimdal/lib/gssapi/krb5/test_cred.c new file mode 100644 index 0000000..e0395f0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_cred.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2003-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include +#include + +static void +gss_print_errors (int min_stat) +{ + OM_uint32 new_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + OM_uint32 ret; + + do { + ret = gss_display_status (&new_stat, + min_stat, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + fprintf (stderr, "%.*s\n", (int)status_string.length, + (char *)status_string.value); + gss_release_buffer (&new_stat, &status_string); + } while (!GSS_ERROR(ret) && msg_ctx != 0); +} + +static void +gss_err(int exitval, int status, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx (fmt, args); + gss_print_errors (status); + va_end(args); + exit (exitval); +} + +static void +acquire_release_loop(gss_name_t name, int counter, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred; + int i; + + for (i = 0; i < counter; i++) { + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + } +} + + +static void +acquire_add_release_add(gss_name_t name, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred, cred2, cred3; + + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred2, + NULL, + NULL, + NULL); + + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred2, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_BOTH, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred3, + NULL, + NULL, + NULL); + + maj_stat = gss_release_cred(&min_stat, &cred2); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred3); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); +} + +static void +add_add_release_add(gss_name_t name, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred, cred2; + + maj_stat = gss_add_cred(&min_stat, + GSS_C_NO_CREDENTIAL, + name, + GSS_KRB5_MECHANISM, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred, + NULL, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred2, + NULL, + NULL, + NULL); + + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred2, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_BOTH, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + NULL, + NULL, + NULL, + NULL); + + maj_stat = gss_release_cred(&min_stat, &cred2); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); +} + +static int version_flag = 0; +static int help_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + + +int +main(int argc, char **argv) +{ + struct gss_buffer_desc_struct name_buffer; + OM_uint32 maj_stat, min_stat; + gss_name_t name; + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc < 1) + errx(1, "argc < 1"); + + name_buffer.value = argv[0]; + name_buffer.length = strlen(argv[0]); + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import name error"); + + acquire_release_loop(name, 100, GSS_C_ACCEPT); + acquire_release_loop(name, 100, GSS_C_INITIATE); + acquire_release_loop(name, 100, GSS_C_BOTH); + + acquire_add_release_add(name, GSS_C_ACCEPT); + acquire_add_release_add(name, GSS_C_INITIATE); + acquire_add_release_add(name, GSS_C_BOTH); + + add_add_release_add(name, GSS_C_ACCEPT); + add_add_release_add(name, GSS_C_INITIATE); + add_add_release_add(name, GSS_C_BOTH); + + gss_release_name(&min_stat, &name); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_kcred.c b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c new file mode 100644 index 0000000..c90a144 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include +#include + +static int version_flag = 0; +static int help_flag = 0; + +static void +copy_import(void) +{ + gss_cred_id_t cred1, cred2; + OM_uint32 maj_stat, min_stat; + gss_name_t name1, name2; + OM_uint32 lifetime1, lifetime2; + gss_cred_usage_t usage1, usage2; + gss_OID_set mechs1, mechs2; + krb5_ccache id; + krb5_error_code ret; + krb5_context context; + int equal; + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_INITIATE, + &cred1, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_acquire_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred1, &name1, &lifetime1, + &usage1, &mechs1); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred"); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context"); + + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_new_unique"); + + maj_stat = gss_krb5_copy_ccache(&min_stat, context, cred1, id); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_copy_ccache"); + + maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &cred2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_import_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2, + &usage2, &mechs2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred 2"); + + maj_stat = gss_compare_name(&min_stat, name1, name2, &equal); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_compare_name"); + if (!equal) + errx(1, "names not equal"); + + /* This check is racy! */ + if (getenv("TESTS_ENVIRONMENT") == NULL) && lifetime1 != lifetime2) + errx(1, "lifetime not equal"); + if (lifetime1 != lifetime2) + warnx("lifetime not equal"); + + if (usage1 != usage1) + errx(1, "usage not equal"); + + gss_release_cred(&min_stat, &cred1); + gss_release_cred(&min_stat, &cred2); + + gss_release_name(&min_stat, &name1); + gss_release_name(&min_stat, &name2); + +#if 0 + compare(mechs1, mechs2); +#endif + + gss_release_oid_set(&min_stat, &mechs1); + gss_release_oid_set(&min_stat, &mechs2); + + krb5_cc_destroy(context, id); + krb5_free_context(context); +} + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + copy_import(); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_oid.c b/third_party/heimdal/lib/gssapi/krb5/test_oid.c new file mode 100644 index 0000000..00219b9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_oid.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +int +main(int argc, char **argv) +{ + OM_uint32 minor_status, maj_stat; + gss_buffer_desc data; + int ret; + + maj_stat = gss_oid_to_str(&minor_status, GSS_KRB5_MECHANISM, &data); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_oid_to_str failed"); + ret = strncmp(data.value, "1 2 840 113554 1 2 2", data.length); + gss_release_buffer(&maj_stat, &data); + if (ret) + return 1; + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_sequence.c b/third_party/heimdal/lib/gssapi/krb5/test_sequence.c new file mode 100644 index 0000000..33a4aac --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_sequence.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* correct ordering */ +OM_uint32 pattern1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 +}; + +/* gap 10 */ +OM_uint32 pattern2[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13 +}; + +/* dup 9 */ +OM_uint32 pattern3[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13 +}; + +/* gaps */ +OM_uint32 pattern4[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 18, 100 +}; + +/* 11 before 10 */ +OM_uint32 pattern5[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 +}; + +/* long */ +OM_uint32 pattern6[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59 +}; + +/* don't start at 0 */ +OM_uint32 pattern7[] = { + 11, 12, 13 +}; + +/* wrap around */ +OM_uint32 pattern8[] = { + 4294967293U, 4294967294U, 4294967295U, 0, 1, 2 +}; + +static int +test_seq(int t, OM_uint32 flags, OM_uint32 start_seq, + OM_uint32 *pattern, int pattern_len, OM_uint32 expected_error) +{ + struct gss_msg_order *o; + OM_uint32 maj_stat, min_stat; + krb5_storage *sp; + int i; + + maj_stat = _gssapi_msg_order_create(&min_stat, &o, flags, + start_seq, 20, 0); + if (maj_stat) + errx(1, "create: %d %d", maj_stat, min_stat); + + sp = krb5_storage_emem(); + if (sp == NULL) + errx(1, "krb5_storage_from_emem"); + + _gssapi_msg_order_export(sp, o); + + for (i = 0; i < pattern_len; i++) { + maj_stat = _gssapi_msg_order_check(o, pattern[i]); + if (maj_stat) + break; + } + if (maj_stat != expected_error) { + printf("test pattern %d failed with %d (should have been %d)\n", + t, maj_stat, expected_error); + krb5_storage_free(sp); + _gssapi_msg_order_destroy(&o); + return 1; + } + + + _gssapi_msg_order_destroy(&o); + + /* try again, now with export/imported blob */ + krb5_storage_seek(sp, 0, SEEK_SET); + + maj_stat = _gssapi_msg_order_import(&min_stat, sp, &o); + if (maj_stat) + errx(1, "import: %d %d", maj_stat, min_stat); + + for (i = 0; i < pattern_len; i++) { + maj_stat = _gssapi_msg_order_check(o, pattern[i]); + if (maj_stat) + break; + } + if (maj_stat != expected_error) { + printf("import/export test pattern %d failed " + "with %d (should have been %d)\n", + t, maj_stat, expected_error); + _gssapi_msg_order_destroy(&o); + krb5_storage_free(sp); + return 1; + } + + _gssapi_msg_order_destroy(&o); + krb5_storage_free(sp); + + return 0; +} + +struct { + OM_uint32 flags; + OM_uint32 *pattern; + int pattern_len; + OM_uint32 error_code; + OM_uint32 start_seq; +} pl[] = { + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + 0 + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + }, + { + 0, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + + }, + { + GSS_C_REPLAY_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_REPLAY_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + 0 + }, + { + GSS_C_REPLAY_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_COMPLETE + }, + { + GSS_C_SEQUENCE_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + }, + { + GSS_C_SEQUENCE_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + 0 + }, + { + GSS_C_SEQUENCE_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_SEQUENCE_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + } +}; + +int +main(int argc, char **argv) +{ + int i, failed = 0; + + for (i = 0; i < sizeof(pl)/sizeof(pl[0]); i++) { + if (test_seq(i, + pl[i].flags, + pl[i].start_seq, + pl[i].pattern, + pl[i].pattern_len, + pl[i].error_code)) + failed++; + } + if (failed) + printf("FAILED %d tests\n", failed); + return failed != 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c b/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c new file mode 100644 index 0000000..df5f11d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +OM_uint32 +_gsskrb5_get_tkt_flags(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + OM_uint32 *tkt_flags) +{ + if (ctx == NULL) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (ctx->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = EINVAL; + return GSS_S_BAD_MECH; + } + + *tkt_flags = TicketFlags2int(ctx->ticket->ticket.flags); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c new file mode 100644 index 0000000..1eea68e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +unwrap_des + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p, *seq; + size_t len; + EVP_MD_CTX *md5; + u_char hash[16]; + EVP_CIPHER_CTX des_ctx; + DES_key_schedule schedule; + DES_cblock deskey; + DES_cblock zero; + size_t i; + uint32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 22 + 8 + 15; /* 45 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } + + p = input_message_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_len, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + len = (p - (u_char *)input_message_buffer->value) + + 22 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + + if (memcmp (p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\x00\x00", 2) == 0) { + cstate = 1; + } else if (memcmp (p, "\xFF\xFF", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 16; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + memset (&zero, 0, sizeof(zero)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0); + EVP_Cipher(&des_ctx, p, p, input_message_buffer->length - len); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset (&deskey, 0, sizeof(deskey)); + } + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; + } + + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, p, input_message_buffer->length - len); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (ct_memcmp (p - 8, hash, 8) != 0) { + memset_s(&deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + return GSS_S_BAD_MIC; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + seq = p; + _gss_mg_decode_be_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 24, + output_message_buffer->length); + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +unwrap_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p; + size_t len; + u_char *seq; + krb5_data seq_data; + u_char cksum[20]; + uint32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + krb5_crypto crypto; + Checksum csum; + int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 34 + 8 + 15; /* 57 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } + + p = input_message_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_len, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + len = (p - (u_char *)input_message_buffer->value) + + 34 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + + if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + return GSS_S_BAD_SIG; + p += 2; + if (ct_memcmp (p, "\x02\x00", 2) == 0) { + cstate = 1; + } else if (ct_memcmp (p, "\xff\xff", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (ct_memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 28; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + krb5_data tmp; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL, + p, input_message_buffer->length - len, &tmp); + krb5_crypto_destroy(context, crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == input_message_buffer->length - len); + + memcpy (p, tmp.data, tmp.length); + krb5_data_free(&tmp); + } + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 28; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + { + DES_cblock ivec; + + memcpy(&ivec, p + 8, 8); + ret = krb5_decrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, + &ivec); + } + krb5_crypto_destroy (context, crypto); + if (ret) { + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + seq = seq_data.data; + _gss_mg_decode_be_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* verify checksum */ + + memcpy (cksum, p + 8, 20); + + memcpy (p + 20, p - 8, 8); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = cksum; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_verify_checksum (context, crypto, + KRB5_KU_USAGE_SIGN, + p + 20, + input_message_buffer->length - len + 8, + &csum); + krb5_crypto_destroy (context, crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 36, + output_message_buffer->length); + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state + ) +{ + krb5_keyblock *key; + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx (minor_status, ctx, context, + input_message_buffer, output_message_buffer, + conf_state, qop_state); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + *minor_status = 0; + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : +#ifdef HEIM_WEAK_CRYPTO + ret = unwrap_des (minor_status, ctx, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); +#else + ret = GSS_S_FAILURE; +#endif + break; + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : + ret = unwrap_des3 (minor_status, ctx, context, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: + ret = _gssapi_unwrap_arcfour (minor_status, ctx, context, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/verify_mic.c b/third_party/heimdal/lib/gssapi/krb5/verify_mic.c new file mode 100644 index 0000000..4a776c8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/verify_mic.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +verify_mic_des + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16], *seq; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock zero; + DES_cblock deskey; + uint32_t seq_number; + OM_uint32 ret; + int cmp; + + p = token_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + p += 16; + + /* verify checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (ct_memcmp (p - 8, hash, 8) != 0) { + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + return GSS_S_BAD_MIC; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + + seq = p; + _gss_mg_decode_be_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +verify_mic_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type + ) +{ + u_char *p; + u_char *seq; + uint32_t seq_number; + OM_uint32 ret; + krb5_crypto crypto; + krb5_data seq_data; + int cmp, docompat; + Checksum csum; + char *tmp; + char ivec[8]; + + p = token_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret){ + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* verify sequence number */ + docompat = 0; +retry: + if (docompat) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + ret = krb5_decrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, ivec); + if (ret) { + if (docompat++) { + krb5_crypto_destroy (context, crypto); + *minor_status = ret; + return GSS_S_FAILURE; + } else + goto retry; + } + + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + if (docompat++) { + krb5_crypto_destroy (context, crypto); + return GSS_S_BAD_MIC; + } else + goto retry; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + seq = seq_data.data; + _gss_mg_decode_be_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + krb5_crypto_destroy (context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + krb5_crypto_destroy (context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + /* verify checksum */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + krb5_crypto_destroy (context, crypto); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = p + 8; + + krb5_crypto_destroy (context, crypto); + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_SHA1, &crypto); + if (ret == 0) + ret = krb5_verify_checksum(context, crypto, + KRB5_KU_USAGE_SIGN, + tmp, message_buffer->length + 8, + &csum); + free (tmp); + if (ret) { + krb5_crypto_destroy (context, crypto); + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + krb5_crypto_destroy (context, crypto); + return GSS_S_COMPLETE; +} + +OM_uint32 +_gsskrb5_verify_mic_internal + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + const char * type + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + + if (ctx->more_flags & IS_CFX) + return _gssapi_verify_mic_cfx (minor_status, ctx, + context, message_buffer, token_buffer, + qop_state); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + *minor_status = 0; + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : +#ifdef HEIM_WEAK_CRYPTO + ret = verify_mic_des (minor_status, ctx, context, + message_buffer, token_buffer, qop_state, key, + type); +#else + ret = GSS_S_FAILURE; +#endif + break; + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : + ret = verify_mic_des3 (minor_status, ctx, context, + message_buffer, token_buffer, qop_state, key, + type); + break; + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: + ret = _gssapi_verify_mic_arcfour (minor_status, ctx, + context, + message_buffer, token_buffer, + qop_state, key, type); + break; + default : + abort(); + } + krb5_free_keyblock (context, key); + + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_verify_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + krb5_context context; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + ret = _gsskrb5_verify_mic_internal(minor_status, + (gsskrb5_ctx)context_handle, + context, + message_buffer, token_buffer, + qop_state, (void *)(intptr_t)"\x01\x01"); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/wrap.c b/third_party/heimdal/lib/gssapi/krb5/wrap.c new file mode 100644 index 0000000..481e303 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/wrap.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +/* + * Return initiator subkey, or if that doesn't exists, the subkey. + */ + +krb5_error_code +_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + krb5_error_code ret; + *key = NULL; + + if (ctx->more_flags & LOCAL) { + ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, + key); + } else { + ret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + key); + } + if (ret == 0 && *key == NULL) + ret = krb5_auth_con_getkey(context, + ctx->auth_context, + key); + if (ret == 0 && *key == NULL) { + krb5_set_error_message(context, 0, "No initiator subkey available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return ret; +} + +krb5_error_code +_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + krb5_error_code ret; + *key = NULL; + + if (ctx->more_flags & LOCAL) { + ret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + key); + } else { + ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, + key); + } + if (ret == 0 && *key == NULL) { + krb5_set_error_message(context, 0, "No acceptor subkey available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return ret; +} + +OM_uint32 +_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + _gsskrb5i_get_acceptor_subkey(ctx, context, key); + if(*key == NULL) { + /* + * Only use the initiator subkey or ticket session key if an + * acceptor subkey was not required. + */ + if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0) + _gsskrb5i_get_initiator_subkey(ctx, context, key); + } + if (*key == NULL) { + krb5_set_error_message(context, 0, "No token key available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return 0; +} + +static OM_uint32 +sub_wrap_size ( + OM_uint32 req_output_size, + OM_uint32 * max_input_size, + int blocksize, + int extrasize + ) +{ + size_t len, total_len; + + len = 8 + req_output_size + blocksize + extrasize; + + _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + total_len -= req_output_size; /* token length */ + if (total_len < req_output_size) { + *max_input_size = (req_output_size - total_len); + (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); + } else { + *max_input_size = 0; + } + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_wrap_size_limit ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 * max_input_size + ) +{ + krb5_context context; + krb5_keyblock *key; + OM_uint32 ret; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_size_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, + req_output_size, max_input_size); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : +#ifdef HEIM_WEAK_CRYPTO + ret = sub_wrap_size(req_output_size, max_input_size, 8, 22); +#else + ret = GSS_S_FAILURE; +#endif + break; + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: + ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context, + conf_req_flag, qop_req, + req_output_size, max_input_size, key); + break; + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : + ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + *minor_status = 0; + return ret; +} + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +wrap_des + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16]; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock deskey; + DES_cblock zero; + size_t i; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 22 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 22; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x00\x00", 2); + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x00\x00", 2); + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* fill in later */ + memset (p, 0, 16); + p += 16; + + /* confounder + data + pad */ + krb5_generate_random_block(p, 8); + memcpy (p + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 8 + input_message_buffer->length, padlength, padlength); + + /* checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, p, datalen); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); + + /* sequence number */ + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + p -= 16; + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* encrypt the data */ + p += 16; + + if(conf_req_flag) { + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1); + EVP_Cipher(&des_ctx, p, p, datalen); + EVP_CIPHER_CTX_cleanup(&des_ctx); + } + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +#endif + +static OM_uint32 +wrap_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key + ) +{ + u_char *p; + u_char seq[8]; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + uint32_t ret; + krb5_crypto crypto; + Checksum cksum; + krb5_data encdata; + + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 34 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 34; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x02\x00", 2); /* DES3-KD */ + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* calculate checksum (the above + confounder + data + pad) */ + + memcpy (p + 20, p - 8, 8); + krb5_generate_random_block(p + 28, 8); + memcpy (p + 28 + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_create_checksum (context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + p + 20, + datalen + 8, + &cksum); + krb5_crypto_destroy (context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* zero out SND_SEQ + SGN_CKSUM in case */ + memset (p, 0, 28); + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, + &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + DES_cblock ivec; + + memcpy (&ivec, p + 8, 8); + ret = krb5_encrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, + &ivec); + } + krb5_crypto_destroy (context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* encrypt the data */ + p += 28; + + if(conf_req_flag) { + krb5_data tmp; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, + p, datalen, &tmp); + krb5_crypto_destroy(context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == datalen); + + memcpy (p, tmp.data, datalen); + krb5_data_free(&tmp); + } + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_wrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer + ) +{ + krb5_context context; + krb5_keyblock *key; + OM_uint32 ret; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, + input_message_buffer, conf_state, + output_message_buffer); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : +#ifdef HEIM_WEAK_CRYPTO + ret = wrap_des (minor_status, ctx, context, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); +#else + ret = GSS_S_FAILURE; +#endif + break; + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : + ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: + ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/libgssapi-exports.def b/third_party/heimdal/lib/gssapi/libgssapi-exports.def new file mode 100644 index 0000000..6077c8e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/libgssapi-exports.def @@ -0,0 +1,203 @@ +EXPORTS + __gss_c_nt_anonymous_oid_desc DATA + __gss_c_nt_composite_export_oid_desc DATA + __gss_c_nt_export_name_oid_desc DATA + __gss_c_nt_hostbased_service_oid_desc DATA + __gss_c_nt_hostbased_service_x_oid_desc DATA + __gss_c_nt_machine_uid_name_oid_desc DATA + __gss_c_nt_string_uid_name_oid_desc DATA + __gss_c_nt_user_name_oid_desc DATA + __gss_krb5_nt_principal_name_oid_desc DATA + __gss_c_attr_stream_sizes_oid_desc DATA + __gss_c_attr_local_login_user DATA + gss_accept_sec_context + gss_acquire_cred + gss_acquire_cred_impersonate_name + gss_acquire_cred_from + gss_acquire_cred_with_password + gss_add_buffer_set_member + gss_add_cred + gss_add_cred_from + gss_add_cred_with_password + gss_add_oid_set_member + gss_authorize_localname + gss_canonicalize_name + gss_compare_name + gss_context_query_attributes + gss_context_time + gss_create_empty_buffer_set + gss_create_empty_oid_set + gss_decapsulate_token + gss_delete_name_attribute + gss_delete_sec_context + gss_display_mech_attr + gss_display_name + gss_display_name_ext + gss_display_status + gss_duplicate_name + gss_duplicate_oid + gss_duplicate_oid_set + gss_encapsulate_token + gss_export_cred + gss_export_name + gss_export_name_composite + gss_export_sec_context + gss_get_mic + gss_get_neg_mechs + gss_get_name_attribute + gss_import_cred + gss_import_name + gss_import_sec_context + gss_indicate_mechs + gss_indicate_mechs_by_attrs + gss_init_sec_context + gss_inquire_attrs_for_mech + gss_inquire_context + gss_inquire_cred + gss_inquire_cred_by_mech + gss_inquire_cred_by_oid + gss_inquire_mech_for_saslname + gss_inquire_mechs_for_name + gss_inquire_name + gss_inquire_names_for_mech + gss_inquire_saslname_for_mech + gss_inquire_sec_context_by_oid ;! + gss_krb5_ccache_name + gss_krb5_copy_ccache + gss_krb5_export_lucid_sec_context + gss_krb5_free_lucid_sec_context + gss_krb5_get_tkt_flags + gss_krb5_import_cred + gss_krb5_set_allowable_enctypes + gss_localname + gss_mg_collect_error + gss_mo_get + gss_mo_set + gss_mo_list + gss_mo_name + gss_name_to_oid + gss_oid_to_name + gss_oid_equal + gss_oid_to_str + gss_pname_to_uid + gss_process_context_token + gss_pseudo_random + gss_release_buffer + gss_release_buffer_set + gss_release_cred + gss_release_iov_buffer + gss_release_name + gss_release_oid + gss_release_oid_set + gss_seal + gss_set_cred_option + gss_set_name_attribute + gss_set_log_function + gss_set_neg_mechs + gss_set_sec_context_option + gss_sign + gss_store_cred + gss_store_cred_into + gss_store_cred_into2 + gss_test_oid_set_member + gss_unseal + gss_unwrap + gss_unwrap_aead + gss_unwrap_iov + gss_userok + gss_verify + gss_verify_mic + gss_wrap + gss_wrap_aead + gss_wrap_iov + gss_wrap_iov_length + gss_wrap_size_limit + gsskrb5_extract_authtime_from_sec_context + gsskrb5_extract_authz_data_from_sec_context + gsskrb5_extract_service_keyblock + gsskrb5_get_initiator_subkey + gsskrb5_get_subkey + gsskrb5_get_time_offset + gsskrb5_register_acceptor_identity + gsskrb5_set_default_realm + gsskrb5_set_dns_canonicalize + gsskrb5_set_send_to_kdc + gsskrb5_set_time_offset + krb5_gss_register_acceptor_identity + +; _gsskrb5cfx_ are really internal symbols, but export +; then now to make testing easier. + _gsskrb5cfx_wrap_length_cfx + _gssapi_wrap_size_cfx + + initialize_gk5_error_table_r ;! + + __gss_krb5_copy_ccache_x_oid_desc DATA + __gss_krb5_get_tkt_flags_x_oid_desc DATA + __gss_krb5_extract_authz_data_from_sec_context_x_oid_desc DATA + __gss_krb5_compat_des3_mic_x_oid_desc DATA + __gss_krb5_register_acceptor_identity_x_oid_desc DATA + __gss_krb5_export_lucid_context_x_oid_desc DATA + __gss_krb5_export_lucid_context_v1_x_oid_desc DATA + __gss_krb5_set_dns_canonicalize_x_oid_desc DATA + __gss_krb5_get_subkey_x_oid_desc DATA + __gss_krb5_get_initiator_subkey_x_oid_desc DATA + __gss_krb5_get_acceptor_subkey_x_oid_desc DATA + __gss_krb5_send_to_kdc_x_oid_desc DATA + __gss_krb5_get_authtime_x_oid_desc DATA + __gss_krb5_get_service_keyblock_x_oid_desc DATA + __gss_krb5_set_allowable_enctypes_x_oid_desc DATA + __gss_krb5_set_default_realm_x_oid_desc DATA + __gss_krb5_ccache_name_x_oid_desc DATA + __gss_krb5_set_time_offset_x_oid_desc DATA + __gss_krb5_get_time_offset_x_oid_desc DATA + __gss_krb5_plugin_register_x_oid_desc DATA + __gss_ntlm_get_session_key_x_oid_desc DATA + __gss_c_nt_ntlm_oid_desc DATA + __gss_c_nt_dn_oid_desc DATA + __gss_krb5_nt_principal_name_referral_oid_desc DATA + __gss_c_ntlm_avguest_oid_desc DATA + __gss_c_ntlm_v1_oid_desc DATA + __gss_c_ntlm_v2_oid_desc DATA + __gss_c_ntlm_session_key_oid_desc DATA + __gss_c_ntlm_force_v1_oid_desc DATA + __gss_krb5_cred_no_ci_flags_x_oid_desc DATA + __gss_krb5_import_cred_x_oid_desc DATA + __gss_c_ma_sasl_mech_name_oid_desc DATA + __gss_c_ma_mech_name_oid_desc DATA + __gss_c_ma_mech_description_oid_desc DATA + __gss_sasl_digest_md5_mechanism_oid_desc DATA + __gss_krb5_mechanism_oid_desc DATA + __gss_ntlm_mechanism_oid_desc DATA + __gss_spnego_mechanism_oid_desc DATA + __gss_sanon_x25519_mechanism_oid_desc DATA + __gss_c_ma_mech_concrete_oid_desc DATA + __gss_c_ma_mech_pseudo_oid_desc DATA + __gss_c_ma_mech_composite_oid_desc DATA + __gss_c_ma_mech_nego_oid_desc DATA + __gss_c_ma_mech_glue_oid_desc DATA + __gss_c_ma_not_mech_oid_desc DATA + __gss_c_ma_deprecated_oid_desc DATA + __gss_c_ma_not_dflt_mech_oid_desc DATA + __gss_c_ma_itok_framed_oid_desc DATA + __gss_c_ma_auth_init_oid_desc DATA + __gss_c_ma_auth_targ_oid_desc DATA + __gss_c_ma_auth_init_init_oid_desc DATA + __gss_c_ma_auth_targ_init_oid_desc DATA + __gss_c_ma_auth_init_anon_oid_desc DATA + __gss_c_ma_auth_targ_anon_oid_desc DATA + __gss_c_ma_deleg_cred_oid_desc DATA + __gss_c_ma_integ_prot_oid_desc DATA + __gss_c_ma_conf_prot_oid_desc DATA + __gss_c_ma_mic_oid_desc DATA + __gss_c_ma_wrap_oid_desc DATA + __gss_c_ma_prot_ready_oid_desc DATA + __gss_c_ma_replay_det_oid_desc DATA + __gss_c_ma_oos_det_oid_desc DATA + __gss_c_ma_cbindings_oid_desc DATA + __gss_c_ma_pfs_oid_desc DATA + __gss_c_ma_compress_oid_desc DATA + __gss_c_ma_ctx_trans_oid_desc DATA + __gss_c_ma_negoex_and_spnego_oid_desc DATA + __gss_c_inq_negoex_key_oid_desc DATA + __gss_c_inq_negoex_verify_key_oid_desc DATA diff --git a/third_party/heimdal/lib/gssapi/libgssapi-version.rc b/third_party/heimdal/lib/gssapi/libgssapi-version.rc new file mode 100644 index 0000000..074066f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/libgssapi-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_DLL +#define RC_FILE_DESC_0409 "Generic Security Service Application Program Interface library" +#define RC_FILE_ORIG_0409 "gssapi.dll" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/gssapi/mech/compat.h b/third_party/heimdal/lib/gssapi/mech/compat.h new file mode 100644 index 0000000..d23a6e9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/compat.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_saslname_for_mech_t ( + OM_uint32 *, /* minor_status */ + const gss_OID, /* desired_mech */ + gss_buffer_t, /* sasl_mech_name */ + gss_buffer_t, /* mech_name */ + gss_buffer_t /* mech_description */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_mech_for_saslname_t ( + OM_uint32 *, /* minor_status */ + const gss_buffer_t, /* sasl_mech_name */ + gss_OID * /* mech_type */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_inquire_attrs_for_mech_t ( + OM_uint32 *, /* minor_status */ + gss_const_OID, /* mech */ + gss_OID_set *, /* mech_attrs */ + gss_OID_set * /* known_mech_attrs */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_acquire_cred_with_password_t + (OM_uint32 *, /* minor_status */ + gss_const_name_t, /* desired_name */ + const gss_buffer_t, /* password */ + OM_uint32, /* time_req */ + const gss_OID_set, /* desired_mechs */ + gss_cred_usage_t, /* cred_usage */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 * /* time_rec */ + ); + +typedef OM_uint32 GSSAPI_CALLCONV _gss_add_cred_with_password_t ( + OM_uint32 *, /* minor_status */ + gss_const_cred_id_t, /* input_cred_handle */ + gss_const_name_t, /* desired_name */ + const gss_OID, /* desired_mech */ + const gss_buffer_t, /* password */ + gss_cred_usage_t, /* cred_usage */ + OM_uint32, /* initiator_time_req */ + OM_uint32, /* acceptor_time_req */ + gss_cred_id_t *, /* output_cred_handle */ + gss_OID_set *, /* actual_mechs */ + OM_uint32 *, /* initiator_time_rec */ + OM_uint32 * /* acceptor_time_rec */ + ); + +/* + * API-as-SPI compatibility for compatibility with MIT mechanisms; + * native Heimdal mechanisms should not use these. + */ +struct gss_mech_compat_desc_struct { + _gss_inquire_saslname_for_mech_t *gmc_inquire_saslname_for_mech; + _gss_inquire_mech_for_saslname_t *gmc_inquire_mech_for_saslname; + _gss_inquire_attrs_for_mech_t *gmc_inquire_attrs_for_mech; + _gss_acquire_cred_with_password_t *gmc_acquire_cred_with_password; +#if 0 + _gss_add_cred_with_password_t *gmc_add_cred_with_password; +#endif +}; + diff --git a/third_party/heimdal/lib/gssapi/mech/context.c b/third_party/heimdal/lib/gssapi/mech/context.c new file mode 100644 index 0000000..83e2cef --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/context.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include "heim_threads.h" +#include +#include "krb5_locl.h" +#include "negoex_err.h" + +struct mg_thread_ctx { + gss_OID mech; + OM_uint32 min_stat; + gss_buffer_desc min_error; + krb5_context context; +}; + +static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; +static int created_key; +static HEIMDAL_thread_key context_key; + + +static void +destroy_context(void *ptr) +{ + struct mg_thread_ctx *mg = ptr; + OM_uint32 junk; + + if (mg == NULL) + return; + + gss_release_buffer(&junk, &mg->min_error); + + if (mg->context) + krb5_free_context(mg->context); + + free(mg); +} + + +static struct mg_thread_ctx * +_gss_mechglue_thread(void) +{ + struct mg_thread_ctx *ctx; + int ret = 0; + + HEIMDAL_MUTEX_lock(&context_mutex); + + if (!created_key) { + HEIMDAL_key_create(&context_key, destroy_context, ret); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_mutex); + return NULL; + } + created_key = 1; + } + HEIMDAL_MUTEX_unlock(&context_mutex); + + ctx = HEIMDAL_getspecific(context_key); + if (ctx == NULL) { + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ret = krb5_init_context(&ctx->context); + if (ret) { + free(ctx); + return NULL; + } + + krb5_add_et_list(ctx->context, initialize_ngex_error_table_r); + + HEIMDAL_setspecific(context_key, ctx, ret); + if (ret) { + krb5_free_context(ctx->context); + free(ctx); + return NULL; + } + } + return ctx; +} + +krb5_context +_gss_mg_krb5_context(void) +{ + struct mg_thread_ctx *mg; + + mg = _gss_mechglue_thread(); + + return mg ? mg->context : NULL; +} + +OM_uint32 +_gss_mg_get_error(const gss_OID mech, + OM_uint32 value, + gss_buffer_t string) +{ + struct mg_thread_ctx *mg; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return GSS_S_BAD_STATUS; + + if (value != mg->min_stat || mg->min_error.length == 0) { + _mg_buffer_zero(string); + return GSS_S_BAD_STATUS; + } + string->value = malloc(mg->min_error.length); + if (string->value == NULL) { + _mg_buffer_zero(string); + return GSS_S_FAILURE; + } + string->length = mg->min_error.length; + memcpy(string->value, mg->min_error.value, mg->min_error.length); + return GSS_S_COMPLETE; +} + +void +_gss_mg_error(struct gssapi_mech_interface_desc *m, OM_uint32 min) +{ + OM_uint32 major_status, minor_status; + OM_uint32 message_content = 0; + struct mg_thread_ctx *mg; + + /* + * Mechs without gss_display_status() does + * gss_mg_collect_error() by themself. + */ + if (m->gm_display_status == NULL) + return ; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return; + + gss_release_buffer(&minor_status, &mg->min_error); + + mg->mech = &m->gm_mech_oid; + mg->min_stat = min; + + major_status = m->gm_display_status(&minor_status, + min, + GSS_C_MECH_CODE, + &m->gm_mech_oid, + &message_content, + &mg->min_error); + if (major_status != GSS_S_COMPLETE) { + _mg_buffer_zero(&mg->min_error); + } else { + _gss_mg_log(5, "_gss_mg_error: captured %.*s (%d) from underlying mech %s", + (int)mg->min_error.length, (const char *)mg->min_error.value, + (int)min, m->gm_name); + } +} + +void +gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) +{ + gssapi_mech_interface m = __gss_get_mechanism(mech); + if (m == NULL) + return; + _gss_mg_error(m, min); +} + +OM_uint32 +gss_mg_set_error_string(gss_OID mech, + OM_uint32 maj, OM_uint32 min, + const char *fmt, ...) +{ + struct mg_thread_ctx *mg; + char *str = NULL; + OM_uint32 junk; + va_list ap; + int vasprintf_ret; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return maj; + + va_start(ap, fmt); + vasprintf_ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (vasprintf_ret >= 0 && str) { + gss_release_buffer(&junk, &mg->min_error); + + mg->mech = mech; + mg->min_stat = min; + + mg->min_error.value = str; + mg->min_error.length = strlen(str); + + _gss_mg_log(5, "gss_mg_set_error_string: %.*s (%d/%d)", + (int)mg->min_error.length, (const char *)mg->min_error.value, + (int)maj, (int)min); + } + return maj; +} + +static void *log_ctx = NULL; +static void (*log_func)(void *ctx, int level, const char *fmt, va_list) = NULL; + +void GSSAPI_LIB_CALL +gss_set_log_function(void *ctx, void (*func)(void * ctx, int level, const char *fmt, va_list)) +{ + if (log_func == NULL) { + log_func = func; + log_ctx = ctx; + } +} + +int +_gss_mg_log_level(int level) +{ + struct mg_thread_ctx *mg; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return 0; + + return _krb5_have_debug(mg->context, level); +} + +/* + * TODO: refactor logging so that it no longer depends on libkrb5 + * and can be configured independently. + */ +void +_gss_mg_log(int level, const char *fmt, ...) +{ + struct mg_thread_ctx *mg; + va_list ap; + + if (!_gss_mg_log_level(level)) + return; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return; + + if (mg->context && _krb5_have_debug(mg->context, level)) { + va_start(ap, fmt); + krb5_vlog(mg->context, heim_get_debug_dest(mg->context->hcontext), + level, fmt, ap); + va_end(ap); + } + + if (log_func) { + va_start(ap, fmt); + log_func(log_ctx, level, fmt, ap); + va_end(ap); + } +} + +void +_gss_mg_log_name(int level, + struct _gss_name *name, + gss_OID mech_type, + const char *fmt, ...) +{ + struct _gss_mechanism_name *mn = NULL; + gssapi_mech_interface m; + OM_uint32 junk; + + if (!_gss_mg_log_level(level)) + return; + + m = __gss_get_mechanism(mech_type); + if (m == NULL) + return; + + if (_gss_find_mn(&junk, name, mech_type, &mn) == GSS_S_COMPLETE) { + OM_uint32 maj_stat = GSS_S_COMPLETE; + gss_buffer_desc namebuf; + int ret; + + if (mn == NULL) { + namebuf.value = "no name"; + namebuf.length = strlen((char *)namebuf.value); + } else { + maj_stat = m->gm_display_name(&junk, mn->gmn_name, + &namebuf, NULL); + } + if (maj_stat == GSS_S_COMPLETE) { + char *str = NULL; + va_list ap; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (ret >= 0 && str) + _gss_mg_log(level, "%s %.*s", str, + (int)namebuf.length, (char *)namebuf.value); + free(str); + if (mn != NULL) + gss_release_buffer(&junk, &namebuf); + } + } + +} + +void +_gss_mg_log_cred(int level, + struct _gss_cred *cred, + const char *fmt, ...) +{ + struct _gss_mechanism_cred *mc; + char *str; + va_list ap; + int ret; + + if (!_gss_mg_log_level(level)) + return; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (ret >=0 && cred) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + _gss_mg_log(1, "%s: %s", str, mc->gmc_mech->gm_name); + } + } else { + _gss_mg_log(1, "%s: GSS_C_NO_CREDENTIAL", str); + } + free(str); +} + diff --git a/third_party/heimdal/lib/gssapi/mech/context.h b/third_party/heimdal/lib/gssapi/mech/context.h new file mode 100644 index 0000000..5029171 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/context.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/context.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + * $Id$ + */ + +#include + +struct _gss_context { + gss_buffer_desc gc_input; + char *gc_free_this; + size_t gc_target_len; + size_t gc_oid_offset; + gssapi_mech_interface gc_mech; + gss_ctx_id_t gc_ctx; + uint8_t gc_initial; +}; + +#define EXPORT_CONTEXT_VERSION_MASK 0x03 +#define EXPORT_CONTEXT_FLAGS_MASK 0xfc +#define EXPORT_CONTEXT_FLAG_ACCUMULATING 0x04 +#define EXPORT_CONTEXT_FLAG_MECH_CTX 0x08 + +void +_gss_mg_error(gssapi_mech_interface, OM_uint32); + +OM_uint32 +_gss_mg_get_error(const gss_OID, OM_uint32, gss_buffer_t); diff --git a/third_party/heimdal/lib/gssapi/mech/cred.c b/third_party/heimdal/lib/gssapi/mech/cred.c new file mode 100644 index 0000000..92cc61a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/cred.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include "heim_threads.h" +#include "heimbase.h" + +static OM_uint32 +release_mech_cred(OM_uint32 *minor, struct _gss_mechanism_cred *mc) +{ + OM_uint32 major; + + if (mc->gmc_mech->gm_release_cred != NULL) + major = mc->gmc_mech->gm_release_cred(minor, &mc->gmc_cred); + else + major = GSS_S_COMPLETE; + + free(mc); + + return major; +} + + +void +_gss_mg_release_cred(struct _gss_cred *cred) +{ + struct _gss_mechanism_cred *mc, *next; + OM_uint32 junk; + + HEIM_TAILQ_FOREACH_SAFE(mc, &cred->gc_mc, gmc_link, next) { + HEIM_TAILQ_REMOVE(&cred->gc_mc, mc, gmc_link); + release_mech_cred(&junk, mc); + } + gss_release_oid_set(&junk, &cred->gc_neg_mechs); + free(cred); +} + +struct _gss_cred * +_gss_mg_alloc_cred(void) +{ + struct _gss_cred *cred; + cred = calloc(1, sizeof(struct _gss_cred)); + if (cred == NULL) + return NULL; + HEIM_TAILQ_INIT(&cred->gc_mc); + + return cred; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/cred.h b/third_party/heimdal/lib/gssapi/mech/cred.h new file mode 100644 index 0000000..eed4a82 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/cred.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/cred.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + * $Id$ + */ + +struct _gss_mechanism_cred { + HEIM_TAILQ_ENTRY(_gss_mechanism_cred) gmc_link; + gssapi_mech_interface gmc_mech; /* mechanism ops for MC */ + gss_OID gmc_mech_oid; /* mechanism oid for MC */ + gss_cred_id_t gmc_cred; /* underlying MC */ +}; +HEIM_TAILQ_HEAD(_gss_mechanism_cred_list, _gss_mechanism_cred); + +struct _gss_cred { + struct _gss_mechanism_cred_list gc_mc; + gss_OID_set gc_neg_mechs; +}; + +struct _gss_cred * +_gss_mg_alloc_cred(void); + +void +_gss_mg_release_cred(struct _gss_cred *cred); + +struct _gss_mechanism_cred * +_gss_copy_cred(struct _gss_mechanism_cred *mc); + +struct _gss_mechanism_name; + +OM_uint32 +_gss_mg_add_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + const struct _gss_mechanism_name *mn, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **output_cred_handle, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec); diff --git a/third_party/heimdal/lib/gssapi/mech/doxygen.c b/third_party/heimdal/lib/gssapi/mech/doxygen.c new file mode 100644 index 0000000..4ead9f1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/doxygen.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*! @mainpage Heimdal GSS-API Library + * + * Heimdal implements the following mechanisms: + * + * - Kerberos 5 + * - SPNEGO + * - NTLM + * + * @sa + * + * - @ref gssapi_services_intro + * - @ref gssapi_mechs + * - @ref gssapi_api_INvsMN + * - The project web page: http://www.h5l.org/ + */ + +/** + * @page gssapi_services_intro Introduction to GSS-API services + * @section gssapi_services GSS-API services + * + * @subsection gssapi_services_context Context creation + * + * - delegation + * - mutual authentication + * - anonymous + * - use per message before context creation has completed + * + * return status: + * - support conf + * - support int + * + * @subsection gssapi_context_flags Context creation flags + * + * - GSS_C_DELEG_FLAG + * - GSS_C_MUTUAL_FLAG + * - GSS_C_REPLAY_FLAG + * - GSS_C_SEQUENCE_FLAG + * - GSS_C_CONF_FLAG + * - GSS_C_INTEG_FLAG + * - GSS_C_ANON_FLAG + * - GSS_C_PROT_READY_FLAG + * - GSS_C_TRANS_FLAG + * - GSS_C_DCE_STYLE + * - GSS_C_IDENTIFY_FLAG + * - GSS_C_EXTENDED_ERROR_FLAG + * - GSS_C_DELEG_POLICY_FLAG + * + * + * @subsection gssapi_services_permessage Per-message services + * + * - conf + * - int + * - message integrity + * - replay detection + * - out of sequence + * + */ + +/** + * @page gssapi_mechs_intro GSS-API mechanisms + * @section gssapi_mechs GSS-API mechanisms + * + * - Kerberos 5 - GSS_KRB5_MECHANISM + * - SPNEGO - GSS_SPNEGO_MECHANISM + * - NTLM - GSS_NTLM_MECHANISM + + */ + + +/** + * @page internalVSmechname Internal names and mechanism names + * @section gssapi_api_INvsMN Name forms + * + * There are two name representations in GSS-API: Internal form and + * Contiguous string ("flat") form. Functions gss_export_name() and + * gss_import_name() can be used to convert between the two forms. + * + * - The contiguous string form is described by an oid specificing the + * type and an octet string. A special form of the contiguous + * string form is the exported name object. The exported name + * defined for each mechanism, is something that can be stored and + * compared later. The exported name is what should be used for + * ACLs comparisons. + * + * - The Internal form is opaque to the application programmer and + * is implementation-dependent. + * + * - There is also a special form of the Internal Name (IN), and that is + * the Mechanism Name (MN). In the mechanism name all the generic + * information is stripped of and only contain the information for + * one mechanism. In GSS-API some function return MN and some + * require MN as input. Each of these function is marked up as such. + * + * @FIXME Describe relationship between import_name, canonicalize_name, + * export_name and friends. Also, update for RFC2743 language + * ("contiguous" and "flat" are gone, leaving just "exported name + * token", "internal", and "MN"). + */ + +/** @defgroup gssapi Heimdal GSS-API functions */ diff --git a/third_party/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_accept_sec_context.c new file mode 100644 index 0000000..04d7ab5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_accept_sec_context.c @@ -0,0 +1,517 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_accept_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/* + * accumulate_token() tries to assemble a complete GSS token which may + * be fed to it in pieces. Microsoft does this when tokens are too large + * in CIFS, e.g. It may occur in other places as well. It is specified in: + * + * [MS-SPNG]: Simple and Protected GSS-API Negotiation + * Mechanism (SPNEGO) Extension + * + * https://winprotocoldoc.blob.core.windows.net/ + * productionwindowsarchives/MS-SPNG/%5bMS-SPNG%5d.pdf + * + * Sections 3.1.5.4 to 3.1.5.9. + * + * We only accumulate if we see the appropriate application tag in the + * first byte of 0x60 because in the absence of this, we cannot interpret + * the following bytes as a DER length. + * + * We only allocate an accumulating buffer if we detect that the token + * is split between multiple packets as this is the uncommon case and + * we want to optimise for the common case. If we aren't accumulating, + * we simply return success. + * + * Our return value is GSS_S_CONTINUE_NEEDED if we need more input. + * We return GSS_S_COMPLETE if we are either finished accumulating or + * if we decide that we do not understand this token. We only return + * an error if we think that we should understand the token and still + * fail to understand it. + */ + +static OM_uint32 +accumulate_token(struct _gss_context *ctx, gss_buffer_t input_token) +{ + unsigned char *p = input_token->value; + size_t len = input_token->length; + gss_buffer_t gci; + size_t l; + + /* + * Token must start with [APPLICATION 0] SEQUENCE. + * But if it doesn't assume it is DCE-STYLE Kerberos! + */ + if (!ctx->gc_target_len) { + free(ctx->gc_free_this); + ctx->gc_free_this = NULL; + _mg_buffer_zero(&ctx->gc_input); + + /* + * Let's prepare gc_input for the case where + * we aren't accumulating. + */ + + ctx->gc_input.length = len; + ctx->gc_input.value = p; + + if (len == 0) + return GSS_S_COMPLETE; + + /* Not our DER w/ a length */ + if (*p != 0x60) + return GSS_S_COMPLETE; + + if (der_get_length(p+1, len-1, &ctx->gc_target_len, &l) != 0) + return GSS_S_DEFECTIVE_TOKEN; + + _gss_mg_log(10, "gss-asc: DER length: %zu", + ctx->gc_target_len); + + ctx->gc_oid_offset = l + 1; + ctx->gc_target_len += ctx->gc_oid_offset; + + _gss_mg_log(10, "gss-asc: total length: %zu", + ctx->gc_target_len); + + if (ctx->gc_target_len == ASN1_INDEFINITE || + ctx->gc_target_len < len) + return GSS_S_DEFECTIVE_TOKEN; + + /* We've got it all, short-circuit the accumulating */ + if (ctx->gc_target_len == len) + goto done; + + _gss_mg_log(10, "gss-asc: accumulating partial token"); + + ctx->gc_input.length = 0; + ctx->gc_input.value = calloc(ctx->gc_target_len, 1); + if (!ctx->gc_input.value) + return GSS_S_FAILURE; + ctx->gc_free_this = ctx->gc_input.value; + } + + if (len == 0) + return GSS_S_DEFECTIVE_TOKEN; + + gci = &ctx->gc_input; + + if (ctx->gc_target_len > gci->length) { + if (gci->length + len > ctx->gc_target_len) { + _gss_mg_log(10, "gss-asc: accumulation exceeded " + "target length: bailing"); + return GSS_S_DEFECTIVE_TOKEN; + } + memcpy((char *)gci->value + gci->length, p, len); + gci->length += len; + } + + if (gci->length != ctx->gc_target_len) { + _gss_mg_log(10, "gss-asc: collected %zu/%zu bytes", + gci->length, ctx->gc_target_len); + return GSS_S_CONTINUE_NEEDED; + } + +done: + _gss_mg_log(10, "gss-asc: received complete %zu byte token", + ctx->gc_target_len); + ctx->gc_target_len = 0; + + return GSS_S_COMPLETE; +} + +static void +log_oid(const char *str, gss_OID mech) +{ + OM_uint32 maj, min; + gss_buffer_desc buf; + + maj = gss_oid_to_str(&min, mech, &buf); + if (maj == GSS_S_COMPLETE) { + _gss_mg_log(10, "%s: %.*s", str, (int)buf.length, + (char *)buf.value); + gss_release_buffer(&min, &buf); + } +} + +static OM_uint32 +choose_mech(struct _gss_context *ctx) +{ + gss_OID_desc mech; + gss_OID mech_oid; + unsigned char *p = ctx->gc_input.value; + size_t len = ctx->gc_input.length; + + if (len == 0) { + /* + * There is the a wierd mode of SPNEGO (in CIFS and + * SASL GSS-SPENGO) where the first token is zero + * length and the acceptor returns a mech_list, lets + * hope that is what is happening now. + * + * http://msdn.microsoft.com/en-us/library/cc213114.aspx + * "NegTokenInit2 Variation for Server-Initiation" + */ + mech_oid = &__gss_spnego_mechanism_oid_desc; + goto gss_get_mechanism; + } + + p += ctx->gc_oid_offset; + len -= ctx->gc_oid_offset; + + /* + * Decode the OID for the mechanism. Simplify life by + * assuming that the OID length is less than 128 bytes. + */ + if (len < 2 || *p != 0x06) { + _gss_mg_log(10, "initial context token appears to be for non-standard mechanism"); + return GSS_S_COMPLETE; + } + len -= 2; + if ((p[1] & 0x80) || p[1] > len) { + _gss_mg_log(10, "mechanism oid in initial context token is too long"); + return GSS_S_COMPLETE; + } + mech.length = p[1]; + p += 2; + mech.elements = p; + + mech_oid = _gss_mg_support_mechanism(&mech); + if (mech_oid == GSS_C_NO_OID) + return GSS_S_COMPLETE; + +gss_get_mechanism: + /* + * If mech_oid == GSS_C_NO_OID then the mech is non-standard + * and we have to try all mechs (that we have a cred element + * for, if we have a cred). + */ + log_oid("mech oid", mech_oid); + ctx->gc_mech = __gss_get_mechanism(mech_oid); + if (!ctx->gc_mech) { + _gss_mg_log(10, "mechanism client used is unknown"); + return (GSS_S_BAD_MECH); + } + _gss_mg_log(10, "using mech \"%s\"", ctx->gc_mech->gm_name); + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_accept_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 major_status, mech_ret_flags, junk; + gssapi_mech_interface m = NULL; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; + struct _gss_mechanism_cred *mc; + gss_buffer_desc defective_token_error; + gss_const_cred_id_t acceptor_mc; + gss_cred_id_t delegated_mc = GSS_C_NO_CREDENTIAL; + gss_name_t src_mn = GSS_C_NO_NAME; + gss_OID mech_ret_type = GSS_C_NO_OID; + int initial; + + defective_token_error.length = 0; + defective_token_error.value = NULL; + + *minor_status = 0; + if (src_name) + *src_name = GSS_C_NO_NAME; + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + if (delegated_cred_handle) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + _mg_buffer_zero(output_token); + + if (!*context_handle) { + ctx = calloc(sizeof(*ctx), 1); + if (!ctx) { + *minor_status = ENOMEM; + return (GSS_S_DEFECTIVE_TOKEN); + } + *context_handle = (gss_ctx_id_t)ctx; + ctx->gc_initial = 1; + } + + major_status = accumulate_token(ctx, input_token); + if (major_status != GSS_S_COMPLETE) + return major_status; + + /* + * If we get here, then we have a complete token. Please note + * that we may have a major_status of GSS_S_DEFECTIVE_TOKEN. This + * + */ + + initial = ctx->gc_initial; + ctx->gc_initial = 0; + + if (major_status == GSS_S_COMPLETE && initial) { + major_status = choose_mech(ctx); + if (major_status != GSS_S_COMPLETE) + return major_status; + } + m = ctx->gc_mech; + + if (initial && !m && acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * No header, not a standard mechanism. Try all the mechanisms + * (because default credential). + */ + struct _gss_mech_switch *ms; + + _gss_load_mech(); + acceptor_mc = GSS_C_NO_CREDENTIAL; + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; + mech_ret_flags = 0; + major_status = m->gm_accept_sec_context(minor_status, + &ctx->gc_ctx, + acceptor_mc, + &ctx->gc_input, + input_chan_bindings, + &src_mn, + &mech_ret_type, + output_token, + &mech_ret_flags, + time_rec, + &delegated_mc); + if (major_status == GSS_S_DEFECTIVE_TOKEN) { + /* + * Try to retain and output one error token for + * GSS_S_DEFECTIVE_TOKEN. The first one. + */ + if (output_token->length && + defective_token_error.length == 0) { + defective_token_error = *output_token; + output_token->length = 0; + output_token->value = NULL; + } + gss_release_buffer(&junk, output_token); + continue; + } + gss_release_buffer(&junk, &defective_token_error); + ctx->gc_mech = m; + goto got_one; + } + m = NULL; + acceptor_mc = GSS_C_NO_CREDENTIAL; + } else if (initial && !m) { + /* + * No header, not a standard mechanism. Try all the mechanisms + * that we have a credential element for if we have a + * non-default credential. + */ + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + m = mc->gmc_mech; + acceptor_mc = (m->gm_flags & GM_USE_MG_CRED) ? + acceptor_cred_handle : mc->gmc_cred; + mech_ret_flags = 0; + major_status = m->gm_accept_sec_context(minor_status, + &ctx->gc_ctx, + acceptor_mc, + &ctx->gc_input, + input_chan_bindings, + &src_mn, + &mech_ret_type, + output_token, + &mech_ret_flags, + time_rec, + &delegated_mc); + if (major_status == GSS_S_DEFECTIVE_TOKEN) { + if (output_token->length && + defective_token_error.length == 0) { + defective_token_error = *output_token; + output_token->length = 0; + output_token->value = NULL; + } + gss_release_buffer(&junk, output_token); + continue; + } + gss_release_buffer(&junk, &defective_token_error); + ctx->gc_mech = m; + goto got_one; + } + m = NULL; + acceptor_mc = GSS_C_NO_CREDENTIAL; + } + + if (m == NULL) { + gss_delete_sec_context(&junk, context_handle, NULL); + _gss_mg_log(10, "No mechanism accepted the non-standard initial security context token"); + *output_token = defective_token_error; + return GSS_S_BAD_MECH; + } + + if (m->gm_flags & GM_USE_MG_CRED) { + acceptor_mc = acceptor_cred_handle; + } else if (cred) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) + if (mc->gmc_mech == m) + break; + if (!mc) { + gss_delete_sec_context(&junk, context_handle, NULL); + _gss_mg_log(10, "gss-asc: client sent mech %s " + "but no credential was matching", + m->gm_name); + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) + _gss_mg_log(10, "gss-asc: available creds were %s", mc->gmc_mech->gm_name); + return (GSS_S_BAD_MECH); + } + acceptor_mc = mc->gmc_cred; + } else { + acceptor_mc = GSS_C_NO_CREDENTIAL; + } + + mech_ret_flags = 0; + major_status = m->gm_accept_sec_context(minor_status, + &ctx->gc_ctx, + acceptor_mc, + &ctx->gc_input, + input_chan_bindings, + &src_mn, + &mech_ret_type, + output_token, + &mech_ret_flags, + time_rec, + &delegated_mc); + +got_one: + if (major_status != GSS_S_COMPLETE && + major_status != GSS_S_CONTINUE_NEEDED) + { + _gss_mg_error(m, *minor_status); + gss_delete_sec_context(&junk, context_handle, NULL); + return (major_status); + } + + if (mech_type) + *mech_type = mech_ret_type; + + if (src_name && src_mn) { + if (ctx->gc_mech->gm_flags & GM_USE_MG_NAME) { + /* Negotiation mechanisms use mechglue names as names */ + *src_name = src_mn; + src_mn = GSS_C_NO_NAME; + } else { + /* + * Make a new name and mark it as an MN. + * + * Note that _gss_create_name() consumes `src_mn' but doesn't + * take a pointer, so it can't set it to GSS_C_NO_NAME. + */ + struct _gss_name *name = _gss_create_name(src_mn, m); + + if (!name) { + m->gm_release_name(minor_status, &src_mn); + gss_delete_sec_context(&junk, context_handle, NULL); + return (GSS_S_FAILURE); + } + *src_name = (gss_name_t) name; + src_mn = GSS_C_NO_NAME; + } + } else if (src_mn) { + if (ctx->gc_mech->gm_flags & GM_USE_MG_NAME) { + _gss_mg_release_name((struct _gss_name *)src_mn); + src_mn = GSS_C_NO_NAME; + } else { + m->gm_release_name(minor_status, &src_mn); + } + } + + if (mech_ret_flags & GSS_C_DELEG_FLAG) { + if (!delegated_cred_handle) { + if (m->gm_flags & GM_USE_MG_CRED) + gss_release_cred(minor_status, &delegated_mc); + else + m->gm_release_cred(minor_status, &delegated_mc); + mech_ret_flags &= + ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); + } else if ((m->gm_flags & GM_USE_MG_CRED) != 0) { + /* + * If credential is uses mechglue cred, assume it + * returns one too. + */ + *delegated_cred_handle = delegated_mc; + } else if (gss_oid_equal(mech_ret_type, &m->gm_mech_oid) == 0) { + /* + * If the returned mech_type is not the same + * as the mech, assume its pseudo mech type + * and the returned type is already a + * mech-glue object + */ + *delegated_cred_handle = delegated_mc; + + } else if (delegated_mc) { + struct _gss_cred *dcred; + struct _gss_mechanism_cred *dmc; + + dcred = _gss_mg_alloc_cred(); + if (!dcred) { + *minor_status = ENOMEM; + gss_delete_sec_context(&junk, context_handle, NULL); + return (GSS_S_FAILURE); + } + dmc = malloc(sizeof(struct _gss_mechanism_cred)); + if (!dmc) { + free(dcred); + *minor_status = ENOMEM; + gss_delete_sec_context(&junk, context_handle, NULL); + return (GSS_S_FAILURE); + } + dmc->gmc_mech = m; + dmc->gmc_mech_oid = &m->gm_mech_oid; + dmc->gmc_cred = delegated_mc; + HEIM_TAILQ_INSERT_TAIL(&dcred->gc_mc, dmc, gmc_link); + + *delegated_cred_handle = (gss_cred_id_t) dcred; + } + } + + _gss_mg_log(10, "gss-asc: return %d/%d", (int)major_status, (int)*minor_status); + + if (ret_flags) + *ret_flags = mech_ret_flags; + return (major_status); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred.c new file mode 100644 index 0000000..fd92a25 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_acquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred(OM_uint32 *minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + return gss_acquire_cred_from(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + GSS_C_NO_CRED_STORE, + output_cred_handle, + actual_mechs, + time_rec); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c new file mode 100644 index 0000000..5bb956c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2011, 2018 PADL Software Pty Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_acquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/* + * Shim for gss_acquire_cred_with_password() + */ +static const char * +find_password_in_cred_store(gss_const_key_value_set_t cred_store) +{ + size_t i; + + if (cred_store == GSS_C_NO_CRED_STORE) + return NULL; + + for (i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "password") == 0) + return cred_store->elements[i].value; + } + + return NULL; +} + +static OM_uint32 +acquire_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_name *mn, + OM_uint32 time_req, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **out, + OM_uint32 *time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *mc; + gss_OID_set_desc mech; + const char *spassword; + + *out = NULL; + if (time_rec) + *time_rec = 0; + + mc = calloc(1, sizeof(struct _gss_mechanism_cred)); + if (mc == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + mc->gmc_mech = m; + mc->gmc_mech_oid = &m->gm_mech_oid; + + mech.count = 1; + mech.elements = mc->gmc_mech_oid; + + if (m->gm_acquire_cred_from) { + major_status = m->gm_acquire_cred_from(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + time_req, + &mech, + cred_usage, + cred_store, + &mc->gmc_cred, + NULL, + time_rec); + } else if ((cred_store == GSS_C_NO_CRED_STORE || cred_store->count == 0) && + m->gm_acquire_cred) { + major_status = m->gm_acquire_cred(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + time_req, + &mech, + cred_usage, + &mc->gmc_cred, + NULL, + time_rec); + } else if (m->gm_compat && + m->gm_compat->gmc_acquire_cred_with_password && + (spassword = find_password_in_cred_store(cred_store)) != NULL) { + gss_buffer_desc password; + + password.length = strlen(spassword); + password.value = rk_UNCONST(spassword); + + /* compat glue for loadable mechanisms that implement API-as-SPI */ + major_status = m->gm_compat->gmc_acquire_cred_with_password(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &password, + time_req, + &mech, + cred_usage, + &mc->gmc_cred, + NULL, + time_rec); + } else + major_status = GSS_S_UNAVAILABLE; + + heim_assert(major_status == GSS_S_COMPLETE || mc->gmc_cred == NULL, + "gss_acquire_cred_from: mech succeeded but did not return a credential"); + + if (major_status == GSS_S_COMPLETE) + *out = mc; + else + free(mc); + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_from(OM_uint32 *minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + OM_uint32 major_status, minor; + struct _gss_name *name = (struct _gss_name *)desired_name; + gssapi_mech_interface m; + struct _gss_cred *cred = NULL; + size_t i; + OM_uint32 min_time = GSS_C_INDEFINITE; + gss_OID_set mechs = GSS_C_NO_OID_SET; + + *minor_status = 0; + if (output_cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if (time_rec) + *time_rec = 0; + + _gss_load_mech(); + + if (desired_mechs != GSS_C_NO_OID_SET) { + int only_mg_cred_mechs = -1; + + for (i = 0; i < desired_mechs->count; i++) { + m = __gss_get_mechanism(&desired_mechs->elements[i]); + if (m != NULL) { + if ((m->gm_flags & GM_USE_MG_CRED) == 0) + only_mg_cred_mechs = 0; + else if (only_mg_cred_mechs == -1) + only_mg_cred_mechs = 1; + } + } + /* + * Now SPNEGO supports GM_USE_MG_CRED it's no longer necessary + * to specifically acquire SPNEGO credentials. If the caller + * did not specify any concrete mechanisms then we will acquire + * credentials for all of them. + */ + if (only_mg_cred_mechs == -1) { + *minor_status = 0; + major_status = GSS_S_BAD_MECH; + goto cleanup; + } else if (only_mg_cred_mechs == 0) + mechs = desired_mechs; + else + mechs = _gss_mech_oids; + } else + mechs = _gss_mech_oids; + + cred = _gss_mg_alloc_cred(); + if (cred == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto cleanup; + } + + if (actual_mechs) { + major_status = gss_create_empty_oid_set(minor_status, actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + + major_status = GSS_S_UNAVAILABLE; /* in case of no mechs */ + + for (i = 0; i < mechs->count; i++) { + struct _gss_mechanism_name *mn = NULL; + struct _gss_mechanism_cred *mc = NULL; + OM_uint32 cred_time; + + m = __gss_get_mechanism(&mechs->elements[i]); + if (m == NULL || (m->gm_flags & GM_USE_MG_CRED) != 0) + continue; + + if (desired_name != GSS_C_NO_NAME) { + major_status = _gss_find_mn(minor_status, name, + &mechs->elements[i], &mn); + if (major_status != GSS_S_COMPLETE) + continue; + } + + major_status = acquire_mech_cred(minor_status, m, mn, + time_req, cred_usage, + cred_store, &mc, &cred_time); + if (major_status != GSS_S_COMPLETE) { + if (mechs->count == 1) + _gss_mg_error(m, *minor_status); + continue; + } + + _gss_mg_log_name(10, name, &mechs->elements[i], + "gss_acquire_cred %s name: %ld/%ld", + m->gm_name, + (long)major_status, (long)*minor_status); + + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); + + if (cred_time < min_time) + min_time = cred_time; + if (actual_mechs != NULL) { + major_status = gss_add_oid_set_member(minor_status, + mc->gmc_mech_oid, + actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + } + + /* + * If we didn't manage to create a single credential, return + * an error. + */ + if (!HEIM_TAILQ_FIRST(&cred->gc_mc)) { + if (mechs->count > 1) { + *minor_status = 0; + major_status = GSS_S_NO_CRED; + } + heim_assert(major_status != GSS_S_COMPLETE, + "lack of credentials must result in an error"); + goto cleanup; + } + + /* add all GM_USE_MG_CRED mechs such as SPNEGO */ + if (actual_mechs != NULL) { + struct _gss_mech_switch *ms; + + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; + + if ((m->gm_flags & GM_USE_MG_CRED) == 0) + continue; + + major_status = gss_add_oid_set_member(minor_status, + &m->gm_mech_oid, + actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + } + + *minor_status = 0; + major_status = GSS_S_COMPLETE; + + *output_cred_handle = (gss_cred_id_t)cred; + if (time_rec) + *time_rec = min_time; + + _gss_mg_log_cred(10, cred, "gss_acquire_cred_from"); + +cleanup: + if (major_status != GSS_S_COMPLETE) { + gss_release_cred(&minor, (gss_cred_id_t *)&cred); + if (actual_mechs) + gss_release_oid_set(&minor, actual_mechs); + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c new file mode 100644 index 0000000..ec027ed --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c @@ -0,0 +1,51 @@ +/*- + * Copyright 2021, Dr Robert Harvey Crowston. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_impersonate_name( + OM_uint32 *minor_status, + gss_const_cred_id_t icred_handle, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *ocred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + *minor_status = 0; + + if (ocred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *ocred_handle = GSS_C_NO_CREDENTIAL; + + /* Not implemented. */ + return GSS_S_UNAVAILABLE; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_with_password.c b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_with_password.c new file mode 100644 index 0000000..4e6138b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_with_password.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_with_password(OM_uint32 *minor_status, + gss_const_name_t desired_name, + const gss_buffer_t password, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + OM_uint32 major_status; + gss_key_value_element_desc kv; + gss_key_value_set_desc store; + char *spassword = NULL; + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + if (password == GSS_C_NO_BUFFER || password->value == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + spassword = malloc(password->length + 1); + if (spassword == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(spassword, password->value, password->length); + spassword[password->length] = '\0'; + + kv.key = "password"; + kv.value = spassword; + + store.count = 1; + store.elements = &kv; + + major_status = gss_acquire_cred_from(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + &store, + output_cred_handle, + actual_mechs, + time_rec); + if (spassword) { + memset_s(spassword, password->length, 0, password->length); + free(spassword); + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_add_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_add_cred.c new file mode 100644 index 0000000..6d44f5c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_add_cred.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_cred(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + return gss_add_cred_from(minor_status, + rk_UNCONST(input_cred_handle), + desired_name, + desired_mech, + cred_usage, + initiator_time_req, + acceptor_time_req, + GSS_C_NO_CRED_STORE, + output_cred_handle, + actual_mechs, + initiator_time_rec, + acceptor_time_rec); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_add_cred_from.c b/third_party/heimdal/lib/gssapi/mech/gss_add_cred_from.c new file mode 100644 index 0000000..9f761e8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_add_cred_from.c @@ -0,0 +1,292 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * Copyright (c) 2018 AuriStor, Inc. + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +OM_uint32 +_gss_mg_add_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + const struct _gss_mechanism_name *mn, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **out, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *new_mc = NULL; + + if (out) { + *out = NULL; + + new_mc = calloc(1, sizeof(struct _gss_mechanism_cred)); + if (new_mc == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + new_mc->gmc_mech = m; + new_mc->gmc_mech_oid = &m->gm_mech_oid; + } + + if (m->gm_add_cred_from) { + major_status = m->gm_add_cred_from(minor_status, + mc ? mc->gmc_cred : GSS_C_NO_CREDENTIAL, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &m->gm_mech_oid, + cred_usage, + initiator_time_req, + acceptor_time_req, + cred_store, + new_mc ? &new_mc->gmc_cred : NULL, + NULL, + initiator_time_rec, + acceptor_time_rec); + } else if (cred_store == GSS_C_NO_CRED_STORE && m->gm_add_cred) { + major_status = m->gm_add_cred(minor_status, + mc ? mc->gmc_cred : GSS_C_NO_CREDENTIAL, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &m->gm_mech_oid, + cred_usage, + initiator_time_req, + acceptor_time_req, + new_mc ? &new_mc->gmc_cred : NULL, + NULL, + initiator_time_rec, + acceptor_time_rec); + } else + major_status = GSS_S_UNAVAILABLE; + + if (major_status == GSS_S_COMPLETE && out) { + heim_assert(new_mc->gmc_cred != GSS_C_NO_CREDENTIAL, + "mechanism gss_add_cred did not return a cred"); + *out = new_mc; + } else + free(new_mc); + + return major_status; +} + +static OM_uint32 +add_mech_cred_internal(OM_uint32 *minor_status, + gss_const_name_t desired_name, + gssapi_mech_interface m, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_cred *mut_cred, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *mc; + struct _gss_mechanism_name *mn; + + heim_assert((m->gm_flags & GM_USE_MG_CRED) == 0, + "add_mech_cred_internal must be called with concrete mechanism"); + + if (desired_name != GSS_C_NO_NAME) { + major_status = _gss_find_mn(minor_status, + (struct _gss_name *)desired_name, + &m->gm_mech_oid, &mn); + if (major_status != GSS_S_COMPLETE) + return major_status; + } else + mn = NULL; + + /* + * If we have an existing mechanism credential for mechanism m, then + * add the desired credential to it; otherwise, create a new one and + * add it to mut_cred. + */ + HEIM_TAILQ_FOREACH(mc, &mut_cred->gc_mc, gmc_link) { + if (gss_oid_equal(&m->gm_mech_oid, mc->gmc_mech_oid)) + break; + } + + if (mc) { + major_status = _gss_mg_add_mech_cred(minor_status, m, + mc, mn, cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, NULL, + initiator_time_rec, acceptor_time_rec); + } else { + struct _gss_mechanism_cred *new_mc = NULL; + + major_status = _gss_mg_add_mech_cred(minor_status, m, + NULL, mn, cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, &new_mc, + initiator_time_rec, acceptor_time_rec); + if (major_status == GSS_S_COMPLETE) + HEIM_TAILQ_INSERT_TAIL(&mut_cred->gc_mc, new_mc, gmc_link); + } + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_cred_from(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + gss_cred_id_t release_cred = GSS_C_NO_CREDENTIAL; + struct _gss_cred *mut_cred; + OM_uint32 junk; + + *minor_status = 0; + + /* Input validation */ + if (output_cred_handle) + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (initiator_time_rec) + *initiator_time_rec = 0; + if (acceptor_time_rec) + *acceptor_time_rec = 0; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if ((m = __gss_get_mechanism(desired_mech)) == NULL) + return GSS_S_BAD_MECH; + if (input_cred_handle == GSS_C_NO_CREDENTIAL && + output_cred_handle == NULL) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + /* Setup mut_cred to be the credential we mutate */ + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + output_cred_handle != NULL) { + gss_cred_id_t new_cred; + + /* Duplicate the input credential */ + major_status = gss_duplicate_cred(minor_status, input_cred_handle, + &new_cred); + if (major_status != GSS_S_COMPLETE) + return major_status; + mut_cred = (struct _gss_cred *)new_cred; + release_cred = (gss_cred_id_t)mut_cred; + } else if (input_cred_handle != GSS_C_NO_CREDENTIAL) { + /* Mutate the input credentials */ + mut_cred = rk_UNCONST(input_cred_handle); + } else { + mut_cred = _gss_mg_alloc_cred(); + if (mut_cred == NULL) { + *minor_status = ENOMEM; + return GSS_S_UNAVAILABLE; + } + release_cred = (gss_cred_id_t)mut_cred; + } + + if (m->gm_flags & GM_USE_MG_CRED) { + struct _gss_mech_switch *ms; + OM_uint32 initiator_time_min = GSS_C_INDEFINITE; + OM_uint32 acceptor_time_min = GSS_C_INDEFINITE; + + major_status = GSS_S_UNAVAILABLE; /* in case of no mechs */ + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; /* for _gss_mg_error() */ + + if (m->gm_flags & GM_USE_MG_CRED) + continue; + + major_status = add_mech_cred_internal(minor_status, desired_name, m, + cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, mut_cred, + initiator_time_rec, acceptor_time_rec); + if (major_status != GSS_S_COMPLETE) + continue; + + if (initiator_time_rec && *initiator_time_rec < initiator_time_min) + initiator_time_min = *initiator_time_rec; + if (acceptor_time_rec && *acceptor_time_rec < acceptor_time_min) + acceptor_time_min = *acceptor_time_rec; + } + } else { + OM_uint32 lifetime; + gss_cred_usage_t usage = GSS_C_BOTH; + + major_status = gss_inquire_cred(minor_status, input_cred_handle, + NULL, &lifetime, &usage, NULL); + if (major_status == GSS_S_COMPLETE) { + if (usage == GSS_C_BOTH || usage == GSS_C_INITIATE) + initiator_time_min = lifetime; + if (usage == GSS_C_BOTH || usage == GSS_C_ACCEPT) + acceptor_time_min = lifetime; + } + } + + if (initiator_time_rec) + *initiator_time_rec = initiator_time_min; + if (acceptor_time_rec) + *acceptor_time_rec = acceptor_time_min; + } else { + major_status = add_mech_cred_internal(minor_status, desired_name, m, + cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, mut_cred, + initiator_time_rec, acceptor_time_rec); + } + + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + + /* Lastly, we have to inquire the cred to get the actual_mechs */ + if (major_status == GSS_S_COMPLETE && actual_mechs != NULL) { + major_status = gss_inquire_cred(minor_status, + (gss_const_cred_id_t)mut_cred, NULL, + NULL, NULL, actual_mechs); + } + if (major_status == GSS_S_COMPLETE) { + if (output_cred_handle != NULL) + *output_cred_handle = (gss_cred_id_t)mut_cred; + } else { + gss_release_cred(&junk, &release_cred); + } + return major_status; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_add_cred_with_password.c b/third_party/heimdal/lib/gssapi/mech/gss_add_cred_with_password.c new file mode 100644 index 0000000..eeb5949 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_add_cred_with_password.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_cred_with_password(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + const gss_buffer_t password, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + gss_key_value_element_desc kv; + gss_key_value_set_desc store; + char *spassword = NULL; + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + if (password == GSS_C_NO_BUFFER || password->value == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + spassword = malloc(password->length + 1); + if (spassword == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(spassword, password->value, password->length); + spassword[password->length] = '\0'; + + kv.key = "password"; + kv.value = spassword; + + store.count = 1; + store.elements = &kv; + + major_status = gss_add_cred_from(minor_status, + rk_UNCONST(input_cred_handle), + desired_name, + desired_mech, + cred_usage, + initiator_time_req, + acceptor_time_req, + &store, + output_cred_handle, + actual_mechs, + initiator_time_rec, + acceptor_time_rec); + + if (spassword) { + memset_s(spassword, password->length, 0, password->length); + free(spassword); + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_add_oid_set_member.c b/third_party/heimdal/lib/gssapi/mech/gss_add_oid_set_member.c new file mode 100644 index 0000000..8574224 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_add_oid_set_member.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +/** + * Add a oid to the oid set. + * + * If there is a duplicate member of the oid, the new member is not + * added to to the set. + * + * @param minor_status minor status code. + * @param member_oid member to add to the oid set + * @param oid_set oid set to add the member too + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_oid_set_member (OM_uint32 * minor_status, + const gss_OID member_oid, + gss_OID_set * oid_set) +{ + gss_OID tmp, interned_oid; + size_t n; + OM_uint32 res; + int present; + + res = gss_test_oid_set_member(minor_status, member_oid, *oid_set, &present); + if (res != GSS_S_COMPLETE) + return res; + + if (present) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + + n = (*oid_set)->count + 1; + tmp = realloc ((*oid_set)->elements, n * sizeof(gss_OID_desc)); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + (*oid_set)->elements = tmp; + + res = _gss_intern_oid(minor_status, member_oid, &interned_oid); + if (res != GSS_S_COMPLETE) + return res; + + (*oid_set)->count = n; + (*oid_set)->elements[n-1] = *interned_oid; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_aeap.c b/third_party/heimdal/lib/gssapi/mech/gss_aeap.c new file mode 100644 index 0000000..dbcd611 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_aeap.c @@ -0,0 +1,334 @@ +/* + * AEAD support + */ + +#include "mech_locl.h" + +/** + * Encrypts or sign the data. + * + * This is a more complicated version of gss_wrap(), it allows the + * caller to use AEAD data (signed header/trailer) and allow greater + * controll over where the encrypted data is placed. + * + * The maximum packet size is gss_context_stream_sizes.max_msg_size. + * + * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode: + * + * - HEADER (of size gss_context_stream_sizes.header) + * { DATA or SIGN_ONLY } (optional, zero or more) + * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted) + * TRAILER (of size gss_context_stream_sizes.trailer) + * + * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the + * DATA elements is padded to a block bountry and header is of at + * least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer. + * + * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large. + * + * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER + * + * When used in conf_req_flag=0, + * + * - HEADER (of size gss_context_stream_sizes.header) + * { DATA or SIGN_ONLY } (optional, zero or more) + * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted) + * TRAILER (of size gss_context_stream_sizes.trailer) + * + * + * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or + * gss_context_query_attributes(). + * + * @ingroup gssapi + */ + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_wrap_iov == NULL) + return GSS_S_UNAVAILABLE; + + return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +/** + * Decrypt or verifies the signature on the data. + * + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_unwrap_iov == NULL) + return GSS_S_UNAVAILABLE; + + return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx, + conf_state, qop_state, + iov, iov_count); +} + +/** + * Update the length fields in iov buffer for the types: + * - GSS_IOV_BUFFER_TYPE_HEADER + * - GSS_IOV_BUFFER_TYPE_PADDING + * - GSS_IOV_BUFFER_TYPE_TRAILER + * + * Consider using gss_context_query_attributes() to fetch the data instead. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (minor_status) + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + m = ctx->gc_mech; + + if (m->gm_wrap_iov_length == NULL) + return GSS_S_UNAVAILABLE; + + return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +/** + * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by + * looking at the GSS_IOV_BUFFER_FLAG_ALLOCATED flag. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_iov_buffer(OM_uint32 *minor_status, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 junk; + int i; + + if (minor_status) + *minor_status = 0; + if (iov == NULL && iov_count != 0) + return GSS_S_CALL_INACCESSIBLE_READ; + + for (i = 0; i < iov_count; i++) { + if ((iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0) + continue; + gss_release_buffer(&junk, &iov[i].buffer); + iov[i].type &= ~GSS_IOV_BUFFER_FLAG_ALLOCATED; + } + return GSS_S_COMPLETE; +} + +/** + * Query the context for parameters. + * + * SSPI equivalent if this function is QueryContextAttributes. + * + * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes. + * + * @ingroup gssapi + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_attr_stream_sizes_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")}; + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_context_query_attributes(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID attribute, + void *data, + size_t len) +{ + if (minor_status) + *minor_status = 0; + + if (gss_oid_equal(GSS_C_ATTR_STREAM_SIZES, attribute)) { + memset(data, 0, len); + return GSS_S_COMPLETE; + } + + return GSS_S_FAILURE; +} + +/* + * AEAD wrap API for a single piece of associated data, for compatibility + * with MIT and as specified by draft-howard-gssapi-aead-00.txt. + * + * @ingroup gssapi + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_assoc_buffer, + gss_buffer_t input_payload_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + OM_uint32 major_status, tmp, flags = 0; + gss_iov_buffer_desc iov[5]; + size_t i; + unsigned char *p; + + memset(iov, 0, sizeof(iov)); + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + if (input_assoc_buffer) + iov[1].buffer = *input_assoc_buffer; + + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + if (input_payload_buffer) + iov[2].buffer.length = input_payload_buffer->length; + + gss_inquire_context(minor_status, context_handle, NULL, NULL, + NULL, NULL, &flags, NULL, NULL); + + /* krb5 mech rejects padding/trailer if DCE-style is set */ + iov[3].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY + : GSS_IOV_BUFFER_TYPE_PADDING; + iov[4].type = (flags & GSS_C_DCE_STYLE) ? GSS_IOV_BUFFER_TYPE_EMPTY + : GSS_IOV_BUFFER_TYPE_TRAILER; + + major_status = gss_wrap_iov_length(minor_status, context_handle, + conf_req_flag, qop_req, conf_state, + iov, 5); + if (GSS_ERROR(major_status)) + return major_status; + + for (i = 0, output_message_buffer->length = 0; i < 5; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY) + continue; + + output_message_buffer->length += iov[i].buffer.length; + } + + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + for (i = 0, p = output_message_buffer->value; i < 5; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_SIGN_ONLY) + continue; + else if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) + memcpy(p, input_payload_buffer->value, input_payload_buffer->length); + + iov[i].buffer.value = p; + p += iov[i].buffer.length; + } + + major_status = gss_wrap_iov(minor_status, context_handle, conf_req_flag, + qop_req, conf_state, iov, 5); + if (GSS_ERROR(major_status)) + gss_release_buffer(&tmp, output_message_buffer); + + return major_status; +} + +/* + * AEAD unwrap for a single piece of associated data, for compatibility + * with MIT and as specified by draft-howard-gssapi-aead-00.txt. + * + * @ingroup gssapi + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t input_assoc_buffer, + gss_buffer_t output_payload_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + OM_uint32 major_status, tmp; + gss_iov_buffer_desc iov[3]; + + memset(iov, 0, sizeof(iov)); + + iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM; + iov[0].buffer = *input_message_buffer; + + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + if (input_assoc_buffer) + iov[1].buffer = *input_assoc_buffer; + + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE; + + major_status = gss_unwrap_iov(minor_status, context_handle, conf_state, + qop_state, iov, 3); + if (GSS_ERROR(major_status)) + gss_release_iov_buffer(&tmp, &iov[2], 1); + else + *output_payload_buffer = iov[2].buffer; + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_authorize_localname.c b/third_party/heimdal/lib/gssapi/mech/gss_authorize_localname.c new file mode 100644 index 0000000..b72b7bd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_authorize_localname.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +gss_buffer_desc GSSAPI_LIB_VARIABLE __gss_c_attr_local_login_user = { + sizeof("local-login-user") - 1, + "local-login-user" +}; + +static OM_uint32 +mech_authorize_localname(OM_uint32 *minor_status, + const struct _gss_name *name, + const struct _gss_name *user) +{ + OM_uint32 major_status = GSS_S_NAME_NOT_MN; + struct _gss_mechanism_name *mn; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (m->gm_authorize_localname == NULL) { + major_status = GSS_S_UNAVAILABLE; + continue; + } + + major_status = m->gm_authorize_localname(minor_status, + mn->gmn_name, + &user->gn_value, + user->gn_type); + if (major_status != GSS_S_UNAUTHORIZED) + break; + } + + return major_status; +} + +/* + * Naming extensions based local login authorization. + */ +static OM_uint32 +attr_authorize_localname(OM_uint32 *minor_status, + const struct _gss_name *name, + const struct _gss_name *user) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + int more = -1; + + if (!gss_oid_equal(user->gn_type, GSS_C_NT_USER_NAME)) + return GSS_S_BAD_NAMETYPE; + + while (more != 0 && major_status != GSS_S_COMPLETE) { + OM_uint32 tmpMajor, tmpMinor; + gss_buffer_desc value; + gss_buffer_desc display_value; + int authenticated = 0, complete = 0; + + tmpMajor = gss_get_name_attribute(minor_status, + (gss_name_t)name, + GSS_C_ATTR_LOCAL_LOGIN_USER, + &authenticated, + &complete, + &value, + &display_value, + &more); + if (GSS_ERROR(tmpMajor)) { + major_status = tmpMajor; + break; + } + + /* If attribute is present, return an authoritative error code. */ + if (authenticated && + value.length == user->gn_value.length && + memcmp(value.value, user->gn_value.value, user->gn_value.length) == 0) + major_status = GSS_S_COMPLETE; + else + major_status = GSS_S_UNAUTHORIZED; + + gss_release_buffer(&tmpMinor, &value); + gss_release_buffer(&tmpMinor, &display_value); + } + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_authorize_localname(OM_uint32 *minor_status, + gss_const_name_t gss_name, + gss_const_name_t gss_user) + +{ + OM_uint32 major_status; + const struct _gss_name *name = (const struct _gss_name *) gss_name; + const struct _gss_name *user = (const struct _gss_name *) gss_user; + int mechAvailable = 0; + + *minor_status = 0; + + if (gss_name == GSS_C_NO_NAME || gss_user == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ; + + /* + * We should check that the user name is not a mechanism name, but + * as Heimdal always calls the mechanism's gss_import_name(), it's + * not possible to make this check. + */ +#if 0 + if (HEIM_TAILQ_FIRST(&user->gn_mn) != NULL) + return GSS_S_BAD_NAME; +#endif + + /* If mech returns yes, we return yes */ + major_status = mech_authorize_localname(minor_status, name, user); + if (major_status == GSS_S_COMPLETE) + return GSS_S_COMPLETE; + else if (major_status != GSS_S_UNAVAILABLE) + mechAvailable = 1; + + /* If attribute exists, it is authoritative */ + major_status = attr_authorize_localname(minor_status, name, user); + if (major_status == GSS_S_COMPLETE || major_status == GSS_S_UNAUTHORIZED) + return major_status; + + /* If mechanism did not implement SPI, compare the local name */ + if (mechAvailable == 0) { + int match = 0; + + major_status = gss_compare_name(minor_status, gss_name, + gss_user, &match); + if (major_status == GSS_S_COMPLETE && match == 0) + major_status = GSS_S_UNAUTHORIZED; + } + + return major_status; +} + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_userok(gss_const_name_t name, + const char *user) +{ + OM_uint32 major_status, minor_status; + gss_buffer_desc userBuf; + gss_name_t userName; + + userBuf.value = (void *)user; + userBuf.length = strlen(user); + + major_status = gss_import_name(&minor_status, &userBuf, + GSS_C_NT_USER_NAME, &userName); + if (GSS_ERROR(major_status)) + return 0; + + major_status = gss_authorize_localname(&minor_status, name, userName); + + gss_release_name(&minor_status, &userName); + + return (major_status == GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_buffer_set.c b/third_party/heimdal/lib/gssapi/mech/gss_buffer_set.c new file mode 100644 index 0000000..48fb720 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_buffer_set.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_create_empty_buffer_set + (OM_uint32 * minor_status, + gss_buffer_set_t *buffer_set) +{ + gss_buffer_set_t set; + + set = (gss_buffer_set_desc *) malloc(sizeof(*set)); + if (set == GSS_C_NO_BUFFER_SET) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + set->count = 0; + set->elements = NULL; + + *buffer_set = set; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_buffer_set_member + (OM_uint32 * minor_status, + const gss_buffer_t member_buffer, + gss_buffer_set_t *buffer_set) +{ + gss_buffer_set_t set; + gss_buffer_t p; + OM_uint32 ret; + + if (*buffer_set == GSS_C_NO_BUFFER_SET) { + ret = gss_create_empty_buffer_set(minor_status, + buffer_set); + if (ret) { + return ret; + } + } + + set = *buffer_set; + set->elements = realloc(set->elements, + (set->count + 1) * sizeof(set->elements[0])); + if (set->elements == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = &set->elements[set->count]; + + p->value = malloc(member_buffer->length); + if (p->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(p->value, member_buffer->value, member_buffer->length); + p->length = member_buffer->length; + + set->count++; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_buffer_set(OM_uint32 * minor_status, + gss_buffer_set_t *buffer_set) +{ + size_t i; + OM_uint32 minor; + + *minor_status = 0; + + if (*buffer_set == GSS_C_NO_BUFFER_SET) + return GSS_S_COMPLETE; + + for (i = 0; i < (*buffer_set)->count; i++) + gss_release_buffer(&minor, &((*buffer_set)->elements[i])); + + free((*buffer_set)->elements); + + (*buffer_set)->elements = NULL; + (*buffer_set)->count = 0; + + free(*buffer_set); + *buffer_set = GSS_C_NO_BUFFER_SET; + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_canonicalize_name.c b/third_party/heimdal/lib/gssapi/mech/gss_canonicalize_name.c new file mode 100644 index 0000000..859c688 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_canonicalize_name.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_canonicalize_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/** + * gss_canonicalize_name takes a Internal Name (IN) and converts in into a + * mechanism specific Mechanism Name (MN). + * + * The input name may multiple name, or generic name types. + * + * If the input_name if of the GSS_C_NT_USER_NAME, and the Kerberos + * mechanism is specified, the resulting MN type is a + * GSS_KRB5_NT_PRINCIPAL_NAME. + * + * For more information about @ref internalVSmechname. + * + * @param minor_status minor status code. + * @param input_name name to covert, unchanged by gss_canonicalize_name(). + * @param mech_type the type to convert Name too. + * @param output_name the resulting type, release with + * gss_release_name(), independent of input_name. + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_canonicalize_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t *output_name) +{ + OM_uint32 major_status; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + gssapi_mech_interface m; + gss_name_t new_canonical_name; + + *minor_status = 0; + *output_name = GSS_C_NO_NAME; + + if ((m = __gss_get_mechanism(mech_type)) == NULL || + (m->gm_flags & GM_USE_MG_NAME)) + return GSS_S_BAD_MECH; + + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status) + return major_status; + if (mn == NULL) + return GSS_S_BAD_NAME; + + m = mn->gmn_mech; + major_status = m->gm_canonicalize_name(minor_status, + mn->gmn_name, mech_type, &new_canonical_name); + if (major_status) { + _gss_mg_error(m, *minor_status); + return (major_status); + } + + /* + * Now we make a new name and mark it as an MN. + */ + *minor_status = 0; + name = _gss_create_name(new_canonical_name, m); + if (!name) { + m->gm_release_name(minor_status, &new_canonical_name); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + *output_name = (gss_name_t) name; + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c b/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c new file mode 100644 index 0000000..97ef578 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_compare_name.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_compare_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_compare_name(OM_uint32 *minor_status, + gss_const_name_t name1_arg, + gss_const_name_t name2_arg, + int *name_equal) +{ + struct _gss_name *name1 = (struct _gss_name *) name1_arg; + struct _gss_name *name2 = (struct _gss_name *) name2_arg; + + /* + * First check the implementation-independant name if both + * names have one. Otherwise, try to find common mechanism + * names and compare them. + */ + if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type == GSS_C_NO_OID && name2->gn_type == GSS_C_NO_OID) { + *name_equal = + name1->gn_value.length == name2->gn_value.length && + memcmp(name1->gn_value.value, name2->gn_value.value, + name1->gn_value.length) == 0; + } else if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type != GSS_C_NO_OID && + name2->gn_type != GSS_C_NO_OID) { + *name_equal = 1; + /* RFC 2743: anonymous names always compare false */ + if (gss_oid_equal(name1->gn_type, GSS_C_NT_ANONYMOUS) || + gss_oid_equal(name2->gn_type, GSS_C_NT_ANONYMOUS) || + !gss_oid_equal(name1->gn_type, name2->gn_type)) { + *name_equal = 0; + } else if (name1->gn_value.length != name2->gn_value.length || + memcmp(name1->gn_value.value, name2->gn_value.value, + name1->gn_value.length) != 0) { + *name_equal = 0; + } + } else { + struct _gss_mechanism_name *mn1; + struct _gss_mechanism_name *mn2; + + HEIM_TAILQ_FOREACH(mn1, &name1->gn_mn, gmn_link) { + OM_uint32 major_status; + + major_status = _gss_find_mn(minor_status, name2, + mn1->gmn_mech_oid, &mn2); + if (major_status == GSS_S_COMPLETE && mn2) { + return (mn1->gmn_mech->gm_compare_name( + minor_status, + mn1->gmn_name, + mn2->gmn_name, + name_equal)); + } + } + HEIM_TAILQ_FOREACH(mn2, &name2->gn_mn, gmn_link) { + OM_uint32 major_status; + + major_status = _gss_find_mn(minor_status, name1, + mn2->gmn_mech_oid, &mn1); + if (major_status == GSS_S_COMPLETE && mn1) { + return (mn2->gmn_mech->gm_compare_name( + minor_status, + mn2->gmn_name, + mn1->gmn_name, + name_equal)); + } + } + *name_equal = 0; + } + + *minor_status = 0; + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_context_time.c b/third_party/heimdal/lib/gssapi/mech/gss_context_time.c new file mode 100644 index 0000000..a5b646c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_context_time.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_context_time.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_context_time(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 *time_rec) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m = ctx->gc_mech; + + return (m->gm_context_time(minor_status, ctx->gc_ctx, time_rec)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_create_empty_oid_set.c b/third_party/heimdal/lib/gssapi/mech/gss_create_empty_oid_set.c new file mode 100644 index 0000000..8d880f5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_create_empty_oid_set.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_create_empty_oid_set.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_create_empty_oid_set(OM_uint32 *minor_status, + gss_OID_set *oid_set) +{ + gss_OID_set set; + + *minor_status = 0; + *oid_set = GSS_C_NO_OID_SET; + + set = malloc(sizeof(gss_OID_set_desc)); + if (!set) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + set->count = 0; + set->elements = 0; + *oid_set = set; + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_cred.c new file mode 100644 index 0000000..00561ce --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_cred.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include + +static OM_uint32 +store_mech_oid_and_oid_set(OM_uint32 *minor_status, + krb5_storage *sp, + gss_const_OID mech, + gss_const_OID_set oids) +{ + OM_uint32 ret; + size_t i, len; + + ret = _gss_mg_store_oid(minor_status, sp, mech); + if (ret) + return ret; + + for (i = 0, len = 0; i < oids->count; i++) + len += 4 + oids->elements[i].length; + + *minor_status = krb5_store_uint32(sp, len); + if (*minor_status) + return GSS_S_FAILURE; + + for (i = 0; i < oids->count; i++) { + ret = _gss_mg_store_oid(minor_status, sp, &oids->elements[i]); + if (ret) + return ret; + } + + return GSS_S_COMPLETE; +} + + +/* + * format: any number of: + * mech-len: int32 + * mech-data: char * (not alligned) + * cred-len: int32 + * cred-data char * (not alligned) + * + * where neg_mechs is encoded for GSS_SPNEGO_MECHANISM +*/ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_cred(OM_uint32 * minor_status, + gss_cred_id_t cred_handle, + gss_buffer_t token) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + struct _gss_mechanism_cred *mc; + gss_buffer_desc buffer; + krb5_error_code ret; + krb5_ssize_t bytes; + krb5_storage *sp; + OM_uint32 major; + krb5_data data; + + _mg_buffer_zero(token); + + if (cred == NULL) { + *minor_status = 0; + return GSS_S_NO_CRED; + } + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + if (mc->gmc_mech->gm_export_cred == NULL) { + *minor_status = 0; + gss_mg_set_error_string(&mc->gmc_mech->gm_mech_oid, + GSS_S_NO_CRED, *minor_status, + "Credential doesn't support exporting"); + return GSS_S_NO_CRED; + } + } + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + major = mc->gmc_mech->gm_export_cred(minor_status, + mc->gmc_cred, &buffer); + if (major) { + krb5_storage_free(sp); + return major; + } + + if (buffer.length) { + bytes = krb5_storage_write(sp, buffer.value, buffer.length); + if (bytes < 0 || (size_t)bytes != buffer.length) { + _gss_secure_release_buffer(minor_status, &buffer); + krb5_storage_free(sp); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + _gss_secure_release_buffer(minor_status, &buffer); + } + + if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) { + major = store_mech_oid_and_oid_set(minor_status, sp, + GSS_SPNEGO_MECHANISM, + cred->gc_neg_mechs); + if (major != GSS_S_COMPLETE) { + krb5_storage_free(sp); + return major; + } + } + + ret = krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (data.length == 0) { + *minor_status = 0; + gss_mg_set_error_string(GSS_C_NO_OID, + GSS_S_NO_CRED, *minor_status, + "Credential was not exportable"); + return GSS_S_NO_CRED; + } + + token->value = data.data; + token->length = data.length; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +import_oid_set(OM_uint32 *minor_status, + gss_const_buffer_t token, + gss_OID_set *oids) +{ + OM_uint32 major, junk; + krb5_storage *sp = NULL; + + *oids = GSS_C_NO_OID_SET; + + if (token->length == 0) + return GSS_S_COMPLETE; + + major = gss_create_empty_oid_set(minor_status, oids); + if (major != GSS_S_COMPLETE) + goto out; + + sp = krb5_storage_from_readonly_mem(token->value, token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + while (1) { + gss_OID oid; + + major = _gss_mg_ret_oid(minor_status, sp, &oid); + if (*minor_status == (OM_uint32)HEIM_ERR_EOF) + break; + else if (major) + goto out; + + major = gss_add_oid_set_member(minor_status, oid, oids); + if (major != GSS_S_COMPLETE) + goto out; + } + + major = GSS_S_COMPLETE; + *minor_status = 0; + +out: + if (major != GSS_S_COMPLETE) + gss_release_oid_set(&junk, oids); + krb5_storage_free(sp); + + return major; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_import_cred(OM_uint32 * minor_status, + gss_buffer_t token, + gss_cred_id_t * cred_handle) +{ + gssapi_mech_interface m; + struct _gss_cred *cred; + krb5_storage *sp = NULL; + OM_uint32 major, junk; + + *cred_handle = GSS_C_NO_CREDENTIAL; + + if (token->length == 0) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + sp = krb5_storage_from_readonly_mem(token->value, token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + cred = _gss_mg_alloc_cred(); + if (cred == NULL) { + krb5_storage_free(sp); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *cred_handle = (gss_cred_id_t)cred; + + while(1) { + struct _gss_mechanism_cred *mc; + gss_buffer_desc buffer; + gss_cred_id_t mcred; + gss_OID oid; + + major = _gss_mg_ret_oid(minor_status, sp, &oid); + if (*minor_status == (OM_uint32)HEIM_ERR_EOF) + break; + else if (major != GSS_S_COMPLETE) + goto out; + + m = __gss_get_mechanism(oid); + if (!m) { + *minor_status = 0; + major = GSS_S_BAD_MECH; + goto out; + } + + if (m->gm_import_cred == NULL) { + *minor_status = 0; + major = GSS_S_BAD_MECH; + goto out; + } + + major = _gss_mg_ret_buffer(minor_status, sp, &buffer); + if (major != GSS_S_COMPLETE) + goto out; + + if (buffer.value == NULL) { + major = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + if (gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) { + major = import_oid_set(minor_status, &buffer, &cred->gc_neg_mechs); + gss_release_buffer(&junk, &buffer); + if (major != GSS_S_COMPLETE) + goto out; + else + continue; + } + + major = m->gm_import_cred(minor_status, &buffer, &mcred); + gss_release_buffer(&junk, &buffer); + if (major != GSS_S_COMPLETE) + goto out; + + mc = calloc(1, sizeof(struct _gss_mechanism_cred)); + if (mc == NULL) { + *minor_status = EINVAL; + major = GSS_S_FAILURE; + goto out; + } + + mc->gmc_mech = m; + mc->gmc_mech_oid = &m->gm_mech_oid; + mc->gmc_cred = mcred; + + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); + } + krb5_storage_free(sp); + sp = NULL; + + if (HEIM_TAILQ_EMPTY(&cred->gc_mc)) { + major = GSS_S_NO_CRED; + goto out; + } + + return GSS_S_COMPLETE; + + out: + if (sp) + krb5_storage_free(sp); + + gss_release_cred(&junk, cred_handle); + + return major; + +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_decapsulate_token.c b/third_party/heimdal/lib/gssapi/mech/gss_decapsulate_token.c new file mode 100644 index 0000000..5d9eca0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_decapsulate_token.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_decapsulate_token(gss_const_buffer_t input_token, + gss_const_OID oid, + gss_buffer_t output_token) +{ + GSSAPIContextToken ct; + heim_oid o; + OM_uint32 status; + int ret; + size_t size; + + _mg_buffer_zero(output_token); + + ret = der_get_oid (oid->elements, oid->length, &o, &size); + if (ret) + return GSS_S_FAILURE; + + ret = decode_GSSAPIContextToken(input_token->value, input_token->length, + &ct, NULL); + if (ret) { + der_free_oid(&o); + return GSS_S_DEFECTIVE_TOKEN; + } + + if (der_heim_oid_cmp(&ct.thisMech, &o) == 0) { + status = GSS_S_COMPLETE; + output_token->value = ct.innerContextToken.data; + output_token->length = ct.innerContextToken.length; + der_free_oid(&ct.thisMech); + } else { + free_GSSAPIContextToken(&ct); + status = GSS_S_BAD_MECH; + } + der_free_oid(&o); + + return status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_delete_name_attribute.c b/third_party/heimdal/lib/gssapi/mech/gss_delete_name_attribute.c new file mode 100644 index 0000000..a1ca5da --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_delete_name_attribute.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t attr) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_delete_name_attribute) + continue; + + major_status = m->gm_delete_name_attribute(minor_status, + mn->gmn_name, + attr); + if (GSS_ERROR(major_status)) + _gss_mg_error(m, *minor_status); + else + break; + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_delete_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_delete_sec_context.c new file mode 100644 index 0000000..8e1f98c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_delete_sec_context.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_delete_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_delete_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + OM_uint32 major_status; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + + if (output_token) + _mg_buffer_zero(output_token); + + *minor_status = 0; + major_status = GSS_S_COMPLETE; + + if (!ctx) + return GSS_S_COMPLETE; + + free(ctx->gc_free_this); + + /* + * If we have an implementation ctx, delete it, + * otherwise fake an empty token. + */ + if (ctx->gc_ctx) { + major_status = ctx->gc_mech->gm_delete_sec_context( + minor_status, &ctx->gc_ctx, output_token); + } + free(ctx); + *context_handle = GSS_C_NO_CONTEXT; + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_destroy_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_destroy_cred.c new file mode 100644 index 0000000..5b7fafc --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_destroy_cred.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include + +/** + * Destroy a credential + * + * gss_release_cred() frees the memory, gss_destroy_cred() removes the credentials from memory/disk and then call gss_release_cred() on the credential. + * + * @param min_stat minor status code + * @param cred_handle credentail to destory + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_destroy_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) +{ + struct _gss_cred *cred; + struct _gss_mechanism_cred *mc, *next; + + OM_uint32 junk; + + if (cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + if (*cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_COMPLETE; + + cred = (struct _gss_cred *)*cred_handle; + *cred_handle = GSS_C_NO_CREDENTIAL; + + HEIM_TAILQ_FOREACH_SAFE(mc, &cred->gc_mc, gmc_link, next) { + HEIM_TAILQ_REMOVE(&cred->gc_mc, mc, gmc_link); + if (mc->gmc_mech->gm_destroy_cred) + mc->gmc_mech->gm_destroy_cred(&junk, &mc->gmc_cred); + else + mc->gmc_mech->gm_release_cred(&junk, &mc->gmc_cred); + free(mc); + } + free(cred); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_display_name.c b/third_party/heimdal/lib/gssapi/mech/gss_display_name.c new file mode 100644 index 0000000..fadd68b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_display_name.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_display_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + OM_uint32 major_status; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + _mg_buffer_zero(output_name_buffer); + if (output_name_type) + *output_name_type = GSS_C_NO_OID; + + if (name == NULL) { + *minor_status = 0; + return (GSS_S_BAD_NAME); + } + + /* + * If we know it, copy the buffer used to import the name in + * the first place. Otherwise, ask all the MNs in turn if + * they can display the thing. + */ + if (name->gn_value.value) { + output_name_buffer->value = malloc(name->gn_value.length); + if (!output_name_buffer->value) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + output_name_buffer->length = name->gn_value.length; + memcpy(output_name_buffer->value, name->gn_value.value, + output_name_buffer->length); + if (output_name_type) + *output_name_type = name->gn_type; + + *minor_status = 0; + return (GSS_S_COMPLETE); + } else { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + major_status = mn->gmn_mech->gm_display_name( + minor_status, mn->gmn_name, + output_name_buffer, + output_name_type); + if (major_status == GSS_S_COMPLETE) + return (GSS_S_COMPLETE); + } + } + + *minor_status = 0; + return (GSS_S_FAILURE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_display_name_ext.c b/third_party/heimdal/lib/gssapi/mech/gss_display_name_ext.c new file mode 100644 index 0000000..80ea72b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_display_name_ext.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_name_ext(OM_uint32 *minor_status, + gss_name_t input_name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + _mg_buffer_zero(display_name); + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_display_name_ext) + continue; + + major_status = m->gm_display_name_ext(minor_status, + mn->gmn_name, + display_as_name_type, + display_name); + if (GSS_ERROR(major_status)) + _gss_mg_error(m, *minor_status); + else + break; + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_display_status.c b/third_party/heimdal/lib/gssapi/mech/gss_display_status.c new file mode 100644 index 0000000..dca5d1b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_display_status.c @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_display_status.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ +/* + * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +static const char * +calling_error(OM_uint32 v) +{ + static const char *msgs[] = { + NULL, /* 0 */ + "A required input parameter could not be read.", /* */ + "A required output parameter could not be written.", /* */ + "A parameter was malformed" + }; + + v >>= GSS_C_CALLING_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown calling error"; + else + return msgs[v]; +} + +static const char * +routine_error(OM_uint32 v) +{ + static const char *msgs[] = { + "Function completed successfully", /* 0 */ + "An unsupported mechanism was requested", + "An invalid name was supplied", + "A supplied name was of an unsupported type", + "Incorrect channel bindings were supplied", + "An invalid status code was supplied", + "A token had an invalid MIC", + "No credentials were supplied, or the credentials were unavailable or inaccessible.", + "No context has been established", + "A token was invalid", + "A credential was invalid", + "The referenced credentials have expired", + "The context has expired", + "Miscellaneous failure (see text)", + "The quality-of-protection requested could not be provide", + "The operation is forbidden by local security policy", + "The operation or option is not available", + "The requested credential element already exists", + "The provided name was not a mechanism name.", + }; + + v >>= GSS_C_ROUTINE_ERROR_OFFSET; + + if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +static const char * +supplementary_error(OM_uint32 v) +{ + static const char *msgs[] = { + "normal completion", + "continuation call to routine required", + "duplicate per-message token detected", + "timed-out per-message token detected", + "reordered (early) per-message token detected", + "skipped predecessor token(s) detected" + }; + + v >>= GSS_C_SUPPLEMENTARY_OFFSET; + + if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +/** + * Convert a GSS-API status code to text + * + * @param minor_status minor status code + * @param status_value status value to convert + * @param status_type One of: + * GSS_C_GSS_CODE - status_value is a GSS status code, + * GSS_C_MECH_CODE - status_value is a mechanism status code + * @param mech_type underlying mechanism. Use GSS_C_NO_OID to obtain the + * system default. + * @param message_context state information to extract further messages from the + * status_value + * @param status_string the allocated text representation. Release with + * gss_release_buffer() + * + * @returns a gss_error code. + * + * @ingroup gssapi + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_status(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + OM_uint32 major_status; + + _mg_buffer_zero(status_string); + *message_context = 0; + + *minor_status = 0; + switch (status_type) { + case GSS_C_GSS_CODE: { + char *buf = NULL; + int e; + + if (GSS_SUPPLEMENTARY_INFO(status_value)) + e = asprintf(&buf, "%s", supplementary_error( + GSS_SUPPLEMENTARY_INFO(status_value))); + else + e = asprintf (&buf, "%s %s", + calling_error(GSS_CALLING_ERROR(status_value)), + routine_error(GSS_ROUTINE_ERROR(status_value))); + + if (e < 0 || buf == NULL) + break; + + status_string->length = strlen(buf); + status_string->value = buf; + + return GSS_S_COMPLETE; + } + case GSS_C_MECH_CODE: { + OM_uint32 maj_junk, min_junk; + gss_buffer_desc oid; + char *buf = NULL; + int e; + + major_status = _gss_mg_get_error(mech_type, status_value, + status_string); + if (major_status == GSS_S_COMPLETE) { + *message_context = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + + maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); + if (maj_junk != GSS_S_COMPLETE) { + oid.value = rk_UNCONST("unknown"); + oid.length = 7; + } + + e = asprintf (&buf, "unknown mech-code %lu for mech %.*s", + (unsigned long)status_value, + (int)oid.length, (char *)oid.value); + if (maj_junk == GSS_S_COMPLETE) + gss_release_buffer(&min_junk, &oid); + + if (e < 0 || buf == NULL) + break; + + status_string->length = strlen(buf); + status_string->value = buf; + + return GSS_S_COMPLETE; + } + } + _mg_buffer_zero(status_string); + return (GSS_S_BAD_STATUS); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_duplicate_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_cred.c new file mode 100644 index 0000000..0c25ce9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_cred.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +static OM_uint32 +copy_cred_element(OM_uint32 *minor_status, + struct _gss_mechanism_cred *mc, + struct _gss_mechanism_cred **out) +{ + gssapi_mech_interface m = mc->gmc_mech; + OM_uint32 major_status, tmp; + struct _gss_mechanism_cred *new_mc; + OM_uint32 initiator_lifetime, acceptor_lifetime; + gss_cred_usage_t cred_usage; + gss_cred_id_t dup_cred = GSS_C_NO_CREDENTIAL; + + *out = NULL; + + if (m->gm_duplicate_cred) { + major_status = m->gm_duplicate_cred(minor_status, + mc->gmc_cred, &dup_cred); + } else if (m->gm_import_cred && m->gm_export_cred) { + gss_buffer_desc export; + + major_status = m->gm_export_cred(minor_status, mc->gmc_cred, &export); + if (major_status == GSS_S_COMPLETE) { + major_status = m->gm_import_cred(minor_status, &export, &dup_cred); + _gss_secure_release_buffer(&tmp, &export); + } + } else { + struct _gss_mechanism_name mn; + + mn.gmn_mech = m; + mn.gmn_mech_oid = mc->gmc_mech_oid; + mn.gmn_name = GSS_C_NO_NAME; + + /* This path won't work for ephemeral creds or cred stores */ + major_status = m->gm_inquire_cred_by_mech(minor_status, mc->gmc_cred, + mc->gmc_mech_oid, &mn.gmn_name, + &initiator_lifetime, + &acceptor_lifetime, &cred_usage); + if (major_status == GSS_S_COMPLETE) { + major_status = _gss_mg_add_mech_cred(minor_status, + m, + NULL, /* mc */ + &mn, + cred_usage, + initiator_lifetime, + acceptor_lifetime, + GSS_C_NO_CRED_STORE, + &new_mc, + NULL, + NULL); + m->gm_release_name(&tmp, &mn.gmn_name); + } + } + + if (major_status == GSS_S_COMPLETE) { + new_mc = calloc(1, sizeof(*new_mc)); + if (new_mc == NULL) { + *minor_status = ENOMEM; + m->gm_release_cred(&tmp, &dup_cred); + return GSS_S_FAILURE; + } + + new_mc->gmc_mech = m; + new_mc->gmc_mech_oid = mc->gmc_mech_oid; + new_mc->gmc_cred = dup_cred; + + *out = new_mc; + } else + _gss_mg_error(m, *minor_status); + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_cred(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + struct _gss_mechanism_cred *mc; + struct _gss_cred *new_cred; + struct _gss_cred *cred = (struct _gss_cred *)input_cred_handle; + OM_uint32 major_status, junk; + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * "Copy" the default credential by acquiring a cred handle for the + * default credential's name, GSS_C_NO_NAME. + */ + return gss_acquire_cred(minor_status, GSS_C_NO_NAME, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_BOTH, + output_cred_handle, NULL, NULL); + } + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + new_cred = _gss_mg_alloc_cred(); + if (!new_cred) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *minor_status = 0; + major_status = GSS_S_NO_CRED; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + struct _gss_mechanism_cred *copy_mc; + + major_status = copy_cred_element(minor_status, mc, ©_mc); + if (major_status != GSS_S_COMPLETE) + break; + + HEIM_TAILQ_INSERT_TAIL(&new_cred->gc_mc, copy_mc, gmc_link); + } + + if (major_status != GSS_S_COMPLETE) { + gss_cred_id_t release_cred = (gss_cred_id_t)new_cred; + gss_release_cred(&junk, &release_cred); + new_cred = NULL; + } + + *output_cred_handle = (gss_cred_id_t)new_cred; + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_duplicate_name.c b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_name.c new file mode 100644 index 0000000..e8d1e32 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_name.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_duplicate_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_name(OM_uint32 *minor_status, + gss_const_name_t src_name, + gss_name_t *dest_name) +{ + OM_uint32 major_status; + struct _gss_name *name = (struct _gss_name *) src_name; + struct _gss_name *new_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + *dest_name = GSS_C_NO_NAME; + + /* + * If this name has a value (i.e. it didn't come from + * gss_canonicalize_name(), we re-import the thing. Otherwise, + * we make copy of each mech names. + */ + if (name->gn_value.value) { + major_status = gss_import_name(minor_status, + &name->gn_value, name->gn_type, dest_name); + if (major_status != GSS_S_COMPLETE) + return (major_status); + new_name = (struct _gss_name *) *dest_name; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + struct _gss_mechanism_name *mn2; + _gss_find_mn(minor_status, new_name, + mn->gmn_mech_oid, &mn2); + } + } else { + new_name = _gss_create_name(NULL, NULL); + if (!new_name) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + *dest_name = (gss_name_t) new_name; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + struct _gss_mechanism_name *new_mn; + + new_mn = malloc(sizeof(*new_mn)); + if (!new_mn) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + new_mn->gmn_mech = mn->gmn_mech; + new_mn->gmn_mech_oid = mn->gmn_mech_oid; + + major_status = + mn->gmn_mech->gm_duplicate_name(minor_status, + mn->gmn_name, &new_mn->gmn_name); + if (major_status != GSS_S_COMPLETE) { + free(new_mn); + continue; + } + HEIM_TAILQ_INSERT_TAIL(&new_name->gn_mn, new_mn, gmn_link); + } + + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid.c b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid.c new file mode 100644 index 0000000..29a9cf8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_oid ( + OM_uint32 *minor_status, + gss_OID src_oid, + gss_OID *dest_oid + ) +{ + *minor_status = 0; + + if (src_oid == GSS_C_NO_OID) { + *dest_oid = GSS_C_NO_OID; + return GSS_S_COMPLETE; + } + + return _gss_intern_oid(minor_status, src_oid, dest_oid); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid_set.c b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid_set.c new file mode 100644 index 0000000..ae0ab8d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_duplicate_oid_set.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_oid_set(OM_uint32 *minor_status, + gss_OID_set src_oid_set, + gss_OID_set *dest_oid_set) +{ + OM_uint32 major_status, junk; + size_t i; + + *dest_oid_set = GSS_C_NO_OID_SET; + + major_status = gss_create_empty_oid_set(minor_status, dest_oid_set); + + for (i = 0; major_status == GSS_S_COMPLETE && i < src_oid_set->count; i++) + major_status = gss_add_oid_set_member(minor_status, + &src_oid_set->elements[i], + dest_oid_set); + + if (major_status != GSS_S_COMPLETE) + gss_release_oid_set(&junk, dest_oid_set); + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_encapsulate_token.c b/third_party/heimdal/lib/gssapi/mech/gss_encapsulate_token.c new file mode 100644 index 0000000..1b1f973 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_encapsulate_token.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_encapsulate_token(gss_const_buffer_t input_token, + gss_const_OID oid, + gss_buffer_t output_token) +{ + GSSAPIContextToken ct; + int ret; + size_t size; + + ret = der_get_oid (oid->elements, oid->length, &ct.thisMech, &size); + if (ret) { + _mg_buffer_zero(output_token); + return GSS_S_FAILURE; + } + + ct.innerContextToken.data = input_token->value; + ct.innerContextToken.length = input_token->length; + + ASN1_MALLOC_ENCODE(GSSAPIContextToken, + output_token->value, output_token->length, + &ct, &size, ret); + der_free_oid(&ct.thisMech); + if (ret) { + _mg_buffer_zero(output_token); + return GSS_S_FAILURE; + } + if (output_token->length != size) + abort(); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_export_name.c b/third_party/heimdal/lib/gssapi/mech/gss_export_name.c new file mode 100644 index 0000000..92b7a8f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_export_name.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_export_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/** + * Convert a GGS-API name from internal form to contiguous string. + * + * @sa gss_import_name(), @ref internalVSmechname. + * + * @param minor_status minor status code + * @param input_name input name in internal name form + * @param exported_name output name in contiguos string form + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name) +{ + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + _mg_buffer_zero(exported_name); + + /* + * If this name already has any attached MNs, export the first + * one, otherwise export based on the first mechanism in our + * list. + */ + mn = HEIM_TAILQ_FIRST(&name->gn_mn); + if (!mn) { + *minor_status = 0; + return (GSS_S_NAME_NOT_MN); + } + + return mn->gmn_mech->gm_export_name(minor_status, + mn->gmn_name, exported_name); +} + +OM_uint32 +gss_mg_export_name(OM_uint32 *minor_status, + const gss_const_OID mech, + const void *name, + size_t length, + gss_buffer_t exported_name) +{ + uint8_t *buf; + + exported_name->length = 10 + length + mech->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + memcpy(buf, "\x04\x01", 2); + buf += 2; + buf[0] = ((mech->length + 2) >> 8) & 0xff; + buf[1] = (mech->length + 2) & 0xff; + buf+= 2; + buf[0] = 0x06; + buf[1] = (mech->length) & 0xFF; + buf+= 2; + + memcpy(buf, mech->elements, mech->length); + buf += mech->length; + + buf[0] = (length >> 24) & 0xff; + buf[1] = (length >> 16) & 0xff; + buf[2] = (length >> 8) & 0xff; + buf[3] = (length) & 0xff; + buf += 4; + + memcpy (buf, name, length); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_export_name_composite.c b/third_party/heimdal/lib/gssapi/mech/gss_export_name_composite.c new file mode 100644 index 0000000..d833ebb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_export_name_composite.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_name_composite(OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t exp_composite_name) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + _mg_buffer_zero(exp_composite_name); + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_export_name_composite) + continue; + + major_status = m->gm_export_name_composite(minor_status, + mn->gmn_name, + exp_composite_name); + if (GSS_ERROR(major_status)) + _gss_mg_error(m, *minor_status); + else + break; + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c new file mode 100644 index 0000000..c030980 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_export_sec_context.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_export_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) +{ + OM_uint32 major_status = GSS_S_FAILURE, tmp_minor; + krb5_storage *sp; + krb5_data data; + krb5_error_code kret; + struct _gss_context *ctx; + gssapi_mech_interface m; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + unsigned char verflags; + + *minor_status = 0; + + if (!interprocess_token) + return GSS_S_CALL_INACCESSIBLE_READ; + + _mg_buffer_zero(interprocess_token); + + if (context_handle == NULL) + return GSS_S_NO_CONTEXT; + + ctx = (struct _gss_context *) *context_handle; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + goto failure; + } + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + verflags = 0x00; /* Version 0 */ + + if (ctx->gc_target_len) + verflags |= EXPORT_CONTEXT_FLAG_ACCUMULATING; + + if (ctx->gc_ctx) + verflags |= EXPORT_CONTEXT_FLAG_MECH_CTX; + + kret = krb5_store_uint8(sp, verflags); + if (kret) { + *minor_status = kret; + goto failure; + } + + if (ctx->gc_target_len) { + _gss_mg_log(10, "gss-esc: exporting partial token %zu/%zu", + ctx->gc_input.length, ctx->gc_target_len); + kret = krb5_store_uint8(sp, ctx->gc_initial); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_uint32(sp, ctx->gc_target_len); + if (kret) { + *minor_status = kret; + goto failure; + } + major_status = _gss_mg_store_buffer(minor_status, sp, + &ctx->gc_input); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (ctx->gc_ctx == GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&tmp_minor, context_handle, + GSS_C_NO_BUFFER); + return GSS_S_NO_CONTEXT; + } + + if (ctx->gc_ctx) { + m = ctx->gc_mech; + + major_status = m->gm_export_sec_context(minor_status, + &ctx->gc_ctx, &buf); + + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + goto failure; + } + + major_status = _gss_mg_store_oid(minor_status, sp, + &m->gm_mech_oid); + if (major_status != GSS_S_COMPLETE) + goto failure; + + major_status = _gss_mg_store_buffer(minor_status, sp, &buf); + if (major_status != GSS_S_COMPLETE) + goto failure; + } + + kret = krb5_storage_to_data(sp, &data); + if (kret) { + *minor_status = kret; + goto failure; + } + + interprocess_token->length = data.length; + interprocess_token->value = data.data; + + major_status = GSS_S_COMPLETE; + + _gss_mg_log(1, "gss-esc: token length %zu", data.length); + +failure: + if (major_status == GSS_S_COMPLETE && *minor_status == 0) + gss_delete_sec_context(&tmp_minor, context_handle, + GSS_C_NO_BUFFER); + else if (*minor_status) + major_status = GSS_S_FAILURE; + + _gss_secure_release_buffer(minor_status, &buf); + krb5_storage_free(sp); + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_get_mic.c b/third_party/heimdal/lib/gssapi/mech/gss_get_mic.c new file mode 100644 index 0000000..8663053 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_get_mic.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_get_mic.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_get_mic(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + _mg_buffer_zero(message_token); + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + return (m->gm_get_mic(minor_status, ctx->gc_ctx, qop_req, + message_buffer, message_token)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_get_name_attribute.c b/third_party/heimdal/lib/gssapi/mech/gss_get_name_attribute.c new file mode 100644 index 0000000..1b7bee5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_get_name_attribute.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_get_name_attribute(OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + if (authenticated != NULL) + *authenticated = 0; + if (complete != NULL) + *complete = 0; + _mg_buffer_zero(value); + _mg_buffer_zero(display_value); + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + _gss_mg_check_name(input_name); + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_get_name_attribute) + continue; + + major_status = m->gm_get_name_attribute(minor_status, + mn->gmn_name, + attr, + authenticated, + complete, + value, + display_value, + more); + if (GSS_ERROR(major_status)) + _gss_mg_error(m, *minor_status); + else + break; + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_get_neg_mechs.c b/third_party/heimdal/lib/gssapi/mech/gss_get_neg_mechs.c new file mode 100644 index 0000000..cbc3786 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_get_neg_mechs.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_get_neg_mechs(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + gss_OID_set *mechs) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (mechs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) + return gss_duplicate_oid_set(minor_status, cred->gc_neg_mechs, mechs); + + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_import_name.c b/third_party/heimdal/lib/gssapi/mech/gss_import_name.c new file mode 100644 index 0000000..54930bf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_import_name.c @@ -0,0 +1,323 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_import_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +static OM_uint32 +_gss_import_export_name(OM_uint32 *minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID name_type, + gss_name_t *output_name) +{ + OM_uint32 major_status; + unsigned char *p = input_name_buffer->value; + size_t len = input_name_buffer->length; + size_t t; + gss_OID_desc mech_oid; + gssapi_mech_interface m; + struct _gss_name *name; + gss_name_t new_canonical_name; + int composite = 0; + + *minor_status = 0; + *output_name = 0; + + /* + * Make sure that TOK_ID is {4, 1}. + */ + if (len < 2) + return (GSS_S_BAD_NAME); + if (p[0] != 4) + return (GSS_S_BAD_NAME); + switch (p[1]) { + case 1: /* non-composite name */ + break; + case 2: /* composite name */ + composite = 1; + break; + default: + return (GSS_S_BAD_NAME); + } + p += 2; + len -= 2; + + /* + * If the name token is a composite token (TOK_ID 0x04 0x02) then per + * RFC6680 everything after that is implementation-specific. This + * mech-glue is pluggable however, so we need the format of the rest of + * the header to be stable, otherwise we couldn't reliably determine + * what mechanism the token is for and we'd have to try all of them. + * + * So... we keep the same format for the exported composite name token + * as for normal exported name tokens (see RFC2743, section 3.2), with + * the TOK_ID 0x04 0x02, but only up to the mechanism OID. We don't + * enforce that there be a NAME_LEN in the exported composite name + * token, or that it match the length of the remainder of the token. + * + * FYI, at least one out-of-tree mechanism implements exported + * composite name tokens as the same as exported name tokens with + * attributes appended and the NAME_LEN not modified to match. + */ + + /* + * Get the mech length and the name length and sanity + * check the size of of the buffer. + */ + if (len < 2) + return (GSS_S_BAD_NAME); + t = (p[0] << 8) + p[1]; + p += 2; + len -= 2; + + /* + * Check the DER encoded OID to make sure it agrees with the + * length we just decoded. + */ + if (p[0] != 6) /* 6=OID */ + return (GSS_S_BAD_NAME); + p++; + len--; + t--; + if (p[0] & 0x80) { + int digits = p[0]; + p++; + len--; + t--; + mech_oid.length = 0; + while (digits--) { + mech_oid.length = (mech_oid.length << 8) | p[0]; + p++; + len--; + t--; + } + } else { + mech_oid.length = p[0]; + p++; + len--; + t--; + } + if (mech_oid.length != t) + return (GSS_S_BAD_NAME); + + mech_oid.elements = p; + + if (!composite) { + if (len < t + 4) + return (GSS_S_BAD_NAME); + p += t; + len -= t; + + t = ((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + /* p += 4; // we're done using `p' now */ + len -= 4; + + if (len != t) + return (GSS_S_BAD_NAME); + } + + m = __gss_get_mechanism(&mech_oid); + if (!m || !m->gm_import_name) + return (GSS_S_BAD_MECH); + + /* + * Ask the mechanism to import the name. + */ + major_status = m->gm_import_name(minor_status, + input_name_buffer, name_type, &new_canonical_name); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + return major_status; + } + + /* + * Now we make a new name and mark it as an MN. + */ + name = _gss_create_name(new_canonical_name, m); + if (!name) { + m->gm_release_name(minor_status, &new_canonical_name); + return (GSS_S_FAILURE); + } + + *output_name = (gss_name_t) name; + + *minor_status = 0; + return (GSS_S_COMPLETE); +} + +/** + * Convert a GGS-API name from contiguous string to internal form. + * + * Type of name and their format: + * - GSS_C_NO_OID + * - GSS_C_NT_USER_NAME + * - GSS_C_NT_HOSTBASED_SERVICE + * - GSS_C_NT_EXPORT_NAME + * - GSS_C_NT_COMPOSITE_EXPORT + * - GSS_C_NT_ANONYMOUS + * - GSS_KRB5_NT_PRINCIPAL_NAME + * + * @sa gss_export_name(), @ref internalVSmechname. + * + * @param minor_status minor status code + * @param input_name_buffer import name buffer + * @param input_name_type type of the import name buffer + * @param output_name the resulting type, release with + * gss_release_name(), independent of input_name + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_import_name(OM_uint32 *minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t *output_name) +{ + struct _gss_mechanism_name *mn; + gss_OID name_type = input_name_type; + OM_uint32 major_status, ms; + struct _gss_name *name; + struct _gss_mech_switch *m; + gss_name_t rname; + + if (input_name_buffer == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ; + if (output_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *output_name = GSS_C_NO_NAME; + + /* Allow empty names since that's valid (ANONYMOUS for example) */ + + _gss_load_mech(); + + /* + * If this is an exported name, we need to parse it to find + * the mechanism and then import it as an MN. See RFC 2743 + * section 3.2 for a description of the format. + */ + if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(name_type, GSS_C_NT_COMPOSITE_EXPORT)) { + return _gss_import_export_name(minor_status, input_name_buffer, + name_type, output_name); + } + + + *minor_status = 0; + name = _gss_create_name(NULL, NULL); + if (!name) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + if (name_type != GSS_C_NO_OID) { + major_status = _gss_intern_oid(minor_status, + name_type, &name->gn_type); + if (major_status) { + rname = (gss_name_t)name; + gss_release_name(&ms, (gss_name_t *)&rname); + return (GSS_S_FAILURE); + } + } else + name->gn_type = GSS_C_NO_OID; + + major_status = _gss_copy_buffer(minor_status, + input_name_buffer, &name->gn_value); + if (major_status) + goto out; + + /* + * Walk over the mechs and import the name into a mech name + * for those supported this nametype. + */ + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + int present = 0; + + if ((m->gm_mech.gm_flags & GM_USE_MG_NAME)) + continue; + + if (name_type != GSS_C_NO_OID) { + major_status = gss_test_oid_set_member(minor_status, + name_type, m->gm_name_types, &present); + + if (GSS_ERROR(major_status) || present == 0) + continue; + } + + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto out; + } + + major_status = (*m->gm_mech.gm_import_name)(minor_status, + &name->gn_value, + name->gn_type, + &mn->gmn_name); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(&m->gm_mech, *minor_status); + free(mn); + /** + * If we failed to import the name in a mechanism, it + * will be ignored as long as its possible to import + * name in some other mechanism. We will catch the + * failure later though in gss_init_sec_context() or + * another function. + */ + continue; + } + + mn->gmn_mech = &m->gm_mech; + mn->gmn_mech_oid = m->gm_mech_oid; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } + + /* + * If we can't find a mn for the name, bail out already here. + */ + + mn = HEIM_TAILQ_FIRST(&name->gn_mn); + if (!mn) { + *minor_status = 0; + major_status = GSS_S_NAME_NOT_MN; + goto out; + } + + *output_name = (gss_name_t) name; + return (GSS_S_COMPLETE); + + out: + rname = (gss_name_t)name; + gss_release_name(&ms, &rname); + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c new file mode 100644 index 0000000..39b717e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_import_sec_context.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_import_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_import_sec_context(OM_uint32 *minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + OM_uint32 ret = GSS_S_FAILURE, tmp_minor; + krb5_storage *sp; + gssapi_mech_interface m; + struct _gss_context *ctx = NULL; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + unsigned char verflags; + + _gss_mg_log(10, "gss-isc called"); + + if (!context_handle) { + *minor_status = EFAULT; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + *minor_status = 0; + *context_handle = GSS_C_NO_CONTEXT; + + sp = krb5_storage_from_mem(interprocess_token->value, + interprocess_token->length); + if (!sp) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + ctx = calloc(1, sizeof(struct _gss_context)); + if (!ctx) { + *minor_status = ENOMEM; + goto failure; + } + + if (krb5_ret_uint8(sp, &verflags)) + goto failure; + + if ((verflags & EXPORT_CONTEXT_VERSION_MASK) != 0) { + _gss_mg_log(10, "gss-isc failed, token version %d not recognised", + (int)(verflags & EXPORT_CONTEXT_VERSION_MASK)); + /* We don't recognise the version */ + goto failure; + } + + if (verflags & EXPORT_CONTEXT_FLAG_ACCUMULATING) { + uint32_t target_len; + + if (krb5_ret_uint8(sp, &ctx->gc_initial)) + goto failure; + + if (krb5_ret_uint32(sp, &target_len)) + goto failure; + + ret = _gss_mg_ret_buffer(minor_status, sp, &buf); + if (ret != GSS_S_COMPLETE) + goto failure; + + ctx->gc_free_this = ctx->gc_input.value = calloc(target_len, 1); + if (ctx->gc_input.value == NULL) + goto failure; + + ctx->gc_target_len = target_len; + ctx->gc_input.length = buf.length; + if (buf.value) + memcpy(ctx->gc_input.value, buf.value, buf.length); + + gss_release_buffer(&tmp_minor, &buf); + } + + if (verflags & EXPORT_CONTEXT_FLAG_MECH_CTX) { + gss_OID mech_oid; + + ret = _gss_mg_ret_oid(minor_status, sp, &mech_oid); + if (ret != GSS_S_COMPLETE) + goto failure; + + if (mech_oid == GSS_C_NO_OID) { + ret = GSS_S_BAD_MECH; + goto failure; + } + + m = __gss_get_mechanism(mech_oid); + if (m == NULL) { + ret = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + ctx->gc_mech = m; + + ret = _gss_mg_ret_buffer(minor_status, sp, &buf); + if (ret != GSS_S_COMPLETE) + goto failure; + + if (buf.value == NULL) { + ret = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + ret = m->gm_import_sec_context(minor_status, &buf, &ctx->gc_ctx); + if (ret != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + goto failure; + } + } + + *context_handle = (gss_ctx_id_t) ctx; + ctx = NULL; + + ret = GSS_S_COMPLETE; + +failure: + free(ctx); + krb5_storage_free(sp); + _gss_secure_release_buffer(&tmp_minor, &buf); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_indicate_mechs.c b/third_party/heimdal/lib/gssapi/mech/gss_indicate_mechs.c new file mode 100644 index 0000000..9eef62e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_indicate_mechs.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_indicate_mechs.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_indicate_mechs(OM_uint32 *minor_status, + gss_OID_set *mech_set) +{ + struct _gss_mech_switch *m; + OM_uint32 major_status, junk; + gss_OID_set set; + size_t i; + + _gss_load_mech(); + + major_status = gss_create_empty_oid_set(minor_status, mech_set); + if (major_status) + return (major_status); + + /* XXX We ignore ENOMEM from gss_add_oid_set_member() */ + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_indicate_mechs) { + major_status = m->gm_mech.gm_indicate_mechs( + minor_status, &set); + if (major_status) + continue; + major_status = GSS_S_COMPLETE; + for (i = 0; i < set->count; i++) { + major_status = gss_add_oid_set_member( + minor_status, &set->elements[i], mech_set); + if (major_status) + break; + } + gss_release_oid_set(minor_status, &set); + } else { + major_status = gss_add_oid_set_member( + minor_status, m->gm_mech_oid, mech_set); + } + if (major_status) + break; + } + + if (major_status) + gss_release_oid_set(&junk, mech_set); + + *minor_status = 0; + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_init_sec_context.c b/third_party/heimdal/lib/gssapi/mech/gss_init_sec_context.c new file mode 100644 index 0000000..6d28938 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_init_sec_context.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_init_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +gss_cred_id_t +_gss_mg_find_mech_cred( + gss_const_cred_id_t cred_handle, + gss_const_OID mech_type) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + struct _gss_mechanism_cred *mc; + + if (cred == NULL) + return GSS_C_NO_CREDENTIAL; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) + return mc->gmc_cred; + } + return GSS_C_NO_CREDENTIAL; +} + +static void +log_init_sec_context(struct _gss_context *ctx, + struct _gss_name *target, + OM_uint32 req_flags, + struct _gss_cred *cred, + gss_OID mech_type, + gss_buffer_t input_token) +{ + gssapi_mech_interface m; + + if (ctx) + m = ctx->gc_mech; + else + m = __gss_get_mechanism(mech_type); + if (m == NULL) + return; + + mech_type = &m->gm_mech_oid; + + _gss_mg_log(1, "gss_isc: %s %sfirst flags %08x, %s cred, %stoken", + m->gm_name, + (ctx == NULL) ? "" : "not ", + req_flags, + (cred != NULL) ? "specific" : "default", + (input_token != NULL && input_token->length) ? "" : "no "); + + _gss_mg_log_cred(1, cred, "gss_isc cred"); + + /* print target name */ + _gss_mg_log_name(1, target, mech_type, "gss_isc: target"); +} + +/** + * As the initiator build a context with an acceptor. + * + * Returns in the major + * - GSS_S_COMPLETE - if the context if build + * - GSS_S_CONTINUE_NEEDED - if the caller needs to continue another + * round of gss_i nit_sec_context + * - error code - any other error code + * + * @param minor_status minor status code. + * + * @param initiator_cred_handle the credential to use when building + * the context, if GSS_C_NO_CREDENTIAL is passed, the default + * credential for the mechanism will be used. + * + * @param context_handle a pointer to a context handle, will be + * returned as long as there is not an error. + * + * @param target_name the target name of acceptor, created using + * gss_import_name(). The name is can be of any name types the + * mechanism supports, check supported name types with + * gss_inquire_names_for_mech(). + * + * @param input_mech_type mechanism type to use, if GSS_C_NO_OID is + * used, Kerberos (GSS_KRB5_MECHANISM) will be tried. Other + * available mechanism are listed in the @ref gssapi_mechs_intro + * section. + * + * @param req_flags flags using when building the context, see @ref + * gssapi_context_flags + * + * @param time_req time requested this context should be valid in + * seconds, common used value is GSS_C_INDEFINITE + * + * @param input_chan_bindings Channel bindings used, if not exepected + * otherwise, used GSS_C_NO_CHANNEL_BINDINGS + * + * @param input_token input token sent from the acceptor, for the + * initial packet the buffer of { NULL, 0 } should be used. + * + * @param actual_mech_type the actual mech used, MUST NOT be freed + * since it pointing to static memory. + * + * @param output_token if there is an output token, regardless of + * complete, continue_needed, or error it should be sent to the + * acceptor + * + * @param ret_flags return what flags was negotitated, caller should + * check if they are accetable. For example, if + * GSS_C_MUTUAL_FLAG was negotiated with the acceptor or not. + * + * @param time_rec amount of time this context is valid for + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_init_sec_context(OM_uint32 * minor_status, + gss_const_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID input_mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + gss_const_name_t mn_inner = GSS_C_NO_NAME; + struct _gss_name *name = (struct _gss_name *) target_name; + struct _gss_mechanism_name *mn; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + gss_const_cred_id_t cred_handle; + int allocated_ctx; + gss_OID mech_type = input_mech_type; + + *minor_status = 0; + + _mg_buffer_zero(output_token); + if (actual_mech_type) + *actual_mech_type = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + + if (mech_type == GSS_C_NO_OID) + mech_type = GSS_KRB5_MECHANISM; + + _gss_mg_check_name(target_name); + + if (_gss_mg_log_level(1)) + log_init_sec_context(ctx, name, req_flags, + (struct _gss_cred *)initiator_cred_handle, + input_mech_type, input_token); + + /* + * If we haven't allocated a context yet, do so now and lookup + * the mechanism switch table. If we have one already, make + * sure we use the same mechanism switch as before. + */ + if (!ctx) { + ctx = malloc(sizeof(struct _gss_context)); + if (!ctx) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + memset(ctx, 0, sizeof(struct _gss_context)); + m = ctx->gc_mech = __gss_get_mechanism(mech_type); + if (!m) { + free(ctx); + *minor_status = 0; + gss_mg_set_error_string(mech_type, GSS_S_BAD_MECH, + *minor_status, + "Unsupported mechanism requested"); + return (GSS_S_BAD_MECH); + } + allocated_ctx = 1; + } else { + m = ctx->gc_mech; + mech_type = &ctx->gc_mech->gm_mech_oid; + allocated_ctx = 0; + } + + /* + * Find the MN for this mechanism. + */ + if ((m->gm_flags & GM_USE_MG_NAME)) { + mn_inner = target_name; + } else { + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) { + if (allocated_ctx) + free(ctx); + return major_status; + } + if (mn) + mn_inner = mn->gmn_name; + } + + /* + * If we have a cred, find the cred for this mechanism. + */ + if (m->gm_flags & GM_USE_MG_CRED) + cred_handle = initiator_cred_handle; + else + cred_handle = _gss_mg_find_mech_cred(initiator_cred_handle, mech_type); + + if (initiator_cred_handle != GSS_C_NO_CREDENTIAL && + cred_handle == NULL) { + *minor_status = 0; + if (allocated_ctx) + free(ctx); + gss_mg_set_error_string(mech_type, GSS_S_UNAVAILABLE, + *minor_status, + "Credential for the requested mechanism " + "not found in credential handle"); + return GSS_S_UNAVAILABLE; + } + + major_status = m->gm_init_sec_context(minor_status, + cred_handle, + &ctx->gc_ctx, + mn_inner, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + + if (major_status != GSS_S_COMPLETE + && major_status != GSS_S_CONTINUE_NEEDED) { + if (allocated_ctx) + free(ctx); + _mg_buffer_zero(output_token); + _gss_mg_error(m, *minor_status); + } else { + *context_handle = (gss_ctx_id_t) ctx; + } + + _gss_mg_log(1, "gss_isc: %s maj_stat: %d/%d", + m->gm_name, (int)major_status, (int)*minor_status); + + return (major_status); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_context.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_context.c new file mode 100644 index 0000000..6140696 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_context.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_inquire_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_context(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *xopen) +{ + OM_uint32 major_status; + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + struct _gss_name *name; + gss_name_t src_mn, targ_mn; + + if (locally_initiated) + *locally_initiated = 0; + if (xopen) + *xopen = 0; + if (lifetime_rec) + *lifetime_rec = 0; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (targ_name) + *targ_name = GSS_C_NO_NAME; + if (mech_type) + *mech_type = GSS_C_NO_OID; + src_mn = targ_mn = GSS_C_NO_NAME; + + if (ctx == NULL || ctx->gc_ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + major_status = m->gm_inquire_context(minor_status, + ctx->gc_ctx, + src_name ? &src_mn : NULL, + targ_name ? &targ_mn : NULL, + lifetime_rec, + mech_type, + ctx_flags, + locally_initiated, + xopen); + + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + return (major_status); + } + + if (src_name && (m->gm_flags & GM_USE_MG_NAME)) { + *src_name = src_mn; + src_mn = GSS_C_NO_NAME; + } else if (src_name && src_mn) { + /* _gss_create_name() consumes `src_mn' on success */ + name = _gss_create_name(src_mn, m); + if (!name) { + if (mech_type) + *mech_type = GSS_C_NO_OID; + m->gm_release_name(minor_status, &src_mn); + *minor_status = 0; + return (GSS_S_FAILURE); + } + *src_name = (gss_name_t) name; + src_mn = GSS_C_NO_NAME; + } + + if (targ_name && (m->gm_flags & GM_USE_MG_NAME)) { + *targ_name = targ_mn; + } else if (targ_name && targ_mn) { + name = _gss_create_name(targ_mn, m); + if (!name) { + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (src_name) + gss_release_name(minor_status, src_name); + m->gm_release_name(minor_status, &targ_mn); + *minor_status = 0; + return (GSS_S_FAILURE); + } + *targ_name = (gss_name_t) name; + targ_mn = GSS_C_NO_NAME; + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred.c new file mode 100644 index 0000000..305cae2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred.c @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_inquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +#define AUSAGE 1 +#define IUSAGE 2 + +static void +updateusage(gss_cred_usage_t usage, int *usagemask) +{ + if (usage == GSS_C_BOTH) + *usagemask |= AUSAGE | IUSAGE; + else if (usage == GSS_C_ACCEPT) + *usagemask |= AUSAGE; + else if (usage == GSS_C_INITIATE) + *usagemask |= IUSAGE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_cred(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t *name_ret, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + OM_uint32 major_status; + struct _gss_mech_switch *m; + struct _gss_cred *cred = (struct _gss_cred *) cred_handle; + struct _gss_name *name; + struct _gss_mechanism_name *mn; + OM_uint32 min_lifetime; + int found = FALSE; + int usagemask = 0; + gss_cred_usage_t usage; + + _gss_load_mech(); + + *minor_status = 0; + if (name_ret) + *name_ret = GSS_C_NO_NAME; + if (lifetime) + *lifetime = 0; + if (cred_usage) + *cred_usage = 0; + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + if (name_ret) { + name = _gss_create_name(NULL, NULL); + if (name == NULL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + } else { + name = NULL; + } + + if (mechanisms) { + major_status = gss_create_empty_oid_set(minor_status, + mechanisms); + if (major_status) { + if (name) free(name); + return (major_status); + } + } + + min_lifetime = GSS_C_INDEFINITE; + if (cred) { + struct _gss_mechanism_cred *mc; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + gss_name_t mc_name = GSS_C_NO_NAME; + OM_uint32 mc_lifetime = GSS_C_INDEFINITE; + + heim_assert((mc->gmc_mech->gm_flags & GM_USE_MG_CRED) == 0, + "should not have mech creds for GM_USE_MG_CRED mechs"); + + if (mc->gmc_mech->gm_inquire_cred == NULL) + continue; + + major_status = mc->gmc_mech->gm_inquire_cred(minor_status, + mc->gmc_cred, &mc_name, &mc_lifetime, &usage, NULL); + if (major_status) + continue; + + updateusage(usage, &usagemask); + if (name) { + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) { + mc->gmc_mech->gm_release_name(minor_status, + &mc_name); + continue; + } + mn->gmn_mech = mc->gmc_mech; + mn->gmn_mech_oid = mc->gmc_mech_oid; + mn->gmn_name = mc_name; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } else { + mc->gmc_mech->gm_release_name(minor_status, + &mc_name); + } + + if (mc_lifetime < min_lifetime) + min_lifetime = mc_lifetime; + + if (mechanisms) + gss_add_oid_set_member(minor_status, + mc->gmc_mech_oid, mechanisms); + found = TRUE; + } + } else { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + gss_name_t mc_name; + OM_uint32 mc_lifetime; + + if (m->gm_mech.gm_inquire_cred == NULL || + (m->gm_mech.gm_flags & GM_USE_MG_CRED)) + continue; + + major_status = m->gm_mech.gm_inquire_cred(minor_status, + GSS_C_NO_CREDENTIAL, &mc_name, &mc_lifetime, + &usage, NULL); + if (major_status) + continue; + + updateusage(usage, &usagemask); + if (name && mc_name) { + mn = malloc( + sizeof(struct _gss_mechanism_name)); + if (!mn) { + m->gm_mech.gm_release_name( + minor_status, &mc_name); + continue; + } + mn->gmn_mech = &m->gm_mech; + mn->gmn_mech_oid = m->gm_mech_oid; + mn->gmn_name = mc_name; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } else if (mc_name) { + m->gm_mech.gm_release_name(minor_status, + &mc_name); + } + + if (mc_lifetime < min_lifetime) + min_lifetime = mc_lifetime; + + if (mechanisms) + gss_add_oid_set_member(minor_status, + m->gm_mech_oid, mechanisms); + found = TRUE; + } + } + + if (found && mechanisms) { + /* GM_USE_MG_CRED mechs (SPNEGO) always can be used */ + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if ((m->gm_mech.gm_flags & GM_USE_MG_CRED) == 0) + continue; + + gss_add_oid_set_member(minor_status, + m->gm_mech_oid, mechanisms); + } + } + + if (found == FALSE || min_lifetime == 0) { + gss_name_t n = (gss_name_t)name; + if (n) + gss_release_name(minor_status, &n); + gss_release_oid_set(minor_status, mechanisms); + *minor_status = 0; + if (min_lifetime == 0) + return (GSS_S_CREDENTIALS_EXPIRED); + + return (GSS_S_NO_CRED); + } + + *minor_status = 0; + if (name_ret) + *name_ret = (gss_name_t) name; + if (lifetime) + *lifetime = min_lifetime; + if (cred_usage) { + if ((usagemask & (AUSAGE|IUSAGE)) == (AUSAGE|IUSAGE)) + *cred_usage = GSS_C_BOTH; + else if (usagemask & IUSAGE) + *cred_usage = GSS_C_INITIATE; + else if (usagemask & AUSAGE) + *cred_usage = GSS_C_ACCEPT; + } + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c new file mode 100644 index 0000000..10ba9b7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_inquire_cred_by_mech.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_cred_by_mech(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t *cred_name, + OM_uint32 *initiator_lifetime, + OM_uint32 *acceptor_lifetime, + gss_cred_usage_t *cred_usage) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + struct _gss_mechanism_cred *mcp; + gss_cred_id_t mc; + gss_name_t mn; + struct _gss_name *name; + + *minor_status = 0; + if (cred_name) + *cred_name = GSS_C_NO_NAME; + if (initiator_lifetime) + *initiator_lifetime = 0; + if (acceptor_lifetime) + *acceptor_lifetime = 0; + if (cred_usage) + *cred_usage = 0; + + m = __gss_get_mechanism(mech_type); + if (m == NULL || m->gm_inquire_cred_by_mech == NULL) + return (GSS_S_NO_CRED); + + if (cred_handle != GSS_C_NO_CREDENTIAL) { + struct _gss_cred *cred = (struct _gss_cred *) cred_handle; + HEIM_TAILQ_FOREACH(mcp, &cred->gc_mc, gmc_link) + if (mcp->gmc_mech == m) + break; + if (!mcp) + return (GSS_S_NO_CRED); + mc = mcp->gmc_cred; + } else { + mc = GSS_C_NO_CREDENTIAL; + } + + major_status = m->gm_inquire_cred_by_mech(minor_status, mc, mech_type, + &mn, initiator_lifetime, acceptor_lifetime, cred_usage); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + return (major_status); + } + + if (cred_name) { + name = _gss_create_name(mn, m); + if (!name) { + m->gm_release_name(minor_status, &mn); + return (GSS_S_NO_CRED); + } + *cred_name = (gss_name_t) name; + } else + m->gm_release_name(minor_status, &mn); + + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_oid.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_oid.c new file mode 100644 index 0000000..4e7c73f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_cred_by_oid.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_cred_by_oid (OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + struct _gss_cred *cred = (struct _gss_cred *) cred_handle; + OM_uint32 status = GSS_S_COMPLETE; + struct _gss_mechanism_cred *mc; + gssapi_mech_interface m; + gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + + if (cred == NULL) + return GSS_S_NO_CRED; + + status = GSS_S_FAILURE; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + gss_buffer_set_t rset = GSS_C_NO_BUFFER_SET; + size_t i; + + m = mc->gmc_mech; + if (m == NULL) { + _gss_secure_release_buffer_set(minor_status, &set); + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + if (m->gm_inquire_cred_by_oid == NULL) + continue; + + status = m->gm_inquire_cred_by_oid(minor_status, + mc->gmc_cred, desired_object, &rset); + if (status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + continue; + } + + for (i = 0; rset != NULL && i < rset->count; i++) { + status = gss_add_buffer_set_member(minor_status, + &rset->elements[i], &set); + if (status != GSS_S_COMPLETE) + break; + } + _gss_secure_release_buffer_set(minor_status, &rset); + } + if (set == GSS_C_NO_BUFFER_SET && status == GSS_S_COMPLETE) + status = GSS_S_FAILURE; + *data_set = set; + *minor_status = 0; + return status; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_mechs_for_name.c new file mode 100644 index 0000000..f75dbaa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_mechs_for_name.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_inquire_mechs_for_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_mechs_for_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_OID_set *mech_types) +{ + OM_uint32 major_status; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mech_switch *m; + gss_OID_set name_types; + int present; + + *minor_status = 0; + + _gss_load_mech(); + + major_status = gss_create_empty_oid_set(minor_status, mech_types); + if (major_status) + return (major_status); + + /* + * We go through all the loaded mechanisms and see if this + * name's type is supported by the mechanism. If it is, add + * the mechanism to the set. + */ + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + major_status = gss_inquire_names_for_mech(minor_status, + m->gm_mech_oid, &name_types); + if (major_status) { + gss_release_oid_set(minor_status, mech_types); + return (major_status); + } + gss_test_oid_set_member(minor_status, + name->gn_type, name_types, &present); + gss_release_oid_set(minor_status, &name_types); + if (present) { + major_status = gss_add_oid_set_member(minor_status, + m->gm_mech_oid, mech_types); + if (major_status) { + gss_release_oid_set(minor_status, mech_types); + return (major_status); + } + } + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_name.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_name.c new file mode 100644 index 0000000..f109a9f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_name.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_name(OM_uint32 *minor_status, + gss_name_t input_name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + if (name_is_MN != NULL) + *name_is_MN = 0; + if (MN_mech != NULL) + *MN_mech = GSS_C_NO_OID; + if (attrs != NULL) + *attrs = GSS_C_NO_BUFFER_SET; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_inquire_name) + continue; + + major_status = m->gm_inquire_name(minor_status, + mn->gmn_name, + NULL, + MN_mech, + attrs); + if (major_status == GSS_S_COMPLETE) { + if (name_is_MN != NULL) + *name_is_MN = 1; + if (MN_mech != NULL && *MN_mech == GSS_C_NO_OID) + *MN_mech = &m->gm_mech_oid; + break; + } + _gss_mg_error(m, *minor_status); + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_names_for_mech.c new file mode 100644 index 0000000..595ab73 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_names_for_mech.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_inquire_names_for_mech.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_names_for_mech(OM_uint32 *minor_status, + const gss_OID mechanism, + gss_OID_set *name_types) +{ + OM_uint32 major_status; + gssapi_mech_interface m = __gss_get_mechanism(mechanism); + + *minor_status = 0; + *name_types = GSS_C_NO_OID_SET; + if (!m) + return (GSS_S_BAD_MECH); + + /* + * If the implementation can do it, ask it for a list of + * names, otherwise fake it. + */ + if (m->gm_inquire_names_for_mech) { + return (m->gm_inquire_names_for_mech(minor_status, + mechanism, name_types)); + } else { + major_status = gss_create_empty_oid_set(minor_status, + name_types); + if (major_status) + return (major_status); + major_status = gss_add_oid_set_member(minor_status, + GSS_C_NT_HOSTBASED_SERVICE, name_types); + if (major_status) { + OM_uint32 junk; + gss_release_oid_set(&junk, name_types); + return (major_status); + } + major_status = gss_add_oid_set_member(minor_status, + GSS_C_NT_USER_NAME, name_types); + if (major_status) { + OM_uint32 junk; + gss_release_oid_set(&junk, name_types); + return (major_status); + } + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c b/third_party/heimdal/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c new file mode 100644 index 0000000..55ff671 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + OM_uint32 major_status; + gssapi_mech_interface m; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + m = ctx->gc_mech; + + if (m == NULL) + return GSS_S_BAD_MECH; + + if (m->gm_inquire_sec_context_by_oid != NULL) { + major_status = m->gm_inquire_sec_context_by_oid(minor_status, + ctx->gc_ctx, desired_object, data_set); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + } else + major_status = GSS_S_BAD_MECH; + + return major_status; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_krb5.c b/third_party/heimdal/lib/gssapi/mech/gss_krb5.c new file mode 100644 index 0000000..21bb2bf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_krb5.c @@ -0,0 +1,926 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_krb5.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" +#include "krb5/gsskrb5_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_copy_ccache(OM_uint32 *minor_status, + gss_cred_id_t cred, + krb5_ccache out) +{ + gss_key_value_element_desc cred_store_kvs[1]; + gss_key_value_set_desc cred_store; + krb5_context context; + OM_uint32 major = GSS_S_FAILURE; + char *fullname = NULL; + + GSSAPI_KRB5_INIT(&context); + *minor_status = krb5_cc_get_full_name(context, out, &fullname); + if (*minor_status == 0) { + cred_store_kvs[0].key = "ccache"; + cred_store_kvs[0].value = fullname; + cred_store.count = 1; + cred_store.elements = cred_store_kvs; + major = gss_store_cred_into2(minor_status, cred, GSS_C_INITIATE, + GSS_KRB5_MECHANISM, + GSS_C_STORE_CRED_OVERWRITE, &cred_store, + NULL, NULL, NULL); + free(fullname); + } + return major; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_import_cred(OM_uint32 *minor_status, + krb5_ccache id, + krb5_principal keytab_principal, + krb5_keytab keytab, + gss_cred_id_t *cred) +{ + gss_buffer_desc buffer; + OM_uint32 major_status; + krb5_context context; + krb5_error_code ret; + krb5_storage *sp; + krb5_data data; + char *str; + + *cred = GSS_C_NO_CREDENTIAL; + + ret = krb5_init_context(&context); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto out; + } + + if (id) { + ret = krb5_cc_get_full_name(context, id, &str); + if (ret == 0) { + ret = krb5_store_string(sp, str); + free(str); + } + } else + ret = krb5_store_string(sp, ""); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto out; + } + + if (keytab_principal) { + ret = krb5_unparse_name(context, keytab_principal, &str); + if (ret == 0) { + ret = krb5_store_string(sp, str); + free(str); + } + } else + krb5_store_string(sp, ""); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto out; + } + + + if (keytab) { + ret = krb5_kt_get_full_name(context, keytab, &str); + if (ret == 0) { + ret = krb5_store_string(sp, str); + free(str); + } + } else + krb5_store_string(sp, ""); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto out; + } + + ret = krb5_storage_to_data(sp, &data); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto out; + } + + buffer.value = data.data; + buffer.length = data.length; + + major_status = gss_set_cred_option(minor_status, + cred, + GSS_KRB5_IMPORT_CRED_X, + &buffer); + krb5_data_free(&data); +out: + if (sp) + krb5_storage_free(sp); + krb5_free_context(context); + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_register_acceptor_identity(const char *identity) +{ + gssapi_mech_interface m; + gss_buffer_desc buffer; + OM_uint32 junk; + + _gss_load_mech(); + + buffer.value = rk_UNCONST(identity); + buffer.length = strlen(identity); + + m = __gss_get_mechanism(GSS_KRB5_MECHANISM); + if (m == NULL || m->gm_set_sec_context_option == NULL) + return GSS_S_FAILURE; + + return m->gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +krb5_gss_register_acceptor_identity(const char *identity) +{ + return gsskrb5_register_acceptor_identity(identity); +} + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_dns_canonicalize(int flag) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + char b = (flag != 0); + + _gss_load_mech(); + + buffer.value = &b; + buffer.length = sizeof(b); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer); + } + + return (GSS_S_COMPLETE); +} + + + +static krb5_error_code +set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key) +{ + key->type = keyblock->keytype; + key->length = keyblock->keyvalue.length; + key->data = malloc(key->length); + if (key->data == NULL && key->length != 0) + return ENOMEM; + memcpy(key->data, keyblock->keyvalue.data, key->length); + return 0; +} + +static void +free_key(gss_krb5_lucid_key_t *key) +{ + memset(key->data, 0, key->length); + free(key->data); + memset(key, 0, sizeof(*key)); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + OM_uint32 version, + void **rctx) +{ + krb5_context context = NULL; + krb5_error_code ret; + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + OM_uint32 major_status; + gss_krb5_lucid_context_v1_t *ctx = NULL; + krb5_storage *sp = NULL; + uint32_t num; + + if (context_handle == NULL + || *context_handle == GSS_C_NO_CONTEXT + || version != 1) + { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + major_status = + gss_inquire_sec_context_by_oid (minor_status, + *context_handle, + GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, + &data_set); + if (major_status) + return major_status; + + if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_init_context(&context); + if (ret) + goto out; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + ret = ENOMEM; + goto out; + } + + sp = krb5_storage_from_mem(data_set->elements[0].value, + data_set->elements[0].length); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + ret = krb5_ret_uint32(sp, &num); + if (ret) goto out; + if (num != 1) { + ret = EINVAL; + goto out; + } + ctx->version = 1; + /* initiator */ + ret = krb5_ret_uint32(sp, &ctx->initiate); + if (ret) goto out; + /* endtime */ + ret = krb5_ret_uint32(sp, &ctx->endtime); + if (ret) goto out; + /* send_seq */ + ret = krb5_ret_uint32(sp, &num); + if (ret) goto out; + ctx->send_seq = ((uint64_t)num) << 32; + ret = krb5_ret_uint32(sp, &num); + if (ret) goto out; + ctx->send_seq |= num; + /* recv_seq */ + ret = krb5_ret_uint32(sp, &num); + if (ret) goto out; + ctx->recv_seq = ((uint64_t)num) << 32; + ret = krb5_ret_uint32(sp, &num); + if (ret) goto out; + ctx->recv_seq |= num; + /* protocol */ + ret = krb5_ret_uint32(sp, &ctx->protocol); + if (ret) goto out; + if (ctx->protocol == 0) { + krb5_keyblock key; + + /* sign_alg */ + ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); + if (ret) goto out; + /* seal_alg */ + ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); + if (ret) goto out; + /* ctx_key */ + ret = krb5_ret_keyblock(sp, &key); + if (ret) goto out; + ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); + krb5_free_keyblock_contents(context, &key); + if (ret) goto out; + } else if (ctx->protocol == 1) { + krb5_keyblock key; + + /* acceptor_subkey */ + ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); + if (ret) goto out; + /* ctx_key */ + ret = krb5_ret_keyblock(sp, &key); + if (ret) goto out; + ret = set_key(&key, &ctx->cfx_kd.ctx_key); + krb5_free_keyblock_contents(context, &key); + if (ret) goto out; + /* acceptor_subkey */ + if (ctx->cfx_kd.have_acceptor_subkey) { + ret = krb5_ret_keyblock(sp, &key); + if (ret) goto out; + ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); + krb5_free_keyblock_contents(context, &key); + if (ret) goto out; + } + } else { + ret = EINVAL; + goto out; + } + + *rctx = ctx; + +out: + _gss_secure_release_buffer_set(minor_status, &data_set); + if (sp) + krb5_storage_free(sp); + if (context) + krb5_free_context(context); + + if (ret) { + OM_uint32 junk; + if (ctx) + gss_krb5_free_lucid_sec_context(&junk, ctx); + + *minor_status = ret; + return GSS_S_FAILURE; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c) +{ + gss_krb5_lucid_context_v1_t *ctx = c; + + if (ctx->version != 1) { + if (minor_status) + *minor_status = 0; + return GSS_S_FAILURE; + } + + if (ctx->protocol == 0) { + free_key(&ctx->rfc1964_kd.ctx_key); + } else if (ctx->protocol == 1) { + free_key(&ctx->cfx_kd.ctx_key); + if (ctx->cfx_kd.have_acceptor_subkey) + free_key(&ctx->cfx_kd.acceptor_subkey); + } + free(ctx); + if (minor_status) + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, + gss_cred_id_t cred, + OM_uint32 num_enctypes, + int32_t *enctypes) +{ + krb5_error_code ret; + OM_uint32 maj_status; + gss_buffer_desc buffer; + krb5_storage *sp; + krb5_data data; + size_t i; + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + maj_status = GSS_S_FAILURE; + goto out; + } + + for (i = 0; i < num_enctypes; i++) { + ret = krb5_store_int32(sp, enctypes[i]); + if (ret) { + *minor_status = ret; + maj_status = GSS_S_FAILURE; + goto out; + } + } + + ret = krb5_storage_to_data(sp, &data); + if (ret) { + *minor_status = ret; + maj_status = GSS_S_FAILURE; + goto out; + } + + buffer.value = data.data; + buffer.length = data.length; + + maj_status = gss_set_cred_option(minor_status, + &cred, + GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, + &buffer); + krb5_data_free(&data); +out: + if (sp) + krb5_storage_free(sp); + return maj_status; +} + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + + _gss_load_mech(); + + if (c) { + buffer.value = c; + buffer.length = sizeof(*c); + } else { + buffer.value = NULL; + buffer.length = 0; + } + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_SEND_TO_KDC_X, &buffer); + } + + return (GSS_S_COMPLETE); +} + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_ccache_name(OM_uint32 *minor_status, + const char *name, + const char **out_name) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + OM_uint32 major_status; + struct gsskrb5_ccache_name_args args; + + _gss_load_mech(); + + *minor_status = 0; + + if (out_name) + *out_name = NULL; + + args.name = name; + args.out_name = NULL; + + buffer.value = &args; + buffer.length = sizeof(args); + + major_status = GSS_S_UNAVAILABLE; + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + OM_uint32 mech_major, mech_minor; + + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + + mech_major = m->gm_mech.gm_set_sec_context_option(&mech_minor, + NULL, GSS_KRB5_CCACHE_NAME_X, &buffer); + if (mech_major != GSS_S_UNAVAILABLE) { + major_status = mech_major; + *minor_status = mech_minor; + break; + } + } + + if (out_name) + *out_name = args.out_name; + + return major_status; +} + + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + time_t *authtime) +{ + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + OM_uint32 maj_stat; + + if (context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + maj_stat = + gss_inquire_sec_context_by_oid (minor_status, + context_handle, + GSS_KRB5_GET_AUTHTIME_X, + &data_set); + if (maj_stat) + return maj_stat; + + if (data_set == GSS_C_NO_BUFFER_SET) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (data_set->count != 1) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (data_set->elements[0].length != SIZEOF_TIME_T) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + +#if SIZEOF_TIME_T == 8 + _gss_mg_decode_le_uint64(data_set->elements[0].value, (uint64_t *)authtime); +#elif SIZEOF_TIME_T == 4 + _gss_mg_decode_le_uint32(data_set->elements[0].value, (uint32_t *)authtime); +#else +#error set SIZEOF_TIME_T for your platform +#endif + + gss_release_buffer_set(minor_status, &data_set); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int ad_type, + gss_buffer_t ad_data) +{ + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + OM_uint32 maj_stat, tmp; + gss_OID_desc oid_flat; + heim_oid baseoid, oid; + size_t size; + + if (context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + /* All this to append an integer to an oid... */ + + if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, + GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, + &baseoid, NULL) != 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + oid.length = baseoid.length + 1; + oid.components = calloc(oid.length, sizeof(*oid.components)); + if (oid.components == NULL) { + der_free_oid(&baseoid); + + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(oid.components, baseoid.components, + baseoid.length * sizeof(*baseoid.components)); + + der_free_oid(&baseoid); + + oid.components[oid.length - 1] = ad_type; + + oid_flat.length = (OM_uint32)der_length_oid(&oid); + oid_flat.elements = malloc(oid_flat.length); + if (oid_flat.elements == NULL) { + free(oid.components); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, + oid_flat.length, &oid, &size) != 0) { + free(oid.components); + _gss_free_oid(&tmp, &oid_flat); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + if (oid_flat.length != size) + abort(); + + free(oid.components); + + /* FINALLY, we have the OID */ + + maj_stat = gss_inquire_sec_context_by_oid (minor_status, + context_handle, + &oid_flat, + &data_set); + + _gss_free_oid(&tmp, &oid_flat); + + if (maj_stat) + return maj_stat; + + if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ad_data->value = malloc(data_set->elements[0].length); + if (ad_data->value == NULL) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ad_data->length = data_set->elements[0].length; + memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); + gss_release_buffer_set(minor_status, &data_set); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * + */ + +static OM_uint32 +gsskrb5_extract_key(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + const gss_OID oid, + krb5_keyblock **keyblock) +{ + krb5_error_code ret; + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + OM_uint32 major_status; + krb5_context context = NULL; + krb5_storage *sp = NULL; + + if (context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_init_context(&context); + if(ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + major_status = + gss_inquire_sec_context_by_oid (minor_status, + context_handle, + oid, + &data_set); + if (major_status) + return major_status; + + if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { + _gss_secure_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + sp = krb5_storage_from_mem(data_set->elements[0].value, + data_set->elements[0].length); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + *keyblock = calloc(1, sizeof(**keyblock)); + if (*keyblock == NULL) { + ret = ENOMEM; + goto out; + } + + ret = krb5_ret_keyblock(sp, *keyblock); + +out: + _gss_secure_release_buffer_set(minor_status, &data_set); + if (sp) + krb5_storage_free(sp); + if (ret && keyblock) { + krb5_free_keyblock(context, *keyblock); + *keyblock = NULL; + } + if (context) + krb5_free_context(context); + + *minor_status = ret; + if (ret) + return GSS_S_FAILURE; + + return GSS_S_COMPLETE; +} + +/* + * + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_extract_service_keyblock(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + krb5_keyblock **keyblock) +{ + return gsskrb5_extract_key(minor_status, + context_handle, + GSS_KRB5_GET_SERVICE_KEYBLOCK_X, + keyblock); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_initiator_subkey(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + krb5_keyblock **keyblock) +{ + return gsskrb5_extract_key(minor_status, + context_handle, + GSS_KRB5_GET_INITIATOR_SUBKEY_X, + keyblock); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_subkey(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + krb5_keyblock **keyblock) +{ + return gsskrb5_extract_key(minor_status, + context_handle, + GSS_KRB5_GET_SUBKEY_X, + keyblock); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_default_realm(const char *realm) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + + _gss_load_mech(); + + buffer.value = rk_UNCONST(realm); + buffer.length = strlen(realm); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_SET_DEFAULT_REALM_X, &buffer); + } + + return (GSS_S_COMPLETE); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_krb5_get_tkt_flags(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + OM_uint32 *tkt_flags) +{ + + OM_uint32 major_status; + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + + if (context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + major_status = + gss_inquire_sec_context_by_oid (minor_status, + context_handle, + GSS_KRB5_GET_TKT_FLAGS_X, + &data_set); + if (major_status) + return major_status; + + if (data_set == GSS_C_NO_BUFFER_SET || + data_set->count != 1 || + data_set->elements[0].length < 4) { + gss_release_buffer_set(minor_status, &data_set); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + _gss_mg_decode_le_uint32(data_set->elements[0].value, tkt_flags); + + gss_release_buffer_set(minor_status, &data_set); + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_set_time_offset(int offset) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + int32_t o = offset; + + _gss_load_mech(); + + buffer.value = &o; + buffer.length = sizeof(o); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_SET_TIME_OFFSET_X, &buffer); + } + + return (GSS_S_COMPLETE); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_get_time_offset(int *offset) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 maj_stat, junk; + int32_t o; + + _gss_load_mech(); + + buffer.value = &o; + buffer.length = sizeof(o); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_GET_TIME_OFFSET_X, &buffer); + + if (maj_stat == GSS_S_COMPLETE) { + *offset = o; + return maj_stat; + } + } + + return (GSS_S_UNAVAILABLE); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c) +{ + struct _gss_mech_switch *m; + gss_buffer_desc buffer; + OM_uint32 junk; + + _gss_load_mech(); + + buffer.value = c; + buffer.length = sizeof(*c); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (m->gm_mech.gm_set_sec_context_option == NULL) + continue; + m->gm_mech.gm_set_sec_context_option(&junk, NULL, + GSS_KRB5_PLUGIN_REGISTER_X, &buffer); + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c b/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c new file mode 100644 index 0000000..3151efe --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_mech_switch.c @@ -0,0 +1,586 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_mech_switch.c,v 1.2 2006/02/04 09:40:21 dfr Exp $ + */ + +#include "mech_locl.h" +#include + +#ifndef _PATH_GSS_MECH +#define _PATH_GSS_MECH "/etc/gss/mech" +#endif + +struct _gss_mech_switch_list _gss_mechs = { NULL, NULL } ; +gss_OID_set _gss_mech_oids; +static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; + +/* + * Convert a string containing an OID in 'dot' form + * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. + */ +static int +_gss_string_to_oid(const char* s, gss_OID *oidp) +{ + int number_count, i, j; + size_t byte_count; + const char *p, *q; + char *res; + gss_OID_desc oid; + + *oidp = GSS_C_NO_OID; + + /* + * First figure out how many numbers in the oid, then + * calculate the compiled oid size. + */ + number_count = 0; + for (p = s; p; p = q) { + q = strchr(p, '.'); + if (q) q = q + 1; + number_count++; + } + + /* + * The first two numbers are in the first byte and each + * subsequent number is encoded in a variable byte sequence. + */ + if (number_count < 2) + return (EINVAL); + + /* + * We do this in two passes. The first pass, we just figure + * out the size. Second time around, we actually encode the + * number. + */ + res = 0; + for (i = 0; i < 2; i++) { + byte_count = 0; + for (p = s, j = 0; p; p = q, j++) { + unsigned int number = 0; + + /* + * Find the end of this number. + */ + q = strchr(p, '.'); + if (q) q = q + 1; + + /* + * Read the number of of the string. Don't + * bother with anything except base ten. + */ + while (*p && *p != '.') { + number = 10 * number + (*p - '0'); + p++; + } + + /* + * Encode the number. The first two numbers + * are packed into the first byte. Subsequent + * numbers are encoded in bytes seven bits at + * a time with the last byte having the high + * bit set. + */ + if (j == 0) { + if (res) + *res = number * 40; + } else if (j == 1) { + if (res) { + *res += number; + res++; + } + byte_count++; + } else if (j >= 2) { + /* + * The number is encoded in seven bit chunks. + */ + unsigned int t; + unsigned int bytes; + + bytes = 0; + for (t = number; t; t >>= 7) + bytes++; + if (bytes == 0) bytes = 1; + while (bytes) { + if (res) { + int bit = 7*(bytes-1); + + *res = (number >> bit) & 0x7f; + if (bytes != 1) + *res |= 0x80; + res++; + } + byte_count++; + bytes--; + } + } + } + if (byte_count == 0) + return EINVAL; + if (!res) { + res = malloc(byte_count); + if (!res) + return (ENOMEM); + oid.length = byte_count; + oid.elements = res; + } + } + + { + OM_uint32 minor_status, tmp; + + if (GSS_ERROR(_gss_intern_oid(&minor_status, &oid, oidp))) { + _gss_free_oid(&tmp, &oid); + return (minor_status); + } + + _gss_free_oid(&tmp, &oid); + } + + return (0); +} + +#define SYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ + if (!m->gm_mech.gm_ ## name || \ + m->gm_mech.gm_ ##name == gss_ ## name) { \ + _gss_mg_log(1, "can't find symbol gss_" #name "\n"); \ + goto bad; \ + } \ +} while (0) + +#define OPTSYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ + if (m->gm_mech.gm_ ## name == gss_ ## name) \ + m->gm_mech.gm_ ## name = NULL; \ +} while (0) + +/* mech exports gssspi_XXX, internally referred to as gss_XXX */ +#define OPTSPISYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ +} while (0) + +/* mech exports gssspi_XXX, internally referred to as gssspi_XXX */ +#define OPTSPISPISYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ + if (m->gm_mech.gm_ ## name == gssspi_ ## name) \ + m->gm_mech.gm_ ## name = NULL; \ +} while (0) + +#define COMPATSYM(name) \ +do { \ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ + if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ + m->gm_mech.gm_compat->gmc_ ## name = NULL; \ +} while (0) + +#define COMPATSPISYM(name) \ +do { \ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ + if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ + m->gm_mech.gm_compat->gmc_ ## name = NULL; \ +} while (0) + +/* + * + */ +static int +add_builtin(gssapi_mech_interface mech) +{ + struct _gss_mech_switch *m; + OM_uint32 minor_status; + + /* not registering any mech is ok */ + if (mech == NULL) + return 0; + + m = calloc(1, sizeof(*m)); + if (m == NULL) + return ENOMEM; + m->gm_so = NULL; + m->gm_mech = *mech; + _gss_intern_oid(&minor_status, &mech->gm_mech_oid, &m->gm_mech_oid); + if (minor_status) { + free(m); + return minor_status; + } + + if (gss_add_oid_set_member(&minor_status, &m->gm_mech.gm_mech_oid, + &_gss_mech_oids) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } + + /* pick up the oid sets of names */ + + if (m->gm_mech.gm_inquire_names_for_mech) + (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, + &m->gm_mech.gm_mech_oid, &m->gm_name_types); + + if (m->gm_name_types == NULL && + gss_create_empty_oid_set(&minor_status, + &m->gm_name_types) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } + + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); + return 0; +} + +static void +init_mech_switch_list(void *p) +{ + struct _gss_mech_switch_list *mechs = p; + + HEIM_TAILQ_INIT(mechs); +} + +/* + * Load the mechanisms file (/etc/gss/mech). + */ +void +_gss_load_mech(void) +{ + OM_uint32 major_status, minor_status; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; +#ifdef HAVE_DLOPEN + FILE *fp; + char buf[256]; + char *p; + char *name, *oid, *lib, *kobj; + struct _gss_mech_switch *m; + void *so; + gss_OID mech_oid; + int found; + const char *conf = secure_getenv("GSS_MECH_CONFIG"); +#endif + + heim_base_once_f(&once, &_gss_mechs, init_mech_switch_list); + + HEIMDAL_MUTEX_lock(&_gss_mech_mutex); + + if (!HEIM_TAILQ_EMPTY(&_gss_mechs)) { + HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); + return; + } + + major_status = gss_create_empty_oid_set(&minor_status, + &_gss_mech_oids); + if (major_status) { + HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); + return; + } + + if (add_builtin(__gss_krb5_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin Kerberos GSS " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_spnego_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SPNEGO " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_ntlm_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin NTLM " + "mechanism to the GSS mechanism switch"); + +#ifdef HAVE_DLOPEN + fp = fopen(conf ? conf : _PATH_GSS_MECH, "r"); + if (!fp) + goto out; + rk_cloexec_file(fp); + + while (fgets(buf, sizeof(buf), fp)) { + _gss_mo_init *mi; + + if (*buf == '#') + continue; + p = buf; + name = strsep(&p, "\t\n "); + if (p) while (isspace((unsigned char)*p)) p++; + oid = strsep(&p, "\t\n "); + if (p) while (isspace((unsigned char)*p)) p++; + lib = strsep(&p, "\t\n "); + if (p) while (isspace((unsigned char)*p)) p++; + kobj = strsep(&p, "\t\n "); + if (!name || !oid || !lib || !kobj) + continue; + + if (_gss_string_to_oid(oid, &mech_oid)) + continue; + + /* + * Check for duplicates, already loaded mechs. + */ + found = 0; + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech_oid)) { + found = 1; + break; + } + } + if (found) + continue; + + so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP); + if (so == NULL) { + _gss_mg_log(1, "dlopen: %s\n", dlerror()); + goto bad; + } + + m = calloc(1, sizeof(*m)); + if (m == NULL) + goto bad; + + m->gm_so = so; + m->gm_mech_oid = mech_oid; + m->gm_mech.gm_name = strdup(name); + m->gm_mech.gm_mech_oid = *mech_oid; + m->gm_mech.gm_flags = 0; + m->gm_mech.gm_compat = calloc(1, sizeof(struct gss_mech_compat_desc_struct)); + if (m->gm_mech.gm_compat == NULL) + goto bad; + + major_status = gss_add_oid_set_member(&minor_status, + &m->gm_mech.gm_mech_oid, &_gss_mech_oids); + if (GSS_ERROR(major_status)) + goto bad; + + SYM(acquire_cred); + SYM(release_cred); + SYM(init_sec_context); + SYM(accept_sec_context); + SYM(process_context_token); + SYM(delete_sec_context); + SYM(context_time); + SYM(get_mic); + SYM(verify_mic); + SYM(wrap); + SYM(unwrap); + OPTSYM(display_status); + OPTSYM(indicate_mechs); + SYM(compare_name); + SYM(display_name); + SYM(import_name); + SYM(export_name); + SYM(release_name); + OPTSYM(inquire_cred); + SYM(inquire_context); + SYM(wrap_size_limit); + OPTSYM(add_cred); + OPTSYM(inquire_cred_by_mech); + SYM(export_sec_context); + SYM(import_sec_context); + OPTSYM(inquire_names_for_mech); + OPTSYM(inquire_mechs_for_name); + SYM(canonicalize_name); + SYM(duplicate_name); + OPTSYM(inquire_cred_by_oid); + OPTSYM(inquire_sec_context_by_oid); + OPTSYM(set_sec_context_option); + OPTSPISYM(set_cred_option); + OPTSYM(pseudo_random); + OPTSYM(wrap_iov); + OPTSYM(unwrap_iov); + OPTSYM(wrap_iov_length); + OPTSYM(store_cred); + OPTSYM(export_cred); + OPTSYM(import_cred); + OPTSYM(acquire_cred_from); + OPTSYM(acquire_cred_impersonate_name); +#if 0 + OPTSYM(iter_creds); + OPTSYM(destroy_cred); + OPTSYM(cred_hold); + OPTSYM(cred_unhold); + OPTSYM(cred_label_get); + OPTSYM(cred_label_set); +#endif + OPTSYM(display_name_ext); + OPTSYM(inquire_name); + OPTSYM(get_name_attribute); + OPTSYM(set_name_attribute); + OPTSYM(delete_name_attribute); + OPTSYM(export_name_composite); + OPTSYM(localname); + OPTSYM(duplicate_cred); + OPTSYM(add_cred_from); + OPTSYM(store_cred_into); + OPTSPISYM(authorize_localname); + OPTSPISPISYM(query_mechanism_info); + OPTSPISPISYM(query_meta_data); + OPTSPISPISYM(exchange_meta_data); + + mi = (_gss_mo_init *)dlsym(so, "gss_mo_init"); + if (mi != NULL) { + major_status = mi(&minor_status, mech_oid, + &m->gm_mech.gm_mo, &m->gm_mech.gm_mo_num); + if (GSS_ERROR(major_status)) + goto bad; + } else { + /* API-as-SPI compatibility */ + COMPATSYM(inquire_saslname_for_mech); + COMPATSYM(inquire_mech_for_saslname); + COMPATSYM(inquire_attrs_for_mech); + COMPATSPISYM(acquire_cred_with_password); + } + + /* pick up the oid sets of names */ + + if (m->gm_mech.gm_inquire_names_for_mech) + (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, + &m->gm_mech.gm_mech_oid, &m->gm_name_types); + + if (m->gm_name_types == NULL) + gss_create_empty_oid_set(&minor_status, &m->gm_name_types); + + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); + continue; + + bad: + if (m != NULL) { + free(m->gm_mech.gm_compat); + /* do not free OID, it has been interned */ + free((char *)m->gm_mech.gm_name); + free(m); + } + if (so != NULL) + dlclose(so); + continue; + } + fclose(fp); + +out: + +#endif + if (add_builtin(__gss_sanon_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SANON " + "mechanism to the GSS mechanism switch"); + HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); +} + +gssapi_mech_interface +__gss_get_mechanism(gss_const_OID mech) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) + return &m->gm_mech; + } + return NULL; +} + +gss_OID +_gss_mg_support_mechanism(gss_const_OID mech) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) + return m->gm_mech_oid; + } + return NULL; +} + +enum mech_name_match { + MATCH_NONE = 0, + MATCH_COMPLETE, + MATCH_PARTIAL +}; + +static enum mech_name_match +match_mech_name(const char *gm_mech_name, + const char *name, + size_t namelen) +{ + if (gm_mech_name == NULL) + return MATCH_NONE; + else if (strcasecmp(gm_mech_name, name) == 0) + return MATCH_COMPLETE; + else if (strncasecmp(gm_mech_name, name, namelen) == 0) + return MATCH_PARTIAL; + else + return MATCH_NONE; +} + +/* + * Return an OID for a built-in or dynamically loaded mechanism. For + * API compatibility with previous versions, we treat "Kerberos 5" + * as an alias for "krb5". Unique partial matches are supported. + */ +GSSAPI_LIB_FUNCTION gss_OID GSSAPI_CALLCONV +gss_name_to_oid(const char *name) +{ + struct _gss_mech_switch *m, *partial = NULL; + gss_OID oid = GSS_C_NO_OID; + size_t namelen = strlen(name); + + if (isdigit((unsigned char)name[0]) && + _gss_string_to_oid(name, &oid) == 0) + return oid; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + enum mech_name_match match; + + match = match_mech_name(m->gm_mech.gm_name, name, namelen); + if (match == MATCH_NONE && + gss_oid_equal(m->gm_mech_oid, GSS_KRB5_MECHANISM)) + match = match_mech_name("Kerberos 5", name, namelen); + + if (match == MATCH_COMPLETE) + return m->gm_mech_oid; + else if (match == MATCH_PARTIAL) { + if (partial) + return NULL; + else + partial = m; + } + } + + if (partial) + return partial->gm_mech_oid; + + return NULL; +} + +GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL +gss_oid_to_name(gss_const_OID oid) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(m->gm_mech_oid, oid)) + return m->gm_mech.gm_name; + } + + return NULL; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_mo.c b/third_party/heimdal/lib/gssapi/mech/gss_mo.c new file mode 100644 index 0000000..08cb43d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_mo.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 PADL Software Pty Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +#include + +static int +get_option_def(int def, gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) +{ + return def; +} + +int +_gss_mo_get_option_1(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) +{ + return get_option_def(1, mech, mo, value); +} + +int +_gss_mo_get_option_0(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) +{ + return get_option_def(0, mech, mo, value); +} + +int +_gss_mo_get_ctx_as_string(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) +{ + if (value) { + value->value = strdup((char *)mo->ctx); + if (value->value == NULL) + return GSS_S_FAILURE; + value->length = strlen((char *)mo->ctx); + } + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_mo_set(gss_const_OID mech, gss_const_OID option, + int enable, gss_buffer_t value) +{ + gssapi_mech_interface m; + size_t n; + + if ((m = __gss_get_mechanism(mech)) == NULL) + return GSS_S_BAD_MECH; + + for (n = 0; n < m->gm_mo_num; n++) + if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].set) + return m->gm_mo[n].set(mech, &m->gm_mo[n], enable, value); + + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_mo_get(gss_const_OID mech, gss_const_OID option, gss_buffer_t value) +{ + gssapi_mech_interface m; + size_t n; + + _mg_buffer_zero(value); + + if ((m = __gss_get_mechanism(mech)) == NULL) + return GSS_S_BAD_MECH; + + for (n = 0; n < m->gm_mo_num; n++) + if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].get) + return m->gm_mo[n].get(mech, &m->gm_mo[n], value); + + return GSS_S_UNAVAILABLE; +} + +static void +add_all_mo(gssapi_mech_interface m, gss_OID_set *options, OM_uint32 mask) +{ + OM_uint32 minor; + size_t n; + + for (n = 0; n < m->gm_mo_num; n++) + if ((m->gm_mo[n].flags & mask) == mask) + gss_add_oid_set_member(&minor, m->gm_mo[n].option, options); +} + +GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL +gss_mo_list(gss_const_OID mech, gss_OID_set *options) +{ + gssapi_mech_interface m; + OM_uint32 major, minor; + + if (options == NULL) + return; + + *options = GSS_C_NO_OID_SET; + + if ((m = __gss_get_mechanism(mech)) == NULL) + return; + + major = gss_create_empty_oid_set(&minor, options); + if (major != GSS_S_COMPLETE) + return; + + add_all_mo(m, options, 0); +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_mo_name(gss_const_OID mech, gss_const_OID option, gss_buffer_t name) +{ + gssapi_mech_interface m; + size_t n; + + if (name == NULL) + return GSS_S_BAD_NAME; + + if ((m = __gss_get_mechanism(mech)) == NULL) + return GSS_S_BAD_MECH; + + for (n = 0; n < m->gm_mo_num; n++) { + if (gss_oid_equal(option, m->gm_mo[n].option)) { + /* + * If there is no name, its because its a GSS_C_MA and + * there is already a table for that. + */ + if (m->gm_mo[n].name) { + name->value = strdup(m->gm_mo[n].name); + if (name->value == NULL) + return GSS_S_BAD_NAME; + name->length = strlen(m->gm_mo[n].name); + return GSS_S_COMPLETE; + } else { + OM_uint32 junk; + return gss_display_mech_attr(&junk, option, + NULL, name, NULL); + } + } + } + return GSS_S_BAD_NAME; +} + +/* + * Helper function to allow NULL name + */ + +static OM_uint32 +mo_value(const gss_const_OID mech, gss_const_OID option, gss_buffer_t name) +{ + if (name == NULL) + return GSS_S_COMPLETE; + + return gss_mo_get(mech, option, name); +} + +/* code derived from draft-ietf-cat-sasl-gssapi-01 */ +static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +static OM_uint32 +make_sasl_name(OM_uint32 *minor, const gss_OID mech, char sasl_name[16]) +{ + EVP_MD_CTX *ctx; + char *p = sasl_name; + u_char hdr[2], hash[20], *h = hash; + + if (mech->length > 127) + return GSS_S_BAD_MECH; + + hdr[0] = 0x06; + hdr[1] = mech->length; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); + EVP_DigestUpdate(ctx, hdr, 2); + EVP_DigestUpdate(ctx, mech->elements, mech->length); + EVP_DigestFinal_ex(ctx, hash, NULL); + EVP_MD_CTX_destroy(ctx); + + memcpy(p, "GS2-", 4); + p += 4; + + *p++ = basis_32[(h[0] >> 3)]; + *p++ = basis_32[((h[0] & 7) << 2) | (h[1] >> 6)]; + *p++ = basis_32[(h[1] & 0x3f) >> 1]; + *p++ = basis_32[((h[1] & 1) << 4) | (h[2] >> 4)]; + *p++ = basis_32[((h[2] & 0xf) << 1) | (h[3] >> 7)]; + *p++ = basis_32[(h[3] & 0x7f) >> 2]; + *p++ = basis_32[((h[3] & 3) << 3) | (h[4] >> 5)]; + *p++ = basis_32[(h[4] & 0x1f)]; + *p++ = basis_32[(h[5] >> 3)]; + *p++ = basis_32[((h[5] & 7) << 2) | (h[6] >> 6)]; + *p++ = basis_32[(h[6] & 0x3f) >> 1]; + + *p = '\0'; + + return GSS_S_COMPLETE; +} + +/* + * gss_inquire_saslname_for_mech() wrapper that uses MIT SPI + */ +static OM_uint32 +inquire_saslname_for_mech_compat(OM_uint32 *minor, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + struct gss_mech_compat_desc_struct *gmc; + gssapi_mech_interface m; + OM_uint32 major; + + m = __gss_get_mechanism(desired_mech); + if (m == NULL) + return GSS_S_BAD_MECH; + + gmc = m->gm_compat; + + if (gmc != NULL && gmc->gmc_inquire_saslname_for_mech != NULL) { + major = gmc->gmc_inquire_saslname_for_mech(minor, + desired_mech, + sasl_mech_name, + mech_name, + mech_description); + } else { + major = GSS_S_UNAVAILABLE; + } + + return major; +} + +/** + * Returns different protocol names and description of the mechanism. + * + * @param minor_status minor status code + * @param desired_mech mech list query + * @param sasl_mech_name SASL GS2 protocol name + * @param mech_name gssapi protocol name + * @param mech_description description of gssapi mech + * + * @return returns GSS_S_COMPLETE or a error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_saslname_for_mech(OM_uint32 *minor_status, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) +{ + OM_uint32 major; + + _mg_buffer_zero(sasl_mech_name); + _mg_buffer_zero(mech_name); + _mg_buffer_zero(mech_description); + + if (minor_status) + *minor_status = 0; + + if (desired_mech == NULL) + return GSS_S_BAD_MECH; + + major = mo_value(desired_mech, GSS_C_MA_SASL_MECH_NAME, sasl_mech_name); + if (major == GSS_S_COMPLETE) { + /* Native SPI */ + major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name); + if (GSS_ERROR(major)) + return major; + + major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description); + if (GSS_ERROR(major)) + return major; + } + + if (GSS_ERROR(major)) { + /* API-as-SPI compatibility */ + major = inquire_saslname_for_mech_compat(minor_status, + desired_mech, + sasl_mech_name, + mech_name, + mech_description); + } + + if (GSS_ERROR(major)) { + /* Algorithmically dervied SASL mechanism name */ + char buf[16]; + gss_buffer_desc tmp = { sizeof(buf) - 1, buf }; + + major = make_sasl_name(minor_status, desired_mech, buf); + if (GSS_ERROR(major)) + return major; + + major = _gss_copy_buffer(minor_status, &tmp, sasl_mech_name); + if (GSS_ERROR(major)) + return major; + } + + return major; +} + +/** + * Find a mech for a sasl name + * + * @param minor_status minor status code + * @param sasl_mech_name + * @param mech_type + * + * @return returns GSS_S_COMPLETE or an error code. + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_mech_for_saslname(OM_uint32 *minor_status, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) +{ + struct _gss_mech_switch *m; + gss_buffer_desc name; + OM_uint32 major, junk; + char buf[16]; + + _gss_load_mech(); + + *mech_type = NULL; + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + struct gss_mech_compat_desc_struct *gmc; + + /* Native SPI */ + major = mo_value(m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); + if (major == GSS_S_COMPLETE && + name.length == sasl_mech_name->length && + memcmp(name.value, sasl_mech_name->value, name.length) == 0) { + gss_release_buffer(&junk, &name); + *mech_type = m->gm_mech_oid; + return GSS_S_COMPLETE; + } + gss_release_buffer(&junk, &name); + + if (GSS_ERROR(major)) { + /* API-as-SPI compatibility */ + gmc = m->gm_mech.gm_compat; + if (gmc && gmc->gmc_inquire_mech_for_saslname) { + major = gmc->gmc_inquire_mech_for_saslname(minor_status, + sasl_mech_name, + mech_type); + if (major == GSS_S_COMPLETE) + return GSS_S_COMPLETE; + } + } + + if (GSS_ERROR(major)) { + /* Algorithmically dervied SASL mechanism name */ + if (sasl_mech_name->length == 16 && + make_sasl_name(minor_status, m->gm_mech_oid, buf) == GSS_S_COMPLETE && + memcmp(buf, sasl_mech_name->value, 16) == 0) { + *mech_type = m->gm_mech_oid; + return GSS_S_COMPLETE; + } + } + } + + return GSS_S_BAD_MECH; +} + +/* + * Test mechanism against indicated attributes using both Heimdal and + * MIT SPIs. + */ +static int +test_mech_attrs(gssapi_mech_interface mi, + gss_const_OID_set mech_attrs, + gss_const_OID_set against_attrs, + int except) +{ + size_t n, m; + int eq = 0; + + if (against_attrs == GSS_C_NO_OID_SET) + return 1; + + for (n = 0; n < against_attrs->count; n++) { + for (m = 0; m < mi->gm_mo_num; m++) { + eq = gss_oid_equal(mi->gm_mo[m].option, + &against_attrs->elements[n]); + if (eq) + break; + } + if (mech_attrs != GSS_C_NO_OID_SET) { + for (m = 0; m < mech_attrs->count; m++) { + eq = gss_oid_equal(&mech_attrs->elements[m], + &against_attrs->elements[n]); + if (eq) + break; + } + } + if (!eq ^ except) + return 0; + } + + return 1; +} + +/** + * Return set of mechanism that fullfill the criteria + * + * @param minor_status minor status code + * @param desired_mech_attrs + * @param except_mech_attrs + * @param critical_mech_attrs + * @param mechs returned mechs, free with gss_release_oid_set(). + * + * @return returns GSS_S_COMPLETE or an error code. + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs) +{ + struct _gss_mech_switch *ms; + gss_OID_set mech_attrs = GSS_C_NO_OID_SET; + gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET; + OM_uint32 major, tmp; + + major = gss_create_empty_oid_set(minor_status, mechs); + if (GSS_ERROR(major)) + return major; + + _gss_load_mech(); + + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + gssapi_mech_interface mi = &ms->gm_mech; + struct gss_mech_compat_desc_struct *gmc = mi->gm_compat; + + if (gmc && gmc->gmc_inquire_attrs_for_mech) { + major = gmc->gmc_inquire_attrs_for_mech(minor_status, + &mi->gm_mech_oid, + &mech_attrs, + &known_mech_attrs); + if (GSS_ERROR(major)) + continue; + } + + /* + * Test mechanism supports all of desired_mech_attrs; + * none of except_mech_attrs; + * and knows of all critical_mech_attrs. + */ + if (test_mech_attrs(mi, mech_attrs, desired_mech_attrs, 0) && + test_mech_attrs(mi, mech_attrs, except_mech_attrs, 1) && + test_mech_attrs(mi, known_mech_attrs, critical_mech_attrs, 0)) { + major = gss_add_oid_set_member(minor_status, &mi->gm_mech_oid, mechs); + } + + gss_release_oid_set(&tmp, &mech_attrs); + gss_release_oid_set(&tmp, &known_mech_attrs); + + if (GSS_ERROR(major)) + break; + } + + if (major) + gss_release_oid_set(&tmp, mechs); + + return major; +} + +/** + * List support attributes for a mech and/or all mechanisms. + * + * @param minor_status minor status code + * @param mech given together with mech_attr will return the list of + * attributes for mechanism, can optionally be GSS_C_NO_OID. + * @param mech_attr see mech parameter, can optionally be NULL, + * release with gss_release_oid_set(). + * @param known_mech_attrs all attributes for mechanisms supported, + * release with gss_release_oid_set(). + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_attrs_for_mech(OM_uint32 * minor_status, + gss_const_OID mech, + gss_OID_set *mech_attr, + gss_OID_set *known_mech_attrs) +{ + OM_uint32 major, junk; + + if (known_mech_attrs) + *known_mech_attrs = GSS_C_NO_OID_SET; + + if (mech_attr && mech) { + gssapi_mech_interface m; + struct gss_mech_compat_desc_struct *gmc; + + if ((m = __gss_get_mechanism(mech)) == NULL) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + gmc = m->gm_compat; + + if (gmc && gmc->gmc_inquire_attrs_for_mech) { + major = gmc->gmc_inquire_attrs_for_mech(minor_status, + mech, + mech_attr, + known_mech_attrs); + } else { + major = gss_create_empty_oid_set(minor_status, mech_attr); + if (major == GSS_S_COMPLETE) + add_all_mo(m, mech_attr, GSS_MO_MA); + } + if (GSS_ERROR(major)) + return major; + } + + if (known_mech_attrs) { + struct _gss_mech_switch *m; + + if (*known_mech_attrs == GSS_C_NO_OID_SET) { + major = gss_create_empty_oid_set(minor_status, known_mech_attrs); + if (GSS_ERROR(major)) { + if (mech_attr) + gss_release_oid_set(&junk, mech_attr); + return major; + } + } + + _gss_load_mech(); + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) + add_all_mo(&m->gm_mech, known_mech_attrs, GSS_MO_MA); + } + + + return GSS_S_COMPLETE; +} + +/** + * Return names and descriptions of mech attributes + * + * @param minor_status minor status code + * @param mech_attr + * @param name + * @param short_desc + * @param long_desc + * + * @return returns GSS_S_COMPLETE or an error code. + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_mech_attr(OM_uint32 * minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc) +{ + struct _gss_oid_name_table *ma = NULL; + OM_uint32 major; + size_t n; + + _mg_buffer_zero(name); + _mg_buffer_zero(short_desc); + _mg_buffer_zero(long_desc); + + if (minor_status) + *minor_status = 0; + + for (n = 0; ma == NULL && _gss_ont_ma[n].oid; n++) + if (gss_oid_equal(mech_attr, _gss_ont_ma[n].oid)) + ma = &_gss_ont_ma[n]; + + if (ma == NULL) + return GSS_S_BAD_MECH_ATTR; + + if (name) { + gss_buffer_desc bd; + bd.value = rk_UNCONST(ma->name); + bd.length = strlen(ma->name); + major = _gss_copy_buffer(minor_status, &bd, name); + if (major != GSS_S_COMPLETE) + return major; + } + + if (short_desc) { + gss_buffer_desc bd; + bd.value = rk_UNCONST(ma->short_desc); + bd.length = strlen(ma->short_desc); + major = _gss_copy_buffer(minor_status, &bd, short_desc); + if (major != GSS_S_COMPLETE) + return major; + } + + if (long_desc) { + gss_buffer_desc bd; + bd.value = rk_UNCONST(ma->long_desc); + bd.length = strlen(ma->long_desc); + major = _gss_copy_buffer(minor_status, &bd, long_desc); + if (major != GSS_S_COMPLETE) + return major; + } + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_names.c b/third_party/heimdal/lib/gssapi/mech/gss_names.c new file mode 100644 index 0000000..729e7f2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_names.c @@ -0,0 +1,262 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_names.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +gss_name_t +_gss_mg_get_underlying_mech_name(gss_name_t name, + gss_const_OID mech) +{ + struct _gss_name *n = (struct _gss_name *)name; + struct _gss_mechanism_name *mn; + + HEIM_TAILQ_FOREACH(mn, &n->gn_mn, gmn_link) { + if (gss_oid_equal(mech, mn->gmn_mech_oid)) + return mn->gmn_name; + } + return GSS_C_NO_NAME; +} + +OM_uint32 +_gss_find_mn(OM_uint32 *minor_status, + struct _gss_name *name, + gss_const_OID mech, + struct _gss_mechanism_name ** output_mn) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + struct _gss_mechanism_name *mn; + + *output_mn = NULL; + + /* null names are ok, some mechs might not have names */ + if (name == NULL) + return GSS_S_COMPLETE; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + if (gss_oid_equal(mech, mn->gmn_mech_oid)) + break; + } + + if (!mn) { + /* + * If this name is canonical (i.e. there is only an + * MN but it is from a different mech), give up now. + */ + if (!name->gn_value.value) + return GSS_S_BAD_NAME; + + m = __gss_get_mechanism(mech); + if (!m || !m->gm_import_name) + return (GSS_S_BAD_MECH); + + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) + return GSS_S_FAILURE; + + major_status = m->gm_import_name(minor_status, + &name->gn_value, + name->gn_type, + &mn->gmn_name); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + free(mn); + return major_status; + } + + mn->gmn_mech = m; + mn->gmn_mech_oid = &m->gm_mech_oid; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } + *output_mn = mn; + return 0; +} + + +/* + * Make a name from an MN. + */ +struct _gss_name * +_gss_create_name(gss_name_t new_mn, + struct gssapi_mech_interface_desc *m) +{ + struct _gss_name *name; + struct _gss_mechanism_name *mn; + + name = calloc(1, sizeof(struct _gss_name)); + if (!name) + return (0); + + HEIM_TAILQ_INIT(&name->gn_mn); + + if (new_mn) { + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) { + free(name); + return (0); + } + + mn->gmn_mech = m; + mn->gmn_mech_oid = &m->gm_mech_oid; + mn->gmn_name = new_mn; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } + + return (name); +} + +/* + * + */ + +void +_gss_mg_release_name(struct _gss_name *name) +{ + OM_uint32 junk; + struct _gss_mechanism_name *mn, *next; + + gss_release_oid(&junk, &name->gn_type); + + HEIM_TAILQ_FOREACH_SAFE(mn, &name->gn_mn, gmn_link, next) { + HEIM_TAILQ_REMOVE(&name->gn_mn, mn, gmn_link); + mn->gmn_mech->gm_release_name(&junk, &mn->gmn_name); + free(mn); + } + gss_release_buffer(&junk, &name->gn_value); + free(name); +} + +void +_gss_mg_check_name(gss_const_name_t name) +{ + if (name == NULL) return; +} + +/* + * + */ + +OM_uint32 +_gss_mech_import_name(OM_uint32 * minor_status, + gss_const_OID mech, + struct _gss_name_type *names, + const gss_buffer_t input_name_buffer, + gss_const_OID input_name_type, + gss_name_t *output_name) +{ + struct _gss_name_type *name; + gss_buffer_t name_buffer = input_name_buffer; + gss_buffer_desc export_name; + + *minor_status = 0; + + if (output_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *output_name = GSS_C_NO_NAME; + + /* + * If its a exported name, strip of the mech glue. + */ + + if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { + unsigned char *p; + uint32_t length; + + if (name_buffer->length < 10 + mech->length) + return GSS_S_BAD_NAME; + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + p = name_buffer->value; + + if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 || + p[3] != mech->length + 2 || + p[4] != 0x06 || + p[5] != mech->length || + memcmp(&p[6], mech->elements, mech->length) != 0) + return GSS_S_BAD_NAME; + + p += 6 + mech->length; + + length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + + if (length > name_buffer->length - 10 - mech->length) + return GSS_S_BAD_NAME; + + /* + * Point this to the mech specific name part, don't modifity + * orignal input_name_buffer. + */ + + export_name.length = length; + export_name.value = p; + + name_buffer = &export_name; + } + + for (name = names; name->gnt_parse != NULL; name++) { + if (gss_oid_equal(input_name_type, name->gnt_name_type) + || (name->gnt_name_type == GSS_C_NO_OID && input_name_type == GSS_C_NO_OID)) + return name->gnt_parse(minor_status, mech, name_buffer, + input_name_type, output_name); + } + + return GSS_S_BAD_NAMETYPE; +} + +OM_uint32 +_gss_mech_inquire_names_for_mech(OM_uint32 * minor_status, + struct _gss_name_type *names, + gss_OID_set *name_types) +{ + struct _gss_name_type *name; + OM_uint32 ret, junk; + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + for (name = names; name->gnt_parse != NULL; name++) { + if (name->gnt_name_type == GSS_C_NO_OID) + continue; + ret = gss_add_oid_set_member(minor_status, + name->gnt_name_type, + name_types); + if (ret != GSS_S_COMPLETE) + break; + } + + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(&junk, name_types); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_oid.c b/third_party/heimdal/lib/gssapi/mech/gss_oid.c new file mode 100644 index 0000000..10ec22d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_oid.c @@ -0,0 +1,370 @@ +/* Generated file */ +#include "mech_locl.h" + +/* GSS_KRB5_COPY_CCACHE_X - 1.2.752.43.13.1 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_copy_ccache_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x01") }; + +/* GSS_KRB5_GET_TKT_FLAGS_X - 1.2.752.43.13.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_tkt_flags_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x02") }; + +/* GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X - 1.2.752.43.13.3 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_extract_authz_data_from_sec_context_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x03") }; + +/* GSS_KRB5_COMPAT_DES3_MIC_X - 1.2.752.43.13.4 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_compat_des3_mic_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x04") }; + +/* GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X - 1.2.752.43.13.5 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_register_acceptor_identity_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x05") }; + +/* GSS_KRB5_EXPORT_LUCID_CONTEXT_X - 1.2.752.43.13.6 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_export_lucid_context_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x06") }; + +/* GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X - 1.2.752.43.13.6.1 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_export_lucid_context_v1_x_oid_desc = { 7, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x06\x01") }; + +/* GSS_KRB5_SET_DNS_CANONICALIZE_X - 1.2.752.43.13.7 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_set_dns_canonicalize_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x07") }; + +/* GSS_KRB5_GET_SUBKEY_X - 1.2.752.43.13.8 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_subkey_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x08") }; + +/* GSS_KRB5_GET_INITIATOR_SUBKEY_X - 1.2.752.43.13.9 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_initiator_subkey_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x09") }; + +/* GSS_KRB5_GET_ACCEPTOR_SUBKEY_X - 1.2.752.43.13.10 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_acceptor_subkey_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0a") }; + +/* GSS_KRB5_SEND_TO_KDC_X - 1.2.752.43.13.11 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_send_to_kdc_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0b") }; + +/* GSS_KRB5_GET_AUTHTIME_X - 1.2.752.43.13.12 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_authtime_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0c") }; + +/* GSS_KRB5_GET_SERVICE_KEYBLOCK_X - 1.2.752.43.13.13 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_service_keyblock_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0d") }; + +/* GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X - 1.2.752.43.13.14 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_set_allowable_enctypes_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0e") }; + +/* GSS_KRB5_SET_DEFAULT_REALM_X - 1.2.752.43.13.15 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_set_default_realm_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x0f") }; + +/* GSS_KRB5_CCACHE_NAME_X - 1.2.752.43.13.16 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_ccache_name_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x10") }; + +/* GSS_KRB5_SET_TIME_OFFSET_X - 1.2.752.43.13.17 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_set_time_offset_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x11") }; + +/* GSS_KRB5_GET_TIME_OFFSET_X - 1.2.752.43.13.18 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_get_time_offset_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x12") }; + +/* GSS_KRB5_PLUGIN_REGISTER_X - 1.2.752.43.13.19 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_plugin_register_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x13") }; + +/* GSS_NTLM_GET_SESSION_KEY_X - 1.2.752.43.13.20 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_ntlm_get_session_key_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x14") }; + +/* GSS_C_NT_NTLM - 1.2.752.43.13.21 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_ntlm_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x15") }; + +/* GSS_C_NT_DN - 1.2.752.43.13.22 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_dn_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x16") }; + +/* GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL - 1.2.752.43.13.23 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_referral_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x17") }; + +/* GSS_C_NTLM_AVGUEST - 1.2.752.43.13.24 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_avguest_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x18") }; + +/* GSS_C_NTLM_V1 - 1.2.752.43.13.25 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_v1_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x19") }; + +/* GSS_C_NTLM_V2 - 1.2.752.43.13.26 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_v2_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1a") }; + +/* GSS_C_NTLM_SESSION_KEY - 1.2.752.43.13.27 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_session_key_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1b") }; + +/* GSS_C_NTLM_FORCE_V1 - 1.2.752.43.13.28 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_force_v1_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1c") }; + +/* GSS_KRB5_CRED_NO_CI_FLAGS_X - 1.2.752.43.13.29 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_cred_no_ci_flags_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1d") }; + +/* GSS_KRB5_IMPORT_CRED_X - 1.2.752.43.13.30 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_cred_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1e") }; + +/* GSS_KRB5_IMPORT_RFC4121_CONTEXT_X - 1.2.752.43.13.31 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_rfc4121_context_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1f") }; + +/* GSS_C_MA_SASL_MECH_NAME - 1.2.752.43.13.100 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_sasl_mech_name_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x64") }; + +/* GSS_C_MA_MECH_NAME - 1.2.752.43.13.101 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_name_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x65") }; + +/* GSS_C_MA_MECH_DESCRIPTION - 1.2.752.43.13.102 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_description_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x66") }; + +/* GSS_SASL_DIGEST_MD5_MECHANISM - 1.2.752.43.14.1 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_sasl_digest_md5_mechanism_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x01") }; + +/* GSS_NETLOGON_MECHANISM - 1.2.752.43.14.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_netlogon_mechanism_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x02") }; + +/* GSS_NETLOGON_SET_SESSION_KEY_X - 1.2.752.43.14.3 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_netlogon_set_session_key_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x03") }; + +/* GSS_NETLOGON_SET_SIGN_ALGORITHM_X - 1.2.752.43.14.4 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_netlogon_set_sign_algorithm_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x04") }; + +/* GSS_NETLOGON_NT_NETBIOS_DNS_NAME - 1.2.752.43.14.5 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_netlogon_nt_netbios_dns_name_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x05") }; + +/* GSS_C_INQ_WIN2K_PAC_X - 1.2.752.43.13.3.128 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_win2k_pac_x_oid_desc = { 8, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x03\x81\x00") }; + +/* GSS_C_INQ_SSPI_SESSION_KEY - 1.2.840.113554.1.2.2.5.5 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_sspi_session_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05") }; + +/* GSS_C_INQ_NEGOEX_KEY - 1.2.840.113554.1.2.2.5.16 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x10") }; + +/* GSS_C_INQ_NEGOEX_VERIFY_KEY - 1.2.840.113554.1.2.2.5.17 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_verify_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x11") }; + +/* GSS_C_INQ_REQUIRE_MECHLIST_MIC - 1.3.6.1.4.1.7165.655.1.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_require_mechlist_mic_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x02") }; + +/* GSS_KRB5_MECHANISM - 1.2.840.113554.1.2.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_mechanism_oid_desc = { 9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; + +/* GSS_NTLM_MECHANISM - 1.3.6.1.4.1.311.2.2.10 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_ntlm_mechanism_oid_desc = { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") }; + +/* GSS_SPNEGO_MECHANISM - 1.3.6.1.5.5.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_spnego_mechanism_oid_desc = { 6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02") }; + +/* GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO - 1.3.6.1.4.1.5322.19.6 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_peer_has_buggy_spnego_oid_desc = { 9, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x13\x06") }; + +/* GSS_C_NTLM_RESET_CRYPTO - 1.3.6.1.4.1.7165.655.1.3 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_reset_crypto_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x03") }; + +/* GSS_NEGOEX_MECHANISM - 1.3.6.1.4.1.311.2.2.30 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_negoex_mechanism_oid_desc = { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e") }; + +/* GSS_SANON_X25519_MECHANISM - 1.3.6.1.4.1.5322.26.1.110 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_sanon_x25519_mechanism_oid_desc = { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x1a\x01\x6e") }; + +/* GSS_C_MA_MECH_CONCRETE - 1.3.6.1.5.5.13.1 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_concrete_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x01") }; + +/* GSS_C_MA_MECH_PSEUDO - 1.3.6.1.5.5.13.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_pseudo_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x02") }; + +/* GSS_C_MA_MECH_COMPOSITE - 1.3.6.1.5.5.13.3 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_composite_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x03") }; + +/* GSS_C_MA_MECH_NEGO - 1.3.6.1.5.5.13.4 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_nego_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x04") }; + +/* GSS_C_MA_MECH_GLUE - 1.3.6.1.5.5.13.5 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_glue_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x05") }; + +/* GSS_C_MA_NOT_MECH - 1.3.6.1.5.5.13.6 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_not_mech_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x06") }; + +/* GSS_C_MA_DEPRECATED - 1.3.6.1.5.5.13.7 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_deprecated_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x07") }; + +/* GSS_C_MA_NOT_DFLT_MECH - 1.3.6.1.5.5.13.8 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_not_dflt_mech_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x08") }; + +/* GSS_C_MA_ITOK_FRAMED - 1.3.6.1.5.5.13.9 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_itok_framed_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x09") }; + +/* GSS_C_MA_AUTH_INIT - 1.3.6.1.5.5.13.10 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_init_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0a") }; + +/* GSS_C_MA_AUTH_TARG - 1.3.6.1.5.5.13.11 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_targ_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0b") }; + +/* GSS_C_MA_AUTH_INIT_INIT - 1.3.6.1.5.5.13.12 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_init_init_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0c") }; + +/* GSS_C_MA_AUTH_TARG_INIT - 1.3.6.1.5.5.13.13 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_targ_init_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0d") }; + +/* GSS_C_MA_AUTH_INIT_ANON - 1.3.6.1.5.5.13.14 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_init_anon_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0e") }; + +/* GSS_C_MA_AUTH_TARG_ANON - 1.3.6.1.5.5.13.15 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_auth_targ_anon_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x0f") }; + +/* GSS_C_MA_DELEG_CRED - 1.3.6.1.5.5.13.16 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_deleg_cred_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x10") }; + +/* GSS_C_MA_INTEG_PROT - 1.3.6.1.5.5.13.17 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_integ_prot_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x11") }; + +/* GSS_C_MA_CONF_PROT - 1.3.6.1.5.5.13.18 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_conf_prot_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x12") }; + +/* GSS_C_MA_MIC - 1.3.6.1.5.5.13.19 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mic_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x13") }; + +/* GSS_C_MA_WRAP - 1.3.6.1.5.5.13.20 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_wrap_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x14") }; + +/* GSS_C_MA_PROT_READY - 1.3.6.1.5.5.13.21 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_prot_ready_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x15") }; + +/* GSS_C_MA_REPLAY_DET - 1.3.6.1.5.5.13.22 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_replay_det_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x16") }; + +/* GSS_C_MA_OOS_DET - 1.3.6.1.5.5.13.23 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_oos_det_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x17") }; + +/* GSS_C_MA_CBINDINGS - 1.3.6.1.5.5.13.24 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_cbindings_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x18") }; + +/* GSS_C_MA_PFS - 1.3.6.1.5.5.13.25 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_pfs_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x19") }; + +/* GSS_C_MA_COMPRESS - 1.3.6.1.5.5.13.26 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_compress_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x1a") }; + +/* GSS_C_MA_CTX_TRANS - 1.3.6.1.5.5.13.27 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_ctx_trans_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x1b") }; + +/* GSS_C_MA_NEGOEX_AND_SPNEGO - 1.2.840.113554.1.2.2.5.18 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_negoex_and_spnego_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x12") }; + +struct _gss_oid_name_table _gss_ont_ma[] = { + { GSS_C_MA_AUTH_INIT, "GSS_C_MA_AUTH_INIT", "auth-init-princ", "" }, + { GSS_C_MA_AUTH_INIT_ANON, "GSS_C_MA_AUTH_INIT_ANON", "auth-init-princ-anon", "" }, + { GSS_C_MA_AUTH_INIT_INIT, "GSS_C_MA_AUTH_INIT_INIT", "auth-init-princ-initial", "" }, + { GSS_C_MA_AUTH_TARG, "GSS_C_MA_AUTH_TARG", "auth-targ-princ", "" }, + { GSS_C_MA_AUTH_TARG_ANON, "GSS_C_MA_AUTH_TARG_ANON", "auth-targ-princ-anon", "" }, + { GSS_C_MA_AUTH_TARG_INIT, "GSS_C_MA_AUTH_TARG_INIT", "auth-targ-princ-initial", "" }, + { GSS_C_MA_CBINDINGS, "GSS_C_MA_CBINDINGS", "channel-bindings", "" }, + { GSS_C_MA_COMPRESS, "GSS_C_MA_COMPRESS", "compress", "" }, + { GSS_C_MA_CONF_PROT, "GSS_C_MA_CONF_PROT", "conf-prot", "" }, + { GSS_C_MA_CTX_TRANS, "GSS_C_MA_CTX_TRANS", "context-transfer", "" }, + { GSS_C_MA_DELEG_CRED, "GSS_C_MA_DELEG_CRED", "deleg-cred", "" }, + { GSS_C_MA_DEPRECATED, "GSS_C_MA_DEPRECATED", "mech-deprecated", "" }, + { GSS_C_MA_INTEG_PROT, "GSS_C_MA_INTEG_PROT", "integ-prot", "" }, + { GSS_C_MA_ITOK_FRAMED, "GSS_C_MA_ITOK_FRAMED", "initial-is-framed", "" }, + { GSS_C_MA_MECH_COMPOSITE, "GSS_C_MA_MECH_COMPOSITE", "composite-mech", "" }, + { GSS_C_MA_MECH_CONCRETE, "GSS_C_MA_MECH_CONCRETE", "concrete-mech", "Indicates that a mech is neither a pseudo-mechanism nor a composite mechanism" }, + { GSS_C_MA_MECH_DESCRIPTION, "GSS_C_MA_MECH_DESCRIPTION", "Mech description", "The long description of the mechanism" }, + { GSS_C_MA_MECH_GLUE, "GSS_C_MA_MECH_GLUE", "mech-glue", "" }, + { GSS_C_MA_MECH_NAME, "GSS_C_MA_MECH_NAME", "GSS mech name", "The name of the GSS-API mechanism" }, + { GSS_C_MA_MECH_NEGO, "GSS_C_MA_MECH_NEGO", "mech-negotiation-mech", "" }, + { GSS_C_MA_MECH_PSEUDO, "GSS_C_MA_MECH_PSEUDO", "pseudo-mech", "" }, + { GSS_C_MA_MIC, "GSS_C_MA_MIC", "mic", "" }, + { GSS_C_MA_NEGOEX_AND_SPNEGO, "GSS_C_MA_NEGOEX_AND_SPNEGO", "negoex-and-spnego", "Indicates that a mechanism supports both NegoEx and SPNEGO" }, + { GSS_C_MA_NOT_DFLT_MECH, "GSS_C_MA_NOT_DFLT_MECH", "mech-not-default", "" }, + { GSS_C_MA_NOT_MECH, "GSS_C_MA_NOT_MECH", "not-mech", "" }, + { GSS_C_MA_OOS_DET, "GSS_C_MA_OOS_DET", "oos-detection", "" }, + { GSS_C_MA_PFS, "GSS_C_MA_PFS", "pfs", "" }, + { GSS_C_MA_PROT_READY, "GSS_C_MA_PROT_READY", "prot-ready", "" }, + { GSS_C_MA_REPLAY_DET, "GSS_C_MA_REPLAY_DET", "replay-detection", "" }, + { GSS_C_MA_SASL_MECH_NAME, "GSS_C_MA_SASL_MECH_NAME", "SASL mechanism name", "The name of the SASL mechanism" }, + { GSS_C_MA_WRAP, "GSS_C_MA_WRAP", "wrap", "" }, + { NULL, NULL, NULL, NULL } +}; + +struct _gss_oid_name_table _gss_ont_mech[] = { + { GSS_KRB5_MECHANISM, "GSS_KRB5_MECHANISM", "Kerberos 5", "Heimdal Kerberos 5 mechanism" }, + { GSS_NTLM_MECHANISM, "GSS_NTLM_MECHANISM", "NTLM", "Heimdal NTLM mechanism" }, + { GSS_SANON_X25519_MECHANISM, "GSS_SANON_X25519_MECHANISM", "SAnon-X25519", "Heimdal Simple Anonymous (X25519) mechanism" }, + { GSS_SPNEGO_MECHANISM, "GSS_SPNEGO_MECHANISM", "SPNEGO", "Heimdal SPNEGO mechanism" }, + { NULL, NULL, NULL, NULL } +}; + +gss_OID _gss_ot_internal[] = { + &__gss_krb5_copy_ccache_x_oid_desc, + &__gss_krb5_get_tkt_flags_x_oid_desc, + &__gss_krb5_extract_authz_data_from_sec_context_x_oid_desc, + &__gss_krb5_compat_des3_mic_x_oid_desc, + &__gss_krb5_register_acceptor_identity_x_oid_desc, + &__gss_krb5_export_lucid_context_x_oid_desc, + &__gss_krb5_export_lucid_context_v1_x_oid_desc, + &__gss_krb5_set_dns_canonicalize_x_oid_desc, + &__gss_krb5_get_subkey_x_oid_desc, + &__gss_krb5_get_initiator_subkey_x_oid_desc, + &__gss_krb5_get_acceptor_subkey_x_oid_desc, + &__gss_krb5_send_to_kdc_x_oid_desc, + &__gss_krb5_get_authtime_x_oid_desc, + &__gss_krb5_get_service_keyblock_x_oid_desc, + &__gss_krb5_set_allowable_enctypes_x_oid_desc, + &__gss_krb5_set_default_realm_x_oid_desc, + &__gss_krb5_ccache_name_x_oid_desc, + &__gss_krb5_set_time_offset_x_oid_desc, + &__gss_krb5_get_time_offset_x_oid_desc, + &__gss_krb5_plugin_register_x_oid_desc, + &__gss_ntlm_get_session_key_x_oid_desc, + &__gss_c_nt_ntlm_oid_desc, + &__gss_c_nt_dn_oid_desc, + &__gss_krb5_nt_principal_name_referral_oid_desc, + &__gss_c_ntlm_avguest_oid_desc, + &__gss_c_ntlm_v1_oid_desc, + &__gss_c_ntlm_v2_oid_desc, + &__gss_c_ntlm_session_key_oid_desc, + &__gss_c_ntlm_force_v1_oid_desc, + &__gss_krb5_cred_no_ci_flags_x_oid_desc, + &__gss_krb5_import_cred_x_oid_desc, + &__gss_krb5_import_rfc4121_context_x_oid_desc, + &__gss_c_ma_sasl_mech_name_oid_desc, + &__gss_c_ma_mech_name_oid_desc, + &__gss_c_ma_mech_description_oid_desc, + &__gss_sasl_digest_md5_mechanism_oid_desc, + &__gss_netlogon_mechanism_oid_desc, + &__gss_netlogon_set_session_key_x_oid_desc, + &__gss_netlogon_set_sign_algorithm_x_oid_desc, + &__gss_netlogon_nt_netbios_dns_name_oid_desc, + &__gss_c_inq_win2k_pac_x_oid_desc, + &__gss_c_inq_sspi_session_key_oid_desc, + &__gss_c_inq_negoex_key_oid_desc, + &__gss_c_inq_negoex_verify_key_oid_desc, + &__gss_c_inq_require_mechlist_mic_oid_desc, + &__gss_krb5_mechanism_oid_desc, + &__gss_ntlm_mechanism_oid_desc, + &__gss_spnego_mechanism_oid_desc, + &__gss_c_inq_peer_has_buggy_spnego_oid_desc, + &__gss_c_ntlm_reset_crypto_oid_desc, + &__gss_negoex_mechanism_oid_desc, + &__gss_sanon_x25519_mechanism_oid_desc, + &__gss_c_ma_mech_concrete_oid_desc, + &__gss_c_ma_mech_pseudo_oid_desc, + &__gss_c_ma_mech_composite_oid_desc, + &__gss_c_ma_mech_nego_oid_desc, + &__gss_c_ma_mech_glue_oid_desc, + &__gss_c_ma_not_mech_oid_desc, + &__gss_c_ma_deprecated_oid_desc, + &__gss_c_ma_not_dflt_mech_oid_desc, + &__gss_c_ma_itok_framed_oid_desc, + &__gss_c_ma_auth_init_oid_desc, + &__gss_c_ma_auth_targ_oid_desc, + &__gss_c_ma_auth_init_init_oid_desc, + &__gss_c_ma_auth_targ_init_oid_desc, + &__gss_c_ma_auth_init_anon_oid_desc, + &__gss_c_ma_auth_targ_anon_oid_desc, + &__gss_c_ma_deleg_cred_oid_desc, + &__gss_c_ma_integ_prot_oid_desc, + &__gss_c_ma_conf_prot_oid_desc, + &__gss_c_ma_mic_oid_desc, + &__gss_c_ma_wrap_oid_desc, + &__gss_c_ma_prot_ready_oid_desc, + &__gss_c_ma_replay_det_oid_desc, + &__gss_c_ma_oos_det_oid_desc, + &__gss_c_ma_cbindings_oid_desc, + &__gss_c_ma_pfs_oid_desc, + &__gss_c_ma_compress_oid_desc, + &__gss_c_ma_ctx_trans_oid_desc, + &__gss_c_ma_negoex_and_spnego_oid_desc, +}; + +size_t _gss_ot_internal_count = sizeof(_gss_ot_internal) / sizeof(_gss_ot_internal[0]); diff --git a/third_party/heimdal/lib/gssapi/mech/gss_oid_equal.c b/third_party/heimdal/lib/gssapi/mech/gss_oid_equal.c new file mode 100644 index 0000000..b125ede --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_oid_equal.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +/** + * Compare two GSS-API OIDs with each other. + * + * GSS_C_NO_OID matches nothing, not even it-self. + * + * @param a first oid to compare + * @param b second oid to compare + * + * @return non-zero when both oid are the same OID, zero when they are + * not the same. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL +gss_oid_equal(gss_const_OID a, gss_const_OID b) +{ + if (a == b && a != GSS_C_NO_OID) + return 1; + if (a == GSS_C_NO_OID || b == GSS_C_NO_OID || a->length != b->length) + return 0; + return memcmp(a->elements, b->elements, a->length) == 0; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_oid_to_str.c b/third_party/heimdal/lib/gssapi/mech/gss_oid_to_str.c new file mode 100644 index 0000000..d8e188d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_oid_to_str.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) +{ + int ret; + size_t size; + heim_oid o; + char *p; + + _mg_buffer_zero(oid_str); + + if (oid == GSS_C_NULL_OID) + return GSS_S_FAILURE; + + ret = der_get_oid (oid->elements, oid->length, &o, &size); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = der_print_heim_oid(&o, ' ', &p); + der_free_oid(&o); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + oid_str->value = p; + oid_str->length = strlen(p); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c b/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c new file mode 100644 index 0000000..5046fae --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_pname_to_uid.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +static OM_uint32 +mech_localname(OM_uint32 *minor_status, + struct _gss_mechanism_name *mn, + gss_buffer_t localname) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + + *minor_status = 0; + + if (mn->gmn_mech->gm_localname == NULL) + return GSS_S_UNAVAILABLE; + + major_status = mn->gmn_mech->gm_localname(minor_status, + mn->gmn_name, + mn->gmn_mech_oid, + localname); + if (GSS_ERROR(major_status)) + _gss_mg_error(mn->gmn_mech, *minor_status); + + return major_status; +} + +static OM_uint32 +attr_localname(OM_uint32 *minor_status, + struct _gss_mechanism_name *mn, + gss_buffer_t localname) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + OM_uint32 tmpMinor; + gss_buffer_desc value = GSS_C_EMPTY_BUFFER; + gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; + int authenticated = 0, complete = 0; + int more = -1; + + *minor_status = 0; + + localname->length = 0; + localname->value = NULL; + + if (mn->gmn_mech->gm_get_name_attribute == NULL) + return GSS_S_UNAVAILABLE; + + major_status = mn->gmn_mech->gm_get_name_attribute(minor_status, + mn->gmn_name, + GSS_C_ATTR_LOCAL_LOGIN_USER, + &authenticated, + &complete, + &value, + &display_value, + &more); + if (GSS_ERROR(major_status)) { + _gss_mg_error(mn->gmn_mech, *minor_status); + return major_status; + } + + if (authenticated) { + *localname = value; + } else { + major_status = GSS_S_UNAVAILABLE; + gss_release_buffer(&tmpMinor, &value); + } + + gss_release_buffer(&tmpMinor, &display_value); + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_localname(OM_uint32 *minor_status, + gss_const_name_t pname, + const gss_OID mech_type, + gss_buffer_t localname) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) pname; + struct _gss_mechanism_name *mn = NULL; + + *minor_status = 0; + + if (mech_type != GSS_C_NO_OID) { + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (GSS_ERROR(major_status)) + return major_status; + + major_status = mech_localname(minor_status, mn, localname); + if (major_status != GSS_S_COMPLETE) + major_status = attr_localname(minor_status, mn, localname); + } else { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + major_status = mech_localname(minor_status, mn, localname); + if (major_status != GSS_S_COMPLETE) + major_status = attr_localname(minor_status, mn, localname); + if (major_status != GSS_S_UNAVAILABLE) + break; + } + } + + if (major_status != GSS_S_COMPLETE && mn != NULL) + _gss_mg_error(mn->gmn_mech, *minor_status); + + return major_status; +} + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_pname_to_uid(OM_uint32 *minor_status, + gss_const_name_t pname, + const gss_OID mech_type, + uid_t *uidp) +{ +#ifdef NO_LOCALNAME + return GSS_S_UNAVAILABLE; +#else + OM_uint32 major, tmpMinor; + gss_buffer_desc localname = GSS_C_EMPTY_BUFFER; + char *szLocalname; +#ifdef POSIX_GETPWNAM_R + char pwbuf[2048]; + struct passwd pw, *pwd; +#else + struct passwd *pwd; +#endif + + major = gss_localname(minor_status, pname, mech_type, &localname); + if (GSS_ERROR(major)) + return major; + if (localname.length == 0) { + *minor_status = KRB5_NO_LOCALNAME; + return GSS_S_FAILURE; + } + + szLocalname = malloc(localname.length + 1); + if (szLocalname == NULL) { + gss_release_buffer(&tmpMinor, &localname); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(szLocalname, localname.value, localname.length); + szLocalname[localname.length] = '\0'; + +#ifdef POSIX_GETPWNAM_R + if (getpwnam_r(szLocalname, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) + pwd = NULL; +#else + pwd = getpwnam(szLocalname); +#endif + + gss_release_buffer(&tmpMinor, &localname); + free(szLocalname); + + *minor_status = 0; + + if (pwd != NULL) { + *uidp = pwd->pw_uid; + major = GSS_S_COMPLETE; + } else { + major = GSS_S_UNAVAILABLE; + } + + return major; +#endif +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_process_context_token.c b/third_party/heimdal/lib/gssapi/mech/gss_process_context_token.c new file mode 100644 index 0000000..d10eb47 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_process_context_token.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_process_context_token.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_process_context_token(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m = ctx->gc_mech; + + return (m->gm_process_context_token(minor_status, ctx->gc_ctx, + token_buffer)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_pseudo_random.c b/third_party/heimdal/lib/gssapi/mech/gss_pseudo_random.c new file mode 100644 index 0000000..1b7eb7e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_pseudo_random.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + struct _gss_context *ctx = (struct _gss_context *) context; + gssapi_mech_interface m; + OM_uint32 major_status; + + _mg_buffer_zero(prf_out); + *minor_status = 0; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + if (m->gm_pseudo_random == NULL) + return GSS_S_UNAVAILABLE; + + major_status = (*m->gm_pseudo_random)(minor_status, ctx->gc_ctx, + prf_key, prf_in, desired_output_len, + prf_out); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_release_buffer.c b/third_party/heimdal/lib/gssapi/mech/gss_release_buffer.c new file mode 100644 index 0000000..c3dd457 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_release_buffer.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_release_buffer.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer) +{ + + *minor_status = 0; + if (buffer->value) + free(buffer->value); + _mg_buffer_zero(buffer); + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_release_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_release_cred.c new file mode 100644 index 0000000..3a85de5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_release_cred.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_release_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/** + * Release a credentials + * + * Its ok to release the GSS_C_NO_CREDENTIAL/NULL credential, it will + * return a GSS_S_COMPLETE error code. On return cred_handle is set ot + * GSS_C_NO_CREDENTIAL. + * + * Example: + * + * @code + * gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + * major = gss_release_cred(&minor, &cred); + * @endcode + * + * @param minor_status minor status return code, mech specific + * @param cred_handle a pointer to the credential too release + * + * @return an gssapi error code + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle) +{ + struct _gss_cred *cred = (struct _gss_cred *) *cred_handle; + + if (cred == NULL) + return (GSS_S_COMPLETE); + + _gss_mg_release_cred(cred); + + *minor_status = 0; + *cred_handle = GSS_C_NO_CREDENTIAL; + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_release_name.c b/third_party/heimdal/lib/gssapi/mech/gss_release_name.c new file mode 100644 index 0000000..db1793e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_release_name.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_release_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/** + * Free a name + * + * import_name can point to NULL or be NULL, or a pointer to a + * gss_name_t structure. If it was a pointer to gss_name_t, the + * pointer will be set to NULL on success and failure. + * + * @param minor_status minor status code + * @param input_name name to free + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_name(OM_uint32 *minor_status, + gss_name_t *input_name) +{ + struct _gss_name *name; + + *minor_status = 0; + + if (input_name == NULL || *input_name == NULL) + return GSS_S_COMPLETE; + + name = (struct _gss_name *) *input_name; + _gss_mg_release_name(name); + + *input_name = GSS_C_NO_NAME; + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_release_oid.c b/third_party/heimdal/lib/gssapi/mech/gss_release_oid.c new file mode 100644 index 0000000..4f674b0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_release_oid.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_oid(OM_uint32 *minor_status, gss_OID *oid) +{ + *oid = GSS_C_NO_OID; + + if (minor_status != NULL) + *minor_status = 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_release_oid_set.c b/third_party/heimdal/lib/gssapi/mech/gss_release_oid_set.c new file mode 100644 index 0000000..183ddf8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_release_oid_set.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_release_oid_set.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_release_oid_set(OM_uint32 *minor_status, + gss_OID_set *set) +{ + + *minor_status = 0; + if (set && *set) { + if ((*set)->elements) + free((*set)->elements); + free(*set); + *set = GSS_C_NO_OID_SET; + } + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_rfc4121.c b/third_party/heimdal/lib/gssapi/mech/gss_rfc4121.c new file mode 100644 index 0000000..97a0833 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_rfc4121.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mech_locl.h" + +/* + * An internal API (for now) to return a mechglue context handle given + * a session key that can provide RFC 4121 compatible message protection + * and PRF services. Used by SAnon. The implementation of those services + * is currently provided by the krb5 GSS mechanism but that is opaque to + * the caller (minor status codes notwithstanding). + */ +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle) +{ + OM_uint32 major = GSS_S_FAILURE, tmpMinor; + krb5_storage *sp; + krb5_error_code ret; + krb5_data d; + gss_buffer_desc rfc4121_args = GSS_C_EMPTY_BUFFER; + + krb5_data_zero(&d); + + *minor = 0; + *rfc4121_context_handle = GSS_C_NO_CONTEXT; + + sp = krb5_storage_emem(); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + /* + * The arguments GSS_KRB5_IMPORT_RFC4121_CONTEXT_X are the serialized + * form of initiator_flag || flags || keytype || session_key. The session + * key length is inferred from the keytype. + */ + ret = krb5_store_uint8(sp, initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_store_uint32(sp, gss_flags); + if (ret != 0) + goto out; + + ret = krb5_store_int32(sp, rfc3961_enctype); + if (ret != 0) + goto out; + + if (krb5_storage_write(sp, session_key->value, session_key->length) + != session_key->length) { + ret = ENOMEM; + goto out; + } + + ret = krb5_storage_to_data(sp, &d); + if (ret != 0) + goto out; + + rfc4121_args.length = d.length; + rfc4121_args.value = d.data; + + major = gss_set_sec_context_option(minor, rfc4121_context_handle, + GSS_KRB5_IMPORT_RFC4121_CONTEXT_X, + &rfc4121_args); + +out: + _gss_secure_release_buffer(&tmpMinor, &rfc4121_args); + krb5_storage_free(sp); + + if (major == GSS_S_FAILURE && *minor == 0) + *minor = ret; + + return major; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_seal.c b/third_party/heimdal/lib/gssapi/mech/gss_seal.c new file mode 100644 index 0000000..26c65da --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_seal.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_seal.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_seal(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + int qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + + return (gss_wrap(minor_status, + context_handle, conf_req_flag, qop_req, + input_message_buffer, conf_state, + output_message_buffer)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_set_cred_option.c b/third_party/heimdal/lib/gssapi/mech/gss_set_cred_option.c new file mode 100644 index 0000000..39b49e3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_set_cred_option.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_cred_option (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID object, + const gss_buffer_t value) +{ + struct _gss_cred *cred = (struct _gss_cred *) *cred_handle; + OM_uint32 major_status = GSS_S_COMPLETE; + struct _gss_mechanism_cred *mc; + int one_ok = 0; + + *minor_status = 0; + + _gss_load_mech(); + + if (cred == NULL) { + struct _gss_mech_switch *m; + + cred = _gss_mg_alloc_cred(); + if (cred == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + + if (m->gm_mech.gm_set_cred_option == NULL) + continue; + + mc = malloc(sizeof(*mc)); + if (mc == NULL) { + *cred_handle = (gss_cred_id_t)cred; + gss_release_cred(minor_status, cred_handle); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + mc->gmc_mech = &m->gm_mech; + mc->gmc_mech_oid = m->gm_mech_oid; + mc->gmc_cred = GSS_C_NO_CREDENTIAL; + + major_status = m->gm_mech.gm_set_cred_option( + minor_status, &mc->gmc_cred, object, value); + + if (major_status) { + free(mc); + continue; + } + one_ok = 1; + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); + } + *cred_handle = (gss_cred_id_t)cred; + if (!one_ok) { + OM_uint32 junk; + gss_release_cred(&junk, cred_handle); + } + } else { + gssapi_mech_interface m; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + m = mc->gmc_mech; + + if (m == NULL) + return GSS_S_BAD_MECH; + + if (m->gm_set_cred_option == NULL) + continue; + + major_status = m->gm_set_cred_option(minor_status, + &mc->gmc_cred, object, value); + if (major_status == GSS_S_COMPLETE) + one_ok = 1; + else + _gss_mg_error(m, *minor_status); + + } + } + if (one_ok) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + return major_status; +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_set_name_attribute.c b/third_party/heimdal/lib/gssapi/mech/gss_set_name_attribute.c new file mode 100644 index 0000000..4e963f3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_set_name_attribute.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_name_attribute(OM_uint32 *minor_status, + gss_name_t input_name, + int complete, + gss_buffer_t attr, + gss_buffer_t value) +{ + OM_uint32 major_status = GSS_S_UNAVAILABLE; + struct _gss_name *name = (struct _gss_name *) input_name; + struct _gss_mechanism_name *mn; + + *minor_status = 0; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { + gssapi_mech_interface m = mn->gmn_mech; + + if (!m->gm_set_name_attribute) + continue; + + major_status = m->gm_set_name_attribute(minor_status, + mn->gmn_name, + complete, + attr, + value); + if (GSS_ERROR(major_status)) + _gss_mg_error(m, *minor_status); + else + break; + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_set_neg_mechs.c b/third_party/heimdal/lib/gssapi/mech/gss_set_neg_mechs.c new file mode 100644 index 0000000..7c527b2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_set_neg_mechs.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_neg_mechs(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + const gss_OID_set mechs) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + OM_uint32 major_status, junk; + gss_OID_set tmp_mechs; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (cred_handle == GSS_C_NO_CREDENTIAL || mechs == GSS_C_NO_OID_SET) + return GSS_S_CALL_INACCESSIBLE_READ; + + major_status = gss_duplicate_oid_set(minor_status, mechs, &tmp_mechs); + if (major_status != GSS_S_COMPLETE) + return major_status; + + gss_release_oid_set(&junk, &cred->gc_neg_mechs); + cred->gc_neg_mechs = tmp_mechs; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_set_sec_context_option.c b/third_party/heimdal/lib/gssapi/mech/gss_set_sec_context_option.c new file mode 100644 index 0000000..5b92ac4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_set_sec_context_option.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004, 2020, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_sec_context_option (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID object, + const gss_buffer_t value) +{ + struct _gss_context *ctx; + OM_uint32 major_status; + gssapi_mech_interface mi; + int allocated_ctx; + + *minor_status = 0; + + if (context_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + _gss_load_mech(); + + ctx = (struct _gss_context *) *context_handle; + if (ctx == NULL) { + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + allocated_ctx = 1; + } else { + allocated_ctx = 0; + } + + major_status = GSS_S_BAD_MECH; + + if (allocated_ctx) { + struct _gss_mech_switch *m; + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + mi = &m->gm_mech; + + if (mi->gm_set_sec_context_option == NULL) + continue; + major_status = mi->gm_set_sec_context_option(minor_status, + &ctx->gc_ctx, object, value); + if (major_status == GSS_S_COMPLETE) { + ctx->gc_mech = mi; + break; + } else { + _gss_mg_error(mi, *minor_status); + } + } + } else { + mi = ctx->gc_mech; + if (mi->gm_set_sec_context_option != NULL) { + major_status = mi->gm_set_sec_context_option(minor_status, + &ctx->gc_ctx, object, value); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(mi, *minor_status); + } + } + + if (allocated_ctx) { + if (major_status == GSS_S_COMPLETE) + *context_handle = (gss_ctx_id_t)ctx; + else + free(ctx); + } + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_sign.c b/third_party/heimdal/lib/gssapi/mech/gss_sign.c new file mode 100644 index 0000000..4ef99c1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_sign.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_sign.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_sign(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int qop_req, + gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + + return gss_get_mic(minor_status, + context_handle, qop_req, message_buffer, message_token); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_store_cred.c b/third_party/heimdal/lib/gssapi/mech/gss_store_cred.c new file mode 100644 index 0000000..7a9344a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_store_cred.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +/* See RFC5588 */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + return gss_store_cred_into(minor_status, + input_cred_handle, + cred_usage, + desired_mech, + overwrite_cred, + default_cred, + GSS_C_NO_CRED_STORE, + elements_stored, + cred_usage_stored); +} + diff --git a/third_party/heimdal/lib/gssapi/mech/gss_store_cred_into.c b/third_party/heimdal/lib/gssapi/mech/gss_store_cred_into.c new file mode 100644 index 0000000..1c739b0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_store_cred_into.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +static OM_uint32 +store_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + gss_cred_usage_t input_usage, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_cred_usage_t *usage_stored, + gss_buffer_set_t *env) +{ + OM_uint32 major_status; + OM_uint32 overwrite_cred = + !!(store_cred_flags & GSS_C_STORE_CRED_OVERWRITE); + OM_uint32 default_cred = !!(store_cred_flags & GSS_C_STORE_CRED_DEFAULT); + + if (m->gm_store_cred_into2) + major_status = m->gm_store_cred_into2(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + store_cred_flags, cred_store, + NULL, usage_stored, + env); + else if (m->gm_store_cred_into) + major_status = m->gm_store_cred_into(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + overwrite_cred, default_cred, + cred_store, NULL, usage_stored); + else if (cred_store == GSS_C_NO_CRED_STORE && m->gm_store_cred) + major_status = m->gm_store_cred(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + overwrite_cred, default_cred, + NULL, usage_stored); + else + major_status = GSS_S_UNAVAILABLE; + + return major_status; +} + +/* + * See RFC5588 for gss_store_cred(). This function is a variant that takes a + * const key/value hashmap-like thing that specifies a credential store in a + * mechanism- and implementation-specific way, though Heimdal and MIT agree on + * at least the following keys for the Kerberos mechanism: ccache, keytab, and + * client_keytab. A set of environment variables may be output as well + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into2(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored, + gss_buffer_set_t *env) +{ + struct _gss_cred *cred = (struct _gss_cred *)input_cred_handle; + struct _gss_mechanism_cred *mc; + OM_uint32 major_status; + OM_uint32 minor; + size_t successes; + + if (env != NULL) + *env = NULL; + + if (input_cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + *minor_status = 0; + + if (cred_usage_stored) + *cred_usage_stored = 0; + + if (elements_stored) { + *elements_stored = GSS_C_NO_OID_SET; + + major_status = gss_create_empty_oid_set(minor_status, + elements_stored); + if (major_status != GSS_S_COMPLETE) + return major_status; + } + + major_status = GSS_S_NO_CRED; + successes = 0; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + gssapi_mech_interface m = mc->gmc_mech; + + if (m == NULL || (m->gm_flags & GM_USE_MG_CRED) != 0) + continue; + + if (desired_mech != GSS_C_NO_OID && + !gss_oid_equal(&m->gm_mech_oid, desired_mech)) + continue; + + major_status = store_mech_cred(minor_status, m, mc, input_usage, + store_cred_flags, cred_store, + cred_usage_stored, env); + if (major_status == GSS_S_COMPLETE) { + if (elements_stored && desired_mech != GSS_C_NO_OID) + gss_add_oid_set_member(&minor, desired_mech, elements_stored); + successes++; + } else if (desired_mech != GSS_C_NO_OID) { + _gss_mg_error(m, *minor_status); + gss_release_oid_set(&minor, elements_stored); + return major_status; + } + } + + if (successes > 0) { + *minor_status = 0; + major_status = GSS_S_COMPLETE; + } + + heim_assert(successes || major_status != GSS_S_COMPLETE, + "cred storage failed, but no error raised"); + + return major_status; +} + +/* + * See RFC5588 for gss_store_cred(). This function is a variant that takes a + * const key/value hashmap-like thing that specifies a credential store in a + * mechanism- and implementation-specific way, though Heimdal and MIT agree on + * at least the following keys for the Kerberos mechanism: ccache, keytab, and + * client_keytab. + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + OM_uint32 store_cred_flags = + (overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) | + (default_cred ? GSS_C_STORE_CRED_DEFAULT : 0); + return gss_store_cred_into2(minor_status, input_cred_handle, input_usage, + desired_mech, store_cred_flags, cred_store, + elements_stored, cred_usage_stored, NULL); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_test_oid_set_member.c b/third_party/heimdal/lib/gssapi/mech/gss_test_oid_set_member.c new file mode 100644 index 0000000..715d34b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_test_oid_set_member.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_test_oid_set_member.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_test_oid_set_member(OM_uint32 *minor_status, + const gss_OID member, + const gss_OID_set set, + int *present) +{ + size_t i; + + *present = 0; + for (i = 0; i < set->count; i++) + if (gss_oid_equal(member, &set->elements[i])) + *present = 1; + + *minor_status = 0; + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_unseal.c b/third_party/heimdal/lib/gssapi/mech/gss_unseal.c new file mode 100644 index 0000000..0add03d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_unseal.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_unseal.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unseal(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + int *qop_state) +{ + + return (gss_unwrap(minor_status, + context_handle, input_message_buffer, + output_message_buffer, conf_state, (gss_qop_t *)qop_state)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_unwrap.c b/third_party/heimdal/lib/gssapi/mech/gss_unwrap.c new file mode 100644 index 0000000..dd6363b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_unwrap.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_unwrap.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + m = ctx->gc_mech; + + return (m->gm_unwrap(minor_status, ctx->gc_ctx, + input_message_buffer, output_message_buffer, + conf_state, qop_state)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_utils.c b/third_party/heimdal/lib/gssapi/mech/gss_utils.c new file mode 100644 index 0000000..62fa262 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_utils.c @@ -0,0 +1,381 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_utils.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +static OM_uint32 +_gss_copy_oid(OM_uint32 *minor_status, + gss_const_OID from_oid, + gss_OID to_oid) +{ + size_t len = from_oid->length; + + *minor_status = 0; + to_oid->elements = malloc(len); + if (!to_oid->elements) { + to_oid->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + to_oid->length = (OM_uint32)len; + memcpy(to_oid->elements, from_oid->elements, len); + return (GSS_S_COMPLETE); +} + +OM_uint32 +_gss_free_oid(OM_uint32 *minor_status, gss_OID oid) +{ + *minor_status = 0; + if (oid->elements) { + free(oid->elements); + oid->elements = NULL; + oid->length = 0; + } + return (GSS_S_COMPLETE); +} + +struct _gss_interned_oid { + HEIM_SLIST_ATOMIC_ENTRY(_gss_interned_oid) gio_link; + gss_OID_desc gio_oid; +}; + +static HEIM_SLIST_ATOMIC_HEAD(_gss_interned_oid_list, _gss_interned_oid) interned_oids = +HEIM_SLIST_HEAD_INITIALIZER(interned_oids); + +extern gss_OID _gss_ot_internal[]; +extern size_t _gss_ot_internal_count; + +static OM_uint32 +intern_oid_static(OM_uint32 *minor_status, + gss_const_OID from_oid, + gss_OID *to_oid) +{ + size_t i; + + /* statically allocated OIDs */ + for (i = 0; i < _gss_ot_internal_count; i++) { + if (gss_oid_equal(_gss_ot_internal[i], from_oid)) { + *minor_status = 0; + *to_oid = _gss_ot_internal[i]; + return GSS_S_COMPLETE; + } + } + + return GSS_S_CONTINUE_NEEDED; +} + +OM_uint32 +_gss_intern_oid(OM_uint32 *minor_status, + gss_const_OID from_oid, + gss_OID *to_oid) +{ + OM_uint32 major_status; + struct _gss_interned_oid *iop; + + major_status = intern_oid_static(minor_status, from_oid, to_oid); + if (major_status != GSS_S_CONTINUE_NEEDED) + return major_status; + + HEIM_SLIST_ATOMIC_FOREACH(iop, &interned_oids, gio_link) { + if (gss_oid_equal(&iop->gio_oid, from_oid)) { + *minor_status = 0; + *to_oid = &iop->gio_oid; + return GSS_S_COMPLETE; + } + } + + iop = malloc(sizeof(*iop)); + if (iop == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = _gss_copy_oid(minor_status, from_oid, &iop->gio_oid); + if (GSS_ERROR(major_status)) { + free(iop); + return major_status; + } + + HEIM_SLIST_ATOMIC_INSERT_HEAD(&interned_oids, iop, gio_link); + + *minor_status = 0; + *to_oid = &iop->gio_oid; + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gss_copy_buffer(OM_uint32 *minor_status, + const gss_buffer_t from_buf, gss_buffer_t to_buf) +{ + size_t len = from_buf->length; + + *minor_status = 0; + to_buf->value = malloc(len); + if (!to_buf->value) { + *minor_status = ENOMEM; + to_buf->length = 0; + return GSS_S_FAILURE; + } + to_buf->length = len; + memcpy(to_buf->value, from_buf->value, len); + return (GSS_S_COMPLETE); +} + +OM_uint32 +_gss_secure_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer) +{ + if (buffer->value) + memset_s(buffer->value, buffer->length, 0, buffer->length); + + return gss_release_buffer(minor_status, buffer); +} + +OM_uint32 +_gss_secure_release_buffer_set(OM_uint32 *minor_status, + gss_buffer_set_t *buffer_set) +{ + size_t i; + OM_uint32 minor; + + *minor_status = 0; + + if (*buffer_set == GSS_C_NO_BUFFER_SET) + return GSS_S_COMPLETE; + + for (i = 0; i < (*buffer_set)->count; i++) + _gss_secure_release_buffer(&minor, &((*buffer_set)->elements[i])); + + (*buffer_set)->count = 0; + + return gss_release_buffer_set(minor_status, buffer_set); +} + +void +_gss_mg_encode_le_uint64(uint64_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; + p[4] = (n >> 32) & 0xFF; + p[5] = (n >> 40) & 0xFF; + p[6] = (n >> 48) & 0xFF; + p[7] = (n >> 56) & 0xFF; +} + +void +_gss_mg_decode_le_uint64(const void *ptr, uint64_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint64_t)p[0] << 0) + | ((uint64_t)p[1] << 8) + | ((uint64_t)p[2] << 16) + | ((uint64_t)p[3] << 24) + | ((uint64_t)p[4] << 32) + | ((uint64_t)p[5] << 40) + | ((uint64_t)p[6] << 48) + | ((uint64_t)p[7] << 56); +} + +void +_gss_mg_encode_be_uint64(uint64_t n, uint8_t *p) +{ + p[0] = (n >> 56) & 0xFF; + p[1] = (n >> 48) & 0xFF; + p[2] = (n >> 40) & 0xFF; + p[3] = (n >> 32) & 0xFF; + p[4] = (n >> 24) & 0xFF; + p[5] = (n >> 16) & 0xFF; + p[6] = (n >> 8 ) & 0xFF; + p[7] = (n >> 0 ) & 0xFF; +} + +void +_gss_mg_decode_be_uint64(const void *ptr, uint64_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint64_t)p[0] << 56) + | ((uint64_t)p[1] << 48) + | ((uint64_t)p[2] << 40) + | ((uint64_t)p[3] << 32) + | ((uint64_t)p[4] << 24) + | ((uint64_t)p[5] << 16) + | ((uint64_t)p[6] << 8) + | ((uint64_t)p[7] << 0); +} + +void +_gss_mg_encode_le_uint32(uint32_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; +} + +void +_gss_mg_decode_le_uint32(const void *ptr, uint32_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint32_t)p[0] << 0) + | ((uint32_t)p[1] << 8) + | ((uint32_t)p[2] << 16) + | ((uint32_t)p[3] << 24); +} + +void +_gss_mg_encode_be_uint32(uint32_t n, uint8_t *p) +{ + p[0] = (n >> 24) & 0xFF; + p[1] = (n >> 16) & 0xFF; + p[2] = (n >> 8 ) & 0xFF; + p[3] = (n >> 0 ) & 0xFF; +} + +void +_gss_mg_decode_be_uint32(const void *ptr, uint32_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); +} + +void +_gss_mg_encode_le_uint16(uint16_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; +} + +void +_gss_mg_decode_le_uint16(const void *ptr, uint16_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 0) | (p[1] << 8); +} + +void +_gss_mg_encode_be_uint16(uint16_t n, uint8_t *p) +{ + p[0] = (n >> 8) & 0xFF; + p[1] = (n >> 0) & 0xFF; +} + +void +_gss_mg_decode_be_uint16(const void *ptr, uint16_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 24) | (p[1] << 16); +} + +OM_uint32 +_gss_mg_ret_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_OID *oidp) +{ + krb5_data data; + gss_OID_desc oid; + OM_uint32 major; + + *minor = 0; + *oidp = GSS_C_NO_OID; + + *minor = krb5_ret_data(sp, &data); + if (*minor) + return GSS_S_FAILURE; + + if (data.length) { + oid.length = data.length; + oid.elements = data.data; + + major = _gss_intern_oid(minor, &oid, oidp); + } else + major = GSS_S_COMPLETE; + + krb5_data_free(&data); + + return major; +} + +OM_uint32 +_gss_mg_store_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_const_OID oid) +{ + krb5_data data; + + if (oid) { + data.length = oid->length; + data.data = oid->elements; + } else + krb5_data_zero(&data); + + *minor = krb5_store_data(sp, data); + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 +_gss_mg_ret_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_buffer_t buffer) +{ + krb5_data data; + + _mg_buffer_zero(buffer); + + *minor = krb5_ret_data(sp, &data); + if (*minor == 0) { + if (data.length) { + buffer->length = data.length; + buffer->value = data.data; + } else + krb5_data_free(&data); + } + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 +_gss_mg_store_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_const_buffer_t buffer) +{ + krb5_data data; + + if (buffer) { + data.length = buffer->length; + data.data = buffer->value; + } else + krb5_data_zero(&data); + + *minor = krb5_store_data(sp, data); + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_verify.c b/third_party/heimdal/lib/gssapi/mech/gss_verify.c new file mode 100644 index 0000000..dd53ddb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_verify.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_verify.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_verify(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t message_buffer, + gss_buffer_t token_buffer, + int *qop_state) +{ + + return (gss_verify_mic(minor_status, + context_handle, message_buffer, token_buffer, + (gss_qop_t *)qop_state)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_verify_mic.c b/third_party/heimdal/lib/gssapi/mech/gss_verify_mic.c new file mode 100644 index 0000000..ae3b52f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_verify_mic.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_verify_mic.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_verify_mic(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (qop_state) + *qop_state = 0; + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + return (m->gm_verify_mic(minor_status, ctx->gc_ctx, + message_buffer, token_buffer, qop_state)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_wrap.c b/third_party/heimdal/lib/gssapi/mech/gss_wrap.c new file mode 100644 index 0000000..82378d3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_wrap.c @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_wrap.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/** + * Wrap a message using either confidentiality (encryption + + * signature) or sealing (signature). + * + * @param minor_status minor status code. + * @param context_handle context handle. + * @param conf_req_flag if non zero, confidentiality is requestd. + * @param qop_req type of protection needed, in most cases it GSS_C_QOP_DEFAULT should be passed in. + * @param input_message_buffer messages to wrap + * @param conf_state returns non zero if confidentiality was honoured. + * @param output_message_buffer the resulting buffer, release with gss_release_buffer(). + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + if (conf_state) + *conf_state = 0; + _mg_buffer_zero(output_message_buffer); + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + return (m->gm_wrap(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, input_message_buffer, + conf_state, output_message_buffer)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c b/third_party/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c new file mode 100644 index 0000000..3bcd9ec --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gss_wrap_size_limit.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_wrap_size_limit.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_size_limit(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m; + + *max_input_size = 0; + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + + return (m->gm_wrap_size_limit(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, req_output_size, max_input_size)); +} diff --git a/third_party/heimdal/lib/gssapi/mech/gssapi.asn1 b/third_party/heimdal/lib/gssapi/mech/gssapi.asn1 new file mode 100644 index 0000000..96ca6bd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gssapi.asn1 @@ -0,0 +1,12 @@ +-- $Id$ + +GSS-API DEFINITIONS ::= BEGIN + +IMPORTS HEIM_ANY_SET FROM heim; + +GSSAPIContextToken ::= [APPLICATION 0] IMPLICIT SEQUENCE { + thisMech OBJECT IDENTIFIER, + innerContextToken HEIM_ANY_SET +} + +END diff --git a/third_party/heimdal/lib/gssapi/mech/gssspi_exchange_meta_data.c b/third_party/heimdal/lib/gssapi/mech/gssspi_exchange_meta_data.c new file mode 100644 index 0000000..fa98cbd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gssspi_exchange_meta_data.c @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2019 AuriStor, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_exchange_meta_data( + OM_uint32 *minor_status, + gss_const_OID input_mech_type, + gss_cred_id_t input_cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t target_name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + OM_uint32 major_status, junk; + gssapi_mech_interface m; + struct _gss_name *name = (struct _gss_name *) target_name; + struct _gss_mechanism_name *mn; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + gss_cred_id_t cred_handle; + int allocated_ctx; + gss_const_OID mech_type = input_mech_type; + + *minor_status = 0; + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + if (ctx == NULL) { + ctx = calloc(1, sizeof(struct _gss_context)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + m = ctx->gc_mech = __gss_get_mechanism(mech_type); + if (m == NULL) { + free(ctx); + return GSS_S_BAD_MECH; + } + allocated_ctx = 1; + } else { + m = ctx->gc_mech; + mech_type = &m->gm_mech_oid; + allocated_ctx = 0; + } + + if (m->gm_exchange_meta_data == NULL) { + major_status = GSS_S_BAD_MECH; + goto cleanup; + } + + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) + goto cleanup; + + if (m->gm_flags & GM_USE_MG_CRED) + cred_handle = input_cred_handle; + else + cred_handle = _gss_mg_find_mech_cred(input_cred_handle, mech_type); + + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + cred_handle == NULL) { + major_status = GSS_S_NO_CRED; + goto cleanup; + } + + /* note: mechanism is not obligated to allocate a context on success */ + major_status = m->gm_exchange_meta_data(minor_status, + mech_type, + cred_handle, + &ctx->gc_ctx, + mn ? mn->gmn_name : GSS_C_NO_NAME, + req_flags, + meta_data); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + +cleanup: + if (allocated_ctx && major_status != GSS_S_COMPLETE) + gss_delete_sec_context(&junk, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + + *context_handle = (gss_ctx_id_t) ctx; + + _gss_mg_log(10, "gss-emd: return %d/%d", (int)major_status, (int)*minor_status); + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gssspi_query_mechanism_info.c b/third_party/heimdal/lib/gssapi/mech/gssspi_query_mechanism_info.c new file mode 100644 index 0000000..82fe9d9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gssspi_query_mechanism_info.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2019 AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_mechanism_info( + OM_uint32 *minor_status, + gss_const_OID mech_type, + unsigned char auth_scheme[16]) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + + *minor_status = 0; + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + m = __gss_get_mechanism(mech_type); + if (m == NULL || m->gm_query_mechanism_info == NULL) + return GSS_S_BAD_MECH; + + major_status = m->gm_query_mechanism_info(minor_status, + mech_type, + auth_scheme); + + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/gssspi_query_meta_data.c b/third_party/heimdal/lib/gssapi/mech/gssspi_query_meta_data.c new file mode 100644 index 0000000..490bbc9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/gssspi_query_meta_data.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2019 AuriStor, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_meta_data( + OM_uint32 *minor_status, + gss_const_OID input_mech_type, + gss_cred_id_t input_cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t target_name, + OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + OM_uint32 major_status, junk; + gssapi_mech_interface m; + struct _gss_name *name = (struct _gss_name *) target_name; + struct _gss_mechanism_name *mn; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + gss_cred_id_t cred_handle; + int allocated_ctx; + gss_const_OID mech_type = input_mech_type; + + *minor_status = 0; + + _mg_buffer_zero(meta_data); + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + if (ctx == NULL) { + ctx = calloc(1, sizeof(struct _gss_context)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + m = ctx->gc_mech = __gss_get_mechanism(mech_type); + if (m == NULL) { + free(ctx); + return GSS_S_BAD_MECH; + } + allocated_ctx = 1; + } else { + m = ctx->gc_mech; + mech_type = &m->gm_mech_oid; + allocated_ctx = 0; + } + + if (m->gm_query_meta_data == NULL) { + major_status = GSS_S_BAD_MECH; + goto cleanup; + } + + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) + goto cleanup; + + if (m->gm_flags & GM_USE_MG_CRED) + cred_handle = input_cred_handle; + else + cred_handle = _gss_mg_find_mech_cred(input_cred_handle, mech_type); + + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + cred_handle == NULL) { + major_status = GSS_S_NO_CRED; + goto cleanup; + } + + /* note: mechanism is not obligated to allocate a context on success */ + major_status = m->gm_query_meta_data(minor_status, + mech_type, + cred_handle, + &ctx->gc_ctx, + mn ? mn->gmn_name : GSS_C_NO_NAME, + req_flags, + meta_data); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + +cleanup: + if (allocated_ctx && major_status != GSS_S_COMPLETE) + gss_delete_sec_context(&junk, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + + *context_handle = (gss_ctx_id_t) ctx; + + _gss_mg_log(10, "gss-qmd: return %d/%d", (int)major_status, (int)*minor_status); + + return major_status; +} diff --git a/third_party/heimdal/lib/gssapi/mech/mech.5 b/third_party/heimdal/lib/gssapi/mech/mech.5 new file mode 100644 index 0000000..56e916e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/mech.5 @@ -0,0 +1,94 @@ +.\" Copyright (c) 2005 Doug Rabson +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/lib/libgssapi/mech.5,v 1.1 2005/12/29 14:40:20 dfr Exp $ +.Dd November 14, 2005 +.Dt MECH 5 +.Os +.Sh NAME +.Nm mech , +.Nm qop +.Nd "GSS-API Mechanism and QOP files" +.Sh SYNOPSIS +.Pa "/etc/gss/mech" +.Pa "/etc/gss/qop" +.Sh DESCRIPTION +The +.Pa "/etc/gss/mech" +file contains a list of installed GSS-API security mechanisms. +Each line of the file either contains a comment if the first character +is '#' or it contains five fields with the following meanings: +.Bl -tag +.It Name +The name of this GSS-API mechanism. +.It Object identifier +The OID for this mechanism. +.It Library +A shared library containing the implementation of this mechanism. +.It Kernel module (optional) +A kernel module containing the implementation of this mechanism (not +yet supported in FreeBSD). +.It Library options (optional) +Optionsal parameters interpreted by the mechanism. Library options +must be enclosed in brackets ([ ]) to differentiate them from the +optional kernel module entry. +.El +.Pp +The +.Pa "/etc/gss/qop" +file contains a list of Quality of Protection values for use with +GSS-API. +Each line of the file either contains a comment if the first character +is '#' or it contains three fields with the following meanings: +.Bl -tag +.It QOP string +The name of this Quality of Protection algorithm. +.It QOP value +The numeric value used to select this algorithm for use with GSS-API +functions such as +.Xr gss_get_mic 3 . +.It Mechanism name +The GSS-API mechanism name that corresponds to this algorithm. +.El +.Sh EXAMPLES +This is a typical entry from +.Pa "/etc/gss/mech" : +.Bd -literal +kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.8 - +.Ed +.Pp +This is a typical entry from +.Pa "/etc/gss/qop" : +.Bd -literal +GSS_KRB5_CONF_C_QOP_DES 0x0100 kerberosv5 +.Ed +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 7.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq Mt dfr@FreeBSD.org . diff --git a/third_party/heimdal/lib/gssapi/mech/mech_locl.h b/third_party/heimdal/lib/gssapi/mech/mech_locl.h new file mode 100644 index 0000000..f0cfcb5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/mech_locl.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#include + +#include + +#include + +#include + +#include +#include "heimbase-atomics.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include "context.h" +#include "cred.h" +#include "mech_switch.h" +#include "name.h" +#include "utils.h" +#include "compat.h" + +#define _mg_buffer_zero(buffer) \ + do { \ + if (buffer) { \ + (buffer)->value = NULL; \ + (buffer)->length = 0; \ + } \ + } while(0) + +#define _mg_oid_set_zero(oid_set) \ + do { \ + if (oid_set) { \ + (oid_set)->elements = NULL; \ + (oid_set)->count = 0; \ + } \ + } while(0) diff --git a/third_party/heimdal/lib/gssapi/mech/mech_switch.h b/third_party/heimdal/lib/gssapi/mech/mech_switch.h new file mode 100644 index 0000000..abc89ae --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/mech_switch.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/mech_switch.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + * $Id$ + */ + +#include + +struct _gss_mech_switch { + HEIM_TAILQ_ENTRY(_gss_mech_switch) gm_link; + gss_OID gm_mech_oid; + gss_OID_set gm_name_types; + void *gm_so; + gssapi_mech_interface_desc gm_mech; +}; +HEIM_TAILQ_HEAD(_gss_mech_switch_list, _gss_mech_switch); +extern struct _gss_mech_switch_list _gss_mechs; +extern gss_OID_set _gss_mech_oids; + +void _gss_load_mech(void); diff --git a/third_party/heimdal/lib/gssapi/mech/name.h b/third_party/heimdal/lib/gssapi/mech/name.h new file mode 100644 index 0000000..4a03486 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/name.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/name.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + * $Id$ + */ + +struct _gss_mechanism_name { + HEIM_TAILQ_ENTRY(_gss_mechanism_name) gmn_link; + gssapi_mech_interface gmn_mech; /* mechanism ops for MN */ + gss_OID gmn_mech_oid; /* mechanism oid for MN */ + gss_name_t gmn_name; /* underlying MN */ +}; +HEIM_TAILQ_HEAD(_gss_mechanism_name_list, _gss_mechanism_name); + +struct _gss_name { + gss_OID gn_type; /* type of name */ + gss_buffer_desc gn_value; /* value (as imported) */ + struct _gss_mechanism_name_list gn_mn; /* list of MNs */ +}; + +OM_uint32 + _gss_find_mn(OM_uint32 *, struct _gss_name *, gss_const_OID, + struct _gss_mechanism_name **); +struct _gss_name * + _gss_create_name(gss_name_t new_mn, gssapi_mech_interface m); +void _gss_mg_release_name(struct _gss_name *); + + +void _gss_mg_check_name(gss_const_name_t name); + +gss_name_t + _gss_mg_get_underlying_mech_name(gss_name_t name, gss_const_OID mech); + +OM_uint32 +_gss_mech_import_name(OM_uint32 * minor_status, + gss_const_OID mech, + struct _gss_name_type *names, + const gss_buffer_t input_name_buffer, + gss_const_OID input_name_type, + gss_name_t *output_name); + +OM_uint32 +gss_mg_export_name(OM_uint32 *minor_status, + const gss_const_OID mech, + const void *name, + size_t length, + gss_buffer_t exported_name); + +OM_uint32 +_gss_mech_inquire_names_for_mech(OM_uint32 * minor_status, + struct _gss_name_type *names, + gss_OID_set *name_types); + + diff --git a/third_party/heimdal/lib/gssapi/mech/utils.h b/third_party/heimdal/lib/gssapi/mech/utils.h new file mode 100644 index 0000000..717ca49 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/mech/utils.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/utils.h,v 1.1 2005/12/29 14:40:20 dfr Exp $ + * $Id$ + */ + +OM_uint32 _gss_free_oid(OM_uint32 *, gss_OID); +OM_uint32 _gss_intern_oid(OM_uint32 *, gss_const_OID, gss_OID *); +OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, + const gss_buffer_t from_buf, gss_buffer_t to_buf); +OM_uint32 _gss_secure_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer); +OM_uint32 _gss_secure_release_buffer_set(OM_uint32 *minor_status, + gss_buffer_set_t *buffer_set); + +void _gss_mg_encode_le_uint64(uint64_t n, uint8_t *p); +void _gss_mg_decode_le_uint64(const void *ptr, uint64_t *n); +void _gss_mg_encode_be_uint64(uint64_t n, uint8_t *p); +void _gss_mg_decode_be_uint64(const void *ptr, uint64_t *n); + +void _gss_mg_encode_le_uint32(uint32_t n, uint8_t *p); +void _gss_mg_decode_le_uint32(const void *ptr, uint32_t *n); +void _gss_mg_encode_be_uint32(uint32_t n, uint8_t *p); +void _gss_mg_decode_be_uint32(const void *ptr, uint32_t *n); + +void _gss_mg_encode_le_uint16(uint16_t n, uint8_t *p); +void _gss_mg_decode_le_uint16(const void *ptr, uint16_t *n); +void _gss_mg_encode_be_uint16(uint16_t n, uint8_t *p); +void _gss_mg_decode_be_uint16(const void *ptr, uint16_t *n); + +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle); + +#include + +/* + * Note: functions below support zero-length OIDs and buffers and will + * return NULL values. Callers should handle accordingly. + */ + +OM_uint32 +_gss_mg_ret_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_OID *oidp); + +OM_uint32 +_gss_mg_store_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_const_OID oid); + +OM_uint32 +_gss_mg_ret_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_buffer_t buffer); + +OM_uint32 +_gss_mg_store_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_const_buffer_t buffer); diff --git a/third_party/heimdal/lib/gssapi/netlogon/accept_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/accept_sec_context.c new file mode 100644 index 0000000..06ddfd5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/accept_sec_context.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +/* + * Not implemented: this is needed only by domain controllers. + */ + +OM_uint32 +_netlogon_accept_sec_context +(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle + ) +{ + + output_token->value = NULL; + output_token->length = 0; + + *minor_status = 0; + + if (context_handle == NULL) + return GSS_S_FAILURE; + + if (input_token_buffer == GSS_C_NO_BUFFER) + return GSS_S_FAILURE; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + if (delegated_cred_handle) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + if (*context_handle == GSS_C_NO_CONTEXT) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } else { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/acquire_cred.c b/third_party/heimdal/lib/gssapi/netlogon/acquire_cred.c new file mode 100644 index 0000000..d790d08 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/acquire_cred.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" +#include + +OM_uint32 +_netlogon_acquire_cred(OM_uint32 * min_stat, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t * output_cred_handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec) +{ + OM_uint32 ret; + gssnetlogon_cred cred; + + /* only initiator support so far */ + if (cred_usage != GSS_C_INITIATE) + return GSS_S_FAILURE; + + if (desired_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + cred = (gssnetlogon_cred)calloc(1, sizeof(*cred)); + if (cred == NULL) { + *min_stat = ENOMEM; + return GSS_S_FAILURE; + } + cred->SignatureAlgorithm = NL_SIGN_ALG_HMAC_MD5; + cred->SealAlgorithm = NL_SEAL_ALG_RC4; + + ret = _netlogon_duplicate_name(min_stat, desired_name, + (gss_name_t *)&cred->Name); + if (GSS_ERROR(ret)) { + free(cred); + return ret; + } + + *output_cred_handle = (gss_cred_id_t)cred; + if (actual_mechs != NULL) + *actual_mechs = GSS_C_NO_OID_SET; + if (time_rec != NULL) + *time_rec = GSS_C_INDEFINITE; + + return GSS_S_COMPLETE; +} + +OM_uint32 +_netlogon_acquire_cred_ex(gss_status_id_t status, + gss_const_name_t desired_name, + OM_uint32 flags, + OM_uint32 time_req, + gss_cred_usage_t cred_usage, + gss_auth_identity_t identity, + void *ctx, + void (*complete)(void *, OM_uint32, gss_status_id_t, gss_cred_id_t, OM_uint32)) +{ + return GSS_S_UNAVAILABLE; +} + +/* + * value contains 16 byte session key + */ +static OM_uint32 +_netlogon_set_session_key(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + gssnetlogon_cred cred; + + if (*cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + cred = (gssnetlogon_cred)*cred_handle; + + if (value->length != sizeof(cred->SessionKey)) { + *minor_status = ERANGE; + return GSS_S_FAILURE; + } + + memcpy(cred->SessionKey, value->value, value->length); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * value contains 16 bit little endian encoded seal algorithm + */ +static OM_uint32 +_netlogon_set_sign_algorithm(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + gssnetlogon_cred cred; + uint16_t alg; + const uint8_t *p; + + if (*cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + cred = (gssnetlogon_cred)*cred_handle; + + if (value->length != 2) { + *minor_status = ERANGE; + return GSS_S_FAILURE; + } + + p = (const uint8_t *)value->value; + alg = (p[0] << 0) | (p[1] << 8); + + if (alg != NL_SIGN_ALG_HMAC_MD5 && alg != NL_SIGN_ALG_SHA256) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + cred->SignatureAlgorithm = alg; + if (alg == NL_SIGN_ALG_SHA256) + cred->SealAlgorithm = NL_SEAL_ALG_AES128; + else + cred->SealAlgorithm = NL_SEAL_ALG_RC4; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_netlogon_set_cred_option + (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + if (value == GSS_C_NO_BUFFER) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (gss_oid_equal(desired_object, GSS_NETLOGON_SET_SESSION_KEY_X)) + return _netlogon_set_session_key(minor_status, cred_handle, value); + else if (gss_oid_equal(desired_object, GSS_NETLOGON_SET_SIGN_ALGORITHM_X)) + return _netlogon_set_sign_algorithm(minor_status, cred_handle, value); + + *minor_status = EINVAL; + return GSS_S_FAILURE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/add_cred.c b/third_party/heimdal/lib/gssapi/netlogon/add_cred.c new file mode 100644 index 0000000..0222303 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/add_cred.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_add_cred ( + OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 ret; + int equal; + const gssnetlogon_cred src = (const gssnetlogon_cred)input_cred_handle; + gssnetlogon_cred dst; + + if (desired_name != GSS_C_NO_NAME) { + if (input_cred_handle != GSS_C_NO_CREDENTIAL) { + ret = _netlogon_compare_name(minor_status, desired_name, + (gss_name_t)src->Name, &equal); + if (GSS_ERROR(ret)) + return ret; + + if (!equal) + return GSS_S_BAD_NAME; + } + } + + ret = _netlogon_acquire_cred(minor_status, + input_cred_handle ? (gss_name_t)src->Name : desired_name, + initiator_time_req, GSS_C_NO_OID_SET, cred_usage, + output_cred_handle, actual_mechs, initiator_time_rec); + if (GSS_ERROR(ret)) + return ret; + + dst = (gssnetlogon_cred)*output_cred_handle; + + if (src != NULL) { + dst->SignatureAlgorithm = src->SignatureAlgorithm; + dst->SealAlgorithm = src->SealAlgorithm; + + memcpy(dst->SessionKey, src->SessionKey, sizeof(src->SessionKey)); + } + + if (acceptor_time_rec != NULL) + *acceptor_time_rec = 0; + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/canonicalize_name.c b/third_party/heimdal/lib/gssapi/netlogon/canonicalize_name.c new file mode 100644 index 0000000..1e8087a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/canonicalize_name.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_canonicalize_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t * output_name + ) +{ + return _netlogon_duplicate_name(minor_status, input_name, output_name); +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/compare_name.c b/third_party/heimdal/lib/gssapi/netlogon/compare_name.c new file mode 100644 index 0000000..986c3b0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/compare_name.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_compare_name + (OM_uint32 * minor_status, + gss_const_name_t name1, + gss_const_name_t name2, + int * name_equal + ) +{ + const gssnetlogon_name n1 = (const gssnetlogon_name)name1; + const gssnetlogon_name n2 = (const gssnetlogon_name)name2; + + *name_equal = 0; + + if (n1->NetbiosName.value != NULL && n2->NetbiosName.value != NULL) + *name_equal = (strcasecmp((char *)n1->NetbiosName.value, + (char *)n2->NetbiosName.value) == 0); + + if (n1->DnsName.value != NULL && n2->DnsName.value != NULL) + *name_equal = (strcasecmp((char *)n1->DnsName.value, + (char *)n2->DnsName.value) == 0); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/context_time.c b/third_party/heimdal/lib/gssapi/netlogon/context_time.c new file mode 100644 index 0000000..c7bf9eb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/context_time.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_context_time + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 * time_rec + ) +{ + if (time_rec != NULL) + *time_rec = GSS_C_INDEFINITE; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/crypto.c b/third_party/heimdal/lib/gssapi/netlogon/crypto.c new file mode 100644 index 0000000..6147eec --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/crypto.c @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +static uint8_t zeros[4]; + +static void +_netlogon_encode_sequence_number(uint64_t SequenceNumber, uint8_t *p, + int initiatorFlag) +{ + uint32_t LowPart, HighPart; + + LowPart = (SequenceNumber >> 0 ) & 0xFFFFFFFF; + HighPart = (SequenceNumber >> 32) & 0xFFFFFFFF; + + _gss_mg_encode_be_uint32(LowPart, &p[0]); + _gss_mg_encode_be_uint32(HighPart, &p[4]); + + if (initiatorFlag) + p[4] |= 0x80; +} + +static int +_netlogon_decode_sequence_number(void *ptr, uint64_t *n, + int initiatorFlag) +{ + uint8_t *p = ptr; + uint32_t LowPart, HighPart; + int gotInitiatorFlag; + + gotInitiatorFlag = (p[4] & 0x80) != 0; + if (gotInitiatorFlag != initiatorFlag) + return -1; + + p[4] &= 0x7F; /* clear initiator bit */ + + _gss_mg_decode_be_uint32(&p[0], &LowPart); + _gss_mg_decode_be_uint32(&p[4], &HighPart); + + *n = (LowPart << 0) | ((uint64_t)HighPart << 32); + + return 0; +} + +static inline size_t +_netlogon_checksum_length(NL_AUTH_SIGNATURE *sig) +{ +#if 0 + return (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256) ? 32 : 8; +#else + /* Owing to a bug in Windows it always uses the old value */ + return 8; +#endif +} + +static inline size_t +_netlogon_signature_length(uint16_t alg, int conf_req_flag) +{ + return NL_AUTH_SIGNATURE_COMMON_LENGTH + + (alg == NL_SIGN_ALG_SHA256 ? 32 : 8) + + (conf_req_flag ? 8 : 0); +} + +static inline uint8_t * +_netlogon_confounder(NL_AUTH_SIGNATURE *sig) +{ + size_t cksumlen = _netlogon_checksum_length(sig); + + return &sig->Checksum[cksumlen]; +} + +static int +_netlogon_encode_NL_AUTH_SIGNATURE(NL_AUTH_SIGNATURE *sig, + uint8_t *p, size_t len) +{ + *p++ = (sig->SignatureAlgorithm >> 0) & 0xFF; + *p++ = (sig->SignatureAlgorithm >> 8) & 0xFF; + *p++ = (sig->SealAlgorithm >> 0) & 0xFF; + *p++ = (sig->SealAlgorithm >> 8) & 0xFF; + *p++ = (sig->Pad >> 0) & 0xFF; + *p++ = (sig->Pad >> 8) & 0xFF; + *p++ = (sig->Flags >> 0) & 0xFF; + *p++ = (sig->Flags >> 8) & 0xFF; + + if (len > NL_AUTH_SIGNATURE_HEADER_LENGTH) { + memcpy(p, sig->SequenceNumber, 8); + p += 8; + } + + if (len > NL_AUTH_SIGNATURE_COMMON_LENGTH) { + size_t cksumlen = _netlogon_checksum_length(sig); + + memcpy(p, sig->Checksum, cksumlen); + p += cksumlen; + + /* Confounder, if present, is immediately after checksum */ + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) { + memcpy(p, &sig->Checksum[cksumlen], 8); + } + } + + return 0; +} + +static int +_netlogon_decode_NL_AUTH_SIGNATURE(const uint8_t *ptr, + size_t len, + NL_AUTH_SIGNATURE *sig) +{ + const uint8_t *p = ptr; + size_t cksumlen; + + if (len < NL_AUTH_SIGNATURE_COMMON_LENGTH) + return KRB5_BAD_MSIZE; + + sig->SignatureAlgorithm = (p[0] << 0) | (p[1] << 8); + sig->SealAlgorithm = (p[2] << 0) | (p[3] << 8); + sig->Pad = (p[4] << 0) | (p[5] << 8); + sig->Flags = (p[6] << 0) | (p[7] << 8); + p += 8; + + memcpy(sig->SequenceNumber, p, 8); + p += 8; + + /* Validate signature algorithm is known and matches enctype */ + switch (sig->SignatureAlgorithm) { + case NL_SIGN_ALG_HMAC_MD5: + cksumlen = NL_AUTH_SIGNATURE_LENGTH; + break; + case NL_SIGN_ALG_SHA256: + cksumlen = NL_AUTH_SHA2_SIGNATURE_LENGTH; + break; + default: + return EINVAL; + break; + } + + if (sig->SealAlgorithm == NL_SEAL_ALG_NONE) + cksumlen -= 8; /* confounder is optional if no sealing */ + + if (len < cksumlen) + return KRB5_BAD_MSIZE; + + /* Copy variable length checksum */ + cksumlen = _netlogon_checksum_length(sig); + memcpy(sig->Checksum, p, cksumlen); + p += cksumlen; + + /* Copy confounder in past checksum */ + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) + memcpy(&sig->Checksum[cksumlen], p, 8); + + return 0; +} + +static void +_netlogon_derive_rc4_hmac_key(uint8_t key[16], + uint8_t *salt, + size_t saltLength, + EVP_CIPHER_CTX *rc4Key, + int enc) +{ + uint8_t tmpData[MD5_DIGEST_LENGTH]; + uint8_t derivedKey[MD5_DIGEST_LENGTH]; + unsigned int len = MD5_DIGEST_LENGTH; + + HMAC(EVP_md5(), key, 16, zeros, sizeof(zeros), tmpData, &len); + HMAC(EVP_md5(), tmpData, MD5_DIGEST_LENGTH, + salt, saltLength, derivedKey, &len); + + assert(len == MD5_DIGEST_LENGTH); + + EVP_CipherInit_ex(rc4Key, EVP_rc4(), NULL, derivedKey, NULL, enc); + + memset(derivedKey, 0, sizeof(derivedKey)); +} + +static void +_netlogon_derive_rc4_seal_key(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + EVP_CIPHER_CTX *sealkey, + int enc) +{ + uint8_t xorKey[16]; + int i; + + for (i = 0; i < sizeof(xorKey); i++) { + xorKey[i] = ctx->SessionKey[i] ^ 0xF0; + } + + _netlogon_derive_rc4_hmac_key(xorKey, + sig->SequenceNumber, sizeof(sig->SequenceNumber), sealkey, enc); + + memset(xorKey, 0, sizeof(xorKey)); +} + +static void +_netlogon_derive_rc4_seq_key(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + EVP_CIPHER_CTX *seqkey, + int enc) +{ + _netlogon_derive_rc4_hmac_key(ctx->SessionKey, + sig->Checksum, sizeof(sig->Checksum), seqkey, enc); +} + +static void +_netlogon_derive_aes_seal_key(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + EVP_CIPHER_CTX *sealkey, + int enc) +{ + uint8_t encryptionKey[16]; + uint8_t ivec[16]; + int i; + + for (i = 0; i < sizeof(encryptionKey); i++) { + encryptionKey[i] = ctx->SessionKey[i] ^ 0xF0; + } + + memcpy(&ivec[0], sig->SequenceNumber, 8); + memcpy(&ivec[8], sig->SequenceNumber, 8); + + EVP_CipherInit_ex(sealkey, EVP_aes_128_cfb8(), + NULL, encryptionKey, ivec, enc); + + memset(encryptionKey, 0, sizeof(encryptionKey)); +} + +static void +_netlogon_derive_aes_seq_key(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + EVP_CIPHER_CTX *seqkey, + int enc) +{ + uint8_t ivec[16]; + + memcpy(&ivec[0], sig->Checksum, 8); + memcpy(&ivec[8], sig->Checksum, 8); + + EVP_CipherInit_ex(seqkey, EVP_aes_128_cfb8(), + NULL, ctx->SessionKey, ivec, enc); +} + +static void +_netlogon_seal(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + gss_iov_buffer_desc *iov, + int iov_count, + int enc) +{ + EVP_CIPHER_CTX sealkey; + int i; + uint8_t *confounder = _netlogon_confounder(sig); + + EVP_CIPHER_CTX_init(&sealkey); + + if (sig->SealAlgorithm == NL_SEAL_ALG_AES128) + _netlogon_derive_aes_seal_key(ctx, sig, &sealkey, enc); + else + _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc); + + EVP_Cipher(&sealkey, confounder, confounder, 8); + + /* + * For RC4, Windows resets the cipherstate after encrypting + * the confounder, thus defeating the purpose of the confounder + */ + if (sig->SealAlgorithm == NL_SEAL_ALG_RC4) { + EVP_CipherFinal_ex(&sealkey, NULL, &i); + _netlogon_derive_rc4_seal_key(ctx, sig, &sealkey, enc); + } + + for (i = 0; i < iov_count; i++) { + gss_iov_buffer_t iovp = &iov[i]; + + switch (GSS_IOV_BUFFER_TYPE(iovp->type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + EVP_Cipher(&sealkey, iovp->buffer.value, iovp->buffer.value, + iovp->buffer.length); + break; + default: + break; + } + } + + EVP_CipherFinal_ex(&sealkey, NULL, &i); + EVP_CIPHER_CTX_cleanup(&sealkey); +} + +static void +_netlogon_seq(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + int enc) +{ + EVP_CIPHER_CTX seqkey; + + EVP_CIPHER_CTX_init(&seqkey); + + if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256) + _netlogon_derive_aes_seq_key(ctx, sig, &seqkey, enc); + else + _netlogon_derive_rc4_seq_key(ctx, sig, &seqkey, enc); + + EVP_Cipher(&seqkey, sig->SequenceNumber, sig->SequenceNumber, 8); + + EVP_CIPHER_CTX_cleanup(&seqkey); +} + +static void +_netlogon_digest_md5(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + gss_iov_buffer_desc *iov, + int iov_count, + uint8_t *md) +{ + EVP_MD_CTX *md5; + uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH]; + uint8_t digest[MD5_DIGEST_LENGTH]; + unsigned int md_len = MD5_DIGEST_LENGTH; + int i; + + _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header)); + + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, zeros, sizeof(zeros)); + EVP_DigestUpdate(md5, header, sizeof(header)); + + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) { + EVP_DigestUpdate(md5, sig->Confounder, sizeof(sig->Confounder)); + } + + for (i = 0; i < iov_count; i++) { + gss_iov_buffer_t iovp = &iov[i]; + + switch (GSS_IOV_BUFFER_TYPE(iovp->type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + EVP_DigestUpdate(md5, iovp->buffer.value, iovp->buffer.length); + break; + default: + break; + } + } + + EVP_DigestFinal_ex(md5, digest, NULL); + EVP_MD_CTX_destroy(md5); + + HMAC(EVP_md5(), ctx->SessionKey, sizeof(ctx->SessionKey), + digest, sizeof(digest), digest, &md_len); + memcpy(md, digest, 8); +} + +static void +_netlogon_digest_sha256(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + gss_iov_buffer_desc *iov, + int iov_count, + uint8_t *md) +{ + HMAC_CTX hmac; + uint8_t header[NL_AUTH_SIGNATURE_HEADER_LENGTH]; + uint8_t digest[SHA256_DIGEST_LENGTH]; + unsigned int md_len = SHA256_DIGEST_LENGTH; + int i; + + /* Encode first 8 bytes of signature into header */ + _netlogon_encode_NL_AUTH_SIGNATURE(sig, header, sizeof(header)); + + HMAC_CTX_init(&hmac); + HMAC_Init_ex(&hmac, ctx->SessionKey, sizeof(ctx->SessionKey), + EVP_sha256(), NULL); + HMAC_Update(&hmac, header, sizeof(header)); + + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) { + /* + * If the checksum length bug is ever fixed, then be sure to + * update this code to point to &sig->Checksum[32] as that is + * where the confounder is supposed to be. + */ + HMAC_Update(&hmac, sig->Confounder, 8); + } + + for (i = 0; i < iov_count; i++) { + gss_iov_buffer_t iovp = &iov[i]; + + switch (GSS_IOV_BUFFER_TYPE(iovp->type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + HMAC_Update(&hmac, iovp->buffer.value, iovp->buffer.length); + break; + default: + break; + } + } + + HMAC_Final(&hmac, digest, &md_len); + HMAC_CTX_cleanup(&hmac); + memcpy(md, digest, 8); +} + +static void +_netlogon_digest(gssnetlogon_ctx ctx, + NL_AUTH_SIGNATURE *sig, + gss_iov_buffer_desc *iov, + int iov_count, + uint8_t *md) +{ + if (sig->SignatureAlgorithm == NL_SIGN_ALG_SHA256) + _netlogon_digest_sha256(ctx, sig, iov, iov_count, md); + else + _netlogon_digest_md5(ctx, sig, iov, iov_count, md); +} + +OM_uint32 +_netlogon_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + gss_iov_buffer_t header; + NL_AUTH_SIGNATURE_U sigbuf = { { 0 } }; + NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf); + gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle; + size_t size; + uint8_t *seqdata; + + if (ctx->State != NL_AUTH_ESTABLISHED) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + size = _netlogon_signature_length(ctx->SignatureAlgorithm, conf_req_flag); + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + ret = _gss_mg_allocate_buffer(minor_status, header, size); + if (GSS_ERROR(ret)) + return ret; + } else if (header->buffer.length < size) { + *minor_status = KRB5_BAD_MSIZE; + return GSS_S_FAILURE; + } else { + header->buffer.length = size; + } + + memset(header->buffer.value, 0, header->buffer.length); + + sig->SignatureAlgorithm = ctx->SignatureAlgorithm; + sig->SealAlgorithm = conf_req_flag ? ctx->SealAlgorithm : NL_SEAL_ALG_NONE; + + if (conf_req_flag) + krb5_generate_random_block(_netlogon_confounder(sig), 8); + + sig->Pad = 0xFFFF; /* [MS-NRPC] 3.3.4.2.1.3 */ + sig->Flags = 0; /* [MS-NRPC] 3.3.4.2.1.4 */ + HEIMDAL_MUTEX_lock(&ctx->Mutex); + _netlogon_encode_sequence_number(ctx->SequenceNumber, sig->SequenceNumber, + ctx->LocallyInitiated); + ctx->SequenceNumber++; + HEIMDAL_MUTEX_unlock(&ctx->Mutex); + + /* [MS-NRPC] 3.3.4.2.1.7: sign header, optional confounder and data */ + _netlogon_digest(ctx, sig, iov, iov_count, sig->Checksum); + + /* [MS-NRPC] 3.3.4.2.1.8: optionally encrypt confounder and data */ + if (conf_req_flag) + _netlogon_seal(ctx, sig, iov, iov_count, 1); + + /* [MS-NRPC] 3.3.4.2.1.9: encrypt sequence number */ + _netlogon_seq(ctx, sig, 1); + + _netlogon_encode_NL_AUTH_SIGNATURE(sig, header->buffer.value, + header->buffer.length); + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_netlogon_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + gss_iov_buffer_t header; + NL_AUTH_SIGNATURE_U sigbuf; + NL_AUTH_SIGNATURE *sig = NL_AUTH_SIGNATURE_P(&sigbuf); + gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle; + uint8_t checksum[SHA256_DIGEST_LENGTH]; + uint64_t SequenceNumber; + + if (ctx->State != NL_AUTH_ESTABLISHED) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + header = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = _netlogon_decode_NL_AUTH_SIGNATURE(header->buffer.value, + header->buffer.length, + sig); + if (ret != 0) { + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* [MS-NRPC] 3.3.4.2.2.1: verify signature algorithm selection */ + if (sig->SignatureAlgorithm != ctx->SignatureAlgorithm) + return GSS_S_BAD_SIG; + + /* [MS-NRPC] 3.3.4.2.2.2: verify encryption algorithm selection */ + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE && + sig->SealAlgorithm != ctx->SealAlgorithm) + return GSS_S_DEFECTIVE_TOKEN; + + /* [MS-NRPC] 3.3.4.2.2.3: verify Pad bytes */ + if (sig->Pad != 0xFFFF) + return GSS_S_DEFECTIVE_TOKEN; + + /* [MS-NRPC] 3.3.4.2.2.5: decrypt sequence number */ + _netlogon_seq(ctx, sig, 0); + + /* [MS-NRPC] 3.3.4.2.2.6: decode sequence number */ + if (_netlogon_decode_sequence_number(sig->SequenceNumber, &SequenceNumber, + !ctx->LocallyInitiated) != 0) + return GSS_S_UNSEQ_TOKEN; + + /* [MS-NRPC] 3.3.4.2.2.9: decrypt confounder and data */ + if (sig->SealAlgorithm != NL_SEAL_ALG_NONE) + _netlogon_seal(ctx, sig, iov, iov_count, 0); + + /* [MS-NRPC] 3.3.4.2.2.10: verify signature */ + _netlogon_digest(ctx, sig, iov, iov_count, checksum); + if (ct_memcmp(sig->Checksum, checksum, _netlogon_checksum_length(sig)) != 0) + return GSS_S_BAD_SIG; + + HEIMDAL_MUTEX_lock(&ctx->Mutex); + if (SequenceNumber != ctx->SequenceNumber) { + /* [MS-NRPC] 3.3.4.2.2.7: check sequence number */ + ret = GSS_S_UNSEQ_TOKEN; + } else { + /* [MS-NRPC] 3.3.4.2.2.8: increment sequence number */ + ctx->SequenceNumber++; + ret = GSS_S_COMPLETE; + } + HEIMDAL_MUTEX_unlock(&ctx->Mutex); + + if (conf_state != NULL) + *conf_state = (sig->SealAlgorithm != NL_SEAL_ALG_NONE); + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + *minor_status = 0; + return ret; +} + +OM_uint32 +_netlogon_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + gss_iov_buffer_t iovp; + gssnetlogon_ctx ctx = (gssnetlogon_ctx)context_handle; + size_t len; + + iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (iovp == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + len = NL_AUTH_SIGNATURE_COMMON_LENGTH; + if (ctx->SignatureAlgorithm == NL_SIGN_ALG_SHA256) + len += 32; /* SHA2 checksum size */ + else + len += 8; /* HMAC checksum size */ + if (conf_req_flag) + len += 8; /* counfounder */ + + iovp->buffer.length = len; + + iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (iovp != NULL) + iovp->buffer.length = 0; + + iovp = _gss_mg_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + if (iovp != NULL) + iovp->buffer.length = 0; + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _netlogon_get_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + gss_iov_buffer_desc iov[2]; + OM_uint32 ret; + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer = *message_buffer; + iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + iov[1].buffer.length = 0; + iov[1].buffer.value = NULL; + + ret = _netlogon_wrap_iov(minor_status, context_handle, 0, + qop_req, NULL, iov, 2); + if (ret == GSS_S_COMPLETE) + *message_token = iov[1].buffer; + + return ret; +} + +OM_uint32 +_netlogon_verify_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + gss_iov_buffer_desc iov[2]; + + iov[0].type = GSS_IOV_BUFFER_TYPE_DATA; + iov[0].buffer = *message_buffer; + iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[1].buffer = *token_buffer; + + return _netlogon_unwrap_iov(minor_status, context_handle, + NULL, qop_state, iov, 2); +} + +OM_uint32 +_netlogon_wrap_size_limit ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size + ) +{ + gss_iov_buffer_desc iov[1]; + OM_uint32 ret; + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER; + iov[0].buffer.length = 0; + + ret = _netlogon_wrap_iov_length(minor_status, context_handle, + conf_req_flag, qop_req, NULL, + iov, sizeof(iov)/sizeof(iov[0])); + if (GSS_ERROR(ret)) + return ret; + + if (req_output_size < iov[0].buffer.length) + *max_input_size = 0; + else + *max_input_size = req_output_size - iov[0].buffer.length; + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/delete_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/delete_sec_context.c new file mode 100644 index 0000000..8710416 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/delete_sec_context.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 +_netlogon_delete_sec_context(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token) +{ + if (context_handle != NULL && *context_handle != GSS_C_NO_CONTEXT) { + gssnetlogon_ctx ctx = (gssnetlogon_ctx)*context_handle; + + *context_handle = GSS_C_NO_CONTEXT; + + _netlogon_release_name(minor_status, (gss_name_t *)&ctx->SourceName); + _netlogon_release_name(minor_status, (gss_name_t *)&ctx->TargetName); + HEIMDAL_MUTEX_destroy(&ctx->Mutex); + memset(ctx, 0, sizeof(*ctx)); + free(ctx); + } + + if (output_token != GSS_C_NO_BUFFER) { + output_token->length = 0; + output_token->value = NULL; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/display_name.c b/third_party/heimdal/lib/gssapi/netlogon/display_name.c new file mode 100644 index 0000000..7b0e223 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/display_name.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_display_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type + ) +{ + const gssnetlogon_name name = (const gssnetlogon_name)input_name; + gss_buffer_t namebuf; + + if (output_name_type != NULL) + *output_name_type = GSS_C_NO_OID; + + if (output_name_buffer != NULL) { + namebuf = name->DnsName.length ? &name->DnsName : &name->NetbiosName; + + output_name_buffer->value = malloc(namebuf->length + 1); + if (output_name_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(output_name_buffer->value, namebuf->value, namebuf->length); + ((char *)output_name_buffer->value)[namebuf->length] = '\0'; + output_name_buffer->length = namebuf->length; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/display_status.c b/third_party/heimdal/lib/gssapi/netlogon/display_status.c new file mode 100644 index 0000000..68946e5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/display_status.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_display_status + (OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + if (minor_status) + *minor_status = 0; + if (status_string) { + status_string->length = 0; + status_string->value = NULL; + } + if (message_context) + *message_context = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/duplicate_cred.c b/third_party/heimdal/lib/gssapi/netlogon/duplicate_cred.c new file mode 100644 index 0000000..0271fb2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/duplicate_cred.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 +_netlogon_duplicate_cred(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + gssnetlogon_const_cred src = (gssnetlogon_const_cred)input_cred_handle; + gssnetlogon_cred dst; + + dst = calloc(1, sizeof(*dst)); + if (dst == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *dst = *src; + return _netlogon_duplicate_name(minor_status, (gss_name_t)&src->Name, &dst->Name) +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/duplicate_name.c b/third_party/heimdal/lib/gssapi/netlogon/duplicate_name.c new file mode 100644 index 0000000..1365e76 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/duplicate_name.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_duplicate_name ( + OM_uint32 * minor_status, + gss_const_name_t src_name, + gss_name_t * dest_name + ) +{ + const gssnetlogon_name src = (const gssnetlogon_name)src_name; + gssnetlogon_name dst = NULL; + + dst = calloc(1, sizeof(*dst)); + if (dst == NULL) + goto fail; + + dst->NetbiosName.value = malloc(src->NetbiosName.length + 1); + if (dst->NetbiosName.value == NULL) + goto fail; + memcpy(dst->NetbiosName.value, src->NetbiosName.value, + src->NetbiosName.length); + dst->NetbiosName.length = src->NetbiosName.length; + ((char *)dst->NetbiosName.value)[dst->NetbiosName.length] = '\0'; + + if (src->DnsName.length != 0) { + dst->DnsName.value = malloc(src->DnsName.length + 1); + if (dst->DnsName.value == NULL) + goto fail; + memcpy(dst->DnsName.value, src->DnsName.value, src->DnsName.length); + dst->DnsName.length = src->DnsName.length; + ((char *)dst->DnsName.value)[dst->DnsName.length] = '\0'; + } + + *minor_status = 0; + *dest_name = (gss_name_t)dst; + return GSS_S_COMPLETE; + +fail: + _netlogon_release_name(minor_status, (gss_name_t *)&dst); + *minor_status = ENOMEM; + return GSS_S_FAILURE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/export_name.c b/third_party/heimdal/lib/gssapi/netlogon/export_name.c new file mode 100644 index 0000000..9984f8b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/export_name.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_export_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name + ) +{ + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/export_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/export_sec_context.c new file mode 100644 index 0000000..7e410aa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/export_sec_context.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 +_netlogon_export_sec_context ( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t interprocess_token + ) +{ + if (interprocess_token != GSS_C_NO_BUFFER) { + interprocess_token->length = 0; + interprocess_token->value = NULL; + } + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/external.c b/third_party/heimdal/lib/gssapi/netlogon/external.c new file mode 100644 index 0000000..14f471e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/external.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +static gssapi_mech_interface_desc netlogon_mech = { + GMI_VERSION, + "netlogon", + {6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x02") }, + 0, + _netlogon_acquire_cred, + _netlogon_release_cred, + _netlogon_init_sec_context, + _netlogon_accept_sec_context, + _netlogon_process_context_token, + _netlogon_delete_sec_context, + _netlogon_context_time, + _netlogon_get_mic, + _netlogon_verify_mic, + NULL, + NULL, + _netlogon_display_status, + NULL, + _netlogon_compare_name, + _netlogon_display_name, + _netlogon_import_name, + _netlogon_export_name, + _netlogon_release_name, + _netlogon_inquire_cred, + _netlogon_inquire_context, + _netlogon_wrap_size_limit, + _netlogon_add_cred, + _netlogon_inquire_cred_by_mech, + _netlogon_export_sec_context, + _netlogon_import_sec_context, + _netlogon_inquire_names_for_mech, + _netlogon_inquire_mechs_for_name, + _netlogon_canonicalize_name, + _netlogon_duplicate_name, + NULL, + NULL, + NULL, + _netlogon_set_cred_option, + NULL, + _netlogon_wrap_iov, + _netlogon_unwrap_iov, + _netlogon_wrap_iov_length, + NULL, /* gm_store_cred */ + NULL, /* gm_export_cred */ + NULL, /* gm_import_cred */ + NULL, /* gm_acquire_cred_from */ + NULL, /* gm_acquire_cred_impersonate_name */ + NULL, /* gm_iter_creds */ + NULL, /* gm_destroy_cred */ + NULL, /* gm_cred_hold */ + NULL, /* gm_cred_unhold */ + NULL, /* gm_cred_label_get */ + NULL, /* gm_cred_label_set */ + NULL, /* gm_mo */ + 0, /* gm_mo_num */ + NULL, /* gm_localname */ + NULL, /* gm_authorize_localname */ + NULL, /* gm_display_name_ext */ + NULL, /* gm_inquire_name */ + NULL, /* gm_get_name_attribute */ + NULL, /* gm_set_name_attribute */ + NULL, /* gm_delete_name_attribute */ + NULL, /* gm_export_name_composite */ + NULL, /* gm_duplicate_cred */ + NULL, /* gm_add_cred_from */ + NULL, /* gm_store_cred_into */ + NULL /* gm_compat */ +}; + +gssapi_mech_interface +__gss_netlogon_initialize(void) +{ + return &netlogon_mech; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/import_name.c b/third_party/heimdal/lib/gssapi/netlogon/import_name.c new file mode 100644 index 0000000..8d46486 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/import_name.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" +#include + +OM_uint32 _netlogon_import_name + (OM_uint32 * minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t * output_name + ) +{ + gssnetlogon_name name; + const char *netbiosName; + const char *dnsName = NULL; + size_t len, i; + + if (!gss_oid_equal(input_name_type, GSS_NETLOGON_NT_NETBIOS_DNS_NAME)) { + return GSS_S_BAD_NAME; + } + + /* encoding is NetBIOS name \0 DNS name \0 */ + + netbiosName = input_name_buffer->value; + len = strlen(netbiosName); + if (len < input_name_buffer->length) + dnsName = netbiosName + len + 1; + + name = (gssnetlogon_name)calloc(1, sizeof(*name)); + if (name == NULL) + goto cleanup; + + name->NetbiosName.value = malloc(len + 1); + if (name->NetbiosName.value == NULL) + goto cleanup; + memcpy(name->NetbiosName.value, netbiosName, len + 1); + name->NetbiosName.length = len; + + /* normalise name to uppercase XXX UTF-8 OK? */ + for (i = 0; i < len; i++) { + ((unsigned char *)name->NetbiosName.value)[i] = + toupper(((unsigned char *)name->NetbiosName.value)[i]); + } + + if (dnsName != NULL && dnsName[0] != '\0') { + name->DnsName.value = strdup(dnsName); + if (name->DnsName.value == NULL) + goto cleanup; + name->DnsName.length = strlen(dnsName); + } + + *output_name = (gss_name_t)name; + *minor_status = 0; + return GSS_S_COMPLETE; + +cleanup: + _netlogon_release_name(minor_status, (gss_name_t *)&name); + *minor_status = ENOMEM; + return GSS_S_FAILURE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/import_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/import_sec_context.c new file mode 100644 index 0000000..0415b39 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/import_sec_context.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 +_netlogon_import_sec_context ( + OM_uint32 * minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t * context_handle + ) +{ + *minor_status = 0; + if (context_handle != NULL) + *context_handle = GSS_C_NO_CONTEXT; + + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/indicate_mechs.c b/third_party/heimdal/lib/gssapi/netlogon/indicate_mechs.c new file mode 100644 index 0000000..9192e42 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/indicate_mechs.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_indicate_mechs +(OM_uint32 * minor_status, + gss_OID_set * mech_set + ) +{ + *minor_status = 0; + if (mech_set != NULL) + *mech_set = GSS_C_NO_OID_SET; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c b/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c new file mode 100644 index 0000000..906f457 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/init_sec_context.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" +#include + +static OM_uint32 +_netlogon_encode_dns_string(OM_uint32 *minor_status, + const gss_buffer_t str, + gss_buffer_t buffer) +{ + int ret; + + memset(buffer->value, 0, buffer->length); + + ret = ns_name_compress((const char *)str->value, + (uint8_t *)buffer->value, buffer->length, + NULL, NULL); + if (ret < 0) { + *minor_status = errno; + return GSS_S_FAILURE; + } + + buffer->length = ret; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +_netlogon_make_initial_auth_message(OM_uint32 *minor_status, + gssnetlogon_ctx ctx, + gss_buffer_t output_token) +{ + uint32_t flags = 0; +#define MAX_NL_NAMES 5 + gss_buffer_desc names[MAX_NL_NAMES]; + uint8_t comp_names[3][MAXHOSTNAMELEN * 2]; + size_t n = 0, i = 0, len; + OM_uint32 ret; + uint8_t *p; + + if (ctx->TargetName->NetbiosName.length) { + flags |= NL_FLAG_NETBIOS_DOMAIN_NAME; + names[n] = ctx->TargetName->NetbiosName; /* OEM encoding */ + names[n].length++; + n++; + } + if (ctx->SourceName->NetbiosName.length) { + flags |= NL_FLAG_NETBIOS_COMPUTER_NAME; + names[n] = ctx->SourceName->NetbiosName; /* OEM encoding */ + names[n].length++; + n++; + } + if (ctx->TargetName->DnsName.length) { + flags |= NL_FLAG_DNS_DOMAIN_NAME; + names[n].value = comp_names[i++]; + names[n].length = MAXHOSTNAMELEN * 2; + ret = _netlogon_encode_dns_string(minor_status, + &ctx->TargetName->DnsName, + &names[n]); + if (GSS_ERROR(ret)) + return ret; + n++; + } + if (ctx->SourceName->DnsName.length) { + flags |= NL_FLAG_DNS_HOST_NAME; + names[n].value = comp_names[i++]; + names[n].length = MAXHOSTNAMELEN * 2; + ret = _netlogon_encode_dns_string(minor_status, + &ctx->SourceName->DnsName, + &names[n]); + if (GSS_ERROR(ret)) + return ret; + n++; + } + if (ctx->SourceName->NetbiosName.length) { + flags |= NL_FLAG_UTF8_COMPUTER_NAME; + names[n].value = comp_names[i++]; + names[n].length = MAXHOSTNAMELEN * 2; + ret = _netlogon_encode_dns_string(minor_status, + &ctx->SourceName->NetbiosName, + &names[n]); + if (GSS_ERROR(ret)) + return ret; + n++; + } + + for (i = 0, len = NL_AUTH_MESSAGE_LENGTH; i < n; i++) { + len += names[i].length; + } + + output_token->value = malloc(len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = (uint8_t *)output_token->value; + _gss_mg_encode_le_uint32(NL_NEGOTIATE_REQUEST_MESSAGE, p); + _gss_mg_encode_le_uint32(flags, p + 4); + p += 8; + + for (i = 0; i < n; i++) { + assert(names[i].length != 0); + assert(((char *)names[i].value)[names[i].length - 1] == '\0'); + memcpy(p, names[i].value, names[i].length); + p += names[i].length; + } + + output_token->length = len; + assert(p == (uint8_t *)output_token->value + len); + + *minor_status = 0; + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +_netlogon_read_initial_auth_message(OM_uint32 *minor_status, + gssnetlogon_ctx ctx, + const gss_buffer_t input_token) +{ + NL_AUTH_MESSAGE msg; + const uint8_t *p = (const uint8_t *)input_token->value; + + if (ctx->State != NL_AUTH_NEGOTIATE) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (input_token->length < NL_AUTH_MESSAGE_LENGTH) + return GSS_S_DEFECTIVE_TOKEN; + + _gss_mg_decode_le_uint32(&p[0], &msg.MessageType); + _gss_mg_decode_le_uint32(&p[4], &msg.Flags); + + if (msg.MessageType != NL_NEGOTIATE_RESPONSE_MESSAGE || + msg.Flags != 0) + return GSS_S_DEFECTIVE_TOKEN; + + ctx->State = NL_AUTH_ESTABLISHED; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +_netlogon_alloc_context(OM_uint32 *minor_status, + gssnetlogon_ctx *pContext) +{ + gssnetlogon_ctx ctx; + + ctx = (gssnetlogon_ctx)calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ctx->State = NL_AUTH_NEGOTIATE; + ctx->LocallyInitiated = 1; + ctx->MessageBlockSize = 1; + + HEIMDAL_MUTEX_init(&ctx->Mutex); + + *pContext = ctx; + + return GSS_S_COMPLETE; +} + +OM_uint32 +_netlogon_init_sec_context(OM_uint32 * minor_status, + gss_const_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + const gssnetlogon_cred cred = (const gssnetlogon_cred)initiator_cred_handle; + gssnetlogon_ctx ctx = (gssnetlogon_ctx)*context_handle; + const gssnetlogon_name target = (const gssnetlogon_name)target_name; + OM_uint32 ret; + + *minor_status = 0; + + output_token->value = NULL; + output_token->length = 0; + + /* Validate arguments */ + if (cred == NULL) + return GSS_S_NO_CRED; + else if (target == NULL) + return GSS_S_BAD_NAME; + + if (ctx == NULL) { + if (input_token->length != 0) + return GSS_S_DEFECTIVE_TOKEN; + + ret = _netlogon_alloc_context(minor_status, &ctx); + if (GSS_ERROR(ret)) + goto cleanup; + + HEIMDAL_MUTEX_lock(&ctx->Mutex); + *context_handle = (gss_ctx_id_t)ctx; + + ctx->GssFlags = req_flags & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | + GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | + GSS_C_INTEG_FLAG | GSS_C_DCE_STYLE); + ctx->SignatureAlgorithm = cred->SignatureAlgorithm; + ctx->SealAlgorithm = cred->SealAlgorithm; + + ret = _netlogon_duplicate_name(minor_status, (gss_name_t)cred->Name, + (gss_name_t *)&ctx->SourceName); + if (GSS_ERROR(ret)) + goto cleanup; + + ret = _netlogon_duplicate_name(minor_status, (gss_name_t)target, + (gss_name_t *)&ctx->TargetName); + if (GSS_ERROR(ret)) + goto cleanup; + + memcpy(ctx->SessionKey, cred->SessionKey, sizeof(cred->SessionKey)); + + ret = _netlogon_make_initial_auth_message(minor_status, ctx, + output_token); + if (GSS_ERROR(ret)) + goto cleanup; + } else { + HEIMDAL_MUTEX_lock(&ctx->Mutex); + ret = _netlogon_read_initial_auth_message(minor_status, ctx, + input_token); + } + + if (ret_flags != NULL) + *ret_flags = ctx->GssFlags; + if (time_rec != NULL) + *time_rec = GSS_C_INDEFINITE; + if (actual_mech_type != NULL) + *actual_mech_type = GSS_NETLOGON_MECHANISM; + +cleanup: + HEIMDAL_MUTEX_unlock(&ctx->Mutex); + + if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) { + OM_uint32 tmp; + _netlogon_delete_sec_context(&tmp, context_handle, NULL); + } + + return ret; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/inquire_context.c b/third_party/heimdal/lib/gssapi/netlogon/inquire_context.c new file mode 100644 index 0000000..24995c2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/inquire_context.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_inquire_context ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t * src_name, + gss_name_t * targ_name, + OM_uint32 * lifetime_rec, + gss_OID * mech_type, + OM_uint32 * ctx_flags, + int * locally_initiated, + int * open_context + ) +{ + const gssnetlogon_ctx ctx = (const gssnetlogon_ctx)context_handle; + OM_uint32 ret; + + if (src_name != NULL) { + ret = _netlogon_duplicate_name(minor_status, (gss_name_t)ctx->SourceName, + (gss_name_t *)src_name); + if (GSS_ERROR(ret)) + return ret; + } + if (targ_name != NULL) { + ret = _netlogon_duplicate_name(minor_status, (gss_name_t)ctx->TargetName, + (gss_name_t *)targ_name); + if (GSS_ERROR(ret)) + return ret; + } + if (mech_type != NULL) + *mech_type = GSS_NETLOGON_MECHANISM; + if (ctx_flags != NULL) + *ctx_flags = ctx->GssFlags; + if (locally_initiated != NULL) + *locally_initiated = ctx->LocallyInitiated; + if (open_context != NULL) + *open_context = (ctx->State == NL_AUTH_ESTABLISHED); + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/inquire_cred.c b/third_party/heimdal/lib/gssapi/netlogon/inquire_cred.c new file mode 100644 index 0000000..6c7ca34 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/inquire_cred.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_inquire_cred + (OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t * name, + OM_uint32 * lifetime, + gss_cred_usage_t * cred_usage, + gss_OID_set * mechanisms + ) +{ + OM_uint32 ret; + const gssnetlogon_cred cred = (const gssnetlogon_cred)cred_handle; + + *minor_status = 0; + + if (cred == NULL) + return GSS_S_NO_CRED; + + if (name != NULL) { + ret = _netlogon_duplicate_name(minor_status, + (gss_const_name_t)cred->Name, name); + if (GSS_ERROR(ret)) + return ret; + } + if (lifetime != NULL) + *lifetime = GSS_C_INDEFINITE; + if (cred_usage != NULL) + *cred_usage = GSS_C_INITIATE; + if (mechanisms != NULL) + *mechanisms = GSS_C_NO_OID_SET; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/netlogon/inquire_cred_by_mech.c new file mode 100644 index 0000000..f36310f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/inquire_cred_by_mech.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_inquire_cred_by_mech ( + OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t * name, + OM_uint32 * initiator_lifetime, + OM_uint32 * acceptor_lifetime, + gss_cred_usage_t * cred_usage + ) +{ + OM_uint32 ret; + const gssnetlogon_cred cred = (const gssnetlogon_cred)cred_handle; + + if (name != NULL) { + ret = _netlogon_duplicate_name(minor_status, + (gss_const_name_t)cred->Name, name); + if (GSS_ERROR(ret)) + return ret; + } + if (initiator_lifetime != NULL) + *initiator_lifetime = GSS_C_INDEFINITE; + if (acceptor_lifetime != NULL) + *acceptor_lifetime = GSS_C_INDEFINITE; + if (cred_usage != NULL) + *cred_usage = GSS_C_INITIATE; + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/netlogon/inquire_mechs_for_name.c new file mode 100644 index 0000000..dbf385c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/inquire_mechs_for_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_inquire_mechs_for_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_OID_set * mech_types + ) +{ + if (mech_types != NULL) + *mech_types = GSS_C_NO_OID_SET; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/netlogon/inquire_names_for_mech.c new file mode 100644 index 0000000..9802e53 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/inquire_names_for_mech.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_inquire_names_for_mech ( + OM_uint32 * minor_status, + const gss_OID mechanism, + gss_OID_set * name_types + ) +{ + OM_uint32 ret, tmp; + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + ret = gss_add_oid_set_member(minor_status, GSS_NETLOGON_NT_NETBIOS_DNS_NAME, name_types); + if (ret != GSS_S_COMPLETE) { + gss_release_oid_set(&tmp, name_types); + return ret; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/iter_cred.c b/third_party/heimdal/lib/gssapi/netlogon/iter_cred.c new file mode 100644 index 0000000..93a8d59 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/iter_cred.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" +#include + +void +_netlogon_iter_creds_f(OM_uint32 flags, + void *userctx , + void (*cred_iter)(void *, gss_OID, gss_cred_id_t)) +{ +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/netlogon.h b/third_party/heimdal/lib/gssapi/netlogon/netlogon.h new file mode 100644 index 0000000..68573e2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/netlogon.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef NETLOGON_NETLOGON_H +#define NETLOGON_NETLOGON_H + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define HC_DEPRECATED_CRYPTO +#include "crypto-headers.h" + +/* + * + */ + +typedef struct { +#define NL_NEGOTIATE_REQUEST_MESSAGE 0x00000000 +#define NL_NEGOTIATE_RESPONSE_MESSAGE 0x00000001 + uint32_t MessageType; +#define NL_FLAG_NETBIOS_DOMAIN_NAME 0x00000001 +#define NL_FLAG_NETBIOS_COMPUTER_NAME 0x00000002 +#define NL_FLAG_DNS_DOMAIN_NAME 0x00000004 +#define NL_FLAG_DNS_HOST_NAME 0x00000008 /* not used */ +#define NL_FLAG_UTF8_COMPUTER_NAME 0x00000010 + uint32_t Flags; + char *Buffer[0]; +} NL_AUTH_MESSAGE; + +#define NL_AUTH_MESSAGE_LENGTH 8 + +/* SignatureAlgorithm */ +#define NL_SIGN_ALG_HMAC_MD5 0x0077 +#define NL_SIGN_ALG_SHA256 0x0013 + +/* SealAlgorithm */ +#define NL_SEAL_ALG_RC4 0x007A +#define NL_SEAL_ALG_AES128 0x001A +#define NL_SEAL_ALG_NONE 0xFFFF + +typedef struct { + uint16_t SignatureAlgorithm; + uint16_t SealAlgorithm; + uint16_t Pad; + uint16_t Flags; + uint8_t SequenceNumber[8]; + uint8_t Checksum[8]; + uint8_t Confounder[8]; +} NL_AUTH_SIGNATURE; + +#define NL_AUTH_SIGNATURE_HEADER_LENGTH 8 +#define NL_AUTH_SIGNATURE_COMMON_LENGTH 16 +#define NL_AUTH_SIGNATURE_LENGTH 32 + +typedef struct { + uint16_t SignatureAlgorithm; + uint16_t SealAlgorithm; + uint16_t Pad; + uint16_t Flags; + uint8_t SequenceNumber[8]; + uint8_t Checksum[32]; + uint8_t Confounder[8]; +} NL_AUTH_SHA2_SIGNATURE; + +#define NL_AUTH_SHA2_SIGNATURE_LENGTH 56 + +typedef union { + NL_AUTH_SIGNATURE Signature; + NL_AUTH_SHA2_SIGNATURE SHA2Signature; +} NL_AUTH_SIGNATURE_U; + +#define NL_AUTH_SIGNATURE_P(_u) (&(_u)->Signature) + +typedef struct gssnetlogon_name { + gss_buffer_desc NetbiosName; + gss_buffer_desc DnsName; +} *gssnetlogon_name; +typedef const struct gssnetlogon_name *gssnetlogon_const_name; + +typedef struct gssnetlogon_cred { + gssnetlogon_name *Name; + uint16_t SignatureAlgorithm; + uint16_t SealAlgorithm; + uint8_t SessionKey[16]; +} *gssnetlogon_cred; +typedef const struct gssnetlogon_cred *gssnetlogon_const_cred; + +typedef struct gssnetlogon_ctx { + HEIMDAL_MUTEX Mutex; + enum { NL_AUTH_NEGOTIATE, NL_AUTH_ESTABLISHED } State; + OM_uint32 GssFlags; + uint8_t LocallyInitiated; + uint32_t MessageBlockSize; + uint16_t SignatureAlgorithm; + uint16_t SealAlgorithm; + uint64_t SequenceNumber; + gssnetlogon_name SourceName; + gssnetlogon_name TargetName; + uint8_t SessionKey[16]; +} *gssnetlogon_ctx; + +#include + +#endif /* NETLOGON_NETLOGON_H */ diff --git a/third_party/heimdal/lib/gssapi/netlogon/process_context_token.c b/third_party/heimdal/lib/gssapi/netlogon/process_context_token.c new file mode 100644 index 0000000..0f83613 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/process_context_token.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_process_context_token ( + OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer + ) +{ + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/netlogon/regen.sh b/third_party/heimdal/lib/gssapi/netlogon/regen.sh new file mode 100644 index 0000000..b034dbf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/regen.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +perl ../../../cf/make-proto.pl -q -P comment -p netlogon-private.h *.c diff --git a/third_party/heimdal/lib/gssapi/netlogon/release_cred.c b/third_party/heimdal/lib/gssapi/netlogon/release_cred.c new file mode 100644 index 0000000..7db71b6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/release_cred.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_release_cred + (OM_uint32 * minor_status, + gss_cred_id_t * cred_handle + ) +{ + gssnetlogon_cred cred = (gssnetlogon_cred)*cred_handle; + + if (cred != NULL) { + _netlogon_release_name(minor_status, (gss_name_t *)&cred->Name); + memset(cred, 0, sizeof(*cred)); + free(cred); + *cred_handle = GSS_C_NO_CREDENTIAL; + } + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/netlogon/release_name.c b/third_party/heimdal/lib/gssapi/netlogon/release_name.c new file mode 100644 index 0000000..27ca018 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/netlogon/release_name.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "netlogon.h" + +OM_uint32 _netlogon_release_name + (OM_uint32 * minor_status, + gss_name_t * input_name + ) +{ + gssnetlogon_name name = (gssnetlogon_name)*input_name; + + if (name != NULL) { + gss_release_buffer(minor_status, &name->NetbiosName); + gss_release_buffer(minor_status, &name->DnsName); + free(name); + *input_name = GSS_C_NO_NAME; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c new file mode 100644 index 0000000..6a3e889 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/accept_sec_context.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +/* + * + */ + +OM_uint32 +_gss_ntlm_allocate_ctx(OM_uint32 *minor_status, ntlm_ctx *ctx) +{ + OM_uint32 maj_stat; + struct ntlm_server_interface *ns_interface = NULL; + +#ifdef DIGEST + ns_interface = &ntlmsspi_kdc_digest; +#endif + if (ns_interface == NULL) + return GSS_S_FAILURE; + + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + (*ctx)->server = ns_interface; + + maj_stat = (*(*ctx)->server->nsi_init)(minor_status, &(*ctx)->ictx); + if (maj_stat == GSS_S_COMPLETE) + return GSS_S_COMPLETE; + + if (*ctx) + free(*ctx); + (*ctx) = NULL; + + return maj_stat; +} + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_accept_sec_context +(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle + ) +{ + krb5_error_code ret; + struct ntlm_buf data; + OM_uint32 junk; + ntlm_ctx ctx; + + output_token->value = NULL; + output_token->length = 0; + + *minor_status = 0; + + if (context_handle == NULL) + return GSS_S_FAILURE; + + if (input_token_buffer == GSS_C_NO_BUFFER) + return GSS_S_FAILURE; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + if (delegated_cred_handle) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + if (*context_handle == GSS_C_NO_CONTEXT) { + struct ntlm_type1 type1; + OM_uint32 major_status; + OM_uint32 retflags; + struct ntlm_buf out; + + major_status = _gss_ntlm_allocate_ctx(minor_status, &ctx); + if (major_status) + return major_status; + *context_handle = (gss_ctx_id_t)ctx; + + /* check if the mechs is allowed by remote service */ + major_status = (*ctx->server->nsi_probe)(minor_status, ctx->ictx, NULL); + if (major_status) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + return major_status; + } + + data.data = input_token_buffer->value; + data.length = input_token_buffer->length; + + ret = heim_ntlm_decode_type1(&data, &type1); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if ((type1.flags & NTLM_NEG_UNICODE) == 0) { + heim_ntlm_free_type1(&type1); + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (type1.flags & NTLM_NEG_SIGN) + ctx->gssflags |= GSS_C_CONF_FLAG; + if (type1.flags & NTLM_NEG_SIGN) + ctx->gssflags |= GSS_C_INTEG_FLAG; + + major_status = (*ctx->server->nsi_type2)(minor_status, + ctx->ictx, + type1.flags, + type1.hostname, + type1.domain, + &retflags, + &out); + heim_ntlm_free_type1(&type1); + if (major_status != GSS_S_COMPLETE) { + OM_uint32 gunk; + _gss_ntlm_delete_sec_context(&gunk, context_handle, NULL); + return major_status; + } + + output_token->value = malloc(out.length); + if (output_token->value == NULL && out.length != 0) { + OM_uint32 gunk; + heim_ntlm_free_buf(&out); + _gss_ntlm_delete_sec_context(&gunk, context_handle, NULL); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(output_token->value, out.data, out.length); + output_token->length = out.length; + heim_ntlm_free_buf(&out); + + ctx->flags = retflags; + + return GSS_S_CONTINUE_NEEDED; + } else { + OM_uint32 maj_stat; + struct ntlm_type3 type3; + struct ntlm_buf session; + + ctx = (ntlm_ctx)*context_handle; + + data.data = input_token_buffer->value; + data.length = input_token_buffer->length; + + ret = heim_ntlm_decode_type3(&data, 1, &type3); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + maj_stat = (*ctx->server->nsi_type3)(minor_status, + ctx->ictx, + &type3, + &session); + if (maj_stat) { + heim_ntlm_free_type3(&type3); + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + return maj_stat; + } + + if (src_name) { + ntlm_name n = calloc(1, sizeof(*n)); + if (n) { + n->user = strdup(type3.username); + n->domain = strdup(type3.targetname); + } + if (n == NULL || n->user == NULL || n->domain == NULL) { + gss_name_t tempn = (gss_name_t)n; + _gss_ntlm_release_name(&junk, &tempn); + heim_ntlm_free_type3(&type3); + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + return maj_stat; + } + *src_name = (gss_name_t)n; + } + + heim_ntlm_free_type3(&type3); + + ret = krb5_data_copy(&ctx->sessionkey, + session.data, session.length); + if (ret) { + if (src_name) + _gss_ntlm_release_name(&junk, src_name); + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + _gss_ntlm_set_keys(ctx); + + if (mech_type) + *mech_type = GSS_NTLM_MECHANISM; + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + + ctx->status |= STATUS_OPEN; + + if (ret_flags) + *ret_flags = ctx->gssflags; + + return GSS_S_COMPLETE; + } +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/acquire_cred.c b/third_party/heimdal/lib/gssapi/ntlm/acquire_cred.c new file mode 100644 index 0000000..a6b151f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/acquire_cred.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_acquire_cred_from(OM_uint32 *min_stat, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + ntlm_name name = (ntlm_name) desired_name; + OM_uint32 maj_stat; + ntlm_ctx ctx; + + *min_stat = 0; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + + if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_ACCEPT) { + int ret; + + maj_stat = _gss_ntlm_allocate_ctx(min_stat, &ctx); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + ret = (*ctx->server->nsi_probe)(min_stat, ctx->ictx, NULL); + { + gss_ctx_id_t context = (gss_ctx_id_t)ctx; + OM_uint32 junk; + _gss_ntlm_delete_sec_context(&junk, &context, NULL); + } + if (ret) { + *min_stat = ret; + return GSS_S_NO_CRED; + } + } + if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) { + ntlm_cred cred; + + *min_stat = _gss_ntlm_get_user_cred(name, &cred); + if (*min_stat) + return GSS_S_NO_CRED; + cred->usage = cred_usage; + + *output_cred_handle = (gss_cred_id_t)cred; + } + + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/add_cred.c b/third_party/heimdal/lib/gssapi/ntlm/add_cred.c new file mode 100644 index 0000000..1517232 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/add_cred.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_add_cred ( + OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + if (minor_status) + *minor_status = 0; + if (output_cred_handle) + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if (initiator_time_rec) + *initiator_time_rec = 0; + if (acceptor_time_rec) + *acceptor_time_rec = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/canonicalize_name.c b/third_party/heimdal/lib/gssapi/ntlm/canonicalize_name.c new file mode 100644 index 0000000..3409b3b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/canonicalize_name.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_canonicalize_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t * output_name + ) +{ + return gss_duplicate_name (minor_status, input_name, output_name); +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/compare_name.c b/third_party/heimdal/lib/gssapi/ntlm/compare_name.c new file mode 100644 index 0000000..d185ab9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/compare_name.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_compare_name + (OM_uint32 * minor_status, + gss_const_name_t name1, + gss_const_name_t name2, + int * name_equal + ) +{ + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/context_time.c b/third_party/heimdal/lib/gssapi/ntlm/context_time.c new file mode 100644 index 0000000..589ee2a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/context_time.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_context_time + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 * time_rec + ) +{ + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/creds.c b/third_party/heimdal/lib/gssapi/ntlm/creds.c new file mode 100644 index 0000000..5794015 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/creds.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_cred + (OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t * name, + OM_uint32 * lifetime, + gss_cred_usage_t * cred_usage, + gss_OID_set * mechanisms + ) +{ + OM_uint32 ret, junk; + + *minor_status = 0; + + if (cred_handle == NULL) + return GSS_S_NO_CRED; + + if (name) { + ntlm_name n = calloc(1, sizeof(*n)); + ntlm_cred c = (ntlm_cred)cred_handle; + if (n) { + n->user = strdup(c->username); + n->domain = strdup(c->domain); + } + if (n == NULL || n->user == NULL || n->domain == NULL) { + if (n) { + free(n->user); + free(n->domain); + free(n); + } + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *name = (gss_name_t)n; + } + if (lifetime) + *lifetime = GSS_C_INDEFINITE; + if (cred_usage) + *cred_usage = 0; + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + if (mechanisms) { + ret = gss_create_empty_oid_set(minor_status, mechanisms); + if (ret) + goto out; + ret = gss_add_oid_set_member(minor_status, + GSS_NTLM_MECHANISM, + mechanisms); + if (ret) + goto out; + } + + return GSS_S_COMPLETE; +out: + gss_release_oid_set(&junk, mechanisms); + return ret; +} + +#ifdef HAVE_KCM +static OM_uint32 +_gss_ntlm_destroy_kcm_cred(gss_cred_id_t *cred_handle) +{ + krb5_storage *request, *response; + krb5_data response_data; + krb5_context context; + krb5_error_code ret; + ntlm_cred cred; + + cred = (ntlm_cred)*cred_handle; + + ret = krb5_init_context(&context); + if (ret) + return ret; + + ret = krb5_kcm_storage_request(context, KCM_OP_DEL_NTLM_CRED, &request); + if (ret) + goto out; + + ret = krb5_store_stringz(request, cred->username); + if (ret) + goto out; + + ret = krb5_store_stringz(request, cred->domain); + if (ret) + goto out; + + ret = krb5_kcm_call(context, request, &response, &response_data); + if (ret) + goto out; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + out: + krb5_free_context(context); + + return ret; +} +#endif /* HAVE_KCM */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_destroy_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) +{ +#ifdef HAVE_KCM + krb5_error_code ret; +#endif + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_COMPLETE; + +#ifdef HAVE_KCM + ret = _gss_ntlm_destroy_kcm_cred(cred_handle); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } +#endif + + return _gss_ntlm_release_cred(minor_status, cred_handle); +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/crypto.c b/third_party/heimdal/lib/gssapi/ntlm/crypto.c new file mode 100644 index 0000000..d2cfddf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/crypto.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" +struct hx509_certs_data; +struct krb5_pk_identity; +struct krb5_pk_cert; +struct ContentInfo; +struct AlgorithmIdentifier; +struct _krb5_krb_auth_data; +struct krb5_dh_moduli; +struct _krb5_key_data; +struct _krb5_encryption_type; +struct _krb5_key_type; +#include "krb5_locl.h" + +/* + * + */ + +const char a2i_signmagic[] = + "session key to server-to-client signing key magic constant"; +const char a2i_sealmagic[] = + "session key to server-to-client sealing key magic constant"; +const char i2a_signmagic[] = + "session key to client-to-server signing key magic constant"; +const char i2a_sealmagic[] = + "session key to client-to-server sealing key magic constant"; + + +void +_gss_ntlm_set_key(struct ntlmv2_key *key, int acceptor, int sealsign, + unsigned char *data, size_t len) +{ + unsigned char out[16]; + EVP_MD_CTX *ctx; + const char *signmagic; + const char *sealmagic; + + if (acceptor) { + signmagic = a2i_signmagic; + sealmagic = a2i_sealmagic; + } else { + signmagic = i2a_signmagic; + sealmagic = i2a_sealmagic; + } + + key->seq = 0; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_md5(), NULL); + EVP_DigestUpdate(ctx, data, len); + EVP_DigestUpdate(ctx, signmagic, strlen(signmagic) + 1); + EVP_DigestFinal_ex(ctx, key->signkey, NULL); + + EVP_DigestInit_ex(ctx, EVP_md5(), NULL); + EVP_DigestUpdate(ctx, data, len); + EVP_DigestUpdate(ctx, sealmagic, strlen(sealmagic) + 1); + EVP_DigestFinal_ex(ctx, out, NULL); + EVP_MD_CTX_destroy(ctx); + + RC4_set_key(&key->sealkey, 16, out); + if (sealsign) + key->signsealkey = &key->sealkey; +} + +/* + * Set (or reset) keys + */ + +void +_gss_ntlm_set_keys(ntlm_ctx ctx) +{ + int acceptor; + + if (ctx->sessionkey.length == 0) + return; + + acceptor = !(ctx->status & STATUS_CLIENT); + + ctx->status |= STATUS_SESSIONKEY; + + if (ctx->flags & NTLM_NEG_NTLM2_SESSION) { + _gss_ntlm_set_key(&ctx->u.v2.send, acceptor, + (ctx->flags & NTLM_NEG_KEYEX), + ctx->sessionkey.data, + ctx->sessionkey.length); + _gss_ntlm_set_key(&ctx->u.v2.recv, !acceptor, + (ctx->flags & NTLM_NEG_KEYEX), + ctx->sessionkey.data, + ctx->sessionkey.length); + } else { + ctx->u.v1.crypto_send.seq = 0; + RC4_set_key(&ctx->u.v1.crypto_send.key, + ctx->sessionkey.length, + ctx->sessionkey.data); + ctx->u.v1.crypto_recv.seq = 0; + RC4_set_key(&ctx->u.v1.crypto_recv.key, + ctx->sessionkey.length, + ctx->sessionkey.data); + } +} + +/* + * + */ + +static OM_uint32 +v1_sign_message(gss_buffer_t in, + RC4_KEY *signkey, + uint32_t seq, + unsigned char out[16]) +{ + unsigned char sigature[12]; + uint32_t crc; + + _krb5_crc_init_table(); + crc = _krb5_crc_update(in->value, in->length, 0); + + _gss_mg_encode_le_uint32(0, &sigature[0]); + _gss_mg_encode_le_uint32(crc, &sigature[4]); + _gss_mg_encode_le_uint32(seq, &sigature[8]); + + _gss_mg_encode_le_uint32(1, out); /* version */ + RC4(signkey, sizeof(sigature), sigature, out + 4); + + if (RAND_bytes(out + 4, 4) != 1) + return GSS_S_UNAVAILABLE; + + return 0; +} + + +static OM_uint32 +v2_sign_message(gss_buffer_t in, + unsigned char signkey[16], + RC4_KEY *sealkey, + uint32_t seq, + unsigned char out[16]) +{ + unsigned char hmac[16]; + unsigned int hmaclen; + HMAC_CTX c; + + HMAC_CTX_init(&c); + if (HMAC_Init_ex(&c, signkey, 16, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + return GSS_S_FAILURE; + } + + _gss_mg_encode_le_uint32(seq, hmac); + HMAC_Update(&c, hmac, 4); + HMAC_Update(&c, in->value, in->length); + HMAC_Final(&c, hmac, &hmaclen); + HMAC_CTX_cleanup(&c); + + _gss_mg_encode_le_uint32(1, &out[0]); + if (sealkey) + RC4(sealkey, 8, hmac, &out[4]); + else + memcpy(&out[4], hmac, 8); + + memset(&out[12], 0, 4); + + return GSS_S_COMPLETE; +} + +static OM_uint32 +v2_verify_message(gss_buffer_t in, + unsigned char signkey[16], + RC4_KEY *sealkey, + uint32_t seq, + const unsigned char checksum[16]) +{ + OM_uint32 ret; + unsigned char out[16]; + + ret = v2_sign_message(in, signkey, sealkey, seq, out); + if (ret) + return ret; + + if (ct_memcmp(checksum, out, 16) != 0) + return GSS_S_BAD_MIC; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +v2_seal_message(const gss_buffer_t in, + unsigned char signkey[16], + uint32_t seq, + RC4_KEY *sealkey, + gss_buffer_t out) +{ + unsigned char *p; + OM_uint32 ret; + + if (in->length + 16 < in->length) + return EINVAL; + + p = malloc(in->length + 16); + if (p == NULL) + return ENOMEM; + + RC4(sealkey, in->length, in->value, p); + + ret = v2_sign_message(in, signkey, sealkey, seq, &p[in->length]); + if (ret) { + free(p); + return ret; + } + + out->value = p; + out->length = in->length + 16; + + return 0; +} + +static OM_uint32 +v2_unseal_message(gss_buffer_t in, + unsigned char signkey[16], + uint32_t seq, + RC4_KEY *sealkey, + gss_buffer_t out) +{ + OM_uint32 ret; + + if (in->length < 16) + return GSS_S_BAD_MIC; + + out->length = in->length - 16; + out->value = malloc(out->length); + if (out->value == NULL) + return GSS_S_BAD_MIC; + + RC4(sealkey, out->length, in->value, out->value); + + ret = v2_verify_message(out, signkey, sealkey, seq, + ((const unsigned char *)in->value) + out->length); + if (ret) { + OM_uint32 junk; + gss_release_buffer(&junk, out); + } + return ret; +} + +/* + * + */ + +#define CTX_FLAGS_ISSET(_ctx,_flags) \ + (((_ctx)->flags & (_flags)) == (_flags)) + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_get_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + OM_uint32 junk; + + *minor_status = 0; + + message_token->value = malloc(16); + message_token->length = 16; + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) { + OM_uint32 ret; + + if ((ctx->status & STATUS_SESSIONKEY) == 0) { + gss_release_buffer(&junk, message_token); + return GSS_S_UNAVAILABLE; + } + + ret = v2_sign_message(message_buffer, + ctx->u.v2.send.signkey, + ctx->u.v2.send.signsealkey, + ctx->u.v2.send.seq++, + message_token->value); + if (ret) + gss_release_buffer(&junk, message_token); + return ret; + + } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) { + OM_uint32 ret; + + if ((ctx->status & STATUS_SESSIONKEY) == 0) { + gss_release_buffer(&junk, message_token); + return GSS_S_UNAVAILABLE; + } + + ret = v1_sign_message(message_buffer, + &ctx->u.v1.crypto_send.key, + ctx->u.v1.crypto_send.seq++, + message_token->value); + if (ret) + gss_release_buffer(&junk, message_token); + return ret; + + } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_ALWAYS_SIGN)) { + unsigned char *sigature; + + sigature = message_token->value; + + _gss_mg_encode_le_uint32(1, &sigature[0]); /* version */ + _gss_mg_encode_le_uint32(0, &sigature[4]); + _gss_mg_encode_le_uint32(0, &sigature[8]); + _gss_mg_encode_le_uint32(0, &sigature[12]); + + return GSS_S_COMPLETE; + } + gss_release_buffer(&junk, message_token); + + return GSS_S_UNAVAILABLE; +} + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_verify_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + *minor_status = 0; + + if (token_buffer->length != 16) + return GSS_S_BAD_MIC; + + if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) { + OM_uint32 ret; + + if ((ctx->status & STATUS_SESSIONKEY) == 0) + return GSS_S_UNAVAILABLE; + + ret = v2_verify_message(message_buffer, + ctx->u.v2.recv.signkey, + ctx->u.v2.recv.signsealkey, + ctx->u.v2.recv.seq++, + token_buffer->value); + if (ret) + return ret; + + return GSS_S_COMPLETE; + } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) { + + unsigned char sigature[12]; + uint32_t crc, num; + + if ((ctx->status & STATUS_SESSIONKEY) == 0) + return GSS_S_UNAVAILABLE; + + _gss_mg_decode_le_uint32(token_buffer->value, &num); + if (num != 1) + return GSS_S_BAD_MIC; + + RC4(&ctx->u.v1.crypto_recv.key, sizeof(sigature), + ((unsigned char *)token_buffer->value) + 4, sigature); + + _krb5_crc_init_table(); + crc = _krb5_crc_update(message_buffer->value, + message_buffer->length, 0); + /* skip first 4 bytes in the encrypted checksum */ + _gss_mg_decode_le_uint32(&sigature[4], &num); + if (num != crc) + return GSS_S_BAD_MIC; + _gss_mg_decode_le_uint32(&sigature[8], &num); + if (ctx->u.v1.crypto_recv.seq != num) + return GSS_S_BAD_MIC; + ctx->u.v1.crypto_recv.seq++; + + return GSS_S_COMPLETE; + } else if (ctx->flags & NTLM_NEG_ALWAYS_SIGN) { + uint32_t num; + unsigned char *p; + + p = (unsigned char*)(token_buffer->value); + + _gss_mg_decode_le_uint32(&p[0], &num); /* version */ + if (num != 1) return GSS_S_BAD_MIC; + _gss_mg_decode_le_uint32(&p[4], &num); + if (num != 0) return GSS_S_BAD_MIC; + _gss_mg_decode_le_uint32(&p[8], &num); + if (num != 0) return GSS_S_BAD_MIC; + _gss_mg_decode_le_uint32(&p[12], &num); + if (num != 0) return GSS_S_BAD_MIC; + + return GSS_S_COMPLETE; + } + + return GSS_S_UNAVAILABLE; +} + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_wrap_size_limit ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 * max_input_size + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + + *minor_status = 0; + + if(ctx->flags & NTLM_NEG_SEAL) { + + if (req_output_size < 16) + *max_input_size = 0; + else + *max_input_size = req_output_size - 16; + + return GSS_S_COMPLETE; + } + + return GSS_S_UNAVAILABLE; +} + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_wrap +(OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + OM_uint32 ret; + + *minor_status = 0; + if (conf_state) + *conf_state = 0; + if (output_message_buffer == GSS_C_NO_BUFFER) + return GSS_S_FAILURE; + + + if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) { + + return v2_seal_message(input_message_buffer, + ctx->u.v2.send.signkey, + ctx->u.v2.send.seq++, + &ctx->u.v2.send.sealkey, + output_message_buffer); + + } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) { + gss_buffer_desc trailer; + OM_uint32 junk; + + output_message_buffer->length = input_message_buffer->length + 16; + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + return GSS_S_FAILURE; + } + + + RC4(&ctx->u.v1.crypto_send.key, input_message_buffer->length, + input_message_buffer->value, output_message_buffer->value); + + ret = _gss_ntlm_get_mic(minor_status, context_handle, + 0, input_message_buffer, + &trailer); + if (ret) { + gss_release_buffer(&junk, output_message_buffer); + return ret; + } + if (trailer.length != 16) { + gss_release_buffer(&junk, output_message_buffer); + gss_release_buffer(&junk, &trailer); + return GSS_S_FAILURE; + } + memcpy(((unsigned char *)output_message_buffer->value) + + input_message_buffer->length, + trailer.value, trailer.length); + gss_release_buffer(&junk, &trailer); + + return GSS_S_COMPLETE; + } + + return GSS_S_UNAVAILABLE; +} + +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_unwrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + OM_uint32 ret; + + *minor_status = 0; + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) { + + return v2_unseal_message(input_message_buffer, + ctx->u.v2.recv.signkey, + ctx->u.v2.recv.seq++, + &ctx->u.v2.recv.sealkey, + output_message_buffer); + + } else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) { + + gss_buffer_desc trailer; + OM_uint32 junk; + + if (input_message_buffer->length < 16) + return GSS_S_BAD_MIC; + + output_message_buffer->length = input_message_buffer->length - 16; + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + return GSS_S_FAILURE; + } + + RC4(&ctx->u.v1.crypto_recv.key, output_message_buffer->length, + input_message_buffer->value, output_message_buffer->value); + + trailer.value = ((unsigned char *)input_message_buffer->value) + + output_message_buffer->length; + trailer.length = 16; + + ret = _gss_ntlm_verify_mic(minor_status, context_handle, + output_message_buffer, + &trailer, NULL); + if (ret) { + gss_release_buffer(&junk, output_message_buffer); + return ret; + } + + return GSS_S_COMPLETE; + } + + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c new file mode 100644 index 0000000..57587a0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/delete_sec_context.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_delete_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token + ) +{ + OM_uint32 min; + + if (context_handle) { + ntlm_ctx ctx = (ntlm_ctx)*context_handle; + gss_cred_id_t cred = (gss_cred_id_t)ctx->client; + + *context_handle = GSS_C_NO_CONTEXT; + + if (ctx->server) + (*ctx->server->nsi_destroy)(minor_status, ctx->ictx); + + _gss_ntlm_release_cred(NULL, &cred); + memset_s(ctx->sessionkey.data, ctx->sessionkey.length, 0, + ctx->sessionkey.length); + krb5_data_free(&ctx->sessionkey); + gss_release_buffer(&min, &ctx->pac); + + memset(ctx, 0, sizeof(*ctx)); + free(ctx); + } + if (output_token) { + output_token->length = 0; + output_token->value = NULL; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/display_name.c b/third_party/heimdal/lib/gssapi/ntlm/display_name.c new file mode 100644 index 0000000..59d2c84 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/display_name.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_display_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type + ) +{ + *minor_status = 0; + + if (output_name_type) + *output_name_type = GSS_NTLM_MECHANISM; + + if (output_name_buffer) { + ntlm_name n = (ntlm_name)input_name; + char *str = NULL; + int len; + + output_name_buffer->length = 0; + output_name_buffer->value = NULL; + + if (n == NULL) { + *minor_status = 0; + return GSS_S_BAD_NAME; + } + + len = asprintf(&str, "%s@%s", n->user, n->domain); + if (len < 0 || str == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_name_buffer->length = len; + output_name_buffer->value = str; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/display_status.c b/third_party/heimdal/lib/gssapi/ntlm/display_status.c new file mode 100644 index 0000000..c9e1792 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/display_status.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_display_status + (OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + if (minor_status) + *minor_status = 0; + if (status_string) { + status_string->length = 0; + status_string->value = NULL; + } + if (message_context) + *message_context = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/duplicate_cred.c b/third_party/heimdal/lib/gssapi/ntlm/duplicate_cred.c new file mode 100644 index 0000000..d05f9fa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/duplicate_cred.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2006-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_duplicate_cred(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + ntlm_const_cred cred = (ntlm_const_cred)input_cred_handle; + ntlm_cred new_cred; + OM_uint32 junk; + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) + return _gss_ntlm_acquire_cred_from(minor_status, GSS_C_NO_NAME, + GSS_C_INDEFINITE, GSS_C_NO_OID_SET, + GSS_C_BOTH, GSS_C_NO_CRED_STORE, + output_cred_handle, NULL, NULL); + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + *minor_status = _gss_ntlm_copy_cred((ntlm_cred)input_cred_handle, + (ntlm_cred *)output_cred_handle); + + return *minor_status == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/duplicate_name.c b/third_party/heimdal/lib/gssapi/ntlm/duplicate_name.c new file mode 100644 index 0000000..060fa55 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/duplicate_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_duplicate_name ( + OM_uint32 * minor_status, + gss_const_name_t src_name, + gss_name_t * dest_name + ) +{ + if (minor_status) + *minor_status = 0; + if (dest_name) + *dest_name = NULL; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/export_name.c b/third_party/heimdal/lib/gssapi/ntlm/export_name.c new file mode 100644 index 0000000..e5bdca4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/export_name.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1997, 1999, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_export_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name + ) +{ + if (minor_status) + *minor_status = 0; + if (exported_name) { + exported_name->length = 0; + exported_name->value = NULL; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/export_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/export_sec_context.c new file mode 100644 index 0000000..027a921 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/export_sec_context.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_export_sec_context ( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t interprocess_token + ) +{ + if (minor_status) + *minor_status = 0; + if (interprocess_token) { + interprocess_token->length = 0; + interprocess_token->value = NULL; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/external.c b/third_party/heimdal/lib/gssapi/ntlm/external.c new file mode 100644 index 0000000..ff2cd2d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/external.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +static gss_mo_desc ntlm_mo[] = { + { + GSS_C_MA_SASL_MECH_NAME, + GSS_MO_MA, + "SASL mech name", + rk_UNCONST("NTLM"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_NAME, + GSS_MO_MA, + "Mechanism name", + rk_UNCONST("NTLMSPP"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_DESCRIPTION, + GSS_MO_MA, + "Mechanism description", + rk_UNCONST("Heimdal NTLMSSP Mechanism"), + _gss_mo_get_ctx_as_string, + NULL + } +}; + +static gssapi_mech_interface_desc ntlm_mech = { + GMI_VERSION, + "ntlm", + {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") }, + 0, + NULL, + _gss_ntlm_release_cred, + _gss_ntlm_init_sec_context, + _gss_ntlm_accept_sec_context, + _gss_ntlm_process_context_token, + _gss_ntlm_delete_sec_context, + _gss_ntlm_context_time, + _gss_ntlm_get_mic, + _gss_ntlm_verify_mic, + _gss_ntlm_wrap, + _gss_ntlm_unwrap, + _gss_ntlm_display_status, + NULL, + _gss_ntlm_compare_name, + _gss_ntlm_display_name, + _gss_ntlm_import_name, + _gss_ntlm_export_name, + _gss_ntlm_release_name, + _gss_ntlm_inquire_cred, + _gss_ntlm_inquire_context, + _gss_ntlm_wrap_size_limit, + _gss_ntlm_add_cred, + _gss_ntlm_inquire_cred_by_mech, + _gss_ntlm_export_sec_context, + _gss_ntlm_import_sec_context, + _gss_ntlm_inquire_names_for_mech, + _gss_ntlm_inquire_mechs_for_name, + _gss_ntlm_canonicalize_name, + _gss_ntlm_duplicate_name, + _gss_ntlm_inquire_sec_context_by_oid, + NULL, + _gss_ntlm_set_sec_context_option, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _gss_ntlm_acquire_cred_from, + NULL, /* gm_acquire_cred_impersonate_name */ + _gss_ntlm_iter_creds_f, + _gss_ntlm_destroy_cred, + NULL, + NULL, + NULL, + NULL, + ntlm_mo, + sizeof(ntlm_mo) / sizeof(ntlm_mo[0]), + NULL, /* gm_localname */ + NULL, /* gm_authorize_localname */ + NULL, /* gm_display_name_ext */ + NULL, /* gm_inquire_name */ + NULL, /* gm_get_name_attribute */ + NULL, /* gm_set_name_attribute */ + NULL, /* gm_delete_name_attribute */ + NULL, /* gm_export_name_composite */ + NULL, /* gm_duplicate_cred */ + NULL, /* gm_add_cred_from */ + NULL, /* gm_store_cred_into */ + NULL, /* gm_query_mechanism_info */ + NULL, /* gm_query_meta_data */ + NULL, /* gm_exchange_meta_data */ + NULL, /* gm_store_cred_into2 */ + NULL, /* gm_compat */ +}; + +gssapi_mech_interface +__gss_ntlm_initialize(void) +{ + return &ntlm_mech; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/import_name.c b/third_party/heimdal/lib/gssapi/ntlm/import_name.c new file mode 100644 index 0000000..e75388d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/import_name.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_import_name + (OM_uint32 * minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t * output_name + ) +{ + char *name, *p, *p2; + int is_hostnamed; + int is_username; + ntlm_name n; + + *minor_status = 0; + + if (output_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *output_name = GSS_C_NO_NAME; + + is_hostnamed = gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE); + is_username = gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME); + + if (!is_hostnamed && !is_username) + return GSS_S_BAD_NAMETYPE; + + name = malloc(input_name_buffer->length + 1); + if (name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(name, input_name_buffer->value, input_name_buffer->length); + name[input_name_buffer->length] = '\0'; + + /* find "domain" part of the name and uppercase it */ + p = strchr(name, '@'); + if (p == NULL) { + free(name); + return GSS_S_BAD_NAME; + } + p[0] = '\0'; + p++; + p2 = strchr(p, '.'); + if (p2 && p2[1] != '\0') { + if (is_hostnamed) { + p = p2 + 1; + p2 = strchr(p, '.'); + } + if (p2) + *p2 = '\0'; + } + strupr(p); + + n = calloc(1, sizeof(*n)); + if (n == NULL) { + free(name); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + n->user = strdup(name); + n->domain = strdup(p); + + free(name); + + if (n->user == NULL || n->domain == NULL) { + free(n->user); + free(n->domain); + free(n); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *output_name = (gss_name_t)n; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/import_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/import_sec_context.c new file mode 100644 index 0000000..fe637c0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/import_sec_context.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_import_sec_context ( + OM_uint32 * minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t * context_handle + ) +{ + if (minor_status) + *minor_status = 0; + if (context_handle) + *context_handle = GSS_C_NO_CONTEXT; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/indicate_mechs.c b/third_party/heimdal/lib/gssapi/ntlm/indicate_mechs.c new file mode 100644 index 0000000..7cda475 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/indicate_mechs.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 _gss_ntlm_indicate_mechs +(OM_uint32 * minor_status, + gss_OID_set * mech_set + ) +{ + if (minor_status) + *minor_status = 0; + if (mech_set) + *mech_set = GSS_C_NO_OID_SET; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c b/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c new file mode 100644 index 0000000..be9c987 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/init_sec_context.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +static int +from_file(const char *fn, const char *target_domain, + char **domainp, char **usernamep, struct ntlm_buf *key) +{ + char *str, buf[1024]; + FILE *f; + + *domainp = NULL; + + f = fopen(fn, "r"); + if (f == NULL) + return ENOENT; + rk_cloexec_file(f); + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *d, *u, *p; + buf[strcspn(buf, "\r\n")] = '\0'; + if (buf[0] == '#') + continue; + str = NULL; + d = strtok_r(buf, ":", &str); + free(*domainp); + *domainp = NULL; + if (!d) + continue; + if (d && target_domain != NULL && strcasecmp(target_domain, d) != 0) + continue; + *domainp = strdup(d); + if (*domainp == NULL) { + fclose(f); + return ENOMEM; + } + u = strtok_r(NULL, ":", &str); + p = strtok_r(NULL, ":", &str); + if (u == NULL || p == NULL) + continue; + + *usernamep = strdup(u); + if (*usernamep == NULL) { + fclose(f); + return ENOMEM; + } + heim_ntlm_nt_key(p, key); + + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + fclose(f); + return 0; + } + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + fclose(f); + return ENOENT; +} + +static int +get_user_file(const ntlm_name target_name, + char **domainp, char **usernamep, struct ntlm_buf *key) +{ + const char *domain; + const char *fn; + + *domainp = NULL; + + domain = target_name != NULL ? target_name->domain : NULL; + + fn = secure_getenv("NTLM_USER_FILE"); + if (fn == NULL) + return ENOENT; + if (from_file(fn, domain, domainp, usernamep, key) == 0) + return 0; + + return ENOENT; +} + +/* + * Pick up the ntlm cred from the default krb5 credential cache. + */ + +static int +get_user_ccache(const ntlm_name name, char **domainp, char **usernamep, struct ntlm_buf *key) +{ + krb5_context context = NULL; + krb5_principal client; + krb5_ccache id = NULL; + krb5_error_code ret; + char *confname; + krb5_data data; + int aret; + + *domainp = NULL; + *usernamep = NULL; + krb5_data_zero(&data); + key->length = 0; + key->data = NULL; + + ret = krb5_init_context(&context); + if (ret) + return ret; + + ret = krb5_cc_default(context, &id); + if (ret) + goto out; + + ret = krb5_cc_get_principal(context, id, &client); + if (ret) + goto out; + + ret = krb5_unparse_name_flags(context, client, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, + usernamep); + krb5_free_principal(context, client); + if (ret) + goto out; + + if (name != NULL) { + *domainp = strdup(name->domain); + } else { + krb5_data data_domain; + + krb5_data_zero(&data_domain); + ret = krb5_cc_get_config(context, id, NULL, "default-ntlm-domain", + &data_domain); + if (ret) + goto out; + + *domainp = strndup(data_domain.data, data_domain.length); + krb5_data_free(&data_domain); + } + + if (*domainp == NULL) { + ret = krb5_enomem(context); + goto out; + } + + aret = asprintf(&confname, "ntlm-key-%s", *domainp); + if (aret == -1) { + ret = krb5_enomem(context); + goto out; + } + + ret = krb5_cc_get_config(context, id, NULL, confname, &data); + if (ret) + goto out; + + key->data = malloc(data.length); + if (key->data == NULL) { + ret = ENOMEM; + goto out; + } + key->length = data.length; + memcpy(key->data, data.data, data.length); + + out: + krb5_data_free(&data); + if (id) + krb5_cc_close(context, id); + + krb5_free_context(context); + + return ret; +} + +int +_gss_ntlm_get_user_cred(const ntlm_name target_name, + ntlm_cred *rcred) +{ + ntlm_cred cred; + int ret; + + cred = calloc(1, sizeof(*cred)); + if (cred == NULL) + return ENOMEM; + + ret = get_user_file(target_name, + &cred->domain, &cred->username, &cred->key); + if (ret) + ret = get_user_ccache(target_name, + &cred->domain, &cred->username, &cred->key); + if (ret) { + OM_uint32 tmp; + _gss_ntlm_release_cred(&tmp, (gss_cred_id_t *)&cred); + return ret; + } + + *rcred = cred; + + return ret; +} + +int +_gss_ntlm_copy_cred(ntlm_cred from, ntlm_cred *to) +{ + *to = calloc(1, sizeof(**to)); + if (*to == NULL) + return ENOMEM; + (*to)->usage = from->usage; + (*to)->username = strdup(from->username); + if ((*to)->username == NULL) { + free(*to); + return ENOMEM; + } + (*to)->domain = strdup(from->domain); + if ((*to)->domain == NULL) { + free((*to)->username); + free(*to); + return ENOMEM; + } + (*to)->key.data = malloc(from->key.length); + if ((*to)->key.data == NULL) { + free((*to)->domain); + free((*to)->username); + free(*to); + return ENOMEM; + } + memcpy((*to)->key.data, from->key.data, from->key.length); + (*to)->key.length = from->key.length; + + return 0; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_init_sec_context + (OM_uint32 * minor_status, + gss_const_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + ntlm_ctx ctx; + ntlm_name name = (ntlm_name)target_name; + + *minor_status = 0; + + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + if (actual_mech_type) + *actual_mech_type = GSS_C_NO_OID; + + if (*context_handle == GSS_C_NO_CONTEXT) { + struct ntlm_type1 type1; + struct ntlm_buf data; + uint32_t flags = 0; + int ret; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + ctx->status = STATUS_CLIENT; + *context_handle = (gss_ctx_id_t)ctx; + + if (initiator_cred_handle != GSS_C_NO_CREDENTIAL) { + ntlm_cred cred = (ntlm_cred)initiator_cred_handle; + ret = _gss_ntlm_copy_cred(cred, &ctx->client); + } else + ret = _gss_ntlm_get_user_cred(name, &ctx->client); + + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (req_flags & GSS_C_CONF_FLAG) + flags |= NTLM_NEG_SEAL; + if (req_flags & GSS_C_INTEG_FLAG) + flags |= NTLM_NEG_SIGN; + else + flags |= NTLM_NEG_ALWAYS_SIGN; + + flags |= NTLM_NEG_UNICODE; + flags |= NTLM_NEG_NTLM; + flags |= NTLM_NEG_NTLM2_SESSION; + flags |= NTLM_NEG_KEYEX; + + memset(&type1, 0, sizeof(type1)); + + type1.flags = flags; + type1.domain = name->domain; + type1.hostname = NULL; + type1.os[0] = 0; + type1.os[1] = 0; + + ret = heim_ntlm_encode_type1(&type1, &data); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_token->value = data.data; + output_token->length = data.length; + + return GSS_S_CONTINUE_NEEDED; + } else { + krb5_error_code ret; + struct ntlm_type2 type2; + struct ntlm_type3 type3; + struct ntlm_buf data; + + ctx = (ntlm_ctx)*context_handle; + + data.data = input_token->value; + data.length = input_token->length; + + ret = heim_ntlm_decode_type2(&data, &type2); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + ctx->flags = type2.flags; + + /* XXX check that type2.targetinfo matches `target_name´ */ + /* XXX check verify targetinfo buffer */ + + memset(&type3, 0, sizeof(type3)); + + type3.username = ctx->client->username; + type3.flags = type2.flags; + type3.targetname = type2.targetname; + type3.ws = rk_UNCONST("workstation"); + + /* + * NTLM Version 1 if no targetinfo buffer. + */ + + if (1 || type2.targetinfo.length == 0) { + struct ntlm_buf sessionkey; + + if (type2.flags & NTLM_NEG_NTLM2_SESSION) { + unsigned char nonce[8]; + + if (RAND_bytes(nonce, sizeof(nonce)) != 1) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_calculate_ntlm2_sess(nonce, + type2.challenge, + ctx->client->key.data, + &type3.lm, + &type3.ntlm); + } else { + ret = heim_ntlm_calculate_ntlm1(ctx->client->key.data, + ctx->client->key.length, + type2.challenge, + &type3.ntlm); + + } + if (ret) { + _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_build_ntlm1_master(ctx->client->key.data, + ctx->client->key.length, + &sessionkey, + &type3.sessionkey); + if (ret) { + if (type3.lm.data) + free(type3.lm.data); + if (type3.ntlm.data) + free(type3.ntlm.data); + _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_data_copy(&ctx->sessionkey, + sessionkey.data, sessionkey.length); + free(sessionkey.data); + if (ret) { + if (type3.lm.data) + free(type3.lm.data); + if (type3.ntlm.data) + free(type3.ntlm.data); + _gss_ntlm_delete_sec_context(minor_status,context_handle,NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + ctx->status |= STATUS_SESSIONKEY; + + } else { + struct ntlm_buf sessionkey; + unsigned char ntlmv2[16]; + struct ntlm_targetinfo ti; + + /* verify infotarget */ + + ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti); + if(ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data, + ctx->client->key.length, + ctx->client->username, + name->domain, + type2.challenge, + &type2.targetinfo, + ntlmv2, + &type3.ntlm); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2), + &sessionkey, + &type3.sessionkey); + memset_s(ntlmv2, sizeof(ntlmv2), 0, sizeof(ntlmv2)); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ctx->flags |= NTLM_NEG_NTLM2_SESSION; + + ret = krb5_data_copy(&ctx->sessionkey, + sessionkey.data, sessionkey.length); + free(sessionkey.data); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + } + + + _gss_ntlm_set_keys(ctx); + + + ret = heim_ntlm_encode_type3(&type3, &data, NULL); + free(type3.sessionkey.data); + if (type3.lm.data) + free(type3.lm.data); + if (type3.ntlm.data) + free(type3.ntlm.data); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL); + heim_ntlm_free_type2(&type2); + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_token->length = data.length; + output_token->value = data.data; + + if (actual_mech_type) + *actual_mech_type = GSS_NTLM_MECHANISM; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + + ctx->status |= STATUS_OPEN; + + heim_ntlm_free_type2(&type2); + return GSS_S_COMPLETE; + } +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/inquire_context.c b/third_party/heimdal/lib/gssapi/ntlm/inquire_context.c new file mode 100644 index 0000000..741ad6e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/inquire_context.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_context ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t * src_name, + gss_name_t * targ_name, + OM_uint32 * lifetime_rec, + gss_OID * mech_type, + OM_uint32 * ctx_flags, + int * locally_initiated, + int * open_context + ) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + + *minor_status = 0; + if (src_name) + *src_name = GSS_C_NO_NAME; + if (targ_name) + *targ_name = GSS_C_NO_NAME; + if (lifetime_rec) + *lifetime_rec = GSS_C_INDEFINITE; + if (mech_type) + *mech_type = GSS_NTLM_MECHANISM; + if (ctx_flags) + *ctx_flags = ctx->gssflags; + if (locally_initiated) + *locally_initiated = (ctx->status & STATUS_CLIENT) ? 1 : 0; + if (open_context) + *open_context = (ctx->status & STATUS_OPEN) ? 1 : 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/ntlm/inquire_cred_by_mech.c new file mode 100644 index 0000000..ed42094 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/inquire_cred_by_mech.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_cred_by_mech ( + OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t * name, + OM_uint32 * initiator_lifetime, + OM_uint32 * acceptor_lifetime, + gss_cred_usage_t * cred_usage + ) +{ + if (minor_status) + *minor_status = 0; + if (name) + *name = GSS_C_NO_NAME; + if (initiator_lifetime) + *initiator_lifetime = 0; + if (acceptor_lifetime) + *acceptor_lifetime = 0; + if (cred_usage) + *cred_usage = 0; + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/ntlm/inquire_mechs_for_name.c new file mode 100644 index 0000000..25450ab --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/inquire_mechs_for_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_mechs_for_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_OID_set * mech_types + ) +{ + if (minor_status) + *minor_status = 0; + if (mech_types) + *mech_types = GSS_C_NO_OID_SET; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/ntlm/inquire_names_for_mech.c new file mode 100644 index 0000000..7f49b33 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/inquire_names_for_mech.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_names_for_mech ( + OM_uint32 * minor_status, + const gss_OID mechanism, + gss_OID_set * name_types + ) +{ + OM_uint32 ret; + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/inquire_sec_context_by_oid.c b/third_party/heimdal/lib/gssapi/ntlm/inquire_sec_context_by_oid.c new file mode 100644 index 0000000..2b42b1f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/inquire_sec_context_by_oid.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_inquire_sec_context_by_oid(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + ntlm_ctx ctx = (ntlm_ctx)context_handle; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + if (gss_oid_equal(desired_object, GSS_NTLM_GET_SESSION_KEY_X) || + gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) { + gss_buffer_desc value; + + value.length = ctx->sessionkey.length; + value.value = ctx->sessionkey.data; + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); + } else if (gss_oid_equal(desired_object, GSS_C_INQ_WIN2K_PAC_X)) { + if (ctx->pac.length == 0) { + *minor_status = ENOENT; + return GSS_S_FAILURE; + } + + return gss_add_buffer_set_member(minor_status, + &ctx->pac, + data_set); + + } else if (gss_oid_equal(desired_object, GSS_C_NTLM_AVGUEST)) { + gss_buffer_desc value; + uint32_t num; + + if (ctx->kcmflags & KCM_NTLM_FLAG_AV_GUEST) + num = 1; + else + num = 0; + + value.length = sizeof(num); + value.value = # + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); + } else { + *minor_status = 0; + return GSS_S_FAILURE; + } +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/iter_cred.c b/third_party/heimdal/lib/gssapi/ntlm/iter_cred.c new file mode 100644 index 0000000..ee5ec17 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/iter_cred.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +void GSSAPI_CALLCONV +_gss_ntlm_iter_creds_f(OM_uint32 flags, + void *userctx , + void (*cred_iter)(void *, gss_OID, gss_cred_id_t)) +{ +#ifdef HAVE_KCM + krb5_error_code ret; + krb5_context context = NULL; + krb5_storage *request, *response; + krb5_data response_data; + + ret = krb5_init_context(&context); + if (ret) + goto done; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_NTLM_USER_LIST, &request); + if (ret) + goto done; + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret) + goto done; + + while (1) { + uint32_t morep; + char *user = NULL, *domain = NULL; + ntlm_cred dn; + + ret = krb5_ret_uint32(response, &morep); + if (ret) goto out; + + if (!morep) goto out; + + ret = krb5_ret_stringz(response, &user); + if (ret) goto out; + ret = krb5_ret_stringz(response, &domain); + if (ret) { + free(user); + goto out; + } + + dn = calloc(1, sizeof(*dn)); + if (dn == NULL) { + free(user); + free(domain); + goto out; + } + dn->username = user; + dn->domain = domain; + + cred_iter(userctx, GSS_NTLM_MECHANISM, (gss_cred_id_t)dn); + } + out: + krb5_storage_free(response); + krb5_data_free(&response_data); + done: + if (context) + krb5_free_context(context); +#endif /* HAVE_KCM */ + (*cred_iter)(userctx, NULL, NULL); +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/kdc.c b/third_party/heimdal/lib/gssapi/ntlm/kdc.c new file mode 100644 index 0000000..10aa2b9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/kdc.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +#ifdef DIGEST + +/* + * + */ + +struct ntlmkrb5 { + krb5_context context; + krb5_ntlm ntlm; + krb5_realm kerberos_realm; + krb5_ccache id; + krb5_data opaque; + int destroy; + OM_uint32 flags; + struct ntlm_buf key; + krb5_data sessionkey; +}; + +static OM_uint32 kdc_destroy(OM_uint32 *, void *); + +/* + * Get credential cache that the ntlm code can use to talk to the KDC + * using the digest API. + */ + +static krb5_error_code +get_ccache(krb5_context context, int *destroy, krb5_ccache *id) +{ + krb5_principal principal = NULL; + krb5_error_code ret; + krb5_keytab kt = NULL; + const char *cache = secure_getenv("NTLM_ACCEPTOR_CCACHE"); + + *id = NULL; + + if (cache) { + ret = krb5_cc_resolve(context, cache, id); + if (ret) + goto out; + return 0; + } + + ret = krb5_sname_to_principal(context, NULL, "host", + KRB5_NT_SRV_HST, &principal); + if (ret) + goto out; + + ret = krb5_cc_cache_match(context, principal, id); + if (ret == 0) + goto out; + + /* did not find in default credcache, lets try default keytab */ + ret = krb5_kt_default(context, &kt); + if (ret) + goto out; + + /* XXX check in keytab */ + { + krb5_get_init_creds_opt *opt; + krb5_creds cred; + + memset(&cred, 0, sizeof(cred)); + + ret = krb5_cc_new_unique(context, "MEMORY", NULL, id); + if (ret) + goto out; + *destroy = 1; + ret = krb5_get_init_creds_opt_alloc(context, &opt); + if (ret) + goto out; + ret = krb5_get_init_creds_keytab (context, + &cred, + principal, + kt, + 0, + NULL, + opt); + krb5_get_init_creds_opt_free(context, opt); + if (ret) + goto out; + ret = krb5_cc_initialize (context, *id, cred.client); + if (ret) { + krb5_free_cred_contents (context, &cred); + goto out; + } + ret = krb5_cc_store_cred (context, *id, &cred); + krb5_free_cred_contents (context, &cred); + if (ret) + goto out; + } + + krb5_kt_close(context, kt); + + return 0; + +out: + if (*id) { + if (*destroy) + krb5_cc_destroy(context, *id); + else + krb5_cc_close(context, *id); + *id = NULL; + } + + if (kt) + krb5_kt_close(context, kt); + + if (principal) + krb5_free_principal(context, principal); + return ret; +} + +/* + * + */ + +static OM_uint32 +kdc_alloc(OM_uint32 *minor, void **ctx) +{ + krb5_error_code ret; + struct ntlmkrb5 *c; + OM_uint32 junk; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + ret = krb5_init_context(&c->context); + if (ret) { + kdc_destroy(&junk, c); + *minor = ret; + return GSS_S_FAILURE; + } + + ret = get_ccache(c->context, &c->destroy, &c->id); + if (ret) { + kdc_destroy(&junk, c); + *minor = ret; + return GSS_S_FAILURE; + } + + ret = krb5_ntlm_alloc(c->context, &c->ntlm); + if (ret) { + kdc_destroy(&junk, c); + *minor = ret; + return GSS_S_FAILURE; + } + + *ctx = c; + + return GSS_S_COMPLETE; +} + +static int +kdc_probe(OM_uint32 *minor, void *ctx, const char *realm) +{ + struct ntlmkrb5 *c = ctx; + krb5_error_code ret; + unsigned flags; + + ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags); + if (ret) + return ret; + + if ((flags & (1|2|4)) == 0) + return EINVAL; + + return 0; +} + +/* + * + */ + +static OM_uint32 +kdc_destroy(OM_uint32 *minor, void *ctx) +{ + struct ntlmkrb5 *c = ctx; + krb5_data_free(&c->opaque); + krb5_data_free(&c->sessionkey); + if (c->ntlm) + krb5_ntlm_free(c->context, c->ntlm); + if (c->id) { + if (c->destroy) + krb5_cc_destroy(c->context, c->id); + else + krb5_cc_close(c->context, c->id); + } + if (c->context) + krb5_free_context(c->context); + memset(c, 0, sizeof(*c)); + free(c); + + return GSS_S_COMPLETE; +} + +/* + * + */ + +static OM_uint32 +kdc_type2(OM_uint32 *minor_status, + void *ctx, + uint32_t flags, + const char *hostname, + const char *domain, + uint32_t *ret_flags, + struct ntlm_buf *out) +{ + struct ntlmkrb5 *c = ctx; + krb5_error_code ret; + struct ntlm_type2 type2; + krb5_data challenge; + struct ntlm_buf data; + krb5_data ti; + + memset(&type2, 0, sizeof(type2)); + memset(out, 0, sizeof(*out)); + + /* + * Request data for type 2 packet from the KDC. + */ + ret = krb5_ntlm_init_request(c->context, + c->ntlm, + NULL, + c->id, + flags, + hostname, + domain); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* + * + */ + + ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* + * + */ + + ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + *ret_flags = type2.flags; + + ret = krb5_ntlm_init_get_challenge(c->context, c->ntlm, &challenge); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (challenge.length != sizeof(type2.challenge)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + memcpy(type2.challenge, challenge.data, sizeof(type2.challenge)); + krb5_data_free(&challenge); + + ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm, + &type2.targetname); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti); + if (ret) { + free(type2.targetname); + *minor_status = ret; + return GSS_S_FAILURE; + } + + type2.targetinfo.data = ti.data; + type2.targetinfo.length = ti.length; + + ret = heim_ntlm_encode_type2(&type2, &data); + free(type2.targetname); + krb5_data_free(&ti); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + out->data = data.data; + out->length = data.length; + + return GSS_S_COMPLETE; +} + +/* + * + */ + +static OM_uint32 +kdc_type3(OM_uint32 *minor_status, + void *ctx, + const struct ntlm_type3 *type3, + struct ntlm_buf *sessionkey) +{ + struct ntlmkrb5 *c = ctx; + krb5_error_code ret; + + sessionkey->data = NULL; + sessionkey->length = 0; + + ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags); + if (ret) goto out; + ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username); + if (ret) goto out; + ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm, + type3->targetname); + if (ret) goto out; + ret = krb5_ntlm_req_set_lm(c->context, c->ntlm, + type3->lm.data, type3->lm.length); + if (ret) goto out; + ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm, + type3->ntlm.data, type3->ntlm.length); + if (ret) goto out; + ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque); + if (ret) goto out; + + if (type3->sessionkey.length) { + ret = krb5_ntlm_req_set_session(c->context, c->ntlm, + type3->sessionkey.data, + type3->sessionkey.length); + if (ret) goto out; + } + + /* + * Verify with the KDC the type3 packet is ok + */ + ret = krb5_ntlm_request(c->context, + c->ntlm, + NULL, + c->id); + if (ret) + goto out; + + if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) { + ret = EINVAL; + goto out; + } + + if (type3->sessionkey.length) { + ret = krb5_ntlm_rep_get_sessionkey(c->context, + c->ntlm, + &c->sessionkey); + if (ret) + goto out; + + sessionkey->data = c->sessionkey.data; + sessionkey->length = c->sessionkey.length; + } + + return 0; + + out: + *minor_status = ret; + return GSS_S_FAILURE; +} + +/* + * + */ + +static void +kdc_free_buffer(struct ntlm_buf *sessionkey) +{ + if (sessionkey->data) + free(sessionkey->data); + sessionkey->data = NULL; + sessionkey->length = 0; +} + +/* + * + */ + +struct ntlm_server_interface ntlmsspi_kdc_digest = { + kdc_alloc, + kdc_destroy, + kdc_probe, + kdc_type2, + kdc_type3, + kdc_free_buffer +}; + +#endif /* DIGEST */ diff --git a/third_party/heimdal/lib/gssapi/ntlm/ntlm.h b/third_party/heimdal/lib/gssapi/ntlm/ntlm.h new file mode 100644 index 0000000..7b16aa2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/ntlm.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2006-2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef NTLM_NTLM_H +#define NTLM_NTLM_H + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define HC_DEPRECATED_CRYPTO +#include "crypto-headers.h" + +typedef OM_uint32 +(*ntlm_interface_init)(OM_uint32 *, void **); + +typedef OM_uint32 +(*ntlm_interface_destroy)(OM_uint32 *, void *); + +typedef int +(*ntlm_interface_probe)(OM_uint32 *, void *, const char *); + +typedef OM_uint32 +(*ntlm_interface_type2)(OM_uint32 *, void *, uint32_t, const char *, + const char *, uint32_t *, struct ntlm_buf *); + +typedef OM_uint32 +(*ntlm_interface_type3)(OM_uint32 *, void *, const struct ntlm_type3 *, + struct ntlm_buf *); + +typedef void +(*ntlm_interface_free_buffer)(struct ntlm_buf *); + +struct ntlm_server_interface { + ntlm_interface_init nsi_init; + ntlm_interface_destroy nsi_destroy; + ntlm_interface_probe nsi_probe; + ntlm_interface_type2 nsi_type2; + ntlm_interface_type3 nsi_type3; + ntlm_interface_free_buffer nsi_free_buffer; +}; + + +struct ntlmv2_key { + uint32_t seq; + RC4_KEY sealkey; + RC4_KEY *signsealkey; + unsigned char signkey[16]; +}; + +extern struct ntlm_server_interface ntlmsspi_kdc_digest; + +typedef struct ntlm_cred { + gss_cred_usage_t usage; + char *username; + char *domain; + struct ntlm_buf key; +} *ntlm_cred; +typedef const struct ntlm_cred *ntlm_const_cred; + +typedef struct { + struct ntlm_server_interface *server; + void *ictx; + ntlm_cred client; + OM_uint32 gssflags; + uint32_t kcmflags; + uint32_t flags; + uint32_t status; +#define STATUS_OPEN 1 +#define STATUS_CLIENT 2 +#define STATUS_SESSIONKEY 4 + krb5_data sessionkey; + + gss_buffer_desc pac; + + union { + struct { + struct { + uint32_t seq; + RC4_KEY key; + } crypto_send, crypto_recv; + } v1; + struct { + struct ntlmv2_key send, recv; + } v2; + } u; +} *ntlm_ctx; + +typedef struct { + char *user; + char *domain; +} *ntlm_name; + +#include + + +#endif /* NTLM_NTLM_H */ diff --git a/third_party/heimdal/lib/gssapi/ntlm/process_context_token.c b/third_party/heimdal/lib/gssapi/ntlm/process_context_token.c new file mode 100644 index 0000000..2add53b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/process_context_token.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_process_context_token ( + OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer + ) +{ + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/release_cred.c b/third_party/heimdal/lib/gssapi/ntlm/release_cred.c new file mode 100644 index 0000000..e31a316 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/release_cred.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV _gss_ntlm_release_cred + (OM_uint32 * minor_status, + gss_cred_id_t * cred_handle + ) +{ + ntlm_cred cred; + + if (minor_status) + *minor_status = 0; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_COMPLETE; + + cred = (ntlm_cred)*cred_handle; + *cred_handle = GSS_C_NO_CREDENTIAL; + + if (cred->username) + free(cred->username); + if (cred->domain) + free(cred->domain); + if (cred->key.data) { + memset(cred->key.data, 0, cred->key.length); + free(cred->key.data); + } + + memset(cred, 0, sizeof(*cred)); + free(cred); + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/ntlm/release_name.c b/third_party/heimdal/lib/gssapi/ntlm/release_name.c new file mode 100644 index 0000000..4a5c56d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/release_name.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_release_name + (OM_uint32 * minor_status, + gss_name_t * input_name + ) +{ + if (minor_status) + *minor_status = 0; + if (input_name && *input_name) { + ntlm_name n = (ntlm_name)*input_name; + *input_name = GSS_C_NO_NAME; + free(n->user); + free(n->domain); + free(n); + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/ntlm/set_sec_context_option.c b/third_party/heimdal/lib/gssapi/ntlm/set_sec_context_option.c new file mode 100644 index 0000000..f97443d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/ntlm/set_sec_context_option.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ntlm.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_ntlm_set_sec_context_option(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID object, + const gss_buffer_t value) +{ + ntlm_ctx ctx; + + if (context_handle == NULL) + return GSS_S_UNAVAILABLE; + + *minor_status = 0; + + ctx = (ntlm_ctx)*context_handle; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + + if (gss_oid_equal(object, GSS_C_NTLM_RESET_CRYPTO)) { + _gss_ntlm_set_keys(ctx); + return GSS_S_COMPLETE; + } else + return GSS_S_UNAVAILABLE; +} diff --git a/third_party/heimdal/lib/gssapi/oid.txt b/third_party/heimdal/lib/gssapi/oid.txt new file mode 100644 index 0000000..fa210d6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/oid.txt @@ -0,0 +1,173 @@ +# /* +# * Contact Love Hörnquist Åstrand for new oid arcs */ +# */ +# /* +# * 1.2.752.43 is SU's arc. SU's registry has arcs 13, 14, and 16 +# * below that registered for Heimdal to use. The Heimdal source tree +# * is the authoritative registry for Heimdal's three arcs off of SU's arc. +# * This file is the authoritative registry for 1.2.752.43.13 and 1.2.752.14. +# * ASN.1 modules in lib/asn1/ are authoritative for 1.2.752.43.16. +# * +# * Confirmed by SU's erstwhile registrar, Leif Johansson , +# * as well as by SU's current registrar (through Leif), as: +# * +# * 1.2.752.43.13 Namn Heimdal GSS-API extentions +# * Beskrivning OIDar för användning av Heimdal projektet +# * 1.2.752.43.14 Namn Heimdal GSS-API mechs +# * Beskrivning OIDar för användning av Heimdal projektet +# * 1.2.752.43.16 Namn Heimdal Internal crypto ops +# * Beskrivning OIDar för användning av Heimdal projektet +# * +# * 1.2.752.43.16 is now also used in Heimdal for PKIX-related things. +# * See lib/asn1/ and lib/hx509/. +# * +# * Contact the SU registrar for new oid arcs if any are needed, or carve +# * out an arc of one of the above, preferably off 1.2.752.43.16. +# */ + +# /* +# * 1.2.752.43.13 Heimdal GSS-API Extensions +# */ + +oid base GSS_KRB5_COPY_CCACHE_X 1.2.752.43.13.1 +oid base GSS_KRB5_GET_TKT_FLAGS_X 1.2.752.43.13.2 +oid base GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X 1.2.752.43.13.3 +oid base GSS_KRB5_COMPAT_DES3_MIC_X 1.2.752.43.13.4 +oid base GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X 1.2.752.43.13.5 +oid base GSS_KRB5_EXPORT_LUCID_CONTEXT_X 1.2.752.43.13.6 +oid base GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X 1.2.752.43.13.6.1 +oid base GSS_KRB5_SET_DNS_CANONICALIZE_X 1.2.752.43.13.7 +oid base GSS_KRB5_GET_SUBKEY_X 1.2.752.43.13.8 +oid base GSS_KRB5_GET_INITIATOR_SUBKEY_X 1.2.752.43.13.9 +oid base GSS_KRB5_GET_ACCEPTOR_SUBKEY_X 1.2.752.43.13.10 +oid base GSS_KRB5_SEND_TO_KDC_X 1.2.752.43.13.11 +oid base GSS_KRB5_GET_AUTHTIME_X 1.2.752.43.13.12 +oid base GSS_KRB5_GET_SERVICE_KEYBLOCK_X 1.2.752.43.13.13 +oid base GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X 1.2.752.43.13.14 +oid base GSS_KRB5_SET_DEFAULT_REALM_X 1.2.752.43.13.15 +oid base GSS_KRB5_CCACHE_NAME_X 1.2.752.43.13.16 +oid base GSS_KRB5_SET_TIME_OFFSET_X 1.2.752.43.13.17 +oid base GSS_KRB5_GET_TIME_OFFSET_X 1.2.752.43.13.18 +oid base GSS_KRB5_PLUGIN_REGISTER_X 1.2.752.43.13.19 +oid base GSS_NTLM_GET_SESSION_KEY_X 1.2.752.43.13.20 +oid base GSS_C_NT_NTLM 1.2.752.43.13.21 +oid base GSS_C_NT_DN 1.2.752.43.13.22 +oid base GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL 1.2.752.43.13.23 +oid base GSS_C_NTLM_AVGUEST 1.2.752.43.13.24 +oid base GSS_C_NTLM_V1 1.2.752.43.13.25 +oid base GSS_C_NTLM_V2 1.2.752.43.13.26 +oid base GSS_C_NTLM_SESSION_KEY 1.2.752.43.13.27 +oid base GSS_C_NTLM_FORCE_V1 1.2.752.43.13.28 +oid base GSS_KRB5_CRED_NO_CI_FLAGS_X 1.2.752.43.13.29 +oid base GSS_KRB5_IMPORT_CRED_X 1.2.752.43.13.30 +oid base GSS_KRB5_IMPORT_RFC4121_CONTEXT_X 1.2.752.43.13.31 + +# /* glue for gss_inquire_saslname_for_mech */ +oid base GSS_C_MA_SASL_MECH_NAME 1.2.752.43.13.100 +oid base GSS_C_MA_MECH_NAME 1.2.752.43.13.101 +oid base GSS_C_MA_MECH_DESCRIPTION 1.2.752.43.13.102 + +#/* Heimdal mechanisms - 1.2.752.43.14 */ + +oid base GSS_SASL_DIGEST_MD5_MECHANISM 1.2.752.43.14.1 +oid base GSS_NETLOGON_MECHANISM 1.2.752.43.14.2 +oid base GSS_NETLOGON_SET_SESSION_KEY_X 1.2.752.43.14.3 +oid base GSS_NETLOGON_SET_SIGN_ALGORITHM_X 1.2.752.43.14.4 +oid base GSS_NETLOGON_NT_NETBIOS_DNS_NAME 1.2.752.43.14.5 + +#/* GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X.128 */ +oid base GSS_C_INQ_WIN2K_PAC_X 1.2.752.43.13.3.128 +oid base GSS_C_INQ_SSPI_SESSION_KEY 1.2.840.113554.1.2.2.5.5 +oid base GSS_C_INQ_NEGOEX_KEY 1.2.840.113554.1.2.2.5.16 +oid base GSS_C_INQ_NEGOEX_VERIFY_KEY 1.2.840.113554.1.2.2.5.17 +oid base GSS_C_INQ_REQUIRE_MECHLIST_MIC 1.3.6.1.4.1.7165.655.1.2 + +#/* +# * "Standard" mechs +# */ + +oid base GSS_KRB5_MECHANISM 1.2.840.113554.1.2.2 +oid base GSS_NTLM_MECHANISM 1.3.6.1.4.1.311.2.2.10 +oid base GSS_SPNEGO_MECHANISM 1.3.6.1.5.5.2 + +# /* From Luke Howard */ + +oid base GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO 1.3.6.1.4.1.5322.19.6 +oid base GSS_C_NTLM_RESET_CRYPTO 1.3.6.1.4.1.7165.655.1.3 +oid base GSS_NEGOEX_MECHANISM 1.3.6.1.4.1.311.2.2.30 +oid base GSS_SANON_X25519_MECHANISM 1.3.6.1.4.1.5322.26.1.110 + +#/* +# * OID mappings with name and short description and and slightly longer description +# */ + +desc mech GSS_KRB5_MECHANISM "Kerberos 5" "Heimdal Kerberos 5 mechanism" +desc mech GSS_NTLM_MECHANISM "NTLM" "Heimdal NTLM mechanism" +desc mech GSS_SPNEGO_MECHANISM "SPNEGO" "Heimdal SPNEGO mechanism" +desc mech GSS_SANON_X25519_MECHANISM "SAnon-X25519" "Heimdal Simple Anonymous (X25519) mechanism" + +desc ma GSS_C_MA_MECH_NAME "GSS mech name" "The name of the GSS-API mechanism" +desc ma GSS_C_MA_SASL_MECH_NAME "SASL mechanism name" "The name of the SASL mechanism" +desc ma GSS_C_MA_MECH_DESCRIPTION "Mech description" "The long description of the mechanism" + +#/* +# * RFC5587 +# */ + +oid base GSS_C_MA_MECH_CONCRETE 1.3.6.1.5.5.13.1 +oid base GSS_C_MA_MECH_PSEUDO 1.3.6.1.5.5.13.2 +oid base GSS_C_MA_MECH_COMPOSITE 1.3.6.1.5.5.13.3 +oid base GSS_C_MA_MECH_NEGO 1.3.6.1.5.5.13.4 +oid base GSS_C_MA_MECH_GLUE 1.3.6.1.5.5.13.5 +oid base GSS_C_MA_NOT_MECH 1.3.6.1.5.5.13.6 +oid base GSS_C_MA_DEPRECATED 1.3.6.1.5.5.13.7 +oid base GSS_C_MA_NOT_DFLT_MECH 1.3.6.1.5.5.13.8 +oid base GSS_C_MA_ITOK_FRAMED 1.3.6.1.5.5.13.9 +oid base GSS_C_MA_AUTH_INIT 1.3.6.1.5.5.13.10 +oid base GSS_C_MA_AUTH_TARG 1.3.6.1.5.5.13.11 +oid base GSS_C_MA_AUTH_INIT_INIT 1.3.6.1.5.5.13.12 +oid base GSS_C_MA_AUTH_TARG_INIT 1.3.6.1.5.5.13.13 +oid base GSS_C_MA_AUTH_INIT_ANON 1.3.6.1.5.5.13.14 +oid base GSS_C_MA_AUTH_TARG_ANON 1.3.6.1.5.5.13.15 +oid base GSS_C_MA_DELEG_CRED 1.3.6.1.5.5.13.16 +oid base GSS_C_MA_INTEG_PROT 1.3.6.1.5.5.13.17 +oid base GSS_C_MA_CONF_PROT 1.3.6.1.5.5.13.18 +oid base GSS_C_MA_MIC 1.3.6.1.5.5.13.19 +oid base GSS_C_MA_WRAP 1.3.6.1.5.5.13.20 +oid base GSS_C_MA_PROT_READY 1.3.6.1.5.5.13.21 +oid base GSS_C_MA_REPLAY_DET 1.3.6.1.5.5.13.22 +oid base GSS_C_MA_OOS_DET 1.3.6.1.5.5.13.23 +oid base GSS_C_MA_CBINDINGS 1.3.6.1.5.5.13.24 +oid base GSS_C_MA_PFS 1.3.6.1.5.5.13.25 +oid base GSS_C_MA_COMPRESS 1.3.6.1.5.5.13.26 +oid base GSS_C_MA_CTX_TRANS 1.3.6.1.5.5.13.27 +oid base GSS_C_MA_NEGOEX_AND_SPNEGO 1.2.840.113554.1.2.2.5.18 + +desc ma GSS_C_MA_MECH_CONCRETE "concrete-mech" "Indicates that a mech is neither a pseudo-mechanism nor a composite mechanism" +desc ma GSS_C_MA_MECH_PSEUDO "pseudo-mech" "" +desc ma GSS_C_MA_MECH_COMPOSITE "composite-mech" "" +desc ma GSS_C_MA_MECH_NEGO "mech-negotiation-mech" "" +desc ma GSS_C_MA_MECH_GLUE "mech-glue" "" +desc ma GSS_C_MA_NOT_MECH "not-mech" "" +desc ma GSS_C_MA_DEPRECATED "mech-deprecated" "" +desc ma GSS_C_MA_NOT_DFLT_MECH "mech-not-default" "" +desc ma GSS_C_MA_ITOK_FRAMED "initial-is-framed" "" +desc ma GSS_C_MA_AUTH_INIT "auth-init-princ" "" +desc ma GSS_C_MA_AUTH_TARG "auth-targ-princ" "" +desc ma GSS_C_MA_AUTH_INIT_INIT "auth-init-princ-initial" "" +desc ma GSS_C_MA_AUTH_TARG_INIT "auth-targ-princ-initial" "" +desc ma GSS_C_MA_AUTH_INIT_ANON "auth-init-princ-anon" "" +desc ma GSS_C_MA_AUTH_TARG_ANON "auth-targ-princ-anon" "" +desc ma GSS_C_MA_DELEG_CRED "deleg-cred" "" +desc ma GSS_C_MA_INTEG_PROT "integ-prot" "" +desc ma GSS_C_MA_CONF_PROT "conf-prot" "" +desc ma GSS_C_MA_MIC "mic" "" +desc ma GSS_C_MA_WRAP "wrap" "" +desc ma GSS_C_MA_PROT_READY "prot-ready" "" +desc ma GSS_C_MA_REPLAY_DET "replay-detection" "" +desc ma GSS_C_MA_OOS_DET "oos-detection" "" +desc ma GSS_C_MA_CBINDINGS "channel-bindings" "" +desc ma GSS_C_MA_PFS "pfs" "" +desc ma GSS_C_MA_COMPRESS "compress" "" +desc ma GSS_C_MA_CTX_TRANS "context-transfer" "" +desc ma GSS_C_MA_NEGOEX_AND_SPNEGO "negoex-and-spnego" "Indicates that a mechanism supports both NegoEx and SPNEGO" diff --git a/third_party/heimdal/lib/gssapi/sanon/accept_sec_context.c b/third_party/heimdal/lib/gssapi/sanon/accept_sec_context.c new file mode 100644 index 0000000..72cbe09 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/accept_sec_context.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_accept_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_const_cred_id_t verifier_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + static gss_buffer_desc empty = GSS_C_EMPTY_BUFFER; + OM_uint32 major, tmp; + sanon_ctx sc = (sanon_ctx)*context_handle; + gss_buffer_desc mech_input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc initiator_pk = GSS_C_EMPTY_BUFFER; + gss_buffer_desc hok_mic = GSS_C_EMPTY_BUFFER; + gss_buffer_desc session_key = GSS_C_EMPTY_BUFFER; + OM_uint32 req_flags = 0; + + if (output_token == GSS_C_NO_BUFFER) { + *minor = EINVAL; + major = GSS_S_FAILURE; + goto out; + } + + _mg_buffer_zero(output_token); + + if (input_token == GSS_C_NO_BUFFER) { + major = GSS_S_DEFECTIVE_TOKEN; + goto out; + } else if (sc != NULL) { + major = GSS_S_BAD_STATUS; + goto out; + } + + major = gss_decapsulate_token(input_token, + GSS_SANON_X25519_MECHANISM, + &mech_input_token); + if (major != GSS_S_COMPLETE) + goto out; + + sc = calloc(1, sizeof(*sc)); + if (sc == NULL) { + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + /* initiator token can include optional 64-bit flags */ + if (mech_input_token.length != crypto_scalarmult_curve25519_BYTES && + mech_input_token.length != crypto_scalarmult_curve25519_BYTES + 8) { + *minor = 0; + major = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + initiator_pk = mech_input_token; + initiator_pk.length = crypto_scalarmult_curve25519_BYTES; + + /* compute public and secret keys */ + major = _gss_sanon_curve25519_base(minor, sc); + if (major != GSS_S_COMPLETE) + goto out; + + if (mech_input_token.length > crypto_scalarmult_curve25519_BYTES) { + /* extra flags */ + uint8_t *p = (uint8_t *)mech_input_token.value + crypto_scalarmult_curve25519_BYTES; + uint32_t dummy; + + _gss_mg_decode_be_uint32(p, &dummy); /* upper 32 bits presently unused */ + _gss_mg_decode_be_uint32(&p[4], &req_flags); + } + + /* compute shared secret */ + major = _gss_sanon_curve25519(minor, sc, &initiator_pk, req_flags, + input_chan_bindings, &session_key); + if (major != GSS_S_COMPLETE) + goto out; + + /* do not let initiator set any other flags */ + req_flags &= SANON_PROTOCOL_FLAG_MASK; + + req_flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | + GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG | GSS_C_TRANS_FLAG | + GSS_C_CHANNEL_BOUND_FLAG; /* CB part of KDF, so always validated */ + + major = _gss_sanon_import_rfc4121_context(minor, sc, req_flags, &session_key); + if (major != GSS_S_COMPLETE) + goto out; + + major = _gss_sanon_get_mic(minor, (gss_const_ctx_id_t)sc, + GSS_C_QOP_DEFAULT, &empty, &hok_mic); + if (major != GSS_S_COMPLETE) + goto out; + + output_token->length = sizeof(sc->pk) + hok_mic.length; + output_token->value = malloc(output_token->length); + if (output_token->value == NULL) { + output_token->length = 0; + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + memcpy(output_token->value, sc->pk, sizeof(sc->pk)); + memcpy((uint8_t *)output_token->value + sizeof(sc->pk), hok_mic.value, hok_mic.length); + + major = GSS_S_COMPLETE; + + *context_handle = (gss_ctx_id_t)sc; + + if (src_name) + *src_name = _gss_sanon_anonymous_identity; + if (ret_flags) + *ret_flags = req_flags; + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + +out: + if (mech_type) + *mech_type = GSS_SANON_X25519_MECHANISM; + if (delegated_cred_handle) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + if (GSS_ERROR(major)) { + _gss_sanon_delete_sec_context(&tmp, (gss_ctx_id_t *)&sc, GSS_C_NO_BUFFER); + *context_handle = GSS_C_NO_CONTEXT; + } + gss_release_buffer(&tmp, &mech_input_token); + gss_release_buffer(&tmp, &hok_mic); + _gss_secure_release_buffer(&tmp, &session_key); + + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/acquire_cred.c b/third_party/heimdal/lib/gssapi/sanon/acquire_cred.c new file mode 100644 index 0000000..7aedd3e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/acquire_cred.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +/* SAnon credential handles are aliases of their underyling name */ + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_acquire_cred_from(OM_uint32 *minor, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_stor, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + *minor = 0; + + if (desired_name == GSS_C_NO_NAME || + desired_name == _gss_sanon_anonymous_identity) + *output_cred_handle = _gss_sanon_anonymous_cred; + else + *output_cred_handle = _gss_sanon_non_anonymous_cred; + + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/add_cred.c b/third_party/heimdal/lib/gssapi/sanon/add_cred.c new file mode 100644 index 0000000..f1dfeba --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/add_cred.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_add_cred_from(OM_uint32 *minor, + gss_cred_id_t input_cred_handle, + gss_const_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + *minor = 0; + + if (output_cred_handle != NULL) { + if (desired_name == GSS_C_NO_NAME || + desired_name == _gss_sanon_anonymous_identity) + *output_cred_handle = _gss_sanon_anonymous_cred; + else + *output_cred_handle = _gss_sanon_non_anonymous_cred; + } + + if (initiator_time_rec) + *initiator_time_rec = GSS_C_INDEFINITE; + if (acceptor_time_rec) + *acceptor_time_rec = GSS_C_INDEFINITE; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/canonicalize_name.c b/third_party/heimdal/lib/gssapi/sanon/canonicalize_name.c new file mode 100644 index 0000000..fa1ade0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/canonicalize_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_canonicalize_name(OM_uint32 *minor, + gss_const_name_t src_name, + const gss_OID mech_type, + gss_name_t *dest_name) +{ + *minor = 0; + + if (src_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + *dest_name = (gss_name_t)src_name; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/compare_name.c b/third_party/heimdal/lib/gssapi/sanon/compare_name.c new file mode 100644 index 0000000..85b13b2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/compare_name.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_compare_name(OM_uint32 *minor, + gss_const_name_t name1, + gss_const_name_t name2, + int *name_equal) +{ + *minor = 0; + + /* + * RFC 2743 Section 2.4.3: + * If either name presented to GSS_Compare_name() denotes + * an anonymous principal, GSS_Compare_name() shall indicate + * FALSE + * + * We also have to apply the same logic to non-anonymous + * names as we erase their contents. + */ + *name_equal = FALSE; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/context_time.c b/third_party/heimdal/lib/gssapi/sanon/context_time.c new file mode 100644 index 0000000..338f3ac --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/context_time.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_context_time(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + OM_uint32 *time_rec) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + *minor = 0; + *time_rec = GSS_C_INDEFINITE; + + if (sc == NULL) + return GSS_S_NO_CONTEXT; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/crypto.c b/third_party/heimdal/lib/gssapi/sanon/crypto.c new file mode 100644 index 0000000..0c7a67f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/crypto.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_wrap(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_wrap(minor, sc->rfc4121, + conf_req_flag, qop_req, + input_message_buffer, conf_state, + output_message_buffer); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_wrap_size_limit(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_wrap_size_limit(minor, sc->rfc4121, + conf_req_flag, qop_req, + req_output_size, max_input_size); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_wrap_iov(OM_uint32 *minor, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_wrap_iov(minor, sc->rfc4121, + conf_req_flag, qop_req, + conf_state, iov, iov_count); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_wrap_iov_length(OM_uint32 *minor, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_wrap_iov_length(minor, sc->rfc4121, + conf_req_flag, qop_req, + conf_state, iov, iov_count); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_unwrap(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t * qop_state) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_unwrap(minor, sc->rfc4121, + input_message_buffer, output_message_buffer, + conf_state, qop_state); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_unwrap_iov(OM_uint32 *minor, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_unwrap_iov(minor, sc->rfc4121, + conf_state, qop_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_get_mic(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_get_mic(minor, sc->rfc4121, + qop_req, message_buffer, + message_token); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_verify_mic(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_verify_mic(minor, sc->rfc4121, + message_buffer, token_buffer, + qop_state); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_pseudo_random(OM_uint32 *minor, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = GSS_KRB5_S_KG_CTX_INCOMPLETE; + return GSS_S_NO_CONTEXT; + } + + return gss_pseudo_random(minor, sc->rfc4121, + prf_key, prf_in, desired_output_len, + prf_out); +} + +/* + * Generate a curve25519 secret and public key + */ + +OM_uint32 +_gss_sanon_curve25519_base(OM_uint32 *minor, sanon_ctx sc) +{ + krb5_generate_random_block(sc->sk, crypto_scalarmult_curve25519_BYTES); + + if (crypto_scalarmult_curve25519_base(sc->pk, sc->sk) != 0) { + *minor = EINVAL; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +/* + * Derive the context session key using SP800-108 KDF in HMAC mode + * and the public keys and channel binding data. + */ + +OM_uint32 +_gss_sanon_curve25519(OM_uint32 *minor, + sanon_ctx sc, + gss_buffer_t pk, + OM_uint32 gss_flags, + const gss_channel_bindings_t input_chan_bindings, + gss_buffer_t session_key) +{ + uint8_t shared[crypto_scalarmult_curve25519_BYTES], *p; + krb5_error_code ret; + krb5_context context; + krb5_data kdf_K1, kdf_label, kdf_context, keydata; + + _mg_buffer_zero(session_key); + + if (pk == GSS_C_NO_BUFFER || pk->length != crypto_scalarmult_curve25519_BYTES) + return GSS_S_DEFECTIVE_TOKEN; + + if (crypto_scalarmult_curve25519(shared, sc->sk, pk->value) != 0) + return GSS_S_FAILURE; + + ret = krb5_init_context(&context); + if (ret != 0) { + *minor = ret; + return GSS_S_FAILURE; + } + + kdf_K1.data = shared; + kdf_K1.length = sizeof(shared); + + kdf_label.data = "sanon-x25519"; + kdf_label.length = sizeof("sanon-x25519") - 1; + + ret = krb5_data_alloc(&kdf_context, + 2 * crypto_scalarmult_curve25519_BYTES + 8 + + (input_chan_bindings ? input_chan_bindings->application_data.length : 0)); + if (ret != 0) { + krb5_free_context(context); + *minor = ret; + return GSS_S_FAILURE; + } + + p = kdf_context.data; + + if (sc->is_initiator) { + memcpy(p, sc->pk, sizeof(sc->pk)); + memcpy(&p[pk->length], pk->value, pk->length); + } else { + memcpy(p, pk->value, pk->length); + memcpy(&p[sizeof(sc->pk)], sc->pk, sizeof(sc->pk)); + } + p += 2 * crypto_scalarmult_curve25519_BYTES; + _gss_mg_encode_be_uint32(0, p); /* upper 32 bits presently unused */ + p += 4; + _gss_mg_encode_be_uint32(gss_flags, p); + p += 4; + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS && + input_chan_bindings->application_data.value != NULL) { + memcpy(p, input_chan_bindings->application_data.value, + input_chan_bindings->application_data.length); + } + + ret = krb5_data_alloc(&keydata, 16); + if (ret == 0) { + ret = _krb5_SP800_108_HMAC_KDF(context, &kdf_K1, &kdf_label, + &kdf_context, EVP_sha256(), &keydata); + + session_key->length = keydata.length; + session_key->value = keydata.data; + } else { + krb5_data_free(&keydata); + } + + memset_s(kdf_context.data, kdf_context.length, 0, kdf_context.length); + krb5_data_free(&kdf_context); + + memset_s(shared, sizeof(shared), 0, sizeof(shared)); + + krb5_free_context(context); + + *minor = ret; + return ret != 0 ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 +_gss_sanon_import_rfc4121_context(OM_uint32 *minor, + sanon_ctx sc, + OM_uint32 gss_flags, + gss_const_buffer_t session_key) +{ + return _gss_mg_import_rfc4121_context(minor, sc->is_initiator, gss_flags, + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + session_key, &sc->rfc4121); +} + diff --git a/third_party/heimdal/lib/gssapi/sanon/delete_sec_context.c b/third_party/heimdal/lib/gssapi/sanon/delete_sec_context.c new file mode 100644 index 0000000..fdb8a85 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/delete_sec_context.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_delete_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + sanon_ctx sc; + + *minor = 0; + + if (output_token != GSS_C_NO_BUFFER) { + output_token->length = 0; + output_token->value = NULL; + } + + if (*context_handle == GSS_C_NO_CONTEXT) + return GSS_S_COMPLETE; + + sc = (sanon_ctx)*context_handle; + + *context_handle = GSS_C_NO_CONTEXT; + + gss_delete_sec_context(minor, &sc->rfc4121, GSS_C_NO_BUFFER); + + memset_s(sc, sizeof(*sc), 0, sizeof(*sc)); + free(sc); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/display_name.c b/third_party/heimdal/lib/gssapi/sanon/display_name.c new file mode 100644 index 0000000..1bd55f3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/display_name.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_display_name(OM_uint32 *minor, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + *minor = 0; + + if (input_name != _gss_sanon_anonymous_identity) + return GSS_S_BAD_NAME; + + if (output_name_type) + *output_name_type = GSS_C_NT_ANONYMOUS; + + return _gss_copy_buffer(minor, _gss_sanon_wellknown_user_name, + output_name_buffer); +} diff --git a/third_party/heimdal/lib/gssapi/sanon/display_status.c b/third_party/heimdal/lib/gssapi/sanon/display_status.c new file mode 100644 index 0000000..4e039c6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/display_status.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_display_status(OM_uint32 *minor, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + _mg_buffer_zero(status_string); + + if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && + gss_oid_equal(mech_type, GSS_SANON_X25519_MECHANISM) == 0) { + *minor = 0; + return GSS_S_BAD_MECH; + } + + if (status_type == GSS_C_MECH_CODE) { + return gss_display_status(minor, status_value, + GSS_C_MECH_CODE, GSS_KRB5_MECHANISM, + message_context, status_string); + } else { + *minor = EINVAL; + return GSS_S_BAD_STATUS; + } +} diff --git a/third_party/heimdal/lib/gssapi/sanon/duplicate_cred.c b/third_party/heimdal/lib/gssapi/sanon/duplicate_cred.c new file mode 100644 index 0000000..8c5c5d8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/duplicate_cred.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_duplicate_cred(OM_uint32 *minor, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + *minor = 0; + *output_cred_handle = (gss_cred_id_t)input_cred_handle; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/duplicate_name.c b/third_party/heimdal/lib/gssapi/sanon/duplicate_name.c new file mode 100644 index 0000000..698e83d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/duplicate_name.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_duplicate_name(OM_uint32 *minor, + gss_const_name_t src_name, + gss_name_t *dest_name) +{ + *minor = 0; + *dest_name = (gss_name_t)src_name; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/export_cred.c b/third_party/heimdal/lib/gssapi/sanon/export_cred.c new file mode 100644 index 0000000..359eefd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/export_cred.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_export_cred(OM_uint32 *minor, + gss_cred_id_t input_cred, + gss_buffer_t token) +{ + gss_buffer_desc buf; + krb5_storage *sp; + krb5_data data_out, data; + OM_uint32 major, junk; + + token->value = NULL; + token->length = 0; + + major = _gss_sanon_export_name(minor, (gss_name_t)input_cred, &buf); + if (major) + return major; + + sp = krb5_storage_emem(); + if (sp == NULL) { + gss_release_buffer(&junk, &buf); + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + major = _gss_mg_store_oid(minor, sp, GSS_SANON_X25519_MECHANISM); + if (major) { + gss_release_buffer(&junk, &buf); + krb5_storage_free(sp); + return major; + } + data_out.length = 0; + data_out.data = NULL; + data.length = buf.length; + data.data = buf.value; + *minor = krb5_store_data(sp, data); + if (*minor == 0) + *minor = krb5_storage_to_data(sp, &data_out); + if (*minor == 0) { + token->value = data_out.data; + token->length = data_out.length; + } + gss_release_buffer(&junk, &buf); + krb5_storage_free(sp); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/export_name.c b/third_party/heimdal/lib/gssapi/sanon/export_name.c new file mode 100644 index 0000000..474c58c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/export_name.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_export_name(OM_uint32 *minor, + gss_const_name_t input_name, + gss_buffer_t exported_name) +{ + uint8_t is_anonymous; + + *minor = 0; + + if (input_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + is_anonymous = input_name == _gss_sanon_anonymous_identity; + if (!is_anonymous) + return GSS_S_BAD_NAME; + + return gss_mg_export_name(minor, GSS_SANON_X25519_MECHANISM, + &is_anonymous, 1, exported_name); +} diff --git a/third_party/heimdal/lib/gssapi/sanon/export_sec_context.c b/third_party/heimdal/lib/gssapi/sanon/export_sec_context.c new file mode 100644 index 0000000..52ba6fb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/export_sec_context.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_export_sec_context(OM_uint32 *minor, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) +{ + OM_uint32 major; + const sanon_ctx sc = (sanon_ctx)*context_handle; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + _mg_buffer_zero(interprocess_token); + *minor = 0; + return GSS_S_UNAVAILABLE; + } + + major = gss_export_sec_context(minor, &sc->rfc4121, interprocess_token); + if (major == GSS_S_COMPLETE) + _gss_sanon_delete_sec_context(minor, context_handle, GSS_C_NO_BUFFER); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/external.c b/third_party/heimdal/lib/gssapi/sanon/external.c new file mode 100644 index 0000000..8812f9e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/external.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2006-2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +static uint8_t anonymous_identity; +gss_name_t +_gss_sanon_anonymous_identity = (gss_name_t)&anonymous_identity; +gss_cred_id_t +_gss_sanon_anonymous_cred = (gss_cred_id_t)&anonymous_identity; + +static uint8_t non_anonymous_identity; +gss_name_t +_gss_sanon_non_anonymous_identity = (gss_name_t)&non_anonymous_identity; +gss_cred_id_t +_gss_sanon_non_anonymous_cred = (gss_cred_id_t)&non_anonymous_identity; + +static gss_buffer_desc wellknown_user_name = { + SANON_WELLKNOWN_USER_NAME_LEN, + SANON_WELLKNOWN_USER_NAME +}; +gss_buffer_t +_gss_sanon_wellknown_user_name = &wellknown_user_name; + +static gss_buffer_desc wellknown_service_name = { + SANON_WELLKNOWN_SERVICE_NAME_LEN, + SANON_WELLKNOWN_SERVICE_NAME +}; +gss_buffer_t +_gss_sanon_wellknown_service_name = &wellknown_service_name; + +static gss_mo_desc sanon_mo[] = { + { + GSS_C_MA_MECH_NAME, + GSS_MO_MA, + "Mechanism name", + rk_UNCONST("SANON-X25519"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_DESCRIPTION, + GSS_MO_MA, + "Mechanism description", + rk_UNCONST("Heimdal Simple Anonymous (X25519) Mechanism"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_CONCRETE, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_ITOK_FRAMED, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_INIT_ANON, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_TARG_ANON, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_INTEG_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CONF_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_MIC, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_WRAP, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_REPLAY_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_OOS_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CBINDINGS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_PFS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CTX_TRANS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_NEGOEX_AND_SPNEGO, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + } +}; + +static gssapi_mech_interface_desc sanon_mech = { + GMI_VERSION, + "sanon-x25519", + { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x1a\x01\x6e") }, + 0, + NULL, + _gss_sanon_release_cred, + _gss_sanon_init_sec_context, + _gss_sanon_accept_sec_context, + _gss_sanon_process_context_token, + _gss_sanon_delete_sec_context, + _gss_sanon_context_time, + _gss_sanon_get_mic, + _gss_sanon_verify_mic, + _gss_sanon_wrap, + _gss_sanon_unwrap, + _gss_sanon_display_status, + NULL, /* gm_indicate_mechs */ + _gss_sanon_compare_name, + _gss_sanon_display_name, + _gss_sanon_import_name, + _gss_sanon_export_name, + _gss_sanon_release_name, + _gss_sanon_inquire_cred, + _gss_sanon_inquire_context, + _gss_sanon_wrap_size_limit, + NULL, /* gm_add_cred */ + _gss_sanon_inquire_cred_by_mech, + _gss_sanon_export_sec_context, + _gss_sanon_import_sec_context, + _gss_sanon_inquire_names_for_mech, + _gss_sanon_inquire_mechs_for_name, + _gss_sanon_canonicalize_name, + _gss_sanon_duplicate_name, + _gss_sanon_inquire_sec_context_by_oid, + NULL, /* gm_inquire_cred_by_oid */ + NULL, /* gm_set_sec_context_option */ + NULL, /* gm_set_cred_option */ + _gss_sanon_pseudo_random, + _gss_sanon_wrap_iov, + _gss_sanon_unwrap_iov, + _gss_sanon_wrap_iov_length, + NULL, /* gm_store_cred */ + _gss_sanon_export_cred, + _gss_sanon_import_cred, + _gss_sanon_acquire_cred_from, + NULL, /* gm_acquire_cred_impersonate_name */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sanon_mo, + sizeof(sanon_mo) / sizeof(sanon_mo[0]), + NULL, /* gm_localname */ + NULL, /* gm_authorize_localname */ + NULL, /* gm_display_name_ext */ + NULL, /* gm_inquire_name */ + NULL, /* gm_get_name_attribute */ + NULL, /* gm_set_name_attribute */ + NULL, /* gm_delete_name_attribute */ + NULL, /* gm_export_name_composite */ + _gss_sanon_duplicate_cred, + _gss_sanon_add_cred_from, + NULL, /* gm_store_cred_into */ + _gssspi_sanon_query_mechanism_info, + _gssspi_sanon_query_meta_data, + _gssspi_sanon_exchange_meta_data, + NULL, /* gm_store_cred_into2 */ + NULL, /* gm_compat */ +}; + +gssapi_mech_interface +__gss_sanon_initialize(void) +{ + return &sanon_mech; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/import_cred.c b/third_party/heimdal/lib/gssapi/sanon/import_cred.c new file mode 100644 index 0000000..4266ef1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/import_cred.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_import_cred(OM_uint32 *minor, + gss_buffer_t token, + gss_cred_id_t *cred_handle) +{ + return _gss_sanon_import_name(minor, token, + GSS_C_NT_EXPORT_NAME, + (gss_name_t *)cred_handle); +} diff --git a/third_party/heimdal/lib/gssapi/sanon/import_name.c b/third_party/heimdal/lib/gssapi/sanon/import_name.c new file mode 100644 index 0000000..1a228b6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/import_name.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +static int +is_anonymous_identity_p(gss_buffer_t name_string, gss_OID name_type) +{ + if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) + return TRUE; + else if ((name_type == GSS_C_NO_OID || + gss_oid_equal(name_type, GSS_C_NT_USER_NAME) || + gss_oid_equal(name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) && + buffer_equal_p(name_string, _gss_sanon_wellknown_user_name)) + return TRUE; + else if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE) && + buffer_equal_p(name_string, _gss_sanon_wellknown_service_name)) + return TRUE; + + return FALSE; +} + +static krb5_error_code +storage_ret_der_oid(krb5_storage *sp, gss_OID_desc *oid) +{ + krb5_error_code ret; + uint16_t der_oid_len; + uint8_t oid_len, tag; + + oid->length = 0; + oid->elements = NULL; + + ret = krb5_ret_uint16(sp, &der_oid_len); + if (ret == 0) + ret = krb5_ret_uint8(sp, &tag); + if (ret == 0) + ret = krb5_ret_uint8(sp, &oid_len); + if (ret) + return ret; + if (tag != 0x06) + return EINVAL; + + if (der_oid_len != 2 + oid_len) + return EINVAL; + + oid->elements = malloc(oid_len); + if (oid->elements == NULL) + return ENOMEM; + + if (krb5_storage_read(sp, oid->elements, oid_len) != oid_len) { + free(oid->elements); + oid->elements = NULL; + oid->length = 0; + return EINVAL; + } + + oid->length = oid_len; + + return 0; +} + +static OM_uint32 +import_export_name(OM_uint32 *minor, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + OM_uint32 major; + krb5_error_code ret; + krb5_storage *sp; + uint32_t name_len = 0; + uint16_t tok_id; + gss_OID_desc oid_buf = { 0, NULL }; + uint8_t is_anonymous; + + sp = krb5_storage_from_readonly_mem(input_name_buffer->value, + input_name_buffer->length); + if (sp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); + + major = GSS_S_BAD_NAME; + *minor = 0; + + ret = krb5_ret_uint16(sp, &tok_id); + if (ret == 0 && tok_id != 0x0401) + ret = EINVAL; + if (ret == 0) + ret = storage_ret_der_oid(sp, &oid_buf); + if (ret == 0) { + if (!gss_oid_equal(&oid_buf, GSS_SANON_X25519_MECHANISM)) + ret = EINVAL; + free(oid_buf.elements); + } + if (ret == 0) + ret = krb5_ret_uint32(sp, &name_len); + if (ret == 0) + ret = krb5_ret_uint8(sp, &is_anonymous); + if (ret == 0) { + if (name_len != 1) + ret = EINVAL; + if (is_anonymous == 1) { + *output_name = _gss_sanon_anonymous_identity; + major = GSS_S_COMPLETE; + } else { + major = GSS_S_BAD_NAME; + } + } + + krb5_storage_free(sp); + + if (*minor == 0) + *minor = ret; + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_import_name(OM_uint32 *minor, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t *output_name) +{ + if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) + return import_export_name(minor, input_name_buffer, output_name); + + *minor = 0; + *output_name = + is_anonymous_identity_p(input_name_buffer, input_name_type) ? + _gss_sanon_anonymous_identity : _gss_sanon_non_anonymous_identity; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/import_sec_context.c b/third_party/heimdal/lib/gssapi/sanon/import_sec_context.c new file mode 100644 index 0000000..9aa682a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/import_sec_context.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_import_sec_context(OM_uint32 *minor, + const gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + OM_uint32 major = GSS_S_FAILURE; + sanon_ctx sc; + + *minor = ENOMEM; + *context_handle = GSS_C_NO_CONTEXT; + + if ((sc = calloc(1, sizeof(*sc))) && + (major = gss_import_sec_context(minor, + interprocess_token, + &sc->rfc4121)) == GSS_S_COMPLETE) { + *context_handle = (gss_ctx_id_t)sc; + sc = NULL; + } + + free(sc); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/init_sec_context.c b/third_party/heimdal/lib/gssapi/sanon/init_sec_context.c new file mode 100644 index 0000000..4c199ed --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/init_sec_context.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +int +_gss_sanon_available_p(gss_const_cred_id_t claimant_cred_handle, + gss_const_name_t target_name, + OM_uint32 req_flags) +{ + OM_uint32 minor; + gss_name_t initiator_name = GSS_C_NO_NAME; + int available; + + if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { + _gss_sanon_inquire_cred(&minor, claimant_cred_handle, + &initiator_name, NULL, NULL, NULL); + heim_assert(initiator_name != GSS_C_NO_NAME, + "Invalid null SAnon initiator name"); + } + + /* + * SAnon is available if one of the following is true: + * + * The caller set anon_req_flag (GSS_C_ANON_FLAG) + * The claimant_cred_handle identity is anonymous + * The claimant_cred_handle is the default credential + * and target_name is anonymous + */ + if (req_flags & GSS_C_ANON_FLAG) + available = TRUE; + else if (initiator_name == _gss_sanon_anonymous_identity) + available = TRUE; + else if (claimant_cred_handle == GSS_C_NO_CREDENTIAL && + target_name == _gss_sanon_anonymous_identity) + available = TRUE; + else + available = FALSE; + + _gss_sanon_release_name(&minor, &initiator_name); + return available; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_init_sec_context(OM_uint32 *minor, + gss_const_cred_id_t cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + gss_buffer_desc mech_token = GSS_C_EMPTY_BUFFER; + OM_uint32 major, tmp; + sanon_ctx sc = (sanon_ctx)*context_handle; + OM_uint32 flags; + gss_buffer_desc session_key = GSS_C_EMPTY_BUFFER; + + *minor = 0; + _mg_buffer_zero(output_token); + + if (!_gss_sanon_available_p(cred_handle, target_name, req_flags)) { + major = GSS_S_UNAVAILABLE; + goto out; + } + + /* we always support the following flags */ + flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | + GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG; + /* we support the following optional flags */ + flags |= req_flags & SANON_PROTOCOL_FLAG_MASK; + + if (sc == NULL) { + uint8_t pk_and_flags[crypto_scalarmult_curve25519_BYTES + 8]; + + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { + major = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + sc = calloc(1, sizeof(*sc)); + if (sc == NULL) { + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + sc->is_initiator = 1; + + /* compute public and secret keys */ + major = _gss_sanon_curve25519_base(minor, sc); + if (major != GSS_S_COMPLETE) + goto out; + + if (flags & SANON_PROTOCOL_FLAG_MASK) { + memcpy(pk_and_flags, sc->pk, sizeof(sc->pk)); + _gss_mg_encode_be_uint32(0, &pk_and_flags[sizeof(sc->pk)]); + _gss_mg_encode_be_uint32(flags & SANON_PROTOCOL_FLAG_MASK, + &pk_and_flags[sizeof(sc->pk) + 4]); + mech_token.length = sizeof(pk_and_flags); + mech_token.value = pk_and_flags; + } else { + mech_token.length = sizeof(sc->pk); + mech_token.value = sc->pk; + } + + /* send public key to acceptor */ + major = gss_encapsulate_token(&mech_token, + GSS_SANON_X25519_MECHANISM, + output_token); + if (major != GSS_S_COMPLETE) + goto out; + + *context_handle = (gss_ctx_id_t)sc; + major = GSS_S_CONTINUE_NEEDED; + } else { + static gss_buffer_desc empty = GSS_C_EMPTY_BUFFER; + gss_buffer_desc pk, hok_mic; + + if (input_token == GSS_C_NO_BUFFER || + input_token->length < crypto_scalarmult_curve25519_BYTES) { + major = GSS_S_DEFECTIVE_TOKEN; + goto out; + } else if (sc->rfc4121 != GSS_C_NO_CONTEXT || !(sc->is_initiator)) { + major = GSS_S_BAD_STATUS; + goto out; + } + + pk.length = crypto_scalarmult_curve25519_BYTES; + pk.value = input_token->value; + + /* compute shared secret */ + major = _gss_sanon_curve25519(minor, sc, &pk, + flags & SANON_PROTOCOL_FLAG_MASK, + input_chan_bindings, &session_key); + if (major != GSS_S_COMPLETE) + goto out; + + flags |= GSS_C_TRANS_FLAG; + + major = _gss_sanon_import_rfc4121_context(minor, sc, flags, &session_key); + if (major != GSS_S_COMPLETE) + goto out; + + /* verify holder of key MIC */ + hok_mic.length = input_token->length - pk.length; + hok_mic.value = (uint8_t *)input_token->value + pk.length; + + major = _gss_sanon_verify_mic(minor, (gss_const_ctx_id_t)sc, + &empty, &hok_mic, NULL); + if (major != GSS_S_COMPLETE) + goto out; + } + + if (ret_flags) + *ret_flags = flags; + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + +out: + if (actual_mech_type) + *actual_mech_type = GSS_SANON_X25519_MECHANISM; + + if (GSS_ERROR(major)) { + _gss_sanon_delete_sec_context(&tmp, (gss_ctx_id_t *)&sc, GSS_C_NO_BUFFER); + *context_handle = GSS_C_NO_CONTEXT; + } + _gss_secure_release_buffer(&tmp, &session_key); + + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_context.c b/third_party/heimdal/lib/gssapi/sanon/inquire_context.c new file mode 100644 index 0000000..f5aa727 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_context.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_inquire_context(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open_context) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + OM_uint32 major = GSS_S_COMPLETE; + + *minor = 0; + + if (sc == NULL) + return GSS_S_NO_CONTEXT; + + if (src_name) + *src_name = _gss_sanon_anonymous_identity; + if (targ_name) + *targ_name = _gss_sanon_anonymous_identity; + if (lifetime_rec) + *lifetime_rec = GSS_C_INDEFINITE; + if (mech_type) + *mech_type = GSS_SANON_X25519_MECHANISM; + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + if (locally_initiated) + *locally_initiated = sc->is_initiator; + if (open_context) + *open_context = 0; + if (ctx_flags) + *ctx_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | + GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG; + } else { + major = gss_inquire_context(minor, sc->rfc4121, NULL, NULL, NULL, + NULL, ctx_flags, locally_initiated, + open_context); + } + return major; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_cred.c b/third_party/heimdal/lib/gssapi/sanon/inquire_cred.c new file mode 100644 index 0000000..b25ff2f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_cred.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +_gss_sanon_inquire_cred(OM_uint32 *minor, + gss_const_cred_id_t cred_handle, + gss_name_t *name_ret, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + *minor = 0; + + if (cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_NO_CRED; + + /* the credential handle is a reference to the cred name */ + if (name_ret) + *name_ret = (gss_name_t)cred_handle; + if (lifetime) + *lifetime = GSS_C_INDEFINITE; + if (cred_usage) + *cred_usage = GSS_C_BOTH; + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/sanon/inquire_cred_by_mech.c new file mode 100644 index 0000000..4f8bf66 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_cred_by_mech.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003, 2006, 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_inquire_cred_by_mech(OM_uint32 *minor, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t *name, + OM_uint32 *initiator_lifetime, + OM_uint32 *acceptor_lifetime, + gss_cred_usage_t *cred_usage) +{ + gss_cred_usage_t usage; + OM_uint32 major; + OM_uint32 lifetime; + + major = _gss_sanon_inquire_cred(minor, cred_handle, + name, &lifetime, &usage, NULL); + if (major) + return major; + + if (initiator_lifetime) { + if (usage == GSS_C_INITIATE || usage == GSS_C_BOTH) + *initiator_lifetime = lifetime; + else + *initiator_lifetime = 0; + } + + if (acceptor_lifetime) { + if (usage == GSS_C_ACCEPT || usage == GSS_C_BOTH) + *acceptor_lifetime = lifetime; + else + *acceptor_lifetime = 0; + } + + if (cred_usage) + *cred_usage = usage; + + *minor = 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/sanon/inquire_mechs_for_name.c new file mode 100644 index 0000000..df7387c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_mechs_for_name.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_inquire_mechs_for_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_OID_set *mech_types) +{ + OM_uint32 ret, tmp; + + ret = gss_create_empty_oid_set(minor_status, mech_types); + if (ret != GSS_S_COMPLETE) + return ret; + + ret = gss_add_oid_set_member(minor_status, + GSS_SANON_X25519_MECHANISM, + mech_types); + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(&tmp, mech_types); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/sanon/inquire_names_for_mech.c new file mode 100644 index 0000000..c8b7f23 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_names_for_mech.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "sanon_locl.h" + +static gss_OID name_list[] = { + GSS_C_NT_HOSTBASED_SERVICE, + GSS_C_NT_USER_NAME, + GSS_C_NT_EXPORT_NAME, + GSS_C_NT_ANONYMOUS, + GSS_KRB5_NT_PRINCIPAL_NAME, + NULL +}; + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_inquire_names_for_mech(OM_uint32 *minor, + const gss_OID mechanism, + gss_OID_set *name_types) +{ + OM_uint32 ret, tmp; + int i; + + *minor = 0; + + if (gss_oid_equal(mechanism, GSS_SANON_X25519_MECHANISM) == 0 && + gss_oid_equal(mechanism, GSS_C_NULL_OID) == 0) { + *name_types = GSS_C_NO_OID_SET; + return GSS_S_BAD_MECH; + } + + ret = gss_create_empty_oid_set(minor, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + for (i = 0; name_list[i] != NULL; i++) { + ret = gss_add_oid_set_member(minor, + name_list[i], + name_types); + if (ret != GSS_S_COMPLETE) + break; + } + + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(&tmp, name_types); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/inquire_sec_context_by_oid.c b/third_party/heimdal/lib/gssapi/sanon/inquire_sec_context_by_oid.c new file mode 100644 index 0000000..1d8bc4b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/inquire_sec_context_by_oid.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_inquire_sec_context_by_oid(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + const sanon_ctx sc = (const sanon_ctx)context_handle; + + if (sc == NULL) + return GSS_S_NO_CONTEXT; + + *data_set = GSS_C_NO_BUFFER_SET; + + if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY) || + gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X) || + gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X) || + gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X) || + gss_oid_equal(desired_object, GSS_KRB5_EXPORT_LUCID_CONTEXT_X)) + return gss_inquire_sec_context_by_oid(minor, sc->rfc4121, + desired_object, data_set); + else if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY) || + gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY)) + return _gss_sanon_inquire_negoex_key(minor, sc, desired_object, data_set); + else { + *minor = EINVAL; + return GSS_S_UNAVAILABLE; + } +} diff --git a/third_party/heimdal/lib/gssapi/sanon/negoex.c b/third_party/heimdal/lib/gssapi/sanon/negoex.c new file mode 100644 index 0000000..c6a21dd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/negoex.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gssspi_sanon_query_mechanism_info(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]) +{ + heim_assert(gss_oid_equal(mech_oid, GSS_SANON_X25519_MECHANISM), + "Invalid mechanism OID passed to query_mechanism_info"); + + *minor = 0; + + /* {DEE384FF-1086-4E86-BE78-B94170BFD376} */ + memcpy(auth_scheme, + "\xff\x84\xe3\xde\x86\x10\x86\x4e\xbe\x78\xb9\x41\x70\xbf\xd3\x76", 16); + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gss_sanon_inquire_negoex_key(OM_uint32 *minor, + const sanon_ctx sc, + gss_const_OID desired_object, + gss_buffer_set_t *data_set) +{ + OM_uint32 major, tmpMinor; + int initiator_key; + uint8_t typebytes[4]; + gss_buffer_desc salt, keyvalue = GSS_C_EMPTY_BUFFER, keytype; + + if (sc->rfc4121 == GSS_C_NO_CONTEXT) { + *minor = KRB5KRB_AP_ERR_NOKEY; + return GSS_S_UNAVAILABLE; + } + + initiator_key = !!(sc->is_initiator); + + if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY)) + initiator_key ^= 1; + else if (!gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY)) + return GSS_S_UNAVAILABLE; + + if (initiator_key) { + salt.length = sizeof("sanon-x25519-initiator-negoex-key") - 1; + salt.value = "sanon-x25519-initiator-negoex-key"; + } else { + salt.length = sizeof("sanon-x25519-acceptor-negoex-key") - 1; + salt.value = "sanon-x25519-acceptor-negoex-key"; + } + + _gss_mg_encode_le_uint32(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, typebytes); + + keytype.length = sizeof(typebytes); + keytype.value = typebytes; + + major = gss_pseudo_random(minor, sc->rfc4121, + GSS_C_PRF_KEY_FULL, &salt, + 16, &keyvalue); + if (major == GSS_S_COMPLETE) + major = gss_add_buffer_set_member(minor, &keyvalue, data_set); + if (major == GSS_S_COMPLETE) + major = gss_add_buffer_set_member(minor, &keytype, data_set); + + _gss_secure_release_buffer(&tmpMinor, &keyvalue); + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gssspi_sanon_query_meta_data(OM_uint32 *minor, + gss_const_OID mech_oid, + gss_cred_id_t cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t targ_name, + OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + int is_initiator = (targ_name != GSS_C_NO_NAME); + + *minor = 0; + + if (is_initiator && + !_gss_sanon_available_p(cred_handle, targ_name, req_flags)) + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gssspi_sanon_exchange_meta_data(OM_uint32 *minor, + gss_const_OID mech_oid, + gss_cred_id_t cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t targ_name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + *minor = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/process_context_token.c b/third_party/heimdal/lib/gssapi/sanon/process_context_token.c new file mode 100644 index 0000000..077c8cb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/process_context_token.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +_gss_sanon_process_context_token(OM_uint32 *minor, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer) +{ + *minor = 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/release_cred.c b/third_party/heimdal/lib/gssapi/sanon/release_cred.c new file mode 100644 index 0000000..aa95272 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/release_cred.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_release_cred(OM_uint32 *minor, + gss_cred_id_t *cred_handle) +{ + *minor = 0; + *cred_handle = GSS_C_NO_CREDENTIAL; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/release_name.c b/third_party/heimdal/lib/gssapi/sanon/release_name.c new file mode 100644 index 0000000..7ba788c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/release_name.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sanon_locl.h" + +OM_uint32 GSSAPI_CALLCONV +_gss_sanon_release_name(OM_uint32 *minor, + gss_name_t *input_name) +{ + *minor = 0; + *input_name = GSS_C_NO_NAME; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/sanon/sanon_locl.h b/third_party/heimdal/lib/gssapi/sanon/sanon_locl.h new file mode 100644 index 0000000..93d6aa8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/sanon/sanon_locl.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef SANON_LOCL_H +#define SANON_LOCL_H 1 + +#include + +#include /* for _krb5_SP800_108_HMAC_KDF() */ + +#include + +#include +#include /* for GSS_KRB5_S_XXX */ + +#include "mech/mech_locl.h" + +typedef struct sanon_ctx_desc { + /* X25519 ECDH secret key */ + uint8_t sk[crypto_scalarmult_curve25519_BYTES]; + /* X25519 ECDH public key */ + uint8_t pk[crypto_scalarmult_curve25519_BYTES]; + /* krb5 context for message protection/PRF */ + gss_ctx_id_t rfc4121; + unsigned is_initiator : 1; +} *sanon_ctx; + +extern gss_name_t _gss_sanon_anonymous_identity; +extern gss_name_t _gss_sanon_non_anonymous_identity; + +extern gss_cred_id_t _gss_sanon_anonymous_cred; +extern gss_cred_id_t _gss_sanon_non_anonymous_cred; + +#include "sanon-private.h" + +#define SANON_WELLKNOWN_USER_NAME "WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS" +#define SANON_WELLKNOWN_USER_NAME_LEN (sizeof(SANON_WELLKNOWN_USER_NAME) - 1) + +extern gss_buffer_t _gss_sanon_wellknown_user_name; + +#define SANON_WELLKNOWN_SERVICE_NAME "WELLKNOWN@ANONYMOUS" +#define SANON_WELLKNOWN_SERVICE_NAME_LEN (sizeof(SANON_WELLKNOWN_SERVICE_NAME) - 1) + +extern gss_buffer_t _gss_sanon_wellknown_service_name; + +static inline int +buffer_equal_p(gss_const_buffer_t b1, gss_const_buffer_t b2) +{ + return b1->length == b2->length && + memcmp(b1->value, b2->value, b2->length) == 0; +} + +/* flags that are valid to be sent from a SAnon initiator in the flags field */ +#define SANON_PROTOCOL_FLAG_MASK ( GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG ) + +#endif /* SANON_LOCL_H */ diff --git a/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c b/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c new file mode 100644 index 0000000..c4ac745 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/accept_sec_context.c @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Portions Copyright (c) 2004 PADL Software Pty Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +static OM_uint32 +send_reject (OM_uint32 *minor_status, + gss_const_buffer_t mech_token, + gss_buffer_t output_token) +{ + NegotiationToken nt; + size_t size; + heim_octet_string responseToken; + + nt.element = choice_NegotiationToken_negTokenResp; + + ALLOC(nt.u.negTokenResp.negState, 1); + if (nt.u.negTokenResp.negState == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *(nt.u.negTokenResp.negState) = reject; + nt.u.negTokenResp.supportedMech = NULL; + nt.u.negTokenResp.responseToken = NULL; + + if (mech_token != GSS_C_NO_BUFFER && mech_token->value != NULL) { + responseToken.length = mech_token->length; + responseToken.data = mech_token->value; + nt.u.negTokenResp.responseToken = &responseToken; + } else + nt.u.negTokenResp.responseToken = NULL; + nt.u.negTokenResp.mechListMIC = NULL; + + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, &nt, + &size, *minor_status); + nt.u.negTokenResp.responseToken = NULL; /* allocated on stack */ + free_NegotiationToken(&nt); + if (*minor_status != 0) + return GSS_S_FAILURE; + + return GSS_S_BAD_MECH; +} + +static OM_uint32 +acceptor_approved(OM_uint32 *minor_status, + void *userptr, + gss_const_name_t target_name, + gss_const_cred_id_t cred_handle, + gss_OID mech) +{ + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + gss_OID_set oidset = GSS_C_NO_OID_SET; + OM_uint32 junk, ret; + + if (target_name == GSS_C_NO_NAME) + return GSS_S_COMPLETE; + + if (gss_oid_equal(mech, GSS_NEGOEX_MECHANISM)) { + size_t i; + + ret = _gss_spnego_indicate_mechs(minor_status, &oidset); + if (ret != GSS_S_COMPLETE) + return ret; + + /* before committing to NegoEx, check we can negotiate a mech */ + for (i = 0; i < oidset->count; i++) { + gss_OID inner_mech = &oidset->elements[i]; + + if (_gss_negoex_mech_p(inner_mech)) { + ret = acceptor_approved(minor_status, userptr, + target_name, cred_handle, + inner_mech); + if (ret == GSS_S_COMPLETE) + break; + } + } + } else if (cred_handle != GSS_C_NO_CREDENTIAL) { + ret = gss_inquire_cred_by_mech(minor_status, cred_handle, mech, + NULL, NULL, NULL, NULL); + } else { + ret = gss_create_empty_oid_set(minor_status, &oidset); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, mech, &oidset); + if (ret == GSS_S_COMPLETE) + ret = gss_acquire_cred(minor_status, target_name, + GSS_C_INDEFINITE, oidset, + GSS_C_ACCEPT, &cred, NULL, NULL); + } + + gss_release_oid_set(&junk, &oidset); + gss_release_cred(&junk, &cred); + + return ret; +} + +static OM_uint32 +send_supported_mechs (OM_uint32 *minor_status, + gssspnego_ctx ctx, + gss_const_cred_id_t acceptor_cred, + gss_buffer_t output_token) +{ + NegotiationToken2 nt; + size_t buf_len = 0; + gss_buffer_desc data; + OM_uint32 ret; + + memset(&nt, 0, sizeof(nt)); + + nt.element = choice_NegotiationToken2_negTokenInit; + nt.u.negTokenInit.reqFlags = NULL; + nt.u.negTokenInit.mechToken = NULL; + nt.u.negTokenInit.negHints = NULL; + + ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME, 0, + acceptor_approved, ctx, 1, acceptor_cred, + &nt.u.negTokenInit.mechTypes, NULL); + if (ret != GSS_S_COMPLETE) { + return ret; + } + + ALLOC(nt.u.negTokenInit.negHints, 1); + if (nt.u.negTokenInit.negHints == NULL) { + *minor_status = ENOMEM; + free_NegotiationToken2(&nt); + return GSS_S_FAILURE; + } + + ALLOC(nt.u.negTokenInit.negHints->hintName, 1); + if (nt.u.negTokenInit.negHints->hintName == NULL) { + *minor_status = ENOMEM; + free_NegotiationToken2(&nt); + return GSS_S_FAILURE; + } + + *nt.u.negTokenInit.negHints->hintName = strdup("not_defined_in_RFC4178@please_ignore"); + nt.u.negTokenInit.negHints->hintAddress = NULL; + + ASN1_MALLOC_ENCODE(NegotiationToken2, + data.value, data.length, &nt, &buf_len, ret); + free_NegotiationToken2(&nt); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + if (data.length != buf_len) { + abort(); + UNREACHABLE(return GSS_S_FAILURE); + } + + ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token); + + free (data.value); + + if (ret != GSS_S_COMPLETE) + return ret; + + *minor_status = 0; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +send_accept (OM_uint32 *minor_status, + gssspnego_ctx context_handle, + int optimistic_mech_ok, + gss_buffer_t mech_token, + gss_const_OID selected_mech, /* valid on initial response only */ + gss_buffer_t mech_buf, + gss_buffer_t output_token) +{ + int initial_response = (selected_mech != GSS_C_NO_OID); + NegotiationToken nt; + OM_uint32 ret, minor; + gss_buffer_desc mech_mic_buf; + size_t size; + + memset(&nt, 0, sizeof(nt)); + + nt.element = choice_NegotiationToken_negTokenResp; + + ALLOC(nt.u.negTokenResp.negState, 1); + if (nt.u.negTokenResp.negState == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (context_handle->flags.open) { + if (mech_token != GSS_C_NO_BUFFER + && mech_token->length != 0 + && mech_buf != GSS_C_NO_BUFFER) + *(nt.u.negTokenResp.negState) = accept_incomplete; + else + *(nt.u.negTokenResp.negState) = accept_completed; + } else { + if (initial_response && !optimistic_mech_ok) + *(nt.u.negTokenResp.negState) = request_mic; + else + *(nt.u.negTokenResp.negState) = accept_incomplete; + } + + if (initial_response) { + ALLOC(nt.u.negTokenResp.supportedMech, 1); + if (nt.u.negTokenResp.supportedMech == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto out; + } + + ret = der_get_oid(selected_mech->elements, + selected_mech->length, + nt.u.negTokenResp.supportedMech, + NULL); + if (ret) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto out; + } + + _gss_spnego_log_mech("acceptor sending selected mech", selected_mech); + } else { + nt.u.negTokenResp.supportedMech = NULL; + } + + if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) { + ALLOC(nt.u.negTokenResp.responseToken, 1); + if (nt.u.negTokenResp.responseToken == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto out; + } + nt.u.negTokenResp.responseToken->length = mech_token->length; + nt.u.negTokenResp.responseToken->data = mech_token->value; + mech_token->length = 0; + mech_token->value = NULL; + } else { + nt.u.negTokenResp.responseToken = NULL; + } + + if (mech_buf != GSS_C_NO_BUFFER) { + ret = gss_get_mic(minor_status, + context_handle->negotiated_ctx_id, + 0, + mech_buf, + &mech_mic_buf); + if (ret == GSS_S_COMPLETE) { + _gss_spnego_ntlm_reset_crypto(&minor, context_handle, FALSE); + + ALLOC(nt.u.negTokenResp.mechListMIC, 1); + if (nt.u.negTokenResp.mechListMIC == NULL) { + gss_release_buffer(minor_status, &mech_mic_buf); + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto out; + } + nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length; + nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value; + } else if (ret == GSS_S_UNAVAILABLE) { + nt.u.negTokenResp.mechListMIC = NULL; + } else { + goto out; + } + + } else + nt.u.negTokenResp.mechListMIC = NULL; + + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, + &nt, &size, ret); + if (ret) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto out; + } + + /* + * The response should not be encapsulated, because + * it is a SubsequentContextToken (note though RFC 1964 + * specifies encapsulation for all _Kerberos_ tokens). + */ + + if (*(nt.u.negTokenResp.negState) == accept_completed) + ret = GSS_S_COMPLETE; + else + ret = GSS_S_CONTINUE_NEEDED; + + out: + free_NegotiationToken(&nt); + return ret; +} + +/* + * Return the default acceptor identity based on the local hostname + * or the GSSAPI_SPNEGO_NAME environment variable. + */ + +static OM_uint32 +default_acceptor_name(OM_uint32 *minor_status, + gss_name_t *namep) +{ + OM_uint32 major_status; + gss_buffer_desc namebuf; + char *str = NULL, *host, hostname[MAXHOSTNAMELEN]; + + *namep = GSS_C_NO_NAME; + + host = secure_getenv("GSSAPI_SPNEGO_NAME"); + if (host == NULL) { + int rv; + + if (gethostname(hostname, sizeof(hostname)) != 0) { + *minor_status = errno; + return GSS_S_FAILURE; + } + + rv = asprintf(&str, "host@%s", hostname); + if (rv < 0 || str == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + host = str; + } + + namebuf.length = strlen(host); + namebuf.value = host; + + major_status = gss_import_name(minor_status, &namebuf, + GSS_C_NT_HOSTBASED_SERVICE, namep); + + free(str); + + return major_status; +} + +/* + * Determine whether the mech in mechType can be negotiated. If the + * mech is NegoEx, make NegoEx mechanisms available for negotiation. + */ + +static OM_uint32 +select_mech(OM_uint32 *minor_status, + gssspnego_ctx ctx, + gss_const_cred_id_t cred, + gss_const_OID_set supported_mechs, + MechType *mechType, + int verify_p, /* set on non-optimistic tokens */ + gss_const_OID *advertised_mech_p) +{ + char mechbuf[64]; + size_t mech_len; + gss_OID_desc oid; + gss_OID selected_mech = GSS_C_NO_OID; + OM_uint32 ret, junk; + int negoex_proposed = FALSE, negoex_selected = FALSE; + int includeMSCompatOID = FALSE; + size_t i; + + *minor_status = 0; + *advertised_mech_p = GSS_C_NO_OID; /* deals with broken MS OID */ + + ctx->selected_mech_type = GSS_C_NO_OID; + + ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + mechType, + &mech_len); + if (ret) + return GSS_S_DEFECTIVE_TOKEN; + + oid.length = (OM_uint32)mech_len; + oid.elements = mechbuf + sizeof(mechbuf) - mech_len; + + if (gss_oid_equal(&oid, GSS_NEGOEX_MECHANISM)) + negoex_proposed = TRUE; + else if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) + includeMSCompatOID = TRUE; + + for (i = 0; i < supported_mechs->count; i++) { + gss_OID iter = &supported_mechs->elements[i]; + auth_scheme scheme; + int is_negoex_mech = /* mechanism is negotiable under NegoEx */ + gssspi_query_mechanism_info(&junk, iter, scheme) == GSS_S_COMPLETE; + + if (is_negoex_mech && negoex_proposed) { + ret = _gss_negoex_add_auth_mech(minor_status, ctx, iter, scheme); + if (ret != GSS_S_COMPLETE) + break; + + negoex_selected = TRUE; + } + + if (gss_oid_equal(includeMSCompatOID ? GSS_KRB5_MECHANISM : &oid, iter)) { + ret = _gss_intern_oid(minor_status, iter, &selected_mech); + if (ret != GSS_S_COMPLETE) + return ret; + + break; + } + } + + /* always prefer NegoEx if a mechanism supported both */ + if (negoex_selected) + selected_mech = GSS_NEGOEX_MECHANISM; + if (selected_mech == GSS_C_NO_OID) + ret = GSS_S_BAD_MECH; + if (ret != GSS_S_COMPLETE) + return ret; + + heim_assert(!gss_oid_equal(selected_mech, GSS_SPNEGO_MECHANISM), + "SPNEGO should not be able to negotiate itself"); + + if (verify_p) { + gss_name_t name = GSS_C_NO_NAME; + + /* + * If we do not have a credential, acquire a default name as a hint + * to acceptor_approved() so it can attempt to acquire a default + * credential. + */ + if (cred == GSS_C_NO_CREDENTIAL) { + ret = default_acceptor_name(minor_status, &name); + if (ret != GSS_S_COMPLETE) + return ret; + } + + ret = acceptor_approved(minor_status, ctx, name, cred, selected_mech); + + gss_release_name(&junk, &name); + } else { + /* Stash optimistic mech for use by _gss_spnego_require_mechlist_mic() */ + ret = gss_duplicate_oid(minor_status, &oid, &ctx->preferred_mech_type); + } + + if (ret == GSS_S_COMPLETE) { + *minor_status = 0; + + *advertised_mech_p = ctx->selected_mech_type = selected_mech; + + /* if the initiator used the broken MS OID, send that instead */ + if (includeMSCompatOID && gss_oid_equal(selected_mech, GSS_KRB5_MECHANISM)) + *advertised_mech_p = &_gss_spnego_mskrb_mechanism_oid_desc; + } + + return ret; +} + + +static OM_uint32 +acceptor_complete(OM_uint32 * minor_status, + gssspnego_ctx ctx, + int *get_mic, + gss_buffer_t mech_input_token, + gss_buffer_t mech_output_token, + heim_octet_string *mic, + gss_buffer_t output_token) +{ + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + OM_uint32 ret; + int verify_mic; + + ctx->flags.require_mic = 1; + ctx->flags.safe_omit = _gss_spnego_safe_omit_mechlist_mic(ctx); + + if (ctx->flags.open) { + if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */ + verify_mic = 1; + *get_mic = 0; + } else if (mech_output_token != GSS_C_NO_BUFFER && + mech_output_token->length == 0) { /* Odd */ + *get_mic = verify_mic = 1; + } else { /* Even/One */ + verify_mic = 0; + *get_mic = 1; + } + + /* + * Change from previous versions: do not generate a MIC if not + * necessary. This conforms to RFC4178 s.5 ("if the accepted + * mechanism is the most preferred mechanism of both the initiator + * and acceptor, then the MIC token exchange... is OPTIONAL"), + * and is consistent with MIT and Windows behavior. + */ + if (ctx->flags.safe_omit) + *get_mic = 0; + + if (verify_mic && mic == NULL && ctx->flags.safe_omit) { + /* + * Peer is old and didn't send a mic while we expected + * one, but since it safe to omit, let do that + */ + } else if (verify_mic) { + ret = _gss_spnego_verify_mechtypes_mic(minor_status, ctx, mic); + if (ret) { + if (*get_mic) + send_reject(minor_status, GSS_C_NO_BUFFER, output_token); + if (buf.value) + free(buf.value); + return ret; + } + } + } else + *get_mic = 0; + + return GSS_S_COMPLETE; +} + +/* + * Call gss_accept_sec_context() via mechglue or NegoEx, depending on + * whether mech_oid is NegoEx. + */ + +static OM_uint32 +mech_accept(OM_uint32 *minor_status, + gssspnego_ctx ctx, + gss_const_cred_id_t acceptor_cred_handle, + gss_const_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_buffer_t output_token, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 ret, junk; + + heim_assert(ctx->selected_mech_type != GSS_C_NO_OID, + "mech_accept called with no selected mech"); + + if (gss_oid_equal(ctx->selected_mech_type, GSS_NEGOEX_MECHANISM)) { + ret = _gss_negoex_accept(minor_status, + ctx, + (gss_cred_id_t)acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + output_token, + delegated_cred_handle); + } else { + if (ctx->mech_src_name != GSS_C_NO_NAME) + gss_release_name(&junk, &ctx->mech_src_name); + + ret = gss_accept_sec_context(minor_status, + &ctx->negotiated_ctx_id, + acceptor_cred_handle, + (gss_buffer_t)input_token_buffer, + input_chan_bindings, + &ctx->mech_src_name, + &ctx->negotiated_mech_type, + output_token, + &ctx->mech_flags, + &ctx->mech_time_rec, + delegated_cred_handle); + if (GSS_ERROR(ret)) + gss_mg_collect_error(ctx->negotiated_mech_type, ret, *minor_status); + else if (ctx->negotiated_mech_type != GSS_C_NO_OID && + !gss_oid_equal(ctx->negotiated_mech_type, ctx->selected_mech_type)) + _gss_mg_log(1, "spnego client didn't send the mech they said they would"); + } + + return ret; +} + +static OM_uint32 GSSAPI_CALLCONV +acceptor_start + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t *delegated_cred_handle + ) +{ + OM_uint32 ret, junk; + NegotiationToken nt; + gss_OID_set supported_mechs = GSS_C_NO_OID_SET; + size_t size; + NegTokenInit *ni; + gss_buffer_desc data; + gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; + gss_buffer_desc mech_output_token; + gssspnego_ctx ctx; + int get_mic = 0, first_ok = 0, canonical_order; + gss_const_OID advertised_mech = GSS_C_NO_OID; + + memset(&nt, 0, sizeof(nt)); + + mech_output_token.value = NULL; + mech_output_token.length = 0; + + if (input_token_buffer->length == 0) + return send_supported_mechs (minor_status, NULL, + acceptor_cred_handle, output_token); + + ret = _gss_spnego_alloc_sec_context(minor_status, context_handle); + if (ret != GSS_S_COMPLETE) + return ret; + + ctx = (gssspnego_ctx)*context_handle; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + /* + * The GSS-API encapsulation is only present on the initial + * context token (negTokenInit). + */ + ret = gss_decapsulate_token (input_token_buffer, + GSS_SPNEGO_MECHANISM, + &data); + if (ret) + goto out; + + ret = decode_NegotiationToken(data.value, data.length, &nt, &size); + gss_release_buffer(minor_status, &data); + if (ret) { + *minor_status = ret; + ret = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + if (nt.element != choice_NegotiationToken_negTokenInit) { + *minor_status = 0; + ret = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + ni = &nt.u.negTokenInit; + + if (ni->mechTypes.len < 1) { + free_NegotiationToken(&nt); + *minor_status = 0; + ret = GSS_S_DEFECTIVE_TOKEN; + goto out; + } + + _gss_spnego_log_mechTypes(&ni->mechTypes); + + { + MechTypeList mt; + int kret; + + mt.len = ni->mechTypes.len; + mt.val = ni->mechTypes.val; + + ASN1_MALLOC_ENCODE(MechTypeList, + ctx->NegTokenInit_mech_types.value, + ctx->NegTokenInit_mech_types.length, + &mt, &size, kret); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto out; + } + } + + if (acceptor_cred_handle != GSS_C_NO_CREDENTIAL) + ret = _gss_spnego_inquire_cred_mechs(minor_status, + acceptor_cred_handle, + &supported_mechs, + &canonical_order); + else + ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs); + if (ret != GSS_S_COMPLETE) + goto out; + + /* + * First we try the opportunistic token if we have support for it, + * don't try to verify we have credential for the token, + * gss_accept_sec_context() will (hopefully) tell us that. + * If that failes, + */ + + ret = select_mech(minor_status, + ctx, + acceptor_cred_handle, + supported_mechs, + &ni->mechTypes.val[0], + 0, /* optimistic token */ + &advertised_mech); + + if (ret == GSS_S_COMPLETE && ni->mechToken != NULL) { + gss_buffer_desc ibuf; + + ibuf.length = ni->mechToken->length; + ibuf.value = ni->mechToken->data; + mech_input_token = &ibuf; + + _gss_spnego_log_mech("acceptor selected opportunistic mech", ctx->selected_mech_type); + + ret = mech_accept(&junk, + ctx, + acceptor_cred_handle, + mech_input_token, + input_chan_bindings, + &mech_output_token, + delegated_cred_handle); + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + first_ok = 1; + } else { + ctx->selected_mech_type = GSS_C_NO_OID; + } + + if (ret == GSS_S_COMPLETE) { + ret = acceptor_complete(minor_status, + ctx, + &get_mic, + mech_input_token, + &mech_output_token, + ni->mechListMIC, + output_token); + if (ret != GSS_S_COMPLETE) + goto out; + + ctx->flags.open = 1; + } + } else { + *minor_status = 0; + gss_release_oid_set(&junk, &supported_mechs); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return gss_mg_set_error_string(GSS_C_NO_OID, GSS_S_NO_CONTEXT, + *minor_status, + "SPNEGO acceptor didn't find a prefered mechanism"); + } + + /* + * If opportunistic token failed, lets try the other mechs. + */ + + if (!first_ok) { + size_t j; + + /* Call glue layer to find first mech we support */ + for (j = 1; j < ni->mechTypes.len; ++j) { + ret = select_mech(&junk, + ctx, + acceptor_cred_handle, + supported_mechs, + &ni->mechTypes.val[j], + 1, /* not optimistic token */ + &advertised_mech); + if (ret == GSS_S_COMPLETE) { + _gss_spnego_log_mech("acceptor selected non-opportunistic mech", + ctx->selected_mech_type); + break; + } + } + } + if (ctx->selected_mech_type == GSS_C_NO_OID) { + heim_assert(ret != GSS_S_COMPLETE, "no oid and no error code?"); + *minor_status = junk; + goto out; + } + + /* The initial token always has a response */ + ret = send_accept(minor_status, + ctx, + first_ok, + &mech_output_token, + advertised_mech, + get_mic ? &ctx->NegTokenInit_mech_types : NULL, + output_token); + if (ret) + goto out; + +out: + gss_release_oid_set(&junk, &supported_mechs); + if (mech_output_token.value != NULL) + gss_release_buffer(&junk, &mech_output_token); + free_NegotiationToken(&nt); + + + if (ret == GSS_S_COMPLETE) { + if (src_name != NULL && ctx->mech_src_name != GSS_C_NO_NAME) + ret = gss_duplicate_name(minor_status, + ctx->mech_src_name, + src_name); + } + + if (mech_type != NULL) + *mech_type = ctx->negotiated_mech_type; + if (ret_flags != NULL) + *ret_flags = ctx->mech_flags; + if (time_rec != NULL) + *time_rec = ctx->mech_time_rec; + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + + _gss_spnego_internal_delete_sec_context(&junk, context_handle, + GSS_C_NO_BUFFER); + + return ret; +} + + +static OM_uint32 GSSAPI_CALLCONV +acceptor_continue + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t *delegated_cred_handle + ) +{ + OM_uint32 ret, ret2, minor, junk; + NegotiationToken nt; + size_t nt_len; + NegTokenResp *na; + unsigned int negState = accept_incomplete; + gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; + gss_buffer_t mech_output_token = GSS_C_NO_BUFFER; + gssspnego_ctx ctx; + + ctx = (gssspnego_ctx)*context_handle; + + /* + * The GSS-API encapsulation is only present on the initial + * context token (negTokenInit). + */ + + ret = decode_NegotiationToken(input_token_buffer->value, + input_token_buffer->length, + &nt, &nt_len); + if (ret) { + *minor_status = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + if (nt.element != choice_NegotiationToken_negTokenResp) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + na = &nt.u.negTokenResp; + + if (na->negState != NULL) { + negState = *(na->negState); + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + { + gss_buffer_desc ibuf, obuf; + int get_mic = 0; + int require_response; + + if (na->responseToken != NULL) { + ibuf.length = na->responseToken->length; + ibuf.value = na->responseToken->data; + mech_input_token = &ibuf; + } else { + ibuf.value = NULL; + ibuf.length = 0; + } + + if (mech_input_token != GSS_C_NO_BUFFER) { + + ret = mech_accept(minor_status, + ctx, + acceptor_cred_handle, + mech_input_token, + input_chan_bindings, + &obuf, + delegated_cred_handle); + mech_output_token = &obuf; + if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) { + free_NegotiationToken(&nt); + send_reject(&junk, mech_output_token, output_token); + gss_release_buffer(&junk, mech_output_token); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + if (ret == GSS_S_COMPLETE) + ctx->flags.open = 1; + } else + ret = GSS_S_COMPLETE; + + if (ret == GSS_S_COMPLETE) + ret = acceptor_complete(minor_status, + ctx, + &get_mic, + mech_input_token, + mech_output_token, + na->mechListMIC, + output_token); + + if (ctx->mech_flags & GSS_C_DCE_STYLE) + require_response = (negState != accept_completed); + else + require_response = 0; + + /* + * Check whether we need to send a result: there should be only + * one accept_completed response sent in the entire negotiation + */ + if ((mech_output_token != GSS_C_NO_BUFFER && + mech_output_token->length != 0) + || (ctx->flags.open && negState == accept_incomplete) + || require_response + || get_mic) { + ret2 = send_accept (minor_status, + ctx, + 0, /* ignored on subsequent tokens */ + mech_output_token, + GSS_C_NO_OID, + get_mic ? &ctx->NegTokenInit_mech_types : NULL, + output_token); + if (ret2) + goto out; + } else + ret2 = GSS_S_COMPLETE; + + out: + if (ret2 != GSS_S_COMPLETE) + ret = ret2; + if (mech_output_token != NULL) + gss_release_buffer(&minor, mech_output_token); + free_NegotiationToken(&nt); + } + + if (ret == GSS_S_COMPLETE) { + if (src_name != NULL && ctx->mech_src_name != GSS_C_NO_NAME) + ret = gss_duplicate_name(minor_status, + ctx->mech_src_name, + src_name); + } + + if (mech_type != NULL) + *mech_type = ctx->negotiated_mech_type; + if (ret_flags != NULL) + *ret_flags = ctx->mech_flags; + if (time_rec != NULL) + *time_rec = ctx->mech_time_rec; + + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + + _gss_spnego_internal_delete_sec_context(&minor, context_handle, + GSS_C_NO_BUFFER); + + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_accept_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_const_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t *delegated_cred_handle + ) +{ + _gss_accept_sec_context_t *func; + + *minor_status = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = GSS_C_NO_NAME; + if (mech_type != NULL) + *mech_type = GSS_C_NO_OID; + if (ret_flags != NULL) + *ret_flags = 0; + if (time_rec != NULL) + *time_rec = 0; + if (delegated_cred_handle != NULL) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + + if (*context_handle == GSS_C_NO_CONTEXT) + func = acceptor_start; + else + func = acceptor_continue; + + + return (*func)(minor_status, context_handle, acceptor_cred_handle, + input_token_buffer, input_chan_bindings, + src_name, mech_type, output_token, ret_flags, + time_rec, delegated_cred_handle); +} diff --git a/third_party/heimdal/lib/gssapi/spnego/compat.c b/third_party/heimdal/lib/gssapi/spnego/compat.c new file mode 100644 index 0000000..6cfe552 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/compat.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +/* + * Apparently Microsoft got the OID wrong, and used + * 1.2.840.48018.1.2.2 instead. We need both this and + * the correct Kerberos OID here in order to deal with + * this. Because this is manifest in SPNEGO only I'd + * prefer to deal with this here rather than inside the + * Kerberos mechanism. + */ +gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc = + {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")}; + +/* + * Allocate a SPNEGO context handle + */ +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_alloc_sec_context (OM_uint32 * minor_status, + gss_ctx_id_t *context_handle) +{ + gssspnego_ctx ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ctx->NegTokenInit_mech_types.value = NULL; + ctx->NegTokenInit_mech_types.length = 0; + + ctx->preferred_mech_type = GSS_C_NO_OID; + ctx->selected_mech_type = GSS_C_NO_OID; + ctx->negotiated_mech_type = GSS_C_NO_OID; + + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + + ctx->mech_flags = 0; + ctx->mech_time_rec = 0; + ctx->mech_src_name = GSS_C_NO_NAME; + + ctx->flags.open = 0; + ctx->flags.local = 0; + ctx->flags.peer_require_mic = 0; + ctx->flags.require_mic = 0; + ctx->flags.verified_mic = 0; + + HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); + + ctx->negoex_step = 0; + ctx->negoex_transcript = NULL; + ctx->negoex_seqnum = 0; + HEIM_TAILQ_INIT(&ctx->negoex_mechs); + memset(ctx->negoex_conv_id, 0, GUID_LENGTH); + + *context_handle = (gss_ctx_id_t)ctx; + + return GSS_S_COMPLETE; +} + +/* + * Free a SPNEGO context handle. The caller must have acquired + * the lock before this is called. + */ +OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token + ) +{ + gssspnego_ctx ctx; + OM_uint32 ret, minor; + + *minor_status = 0; + + if (context_handle == NULL) { + return GSS_S_NO_CONTEXT; + } + + if (output_token != GSS_C_NO_BUFFER) { + output_token->length = 0; + output_token->value = NULL; + } + + ctx = (gssspnego_ctx)*context_handle; + *context_handle = GSS_C_NO_CONTEXT; + + if (ctx == NULL) { + return GSS_S_NO_CONTEXT; + } + + if (ctx->NegTokenInit_mech_types.value) + free(ctx->NegTokenInit_mech_types.value); + + ctx->preferred_mech_type = GSS_C_NO_OID; + ctx->negotiated_mech_type = GSS_C_NO_OID; + ctx->selected_mech_type = GSS_C_NO_OID; + + gss_release_name(&minor, &ctx->target_name); + gss_release_name(&minor, &ctx->mech_src_name); + + if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) { + ret = gss_delete_sec_context(minor_status, + &ctx->negotiated_ctx_id, + output_token); + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + } else { + ret = GSS_S_COMPLETE; + } + + _gss_negoex_release_context(ctx); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + + free(ctx); + + return ret; +} + +static int +inq_context_by_oid_bool(gssspnego_ctx ctx, gss_OID oid) +{ + OM_uint32 major, minor; + gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + uint8_t ret = 0; + + major = gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id, + oid, &data_set); + if (major != GSS_S_COMPLETE) + return FALSE; + + if (data_set != GSS_C_NO_BUFFER_SET && + data_set->count == 1 && + data_set->elements[0].length == 1) + ret = *((uint8_t *)data_set->elements[0].value); + + gss_release_buffer_set(&minor, &data_set); + + return ret != 0; +} + +/* + * Returns TRUE if it is safe to omit mechListMIC. + */ + +int +_gss_spnego_safe_omit_mechlist_mic(gssspnego_ctx ctx) +{ + int safe_omit = FALSE; + + if (ctx->flags.peer_require_mic) { + _gss_mg_log(10, "spnego: mechListMIC required by peer"); + } else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) { + /* [MS-SPNG] Appendix A <7> Section 3.1.5.1: may be old peer with buggy SPNEGO */ + safe_omit = TRUE; + _gss_mg_log(10, "spnego: mechListMIC omitted for legacy interoperability"); + } else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_REQUIRE_MECHLIST_MIC)) { + /* [MS-SPNG] Appendix A <7> Section 3.1.5.1: allow NTLM to force MIC */ + _gss_mg_log(10, "spnego: mechListMIC required by mechanism"); + } else if (gss_oid_equal(ctx->selected_mech_type, ctx->preferred_mech_type)) { + safe_omit = TRUE; + _gss_mg_log(10, "spnego: mechListMIC omitted as preferred mechanism selected"); + } else { + _gss_mg_log(10, "spnego: mechListMIC required by default"); + } + + return safe_omit; +} + +/* + * A map between a GSS-API flag and a (mechanism attribute, weight) + * tuple. The list of mechanisms is re-ordered by aggregate weight + * (highest weight is more preferred, e.g. if GSS_C_MUTUAL_FLAG and + * GSS_C_ANON_FLAG are set, we prefer a mechanism that supports + * mutual authentication over one that only supports anonymous). + */ +static struct { + OM_uint32 flag; + gss_OID ma; + int weight; +} flag_to_ma_map[] = { + { GSS_C_MUTUAL_FLAG, GSS_C_MA_AUTH_TARG, 2 }, + { GSS_C_ANON_FLAG, GSS_C_MA_AUTH_INIT_ANON, 1 }, +}; + +/* + * Returns a bitmask indicating GSS flags we can sort on. + */ +static inline OM_uint32 +mech_flag_mask(void) +{ + size_t i; + OM_uint32 mask = 0; + + for (i = 0; i < sizeof(flag_to_ma_map)/sizeof(flag_to_ma_map[0]); i++) + mask |= flag_to_ma_map[i].flag; + + return mask; +} + +/* + * Returns an integer representing the preference weighting for a + * mechanism, based on the requested GSS flags. + */ +static int +mech_weight(gss_const_OID mech, OM_uint32 req_flags) +{ + OM_uint32 major, minor; + gss_OID_set mech_attrs = GSS_C_NO_OID_SET; + int weight = 0; + size_t i, j; + + major = gss_inquire_attrs_for_mech(&minor, mech, &mech_attrs, NULL); + if (GSS_ERROR(major)) + return 0; + + for (i = 0; i < sizeof(flag_to_ma_map)/sizeof(flag_to_ma_map[0]); i++) { + if ((req_flags & flag_to_ma_map[i].flag) == 0) + continue; + + for (j = 0; j < mech_attrs->count; j++) { + if (gss_oid_equal(flag_to_ma_map[i].ma, &mech_attrs->elements[j])) { + weight += flag_to_ma_map[i].weight; + continue; + } + } + } + + gss_release_oid_set(&minor, &mech_attrs); + + return weight; +} + +static int +mech_compare(const void *mech1, const void *mech2, void *req_flags_p) +{ + OM_uint32 req_flags = *((OM_uint32 *)req_flags_p); + int mech1_weight = mech_weight(mech1, req_flags); + int mech2_weight = mech_weight(mech2, req_flags); + + return mech2_weight - mech1_weight; +} + +/* + * Order a list of mechanisms by weight based on requested GSS flags. + */ +static void +order_mechs_by_flags(gss_OID_set mechs, OM_uint32 req_flags) +{ + if (req_flags & mech_flag_mask()) { /* skip if flags irrelevant */ + /* + * NB: must be a stable sort to preserve the existing order + * of mechanisms that are equally weighted. + */ + mergesort_r(mechs->elements, mechs->count, + sizeof(gss_OID_desc), mech_compare, &req_flags); + } +} + +static OM_uint32 +add_mech_type(OM_uint32 *minor_status, + gss_OID mech_type, + MechTypeList *mechtypelist) +{ + MechType mech; + int ret; + + heim_assert(!gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM), + "SPNEGO mechanism not filtered"); + + ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL); + if (ret == 0) { + ret = add_MechTypeList(mechtypelist, &mech); + free_MechType(&mech); + } + + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +static int +add_mech_if_approved(OM_uint32 *minor_status, + gss_const_name_t target_name, + OM_uint32 (*func)(OM_uint32 *, void *, gss_const_name_t, gss_const_cred_id_t, gss_OID), + void *userptr, + int includeMSCompatOID, + gss_const_cred_id_t cred_handle, + MechTypeList *mechtypelist, + gss_OID mech_oid, + gss_OID *first_mech, + OM_uint32 *first_major, + OM_uint32 *first_minor, + int *added_negoex) +{ + OM_uint32 major, minor; + + /* + * Unapproved mechanisms are ignored, but we capture their result + * code in case we didn't find any other mechanisms, in which case + * we return that to the caller of _gss_spnego_indicate_mechtypelist(). + */ + major = (*func)(&minor, userptr, target_name, cred_handle, mech_oid); + if (major != GSS_S_COMPLETE) { + if (*first_mech == GSS_C_NO_OID) { + *first_major = major; + *first_minor = minor; + } + return GSS_S_COMPLETE; + } + + if (_gss_negoex_mech_p(mech_oid)) { + if (*added_negoex == FALSE) { + major = add_mech_type(minor_status, GSS_NEGOEX_MECHANISM, mechtypelist); + if (major != GSS_S_COMPLETE) + return major; + *added_negoex = TRUE; + } + + if (*first_mech == GSS_C_NO_OID) + *first_mech = GSS_NEGOEX_MECHANISM; + + /* if NegoEx-only mech, we are done */ + if (!_gss_negoex_and_spnego_mech_p(mech_oid)) + return GSS_S_COMPLETE; + } + + if (includeMSCompatOID && gss_oid_equal(mech_oid, GSS_KRB5_MECHANISM)) { + major = add_mech_type(minor_status, + &_gss_spnego_mskrb_mechanism_oid_desc, + mechtypelist); + if (major != GSS_S_COMPLETE) + return major; + } + + major = add_mech_type(minor_status, mech_oid, mechtypelist); + if (major != GSS_S_COMPLETE) + return major; + + if (*first_mech == GSS_C_NO_OID) + *first_mech = mech_oid; + + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, + gss_const_name_t target_name, + OM_uint32 req_flags, + OM_uint32 (*func)(OM_uint32 *, void *, gss_const_name_t, gss_const_cred_id_t, gss_OID), + void *userptr, + int includeMSCompatOID, + gss_const_cred_id_t cred_handle, + MechTypeList *mechtypelist, + gss_OID *preferred_mech) +{ + gss_OID_set supported_mechs = GSS_C_NO_OID_SET; + gss_OID first_mech = GSS_C_NO_OID; + OM_uint32 ret, minor; + OM_uint32 first_major = GSS_S_BAD_MECH, first_minor = 0; + size_t i; + int added_negoex = FALSE, canonical_order = FALSE; + + mechtypelist->len = 0; + mechtypelist->val = NULL; + + if (cred_handle != GSS_C_NO_CREDENTIAL) + ret = _gss_spnego_inquire_cred_mechs(minor_status, cred_handle, + &supported_mechs, &canonical_order); + else + ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs); + if (ret != GSS_S_COMPLETE) + return ret; + + if (!canonical_order) + order_mechs_by_flags(supported_mechs, req_flags); + + heim_assert(supported_mechs != GSS_C_NO_OID_SET, + "NULL mech set returned by SPNEGO inquire/indicate mechs"); + + /* + * Previously krb5 was tried explicitly, but now the internal mech + * list is reordered so that krb5 is first, this should no longer + * be required. This permits an application to specify another + * mechanism as preferred over krb5 using gss_set_neg_mechs(). + */ + for (i = 0; i < supported_mechs->count; i++) { + ret = add_mech_if_approved(minor_status, target_name, + func, userptr, includeMSCompatOID, + cred_handle, mechtypelist, + &supported_mechs->elements[i], + &first_mech, + &first_major, &first_minor, + &added_negoex); + if (ret != GSS_S_COMPLETE) { + gss_release_oid_set(&minor, &supported_mechs); + return ret; + } + } + + heim_assert(mechtypelist->len == 0 || first_mech != GSS_C_NO_OID, + "mechtypelist non-empty but no mech selected"); + + if (first_mech != GSS_C_NO_OID) + ret = _gss_intern_oid(minor_status, first_mech, &first_mech); + else if (GSS_ERROR(first_major)) { + ret = first_major; + *minor_status = first_minor; + } else + ret = GSS_S_BAD_MECH; + + if (preferred_mech != NULL) + *preferred_mech = first_mech; + + gss_release_oid_set(&minor, &supported_mechs); + + return ret; +} + +/* + * + */ + +OM_uint32 +_gss_spnego_verify_mechtypes_mic(OM_uint32 *minor_status, + gssspnego_ctx ctx, + heim_octet_string *mic) +{ + gss_buffer_desc mic_buf; + OM_uint32 major_status; + + if (mic == NULL) { + *minor_status = 0; + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_DEFECTIVE_TOKEN, 0, + "SPNEGO peer failed to send mechListMIC"); + } + + if (ctx->flags.verified_mic) { + /* This doesn't make sense, we've already verified it? */ + *minor_status = 0; + return GSS_S_DUPLICATE_TOKEN; + } + + mic_buf.length = mic->length; + mic_buf.value = mic->data; + + major_status = gss_verify_mic(minor_status, + ctx->negotiated_ctx_id, + &ctx->NegTokenInit_mech_types, + &mic_buf, + NULL); + if (major_status == GSS_S_COMPLETE) { + _gss_spnego_ntlm_reset_crypto(minor_status, ctx, TRUE); + } else if (major_status == GSS_S_UNAVAILABLE) { + _gss_mg_log(10, "mech doesn't support MIC, allowing anyway"); + } else if (major_status) { + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_DEFECTIVE_TOKEN, *minor_status, + "SPNEGO peer sent invalid mechListMIC"); + } + ctx->flags.verified_mic = 1; + + *minor_status = 0; + + return GSS_S_COMPLETE; +} + +/* + * According to [MS-SPNG] 3.3.5.1 the crypto state for NTLM is reset + * before the completed context is returned to the application. + */ + +OM_uint32 +_gss_spnego_ntlm_reset_crypto(OM_uint32 *minor_status, + gssspnego_ctx ctx, + OM_uint32 verify) +{ + if (gss_oid_equal(ctx->negotiated_mech_type, GSS_NTLM_MECHANISM)) { + gss_buffer_desc value; + + value.length = sizeof(verify); + value.value = &verify; + + return gss_set_sec_context_option(minor_status, + &ctx->negotiated_ctx_id, + GSS_C_NTLM_RESET_CRYPTO, + &value); + } + + return GSS_S_COMPLETE; +} + +void +_gss_spnego_log_mech(const char *prefix, gss_const_OID oid) +{ + gss_buffer_desc oidbuf = GSS_C_EMPTY_BUFFER; + OM_uint32 junk; + const char *name = NULL; + + if (!_gss_mg_log_level(10)) + return; + + if (oid == GSS_C_NO_OID || + gss_oid_to_str(&junk, (gss_OID)oid, &oidbuf) != GSS_S_COMPLETE) { + _gss_mg_log(10, "spnego: %s (null)", prefix); + return; + } + + if (gss_oid_equal(oid, GSS_NEGOEX_MECHANISM)) + name = "negoex"; /* not a real mech */ + else if (gss_oid_equal(oid, &_gss_spnego_mskrb_mechanism_oid_desc)) + name = "mskrb"; + else { + gssapi_mech_interface m = __gss_get_mechanism(oid); + if (m) + name = m->gm_name; + } + + _gss_mg_log(10, "spnego: %s %s { %.*s }", + prefix, + name ? name : "unknown", + (int)oidbuf.length, (char *)oidbuf.value); + gss_release_buffer(&junk, &oidbuf); +} + +void +_gss_spnego_log_mechTypes(MechTypeList *mechTypes) +{ + size_t i; + char mechbuf[64]; + size_t mech_len; + gss_OID_desc oid; + int ret; + + if (!_gss_mg_log_level(10)) + return; + + for (i = 0; i < mechTypes->len; i++) { + ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + &mechTypes->val[i], + &mech_len); + if (ret) + continue; + + oid.length = (OM_uint32)mech_len; + oid.elements = mechbuf + sizeof(mechbuf) - mech_len; + + _gss_spnego_log_mech("initiator proposed mech", &oid); + } +} + +/* + * Indicate mechs negotiable by SPNEGO + */ + +OM_uint32 +_gss_spnego_indicate_mechs(OM_uint32 *minor_status, + gss_OID_set *mechs_p) +{ + gss_OID_desc oids[3]; + gss_OID_set_desc except; + + *mechs_p = GSS_C_NO_OID_SET; + + oids[0] = *GSS_C_MA_DEPRECATED; + oids[1] = *GSS_C_MA_NOT_DFLT_MECH; + oids[2] = *GSS_C_MA_MECH_NEGO; + + except.count = sizeof(oids) / sizeof(oids[0]); + except.elements = oids; + + return gss_indicate_mechs_by_attrs(minor_status, + GSS_C_NO_OID_SET, + &except, + GSS_C_NO_OID_SET, + mechs_p); +} + +/* + * Indicate mechs in cred negotiatble by SPNEGO + */ + +OM_uint32 +_gss_spnego_inquire_cred_mechs(OM_uint32 *minor_status, + gss_const_cred_id_t cred, + gss_OID_set *mechs_p, + int *canonical_order) +{ + OM_uint32 ret, junk; + gss_OID_set cred_mechs = GSS_C_NO_OID_SET; + gss_OID_set negotiable_mechs = GSS_C_NO_OID_SET; + size_t i; + + *mechs_p = GSS_C_NO_OID_SET; + *canonical_order = FALSE; + + heim_assert(cred != GSS_C_NO_CREDENTIAL, "Invalid null credential handle"); + + ret = gss_get_neg_mechs(minor_status, cred, &cred_mechs); + if (ret == GSS_S_COMPLETE) { + *canonical_order = TRUE; + } else { + ret = gss_inquire_cred(minor_status, cred, NULL, NULL, NULL, &cred_mechs); + if (ret != GSS_S_COMPLETE) + goto out; + } + + heim_assert(cred_mechs != GSS_C_NO_OID_SET && cred_mechs->count > 0, + "gss_inquire_cred succeeded but returned no mechanisms"); + + ret = _gss_spnego_indicate_mechs(minor_status, &negotiable_mechs); + if (ret != GSS_S_COMPLETE) + goto out; + + heim_assert(negotiable_mechs != GSS_C_NO_OID_SET, + "_gss_spnego_indicate_mechs succeeded but returned null OID set"); + + ret = gss_create_empty_oid_set(minor_status, mechs_p); + if (ret != GSS_S_COMPLETE) + goto out; + + /* Filter credential mechs by negotiable mechs, order by credential mechs */ + for (i = 0; i < cred_mechs->count; i++) { + gss_OID cred_mech = &cred_mechs->elements[i]; + int present = 0; + + gss_test_oid_set_member(&junk, cred_mech, negotiable_mechs, &present); + if (!present) + continue; + + ret = gss_add_oid_set_member(minor_status, cred_mech, mechs_p); + if (ret != GSS_S_COMPLETE) + break; + } + +out: + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(&junk, mechs_p); + gss_release_oid_set(&junk, &cred_mechs); + gss_release_oid_set(&junk, &negotiable_mechs); + + return ret; +} + diff --git a/third_party/heimdal/lib/gssapi/spnego/context_storage.c b/third_party/heimdal/lib/gssapi/spnego/context_storage.c new file mode 100644 index 0000000..3924bd3 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/context_storage.c @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2021, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +#define SC_MECH_TYPES 0x0001 +#define SC_PREFERRED_MECH_TYPE 0x0002 +#define SC_SELECTED_MECH_TYPE 0x0004 +#define SC_NEGOTIATED_MECH_TYPE 0x0008 +#define SC_NEGOTIATED_CTX_ID 0x0010 +#define SC_MECH_FLAGS 0x0020 +#define SC_MECH_TIME_REC 0x0040 +#define SC_MECH_SRC_NAME 0x0080 +#define SC_TARGET_NAME 0x0100 +#define SC_NEGOEX 0x0200 + +#define SNC_OID 0x01 +#define SNC_MECH_CONTEXT 0x02 +#define SNC_METADATA 0x04 + +static krb5_error_code +ret_spnego_context(krb5_storage *sp, gssspnego_ctx *ctxp); +static krb5_error_code +store_spnego_context(krb5_storage *sp, gssspnego_ctx ctx); + +static krb5_error_code +ret_negoex_auth_mech(krb5_storage *sp, struct negoex_auth_mech **mechp); +static krb5_error_code +store_negoex_auth_mech(krb5_storage *sp, struct negoex_auth_mech *mech); + +#ifdef sc_flags +#undef sc_flags +#endif + +static uint16_t +spnego_flags_to_int(struct spnego_flags flags); +static struct spnego_flags +int_to_spnego_flags(uint16_t f); + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_import_sec_context_internal(OM_uint32 *minor, + gss_const_buffer_t buffer, + gssspnego_ctx *ctxp) +{ + krb5_error_code ret; + krb5_storage *sp; + + sp = krb5_storage_from_readonly_mem(buffer->value, buffer->length); + if (sp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + ret = ret_spnego_context(sp, ctxp); + + krb5_storage_free(sp); + + *minor = ret; + return ret ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_export_sec_context_internal(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_buffer_t buffer) +{ + krb5_error_code ret; + krb5_storage *sp; + krb5_data data; + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_data_zero(&data); + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + ret = store_spnego_context(sp, ctx); + if (ret == 0) + ret = krb5_storage_to_data(sp, &data); + if (ret == 0) { + buffer->length = data.length; + buffer->value = data.data; + } + + krb5_storage_free(sp); + + *minor = ret; + return ret ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +static krb5_error_code +ret_spnego_context(krb5_storage *sp, gssspnego_ctx *ctxp) +{ + OM_uint32 major = GSS_S_COMPLETE, minor; + gssspnego_ctx ctx = NULL; + krb5_error_code ret = 0; + krb5_data data; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + uint16_t sc_flags, spnego_flags; + + *ctxp = NULL; + krb5_data_zero(&data); + + CHECK(major, _gss_spnego_alloc_sec_context(&minor, (gss_ctx_id_t *)&ctx)); + + CHECK(ret, krb5_ret_uint16(sp, &sc_flags)); + CHECK(ret, krb5_ret_uint16(sp, &spnego_flags)); + ctx->flags = int_to_spnego_flags(spnego_flags); + + if (sc_flags & SC_MECH_TYPES) + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &ctx->NegTokenInit_mech_types)); + if (sc_flags & SC_PREFERRED_MECH_TYPE) + CHECK(major, _gss_mg_ret_oid(&minor, sp, &ctx->preferred_mech_type)); + if (sc_flags & SC_SELECTED_MECH_TYPE) + CHECK(major, _gss_mg_ret_oid(&minor, sp, &ctx->selected_mech_type)); + if (sc_flags & SC_NEGOTIATED_MECH_TYPE) + CHECK(major, _gss_mg_ret_oid(&minor, sp, &ctx->negotiated_mech_type)); + + if (sc_flags & SC_NEGOTIATED_CTX_ID) { + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &buf)); + CHECK(major, gss_import_sec_context(&minor, &buf, + &ctx->negotiated_ctx_id)); + gss_release_buffer(&minor, &buf); + } + + if (sc_flags & SC_MECH_FLAGS) + CHECK(ret, krb5_ret_uint32(sp, &ctx->mech_flags)); + if (sc_flags & SC_MECH_TIME_REC) + CHECK(ret, krb5_ret_uint32(sp, &ctx->mech_time_rec)); + else + ctx->mech_time_rec = GSS_C_INDEFINITE; + + if (sc_flags & SC_MECH_SRC_NAME) { + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &buf)); + CHECK(major, gss_import_name(&minor, &buf, GSS_C_NT_EXPORT_NAME, + &ctx->mech_src_name)); + gss_release_buffer(&minor, &buf); + } + + if (sc_flags & SC_TARGET_NAME) { + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &buf)); + CHECK(major, gss_import_name(&minor, &buf, GSS_C_NT_EXPORT_NAME, + &ctx->target_name)); + gss_release_buffer(&minor, &buf); + } + + if (sc_flags & SC_NEGOEX) { + uint8_t i, nschemes; + + CHECK(ret, krb5_ret_uint8(sp, &ctx->negoex_step)); + + CHECK(ret, krb5_ret_data(sp, &data)); + ctx->negoex_transcript = krb5_storage_emem(); + if (ctx->negoex_transcript == NULL) { + ret = ENOMEM; + goto fail; + } + + krb5_storage_set_byteorder(ctx->negoex_transcript, + KRB5_STORAGE_BYTEORDER_LE); + if (krb5_storage_write(ctx->negoex_transcript, + data.data, data.length) != data.length) { + ret = ENOMEM; + goto fail; + } + krb5_data_free(&data); + + CHECK(ret, krb5_ret_uint32(sp, &ctx->negoex_seqnum)); + + if (krb5_storage_read(sp, ctx->negoex_conv_id, + GUID_LENGTH) != GUID_LENGTH) { + ret = KRB5_BAD_MSIZE; + goto fail; + } + + CHECK(ret, krb5_ret_uint8(sp, &nschemes)); + for (i = 0; i < nschemes; i++) { + struct negoex_auth_mech *mech; + + CHECK(ret, ret_negoex_auth_mech(sp, &mech)); + /* `mech' will not be NULL here, but quiet scan-build */ + if (mech) + HEIM_TAILQ_INSERT_TAIL(&ctx->negoex_mechs, mech, links); + } + } + + *ctxp = ctx; + +fail: + if (ret == 0 && GSS_ERROR(major)) + ret = minor ? minor : KRB5_BAD_MSIZE; + if (ret) + _gss_spnego_delete_sec_context(&minor, (gss_ctx_id_t *)&ctx, + GSS_C_NO_BUFFER); + krb5_data_free(&data); + gss_release_buffer(&minor, &buf); + + return ret; +} + +static krb5_error_code +store_spnego_context(krb5_storage *sp, gssspnego_ctx ctx) +{ + OM_uint32 major = GSS_S_COMPLETE, minor; + krb5_error_code ret = 0; + krb5_data data; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + uint16_t sc_flags = 0, spnego_flags; + + krb5_data_zero(&data); + + if (ctx->NegTokenInit_mech_types.length) + sc_flags |= SC_MECH_TYPES; + if (ctx->preferred_mech_type) + sc_flags |= SC_PREFERRED_MECH_TYPE; + if (ctx->selected_mech_type) + sc_flags |= SC_SELECTED_MECH_TYPE; + if (ctx->negotiated_mech_type) + sc_flags |= SC_NEGOTIATED_MECH_TYPE; + if (ctx->negotiated_ctx_id) + sc_flags |= SC_NEGOTIATED_CTX_ID; + if (ctx->mech_flags) + sc_flags |= SC_MECH_FLAGS; + if (ctx->mech_time_rec != GSS_C_INDEFINITE) + sc_flags |= SC_MECH_TIME_REC; + if (ctx->mech_src_name) + sc_flags |= SC_MECH_SRC_NAME; + if (ctx->target_name) + sc_flags |= SC_TARGET_NAME; + if (ctx->negoex_step) + sc_flags |= SC_NEGOEX; + + CHECK(ret, krb5_store_uint16(sp, sc_flags)); + spnego_flags = spnego_flags_to_int(ctx->flags); + CHECK(ret, krb5_store_uint16(sp, spnego_flags)); + + if (sc_flags & SC_MECH_TYPES) + CHECK(major, _gss_mg_store_buffer(&minor, sp, &ctx->NegTokenInit_mech_types)); + if (sc_flags & SC_PREFERRED_MECH_TYPE) + CHECK(major, _gss_mg_store_oid(&minor, sp, ctx->preferred_mech_type)); + if (sc_flags & SC_SELECTED_MECH_TYPE) + CHECK(major, _gss_mg_store_oid(&minor, sp, ctx->selected_mech_type)); + if (sc_flags & SC_NEGOTIATED_MECH_TYPE) + CHECK(major, _gss_mg_store_oid(&minor, sp, ctx->negotiated_mech_type)); + if (sc_flags & SC_NEGOTIATED_CTX_ID) { + CHECK(major, gss_export_sec_context(&minor, &ctx->negotiated_ctx_id, + &buf)); + CHECK(major, _gss_mg_store_buffer(&minor, sp, &buf)); + gss_release_buffer(&minor, &buf); + } + if (sc_flags & SC_MECH_FLAGS) + CHECK(ret, krb5_store_uint32(sp, ctx->mech_flags)); + if (sc_flags & SC_MECH_TIME_REC) + CHECK(ret, krb5_store_uint32(sp, ctx->mech_time_rec)); + if (sc_flags & SC_MECH_SRC_NAME) { + CHECK(major, gss_export_name(&minor, ctx->mech_src_name, &buf)); + CHECK(major, _gss_mg_store_buffer(&minor, sp, &buf)); + gss_release_buffer(&minor, &buf); + } + + if (sc_flags & SC_TARGET_NAME) { + CHECK(major, gss_export_name(&minor, ctx->target_name, &buf)); + CHECK(major, _gss_mg_store_buffer(&minor, sp, &buf)); + gss_release_buffer(&minor, &buf); + } + + if (sc_flags & SC_NEGOEX) { + uint32_t nschemes; + struct negoex_auth_mech *mech; + + CHECK(ret, krb5_store_uint8(sp, ctx->negoex_step)); + + if (ctx->negoex_transcript) { + CHECK(ret, krb5_storage_to_data(ctx->negoex_transcript, &data)); + } + CHECK(ret, krb5_store_data(sp, data)); + krb5_data_free(&data); + + CHECK(ret, krb5_store_uint32(sp, ctx->negoex_seqnum)); + CHECK(ret, krb5_store_bytes(sp, ctx->negoex_conv_id, GUID_LENGTH)); + + nschemes = 0; + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) + nschemes++; + + if (nschemes > 0xff) { + ret = ERANGE; + goto fail; + } + CHECK(ret, krb5_store_uint8(sp, nschemes)); + + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) + CHECK(ret, store_negoex_auth_mech(sp, mech)); + } + +fail: + if (ret == 0 && GSS_ERROR(major)) + ret = minor ? minor : KRB5_BAD_MSIZE; + krb5_data_free(&data); + gss_release_buffer(&minor, &buf); + + return ret; +} + +static krb5_error_code +ret_negoex_auth_mech(krb5_storage *sp, struct negoex_auth_mech **mechp) +{ + krb5_error_code ret; + OM_uint32 major = GSS_S_COMPLETE, minor; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + struct negoex_auth_mech *mech; + krb5_context context = _gss_mg_krb5_context(); + uint8_t snc_flags, negoex_flags; + + *mechp = NULL; + + mech = calloc(1, sizeof(*mech)); + if (mech == NULL) { + ret = ENOMEM; + goto fail; + } + + CHECK(ret, krb5_ret_uint8(sp, &snc_flags)); + CHECK(ret, krb5_ret_uint8(sp, &negoex_flags)); + if (negoex_flags & (1 << 0)) + mech->complete = 1; + if (negoex_flags & (1 << 1)) + mech->sent_checksum = 1; + if (negoex_flags & (1 << 2)) + mech->verified_checksum = 1; + + if (snc_flags & SNC_OID) + CHECK(major, _gss_mg_ret_oid(&minor, sp, &mech->oid)); + + if (krb5_storage_read(sp, mech->scheme, GUID_LENGTH) != GUID_LENGTH) { + ret = KRB5_BAD_MSIZE; + goto fail; + } + + if (snc_flags & SNC_MECH_CONTEXT) { + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &buf)); + CHECK(major, gss_import_sec_context(&minor, &buf, + &mech->mech_context)); + gss_release_buffer(&minor, &buf); + } + + if (snc_flags & SNC_METADATA) + CHECK(major, _gss_mg_ret_buffer(&minor, sp, &mech->metadata)); + +fail: + if (ret == 0 && GSS_ERROR(major)) + ret = minor ? minor : KRB5_BAD_MSIZE; + if (ret) + _gss_negoex_release_auth_mech(context, mech); + else + *mechp = mech; + + gss_release_buffer(&minor, &buf); + return ret; +} + +static krb5_error_code +store_negoex_auth_mech(krb5_storage *sp, struct negoex_auth_mech *mech) +{ + krb5_error_code ret; + OM_uint32 major = GSS_S_COMPLETE, minor; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + uint8_t negoex_flags = 0, snc_flags = 0; + + negoex_flags = 0; + if (mech->complete) + negoex_flags |= (1 << 0); + if (mech->sent_checksum) + negoex_flags |= (1 << 1); + if (mech->verified_checksum) + negoex_flags |= (1 << 2); + + if (mech->oid) + snc_flags |= SNC_OID; + if (mech->mech_context) + snc_flags |= SNC_MECH_CONTEXT; + if (mech->metadata.length) + snc_flags |= SNC_METADATA; + + CHECK(ret, krb5_store_uint8(sp, snc_flags)); + CHECK(ret, krb5_store_uint8(sp, negoex_flags)); + + if (snc_flags & SNC_OID) + CHECK(major, _gss_mg_store_oid(&minor, sp, mech->oid)); + + CHECK(ret, krb5_store_bytes(sp, mech->scheme, GUID_LENGTH)); + + if (snc_flags & SNC_MECH_CONTEXT) { + CHECK(major, gss_export_sec_context(&minor, &mech->mech_context, + &buf)); + CHECK(major, _gss_mg_store_buffer(&minor, sp, &buf)); + gss_release_buffer(&minor, &buf); + } + + if (snc_flags & SNC_METADATA) + CHECK(major, _gss_mg_store_buffer(&minor, sp, &mech->metadata)); + +fail: + if (ret == 0 && GSS_ERROR(major)) + ret = minor ? minor : KRB5_BAD_MSIZE; + gss_release_buffer(&minor, &buf); + + return ret; +} + +static uint16_t +spnego_flags_to_int(struct spnego_flags flags) +{ + uint16_t f = 0; + + if (flags.open) + f |= (1 << 0); + if (flags.local) + f |= (1 << 1); + if (flags.require_mic) + f |= (1 << 2); + if (flags.peer_require_mic) + f |= (1 << 3); + if (flags.sent_mic) + f |= (1 << 4); + if (flags.verified_mic) + f |= (1 << 5); + if (flags.safe_omit) + f |= (1 << 6); + if (flags.maybe_open) + f |= (1 << 7); + if (flags.seen_supported_mech) + f |= (1 << 8); + + return f; +} + +static struct spnego_flags +int_to_spnego_flags(uint16_t f) +{ + struct spnego_flags flags; + + memset(&flags, 0, sizeof(flags)); + + if (f & (1 << 0)) + flags.open = 1; + if (f & (1 << 1)) + flags.local = 1; + if (f & (1 << 2)) + flags.require_mic = 1; + if (f & (1 << 3)) + flags.peer_require_mic = 1; + if (f & (1 << 4)) + flags.sent_mic = 1; + if (f & (1 << 5)) + flags.verified_mic = 1; + if (f & (1 << 6)) + flags.safe_omit = 1; + if (f & (1 << 7)) + flags.maybe_open = 1; + if (f & (1 << 8)) + flags.seen_supported_mech = 1; + + return flags; +} diff --git a/third_party/heimdal/lib/gssapi/spnego/context_stubs.c b/third_party/heimdal/lib/gssapi/spnego/context_stubs.c new file mode 100644 index 0000000..638e90d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/context_stubs.c @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token + (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer + ) +{ + gss_ctx_id_t context; + gssspnego_ctx ctx; + OM_uint32 ret; + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + context = (gss_ctx_id_t)context_handle; + ctx = (gssspnego_ctx)context_handle; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + ret = gss_process_context_token(minor_status, + ctx->negotiated_ctx_id, + token_buffer); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + + return _gss_spnego_internal_delete_sec_context(minor_status, + &context, + GSS_C_NO_BUFFER); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_delete_sec_context + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token + ) +{ + gssspnego_ctx ctx; + + if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + ctx = (gssspnego_ctx)*context_handle; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + return _gss_spnego_internal_delete_sec_context(minor_status, + context_handle, + output_token); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time + (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 *time_rec + ) +{ + gssspnego_ctx ctx; + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_context_time(minor_status, + ctx->negotiated_ctx_id, + time_rec); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic + (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_get_mic(minor_status, ctx->negotiated_ctx_id, + qop_req, message_buffer, message_token); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_verify_mic(minor_status, + ctx->negotiated_ctx_id, + message_buffer, + token_buffer, + qop_state); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer + ) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_wrap(minor_status, + ctx->negotiated_ctx_id, + conf_req_flag, + qop_req, + input_message_buffer, + conf_state, + output_message_buffer); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state + ) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_unwrap(minor_status, + ctx->negotiated_ctx_id, + input_message_buffer, + output_message_buffer, + conf_state, + qop_state); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_context ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t * src_name, + gss_name_t * targ_name, + OM_uint32 * lifetime_rec, + gss_OID * mech_type, + OM_uint32 * ctx_flags, + int * locally_initiated, + int * open_context + ) +{ + gssspnego_ctx ctx; + OM_uint32 maj_stat; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + maj_stat = gss_inquire_context(minor_status, + ctx->negotiated_ctx_id, + src_name, + targ_name, + lifetime_rec, + mech_type, + ctx_flags, + locally_initiated, + open_context); + + if (open_context) + *open_context = gssspnego_ctx_complete_p(ctx); + + return maj_stat; +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap_size_limit ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 * max_input_size + ) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_wrap_size_limit(minor_status, + ctx->negotiated_ctx_id, + conf_req_flag, + qop_req, + req_output_size, + max_input_size); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_export_sec_context ( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t interprocess_token + ) +{ + gssspnego_ctx ctx; + OM_uint32 major_status; + + *minor_status = 0; + + if (context_handle == NULL) + return GSS_S_NO_CONTEXT; + + ctx = (gssspnego_ctx)*context_handle; + + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + /* + * Partial context export is only supported on the acceptor side, as we + * cannot represent the initiator function pointer state in an exported + * token, and also because it is mostly useful for acceptors which need + * to manage multiple initiator states. + */ + if (ctx->flags.local && !gssspnego_ctx_complete_p(ctx)) { + major_status = GSS_S_NO_CONTEXT; + goto out; + } + + major_status = _gss_spnego_export_sec_context_internal(minor_status, + ctx, + interprocess_token); + +out: + if (major_status == GSS_S_COMPLETE) + major_status = _gss_spnego_internal_delete_sec_context(minor_status, + context_handle, + GSS_C_NO_BUFFER); + else + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return major_status; +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_import_sec_context ( + OM_uint32 * minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle + ) +{ + return _gss_spnego_import_sec_context_internal(minor_status, + interprocess_token, + (gssspnego_ctx *)context_handle); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech ( + OM_uint32 * minor_status, + const gss_OID mechanism, + gss_OID_set * name_types + ) +{ + gss_OID_set mechs, names, n; + OM_uint32 ret, junk; + size_t i, j; + + *name_types = NULL; + + ret = _gss_spnego_indicate_mechs(minor_status, &mechs); + if (ret != GSS_S_COMPLETE) + return ret; + + ret = gss_create_empty_oid_set(minor_status, &names); + if (ret != GSS_S_COMPLETE) + goto out; + + for (i = 0; i < mechs->count; i++) { + ret = gss_inquire_names_for_mech(minor_status, + &mechs->elements[i], + &n); + if (ret) + continue; + + for (j = 0; j < n->count; j++) + gss_add_oid_set_member(minor_status, + &n->elements[j], + &names); + gss_release_oid_set(&junk, &n); + } + + ret = GSS_S_COMPLETE; + *name_types = names; +out: + + gss_release_oid_set(&junk, &mechs); + + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gssspnego_ctx ctx = (gssspnego_ctx)context_handle; + + *minor_status = 0; + + if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gssspnego_ctx ctx = (gssspnego_ctx)context_handle; + + *minor_status = 0; + + if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + return gss_unwrap_iov(minor_status, + ctx->negotiated_ctx_id, + conf_state, qop_state, + iov, iov_count); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + gssspnego_ctx ctx = (gssspnego_ctx)context_handle; + + *minor_status = 0; + + if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id, + conf_req_flag, qop_req, conf_state, + iov, iov_count); +} + +#if 0 +OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_buffer_t input_message_buffer) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_complete_auth_token(minor_status, + ctx->negotiated_ctx_id, + input_message_buffer); +} +#endif + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_inquire_sec_context_by_oid(minor_status, + ctx->negotiated_ctx_id, + desired_object, + data_set); +} + +OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + /* + * Return GSS_S_UNAVAILABLE with a NULL context handle as at + * present no context options can be set globally on SPNEGO + * itself. Global mechanism context options are set directly + * on the mechanism; per-context context options are set below + * if ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT. + */ + if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) + return GSS_S_UNAVAILABLE; + + ctx = (gssspnego_ctx)*context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + return GSS_S_NO_CONTEXT; + } + + return gss_set_sec_context_option(minor_status, + &ctx->negotiated_ctx_id, + desired_object, + value); +} + + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + gssspnego_ctx ctx; + + *minor_status = 0; + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + ctx = (gssspnego_ctx)context_handle; + + if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + return gss_pseudo_random(minor_status, + ctx->negotiated_ctx_id, + prf_key, + prf_in, + desired_output_len, + prf_out); +} diff --git a/third_party/heimdal/lib/gssapi/spnego/external.c b/third_party/heimdal/lib/gssapi/spnego/external.c new file mode 100644 index 0000000..2a5121e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/external.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "spnego_locl.h" +#include + +/* + * RFC2478, SPNEGO: + * The security mechanism of the initial + * negotiation token is identified by the Object Identifier + * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2). + */ +static gss_mo_desc spnego_mo[] = { + { + GSS_C_MA_SASL_MECH_NAME, + GSS_MO_MA, + "SASL mech name", + rk_UNCONST("SPNEGO"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_NAME, + GSS_MO_MA, + "Mechanism name", + rk_UNCONST("SPNEGO"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_DESCRIPTION, + GSS_MO_MA, + "Mechanism description", + rk_UNCONST("Heimdal SPNEGO Mechanism"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_NEGO, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_MECH_PSEUDO, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + } +}; + +static gssapi_mech_interface_desc spnego_mech = { + GMI_VERSION, + "spnego", + {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02") }, + GM_USE_MG_CRED | GM_USE_MG_NAME, + NULL, /* gm_acquire_cred */ + NULL, /* gm_release_cred */ + _gss_spnego_init_sec_context, + _gss_spnego_accept_sec_context, + _gss_spnego_process_context_token, + _gss_spnego_delete_sec_context, + _gss_spnego_context_time, + _gss_spnego_get_mic, + _gss_spnego_verify_mic, + _gss_spnego_wrap, + _gss_spnego_unwrap, + NULL, /* gm_display_status */ + NULL, /* gm_indicate_mechs */ + NULL, /* gm_compare_name */ + NULL, /* gm_display_name */ + NULL, /* gm_import_name */ + NULL, /* gm_export_name */ + NULL, /* gm_release_name */ + NULL, /* gm_inquire_cred */ + _gss_spnego_inquire_context, + _gss_spnego_wrap_size_limit, + NULL, /* gm_add_cred */ + NULL, /* gm_inquire_cred_by_mech */ + _gss_spnego_export_sec_context, + _gss_spnego_import_sec_context, + NULL, /* gm_spnego_inquire_names_for_mech */ + NULL, /* gm_spnego_inquire_mechs_for_name */ + NULL, /* gm_spnego_canonicalize_name */ + NULL, /* gm_spnego_duplicate_name */ + _gss_spnego_inquire_sec_context_by_oid, + NULL, /* gm_inquire_cred_by_oid */ + _gss_spnego_set_sec_context_option, + NULL, /* gm_set_cred_option */ + _gss_spnego_pseudo_random, + _gss_spnego_wrap_iov, + _gss_spnego_unwrap_iov, + _gss_spnego_wrap_iov_length, + NULL, + NULL, /* gm_export_cred */ + NULL, /* gm_import_cred */ + NULL, /* gm_acquire_cred_from */ + NULL, /* gm_acquire_cred_impersonate_name */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + spnego_mo, + sizeof(spnego_mo) / sizeof(spnego_mo[0]), + NULL, /* gm_localname */ + NULL, /* gm_authorize_localname */ + NULL, /* gm_display_name_ext */ + NULL, /* gm_inquire_name */ + NULL, /* gm_get_name_attribute */ + NULL, /* gm_set_name_attribute */ + NULL, /* gm_delete_name_attribute */ + NULL, /* gm_export_name_composite */ + NULL, /* gm_duplicate_cred */ + NULL, /* gm_add_cred_from */ + NULL, /* gm_store_cred_into */ + NULL, /* gm_query_mechanism_info */ + NULL, /* gm_query_meta_data */ + NULL, /* gm_exchange_meta_data */ + NULL, /* gm_store_cred_into2 */ + NULL /* gm_compat */ +}; + +gssapi_mech_interface +__gss_spnego_initialize(void) +{ + return &spnego_mech; +} + diff --git a/third_party/heimdal/lib/gssapi/spnego/init_sec_context.c b/third_party/heimdal/lib/gssapi/spnego/init_sec_context.c new file mode 100644 index 0000000..12ec0ea --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/init_sec_context.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Portions Copyright (c) 2004 PADL Software Pty Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +#define GSISC(name) \ +static \ +OM_uint32 name(OM_uint32 *, gss_const_cred_id_t, gssspnego_ctx, \ + gss_const_name_t, gss_const_OID, \ + OM_uint32, OM_uint32, const gss_channel_bindings_t, \ + gss_const_buffer_t, gss_buffer_t, \ + OM_uint32 *, OM_uint32 *) + +GSISC(spnego_initial); +GSISC(spnego_reply); +GSISC(wait_server_mic); +GSISC(step_completed); + + + /* + * Is target_name an sane target for `mech´. + */ + +static OM_uint32 +initiator_approved(OM_uint32 *minor_status, + void *userptr, + gss_const_name_t target_name, + gss_const_cred_id_t cred, + gss_OID mech) +{ + OM_uint32 min_stat, maj_stat; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc out; + struct gssspnego_optimistic_ctx *sel = userptr; + gss_OID negotiated_mech_type = GSS_C_NO_OID; + OM_uint32 flags = 0, time_rec = 0; + auth_scheme scheme; + int negoex = 0; + + maj_stat = gss_init_sec_context(&min_stat, + cred, + &ctx, + sel->target_name, + mech, + sel->req_flags, + sel->time_req, + sel->input_chan_bindings, + GSS_C_NO_BUFFER, + &negotiated_mech_type, + &out, + &flags, + &time_rec); + if (GSS_ERROR(maj_stat)) { + gss_mg_collect_error(mech, maj_stat, min_stat); + *minor_status = min_stat; + return maj_stat; + } + + if (gssspi_query_mechanism_info(&min_stat, mech, scheme) == GSS_S_COMPLETE) + negoex = 1; + + if (sel->preferred_mech_type == GSS_C_NO_OID) { + sel->preferred_mech_type = mech; + sel->negotiated_mech_type = negotiated_mech_type; + sel->optimistic_token = out; + sel->optimistic_flags = flags; + sel->optimistic_time_rec = time_rec; + sel->gssctx = ctx; + if (maj_stat == GSS_S_COMPLETE) + sel->complete = 1; + if (negoex) + memcpy(sel->scheme, scheme, GUID_LENGTH); + } else { + gss_release_buffer(&min_stat, &out); + gss_delete_sec_context(&min_stat, &ctx, NULL); + } + + maj_stat = GSS_S_COMPLETE; + + if (negoex) { + maj_stat = _gss_negoex_add_auth_mech(minor_status, sel->spnegoctx, + mech, scheme); + } + + return maj_stat; +} + +/* + * Send a reply. Note that we only need to send a reply if we + * need to send a MIC or a mechanism token. Otherwise, we can + * return an empty buffer. + * + * The return value of this will be returned to the API, so it + * must return GSS_S_CONTINUE_NEEDED if a token was generated. + */ +static OM_uint32 +make_reply(OM_uint32 *minor_status, + gssspnego_ctx ctx, + gss_buffer_t mech_token, + gss_buffer_t output_token) +{ + NegotiationToken nt; + gss_buffer_desc mic_buf; + OM_uint32 ret, minor; + size_t size; + NegStateEnum state; + + memset(&nt, 0, sizeof(nt)); + + nt.element = choice_NegotiationToken_negTokenResp; + + nt.u.negTokenResp.negState = NULL; + nt.u.negTokenResp.supportedMech = NULL; + + output_token->length = 0; + output_token->value = NULL; + + /* figure out our status */ + + if (ctx->flags.open) { + if (ctx->flags.verified_mic == 1 || ctx->flags.require_mic == 0) + state = accept_completed; + else + state = accept_incomplete; + } else { + state = accept_incomplete; + } + + if (mech_token->length == 0) { + nt.u.negTokenResp.responseToken = NULL; + } else { + ALLOC(nt.u.negTokenResp.responseToken, 1); + if (nt.u.negTokenResp.responseToken == NULL) { + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + nt.u.negTokenResp.responseToken->length = mech_token->length; + nt.u.negTokenResp.responseToken->data = mech_token->value; + mech_token->length = 0; + mech_token->value = NULL; + } + + /* + * XXX should limit when we send the MIC ? + */ + if (ctx->flags.open && ctx->flags.sent_mic == 0) { + + ctx->flags.sent_mic = 1; + + ret = gss_get_mic(minor_status, + ctx->negotiated_ctx_id, + 0, + &ctx->NegTokenInit_mech_types, + &mic_buf); + if (ret == GSS_S_COMPLETE) { + _gss_spnego_ntlm_reset_crypto(&minor, ctx, FALSE); + + ALLOC(nt.u.negTokenResp.mechListMIC, 1); + if (nt.u.negTokenResp.mechListMIC == NULL) { + gss_release_buffer(minor_status, &mic_buf); + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + nt.u.negTokenResp.mechListMIC->length = mic_buf.length; + nt.u.negTokenResp.mechListMIC->data = mic_buf.value; + /* mic_buf free()d with nt */ + } else if (ret == GSS_S_UNAVAILABLE) { + /* lets hope that its ok to not send te mechListMIC for broken mechs */ + nt.u.negTokenResp.mechListMIC = NULL; + ctx->flags.require_mic = 0; + } else { + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + ret, *minor_status, + "SPNEGO failed to sign MIC"); + } + } else { + nt.u.negTokenResp.mechListMIC = NULL; + } + + ALLOC(nt.u.negTokenResp.negState, 1); + if (nt.u.negTokenResp.negState == NULL) { + free_NegotiationToken(&nt); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *nt.u.negTokenResp.negState = state; + + ASN1_MALLOC_ENCODE(NegotiationToken, + output_token->value, output_token->length, + &nt, &size, ret); + free_NegotiationToken(&nt); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (state != accept_completed) + return GSS_S_CONTINUE_NEEDED; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +spnego_initial(OM_uint32 * minor_status, + gss_const_cred_id_t cred, + gssspnego_ctx ctx, + gss_const_name_t target_name, + gss_const_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + NegotiationToken nt; + int ret; + OM_uint32 sub, minor; + gss_buffer_desc mech_token; + size_t size = 0; + gss_buffer_desc data; + struct gssspnego_optimistic_ctx sel; + + *minor_status = 0; + + memset(&nt, 0, sizeof(nt)); + + if (target_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + sub = gss_duplicate_name(&minor, target_name, &ctx->target_name); + if (GSS_ERROR(sub)) { + *minor_status = minor; + return sub; + } + + nt.element = choice_NegotiationToken_negTokenInit; + + ctx->flags.local = 1; + + memset(&sel, 0, sizeof(sel)); + + sel.spnegoctx = ctx; + sel.target_name = ctx->target_name; + sel.preferred_mech_type = GSS_C_NO_OID; + sel.req_flags = req_flags; + sel.time_req = time_req; + sel.input_chan_bindings = (gss_channel_bindings_t)input_chan_bindings; + + sub = _gss_spnego_indicate_mechtypelist(&minor, + ctx->target_name, + req_flags, + initiator_approved, + &sel, + 0, + cred, + &nt.u.negTokenInit.mechTypes, + &ctx->preferred_mech_type); + if (GSS_ERROR(sub)) { + *minor_status = minor; + return sub; + } + + _gss_spnego_log_mechTypes(&nt.u.negTokenInit.mechTypes); + + nt.u.negTokenInit.reqFlags = NULL; + + if (gss_oid_equal(ctx->preferred_mech_type, GSS_NEGOEX_MECHANISM)) { + struct negoex_auth_mech *mech; + + sub = _gss_negoex_init(&minor, + &sel, + ctx, + (gss_cred_id_t)cred, + req_flags, + time_req, + input_chan_bindings, + GSS_C_NO_BUFFER, + &mech_token); + if (GSS_ERROR(sub)) { + free_NegotiationToken(&nt); + return gss_mg_set_error_string(GSS_C_NO_OID, sub, minor, + "NegoEx could not generate a context token"); + } + mech = _gss_negoex_negotiated_mech(ctx); + ctx->flags.maybe_open = mech && mech->complete; + gss_release_buffer(&minor, &sel.optimistic_token); + } else { + /* optimistic token from selection context */ + mech_token = sel.optimistic_token; + ctx->mech_flags = sel.optimistic_flags; + ctx->mech_time_rec = sel.optimistic_time_rec; + ctx->negotiated_mech_type = sel.negotiated_mech_type; + ctx->negotiated_ctx_id = sel.gssctx; + ctx->flags.maybe_open = sel.complete; + } + + if (ctx->preferred_mech_type == GSS_C_NO_OID) { + free_NegotiationToken(&nt); + *minor_status = 0; + return gss_mg_set_error_string(GSS_C_NO_OID, GSS_S_NO_CONTEXT, 0, + "SPNEGO could not find a preferred mechanism"); + } + + + if (mech_token.length != 0) { + ALLOC(nt.u.negTokenInit.mechToken, 1); + if (nt.u.negTokenInit.mechToken == NULL) { + free_NegotiationToken(&nt); + gss_release_buffer(&minor, &mech_token); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + nt.u.negTokenInit.mechToken->length = mech_token.length; + nt.u.negTokenInit.mechToken->data = malloc(mech_token.length); + if (nt.u.negTokenInit.mechToken->data == NULL && mech_token.length != 0) { + free_NegotiationToken(&nt); + gss_release_buffer(&minor, &mech_token); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(nt.u.negTokenInit.mechToken->data, mech_token.value, mech_token.length); + gss_release_buffer(&minor, &mech_token); + } else + nt.u.negTokenInit.mechToken = NULL; + + nt.u.negTokenInit.mechListMIC = NULL; + + { + MechTypeList mt; + + mt.len = nt.u.negTokenInit.mechTypes.len; + mt.val = nt.u.negTokenInit.mechTypes.val; + + ASN1_MALLOC_ENCODE(MechTypeList, + ctx->NegTokenInit_mech_types.value, + ctx->NegTokenInit_mech_types.length, + &mt, &size, ret); + if (ret) { + *minor_status = ret; + free_NegotiationToken(&nt); + return GSS_S_FAILURE; + } + } + + ASN1_MALLOC_ENCODE(NegotiationToken, data.value, data.length, &nt, &size, ret); + free_NegotiationToken(&nt); + if (ret) { + return GSS_S_FAILURE; + } + if (data.length != size) + abort(); + + sub = gss_encapsulate_token(&data, + GSS_SPNEGO_MECHANISM, + output_token); + free (data.value); + + if (sub) { + return sub; + } + + if (ret_flags) + *ret_flags = ctx->mech_flags; + if (time_rec) + *time_rec = ctx->mech_time_rec; + + ctx->initiator_state = spnego_reply; + + return GSS_S_CONTINUE_NEEDED; +} + +/* + * + */ + +static OM_uint32 +spnego_reply(OM_uint32 * minor_status, + gss_const_cred_id_t cred, + gssspnego_ctx ctx, + gss_const_name_t target_name, + gss_const_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 ret, minor; + NegotiationToken resp; + gss_buffer_desc mech_output_token; + NegStateEnum negState; + + *minor_status = 0; + + output_token->length = 0; + output_token->value = NULL; + + mech_output_token.length = 0; + mech_output_token.value = NULL; + + ret = decode_NegotiationToken(input_token->value, input_token->length, + &resp, NULL); + if (ret) + return ret; + + /* The SPNEGO token must be a negTokenResp */ + if (resp.element != choice_NegotiationToken_negTokenResp) { + free_NegotiationToken(&resp); + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + /* + * When negState is absent, the actual state should be inferred from + * the state of the negotiated mechanism context. (RFC 4178 4.2.2.) + */ + if (resp.u.negTokenResp.negState != NULL) + negState = *resp.u.negTokenResp.negState; + else + negState = accept_incomplete; + + /* + * Pick up the mechanism that the acceptor selected, only pick up + * the first selection. + */ + + if (ctx->selected_mech_type == GSS_C_NO_OID && resp.u.negTokenResp.supportedMech) { + gss_OID_desc oid; + size_t len; + + ctx->flags.seen_supported_mech = 1; + + oid.length = (OM_uint32)der_length_oid(resp.u.negTokenResp.supportedMech); + oid.elements = malloc(oid.length); + if (oid.elements == NULL) { + free_NegotiationToken(&resp); + return GSS_S_BAD_MECH; + } + ret = der_put_oid(((uint8_t *)oid.elements) + oid.length - 1, + oid.length, + resp.u.negTokenResp.supportedMech, + &len); + if (ret || len != oid.length) { + free(oid.elements); + free_NegotiationToken(&resp); + return GSS_S_BAD_MECH; + } + + if (gss_oid_equal(GSS_SPNEGO_MECHANISM, &oid)) { + free(oid.elements); + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "SPNEGO acceptor picked SPNEGO??"); + } + + /* check if the acceptor took our optimistic token */ + if (gss_oid_equal(ctx->preferred_mech_type, &oid)) { + ctx->selected_mech_type = ctx->preferred_mech_type; + } else if (gss_oid_equal(ctx->preferred_mech_type, GSS_KRB5_MECHANISM) && + gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) { + /* mis-encoded asn1 type from msft servers */ + ctx->selected_mech_type = ctx->preferred_mech_type; + } else { + /* nope, lets start over */ + gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id, + GSS_C_NO_BUFFER); + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + + if (gss_oid_equal(&oid, GSS_NEGOEX_MECHANISM)) + ctx->selected_mech_type = GSS_NEGOEX_MECHANISM; + else + ctx->selected_mech_type = _gss_mg_support_mechanism(&oid); + + /* XXX check that server pick a mechanism we proposed */ + if (ctx->selected_mech_type == GSS_C_NO_OID) { + free(oid.elements); + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "SPNEGO acceptor sent unsupported supportedMech"); + } + } + + _gss_spnego_log_mech("initiator selected mechanism", ctx->selected_mech_type); + + free(oid.elements); + + } else if (ctx->selected_mech_type == NULL) { + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "SPNEGO acceptor didn't send supportedMech"); + } + + /* if a token (of non zero length) pass to underlaying mech */ + if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) || + ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { + gss_buffer_desc mech_input_token; + + if (resp.u.negTokenResp.responseToken) { + mech_input_token.length = resp.u.negTokenResp.responseToken->length; + mech_input_token.value = resp.u.negTokenResp.responseToken->data; + } else { + mech_input_token.length = 0; + mech_input_token.value = NULL; + } + + /* Fall through as if the negotiated mechanism + was requested explicitly */ + if (gss_oid_equal(ctx->selected_mech_type, GSS_NEGOEX_MECHANISM)) { + ret = _gss_negoex_init(&minor, + NULL, /* no optimistic token */ + ctx, + (gss_cred_id_t)cred, + req_flags, + time_req, + input_chan_bindings, + &mech_input_token, + &mech_output_token); + } else { + ret = gss_init_sec_context(&minor, + cred, + &ctx->negotiated_ctx_id, + ctx->target_name, + ctx->selected_mech_type, + req_flags, + time_req, + input_chan_bindings, + &mech_input_token, + &ctx->negotiated_mech_type, + &mech_output_token, + &ctx->mech_flags, + &ctx->mech_time_rec); + if (GSS_ERROR(ret)) { + gss_mg_collect_error(ctx->selected_mech_type, ret, minor); + } + } + /* + * If the acceptor rejected, we're out even if the inner context is + * now complete. Note that the rejection is not integrity-protected. + */ + if (negState == reject) + ret = GSS_S_BAD_MECH; + if (GSS_ERROR(ret)) { + free_NegotiationToken(&resp); + *minor_status = minor; + return ret; + } + if (ret == GSS_S_COMPLETE) { + ctx->flags.open = 1; + } + } else if (negState == reject) { + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EPERM), + "SPNEGO acceptor rejected initiator token"); + } else if (negState == accept_completed) { + /* + * Note that the accept_completed isn't integrity-protected, but + * ctx->maybe_open can only be true if the inner context is fully + * established. + */ + if (ctx->flags.maybe_open) + ctx->flags.open = 1; + + if (!ctx->flags.open) { + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "SPNEGO acceptor sent acceptor complete, " + "but we are not complete yet"); + } + } + + if (negState == request_mic) { + ctx->flags.peer_require_mic = 1; + } + + if (ctx->flags.open && ctx->flags.verified_mic == 0) { + + ctx->flags.require_mic = 1; /* default is to require a MIC */ + ctx->flags.safe_omit = _gss_spnego_safe_omit_mechlist_mic(ctx); + + /* + * If the peer sent mechListMIC, require it to verify ... + */ + if (resp.u.negTokenResp.mechListMIC) { + heim_octet_string *m = resp.u.negTokenResp.mechListMIC; + + /* ...unless its a windows 2000 server that sends the + * responseToken inside the mechListMIC too. We only + * accept this condition if would have been safe to omit + * anyway. */ + + if (ctx->flags.safe_omit + && resp.u.negTokenResp.responseToken + && der_heim_octet_string_cmp(m, resp.u.negTokenResp.responseToken) == 0) + { + ctx->flags.require_mic = 0; + } + } + + } else { + ctx->flags.require_mic = 0; + } + + /* + * If we are supposed to check mic and have it, force checking now. + */ + + if (ctx->flags.require_mic && resp.u.negTokenResp.mechListMIC) { + + ret = _gss_spnego_verify_mechtypes_mic(minor_status, ctx, + resp.u.negTokenResp.mechListMIC); + if (ret) { + free_NegotiationToken(&resp); + return ret; + } + } + + /* + * Now that underlaying mech is open (conncted), we can figure out + * what nexd step to go to. + */ + + if (ctx->flags.open) { + + if (negState == accept_completed && ctx->flags.safe_omit) { + ctx->initiator_state = step_completed; + ret = GSS_S_COMPLETE; + } else if (ctx->flags.require_mic != 0 && ctx->flags.verified_mic == 0) { + ctx->initiator_state = wait_server_mic; + ret = GSS_S_CONTINUE_NEEDED; + } else { + ctx->initiator_state = step_completed; + ret = GSS_S_COMPLETE; + } + } + + if (negState != accept_completed || + ctx->initiator_state != step_completed || + mech_output_token.length) + { + OM_uint32 ret2; + ret2 = make_reply(minor_status, ctx, + &mech_output_token, + output_token); + if (ret2) + ret = ret2; + } + + free_NegotiationToken(&resp); + + gss_release_buffer(&minor, &mech_output_token); + + if (ret_flags) + *ret_flags = ctx->mech_flags; + if (time_rec) + *time_rec = ctx->mech_time_rec; + + return ret; +} + +static OM_uint32 +wait_server_mic(OM_uint32 * minor_status, + gss_const_cred_id_t cred, + gssspnego_ctx ctx, + gss_const_name_t target_name, + gss_const_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 major_status; + NegotiationToken resp; + int ret; + + ret = decode_NegotiationToken(input_token->value, input_token->length, &resp, NULL); + if (ret) + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, ret, + "Failed to decode NegotiationToken"); + + if (resp.element != choice_NegotiationToken_negTokenResp + || resp.u.negTokenResp.negState == NULL + || *resp.u.negTokenResp.negState != accept_completed) + { + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "NegToken not accept_completed"); + } + + if (resp.u.negTokenResp.mechListMIC) { + major_status = _gss_spnego_verify_mechtypes_mic(minor_status, ctx, + resp.u.negTokenResp.mechListMIC); + } else if (ctx->flags.safe_omit == 0) { + free_NegotiationToken(&resp); + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_MECH, (*minor_status = EINVAL), + "Waiting for MIC, but its missing in server request"); + } else { + major_status = GSS_S_COMPLETE; + } + + free_NegotiationToken(&resp); + if (major_status != GSS_S_COMPLETE) + return major_status; + + ctx->flags.verified_mic = 1; + ctx->initiator_state = step_completed; + + if (ret_flags) + *ret_flags = ctx->mech_flags; + if (time_rec) + *time_rec = ctx->mech_time_rec; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +step_completed(OM_uint32 * minor_status, + gss_const_cred_id_t cred, + gssspnego_ctx ctx, + gss_const_name_t name, + gss_const_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + GSS_S_BAD_STATUS, (*minor_status = EINVAL), + "SPNEGO called got ISC call one too many"); +} + +OM_uint32 GSSAPI_CALLCONV +_gss_spnego_init_sec_context(OM_uint32 * minor_status, + gss_const_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + gssspnego_ctx ctx; + OM_uint32 ret; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gss_spnego_alloc_sec_context(minor_status, context_handle); + if (GSS_ERROR(ret)) + return ret; + + ctx = (gssspnego_ctx)*context_handle; + + ctx->initiator_state = spnego_initial; + } else { + ctx = (gssspnego_ctx)*context_handle; + } + + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + do { + ret = ctx->initiator_state(minor_status, initiator_cred_handle, ctx, target_name, + mech_type, req_flags, time_req, input_chan_bindings, input_token, + output_token, ret_flags, time_rec); + + } while (ret == GSS_S_COMPLETE && + ctx->initiator_state != step_completed && + output_token->length == 0); + + /* destroy context in case of error */ + if (GSS_ERROR(ret)) { + OM_uint32 junk; + _gss_spnego_internal_delete_sec_context(&junk, context_handle, GSS_C_NO_BUFFER); + } else { + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (actual_mech_type) + *actual_mech_type = ctx->negotiated_mech_type; + } + + return ret; +} + diff --git a/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c b/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c new file mode 100644 index 0000000..3f8aa5c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/negoex_ctx.c @@ -0,0 +1,1041 @@ +/* + * Copyright (C) 2011-2021 PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +/* + * The initial context token emitted by the initiator is a INITIATOR_NEGO + * message followed by zero or more INITIATOR_META_DATA tokens, and zero + * or one AP_REQUEST tokens. + * + * Upon receiving this, the acceptor computes the list of mutually supported + * authentication mechanisms and performs the metadata exchange. The output + * token is ACCEPTOR_NEGO followed by zero or more ACCEPTOR_META_DATA tokens, + * and zero or one CHALLENGE tokens. + * + * Once the metadata exchange is complete and a mechanism is selected, the + * selected mechanism's context token exchange continues with AP_REQUEST and + * CHALLENGE messages. + * + * Once the context token exchange is complete, VERIFY messages are sent to + * authenticate the entire exchange. + */ + +static OM_uint32 +buffer_set_to_crypto(OM_uint32 *minor, + krb5_context context, + gss_buffer_set_t buffers, + krb5_crypto *crypto) +{ + krb5_error_code ret; + krb5_keyblock keyblock; + OM_uint32 tmp; + + /* + * Returned keys must be in two buffers, with the key contents in + * the first and the enctype as a 32-bit little-endian integer in + * the second. + */ + if (buffers->count != 2 || + buffers->elements[1].length != sizeof(tmp)) { + *minor = (OM_uint32)NEGOEX_NO_VERIFY_KEY; + return GSS_S_FAILURE; + } + + if (*crypto != NULL) { + krb5_crypto_destroy(context, *crypto); + *crypto = NULL; + } + + keyblock.keyvalue.data = buffers->elements[0].value; + keyblock.keyvalue.length = buffers->elements[0].length; + _gss_mg_decode_le_uint32(buffers->elements[1].value, &tmp); + keyblock.keytype = tmp; + + ret = krb5_crypto_init(context, &keyblock, 0, crypto); + if (ret) { + *minor = ret; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; +} + +#define NEGOEX_SIGN_KEY 1 +#define NEGOEX_VERIFY_KEY 2 +#define NEGOEX_BOTH_KEYS (NEGOEX_SIGN_KEY|NEGOEX_VERIFY_KEY) + +static OM_uint32 +get_session_keys(OM_uint32 *minor, + krb5_context context, + OM_uint32 flags, + struct negoex_auth_mech *mech) +{ + OM_uint32 major, tmpMinor; + gss_buffer_set_t buffers = GSS_C_NO_BUFFER_SET; + + if (flags & NEGOEX_SIGN_KEY) { + major = gss_inquire_sec_context_by_oid(&tmpMinor, mech->mech_context, + GSS_C_INQ_NEGOEX_KEY, &buffers); + if (major == GSS_S_COMPLETE) { + major = buffer_set_to_crypto(minor, context, + buffers, &mech->crypto); + _gss_secure_release_buffer_set(&tmpMinor, &buffers); + if (major != GSS_S_COMPLETE) + return major; + } + } + + if (flags & NEGOEX_VERIFY_KEY) { + major = gss_inquire_sec_context_by_oid(&tmpMinor, mech->mech_context, + GSS_C_INQ_NEGOEX_VERIFY_KEY, + &buffers); + if (major == GSS_S_COMPLETE) { + major = buffer_set_to_crypto(minor, context, + buffers, &mech->verify_crypto); + _gss_secure_release_buffer_set(&tmpMinor, &buffers); + if (major != GSS_S_COMPLETE) + return major; + } + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +emit_initiator_nego(OM_uint32 *minor, gssspnego_ctx ctx) +{ + uint8_t random[32]; + struct negoex_auth_mech *mech; + size_t i = 0; + + krb5_generate_random_block(random, sizeof(random)); + + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) + _gss_negoex_log_auth_scheme(ctx->flags.local, ++i, mech->scheme); + + return _gss_negoex_add_nego_message(minor, ctx, INITIATOR_NEGO, random); +} + +static OM_uint32 +process_initiator_nego(OM_uint32 *minor, + gssspnego_ctx ctx, + struct negoex_message *messages, + size_t nmessages) +{ + struct nego_message *msg; + size_t i; + + heim_assert(!ctx->flags.local && ctx->negoex_step == 1, + "NegoEx INITIATOR_NEGO token received after first leg"); + + msg = _gss_negoex_locate_nego_message(messages, nmessages, INITIATOR_NEGO); + if (msg == NULL) { + *minor = (OM_uint32)NEGOEX_MISSING_NEGO_MESSAGE; + return GSS_S_DEFECTIVE_TOKEN; + } + + for (i = 0; i < msg->nschemes; i++) + _gss_negoex_log_auth_scheme(ctx->flags.local, i + 1, &msg->schemes[i * GUID_LENGTH]); + + _gss_negoex_restrict_auth_schemes(ctx, msg->schemes, msg->nschemes); + + return GSS_S_COMPLETE; +} + +static OM_uint32 +emit_acceptor_nego(OM_uint32 *minor, gssspnego_ctx ctx) +{ + uint8_t random[32]; + + krb5_generate_random_block(random, 32); + + return _gss_negoex_add_nego_message(minor, ctx, ACCEPTOR_NEGO, random); +} + +static OM_uint32 +process_acceptor_nego(OM_uint32 *minor, + gssspnego_ctx ctx, + struct negoex_message *messages, + size_t nmessages) +{ + struct nego_message *msg; + + msg = _gss_negoex_locate_nego_message(messages, nmessages, ACCEPTOR_NEGO); + if (msg == NULL) { + *minor = (OM_uint32)NEGOEX_MISSING_NEGO_MESSAGE; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* + * Reorder and prune our mech list to match the acceptor's list (or a + * subset of it). + */ + _gss_negoex_common_auth_schemes(ctx, msg->schemes, msg->nschemes); + + return GSS_S_COMPLETE; +} + +static void +query_meta_data(gssspnego_ctx ctx, + struct gssspnego_optimistic_ctx *opt, + gss_cred_id_t cred, + OM_uint32 req_flags) +{ + OM_uint32 major, minor; + struct negoex_auth_mech *p, *next; + + /* + * Note that if we received an optimistic context token from SPNEGO, + * then we will call QMD after ISC, rather than before. Mechanisms + * must be prepared to handle this and must not assume the context + * will be NULL on entry. + */ + HEIM_TAILQ_FOREACH_SAFE(p, &ctx->negoex_mechs, links, next) { + if (opt != NULL && memcmp(opt->scheme, p->scheme, GUID_LENGTH) == 0) + p->mech_context = opt->gssctx;; + + major = gssspi_query_meta_data(&minor, p->oid, cred, &p->mech_context, + ctx->target_name, req_flags, &p->metadata); + /* GSS_Query_meta_data failure removes mechanism from list. */ + if (major != GSS_S_COMPLETE) + _gss_negoex_delete_auth_mech(ctx, p); + } +} + +static void +exchange_meta_data(gssspnego_ctx ctx, + gss_cred_id_t cred, + OM_uint32 req_flags, + struct negoex_message *messages, + size_t nmessages) +{ + OM_uint32 major, minor; + struct negoex_auth_mech *mech; + enum message_type type; + struct exchange_message *msg; + uint32_t i; + + type = ctx->flags.local ? ACCEPTOR_META_DATA : INITIATOR_META_DATA; + + for (i = 0; i < nmessages; i++) { + if (messages[i].type != type) + continue; + msg = &messages[i].u.e; + + mech = _gss_negoex_locate_auth_scheme(ctx, msg->scheme); + if (mech == NULL) + continue; + + major = gssspi_exchange_meta_data(&minor, mech->oid, cred, + &mech->mech_context, + ctx->target_name, + req_flags, &msg->token); + /* GSS_Exchange_meta_data failure removes mechanism from list. */ + if (major != GSS_S_COMPLETE) + _gss_negoex_delete_auth_mech(ctx, mech); + } +} + +static void +release_mech_crypto(struct negoex_auth_mech *mech) +{ + krb5_context context = NULL; + + if (mech->crypto || mech->verify_crypto) + context = _gss_mg_krb5_context(); + + if (mech->crypto) { + krb5_crypto_destroy(context, mech->crypto); + mech->crypto = NULL; + } + + if (mech->verify_crypto) { + krb5_crypto_destroy(context, mech->verify_crypto); + mech->verify_crypto = NULL; + } + + mech->sent_checksum = FALSE; +} + +/* + * In the initiator, if we are processing the acceptor's first reply, discard + * the optimistic context if the acceptor ignored the optimistic token. If the + * acceptor continued the optimistic mech, discard all other mechs. + */ +static void +check_optimistic_result(gssspnego_ctx ctx, + struct negoex_message *messages, + size_t nmessages) +{ + struct negoex_auth_mech *mech; + OM_uint32 tmpMinor; + + heim_assert(ctx->flags.local && ctx->negoex_step == 2, + "NegoEx optimistic result should only be checked in second leg"); + + /* Do nothing if we didn't make an optimistic context. */ + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + if (mech == NULL || mech->mech_context == GSS_C_NO_CONTEXT) + return; + + /* + * If the acceptor used the optimistic token, it will send an acceptor + * token or a checksum (or both) in its first reply. + */ + if (_gss_negoex_locate_exchange_message(messages, nmessages, + CHALLENGE) != NULL || + _gss_negoex_locate_verify_message(messages, nmessages) != NULL) { + /* + * The acceptor continued the optimistic mech, and metadata exchange + * didn't remove it. Commit to this mechanism. + */ + _gss_negoex_select_auth_mech(ctx, mech); + } else { + /* + * The acceptor ignored the optimistic token. Restart the mech. + */ + gss_delete_sec_context(&tmpMinor, &mech->mech_context, GSS_C_NO_BUFFER); + release_mech_crypto(mech); + mech->complete = FALSE; + } +} + +/* Perform an initiator step of the underlying mechanism exchange. */ +static OM_uint32 +mech_init(OM_uint32 *minor, + struct gssspnego_optimistic_ctx *opt, + gssspnego_ctx ctx, + gss_cred_id_t cred, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + struct negoex_message *messages, + size_t nmessages, + gss_buffer_t output_token, + int *mech_error) +{ + OM_uint32 major, first_major = GSS_S_COMPLETE, first_minor = 0; + struct negoex_auth_mech *mech = NULL; + gss_buffer_t input_token = GSS_C_NO_BUFFER; + struct exchange_message *msg; + int first_mech; + krb5_context context = _gss_mg_krb5_context(); + + output_token->value = NULL; + output_token->length = 0; + + *mech_error = FALSE; + + /* Allow disabling of optimistic token for testing. */ + if (ctx->negoex_step == 1 && + secure_getenv("NEGOEX_NO_OPTIMISTIC_TOKEN") != NULL) + return GSS_S_COMPLETE; + + if (HEIM_TAILQ_EMPTY(&ctx->negoex_mechs)) { + *minor = (OM_uint32)NEGOEX_NO_AVAILABLE_MECHS; + return GSS_S_FAILURE; + } + + /* + * Get the input token. The challenge could be for the optimistic mech, + * which we might have discarded in metadata exchange, so ignore the + * challenge if it doesn't match the first auth mech. + */ + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + msg = _gss_negoex_locate_exchange_message(messages, nmessages, CHALLENGE); + if (msg != NULL && GUID_EQ(msg->scheme, mech->scheme)) + input_token = &msg->token; + + if (mech->complete) + return GSS_S_COMPLETE; + + first_mech = TRUE; + major = GSS_S_BAD_MECH; + + while (!HEIM_TAILQ_EMPTY(&ctx->negoex_mechs)) { + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + + /* + * If SPNEGO generated an optimistic token when probing available + * mechanisms, we can reuse it here. This avoids a potentially + * expensive and redundant call to GSS_Init_sec_context(); + */ + if (opt != NULL && memcmp(opt->scheme, mech->scheme, GUID_LENGTH) == 0) { + heim_assert(ctx->negoex_step == 1, + "SPNEGO optimistic token only valid for NegoEx first leg"); + + major = _gss_copy_buffer(minor, &opt->optimistic_token, output_token); + if (GSS_ERROR(major)) + return major; + + ctx->negotiated_mech_type = opt->negotiated_mech_type; + ctx->mech_flags = opt->optimistic_flags; + ctx->mech_time_rec = opt->optimistic_time_rec; + + mech->mech_context = opt->gssctx; + opt->gssctx = NULL; /* steal it */ + + mech->complete = opt->complete; + major = GSS_S_COMPLETE; + } else { + major = gss_init_sec_context(minor, cred, &mech->mech_context, + ctx->target_name, mech->oid, + req_flags, time_req, + input_chan_bindings, input_token, + &ctx->negotiated_mech_type, output_token, + &ctx->mech_flags, &ctx->mech_time_rec); + if (major == GSS_S_COMPLETE) + mech->complete = 1; + else if (GSS_ERROR(major)) { + gss_mg_collect_error(mech->oid, major, *minor); + *mech_error = TRUE; + } + } + if (!GSS_ERROR(major)) + return get_session_keys(minor, context, NEGOEX_BOTH_KEYS, mech); + + /* Remember the error we got from the first mech. */ + if (first_mech) { + first_major = major; + first_minor = *minor; + } + + /* If we still have multiple mechs to try, move on to the next one. */ + _gss_negoex_delete_auth_mech(ctx, mech); + first_mech = FALSE; + input_token = GSS_C_NO_BUFFER; + } + + if (HEIM_TAILQ_EMPTY(&ctx->negoex_mechs)) { + major = first_major; + *minor = first_minor; + } + + return major; +} + +/* Perform an acceptor step of the underlying mechanism exchange. */ +static OM_uint32 +mech_accept(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_cred_id_t cred, + const gss_channel_bindings_t input_chan_bindings, + struct negoex_message *messages, + size_t nmessages, + gss_buffer_t output_token, + gss_cred_id_t *deleg_cred, + int *mech_error) +{ + OM_uint32 major, tmpMinor; + struct negoex_auth_mech *mech; + struct exchange_message *msg; + krb5_context context = _gss_mg_krb5_context(); + + heim_assert(!ctx->flags.local && !HEIM_TAILQ_EMPTY(&ctx->negoex_mechs), + "Acceptor NegoEx function called in wrong sequence"); + + *mech_error = FALSE; + + msg = _gss_negoex_locate_exchange_message(messages, nmessages, AP_REQUEST); + if (msg == NULL) { + /* + * No input token is okay on the first request or if the mech is + * complete. + */ + if (ctx->negoex_step == 1 || + HEIM_TAILQ_FIRST(&ctx->negoex_mechs)->complete) + return GSS_S_COMPLETE; + *minor = (OM_uint32)NEGOEX_MISSING_AP_REQUEST_MESSAGE; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->negoex_step == 1) { + /* + * Ignore the optimistic token if it isn't for our most preferred + * mech. + */ + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + if (!GUID_EQ(msg->scheme, mech->scheme)) { + _gss_mg_log(10, "negoex ignored optimistic token as not for preferred mech"); + return GSS_S_COMPLETE; + } + } else { + /* The initiator has selected a mech; discard other entries. */ + mech = _gss_negoex_locate_auth_scheme(ctx, msg->scheme); + if (mech == NULL) { + *minor = (OM_uint32)NEGOEX_NO_AVAILABLE_MECHS; + return GSS_S_FAILURE; + } + _gss_negoex_select_auth_mech(ctx, mech); + } + + if (mech->complete) + return GSS_S_COMPLETE; + + if (ctx->mech_src_name != GSS_C_NO_NAME) + gss_release_name(&tmpMinor, &ctx->mech_src_name); + if (deleg_cred && *deleg_cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&tmpMinor, deleg_cred); + + major = gss_accept_sec_context(minor, &mech->mech_context, cred, + &msg->token, input_chan_bindings, + &ctx->mech_src_name, &ctx->negotiated_mech_type, + output_token, &ctx->mech_flags, + &ctx->mech_time_rec, deleg_cred); + if (major == GSS_S_COMPLETE) + mech->complete = 1; + + if (!GSS_ERROR(major)) { + if (major == GSS_S_COMPLETE && + !gss_oid_equal(ctx->negotiated_mech_type, mech->oid)) + _gss_mg_log(1, "negoex client didn't send the mech they said they would"); + + major = get_session_keys(minor, context, NEGOEX_BOTH_KEYS, mech); + } else if (ctx->negoex_step == 1) { + gss_mg_collect_error(ctx->negotiated_mech_type, major, *minor); + *mech_error = TRUE; + + /* This was an optimistic token; pretend this never happened. */ + major = GSS_S_COMPLETE; + *minor = 0; + gss_release_buffer(&tmpMinor, output_token); + gss_delete_sec_context(&tmpMinor, &mech->mech_context, GSS_C_NO_BUFFER); + } + + return major; +} + +static krb5_keyusage +verify_keyusage(gssspnego_ctx ctx, int make_checksum) +{ + /* Of course, these are the wrong way around in the spec. */ + return (ctx->flags.local ^ !make_checksum) ? + NEGOEX_KEYUSAGE_ACCEPTOR_CHECKSUM : NEGOEX_KEYUSAGE_INITIATOR_CHECKSUM; +} + +static OM_uint32 +verify_key_flags(gssspnego_ctx ctx, int make_checksum) +{ + return (ctx->flags.local ^ make_checksum) ? + NEGOEX_SIGN_KEY : NEGOEX_VERIFY_KEY; +} + +static OM_uint32 +verify_checksum(OM_uint32 *minor, + gssspnego_ctx ctx, + struct negoex_message *messages, + size_t nmessages, + gss_const_buffer_t input_token, + int *send_alert_out) +{ + krb5_error_code ret; + struct negoex_auth_mech *mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + struct verify_message *msg; + krb5_context context = _gss_mg_krb5_context(); + krb5_crypto_iov iov[3]; + krb5_keyusage usage = verify_keyusage(ctx, FALSE); + + *send_alert_out = FALSE; + heim_assert(mech != NULL, "Invalid null mech when verifying NegoEx checksum"); + + /* + * The other party may not be ready to send a verify token yet, or (in the + * first initiator step) may send one for a mechanism we don't support. + */ + msg = _gss_negoex_locate_verify_message(messages, nmessages); + if (msg == NULL || !GUID_EQ(msg->scheme, mech->scheme)) + return GSS_S_COMPLETE; + + /* + * Last chance attempt to obtain session key for imported exported partial + * contexts (which do not carry the session key at the NegoEx layer). + */ + if (mech->verify_crypto == NULL) + get_session_keys(minor, context, verify_key_flags(ctx, FALSE), mech); + + /* + * A recoverable error may cause us to be unable to verify a token from the + * other party. In this case we should send an alert. + */ + if (mech->verify_crypto == NULL) { + *send_alert_out = TRUE; + return GSS_S_COMPLETE; + } + + if (!krb5_checksum_is_keyed(context, msg->cksum_type)) { + *minor = (OM_uint32)NEGOEX_INVALID_CHECKSUM; + return GSS_S_BAD_SIG; + } + + /* + * Verify the checksum over the existing transcript and the portion of the + * input token leading up to the verify message. + */ + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = krb5_storage_to_data(ctx->negoex_transcript, &iov[0].data); + if (ret) { + *minor = ret; + return GSS_S_FAILURE; + } + + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data.data = input_token->value; + iov[1].data.length = msg->offset_in_token; + + iov[2].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + iov[2].data.data = (uint8_t *)msg->cksum; + iov[2].data.length = msg->cksum_len; + + ret = krb5_verify_checksum_iov(context, mech->verify_crypto, usage, + iov, sizeof(iov) / sizeof(iov[0]), NULL); + if (ret == 0) + mech->verified_checksum = TRUE; + else + *minor = ret; + + krb5_data_free(&iov[0].data); + + return (ret == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +make_checksum(OM_uint32 *minor, gssspnego_ctx ctx) +{ + krb5_error_code ret; + krb5_context context = _gss_mg_krb5_context(); + krb5_data d; + krb5_keyusage usage = verify_keyusage(ctx, TRUE); + krb5_checksum cksum; + struct negoex_auth_mech *mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + OM_uint32 major; + + heim_assert(mech != NULL, "Invalid null mech when making NegoEx checksum"); + + if (mech->crypto == NULL) { + if (mech->complete) { + /* + * Last chance attempt to obtain session key for imported exported partial + * contexts (which do not carry the session key at the NegoEx layer). + */ + get_session_keys(minor, context, verify_key_flags(ctx, TRUE), mech); + if (mech->crypto == NULL) { + *minor = (OM_uint32)NEGOEX_NO_VERIFY_KEY; + return GSS_S_UNAVAILABLE; + } + } else { + return GSS_S_COMPLETE; + } + } + + ret = krb5_storage_to_data(ctx->negoex_transcript, &d); + if (ret) { + *minor = ret; + return GSS_S_FAILURE; + } + + ret = krb5_create_checksum(context, mech->crypto, + usage, 0, d.data, d.length, &cksum); + krb5_data_free(&d); + if (ret) { + *minor = ret; + return GSS_S_FAILURE; + } + + major = _gss_negoex_add_verify_message(minor, ctx, mech->scheme, + cksum.cksumtype, + cksum.checksum.data, + cksum.checksum.length); + free_Checksum(&cksum); + + if (major == GSS_S_COMPLETE) + mech->sent_checksum = TRUE; + + return major; +} + +/* + * If the other side sent a VERIFY_NO_KEY pulse alert, clear the checksum state + * on the mechanism so that we send another VERIFY message. + */ +static void +process_alerts(gssspnego_ctx ctx, + struct negoex_message *messages, + uint32_t nmessages) +{ + struct alert_message *msg; + struct negoex_auth_mech *mech; + + msg = _gss_negoex_locate_alert_message(messages, nmessages); + if (msg != NULL && msg->verify_no_key) { + mech = _gss_negoex_locate_auth_scheme(ctx, msg->scheme); + if (mech != NULL) + release_mech_crypto(mech); + } +} + +static OM_uint32 +make_output_token(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_buffer_t mech_output_token, + int send_alert, + gss_buffer_t output_token) +{ + OM_uint32 major, tmpMinor; + struct negoex_auth_mech *mech; + enum message_type type; + off_t old_transcript_len; + + output_token->length = 0; + output_token->value = NULL; + + old_transcript_len = krb5_storage_seek(ctx->negoex_transcript, 0, SEEK_CUR); + + /* + * If the mech is complete and we previously sent a checksum, we just + * processed the last leg and don't need to send another token. + */ + if (mech_output_token->length == 0 && + HEIM_TAILQ_FIRST(&ctx->negoex_mechs)->sent_checksum) + return GSS_S_COMPLETE; + + if (ctx->negoex_step == 1) { + if (ctx->flags.local) + major = emit_initiator_nego(minor, ctx); + else + major = emit_acceptor_nego(minor, ctx); + if (major != GSS_S_COMPLETE) + return major; + + type = ctx->flags.local ? INITIATOR_META_DATA : ACCEPTOR_META_DATA; + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) { + if (mech->metadata.length > 0) { + major = _gss_negoex_add_exchange_message(minor, ctx, + type, mech->scheme, + &mech->metadata); + if (major != GSS_S_COMPLETE) + return major; + } + } + } + + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + + if (mech_output_token->length > 0) { + type = ctx->flags.local ? AP_REQUEST : CHALLENGE; + major = _gss_negoex_add_exchange_message(minor, ctx, + type, mech->scheme, + mech_output_token); + if (major != GSS_S_COMPLETE) + return major; + } + + if (send_alert) { + major = _gss_negoex_add_verify_no_key_alert(minor, ctx, mech->scheme); + if (major != GSS_S_COMPLETE) + return major; + } + + /* Try to add a VERIFY message if we haven't already done so. */ + if (!mech->sent_checksum) { + major = make_checksum(minor, ctx); + if (major != GSS_S_COMPLETE) + return major; + } + + heim_assert(ctx->negoex_transcript != NULL, "NegoEx context uninitialized"); + + output_token->length = + krb5_storage_seek(ctx->negoex_transcript, 0, SEEK_CUR) - old_transcript_len; + output_token->value = malloc(output_token->length); + if (output_token->value == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_seek(ctx->negoex_transcript, old_transcript_len, SEEK_SET); + + if (krb5_storage_read(ctx->negoex_transcript, + output_token->value, + output_token->length) != output_token->length) { + *minor = ERANGE; + gss_release_buffer(&tmpMinor, output_token); + return GSS_S_FAILURE; + } + + krb5_storage_seek(ctx->negoex_transcript, 0, SEEK_END); + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gss_negoex_init(OM_uint32 *minor, + struct gssspnego_optimistic_ctx *opt, + gssspnego_ctx ctx, + gss_cred_id_t cred, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER; + struct negoex_message *messages = NULL; + struct negoex_auth_mech *mech; + size_t nmessages = 0; + int send_alert = FALSE, mech_error = FALSE; + + output_token->length = 0; + output_token->value = NULL; + + if (ctx->negoex_step == 0 && input_token != GSS_C_NO_BUFFER && + input_token->length != 0) + return GSS_S_DEFECTIVE_TOKEN; + + major = _gss_negoex_begin(minor, ctx); + if (major != GSS_S_COMPLETE) + goto cleanup; + + ctx->negoex_step++; + + if (input_token != GSS_C_NO_BUFFER && input_token->length > 0) { + major = _gss_negoex_parse_token(minor, ctx, input_token, + &messages, &nmessages); + if (major != GSS_S_COMPLETE) + goto cleanup; + } + + process_alerts(ctx, messages, nmessages); + + if (ctx->negoex_step == 1) { + /* Choose a random conversation ID. */ + krb5_generate_random_block(ctx->negoex_conv_id, GUID_LENGTH); + + /* Query each mech for its metadata (this may prune the mech list). */ + query_meta_data(ctx, opt, cred, req_flags); + } else if (ctx->negoex_step == 2) { + /* See if the mech processed the optimistic token. */ + check_optimistic_result(ctx, messages, nmessages); + + /* Pass the acceptor metadata to each mech to prune the list. */ + exchange_meta_data(ctx, cred, req_flags, messages, nmessages); + + /* Process the ACCEPTOR_NEGO message. */ + major = process_acceptor_nego(minor, ctx, messages, nmessages); + if (major != GSS_S_COMPLETE) + goto cleanup; + } + + /* + * Process the input token and/or produce an output token. This may prune + * the mech list, but on success there will be at least one mech entry. + */ + major = mech_init(minor, opt, ctx, cred, req_flags, time_req, + input_chan_bindings, messages, nmessages, + &mech_output_token, &mech_error); + if (major != GSS_S_COMPLETE) + goto cleanup; + heim_assert(!HEIM_TAILQ_EMPTY(&ctx->negoex_mechs), + "Invalid empty NegoEx mechanism list"); + + /* + * At this point in step 2 we have performed the metadata exchange and + * chosen a mech we can use, so discard any fallback mech entries. + */ + if (ctx->negoex_step == 2) + _gss_negoex_select_auth_mech(ctx, HEIM_TAILQ_FIRST(&ctx->negoex_mechs)); + + major = verify_checksum(minor, ctx, messages, nmessages, input_token, + &send_alert); + if (major != GSS_S_COMPLETE) + goto cleanup; + + if (input_token != GSS_C_NO_BUFFER) { + if (krb5_storage_write(ctx->negoex_transcript, + input_token->value, + input_token->length) != input_token->length) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + } + + major = make_output_token(minor, ctx, &mech_output_token, send_alert, + output_token); + if (major != GSS_S_COMPLETE) + goto cleanup; + + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + major = (mech->complete && mech->verified_checksum) ? GSS_S_COMPLETE : + GSS_S_CONTINUE_NEEDED; + +cleanup: + free(messages); + gss_release_buffer(&tmpMinor, &mech_output_token); + _gss_negoex_end(ctx); + + if (GSS_ERROR(major)) { + if (!mech_error) { + krb5_context context = _gss_mg_krb5_context(); + const char *emsg = krb5_get_error_message(context, *minor); + + gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + major, *minor, + "NegoEx failed to initialize security context: %s", + emsg); + krb5_free_error_message(context, emsg); + } + + _gss_negoex_release_context(ctx); + } + + return major; +} + +OM_uint32 +_gss_negoex_accept(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_cred_id_t cred, + gss_const_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_buffer_t output_token, + gss_cred_id_t *deleg_cred) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER; + struct negoex_message *messages = NULL; + struct negoex_auth_mech *mech; + size_t nmessages; + int send_alert = FALSE, mech_error = FALSE; + + output_token->length = 0; + output_token->value = NULL; + if (deleg_cred) + *deleg_cred = GSS_C_NO_CREDENTIAL; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + major = GSS_S_DEFECTIVE_TOKEN; + goto cleanup; + } + + major = _gss_negoex_begin(minor, ctx); + if (major != GSS_S_COMPLETE) + goto cleanup; + + ctx->negoex_step++; + + major = _gss_negoex_parse_token(minor, ctx, input_token, + &messages, &nmessages); + if (major != GSS_S_COMPLETE) + goto cleanup; + + process_alerts(ctx, messages, nmessages); + + if (ctx->negoex_step == 1) { + /* + * Read the INITIATOR_NEGO message to prune the candidate mech list. + */ + major = process_initiator_nego(minor, ctx, messages, nmessages); + if (major != GSS_S_COMPLETE) + goto cleanup; + + /* + * Pass the initiator metadata to each mech to prune the list, and + * query each mech for its acceptor metadata (which may also prune the + * list). + */ + exchange_meta_data(ctx, cred, 0, messages, nmessages); + query_meta_data(ctx, NULL, cred, 0); + + if (HEIM_TAILQ_EMPTY(&ctx->negoex_mechs)) { + *minor = (OM_uint32)NEGOEX_NO_AVAILABLE_MECHS; + major = GSS_S_FAILURE; + goto cleanup; + } + } + + /* + * Process the input token and possibly produce an output token. This may + * prune the list to a single mech. Continue on error if an output token + * is generated, so that we send the token to the initiator. + */ + major = mech_accept(minor, ctx, cred, input_chan_bindings, + messages, nmessages, &mech_output_token, + deleg_cred, &mech_error); + if (major != GSS_S_COMPLETE && mech_output_token.length == 0) + goto cleanup; + + if (major == GSS_S_COMPLETE) { + major = verify_checksum(minor, ctx, messages, nmessages, input_token, + &send_alert); + if (major != GSS_S_COMPLETE) + goto cleanup; + } + + if (krb5_storage_write(ctx->negoex_transcript, + input_token->value, + input_token->length) != input_token->length) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + major = make_output_token(minor, ctx, &mech_output_token, send_alert, + output_token); + if (major != GSS_S_COMPLETE) + goto cleanup; + + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + major = (mech->complete && mech->verified_checksum) ? GSS_S_COMPLETE : + GSS_S_CONTINUE_NEEDED; + +cleanup: + free(messages); + gss_release_buffer(&tmpMinor, &mech_output_token); + _gss_negoex_end(ctx); + + if (GSS_ERROR(major)) { + if (!mech_error) { + krb5_context context = _gss_mg_krb5_context(); + const char *emsg = krb5_get_error_message(context, *minor); + + gss_mg_set_error_string(GSS_SPNEGO_MECHANISM, + major, *minor, + "NegoEx failed to accept security context: %s", + emsg); + krb5_free_error_message(context, emsg); + } + + _gss_negoex_release_context(ctx); + } + + return major; +} diff --git a/third_party/heimdal/lib/gssapi/spnego/negoex_err.et b/third_party/heimdal/lib/gssapi/spnego/negoex_err.et new file mode 100644 index 0000000..99a8a2e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/negoex_err.et @@ -0,0 +1,25 @@ +# +# NegoEx error messages +# + +id "$Id$" + +error_table ngex + +prefix NEGOEX + +error_code INVALID_MESSAGE_SIGNATURE, "Invalid NegoEx signature" +error_code INVALID_MESSAGE_TYPE, "Invalid NegoEx message type" +error_code INVALID_MESSAGE_SIZE, "Invalid NegoEx message size" +error_code INVALID_CONVERSATION_ID, "Invalid NegoEx conversation ID" +error_code AUTH_SCHEME_NOT_FOUND, "NegoEx authentication scheme not found" +error_code MISSING_NEGO_MESSAGE, "Missing NegoEx negotiate message" +error_code MISSING_AP_REQUEST_MESSAGE, "Missing NegoEx authentication protocol request message" +error_code NO_AVAILABLE_MECHS, "No mutually supported NegoEx authentication schemes" +error_code NO_VERIFY_KEY, "No NegoEx verify key" +error_code UNKNOWN_CHECKSUM_SCHEME, "Unknown NegoEx checksum scheme" +error_code INVALID_CHECKSUM, "Invalid NegoEx checksum" +error_code UNSUPPORTED_CRITICAL_EXTENSION, "Unsupported critical NegoEx extension" +error_code UNSUPPORTED_VERSION, "Unsupported NegoEx version" +error_code MESSAGE_OUT_OF_SEQUENCE, "NegoEx message out of sequence" + diff --git a/third_party/heimdal/lib/gssapi/spnego/negoex_locl.h b/third_party/heimdal/lib/gssapi/spnego/negoex_locl.h new file mode 100644 index 0000000..3e0d29a --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/negoex_locl.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2011-2019 PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NEGOEX_LOCL_H +#define NEGOEX_LOCL_H + +#include + +struct gssspnego_ctx_desc; + +#define MESSAGE_SIGNATURE 0x535458454F47454EULL + +#define EXTENSION_LENGTH 12 + +#define EXTENSION_FLAG_CRITICAL 0x80000000 + +#define CHECKSUM_SCHEME_RFC3961 1 + +#define NEGOEX_KEYUSAGE_INITIATOR_CHECKSUM 23 +#define NEGOEX_KEYUSAGE_ACCEPTOR_CHECKSUM 25 + +#define CHECKSUM_HEADER_LENGTH 20 + +#define GUID_LENGTH 16 + +typedef uint8_t auth_scheme[GUID_LENGTH]; +typedef uint8_t conversation_id[GUID_LENGTH]; +#define GUID_EQ(a, b) (memcmp(a, b, GUID_LENGTH) == 0) + +#define NEGO_MESSAGE_HEADER_LENGTH 96 +#define EXCHANGE_MESSAGE_HEADER_LENGTH 64 +#define VERIFY_MESSAGE_HEADER_LENGTH 80 +#define ALERT_MESSAGE_HEADER_LENGTH 72 +#define ALERT_LENGTH 12 +#define ALERT_PULSE_LENGTH 8 + +#define ALERT_TYPE_PULSE 1 +#define ALERT_VERIFY_NO_KEY 1 + +enum message_type { + INITIATOR_NEGO = 0, /* NEGO_MESSAGE */ + ACCEPTOR_NEGO, /* NEGO_MESSAGE */ + INITIATOR_META_DATA, /* EXCHANGE_MESSAGE */ + ACCEPTOR_META_DATA, /* EXCHANGE_MESSAGE */ + CHALLENGE, /* EXCHANGE_MESSAGE */ + AP_REQUEST, /* EXCHANGE_MESSAGE */ + VERIFY, /* VERIFY_MESSAGE */ + ALERT, /* ALERT */ +}; + +struct nego_message { + uint8_t random[32]; + const uint8_t *schemes; + uint16_t nschemes; +}; + +struct exchange_message { + auth_scheme scheme; + gss_buffer_desc token; +}; + +struct verify_message { + auth_scheme scheme; + uint32_t cksum_type; + const uint8_t *cksum; + size_t cksum_len; + size_t offset_in_token; +}; + +struct alert_message { + auth_scheme scheme; + int verify_no_key; +}; + +struct negoex_message { + uint32_t type; + union { + struct nego_message n; + struct exchange_message e; + struct verify_message v; + struct alert_message a; + } u; +}; + +struct negoex_auth_mech { + HEIM_TAILQ_ENTRY(negoex_auth_mech) links; + gss_OID oid; + auth_scheme scheme; + gss_ctx_id_t mech_context; + gss_buffer_desc metadata; + krb5_crypto crypto; + krb5_crypto verify_crypto; + int complete; + int sent_checksum; + int verified_checksum; +}; + +#define NEGOEX_LOG_LEVEL 10 + +#endif /* NEGOEX_LOCL_H */ diff --git a/third_party/heimdal/lib/gssapi/spnego/negoex_util.c b/third_party/heimdal/lib/gssapi/spnego/negoex_util.c new file mode 100644 index 0000000..e6c9a13 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/negoex_util.c @@ -0,0 +1,1047 @@ +/* + * Copyright (C) 2011-2019 PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spnego_locl.h" + +/* + * SPNEGO expects to find the active mech context in ctx->negotiated_ctx_id, + * but the metadata exchange APIs force us to have one mech context per mech + * entry. To address this mismatch, move the active mech context (if we have + * one) to ctx->negotiated_ctx_id at the end of NegoEx processing. + */ +void +_gss_negoex_end(gssspnego_ctx ctx) +{ + struct negoex_auth_mech *mech; + + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + if (mech == NULL || mech->mech_context == GSS_C_NO_CONTEXT) + return; + + heim_assert(ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT, + "SPNEGO/NegoEx context mismatch"); + ctx->negotiated_ctx_id = mech->mech_context; + mech->mech_context = GSS_C_NO_CONTEXT; +} + +OM_uint32 +_gss_negoex_begin(OM_uint32 *minor, gssspnego_ctx ctx) +{ + struct negoex_auth_mech *mech; + + if (ctx->negoex_transcript != NULL) { + /* + * The context is already initialized for NegoEx; undo what + * _gss_negoex_end() did, if applicable. + */ + if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) { + mech = HEIM_TAILQ_FIRST(&ctx->negoex_mechs); + heim_assert(mech != NULL && mech->mech_context == GSS_C_NO_CONTEXT, + "NegoEx/SPNEGO context mismatch"); + mech->mech_context = ctx->negotiated_ctx_id; + ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; + } + return GSS_S_COMPLETE; + } + + ctx->negoex_transcript = krb5_storage_emem(); + if (ctx->negoex_transcript == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(ctx->negoex_transcript, + KRB5_STORAGE_BYTEORDER_LE); + + return GSS_S_COMPLETE; +} + +static void +release_all_mechs(gssspnego_ctx ctx, krb5_context context) +{ + struct negoex_auth_mech *mech, *next; + struct negoex_auth_mech *prev = NULL; + + HEIM_TAILQ_FOREACH_SAFE(mech, &ctx->negoex_mechs, links, next) { + if (prev) + _gss_negoex_release_auth_mech(context, prev); + prev = mech; + } + if (prev) + _gss_negoex_release_auth_mech(context, mech); + + HEIM_TAILQ_INIT(&ctx->negoex_mechs); +} + +void +_gss_negoex_release_context(gssspnego_ctx ctx) +{ + krb5_context context = _gss_mg_krb5_context(); + + if (ctx->negoex_transcript != NULL) { + krb5_storage_free(ctx->negoex_transcript); + ctx->negoex_transcript = NULL; + } + + release_all_mechs(ctx, context); +} + +static int +guid_to_string(const uint8_t guid[16], char *buffer, size_t bufsiz) +{ + uint32_t data1; + uint16_t data2, data3; + + _gss_mg_decode_le_uint32(&guid[0], &data1); + _gss_mg_decode_le_uint16(&guid[4], &data2); + _gss_mg_decode_le_uint16(&guid[6], &data3); + + return snprintf(buffer, bufsiz, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + data1, data2, data3, guid[8], guid[9], guid[10], guid[11], + guid[12], guid[13], guid[14], guid[15]); +} + +void +_gss_negoex_log_auth_scheme(int initiator, + int index, + const auth_scheme scheme) +{ + char scheme_str[37]; + + guid_to_string(scheme, scheme_str, sizeof(scheme_str)); + + _gss_mg_log(NEGOEX_LOG_LEVEL, + "negoex: %s authentication scheme %d %s", + initiator ? "proposing" : "received", index, scheme_str); +} + +void +_gss_negoex_log_message(int direction, + enum message_type type, + const conversation_id conv_id, + unsigned int seqnum, + unsigned int header_len, + unsigned int msg_len) +{ + char conv_str[37]; + char *typestr; + + if (type == INITIATOR_NEGO) + typestr = "INITIATOR_NEGO"; + else if (type == ACCEPTOR_NEGO) + typestr = "ACCEPTOR_NEGO"; + else if (type == INITIATOR_META_DATA) + typestr = "INITIATOR_META_DATA"; + else if (type == ACCEPTOR_META_DATA) + typestr = "ACCEPTOR_META_DATA"; + else if (type == CHALLENGE) + typestr = "CHALLENGE"; + else if (type == AP_REQUEST) + typestr = "AP_REQUEST"; + else if (type == VERIFY) + typestr = "VERIFY"; + else if (type == ALERT) + typestr = "ALERT"; + else + typestr = "UNKNOWN"; + + guid_to_string(conv_id, conv_str, sizeof(conv_str)); + _gss_mg_log(NEGOEX_LOG_LEVEL, + "negoex: %s (%d)%s conversation %s", + direction ? "received" : "sending", + seqnum, typestr, conv_str); +} + +/* + * Check that the described vector lies within the message, and return a + * pointer to its first element. + */ +static inline const uint8_t * +vector_base(size_t offset, size_t count, size_t width, + const uint8_t *msg_base, size_t msg_len) +{ + if (offset > msg_len || count > (msg_len - offset) / width) + return NULL; + return msg_base + offset; +} + +static OM_uint32 +parse_nego_message(OM_uint32 *minor, krb5_storage *sp, + const uint8_t *msg_base, size_t msg_len, + struct nego_message *msg) +{ + krb5_error_code ret; + const uint8_t *p; + uint64_t protocol_version; + uint32_t extension_type, offset; + uint16_t count; + size_t i; + + if (krb5_storage_read(sp, msg->random, + sizeof(msg->random)) != sizeof(msg->random)) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + ret = krb5_ret_uint64(sp, &protocol_version); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (protocol_version != 0) { + *minor = (OM_uint32)NEGOEX_UNSUPPORTED_VERSION; + return GSS_S_UNAVAILABLE; + } + + ret = krb5_ret_uint32(sp, &offset); + if (ret == 0) + ret = krb5_ret_uint16(sp, &count); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + msg->schemes = vector_base(offset, count, GUID_LENGTH, msg_base, msg_len); + msg->nschemes = count; + if (msg->schemes == NULL) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + ret = krb5_ret_uint32(sp, &offset); + if (ret == 0) + ret = krb5_ret_uint16(sp, &count); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + p = vector_base(offset, count, EXTENSION_LENGTH, msg_base, msg_len); + for (i = 0; i < count; i++) { + _gss_mg_decode_le_uint32(p + i * EXTENSION_LENGTH, &extension_type); + if (extension_type & EXTENSION_FLAG_CRITICAL) { + *minor = (OM_uint32)NEGOEX_UNSUPPORTED_CRITICAL_EXTENSION; + return GSS_S_UNAVAILABLE; + } + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +parse_exchange_message(OM_uint32 *minor, krb5_storage *sp, + const uint8_t *msg_base, size_t msg_len, + struct exchange_message *msg) +{ + krb5_error_code ret; + const uint8_t *p; + uint32_t offset; + uint16_t len; + + if (krb5_storage_read(sp, msg->scheme, GUID_LENGTH) != GUID_LENGTH) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + ret = krb5_ret_uint32(sp, &offset); + if (ret == 0) + ret = krb5_ret_uint16(sp, &len); + if (ret) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + p = vector_base(offset, len, 1, msg_base, msg_len); + if (p == NULL) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + msg->token.value = (void *)p; + msg->token.length = len; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +parse_verify_message(OM_uint32 *minor, krb5_storage *sp, + const uint8_t *msg_base, size_t msg_len, + size_t token_offset, struct verify_message *msg) +{ + krb5_error_code ret; + uint32_t hdrlen, cksum_scheme; + uint32_t offset, len; + + if (krb5_storage_read(sp, msg->scheme, GUID_LENGTH) == GUID_LENGTH) + ret = 0; + else + ret = NEGOEX_INVALID_MESSAGE_SIZE; + if (ret == 0) + ret = krb5_ret_uint32(sp, &hdrlen); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (hdrlen != CHECKSUM_HEADER_LENGTH) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + ret = krb5_ret_uint32(sp, &cksum_scheme); + if (ret == 0) + ret = krb5_ret_uint32(sp, &msg->cksum_type); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + if (cksum_scheme != CHECKSUM_SCHEME_RFC3961) { + *minor = (OM_uint32)NEGOEX_UNKNOWN_CHECKSUM_SCHEME; + return GSS_S_UNAVAILABLE; + } + + ret = krb5_ret_uint32(sp, &offset); + if (ret == 0) + ret = krb5_ret_uint32(sp, &len); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + msg->cksum = vector_base(offset, len, 1, msg_base, msg_len); + msg->cksum_len = len; + if (msg->cksum == NULL) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + msg->offset_in_token = token_offset; + return GSS_S_COMPLETE; +} + +static OM_uint32 +storage_from_memory(OM_uint32 *minor, + const uint8_t *data, + size_t length, + krb5_storage **sp) +{ + *sp = krb5_storage_from_readonly_mem(data, length); + if (*sp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(*sp, KRB5_STORAGE_BYTEORDER_LE); + krb5_storage_set_eof_code(*sp, NEGOEX_INVALID_MESSAGE_SIZE); + + return 0; +} + +static OM_uint32 +parse_alert_message(OM_uint32 *minor, krb5_storage *sp, + const uint8_t *msg_base, size_t msg_len, + struct alert_message *msg) +{ + OM_uint32 major; + krb5_error_code ret; + const uint8_t *p; + uint32_t error_code, atype; + uint32_t alerts_offset, nalerts, value_offset, value_len; + size_t i; + krb5_storage *alerts; + + if (krb5_storage_read(sp, msg->scheme, GUID_LENGTH) == GUID_LENGTH) + ret = 0; + else + ret = NEGOEX_INVALID_MESSAGE_SIZE; + if (ret == 0) + ret = krb5_ret_uint32(sp, &error_code); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + ret = krb5_ret_uint32(sp, &alerts_offset); + if (ret == 0) + ret = krb5_ret_uint32(sp, &nalerts); + if (ret) { + *minor = ret; + return GSS_S_DEFECTIVE_TOKEN; + } + + p = vector_base(alerts_offset, nalerts, ALERT_LENGTH, msg_base, msg_len); + if (p == NULL) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Look for a VERIFY_NO_KEY pulse alert in the alerts vector. */ + msg->verify_no_key = FALSE; + + major = storage_from_memory(minor, p, nalerts * ALERT_LENGTH, &alerts); + if (major != GSS_S_COMPLETE) + return major; + + for (i = 0; i < nalerts; i++) { + ret = krb5_ret_uint32(alerts, &atype); + if (ret == 0) + ret = krb5_ret_uint32(alerts, &value_offset); + if (ret == 0) + ret = krb5_ret_uint32(alerts, &value_len); + if (ret) { + *minor = ret; + major = GSS_S_DEFECTIVE_TOKEN; + break; + } + + p = vector_base(value_offset, value_len, 1, msg_base, msg_len); + if (p == NULL) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + major = GSS_S_DEFECTIVE_TOKEN; + break; + } + + if (atype == ALERT_TYPE_PULSE && value_len >= ALERT_PULSE_LENGTH) { + krb5_storage *pulse; + uint32_t hdrlen, reason; + + major = storage_from_memory(minor, p, value_len, &pulse); + if (major != GSS_S_COMPLETE) + break; + + ret = krb5_ret_uint32(pulse, &hdrlen); + if (ret == 0) + ret = krb5_ret_uint32(pulse, &reason); + krb5_storage_free(pulse); + if (ret) { + *minor = ret; + major = GSS_S_DEFECTIVE_TOKEN; + break; + } + + if (reason == ALERT_VERIFY_NO_KEY) + msg->verify_no_key = TRUE; + } + } + + krb5_storage_free(alerts); + + return major; +} + +static OM_uint32 +parse_message(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_const_buffer_t token, + size_t *token_offset, + struct negoex_message *msg) +{ + OM_uint32 major; + krb5_error_code ret; + krb5_storage *sp; + uint64_t signature; + uint32_t header_len, msg_len; + uint32_t type, seqnum; + conversation_id conv_id; + size_t token_remaining = token->length - *token_offset; + const uint8_t *msg_base = (uint8_t *)token->value + *token_offset; + + major = storage_from_memory(minor, msg_base, token_remaining, &sp); + if (major != GSS_S_COMPLETE) + return major; + + major = GSS_S_DEFECTIVE_TOKEN; + + ret = krb5_ret_uint64(sp, &signature); + if (ret == 0) + ret = krb5_ret_uint32(sp, &type); + if (ret == 0) + ret = krb5_ret_uint32(sp, &seqnum); + if (ret == 0) + ret = krb5_ret_uint32(sp, &header_len); + if (ret == 0) + ret = krb5_ret_uint32(sp, &msg_len); + if (ret == 0) { + if (krb5_storage_read(sp, conv_id, GUID_LENGTH) != GUID_LENGTH) + ret = NEGOEX_INVALID_MESSAGE_SIZE; + } + if (ret) { + *minor = ret; + goto cleanup; + } + + if (msg_len > token_remaining || header_len > msg_len) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + goto cleanup; + } + if (signature != MESSAGE_SIGNATURE) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIGNATURE; + goto cleanup; + } + if (seqnum != ctx->negoex_seqnum) { + *minor = (OM_uint32)NEGOEX_MESSAGE_OUT_OF_SEQUENCE; + goto cleanup; + } + if (seqnum == 0) { + memcpy(ctx->negoex_conv_id, conv_id, GUID_LENGTH); + } else if (!GUID_EQ(conv_id, ctx->negoex_conv_id)) { + *minor = (OM_uint32)NEGOEX_INVALID_CONVERSATION_ID; + goto cleanup; + } + + krb5_storage_truncate(sp, msg_len); + + msg->type = type; + if (type == INITIATOR_NEGO || type == ACCEPTOR_NEGO) { + major = parse_nego_message(minor, sp, msg_base, msg_len, &msg->u.n); + } else if (type == INITIATOR_META_DATA || type == ACCEPTOR_META_DATA || + type == CHALLENGE || type == AP_REQUEST) { + major = parse_exchange_message(minor, sp, msg_base, msg_len, + &msg->u.e); + } else if (type == VERIFY) { + major = parse_verify_message(minor, sp, msg_base, msg_len, + msg_base - (uint8_t *)token->value, + &msg->u.v); + } else if (type == ALERT) { + major = parse_alert_message(minor, sp, msg_base, msg_len, &msg->u.a); + } else { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_TYPE; + goto cleanup; + } + +cleanup: + krb5_storage_free(sp); + + if (major == GSS_S_COMPLETE) { + _gss_negoex_log_message(1, msg->type, + ctx->negoex_conv_id, ctx->negoex_seqnum, + header_len, msg_len); + ctx->negoex_seqnum++; + *token_offset += msg_len; + } + + return major; +} + +/* + * Parse token into an array of negoex_message structures. All pointer fields + * within the parsed messages are aliases into token, so the result can be + * freed with free(). An unknown protocol version, a critical extension, or an + * unknown checksum scheme will cause a parsing failure. Increment the + * sequence number in ctx for each message, and record and check the + * conversation ID in ctx as appropriate. + */ +OM_uint32 +_gss_negoex_parse_token(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_const_buffer_t token, + struct negoex_message **messages_out, + size_t *count_out) +{ + OM_uint32 major = GSS_S_DEFECTIVE_TOKEN; + size_t count = 0; + size_t token_offset = 0; + struct negoex_message *messages = NULL, *newptr; + + *messages_out = NULL; + *count_out = 0; + heim_assert(token != GSS_C_NO_BUFFER, "Invalid null NegoEx input token"); + + while (token_offset < token->length) { + newptr = realloc(messages, (count + 1) * sizeof(*newptr)); + if (newptr == NULL) { + free(messages); + *minor = ENOMEM; + return GSS_S_FAILURE; + } + messages = newptr; + + major = parse_message(minor, ctx, token, &token_offset, + &messages[count]); + if (major != GSS_S_COMPLETE) + break; + + count++; + } + + if (token_offset != token->length) { + *minor = (OM_uint32)NEGOEX_INVALID_MESSAGE_SIZE; + major = GSS_S_DEFECTIVE_TOKEN; + } + if (major != GSS_S_COMPLETE) { + free(messages); + return major; + } + + *messages_out = messages; + *count_out = count; + return GSS_S_COMPLETE; +} + +static struct negoex_message * +locate_message(struct negoex_message *messages, size_t nmessages, + enum message_type type) +{ + uint32_t i; + + for (i = 0; i < nmessages; i++) { + if (messages[i].type == type) + return &messages[i]; + } + + return NULL; +} + +struct nego_message * +_gss_negoex_locate_nego_message(struct negoex_message *messages, + size_t nmessages, + enum message_type type) +{ + struct negoex_message *msg = locate_message(messages, nmessages, type); + + return (msg == NULL) ? NULL : &msg->u.n; +} + +struct exchange_message * +_gss_negoex_locate_exchange_message(struct negoex_message *messages, + size_t nmessages, + enum message_type type) +{ + struct negoex_message *msg = locate_message(messages, nmessages, type); + + return (msg == NULL) ? NULL : &msg->u.e; +} + +struct verify_message * +_gss_negoex_locate_verify_message(struct negoex_message *messages, + size_t nmessages) +{ + struct negoex_message *msg = locate_message(messages, nmessages, VERIFY); + + return (msg == NULL) ? NULL : &msg->u.v; +} + +struct alert_message * +_gss_negoex_locate_alert_message(struct negoex_message *messages, + size_t nmessages) +{ + struct negoex_message *msg = locate_message(messages, nmessages, ALERT); + + return (msg == NULL) ? NULL : &msg->u.a; +} + +/* + * Add the encoding of a MESSAGE_HEADER structure to buf, given the number of + * bytes of the payload following the full header. Increment the sequence + * number in ctx. Set *payload_start_out to the position of the payload within + * the message. + */ +static OM_uint32 +put_message_header(OM_uint32 *minor, gssspnego_ctx ctx, + enum message_type type, uint32_t payload_len, + uint32_t *payload_start_out) +{ + krb5_error_code ret; + size_t header_len = 0; + + if (type == INITIATOR_NEGO || type == ACCEPTOR_NEGO) + header_len = NEGO_MESSAGE_HEADER_LENGTH; + else if (type == INITIATOR_META_DATA || type == ACCEPTOR_META_DATA || + type == CHALLENGE || type == AP_REQUEST) + header_len = EXCHANGE_MESSAGE_HEADER_LENGTH; + else if (type == VERIFY) + header_len = VERIFY_MESSAGE_HEADER_LENGTH; + else if (type == ALERT) + header_len = ALERT_MESSAGE_HEADER_LENGTH; + else + heim_assert(0, "Invalid NegoEx message type"); + + /* Signature */ + CHECK(ret, krb5_store_uint64(ctx->negoex_transcript, MESSAGE_SIGNATURE)); + /* MessageType */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, type)); + /* SequenceNum */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, ctx->negoex_seqnum)); + /* cbHeaderLength */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, header_len)); + /* cbMessageLength */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, header_len + payload_len)); + /* ConversationId */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, ctx->negoex_conv_id, GUID_LENGTH)); + + _gss_negoex_log_message(0, type, + ctx->negoex_conv_id, ctx->negoex_seqnum, + header_len, + header_len + payload_len); + + ctx->negoex_seqnum++; + + *payload_start_out = header_len; + return GSS_S_COMPLETE; + +fail: + *minor = ret; + return GSS_S_FAILURE; +} + +OM_uint32 +_gss_negoex_add_nego_message(OM_uint32 *minor, + gssspnego_ctx ctx, + enum message_type type, + uint8_t random[32]) +{ + OM_uint32 major; + krb5_error_code ret; + struct negoex_auth_mech *mech; + uint32_t payload_start; + uint16_t nschemes; + + nschemes = 0; + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) + nschemes++; + + major = put_message_header(minor, ctx, type, + nschemes * GUID_LENGTH, &payload_start); + if (major != GSS_S_COMPLETE) + return major; + + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, random, 32)); + /* ProtocolVersion */ + CHECK(ret, krb5_store_uint64(ctx->negoex_transcript, 0)); + /* AuthSchemes vector */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, payload_start)); + CHECK(ret, krb5_store_uint16(ctx->negoex_transcript, nschemes)); + /* Extensions vector */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, payload_start)); + CHECK(ret, krb5_store_uint16(ctx->negoex_transcript, 0)); + /* Four bytes of padding to reach a multiple of 8 bytes. */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, "\0\0\0\0", 4)); + + /* Payload (auth schemes) */ + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) { + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, mech->scheme, GUID_LENGTH)); + } + + return GSS_S_COMPLETE; + +fail: + *minor = ret; + return GSS_S_FAILURE; +} + +OM_uint32 +_gss_negoex_add_exchange_message(OM_uint32 *minor, + gssspnego_ctx ctx, + enum message_type type, + const auth_scheme scheme, + gss_buffer_t token) +{ + OM_uint32 major; + krb5_error_code ret; + uint32_t payload_start; + + major = put_message_header(minor, ctx, type, token->length, &payload_start); + if (major != GSS_S_COMPLETE) + return major; + + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, scheme, GUID_LENGTH)); + /* Exchange byte vector */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, payload_start)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, token->length)); + /* Payload (token) */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, token->value, token->length)); + + return GSS_S_COMPLETE; + +fail: + *minor = ret; + return GSS_S_FAILURE; +} + +OM_uint32 +_gss_negoex_add_verify_message(OM_uint32 *minor, + gssspnego_ctx ctx, + const auth_scheme scheme, + uint32_t cksum_type, + const uint8_t *cksum, + uint32_t cksum_len) +{ + OM_uint32 major; + krb5_error_code ret; + uint32_t payload_start; + + major = put_message_header(minor, ctx, VERIFY, cksum_len, &payload_start); + if (major != GSS_S_COMPLETE) + return major; + + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, scheme, GUID_LENGTH)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, CHECKSUM_HEADER_LENGTH)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, CHECKSUM_SCHEME_RFC3961)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, cksum_type)); + /* ChecksumValue vector */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, payload_start)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, cksum_len)); + /* Four bytes of padding to reach a multiple of 8 bytes. */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, "\0\0\0\0", 4)); + /* Payload (checksum contents) */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, cksum, cksum_len)); + + return GSS_S_COMPLETE; + +fail: + *minor = ret; + return GSS_S_FAILURE; +} + +/* + * Add an ALERT_MESSAGE containing a single ALERT_TYPE_PULSE alert with the + * reason ALERT_VERIFY_NO_KEY. + */ +OM_uint32 +_gss_negoex_add_verify_no_key_alert(OM_uint32 *minor, + gssspnego_ctx ctx, + const auth_scheme scheme) +{ + OM_uint32 major; + krb5_error_code ret; + uint32_t payload_start; + + major = put_message_header(minor, ctx, + ALERT, ALERT_LENGTH + ALERT_PULSE_LENGTH, + &payload_start); + if (major != GSS_S_COMPLETE) + return major; + + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, scheme, GUID_LENGTH)); + /* ErrorCode */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, 0)); + /* Alerts vector */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, payload_start)); + CHECK(ret, krb5_store_uint16(ctx->negoex_transcript, 1)); + /* Six bytes of padding to reach a multiple of 8 bytes. */ + CHECK(ret, krb5_store_bytes(ctx->negoex_transcript, "\0\0\0\0\0\0", 6)); + /* Payload part 1: a single ALERT element */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, ALERT_TYPE_PULSE)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, + payload_start + ALERT_LENGTH)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, ALERT_PULSE_LENGTH)); + /* Payload part 2: ALERT_PULSE */ + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, ALERT_PULSE_LENGTH)); + CHECK(ret, krb5_store_uint32(ctx->negoex_transcript, ALERT_VERIFY_NO_KEY)); + + return GSS_S_COMPLETE; + +fail: + *minor = ret; + return GSS_S_FAILURE; +} + + +void +_gss_negoex_release_auth_mech(krb5_context context, + struct negoex_auth_mech *mech) +{ + OM_uint32 tmpmin; + + if (mech == NULL) + return; + + gss_delete_sec_context(&tmpmin, &mech->mech_context, NULL); + gss_release_oid(&tmpmin, &mech->oid); + gss_release_buffer(&tmpmin, &mech->metadata); + if (mech->crypto) + krb5_crypto_destroy(context, mech->crypto); + if (mech->verify_crypto) + krb5_crypto_destroy(context, mech->verify_crypto); + + free(mech); +} + +void +_gss_negoex_delete_auth_mech(gssspnego_ctx ctx, + struct negoex_auth_mech *mech) +{ + krb5_context context = _gss_mg_krb5_context(); + + HEIM_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links); + _gss_negoex_release_auth_mech(context, mech); +} + +/* Remove all auth mech entries except for mech from ctx->mechs. */ +void +_gss_negoex_select_auth_mech(gssspnego_ctx ctx, + struct negoex_auth_mech *mech) +{ + krb5_context context = _gss_mg_krb5_context(); + + heim_assert(mech != NULL, "Invalid null NegoEx mech"); + HEIM_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links); + release_all_mechs(ctx, context); + HEIM_TAILQ_INSERT_HEAD(&ctx->negoex_mechs, mech, links); +} + +OM_uint32 +_gss_negoex_add_auth_mech(OM_uint32 *minor, + gssspnego_ctx ctx, + gss_const_OID oid, + auth_scheme scheme) +{ + OM_uint32 major; + struct negoex_auth_mech *mech; + + mech = calloc(1, sizeof(*mech)); + if (mech == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + major = gss_duplicate_oid(minor, (gss_OID)oid, &mech->oid); + if (major != GSS_S_COMPLETE) { + free(mech); + return major; + } + + memcpy(mech->scheme, scheme, GUID_LENGTH); + + HEIM_TAILQ_INSERT_TAIL(&ctx->negoex_mechs, mech, links); + + *minor = 0; + return GSS_S_COMPLETE; +} + +struct negoex_auth_mech * +_gss_negoex_locate_auth_scheme(gssspnego_ctx ctx, + const auth_scheme scheme) +{ + struct negoex_auth_mech *mech; + + HEIM_TAILQ_FOREACH(mech, &ctx->negoex_mechs, links) { + if (GUID_EQ(mech->scheme, scheme)) + return mech; + } + + return NULL; +} + +/* + * Prune ctx->mechs to the schemes present in schemes, and reorder them to + * match its order. + */ +void +_gss_negoex_common_auth_schemes(gssspnego_ctx ctx, + const uint8_t *schemes, + uint16_t nschemes) +{ + struct negoex_mech_list list; + struct negoex_auth_mech *mech; + uint16_t i; + krb5_context context = _gss_mg_krb5_context(); + + /* Construct a new list in the order of schemes. */ + HEIM_TAILQ_INIT(&list); + for (i = 0; i < nschemes; i++) { + mech = _gss_negoex_locate_auth_scheme(ctx, schemes + i * GUID_LENGTH); + if (mech == NULL) + continue; + HEIM_TAILQ_REMOVE(&ctx->negoex_mechs, mech, links); + HEIM_TAILQ_INSERT_TAIL(&list, mech, links); + } + + /* Release any leftover entries and replace the context list. */ + release_all_mechs(ctx, context); + HEIM_TAILQ_CONCAT(&ctx->negoex_mechs, &list, links); +} + +/* + * Prune ctx->mechs to the schemes present in schemes, but do not change + * their order. + */ +void +_gss_negoex_restrict_auth_schemes(gssspnego_ctx ctx, + const uint8_t *schemes, + uint16_t nschemes) +{ + struct negoex_auth_mech *mech, *next; + uint16_t i; + int found; + + HEIM_TAILQ_FOREACH_SAFE(mech, &ctx->negoex_mechs, links, next) { + found = FALSE; + for (i = 0; i < nschemes && !found; i++) { + if (GUID_EQ(mech->scheme, schemes + i * GUID_LENGTH)) + found = TRUE; + } + + if (!found) + _gss_negoex_delete_auth_mech(ctx, mech); + } +} + +/* + * Return the OID of the current NegoEx mechanism. + */ +struct negoex_auth_mech * +_gss_negoex_negotiated_mech(gssspnego_ctx ctx) +{ + return HEIM_TAILQ_FIRST(&ctx->negoex_mechs); +} + +/* + * Returns TRUE if mechanism can be negotiated by both NegoEx and SPNEGO + */ + +int +_gss_negoex_and_spnego_mech_p(gss_const_OID mech) +{ + OM_uint32 major, minor; + gss_OID_set attrs = GSS_C_NO_OID_SET; + int negoex_and_spnego = FALSE; + + major = gss_inquire_attrs_for_mech(&minor, mech, &attrs, NULL); + if (major == GSS_S_COMPLETE) { + gss_test_oid_set_member(&minor, GSS_C_MA_NEGOEX_AND_SPNEGO, + attrs, &negoex_and_spnego); + gss_release_oid_set(&minor, &attrs); + } + + return negoex_and_spnego; +} + +int +_gss_negoex_mech_p(gss_const_OID mech) +{ + OM_uint32 minor; + auth_scheme scheme; + + return gssspi_query_mechanism_info(&minor, mech, + scheme) == GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/spnego/spnego.asn1 b/third_party/heimdal/lib/gssapi/spnego/spnego.asn1 new file mode 100644 index 0000000..bd69a05 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/spnego.asn1 @@ -0,0 +1,66 @@ +-- $Id$ + +SPNEGO DEFINITIONS ::= +BEGIN + +MechType::= OBJECT IDENTIFIER + +MechTypeList ::= SEQUENCE OF MechType + +ContextFlags ::= BIT STRING { + delegFlag (0), + mutualFlag (1), + replayFlag (2), + sequenceFlag (3), + anonFlag (4), + confFlag (5), + integFlag (6) +} + +NegHints ::= SEQUENCE { + hintName [0] GeneralString OPTIONAL, + hintAddress [1] OCTET STRING OPTIONAL +} + +NegTokenInit2 ::= SEQUENCE { + mechTypes [0] MechTypeList, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + negHints [3] NegHints OPTIONAL +} + +NegTokenInit ::= SEQUENCE { + mechTypes [0] MechTypeList, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL, + ... +} + +NegStateEnum ::= ENUMERATED { + accept-completed(0), + accept-incomplete(1), + reject(2), + request-mic(3) +} + +-- NB: negState is not OPTIONAL in the new SPNEGO spec but +-- Windows clients do not always send it +NegTokenResp ::= SEQUENCE { + negState [0] NegStateEnum OPTIONAL, + supportedMech [1] MechType OPTIONAL, + responseToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL, + ... +} + +NegotiationToken ::= CHOICE { + negTokenInit[0] NegTokenInit, + negTokenResp[1] NegTokenResp +} + +NegotiationToken2 ::= CHOICE { + negTokenInit[0] NegTokenInit2 +} + +END diff --git a/third_party/heimdal/lib/gssapi/spnego/spnego.opt b/third_party/heimdal/lib/gssapi/spnego/spnego.opt new file mode 100644 index 0000000..cbf2f23 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/spnego.opt @@ -0,0 +1 @@ +--sequence=MechTypeList diff --git a/third_party/heimdal/lib/gssapi/spnego/spnego_locl.h b/third_party/heimdal/lib/gssapi/spnego/spnego_locl.h new file mode 100644 index 0000000..e3434f2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/spnego/spnego_locl.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef SPNEGO_LOCL_H +#define SPNEGO_LOCL_H + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include + +#ifdef HAVE_PTHREAD_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_NETDB_H +#include +#endif + +#include +#include +#include + +#include + +#include "spnego_asn1.h" +#include "negoex_locl.h" +#include "utils.h" +#include + +#include + +#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) + +#define CHECK(ret, x) do { (ret) = (x); if (ret) goto fail; } while (0) + +struct gssspnego_ctx_desc; +typedef struct gssspnego_ctx_desc *gssspnego_ctx; + +typedef OM_uint32 +(*gssspnego_initiator_state)(OM_uint32 * minor_status, + gss_const_cred_id_t cred, + gssspnego_ctx ctx, + gss_const_name_t name, + gss_const_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_const_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec); + +struct gssspnego_ctx_desc { + gss_buffer_desc NegTokenInit_mech_types; + gss_OID preferred_mech_type; + gss_OID selected_mech_type; + gss_OID negotiated_mech_type; + gss_ctx_id_t negotiated_ctx_id; + OM_uint32 mech_flags; + OM_uint32 mech_time_rec; + gss_name_t mech_src_name; + struct spnego_flags { + unsigned int open : 1; + unsigned int local : 1; + unsigned int require_mic : 1; + unsigned int peer_require_mic : 1; + unsigned int sent_mic : 1; + unsigned int verified_mic : 1; + unsigned int safe_omit : 1; + unsigned int maybe_open : 1; + unsigned int seen_supported_mech : 1; + } flags; + HEIMDAL_MUTEX ctx_id_mutex; + + gss_name_t target_name; + gssspnego_initiator_state initiator_state; + + uint8_t negoex_step; + krb5_storage *negoex_transcript; + uint32_t negoex_seqnum; + conversation_id negoex_conv_id; + HEIM_TAILQ_HEAD(negoex_mech_list, negoex_auth_mech) negoex_mechs; +}; + +extern gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc; + +struct gssspnego_optimistic_ctx { + gssspnego_ctx spnegoctx; + OM_uint32 req_flags; + gss_name_t target_name; + OM_uint32 time_req; + gss_channel_bindings_t input_chan_bindings; + /* out */ + gss_OID preferred_mech_type; + gss_OID negotiated_mech_type; + gss_buffer_desc optimistic_token; + OM_uint32 optimistic_flags, optimistic_time_rec; + gss_ctx_id_t gssctx; + int complete; + auth_scheme scheme; +}; + +#include "spnego-private.h" + +static inline int +gssspnego_ctx_complete_p(gssspnego_ctx ctx) +{ + return ctx->flags.open && + (ctx->flags.safe_omit || (ctx->flags.sent_mic && ctx->flags.verified_mic)); +} + +#endif /* SPNEGO_LOCL_H */ diff --git a/third_party/heimdal/lib/gssapi/test_acquire_cred.c b/third_party/heimdal/lib/gssapi/test_acquire_cred.c new file mode 100644 index 0000000..ef49311 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_acquire_cred.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2003-2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_common.h" + +static void +print_time(OM_uint32 time_rec) +{ + if (time_rec == GSS_C_INDEFINITE) { + printf("cred never expire\n"); + } else { + time_t t = time_rec + time(NULL); + printf("expiration time: %s", ctime(&t)); + } +} + +#if 0 + +static void +test_add(gss_cred_id_t cred_handle) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t copy_cred; + OM_uint32 time_rec; + + major_status = gss_add_cred (&minor_status, + cred_handle, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_INITIATE, + 0, + 0, + ©_cred, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major_status)) + errx(1, "add_cred failed"); + + print_time(time_rec); + + major_status = gss_release_cred(&minor_status, + ©_cred); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} + +static void +copy_cred(void) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + + major_status = gss_acquire_cred(&minor_status, + GSS_C_NO_NAME, + 0, + NULL, + GSS_C_INITIATE, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) + errx(1, "acquire_cred failed"); + + print_time(time_rec); + + test_add(cred_handle); + test_add(cred_handle); + test_add(cred_handle); + + major_status = gss_release_cred(&minor_status, + &cred_handle); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} +#endif + +static gss_cred_id_t +acquire_cred_service(const char *service, + gss_OID nametype, + gss_OID_set oidset, + gss_cred_usage_t usage, + gss_const_key_value_set_t cred_store) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + gss_buffer_desc name_buffer; + gss_name_t name = GSS_C_NO_NAME; + + if (service) { + name_buffer.value = rk_UNCONST(service); + name_buffer.length = strlen(service); + + major_status = gss_import_name(&minor_status, + &name_buffer, + nametype, + &name); + if (GSS_ERROR(major_status)) + errx(1, "import_name failed"); + } + + major_status = gss_acquire_cred_from(&minor_status, + name, + 0, + oidset, + usage, + cred_store, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) { + warnx("acquire_cred failed: %s", + gssapi_err(major_status, minor_status, GSS_C_NO_OID)); + } else { + print_time(time_rec); + gss_release_cred(&minor_status, &cred_handle); + } + + if (name != GSS_C_NO_NAME) + gss_release_name(&minor_status, &name); + + if (GSS_ERROR(major_status)) + exit(1); + + return cred_handle; +} + +static int version_flag = 0; +static int help_flag = 0; +static int kerberos_flag = 0; +static int enctype = 0; +static char *acquire_name; +static char *acquire_type; +static char *target_name; +static char *name_type; +static char *ccache; +static char *client_keytab; +static int num_loops = 1; + +static struct getargs args[] = { + {"acquire-name", 0, arg_string, &acquire_name, "name", NULL }, + {"acquire-type", 0, arg_string, &acquire_type, "type", NULL }, + {"enctype", 0, arg_integer, &enctype, "enctype-num", NULL }, + {"loops", 0, arg_integer, &num_loops, "num-loops", NULL }, + {"kerberos", 0, arg_flag, &kerberos_flag, NULL, NULL }, + {"target-name", 0, arg_string, &target_name, "name", NULL }, + {"ccache", 0, arg_string, &ccache, "name", NULL }, + {"client-keytab", 0,arg_string, &client_keytab, "name", NULL }, + {"name-type", 0, arg_string, &name_type, "type", NULL }, + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + gss_OID_set oidset = GSS_C_NULL_OID_SET; + gss_OID mechoid = GSS_C_NO_OID; + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred; + gss_name_t target = GSS_C_NO_NAME; + int i, optidx = 0; + gss_cred_usage_t cred_usage = GSS_C_BOTH; + gss_OID type = GSS_C_NT_HOSTBASED_SERVICE; + gss_key_value_set_desc store, *storep = GSS_C_NO_CRED_STORE; + gss_key_value_element_desc elements[2]; + + store.count = 0; + store.elements = elements; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc != 0) + usage(1); + + if (acquire_type) { + if (strcasecmp(acquire_type, "both") == 0) + cred_usage = GSS_C_BOTH; + else if (strcasecmp(acquire_type, "accept") == 0) + cred_usage = GSS_C_ACCEPT; + else if (strcasecmp(acquire_type, "initiate") == 0) + cred_usage = GSS_C_INITIATE; + else + errx(1, "unknown type %s", acquire_type); + } + + if (name_type) { + if (strcasecmp("hostbased-service", name_type) == 0) + type = GSS_C_NT_HOSTBASED_SERVICE; + else if (strcasecmp("user-name", name_type) == 0) + type = GSS_C_NT_USER_NAME; + else + errx(1, "unknown name type %s", name_type); + } + + if (ccache) { + store.elements[store.count].key = "ccache"; + store.elements[store.count].value = ccache; + store.count++; + } + if (client_keytab) { + store.elements[store.count].key = "client_keytab"; + store.elements[store.count].value = client_keytab; + store.count++; + } + + if (store.count) + storep = &store; + + if (kerberos_flag) { + mechoid = GSS_KRB5_MECHANISM; + + maj_stat = gss_create_empty_oid_set(&min_stat, &oidset); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_create_empty_oid_set: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + maj_stat = gss_add_oid_set_member(&min_stat, GSS_KRB5_MECHANISM, &oidset); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_add_oid_set_member: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + if (target_name) { + gss_buffer_desc name; + + name.value = target_name; + name.length = strlen(target_name); + maj_stat = gss_import_name(&min_stat, &name, + GSS_C_NT_HOSTBASED_SERVICE, &target); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_import_name: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + for (i = 0; i < num_loops; i++) { + + cred = acquire_cred_service(acquire_name, type, oidset, cred_usage, storep); + + if (enctype) { + int32_t enctypelist = enctype; + + maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred, + 1, &enctypelist); + if (maj_stat) + errx(1, "gss_krb5_set_allowable_enctypes: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + if (target) { + gss_ctx_id_t context = GSS_C_NO_CONTEXT; + gss_buffer_desc out; + + out.length = 0; + out.value = NULL; + + maj_stat = gss_init_sec_context(&min_stat, + cred, &context, + target, mechoid, + GSS_C_MUTUAL_FLAG, 0, NULL, + GSS_C_NO_BUFFER, NULL, + &out, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + errx(1, "init_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + gss_release_buffer(&min_stat, &out); + gss_delete_sec_context(&min_stat, &context, NULL); + } + gss_release_cred(&min_stat, &cred); + } + gss_release_oid_set(&min_stat, &oidset); + gss_release_name(&min_stat, &target); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/test_add_store_cred.c b/third_party/heimdal/lib/gssapi/test_add_store_cred.c new file mode 100644 index 0000000..03c3dc9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_add_store_cred.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015 Cryptonector LLC. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name Cryptonector LLC may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +static void +print_gss_err(OM_uint32 stat, int status_type, gss_OID mech) +{ + gss_buffer_desc str; + OM_uint32 maj; + OM_uint32 min; + OM_uint32 msg_ctx = 0; + int first = 1; + + do { + maj = gss_display_status(&min, stat, status_type, mech, &msg_ctx, + &str); + if (maj != GSS_S_COMPLETE) { + fprintf(stderr, "Error displaying GSS %s error (%lu): %lu, %lu", + status_type == GSS_C_GSS_CODE ? "major" : "minor", + (unsigned long)stat, (unsigned long)maj, + (unsigned long)min); + return; + } + if (first) { + fprintf(stderr, "GSS %s error: %.*s\n", + status_type == GSS_C_GSS_CODE ? "major" : "minor", + (int)str.length, (char *)str.value); + first = 0; + } else { + fprintf(stderr, "\t%.*s\n", (int)str.length, (char *)str.value); + } + gss_release_buffer(&min, &str); + } while (msg_ctx != 0); +} + +static void +print_gss_errs(OM_uint32 major, OM_uint32 minor, gss_OID mech) +{ + print_gss_err(major, GSS_C_GSS_CODE, GSS_C_NO_OID); + print_gss_err(major, GSS_C_MECH_CODE, mech); +} + +static void +gss_err(int exitval, OM_uint32 major, OM_uint32 minor, gss_OID mech, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx(fmt, args); + va_end(args); + print_gss_errs(major, minor, mech); + exit(exitval); +} + +static int version_flag = 0; +static int help_flag = 0; +static int env_flag = 0; +static int def_flag = 0; +static int overwrite_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL }, + {"env", 'e', arg_flag, &env_flag, + "output env settings", NULL }, + {"default", 0, arg_flag, &def_flag, + "switch credential store default principal", NULL }, + {"overwrite", 0, arg_flag, &overwrite_flag, + "overwrite matching credential", NULL }, +}; + +static void +usage(int ret) +{ + arg_printusage(args, sizeof(args)/sizeof(*args), + NULL, "from_ccache to_ccache"); + exit(ret); +} + +int +main(int argc, char **argv) +{ + OM_uint32 major, minor; + gss_cred_id_t from_cred = GSS_C_NO_CREDENTIAL; + gss_cred_id_t to_cred = GSS_C_NO_CREDENTIAL; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + gss_key_value_element_desc from_elements, to_elements; + gss_key_value_set_desc from, to; + gss_buffer_set_t env = GSS_C_NO_BUFFER_SET; + OM_uint32 store_flags = 0; + int optidx = 0; + + setprogname(argv[0]); + if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if (version_flag){ + print_version(NULL); + exit(0); + } + + if (def_flag) + store_flags |= GSS_C_STORE_CRED_DEFAULT; + if (overwrite_flag) + store_flags |= GSS_C_STORE_CRED_OVERWRITE; + + argc -= optidx; + argv += optidx; + + if (argc < 2) + errx(1, "required arguments missing"); + if (argc > 2) + errx(1, "too many arguments"); + + from_elements.key = "ccache"; + from_elements.value = argv[0]; + from.count = 1; + from.elements = &from_elements; + + to_elements.key = "ccache"; + to_elements.value = argv[1]; + to.count = 1; + to.elements = &to_elements; + + major = gss_add_cred_from(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, GSS_C_INITIATE, + GSS_C_INDEFINITE, GSS_C_INDEFINITE, + &from, &from_cred, NULL, NULL, NULL); + if (major != GSS_S_COMPLETE) + gss_err(1, major, minor, GSS_KRB5_MECHANISM, + "failed to acquire creds from %s", argv[0]); + + major = gss_store_cred_into2(&minor, from_cred, GSS_C_INITIATE, + GSS_KRB5_MECHANISM, store_flags, &to, NULL, + NULL, env_flag ? &env : NULL); + if (major != GSS_S_COMPLETE) + gss_err(1, major, minor, GSS_KRB5_MECHANISM, + "failed to store creds into %s", argv[1]); + + if (env_flag) { + size_t i; + int got_krb5ccname = 0; + + if (env == GSS_C_NO_BUFFER_SET) + warnx("No environment settings"); + + for (i = 0; env != GSS_C_NO_BUFFER_SET && i < env->count; i++) { + got_krb5ccname = got_krb5ccname || + (env->elements[i].length > sizeof("KRB5CCNAME=") && + strncmp((const char *)env->elements[i].value, "KRB5CCNAME=", + sizeof("KRB5CCNAME=") - 1) == 0); + printf("%.*s\n", (int)env->elements[i].length, + (const char *)env->elements[i].value); + } + (void) gss_release_buffer_set(&minor, &env); + + if (!got_krb5ccname) + errx(1, "KRB5CCNAME environment variable not set by " + "gss_store_cred_into2()"); + } + + (void) gss_release_cred(&minor, &from_cred); + (void) gss_release_cred(&minor, &to_cred); + + major = gss_add_cred(&minor, GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, GSS_C_INITIATE, GSS_C_INDEFINITE, + GSS_C_INDEFINITE, &cred, NULL, NULL, NULL); + if (major != GSS_S_COMPLETE) + gss_err(1, major, minor, GSS_KRB5_MECHANISM, + "failed to acquire creds from %s", argv[1]); + (void) gss_release_cred(&minor, &cred); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/test_common.c b/third_party/heimdal/lib/gssapi/test_common.c new file mode 100644 index 0000000..ebdcd71 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_common.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "krb5/gsskrb5_locl.h" +#include +#include "test_common.h" + +char * +gssapi_err(OM_uint32 maj_stat, OM_uint32 min_stat, gss_OID mech) +{ + OM_uint32 disp_min_stat; + gss_buffer_desc maj_error_message; + gss_buffer_desc min_error_message; + OM_uint32 msg_ctx = 0; + + char *ret = NULL; + + maj_error_message.length = 0; + maj_error_message.value = NULL; + min_error_message.length = 0; + min_error_message.value = NULL; + + (void) gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE, + mech, &msg_ctx, &maj_error_message); + (void) gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE, + mech, &msg_ctx, &min_error_message); + if (asprintf(&ret, "gss-code: %lu %.*s -- mech-code: %lu %.*s", + (unsigned long)maj_stat, + (int)maj_error_message.length, + (char *)maj_error_message.value, + (unsigned long)min_stat, + (int)min_error_message.length, + (char *)min_error_message.value) < 0 || ret == NULL) + errx(1, "malloc"); + + gss_release_buffer(&disp_min_stat, &maj_error_message); + gss_release_buffer(&disp_min_stat, &min_error_message); + + return ret; +} + diff --git a/third_party/heimdal/lib/gssapi/test_common.h b/third_party/heimdal/lib/gssapi/test_common.h new file mode 100644 index 0000000..fda2949 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_common.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id$ */ + +char * gssapi_err(OM_uint32, OM_uint32, gss_OID); diff --git a/third_party/heimdal/lib/gssapi/test_context.c b/third_party/heimdal/lib/gssapi/test_context.c new file mode 100644 index 0000000..907e9c4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_context.c @@ -0,0 +1,1622 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "krb5/gsskrb5_locl.h" +#include +#include +#include +#include +#include +#include +#include "test_common.h" + +#ifdef NOTYET +/* + * export/import of sec contexts on the initiator side + * don't work properly, yet. + */ +#define DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT 1 +#endif + +static char *type_string; +static char *mech_string; +static char *mechs_string; +static char *ret_mech_string; +static char *localname_string; +static char *client_name; +static char *client_password; +static char *localname_string; +static char *on_behalf_of_string; +static int dns_canon_flag = -1; +static int mutual_auth_flag = 0; +static int dce_style_flag = 0; +static int wrapunwrap_flag = 0; +static int iov_flag = 0; +static int aead_flag = 0; +static int getverifymic_flag = 0; +static int deleg_flag = 0; +static int anon_flag = 0; +static int policy_deleg_flag = 0; +static int server_no_deleg_flag = 0; +static int ei_cred_flag = 0; +static int ei_ctx_flag = 0; +static char *client_ccache = NULL; +static char *client_keytab = NULL; +static char *gsskrb5_acceptor_identity = NULL; +static char *session_enctype_string = NULL; +static int client_time_offset = 0; +static int server_time_offset = 0; +static int max_loops = 0; +static char *limit_enctype_string = NULL; +static int token_split = 0; +static int version_flag = 0; +static int verbose_flag = 0; +static int help_flag = 0; +static char *i_channel_bindings = NULL; +static char *a_channel_bindings = NULL; + +static krb5_context context; +static krb5_enctype limit_enctype = 0; + +static gss_OID +string_to_oid(const char *name) +{ + gss_OID oid = gss_name_to_oid(name); + + if (oid == GSS_C_NO_OID) + errx(1, "name '%s' not known", name); + + return oid; +} + +static void +string_to_oids(gss_OID_set *oidsetp, char *names) +{ + OM_uint32 maj_stat, min_stat; + char *name; + char *s; + + if (names[0] == '\0') { + *oidsetp = GSS_C_NO_OID_SET; + return; + } + + if (strcasecmp(names, "all") == 0) { + maj_stat = gss_indicate_mechs(&min_stat, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_indicate_mechs: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } else { + maj_stat = gss_create_empty_oid_set(&min_stat, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_create_empty_oid_set: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + for (name = strtok_r(names, ", ", &s); + name != NULL; + name = strtok_r(NULL, ", ", &s)) { + gss_OID oid = string_to_oid(name); + + maj_stat = gss_add_oid_set_member(&min_stat, oid, oidsetp); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_add_oid_set_member: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + } +} + +static void +show_pac_client_info(gss_name_t n) +{ + gss_buffer_desc dv = GSS_C_EMPTY_BUFFER; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_buffer_desc a; + OM_uint32 maj, min; + int authenticated, complete, more, name_is_MN, found; + gss_OID MN_mech; + gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; + size_t i; + + krb5_error_code ret; + krb5_storage *sp = NULL; + uint16_t len = 0, *s; + uint64_t tmp; + char *logon_string = NULL; + + maj = gss_inquire_name(&min, n, &name_is_MN, &MN_mech, &attrs); + if (maj != GSS_S_COMPLETE) + errx(1, "gss_inquire_name: %s", + gssapi_err(maj, min, GSS_KRB5_MECHANISM)); + + a.value = "urn:mspac:client-info"; + a.length = sizeof("urn:mspac:client-info") - 1; + + for (found = 0, i = 0; i < attrs->count; i++) { + gss_buffer_t attr = &attrs->elements[i]; + + if (attr->length == a.length && + memcmp(attr->value, a.value, a.length) == 0) { + found++; + break; + } + } + + gss_release_buffer_set(&min, &attrs); + + if (!found) + errx(1, "gss_inquire_name: attribute %.*s not enumerated", + (int)a.length, (char *)a.value); + + more = 0; + maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v, + &dv, &more); + if (maj != GSS_S_COMPLETE) + errx(1, "gss_get_name_attribute: %s", + gssapi_err(maj, min, GSS_KRB5_MECHANISM)); + + + sp = krb5_storage_from_readonly_mem(v.value, v.length); + if (sp == NULL) + errx(1, "show_pac_client_info: out of memory"); + + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + ret = krb5_ret_uint64(sp, &tmp); /* skip over time */ + if (ret == 0) + ret = krb5_ret_uint16(sp, &len); + if (ret || len == 0) + errx(1, "show_pac_client_info: invalid PAC logon info length"); + + s = malloc(len); + ret = krb5_storage_read(sp, s, len); + if (ret != len) + errx(1, "show_pac_client_info:, failed to read PAC logon name"); + + krb5_storage_free(sp); + + { + size_t ucs2len = len / 2; + uint16_t *ucs2; + size_t u8len; + unsigned int flags = WIND_RW_LE; + + ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); + if (ucs2 == NULL) + errx(1, "show_pac_client_info: out of memory"); + + ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); + free(s); + if (ret) + errx(1, "failed to convert string to UCS-2"); + + ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); + if (ret) + errx(1, "failed to count length of UCS-2 string"); + + u8len += 1; /* Add space for NUL */ + logon_string = malloc(u8len); + if (logon_string == NULL) + errx(1, "show_pac_client_info: out of memory"); + + ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); + free(ucs2); + if (ret) + errx(1, "failed to convert to UTF-8"); + } + + printf("logon name: %s\n", logon_string); + free(logon_string); + + gss_release_buffer(&min, &dv); + gss_release_buffer(&min, &v); +} + +static void +loop(gss_OID mechoid, + gss_OID nameoid, const char *target, + gss_cred_id_t init_cred, + gss_ctx_id_t *sctx, gss_ctx_id_t *cctx, + gss_OID *actual_mech, + gss_cred_id_t *deleg_cred) +{ + int server_done = 0, client_done = 0; + int num_loops = 0; + OM_uint32 maj_stat, min_stat; + gss_name_t gss_target_name, src_name = GSS_C_NO_NAME; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; +#ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT + gss_buffer_desc cctx_tok = GSS_C_EMPTY_BUFFER; +#endif + gss_buffer_desc sctx_tok = GSS_C_EMPTY_BUFFER; + OM_uint32 flags = 0, ret_cflags = 0, ret_sflags = 0; + gss_OID actual_mech_client = GSS_C_NO_OID; + gss_OID actual_mech_server = GSS_C_NO_OID; + struct gss_channel_bindings_struct i_channel_bindings_data; + struct gss_channel_bindings_struct a_channel_bindings_data; + gss_channel_bindings_t i_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS; + gss_channel_bindings_t a_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS; + size_t offset = 0; + + memset(&i_channel_bindings_data, 0, sizeof(i_channel_bindings_data)); + memset(&a_channel_bindings_data, 0, sizeof(a_channel_bindings_data)); + + *actual_mech = GSS_C_NO_OID; + + flags |= GSS_C_REPLAY_FLAG; + flags |= GSS_C_INTEG_FLAG; + flags |= GSS_C_CONF_FLAG; + + if (mutual_auth_flag) + flags |= GSS_C_MUTUAL_FLAG; + if (anon_flag) + flags |= GSS_C_ANON_FLAG; + if (dce_style_flag) + flags |= GSS_C_DCE_STYLE; + if (deleg_flag) + flags |= GSS_C_DELEG_FLAG; + if (policy_deleg_flag) + flags |= GSS_C_DELEG_POLICY_FLAG; + + input_token.value = rk_UNCONST(target); + input_token.length = strlen(target); + + maj_stat = gss_import_name(&min_stat, + &input_token, + nameoid, + &gss_target_name); + if (GSS_ERROR(maj_stat)) + err(1, "import name creds failed with: %d", maj_stat); + + if (on_behalf_of_string) { + AuthorizationDataElement e; + gss_buffer_desc attr, value; + int32_t kret; + size_t sz; + + memset(&e, 0, sizeof(e)); + e.ad_type = KRB5_AUTHDATA_ON_BEHALF_OF; + e.ad_data.length = strlen(on_behalf_of_string); + e.ad_data.data = on_behalf_of_string; + ASN1_MALLOC_ENCODE(AuthorizationDataElement, value.value, value.length, + &e, &sz, kret); + if (kret) + errx(1, "Could not encode AD-ON-BEHALF-OF AuthorizationDataElement"); + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authenticator-authz-data") - 1; + maj_stat = gss_set_name_attribute(&min_stat, gss_target_name, 1, &attr, + &value); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_set_name_attribute() failed with: %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + free(value.value); + } + + input_token.length = 0; + input_token.value = NULL; + + if (i_channel_bindings) { + i_channel_bindings_data.application_data.length = strlen(i_channel_bindings); + i_channel_bindings_data.application_data.value = i_channel_bindings; + i_channel_bindings_p = &i_channel_bindings_data; + } + if (a_channel_bindings) { + a_channel_bindings_data.application_data.length = strlen(a_channel_bindings); + a_channel_bindings_data.application_data.value = a_channel_bindings; + a_channel_bindings_p = &a_channel_bindings_data; + } + + /* + * This loop simulates both the initiator and acceptor sides of + * a GSS conversation. We also simulate tokens that are broken + * into pieces before handed to gss_accept_sec_context(). Each + * iteration of the loop optionally calls gss_init_sec_context() + * then optionally calls gss_accept_sec_context(). + */ + + while (!server_done || !client_done) { + num_loops++; + if (verbose_flag) + printf("loop #%d: input_token.length=%zu client_done=%d\n", + num_loops, input_token.length, client_done); + + /* + * First, we need to call gss_import_sec_context() if we are + * running through the loop the first time, or if we have been + * given a token (input_token) by gss_accept_sec_context(). + * We aren't going to be called every time because when we are + * using split tokens, we may need to call gss_accept_sec_context() + * multiple times because it receives an entire token. + */ + if ((num_loops == 1 || input_token.length > 0) && !client_done) { + gsskrb5_set_time_offset(client_time_offset); +#ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT + if (ei_ctx_flag && cctx_tok.length > 0) { + maj_stat = gss_import_sec_context(&min_stat, &cctx_tok, cctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import client context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + gss_release_buffer(&min_stat, &cctx_tok); + } +#endif + + maj_stat = gss_init_sec_context(&min_stat, init_cred, cctx, + gss_target_name, mechoid, + flags, 0, i_channel_bindings_p, + &input_token, &actual_mech_client, + &output_token, &ret_cflags, NULL); + if (GSS_ERROR(maj_stat)) + errx(1, "init_sec_context: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + client_done = !(maj_stat & GSS_S_CONTINUE_NEEDED); + + gss_release_buffer(&min_stat, &input_token); + input_token.length = 0; + input_token.value = NULL; + +#if DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT + if (!client_done && ei_ctx_flag) { + maj_stat = gss_export_sec_context(&min_stat, cctx, &cctx_tok); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export server context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + if (*cctx != GSS_C_NO_CONTEXT) + errx(1, "export client context did not release it"); + } +#endif + + if (verbose_flag) + printf("loop #%d: output_token.length=%zu\n", num_loops, + output_token.length); + + offset = 0; + } + + /* + * We now call gss_accept_sec_context(). To support split + * tokens, we keep track of the offset into the token that + * we have used and keep handing in chunks until we're done. + */ + + if (offset < output_token.length && !server_done) { + gss_buffer_desc tmp; + + gsskrb5_get_time_offset(&client_time_offset); + gsskrb5_set_time_offset(server_time_offset); + + if (output_token.length && ((uint8_t *)output_token.value)[0] == 0x60) { + tmp.length = output_token.length - offset; + if (token_split && tmp.length > token_split) + tmp.length = token_split; + tmp.value = (char *)output_token.value + offset; + } else + tmp = output_token; + + if (verbose_flag) + printf("loop #%d: accept offset=%zu len=%zu\n", num_loops, + offset, tmp.length); + + if (ei_ctx_flag && sctx_tok.length > 0) { + maj_stat = gss_import_sec_context(&min_stat, &sctx_tok, sctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import server context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + gss_release_buffer(&min_stat, &sctx_tok); + } + + maj_stat = gss_accept_sec_context(&min_stat, sctx, + GSS_C_NO_CREDENTIAL, &tmp, + a_channel_bindings_p, &src_name, + &actual_mech_server, + &input_token, &ret_sflags, + NULL, deleg_cred); + if (GSS_ERROR(maj_stat)) + errx(1, "accept_sec_context: %s", + gssapi_err(maj_stat, min_stat, actual_mech_server)); + offset += tmp.length; + if (maj_stat & GSS_S_CONTINUE_NEEDED) + gss_release_name(&min_stat, &src_name); + else + server_done = 1; + + if (ei_ctx_flag && !server_done) { + maj_stat = gss_export_sec_context(&min_stat, sctx, &sctx_tok); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export server context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + if (*sctx != GSS_C_NO_CONTEXT) + errx(1, "export server context did not release it"); + } + + gsskrb5_get_time_offset(&server_time_offset); + + if (output_token.length == offset) + gss_release_buffer(&min_stat, &output_token); + } + if (verbose_flag) + printf("loop #%d: end\n", num_loops); + } + if (output_token.length != 0) + gss_release_buffer(&min_stat, &output_token); + if (input_token.length != 0) + gss_release_buffer(&min_stat, &input_token); + gss_release_name(&min_stat, &gss_target_name); + + if (deleg_flag || policy_deleg_flag) { + if (server_no_deleg_flag) { + if (*deleg_cred != GSS_C_NO_CREDENTIAL) + errx(1, "got delegated cred but didn't expect one"); + } else if (*deleg_cred == GSS_C_NO_CREDENTIAL) + errx(1, "asked for delegarated cred but did get one"); + } else if (*deleg_cred != GSS_C_NO_CREDENTIAL) + errx(1, "got deleg_cred cred but didn't ask"); + + if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0) + errx(1, "mech mismatch"); + *actual_mech = actual_mech_server; + + if (on_behalf_of_string) { + gss_buffer_desc attr, value; + + attr.value = + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580"; + attr.length = + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data#580") - 1; + maj_stat = gss_get_name_attribute(&min_stat, src_name, &attr, NULL, + NULL, &value, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_get_name_attribute(authz-data#580) failed with %s", + gssapi_err(maj_stat, min_stat, GSS_KRB5_MECHANISM)); + + if (value.length != strlen(on_behalf_of_string) || + strncmp(value.value, on_behalf_of_string, + strlen(on_behalf_of_string)) != 0) + errx(1, "AD-ON-BEHALF-OF did not match"); + (void) gss_release_buffer(&min_stat, &value); + } + if (localname_string) { + gss_buffer_desc lname; + + maj_stat = gss_localname(&min_stat, src_name, GSS_C_NO_OID, &lname); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "localname: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + if (verbose_flag) + printf("localname: %.*s\n", (int)lname.length, + (char *)lname.value); + if (lname.length != strlen(localname_string) || + strncmp(localname_string, lname.value, lname.length) != 0) + errx(1, "localname: expected \"%s\", got \"%.*s\" (1)", + localname_string, (int)lname.length, (char *)lname.value); + gss_release_buffer(&min_stat, &lname); + maj_stat = gss_localname(&min_stat, src_name, actual_mech_server, + &lname); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "localname: %s", + gssapi_err(maj_stat, min_stat, actual_mech_server)); + if (lname.length != strlen(localname_string) || + strncmp(localname_string, lname.value, lname.length) != 0) + errx(1, "localname: expected \"%s\", got \"%.*s\" (2)", + localname_string, (int)lname.length, (char *)lname.value); + gss_release_buffer(&min_stat, &lname); + + if (!gss_userok(src_name, localname_string)) + errx(1, "localname is not userok"); + if (gss_userok(src_name, "nosuchuser:no")) + errx(1, "gss_userok() appears broken"); + } + if (verbose_flag) { + gss_buffer_desc iname; + + maj_stat = gss_display_name(&min_stat, src_name, &iname, NULL); + if (maj_stat == GSS_S_COMPLETE) { + printf("client name: %.*s\n", (int)iname.length, + (char *)iname.value); + gss_release_buffer(&min_stat, &iname); + } else + warnx("display_name: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + if (!anon_flag && + gss_oid_equal(actual_mech_server, GSS_KRB5_MECHANISM)) + show_pac_client_info(src_name); + } + gss_release_name(&min_stat, &src_name); + + if (max_loops && num_loops > max_loops) + errx(1, "num loops %d was lager then max loops %d", + num_loops, max_loops); + + if (verbose_flag) { + printf("server time offset: %d\n", server_time_offset); + printf("client time offset: %d\n", client_time_offset); + printf("num loops %d\n", num_loops); + printf("cflags: "); + if (ret_cflags & GSS_C_DELEG_FLAG) + printf("deleg "); + if (ret_cflags & GSS_C_MUTUAL_FLAG) + printf("mutual "); + if (ret_cflags & GSS_C_REPLAY_FLAG) + printf("replay "); + if (ret_cflags & GSS_C_SEQUENCE_FLAG) + printf("sequence "); + if (ret_cflags & GSS_C_CONF_FLAG) + printf("conf "); + if (ret_cflags & GSS_C_INTEG_FLAG) + printf("integ "); + if (ret_cflags & GSS_C_ANON_FLAG) + printf("anon "); + if (ret_cflags & GSS_C_PROT_READY_FLAG) + printf("prot-ready "); + if (ret_cflags & GSS_C_TRANS_FLAG) + printf("trans "); + if (ret_cflags & GSS_C_DCE_STYLE) + printf("dce-style "); + if (ret_cflags & GSS_C_IDENTIFY_FLAG) + printf("identify " ); + if (ret_cflags & GSS_C_EXTENDED_ERROR_FLAG) + printf("extended-error " ); + if (ret_cflags & GSS_C_DELEG_POLICY_FLAG) + printf("deleg-policy " ); + printf("\n"); + printf("sflags: "); + if (ret_sflags & GSS_C_CHANNEL_BOUND_FLAG) + printf("channel-bound " ); + printf("\n"); + } +} + +static void +wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +{ + gss_buffer_desc input_token, output_token, output_token2; + OM_uint32 min_stat, maj_stat; + gss_qop_t qop_state; + int conf_state; + + input_token.value = "foo"; + input_token.length = 3; + + maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token, + &conf_state, &output_token); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_wrap failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + maj_stat = gss_unwrap(&min_stat, sctx, &output_token, + &output_token2, &conf_state, &qop_state); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + gss_release_buffer(&min_stat, &output_token); + gss_release_buffer(&min_stat, &output_token2); + +#if 0 /* doesn't work for NTLM yet */ + if (!!conf_state != !!flags) + errx(1, "conf_state mismatch"); +#endif +} + +#define USE_CONF 1 +#define USE_HEADER_ONLY 2 +#define USE_SIGN_ONLY 4 +#define FORCE_IOV 8 +/* NO_DATA comes from ; we don't use it here; we appropriate it */ +#ifdef NO_DATA +#undef NO_DATA +#endif +#define NO_DATA 16 + +static void +wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +{ + krb5_data token, header, trailer; + OM_uint32 min_stat, maj_stat; + gss_qop_t qop_state; + int conf_state, conf_state2; + gss_iov_buffer_desc iov[6]; + unsigned char *p; + int iov_len; + char header_data[9] = "ABCheader"; + char trailer_data[10] = "trailerXYZ"; + + char token_data[16] = "0123456789abcdef"; + + memset(&iov, 0, sizeof(iov)); + + if (flags & USE_SIGN_ONLY) { + header.data = header_data; + header.length = 9; + trailer.data = trailer_data; + trailer.length = 10; + } else { + header.data = NULL; + header.length = 0; + trailer.data = NULL; + trailer.length = 0; + } + + token.data = token_data; + token.length = 16; + + iov_len = sizeof(iov)/sizeof(iov[0]); + + memset(iov, 0, sizeof(iov)); + + iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + + if (header.length != 0) { + iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[1].buffer.length = header.length; + iov[1].buffer.value = header.data; + } else { + iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[1].buffer.length = 0; + iov[1].buffer.value = NULL; + } + iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; + if (flags & NO_DATA) { + iov[2].buffer.length = 0; + } else { + iov[2].buffer.length = token.length; + } + iov[2].buffer.value = token.data; + if (trailer.length != 0) { + iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov[3].buffer.length = trailer.length; + iov[3].buffer.value = trailer.data; + } else { + iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[3].buffer.length = 0; + iov[3].buffer.value = NULL; + } + if (dce_style_flag) { + iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY; + } else { + iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_FLAG_ALLOCATE; + } + iov[4].buffer.length = 0; + iov[4].buffer.value = 0; + if (dce_style_flag) { + iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY; + } else if (flags & USE_HEADER_ONLY) { + iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY; + } else { + iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_FLAG_ALLOCATE; + } + iov[5].buffer.length = 0; + iov[5].buffer.value = 0; + + maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state, + iov, iov_len); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_wrap_iov failed"); + + token.length = + iov[0].buffer.length + + iov[1].buffer.length + + iov[2].buffer.length + + iov[3].buffer.length + + iov[4].buffer.length + + iov[5].buffer.length; + token.data = emalloc(token.length); + + p = token.data; + + if (iov[0].buffer.length) + memcpy(p, iov[0].buffer.value, iov[0].buffer.length); + p += iov[0].buffer.length; + + if (iov[1].buffer.length) + memcpy(p, iov[1].buffer.value, iov[1].buffer.length); + p += iov[1].buffer.length; + + if (iov[2].buffer.length) + memcpy(p, iov[2].buffer.value, iov[2].buffer.length); + p += iov[2].buffer.length; + + if (iov[3].buffer.length) + memcpy(p, iov[3].buffer.value, iov[3].buffer.length); + p += iov[3].buffer.length; + + if (iov[4].buffer.length) + memcpy(p, iov[4].buffer.value, iov[4].buffer.length); + p += iov[4].buffer.length; + + if (iov[5].buffer.length) + memcpy(p, iov[5].buffer.value, iov[5].buffer.length); + p += iov[5].buffer.length; + + assert(p - ((unsigned char *)token.data) == token.length); + + if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) { + gss_buffer_desc input, output; + + input.value = token.data; + input.length = token.length; + + maj_stat = gss_unwrap(&min_stat, sctx, &input, + &output, &conf_state2, &qop_state); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap from gss_wrap_iov failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + gss_release_buffer(&min_stat, &output); + } else { + maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state, + iov, iov_len); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap_iov failed: %x %s", flags, + gssapi_err(maj_stat, min_stat, mechoid)); + + } + if (conf_state2 != conf_state) + errx(1, "conf state wrong for iov: %x", flags); + + gss_release_iov_buffer(&min_stat, iov, iov_len); + + free(token.data); +} + +static void +wrapunwrap_aead(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +{ + gss_buffer_desc token, assoc, message = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output; + OM_uint32 min_stat, maj_stat; + gss_qop_t qop_state; + int conf_state, conf_state2; + char assoc_data[9] = "ABCheader"; + char token_data[16] = "0123456789abcdef"; + + if (flags & USE_SIGN_ONLY) { + assoc.value = assoc_data; + assoc.length = 9; + } else { + assoc.value = NULL; + assoc.length = 0; + } + + token.value = token_data; + token.length = 16; + + maj_stat = gss_wrap_aead(&min_stat, cctx, dce_style_flag || flags & USE_CONF, + GSS_C_QOP_DEFAULT, &assoc, &token, + &conf_state, &message); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_wrap_aead failed"); + + if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) { + maj_stat = gss_unwrap(&min_stat, sctx, &message, + &output, &conf_state2, &qop_state); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap from gss_wrap_aead failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + } else { + maj_stat = gss_unwrap_aead(&min_stat, sctx, &message, &assoc, + &output, &conf_state2, &qop_state); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap_aead failed: %x %s", flags, + gssapi_err(maj_stat, min_stat, mechoid)); + } + + if (output.length != token.length) + errx(1, "plaintext length wrong for aead"); + else if (memcmp(output.value, token.value, token.length) != 0) + errx(1, "plaintext wrong for aead"); + if (conf_state2 != conf_state) + errx(1, "conf state wrong for aead: %x", flags); + + gss_release_buffer(&min_stat, &message); + gss_release_buffer(&min_stat, &output); +} + +static void +getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid) +{ + gss_buffer_desc input_token, output_token; + OM_uint32 min_stat, maj_stat; + gss_qop_t qop_state; + + input_token.value = "bar"; + input_token.length = 3; + + maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token, + &output_token); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_get_mic failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + maj_stat = gss_verify_mic(&min_stat, sctx, &input_token, + &output_token, &qop_state); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_verify_mic failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + gss_release_buffer(&min_stat, &output_token); +} + +static void +empty_release(void) +{ + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + gss_name_t name = GSS_C_NO_NAME; + gss_OID_set oidset = GSS_C_NO_OID_SET; + OM_uint32 junk; + + gss_delete_sec_context(&junk, &ctx, NULL); + gss_release_cred(&junk, &cred); + gss_release_name(&junk, &name); + gss_release_oid_set(&junk, &oidset); +} + +/* + * + */ + +static struct getargs args[] = { + {"name-type",0, arg_string, &type_string, "type of name", NULL }, + {"mech-type",0, arg_string, &mech_string, "mech type (name)", NULL }, + {"mech-types",0, arg_string, &mechs_string, "mech types (names)", NULL }, + {"ret-mech-type",0, arg_string, &ret_mech_string, + "type of return mech", NULL }, + {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag, + "use dns to canonicalize", NULL }, + {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL }, + {"client-ccache",0, arg_string, &client_ccache, "client credentials cache", NULL }, + {"client-keytab",0, arg_string, &client_keytab, "client keytab", NULL }, + {"client-name", 0, arg_string, &client_name, "client name", NULL }, + {"client-password", 0, arg_string, &client_password, "client password", NULL }, + {"anonymous", 0, arg_flag, &anon_flag, "anonymous auth", NULL }, + {"i-channel-bindings", 0, arg_string, &i_channel_bindings, "initiator channel binding data", NULL }, + {"a-channel-bindings", 0, arg_string, &a_channel_bindings, "acceptor channel binding data", NULL }, + {"limit-enctype",0, arg_string, &limit_enctype_string, "enctype", NULL }, + {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL }, + {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL }, + {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL }, + {"aead", 0, arg_flag, &aead_flag, "wrap/unwrap aead", NULL }, + {"getverifymic",0, arg_flag, &getverifymic_flag, + "get and verify mic", NULL }, + {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL }, + {"policy-delegate",0, arg_flag, &policy_deleg_flag, "policy delegate credential", NULL }, + {"server-no-delegate",0, arg_flag, &server_no_deleg_flag, + "server should get a credential", NULL }, + {"export-import-context",0, arg_flag, &ei_ctx_flag, "test export/import context", NULL }, + {"export-import-cred",0, arg_flag, &ei_cred_flag, "test export/import cred", NULL }, + {"localname",0, arg_string, &localname_string, "expected localname for client", "USERNAME"}, + {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL }, + {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL }, + {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL }, + {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL }, + {"max-loops", 0, arg_integer, &max_loops, "time", NULL }, + {"token-split", 0, arg_integer, &token_split, "bytes", NULL }, + {"on-behalf-of", 0, arg_string, &on_behalf_of_string, "principal", + "send authenticator authz-data AD-ON-BEHALF-OF" }, + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + OM_uint32 min_stat, maj_stat; + gss_ctx_id_t cctx, sctx; + void *ctx; + gss_OID nameoid, mechoid, actual_mech, actual_mech2; + gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL; + gss_name_t cname = GSS_C_NO_NAME; + gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER; + gss_OID_desc oids[7]; + gss_OID_set_desc mechoid_descs; + gss_OID_set mechoids = GSS_C_NO_OID_SET; + gss_key_value_element_desc client_cred_elements[2]; + gss_key_value_set_desc client_cred_store; + gss_OID_set actual_mechs = GSS_C_NO_OID_SET; + + setprogname(argv[0]); + + if (krb5_init_context(&context)) + errx(1, "krb5_init_context"); + + cctx = sctx = GSS_C_NO_CONTEXT; + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc != 1) + usage(1); + + if (dns_canon_flag != -1) + gsskrb5_set_dns_canonicalize(dns_canon_flag); + + if (type_string == NULL) + nameoid = GSS_C_NT_HOSTBASED_SERVICE; + else if (strcmp(type_string, "hostbased-service") == 0) + nameoid = GSS_C_NT_HOSTBASED_SERVICE; + else if (strcmp(type_string, "krb5-principal-name") == 0) + nameoid = GSS_KRB5_NT_PRINCIPAL_NAME; + else + errx(1, "%s not supported", type_string); + + if (mech_string == NULL) + mechoid = GSS_KRB5_MECHANISM; + else + mechoid = string_to_oid(mech_string); + + if (mechs_string == NULL) { + /* + * We ought to be able to use the OID set of the one mechanism + * OID given. But there's some breakage that conspires to make + * that fail though it should succeed: + * + * - the NTLM gss_acquire_cred() refuses to work with + * desired_name == GSS_C_NO_NAME + * - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET + * does work here because we happen to have Kerberos + * credentials in check-ntlm, and the subsequent + * gss_init_sec_context() call finds no cred element for NTLM + * but plows on anyways, surprisingly enough, and then the + * NTLM gss_init_sec_context() just works. + * + * In summary, there's some breakage in gss_init_sec_context() + * and some breakage in NTLM that conspires against us here. + * + * We work around this in check-ntlm and check-spnego by adding + * --client-name=user1@${R} to the invocations of this test + * program that require it. + */ + oids[0] = *mechoid; + mechoid_descs.elements = &oids[0]; + mechoid_descs.count = 1; + mechoids = &mechoid_descs; + } else { + string_to_oids(&mechoids, mechs_string); + } + + if (gsskrb5_acceptor_identity) { + /* XXX replace this with cred store, but test suites will need work */ + maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity); + if (maj_stat) + errx(1, "gsskrb5_acceptor_identity: %s", + gssapi_err(maj_stat, 0, GSS_C_NO_OID)); + } + + if (client_password && (client_ccache || client_keytab)) { + errx(1, "password option mutually exclusive with ccache or keytab option"); + } + + if (client_password) { + credential_data.value = client_password; + credential_data.length = strlen(client_password); + } + + client_cred_store.count = 0; + client_cred_store.elements = client_cred_elements; + + if (client_ccache) { + client_cred_store.elements[client_cred_store.count].key = "ccache"; + client_cred_store.elements[client_cred_store.count].value = client_ccache; + + client_cred_store.count++; + } + + if (client_keytab) { + client_cred_store.elements[client_cred_store.count].key = "client_keytab"; + client_cred_store.elements[client_cred_store.count].value = client_keytab; + + client_cred_store.count++; + } + + if (client_name) { + gss_buffer_desc cn; + + cn.value = client_name; + cn.length = strlen(client_name); + + maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname); + if (maj_stat) + errx(1, "gss_import_name: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + if (client_password) { + maj_stat = gss_acquire_cred_with_password(&min_stat, + cname, + &credential_data, + GSS_C_INDEFINITE, + mechoids, + GSS_C_INITIATE, + &client_cred, + &actual_mechs, + NULL); + if (GSS_ERROR(maj_stat)) { + if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1) + mechoid = &mechoids->elements[0]; + else + mechoid = GSS_C_NO_OID; + errx(1, "gss_acquire_cred_with_password: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + } + } else { + maj_stat = gss_acquire_cred_from(&min_stat, + cname, + GSS_C_INDEFINITE, + mechoids, + GSS_C_INITIATE, + client_cred_store.count ? &client_cred_store + : GSS_C_NO_CRED_STORE, + &client_cred, + &actual_mechs, + NULL); + if (GSS_ERROR(maj_stat) && !anon_flag) + errx(1, "gss_acquire_cred: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + gss_release_name(&min_stat, &cname); + + if (verbose_flag) { + size_t i; + + printf("cred mechs:"); + for (i = 0; i < actual_mechs->count; i++) + printf(" %s", gss_oid_to_name(&actual_mechs->elements[i])); + printf("\n"); + } + + if (gss_oid_equal(mechoid, GSS_SPNEGO_MECHANISM) && mechs_string) { + maj_stat = gss_set_neg_mechs(&min_stat, client_cred, mechoids); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_set_neg_mechs: %s", + gssapi_err(maj_stat, min_stat, GSS_SPNEGO_MECHANISM)); + + mechoid_descs.elements = GSS_SPNEGO_MECHANISM; + mechoid_descs.count = 1; + mechoids = &mechoid_descs; + } + + if (ei_cred_flag) { + gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL; + gss_buffer_desc cb; + + maj_stat = gss_export_cred(&min_stat, client_cred, &cb); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export cred failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + maj_stat = gss_import_cred(&min_stat, &cb, &cred2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import cred failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + gss_release_buffer(&min_stat, &cb); + gss_release_cred(&min_stat, &client_cred); + client_cred = cred2; + } + + if (limit_enctype_string) { + krb5_error_code ret; + + ret = krb5_string_to_enctype(context, + limit_enctype_string, + &limit_enctype); + if (ret) + krb5_err(context, 1, ret, "krb5_string_to_enctype"); + } + + + if (limit_enctype) { + if (client_cred == NULL) + errx(1, "client_cred missing"); + + maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred, + 1, &limit_enctype); + if (maj_stat) + errx(1, "gss_krb5_set_allowable_enctypes: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + } + + loop(mechoid, nameoid, argv[0], client_cred, + &sctx, &cctx, &actual_mech, &deleg_cred); + + if (verbose_flag) + printf("resulting mech: %s\n", gss_oid_to_name(actual_mech)); + + if (ret_mech_string) { + gss_OID retoid; + + retoid = string_to_oid(ret_mech_string); + + if (gss_oid_equal(retoid, actual_mech) == 0) + errx(1, "actual_mech mech is not the expected type %s", + ret_mech_string); + } + + /* XXX should be actual_mech */ + if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { + time_t sc_time; + gss_buffer_desc authz_data; + gss_buffer_desc in, out1, out2; + krb5_keyblock *keyblock, *keyblock2; + krb5_timestamp now; + krb5_error_code ret; + + ret = krb5_timeofday(context, &now); + if (ret) + errx(1, "krb5_timeofday failed"); + + /* client */ + maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, + &cctx, + 1, /* version */ + &ctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_export_lucid_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + + maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_free_lucid_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + /* server */ + maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, + &sctx, + 1, /* version */ + &ctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_export_lucid_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_free_lucid_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat, + sctx, + &sc_time); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + if (sc_time > now) + errx(1, "gsskrb5_extract_authtime_from_sec_context failed: " + "time authtime is before now: %ld %ld", + (long)sc_time, (long)now); + + maj_stat = gsskrb5_extract_service_keyblock(&min_stat, + sctx, + &keyblock); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gsskrb5_export_service_keyblock failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + krb5_free_keyblock(context, keyblock); + + maj_stat = gsskrb5_get_subkey(&min_stat, + sctx, + &keyblock); + if (maj_stat != GSS_S_COMPLETE + && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) + errx(1, "gsskrb5_get_subkey server failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + if (maj_stat != GSS_S_COMPLETE) + keyblock = NULL; + else if (limit_enctype && keyblock->keytype != limit_enctype) + errx(1, "gsskrb5_get_subkey wrong enctype"); + + maj_stat = gsskrb5_get_subkey(&min_stat, + cctx, + &keyblock2); + if (maj_stat != GSS_S_COMPLETE + && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) + errx(1, "gsskrb5_get_subkey client failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + if (maj_stat != GSS_S_COMPLETE) + keyblock2 = NULL; + else if (limit_enctype && keyblock && keyblock->keytype != limit_enctype) + errx(1, "gsskrb5_get_subkey wrong enctype"); + + if (keyblock || keyblock2) { + if (keyblock == NULL) + errx(1, "server missing token keyblock"); + if (keyblock2 == NULL) + errx(1, "client missing token keyblock"); + + if (keyblock->keytype != keyblock2->keytype) + errx(1, "enctype mismatch"); + if (keyblock->keyvalue.length != keyblock2->keyvalue.length) + errx(1, "key length mismatch"); + if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data, + keyblock2->keyvalue.length) != 0) + errx(1, "key data mismatch"); + } + + if (session_enctype_string) { + krb5_enctype enctype; + + ret = krb5_string_to_enctype(context, + session_enctype_string, + &enctype); + + if (ret) + krb5_err(context, 1, ret, "krb5_string_to_enctype"); + + if (keyblock && enctype != keyblock->keytype) + errx(1, "keytype is not the expected %d != %d", + (int)enctype, (int)keyblock2->keytype); + } + + if (keyblock) + krb5_free_keyblock(context, keyblock); + if (keyblock2) + krb5_free_keyblock(context, keyblock2); + + maj_stat = gsskrb5_get_initiator_subkey(&min_stat, + sctx, + &keyblock); + if (maj_stat != GSS_S_COMPLETE + && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY))) + errx(1, "gsskrb5_get_initiator_subkey failed: %s", + gssapi_err(maj_stat, min_stat, actual_mech)); + + if (maj_stat == GSS_S_COMPLETE) { + + if (limit_enctype && keyblock->keytype != limit_enctype) + errx(1, "gsskrb5_get_initiator_subkey wrong enctype"); + krb5_free_keyblock(context, keyblock); + } + + maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, + sctx, + 128, + &authz_data); + if (maj_stat == GSS_S_COMPLETE) + gss_release_buffer(&min_stat, &authz_data); + + + memset(&out1, 0, sizeof(out1)); + memset(&out2, 0, sizeof(out2)); + + in.value = "foo"; + in.length = 3; + + gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, + 100, &out1); + gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in, + 100, &out2); + + if (out1.length != out2.length) + errx(1, "prf len mismatch"); + if (out1.length && memcmp(out1.value, out2.value, out1.length) != 0) + errx(1, "prf data mismatch"); + + gss_release_buffer(&min_stat, &out1); + + gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, + 100, &out1); + + if (out1.length != out2.length) + errx(1, "prf len mismatch"); + if (out1.length && memcmp(out1.value, out2.value, out1.length) != 0) + errx(1, "prf data mismatch"); + + gss_release_buffer(&min_stat, &out1); + gss_release_buffer(&min_stat, &out2); + + in.value = "bar"; + in.length = 3; + + gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in, + 100, &out1); + gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in, + 100, &out2); + + if (out1.length != out2.length) + errx(1, "prf len mismatch"); + if (memcmp(out1.value, out2.value, out1.length) != 0) + errx(1, "prf data mismatch"); + + gss_release_buffer(&min_stat, &out1); + gss_release_buffer(&min_stat, &out2); + + wrapunwrap_flag = 1; + getverifymic_flag = 1; + } + + if (ei_ctx_flag) { + gss_buffer_desc ctx_token = GSS_C_EMPTY_BUFFER; + + maj_stat = gss_export_sec_context(&min_stat, &cctx, &ctx_token); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export client context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + if (cctx != GSS_C_NO_CONTEXT) + errx(1, "export client context did not release it"); + + maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &cctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import client context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + gss_release_buffer(&min_stat, &ctx_token); + + maj_stat = gss_export_sec_context(&min_stat, &sctx, &ctx_token); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export server context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + if (sctx != GSS_C_NO_CONTEXT) + errx(1, "export server context did not release it"); + + maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &sctx); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import server context failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + gss_release_buffer(&min_stat, &ctx_token); + } + + if (wrapunwrap_flag) { + wrapunwrap(cctx, sctx, 0, actual_mech); + wrapunwrap(cctx, sctx, 1, actual_mech); + wrapunwrap(sctx, cctx, 0, actual_mech); + wrapunwrap(sctx, cctx, 1, actual_mech); + } + + if (iov_flag) { + wrapunwrap_iov(cctx, sctx, 0, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech); + + wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + +/* works */ + wrapunwrap_iov(cctx, sctx, 0, actual_mech); + wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + /* works */ + wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech); + wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + } + + if (aead_flag) { + wrapunwrap_aead(cctx, sctx, 0, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech); + + wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, 0, actual_mech); + wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech); + + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech); + wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech); + } + + if (getverifymic_flag) { + getverifymic(cctx, sctx, actual_mech); + getverifymic(cctx, sctx, actual_mech); + getverifymic(sctx, cctx, actual_mech); + getverifymic(sctx, cctx, actual_mech); + } + + gss_delete_sec_context(&min_stat, &cctx, NULL); + gss_delete_sec_context(&min_stat, &sctx, NULL); + + if (deleg_cred != GSS_C_NO_CREDENTIAL) { + gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL; + gss_buffer_desc cb; + + if (verbose_flag) + printf("checking actual mech (%s) on delegated cred\n", + gss_oid_to_name(actual_mech)); + loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2); + + gss_delete_sec_context(&min_stat, &cctx, NULL); + gss_delete_sec_context(&min_stat, &sctx, NULL); + + gss_release_cred(&min_stat, &cred2); + +#if 0 + /* + * XXX We can't do this. Delegated credentials only work with + * the actual_mech. We could gss_store_cred the delegated + * credentials *then* gss_add/acquire_cred() with SPNEGO, then + * we could try loop() with those credentials. + */ + /* try again using SPNEGO */ + if (verbose_flag) + printf("checking spnego on delegated cred\n"); + loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx, + &actual_mech2, &cred2); + + gss_delete_sec_context(&min_stat, &cctx, NULL); + gss_delete_sec_context(&min_stat, &sctx, NULL); + + gss_release_cred(&min_stat, &cred2); +#endif + + /* check export/import */ + if (ei_cred_flag) { + + maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "export cred failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + maj_stat = gss_import_cred(&min_stat, &cb, &cred2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import cred failed: %s", + gssapi_err(maj_stat, min_stat, NULL)); + + gss_release_buffer(&min_stat, &cb); + gss_release_cred(&min_stat, &deleg_cred); + + if (verbose_flag) + printf("checking actual mech (%s) on export/imported cred\n", + gss_oid_to_name(actual_mech)); + loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx, + &actual_mech2, &deleg_cred); + + gss_release_cred(&min_stat, &deleg_cred); + + gss_delete_sec_context(&min_stat, &cctx, NULL); + gss_delete_sec_context(&min_stat, &sctx, NULL); + +#if 0 + /* XXX See above */ + /* try again using SPNEGO */ + if (verbose_flag) + printf("checking SPNEGO on export/imported cred\n"); + loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx, + &actual_mech2, &deleg_cred); + + gss_release_cred(&min_stat, &deleg_cred); + + gss_delete_sec_context(&min_stat, &cctx, NULL); + gss_delete_sec_context(&min_stat, &sctx, NULL); +#endif + + gss_release_cred(&min_stat, &cred2); + + } else { + gss_release_cred(&min_stat, &deleg_cred); + } + + } + + gss_release_cred(&min_stat, &client_cred); + gss_release_oid_set(&min_stat, &actual_mechs); + if (mechoids != GSS_C_NO_OID_SET && mechoids != &mechoid_descs) + gss_release_oid_set(&min_stat, &mechoids); + empty_release(); + + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/test_cred.c b/third_party/heimdal/lib/gssapi/test_cred.c new file mode 100644 index 0000000..9eaabda --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_cred.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int anon_flag = 0; + +static void +gss_print_errors (int min_stat) +{ + OM_uint32 new_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + OM_uint32 ret; + + do { + ret = gss_display_status (&new_stat, + min_stat, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if (!GSS_ERROR(ret)) { + fprintf (stderr, "%.*s\n", (int)status_string.length, + (char *)status_string.value); + gss_release_buffer (&new_stat, &status_string); + } + } while (!GSS_ERROR(ret) && msg_ctx != 0); +} + +static void +gss_err(int exitval, int status, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx (fmt, args); + gss_print_errors (status); + va_end(args); + exit (exitval); +} + +static void +acquire_release_loop(gss_name_t name, int counter, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred; + int i; + + for (i = 0; i < counter; i++) { + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + } +} + + +static void +acquire_add_release_add(gss_name_t name, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred, cred2, cred3; + gss_OID mech_oid = anon_flag ? GSS_SANON_X25519_MECHANISM : GSS_KRB5_MECHANISM; + + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred, + GSS_C_NO_NAME, + mech_oid, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred2, + NULL, + NULL, + NULL); + + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred2, + GSS_C_NO_NAME, + mech_oid, + GSS_C_BOTH, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred3, + NULL, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred 2 %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred2); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred3); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 3 %d != GSS_S_COMPLETE", (int)maj_stat); +} + +static int version_flag = 0; +static int help_flag = 0; + +static struct getargs args[] = { + {"anonymous", 0, arg_flag, &anon_flag, "try anonymous creds", NULL }, + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + + +int +main(int argc, char **argv) +{ + struct gss_buffer_desc_struct name_buffer; + OM_uint32 maj_stat, min_stat; + gss_name_t name; + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc < 1) + errx(1, "argc < 1"); + + name_buffer.value = argv[0]; + name_buffer.length = strlen(argv[0]); + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import name error"); + + acquire_release_loop(name, 100, GSS_C_ACCEPT); + acquire_release_loop(name, 100, GSS_C_INITIATE); + acquire_release_loop(name, 100, GSS_C_BOTH); + + acquire_add_release_add(name, GSS_C_ACCEPT); + acquire_add_release_add(name, GSS_C_INITIATE); + acquire_add_release_add(name, GSS_C_BOTH); + + gss_release_name(&min_stat, &name); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/test_kcred.c b/third_party/heimdal/lib/gssapi/test_kcred.c new file mode 100644 index 0000000..abfe390 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_kcred.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int version_flag = 0; +static int help_flag = 0; + +static void +copy_import(void) +{ + gss_cred_id_t cred1, cred2; + OM_uint32 maj_stat, min_stat; + gss_name_t name1, name2; + OM_uint32 lifetime1, lifetime2; + gss_cred_usage_t usage1, usage2; + gss_OID_set mechs1, mechs2; + krb5_ccache id; + krb5_error_code ret; + krb5_context context; + int equal; + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_INITIATE, + &cred1, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_acquire_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred1, &name1, &lifetime1, + &usage1, &mechs1); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred"); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context"); + + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_new_unique"); + + maj_stat = gss_krb5_copy_ccache(&min_stat, cred1, id); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_copy_ccache"); + + maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &cred2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_import_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2, + &usage2, &mechs2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred 2"); + + maj_stat = gss_compare_name(&min_stat, name1, name2, &equal); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_compare_name"); + if (!equal) + errx(1, "names not equal"); + + /* + * This check is racy! It tends to fail when run with valgrind. + * + * make check-valgrind sets TESTS_ENVIRONMENT in the environment... + */ + if (getenv("TESTS_ENVIRONMENT") == NULL && lifetime1 != lifetime2) + errx(1, "lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); + if (lifetime1 != lifetime2) + warnx("lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); + + if (usage1 != usage2) { + /* as long any of them is both are everything it ok */ + if (usage1 != GSS_C_BOTH && usage2 != GSS_C_BOTH) + errx(1, "usages disjoined"); + } + + gss_release_name(&min_stat, &name2); + gss_release_oid_set(&min_stat, &mechs2); + + maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2, + &usage2, &mechs2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred"); + + maj_stat = gss_compare_name(&min_stat, name1, name2, &equal); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_compare_name"); + if (!equal) + errx(1, "names not equal"); + + /* This check is racy! */ + if (getenv("TESTS_ENVIRONMENT") == NULL && lifetime1 != lifetime2) + errx(1, "lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); + if (lifetime1 != lifetime2) + warnx("lifetime not equal %lu != %lu", + (unsigned long)lifetime1, (unsigned long)lifetime2); + + gss_release_cred(&min_stat, &cred1); + gss_release_cred(&min_stat, &cred2); + + gss_release_name(&min_stat, &name1); + gss_release_name(&min_stat, &name2); + +#if 0 + compare(mechs1, mechs2); +#endif + + gss_release_oid_set(&min_stat, &mechs1); + gss_release_oid_set(&min_stat, &mechs2); + + krb5_cc_destroy(context, id); + krb5_free_context(context); +} + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + copy_import(); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/test_names.c b/third_party/heimdal/lib/gssapi/test_names.c new file mode 100644 index 0000000..933635e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_names.c @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void make_composite_name(CompositePrincipal *, gss_name_t *); +static void assert_attr(gss_name_t, const char *, OM_uint32, gss_buffer_t, + const char *, int, int, int); +static void assert_attr_unavail(gss_name_t, const char *); +static void assert_attr_set(gss_name_t, gss_buffer_set_t); + +static void +gss_print_errors(OM_uint32 stat, gss_OID mech) +{ + OM_uint32 junk; + OM_uint32 more = 0; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + OM_uint32 ret; + + if (mech) { + junk = gss_oid_to_str(&junk, mech, &buf); + if (junk == GSS_S_COMPLETE) + fprintf(stderr, "mech = %.*s\n", (int)buf.length, (char *)buf.value); + gss_release_buffer(&junk, &buf); + } + do { + ret = gss_display_status(&junk, + stat, + mech ? GSS_C_MECH_CODE : GSS_C_GSS_CODE, + mech, + &more, + &buf); + if (ret != GSS_S_COMPLETE) + errx(1, "gss_display_status() failed"); + fprintf(stderr, "%.*s\n", (int)buf.length, (char *)buf.value); + gss_release_buffer(&junk, &buf); + } while (more); +} + +static void + __attribute__ ((__format__ (__printf__, 5, 6))) +gss_err(int exitval, + OM_uint32 maj, + OM_uint32 min, + gss_OID mech, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx(fmt, args); + va_end(args); + gss_print_errors(maj, GSS_C_NO_OID); + if (mech) + gss_print_errors(min, mech); + exit(exitval); +} + +#define MAKE_URN(tail) \ + { sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN tail) - 1, \ + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN tail } + +/* + * Test RFC6680 name attributes for Kerberos. + */ +static void +check_name_attrs(void) +{ + CompositePrincipal p; + EncTicketPart *t; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_name_t n; + OM_uint32 maj, min; + int32_t ret; + gss_buffer_desc attrs[] = { + MAKE_URN("realm"), + MAKE_URN("name-ncomp"), + MAKE_URN("name-ncomp#0"), + MAKE_URN("peer-realm"), + MAKE_URN("ticket-authz-data"), + MAKE_URN("transit-path"), + MAKE_URN("canonical-name"), + }; /* Set of attributes we expect to see indicated */ + gss_buffer_set_desc attr_set; + size_t i, sz; + + memset(&p, 0, sizeof(p)); + attr_set.elements = attrs; + /* + * attr_set.count is set in each of the following sections to ever more + * items. + */ + + /* + * Testing name attributes is pretty tricky. + * + * Our approach is to construct a composite name, construct an exported + * composite name token for it, import it, then test the gss_inquire_name() + * and gss_get_name_attribute() accessors, and then gss_display_name_ext(). + * + * Ideally we'd test the accessors on names imported from query forms with + * gss_import_name(), and on names from established contexts. However, + * that belongs in the test_context program. + * + * TODO: Implement and test gss_set_name_attribute() and + * gss_delete_name_attribute(). + */ + + /* First construct and test an unauthenticated name */ + p.realm = estrdup("TEST.H5L.SE"); + p.name.name_type = KRB5_NT_PRINCIPAL; + p.name.name_string.val = ecalloc(1, sizeof(p.name.name_string.val[0])); + p.name.name_string.len = 1; + p.name.name_string.val[0] = estrdup("someuser"); + p.nameattrs = NULL; + make_composite_name(&p, &n); + + /* Test the attributes we expect it to have */ + v.length = sizeof("TEST.H5L.SE") - 1; + v.value = "TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "realm", GSS_S_COMPLETE, + &v, "TEST.H5L.SE", 0, 1, 0); + + i = 1; + v.length = sizeof(size_t); + v.value = &i; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp", + GSS_S_COMPLETE, &v, "1", 0, 1, 0); + + v.length = sizeof("someuser") - 1; + v.value = "someuser"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#0", + GSS_S_COMPLETE, &v, "someuser", 0, 1, 0); + + attr_set.count = 3; + assert_attr_set(n, &attr_set); + + /* Check that it does not have prefixed attributes */ + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "realm"); + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp"); + assert_attr_unavail(n, "whatever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp#0"); + assert_attr_unavail(n, "what ever " GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "name-ncomp#0"); + + /* Check that it does not have various other supported attributes */ + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "peer-realm"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#1"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "canonical-name"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "ticket-authz-data#pac"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "ticket-authz-data"); + assert_attr_unavail(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "transit-path"); + + /* Exercise URN parser */ + assert_attr_unavail(n, "urn:whatever"); + assert_attr_unavail(n, "urn:whatever#"); + assert_attr_unavail(n, "urn:what#ever"); + assert_attr_unavail(n, "#"); + assert_attr_unavail(n, "#whatever"); + assert_attr_unavail(n, "whatever"); + assert_attr_unavail(n, "what ever"); + assert_attr_unavail(n, "what ever#"); + + /* Now test an authenticated name */ + gss_release_name(&min, &n); + p.nameattrs = ecalloc(1, sizeof(p.nameattrs[0])); + p.nameattrs->authenticated = 1; + make_composite_name(&p, &n); + + v.length = sizeof("TEST.H5L.SE") - 1; + v.value = "TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "realm", GSS_S_COMPLETE, + &v, "TEST.H5L.SE", 1, 1, 0); + + i = 1; + v.length = sizeof(size_t); + v.value = &i; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp", + GSS_S_COMPLETE, &v, "1", 1, 1, 0); + + v.length = sizeof("someuser") - 1; + v.value = "someuser"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp#0", + GSS_S_COMPLETE, &v, "someuser", 1, 1, 0); + + assert_attr_set(n, &attr_set); + + /* Now add a peer realm */ + gss_release_name(&min, &n); + p.nameattrs->peer_realm = ecalloc(1, sizeof(p.nameattrs->peer_realm[0])); + p.nameattrs->peer_realm[0] = estrdup("FOO.TEST.H5L.SE"); + make_composite_name(&p, &n); + + v.length = sizeof("FOO.TEST.H5L.SE") - 1; + v.value = "FOO.TEST.H5L.SE"; + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "peer-realm", + GSS_S_COMPLETE, &v, "FOO.TEST.H5L.SE", 1, 1, 0); + attr_set.count = 4; + assert_attr_set(n, &attr_set); + + /* Now add canonical name and an authz-data element */ + gss_release_name(&min, &n); + p.nameattrs->source = ecalloc(1, sizeof(p.nameattrs->source[0])); + p.nameattrs->source->element = choice_PrincipalNameAttrSrc_enc_ticket_part; + + t = &p.nameattrs->source->u.enc_ticket_part; + t->cname.name_type = KRB5_NT_PRINCIPAL; + t->cname.name_string.val = ecalloc(1, sizeof(t->cname.name_string.val[0])); + t->crealm = estrdup("TEST.H5L.SE"); + t->cname.name_string.len = 1; + t->cname.name_string.val[0] = estrdup("realusername"); + t->authorization_data = ecalloc(1, sizeof(t->authorization_data[0])); + t->authorization_data->val = + ecalloc(1, sizeof(t->authorization_data->val[0])); + t->authorization_data->len = 1; + t->authorization_data->val[0].ad_type = + KRB5_AUTHDATA_ON_BEHALF_OF; /* whatever */ + t->authorization_data->val[0].ad_data.data = + estrdup("foobar@TEST.H5L.SE"); + t->authorization_data->val[0].ad_data.length = + sizeof("foobar@TEST.H5L.SE") - 1; + make_composite_name(&p, &n); + + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "canonical-name", + GSS_S_COMPLETE, GSS_C_NO_BUFFER, "realusername@TEST.H5L.SE", 1, + 1, 0); + + ASN1_MALLOC_ENCODE(AuthorizationData, v.value, v.length, + t->authorization_data, &sz, ret); + if (ret) + errx(1, "Failed to encode AuthorizationData"); + + assert_attr(n, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "ticket-authz-data", + GSS_S_COMPLETE, &v, NULL, 0, 1, 0); + free(v.value); + + attr_set.count = 7; + assert_attr_set(n, &attr_set); + + gss_release_name(&min, &n); + free_CompositePrincipal(&p); + + /* + * Test gss_display_name_ext() with a host-based service principal + * "host/somehost.test.h5l.se@TEST.H5L.SE". + * + * Where gss_display_name() would display this as a Kerberos principal + * name, gss_display_name_ext() with GSS_C_NT_HOSTBASED_SERVICE should + * display it as "host@somehost.test.h5l.se". + */ + p.realm = estrdup("TEST.H5L.SE"); + p.name.name_type = KRB5_NT_SRV_HST; + p.name.name_string.val = ecalloc(2, sizeof(p.name.name_string.val[0])); + p.name.name_string.len = 2; + p.name.name_string.val[0] = estrdup("host"); + p.name.name_string.val[1] = estrdup("somehost.test.h5l.se"); + p.nameattrs = NULL; + make_composite_name(&p, &n); + + maj = gss_display_name_ext(&min, n, GSS_C_NT_HOSTBASED_SERVICE, &v); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "display name ext"); + if (v.length != sizeof("host@somehost.test.h5l.se") - 1 || + strncmp(v.value, "host@somehost.test.h5l.se", v.length) != 0) + errx(1, "display name ext"); + gss_release_buffer(&min, &v); + gss_release_name(&min, &n); + free_CompositePrincipal(&p); + + /* + * TODO: + * + * - test URN fragments for access to specific authorization data element + * types + * - test GSS_C_ATTR_LOCAL_LOGIN_USER support (requires configuration or + * that we register a plugin here) + */ +} + +static int version_flag = 0; +static int help_flag = 0; +static int anon_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"anonymous", 0, arg_flag, &anon_flag, "test anonymous names", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + + +int +main(int argc, char **argv) +{ + gss_buffer_desc name_buffer; + OM_uint32 maj_stat, min_stat; + gss_name_t name, MNname, MNname2; + int optidx = 0; + char *str; + int len, equal; + gss_OID mech_oid; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + gsskrb5_set_default_realm("MIT.EDU"); + + /* + * test import/export + */ + + str = NULL; + len = asprintf(&str, anon_flag ? + "WELLKNOWN@ANONYMOUS" : "ftp@freeze-arrow.mit.edu"); + if (len < 0 || str == NULL) + errx(1, "asprintf"); + + name_buffer.value = str; + name_buffer.length = len; + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_C_NO_OID, "import name error"); + free(str); + + if (anon_flag) + mech_oid = GSS_SANON_X25519_MECHANISM; + else + mech_oid = GSS_KRB5_MECHANISM; + + maj_stat = gss_canonicalize_name (&min_stat, + name, + mech_oid, + &MNname); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, mech_oid, "canonicalize name error"); + + maj_stat = gss_export_name(&min_stat, + MNname, + &name_buffer); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, mech_oid, "export name error"); + + /* + * Import the exported name and compare + */ + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_EXPORT_NAME, + &MNname2); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, mech_oid, "export name error"); + + + maj_stat = gss_compare_name(&min_stat, MNname, MNname2, &equal); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, mech_oid, "compare name error"); + if (equal && anon_flag) + errx(1, "names %s equal", anon_flag ? "incorrectly" : "not"); + + gss_release_name(&min_stat, &MNname2); + gss_release_buffer(&min_stat, &name_buffer); + gss_release_name(&min_stat, &MNname); + gss_release_name(&min_stat, &name); + + /* + * Import oid less name and compare to mech name. + * Dovecot SASL lib does this. + */ + + str = NULL; + len = asprintf(&str, "lha"); + if (len < 0 || str == NULL) + errx(1, "asprintf"); + + name_buffer.value = str; + name_buffer.length = len; + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NO_OID, + &name); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, NULL, "import (no oid) name error"); + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_KRB5_NT_USER_NAME, + &MNname); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, NULL, "import (krb5 mn) name error"); + + free(str); + + maj_stat = gss_compare_name(&min_stat, name, MNname, &equal); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_compare_name"); + if (!equal) + errx(1, "names not equal"); + + gss_release_name(&min_stat, &MNname); + gss_release_name(&min_stat, &name); + +#if 0 + maj_stat = gss_canonicalize_name (&min_stat, + name, + GSS_SPNEGO_MECHANISM, + &MNname); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_SPNEGO_MECHANISM, + "canonicalize name error"); + + + maj_stat = gss_export_name(&maj_stat, + MNname, + &name_buffer); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_SPNEGO_MECHANISM, + "export name error (SPNEGO)"); + + gss_release_name(&min_stat, &MNname); + gss_release_buffer(&min_stat, &name_buffer); +#endif + + if (anon_flag) { + /* check anonymous name canonicalizes to well known name */ + gss_OID name_type; + + name_buffer.length = 0; + name_buffer.value = NULL; + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_ANONYMOUS, &name); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_C_NO_OID, + "import (anon) name error"); + + maj_stat = gss_canonicalize_name(&min_stat, name, + GSS_SANON_X25519_MECHANISM, + &MNname); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_SANON_X25519_MECHANISM, + "canonicalize (anon) name error"); + + maj_stat = gss_display_name(&min_stat, MNname, + &name_buffer, &name_type); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, maj_stat, min_stat, GSS_SANON_X25519_MECHANISM, + "display_name (anon) name error"); + + if (!gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) + errx(1, "display name type not anonymous"); + if (memcmp(name_buffer.value, "WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS", + sizeof("WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS") - 1) != 0) + errx(1, "display name string not well known anonymous name"); + + gss_release_name(&min_stat, &MNname); + gss_release_name(&min_stat, &name); + gss_release_buffer(&min_stat, &name_buffer); + } + + check_name_attrs(); + return 0; +} + +/* Copied from _gsskrb5_export_name_composite() */ +static void +export_name_composite(CompositePrincipal *name, gss_buffer_t exported_name) +{ + gss_buffer_desc inner = GSS_C_EMPTY_BUFFER; + unsigned char *buf; + int32_t ret; + size_t sz; + + ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length, + (void *)name, &sz, ret); + if (ret) + errx(1, "Failed to encode exported composite name token"); + + exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) + errx(1, "Failed to allocate exported composite name token"); + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + buf[0] = 0x04; + buf[1] = 0x02; + buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf[4] = 0x06; + buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF; + + memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += 6 + GSS_KRB5_MECHANISM->length; + + buf[0] = (inner.length >> 24) & 0xff; + buf[1] = (inner.length >> 16) & 0xff; + buf[2] = (inner.length >> 8) & 0xff; + buf[3] = (inner.length) & 0xff; + buf += 4; + + memcpy(buf, inner.value, inner.length); + free(inner.value); +} + +static void +make_composite_name(CompositePrincipal *princ, gss_name_t *n) +{ + gss_buffer_desc token, exported; + OM_uint32 maj, min; + + export_name_composite(princ, &token); + maj = gss_import_name(&min, &token, GSS_C_NT_COMPOSITE_EXPORT, n); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "import composite name"); + maj = gss_export_name_composite(&min, *n, &exported); + if (maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, "export composite name"); + if (token.length != exported.length || + memcmp(token.value, exported.value, token.length) != 0) + errx(1, "import/export composite token disagreement"); + gss_release_buffer(&min, &exported); + free(token.value); /* Use free because we allocated this one */ +} + +static void +assert_attr(gss_name_t n, + const char *aname, + OM_uint32 exp_maj, + gss_buffer_t exp_v, + const char *exp_dv, + int exp_authenticated, + int exp_complete, + int exp_multivalued) +{ + gss_buffer_desc dv = GSS_C_EMPTY_BUFFER; + gss_buffer_desc v = GSS_C_EMPTY_BUFFER; + gss_buffer_desc a; + OM_uint32 maj, min; + int authenticated, complete, more; + + a.value = (void*)(uintptr_t)aname; + a.length = strlen(aname); + more = 0; + maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v, + &dv, &more); + if (maj != GSS_S_COMPLETE && maj != exp_maj) + gss_err(1, maj, min, GSS_KRB5_MECHANISM, + "import composite name error"); + if (maj == GSS_S_COMPLETE && maj != exp_maj) + errx(1, "unexpected name attribute %s", aname); + if (maj == GSS_S_COMPLETE) { + if (exp_v && + (v.length != exp_v->length || + memcmp(v.value, exp_v->value, exp_v->length) != 0)) + errx(1, "import composite name: wrong %s value", aname); + if (exp_dv && + (dv.length != strlen(exp_dv) || + strncmp(dv.value, exp_dv, dv.length) != 0)) + errx(1, "import composite name: wrong %s display value " + "(wanted %s, got %.*s)", aname, exp_dv, + (int)dv.length, (char *)dv.value); + if (authenticated != exp_authenticated) + errx(1, "import composite name: %s incorrectly marked " + "%sauthenticated", aname, authenticated ? "" : "un"); + if (complete != exp_complete) + errx(1, "import composite name: %s incorrectly marked " + "%scomplete", aname, complete ? "" : "in"); + if (more != exp_multivalued) + errx(1, "import composite name: %s incorrectly marked " + "%s-valued", aname, more ? "multi" : "single"); + } + gss_release_buffer(&min, &dv); + gss_release_buffer(&min, &v); +} + +static void +assert_attr_unavail(gss_name_t n, const char *aname) +{ + assert_attr(n, aname, GSS_S_UNAVAILABLE, GSS_C_NO_BUFFER, NULL, 0, 0, 0); +} + +static void +assert_attr_set(gss_name_t n, gss_buffer_set_t exp_as) +{ + OM_uint32 maj, min; + gss_buffer_set_t as = NULL; + gss_OID MN_mech = GSS_C_NO_OID; + size_t i; + int name_is_MN = 0; + + maj = gss_inquire_name(&min, n, &name_is_MN, &MN_mech, &as); + if (maj) + gss_err(1, maj, min, MN_mech, "inquire name"); + for (i = 0; i < as->count && i < exp_as->count; i++) { + if (as->elements[i].length != exp_as->elements[i].length || + memcmp(as->elements[i].value, exp_as->elements[i].value, + as->elements[i].length) != 0) + errx(1, "attribute sets differ"); + } + if (i < as->count) + errx(1, "more attributes indicated than expected"); + if (i < exp_as->count) + errx(1, "fewer attributes indicated than expected"); + gss_release_buffer_set(&min, &as); +} diff --git a/third_party/heimdal/lib/gssapi/test_negoex_mech.c b/third_party/heimdal/lib/gssapi/test_negoex_mech.c new file mode 100644 index 0000000..559c5de --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_negoex_mech.c @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2019 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct test_context { + int initiator; + uint8_t hops; /* hops remaining; 0 means established */ +}; + +OM_uint32 GSSAPI_CALLCONV +gss_init_sec_context(OM_uint32 *minor_status, + gss_const_cred_id_t claimant_cred_handle, + gss_ctx_id_t *context_handle, gss_const_name_t target_name, + const gss_OID mech_type, OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, gss_OID *actual_mech, + gss_buffer_t output_token, OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + struct test_context *ctx = (struct test_context *)*context_handle; + OM_uint32 major; + gss_buffer_desc tok; + const char *envstr; + uint8_t hops, mech_last_octet; + + if (actual_mech) + *actual_mech = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + + major = gss_duplicate_oid(minor_status, mech_type, actual_mech); + if (major != GSS_S_COMPLETE) + return major; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + envstr = getenv("HOPS"); + hops = (envstr != NULL) ? atoi(envstr) : 1; + assert(hops > 0); + } else if (input_token->length == 4 && + memcmp(input_token->value, "fail", 4) == 0) { + *minor_status = 12345; + return GSS_S_FAILURE; + } else { + hops = ((uint8_t *)input_token->value)[0]; + } + + mech_last_octet = ((uint8_t *)mech_type->elements)[mech_type->length - 1]; + envstr = getenv("INIT_FAIL"); + if (envstr != NULL && atoi(envstr) == mech_last_octet) + return GSS_S_FAILURE; + + if (ctx == NULL) { + ctx = malloc(sizeof(*ctx)); + assert(ctx != NULL); + ctx->initiator = 1; + ctx->hops = hops; + *context_handle = (gss_ctx_id_t)ctx; + } else if (ctx != NULL) { + assert(ctx->initiator); + ctx->hops--; + assert(ctx->hops == hops); + } + + if (ctx->hops > 0) { + /* Generate a token containing the remaining hop count. */ + ctx->hops--; + tok.value = &ctx->hops; + tok.length = 1; + major = gss_encapsulate_token(&tok, mech_type, output_token); + assert(major == GSS_S_COMPLETE); + } + + return (ctx->hops > 0) ? GSS_S_CONTINUE_NEEDED : GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, + gss_const_cred_id_t verifier_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, gss_OID *mech_type, + gss_buffer_t output_token, OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + struct test_context *ctx = (struct test_context *)*context_handle; + uint8_t hops, mech_last_octet; + const char *envstr; + unsigned char mechbuf[64]; + GSSAPIContextToken ct; + gss_OID_desc oid; + int ret; + size_t mech_len; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + if (delegated_cred_handle) + *delegated_cred_handle = GSS_C_NO_CREDENTIAL; + + ret = decode_GSSAPIContextToken(input_token->value, input_token->length, + &ct, NULL); + if (ret == 0) { + ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + &ct.thisMech, + &mech_len); + free_GSSAPIContextToken(&ct); + } + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + oid.length = (OM_uint32)mech_len; + oid.elements = mechbuf + sizeof(mechbuf) - mech_len; + + if (mech_type) + gss_duplicate_oid(minor_status, &oid, mech_type); + + /* + * The unwrapped token sits at the end and is just one byte giving the + * remaining number of hops. The final octet of the mech encoding should + * be just prior to it. + */ + assert(input_token->length >= 2); + hops = ((uint8_t *)input_token->value)[input_token->length - 1]; + mech_last_octet = ((uint8_t *)input_token->value)[input_token->length - 2]; + + envstr = getenv("ACCEPT_FAIL"); + if (envstr != NULL && atoi(envstr) == mech_last_octet) { + output_token->value = strdup("fail"); + assert(output_token->value != NULL); + output_token->length = 4; + return GSS_S_FAILURE; + } + + if (*context_handle == GSS_C_NO_CONTEXT) { + ctx = malloc(sizeof(*ctx)); + assert(ctx != NULL); + ctx->initiator = 0; + ctx->hops = hops; + *context_handle = (gss_ctx_id_t)ctx; + } else { + assert(!ctx->initiator); + ctx->hops--; + assert(ctx->hops == hops); + } + + if (ctx->hops > 0) { + /* Generate a token containing the remaining hop count. */ + ctx->hops--; + output_token->value = malloc(1); + assert(output_token->value != NULL); + memcpy(output_token->value, &ctx->hops, 1); + output_token->length = 1; + } + + return (ctx->hops > 0) ? GSS_S_CONTINUE_NEEDED : GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_delete_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + free(*context_handle); + *context_handle = GSS_C_NO_CONTEXT; + return GSS_S_COMPLETE; +} + +static int dummy_cred; + +OM_uint32 GSSAPI_CALLCONV +gss_acquire_cred(OM_uint32 *minor_status, gss_const_name_t desired_name, + OM_uint32 time_req, const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + *minor_status = 0; + *output_cred_handle = (gss_cred_id_t)&dummy_cred; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_acquire_cred_with_password(OM_uint32 *minor_status, + gss_const_name_t desired_name, + const gss_buffer_t password, OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, OM_uint32 *time_rec) +{ + *minor_status = 0; + *output_cred_handle = (gss_cred_id_t)&dummy_cred; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle) +{ + return GSS_S_COMPLETE; +} + +static int dummy_name; + +OM_uint32 GSSAPI_CALLCONV +gss_import_name(OM_uint32 *minor_status, gss_buffer_t input_name_buffer, + gss_OID input_name_type, gss_name_t *output_name) +{ + /* + * We don't need to remember anything about names, but we do need to + * distinguish them from GSS_C_NO_NAME (to determine the direction of + * gss_query_meta_data() and gss_exchange_meta_data()), so assign an + * arbitrary data pointer. + */ + *output_name = (gss_name_t)&dummy_name; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_release_name(OM_uint32 *minor_status, gss_name_t *input_name) +{ + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value, + int status_type, gss_OID mech_type, + OM_uint32 *message_context, gss_buffer_t status_string) +{ + if (status_type == GSS_C_MECH_CODE && status_value == 12345) { + status_string->value = strdup("failure from acceptor"); + assert(status_string->value != NULL); + status_string->length = strlen(status_string->value); + return GSS_S_COMPLETE; + } + return GSS_S_BAD_STATUS; +} + +OM_uint32 GSSAPI_CALLCONV +gssspi_query_meta_data(OM_uint32 *minor_status, gss_const_OID mech_oid, + gss_cred_id_t cred_handle, gss_ctx_id_t *context_handle, + gss_const_name_t targ_name, OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + const char *envstr; + uint8_t mech_last_octet; + int initiator = (targ_name != GSS_C_NO_NAME); + + mech_last_octet = ((uint8_t *)mech_oid->elements)[mech_oid->length - 1]; + envstr = getenv(initiator ? "INIT_QUERY_FAIL" : "ACCEPT_QUERY_FAIL"); + if (envstr != NULL && atoi(envstr) == mech_last_octet) + return GSS_S_FAILURE; + envstr = getenv(initiator ? "INIT_QUERY_NONE" : "ACCEPT_QUERY_NONE"); + if (envstr != NULL && atoi(envstr) == mech_last_octet) + return GSS_S_COMPLETE; + + meta_data->value = strdup("X"); + meta_data->length = 1; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gssspi_exchange_meta_data(OM_uint32 *minor_status, gss_const_OID mech_oid, + gss_cred_id_t cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t targ_name, OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + const char *envstr; + uint8_t mech_last_octet; + int initiator = (targ_name != GSS_C_NO_NAME); + + mech_last_octet = ((uint8_t *)mech_oid->elements)[mech_oid->length - 1]; + envstr = getenv(initiator ? "INIT_EXCHANGE_FAIL" : "ACCEPT_EXCHANGE_FAIL"); + if (envstr != NULL && atoi(envstr) == mech_last_octet) + return GSS_S_FAILURE; + + assert(meta_data->length == 1 && memcmp(meta_data->value, "X", 1) == 0); + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gssspi_query_mechanism_info(OM_uint32 *minor_status, gss_const_OID mech_oid, + unsigned char auth_scheme[16]) +{ + /* Copy the mech OID encoding and right-pad it with zeros. */ + memset(auth_scheme, 0, 16); + assert(mech_oid->length <= 16); + memcpy(auth_scheme, mech_oid->elements, mech_oid->length); + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +gss_inquire_sec_context_by_oid(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + struct test_context *ctx = (struct test_context *)context_handle; + OM_uint32 major; + uint8_t keybytes[32] = { 0 }; + uint8_t typebytes[4]; + gss_buffer_desc key, type; + const char *envstr; + int ask_verify; + + if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY)) + ask_verify = 0; + else if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY)) + ask_verify = 1; + else + return GSS_S_UNAVAILABLE; + + /* + * By default, make a key available only if the context is established. + * This can be overridden to "always", "init-always", "accept-always", + * or "never". + */ + envstr = getenv("KEY"); + if (envstr != NULL && strcmp(envstr, "never") == 0) { + return GSS_S_UNAVAILABLE; + } else if (ctx->hops > 0) { + if (envstr == NULL) + return GSS_S_UNAVAILABLE; + else if (strcmp(envstr, "init-always") == 0 && !ctx->initiator) + return GSS_S_UNAVAILABLE; + else if (strcmp(envstr, "accept-always") == 0 && ctx->initiator) + return GSS_S_UNAVAILABLE; + } + + /* Perturb the key so that each side's verifier key is equal to the other's + * checksum key. */ + keybytes[0] = ask_verify ^ ctx->initiator; + + /* Supply an all-zeros aes256-sha1 negoex key. */ + if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY) || + gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY)) { + OM_uint32 n = ENCTYPE_AES256_CTS_HMAC_SHA1_96; + + typebytes[0] = (n >> 0 ) & 0xFF; + typebytes[1] = (n >> 8 ) & 0xFF; + typebytes[2] = (n >> 16) & 0xFF; + typebytes[3] = (n >> 24) & 0xFF; + + key.value = keybytes; + key.length = sizeof(keybytes); + type.value = typebytes; + type.length = sizeof(typebytes); + major = gss_add_buffer_set_member(minor_status, &key, data_set); + if (major != GSS_S_COMPLETE) + return major; + return gss_add_buffer_set_member(minor_status, &type, data_set); + } + + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_process_context_token(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer) +{ + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_context_time(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 *time_rec) +{ + *time_rec = 0; + return GSS_S_COMPLETE; +} + +/* + * We also need to supply a fake MIC in case SPNEGO test negotiates + * as non-default mechanism + */ +#define FAKE_MIC "negoex-fake-mic" +#define FAKE_MIC_LEN (sizeof(FAKE_MIC) - 1) + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_get_mic(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + message_token->value = strdup(FAKE_MIC); + message_token->length = FAKE_MIC_LEN; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_verify_mic(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state) +{ + *minor_status = 0; + if (token_buffer->length == FAKE_MIC_LEN && + memcmp(token_buffer->value, FAKE_MIC, FAKE_MIC_LEN) == 0) + return GSS_S_COMPLETE; + else + return GSS_S_BAD_MIC; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_unwrap(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_compare_name(OM_uint32 *minor_status, + gss_const_name_t name1_arg, + gss_const_name_t name2_arg, + int *name_equal) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_display_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_context(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *xopen) +{ + *lifetime_rec = GSS_C_INDEFINITE; + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_wrap_size_limit(OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_import_sec_context(OM_uint32 *minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_export_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_canonicalize_name(OM_uint32 *minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t *output_name) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_name(OM_uint32 *minor_status, + gss_const_name_t src_name, + gss_name_t *dest_name) +{ + return GSS_S_UNAVAILABLE; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_inquire_cred(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t *name_ret, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) +{ + if (name_ret) + *name_ret = (gss_name_t)&dummy_name; + if (lifetime) + *lifetime = GSS_C_INDEFINITE; + if (cred_usage) + *cred_usage = GSS_C_BOTH; + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/test_ntlm.c b/third_party/heimdal/lib/gssapi/test_ntlm.c new file mode 100644 index 0000000..de3a8dd --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_ntlm.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include "test_common.h" + +#include +#include + +static int +test_libntlm_v1(int flags) +{ + const char *user = "foo", + *domain = "mydomain", + *password = "digestpassword"; + OM_uint32 maj_stat, min_stat; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc input, output; + struct ntlm_type1 type1; + struct ntlm_type2 type2; + struct ntlm_type3 type3; + struct ntlm_buf data; + krb5_error_code ret; + gss_name_t src_name = GSS_C_NO_NAME; + + memset(&type1, 0, sizeof(type1)); + memset(&type2, 0, sizeof(type2)); + memset(&type3, 0, sizeof(type3)); + + type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_TARGET|NTLM_NEG_NTLM|flags; + type1.domain = strdup(domain); + type1.hostname = NULL; + type1.os[0] = 0; + type1.os[1] = 0; + + ret = heim_ntlm_encode_type1(&type1, &data); + if (ret) + errx(1, "heim_ntlm_encode_type1"); + + input.value = data.data; + input.length = data.length; + + output.length = 0; + output.value = NULL; + + maj_stat = gss_accept_sec_context(&min_stat, + &ctx, + GSS_C_NO_CREDENTIAL, + &input, + GSS_C_NO_CHANNEL_BINDINGS, + NULL, + NULL, + &output, + NULL, + NULL, + NULL); + free(data.data); + if (GSS_ERROR(maj_stat)) + errx(1, "accept_sec_context v1: %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + if (output.length == 0) + errx(1, "output.length == 0"); + + data.data = output.value; + data.length = output.length; + + ret = heim_ntlm_decode_type2(&data, &type2); + if (ret) + errx(1, "heim_ntlm_decode_type2"); + + gss_release_buffer(&min_stat, &output); + + type3.flags = type2.flags; + type3.username = rk_UNCONST(user); + type3.targetname = type2.targetname; + type3.ws = rk_UNCONST("workstation"); + + { + struct ntlm_buf key; + + heim_ntlm_nt_key(password, &key); + + heim_ntlm_calculate_ntlm1(key.data, key.length, + type2.challenge, + &type3.ntlm); + + if (flags & NTLM_NEG_KEYEX) { + struct ntlm_buf sessionkey; + heim_ntlm_build_ntlm1_master(key.data, key.length, + &sessionkey, + &type3.sessionkey); + free(sessionkey.data); + } + free(key.data); + } + + ret = heim_ntlm_encode_type3(&type3, &data, NULL); + if (ret) + errx(1, "heim_ntlm_encode_type3"); + + input.length = data.length; + input.value = data.data; + + maj_stat = gss_accept_sec_context(&min_stat, + &ctx, + GSS_C_NO_CREDENTIAL, + &input, + GSS_C_NO_CHANNEL_BINDINGS, + &src_name, + NULL, + &output, + NULL, + NULL, + NULL); + free(input.value); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "accept_sec_context v1 2 %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + gss_release_buffer(&min_stat, &output); + gss_delete_sec_context(&min_stat, &ctx, NULL); + + if (src_name == GSS_C_NO_NAME) + errx(1, "no source name!"); + + gss_display_name(&min_stat, src_name, &output, NULL); + + printf("src_name: %.*s\n", (int)output.length, (char*)output.value); + + gss_release_name(&min_stat, &src_name); + gss_release_buffer(&min_stat, &output); + + return 0; +} + +static int +test_libntlm_v2(int flags) +{ + const char *user = "foo", + *domain = "mydomain", + *password = "digestpassword"; + OM_uint32 maj_stat, min_stat; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc input, output; + struct ntlm_type1 type1; + struct ntlm_type2 type2; + struct ntlm_type3 type3; + struct ntlm_buf data; + krb5_error_code ret; + + memset(&type1, 0, sizeof(type1)); + memset(&type2, 0, sizeof(type2)); + memset(&type3, 0, sizeof(type3)); + + type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_NTLM|flags; + type1.domain = strdup(domain); + type1.hostname = NULL; + type1.os[0] = 0; + type1.os[1] = 0; + + ret = heim_ntlm_encode_type1(&type1, &data); + if (ret) + errx(1, "heim_ntlm_encode_type1"); + + input.value = data.data; + input.length = data.length; + + output.length = 0; + output.value = NULL; + + maj_stat = gss_accept_sec_context(&min_stat, + &ctx, + GSS_C_NO_CREDENTIAL, + &input, + GSS_C_NO_CHANNEL_BINDINGS, + NULL, + NULL, + &output, + NULL, + NULL, + NULL); + free(data.data); + if (GSS_ERROR(maj_stat)) + errx(1, "accept_sec_context v2 %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + if (output.length == 0) + errx(1, "output.length == 0"); + + data.data = output.value; + data.length = output.length; + + ret = heim_ntlm_decode_type2(&data, &type2); + if (ret) + errx(1, "heim_ntlm_decode_type2"); + + type3.flags = type2.flags; + type3.username = rk_UNCONST(user); + type3.targetname = type2.targetname; + type3.ws = rk_UNCONST("workstation"); + + { + struct ntlm_buf key; + unsigned char ntlmv2[16]; + + heim_ntlm_nt_key(password, &key); + + heim_ntlm_calculate_ntlm2(key.data, key.length, + user, + type2.targetname, + type2.challenge, + &type2.targetinfo, + ntlmv2, + &type3.ntlm); + free(key.data); + + if (flags & NTLM_NEG_KEYEX) { + struct ntlm_buf sessionkey; + heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2), + &sessionkey, + &type3.sessionkey); + free(sessionkey.data); + } + } + + ret = heim_ntlm_encode_type3(&type3, &data, NULL); + if (ret) + errx(1, "heim_ntlm_encode_type3"); + + input.length = data.length; + input.value = data.data; + + maj_stat = gss_accept_sec_context(&min_stat, + &ctx, + GSS_C_NO_CREDENTIAL, + &input, + GSS_C_NO_CHANNEL_BINDINGS, + NULL, + NULL, + &output, + NULL, + NULL, + NULL); + free(input.value); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "accept_sec_context v2 2 %s", + gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); + + gss_delete_sec_context(&min_stat, &ctx, NULL); + + return 0; +} + + + +static int version_flag = 0; +static int help_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int ret = 0, optidx = 0; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + ret += test_libntlm_v1(0); + ret += test_libntlm_v1(NTLM_NEG_KEYEX); + + ret += test_libntlm_v2(0); + ret += test_libntlm_v2(NTLM_NEG_KEYEX); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/test_oid.c b/third_party/heimdal/lib/gssapi/test_oid.c new file mode 100644 index 0000000..ced8a05 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/test_oid.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + OM_uint32 minor_status, maj_stat; + gss_buffer_desc data; + int ret; + + maj_stat = gss_oid_to_str(&minor_status, GSS_KRB5_MECHANISM, &data); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_oid_to_str failed"); + + ret = strncmp(data.value, "1 2 840 113554 1 2 2", data.length); + gss_release_buffer(&maj_stat, &data); + if (ret != 0) + return 1; + + maj_stat = gss_oid_to_str(&minor_status, GSS_C_NT_EXPORT_NAME, &data); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_oid_to_str failed"); + + ret = strncmp(data.value, "1 3 6 1 5 6 4", data.length); + gss_release_buffer(&maj_stat, &data); + if (ret != 0) + return 1; + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/version-script.map b/third_party/heimdal/lib/gssapi/version-script.map new file mode 100644 index 0000000..7f482b5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/version-script.map @@ -0,0 +1,210 @@ +# $Id$ + +HEIMDAL_GSS_2.0 { + global: +# __gss_c_nt_anonymous; + __gss_c_nt_anonymous_oid_desc; + __gss_c_nt_composite_export_oid_desc; + __gss_c_nt_export_name_oid_desc; + __gss_c_nt_hostbased_service_oid_desc; + __gss_c_nt_hostbased_service_x_oid_desc; + __gss_c_nt_machine_uid_name_oid_desc; + __gss_c_nt_string_uid_name_oid_desc; + __gss_c_nt_user_name_oid_desc; + __gss_krb5_nt_principal_name_oid_desc; + __gss_c_attr_stream_sizes_oid_desc; + __gss_c_attr_local_login_user; + gss_accept_sec_context; + gss_acquire_cred; + gss_acquire_cred_from; + gss_acquire_cred_impersonate_name; + gss_acquire_cred_with_password; + gss_add_buffer_set_member; + gss_add_cred; + gss_add_cred_from; + gss_add_cred_with_password; + gss_add_oid_set_member; + gss_authorize_localname; + gss_canonicalize_name; + gss_compare_name; + gss_context_query_attributes; + gss_context_time; + gss_create_empty_buffer_set; + gss_create_empty_oid_set; + gss_decapsulate_token; + gss_delete_name_attribute; + gss_delete_sec_context; + gss_display_name; + gss_display_name_ext; + gss_display_status; + gss_duplicate_name; + gss_duplicate_oid; + gss_duplicate_oid_set; + gss_encapsulate_token; + gss_export_cred; + gss_export_name; + gss_export_name_composite; + gss_export_sec_context; + gss_get_mic; + gss_get_neg_mechs; + gss_get_name_attribute; + gss_import_cred; + gss_import_name; + gss_import_sec_context; + gss_indicate_mechs; + gss_init_sec_context; + gss_inquire_context; + gss_inquire_cred; + gss_inquire_cred_by_mech; + gss_inquire_cred_by_oid; + gss_inquire_mechs_for_name; + gss_inquire_name; + gss_inquire_names_for_mech; + gss_inquire_sec_context_by_oid; + gss_inquire_sec_context_by_oid; + gss_krb5_ccache_name; + gss_krb5_copy_ccache; + gss_krb5_export_lucid_sec_context; + gss_krb5_free_lucid_sec_context; + gss_krb5_get_tkt_flags; + gss_krb5_import_cred; + gss_krb5_set_allowable_enctypes; + gss_localname; + gss_mg_collect_error; + gss_oid_equal; + gss_oid_to_str; + gss_pname_to_uid; + gss_process_context_token; + gss_pseudo_random; + gss_release_buffer; + gss_release_buffer_set; + gss_release_cred; + gss_release_iov_buffer; + gss_release_name; + gss_release_oid; + gss_release_oid_set; + gss_seal; + gss_set_cred_option; + gss_set_name_attribute; + gss_set_log_function; + gss_set_neg_mechs; + gss_set_sec_context_option; + gss_sign; + gss_store_cred; + gss_store_cred_into; + gss_store_cred_into2; + gss_test_oid_set_member; + gss_unseal; + gss_unwrap; + gss_unwrap_aead; + gss_unwrap_iov; + gss_userok; + gss_verify; + gss_verify_mic; + gss_wrap; + gss_wrap_aead; + gss_wrap_iov; + gss_wrap_iov_length; + gss_wrap_size_limit; + gsskrb5_extract_authtime_from_sec_context; + gsskrb5_extract_authz_data_from_sec_context; + gsskrb5_extract_service_keyblock; + gsskrb5_get_initiator_subkey; + gsskrb5_get_subkey; + gsskrb5_get_time_offset; + gsskrb5_register_acceptor_identity; + gsskrb5_set_default_realm; + gsskrb5_set_dns_canonicalize; + gsskrb5_set_send_to_kdc; + gsskrb5_set_time_offset; + krb5_gss_register_acceptor_identity; + gss_display_mech_attr; + gss_inquire_attrs_for_mech; + gss_indicate_mechs_by_attrs; + gss_inquire_mech_for_saslname; + gss_inquire_saslname_for_mech; + gss_mo_get; + gss_mo_set; + gss_mo_list; + gss_mo_name; + gss_name_to_oid; + gss_oid_to_name; + + # _gsskrb5cfx_ are really internal symbols, but export + # then now to make testing easier. + _gsskrb5cfx_wrap_length_cfx; + _gssapi_wrap_size_cfx; + + __gss_krb5_copy_ccache_x_oid_desc; + __gss_krb5_get_tkt_flags_x_oid_desc; + __gss_krb5_extract_authz_data_from_sec_context_x_oid_desc; + __gss_krb5_compat_des3_mic_x_oid_desc; + __gss_krb5_register_acceptor_identity_x_oid_desc; + __gss_krb5_export_lucid_context_x_oid_desc; + __gss_krb5_export_lucid_context_v1_x_oid_desc; + __gss_krb5_set_dns_canonicalize_x_oid_desc; + __gss_krb5_get_subkey_x_oid_desc; + __gss_krb5_get_initiator_subkey_x_oid_desc; + __gss_krb5_get_acceptor_subkey_x_oid_desc; + __gss_krb5_send_to_kdc_x_oid_desc; + __gss_krb5_get_authtime_x_oid_desc; + __gss_krb5_get_service_keyblock_x_oid_desc; + __gss_krb5_set_allowable_enctypes_x_oid_desc; + __gss_krb5_set_default_realm_x_oid_desc; + __gss_krb5_ccache_name_x_oid_desc; + __gss_krb5_set_time_offset_x_oid_desc; + __gss_krb5_get_time_offset_x_oid_desc; + __gss_krb5_plugin_register_x_oid_desc; + __gss_ntlm_get_session_key_x_oid_desc; + __gss_c_nt_ntlm_oid_desc; + __gss_c_nt_dn_oid_desc; + __gss_krb5_nt_principal_name_referral_oid_desc; + __gss_c_ntlm_avguest_oid_desc; + __gss_c_ntlm_v1_oid_desc; + __gss_c_ntlm_v2_oid_desc; + __gss_c_ntlm_session_key_oid_desc; + __gss_c_ntlm_force_v1_oid_desc; + __gss_krb5_cred_no_ci_flags_x_oid_desc; + __gss_krb5_import_cred_x_oid_desc; + __gss_c_ma_sasl_mech_name_oid_desc; + __gss_c_ma_mech_name_oid_desc; + __gss_c_ma_mech_description_oid_desc; + __gss_sasl_digest_md5_mechanism_oid_desc; + __gss_krb5_mechanism_oid_desc; + __gss_ntlm_mechanism_oid_desc; + __gss_spnego_mechanism_oid_desc; + __gss_sanon_x25519_mechanism_oid_desc; + __gss_c_ma_mech_concrete_oid_desc; + __gss_c_ma_mech_pseudo_oid_desc; + __gss_c_ma_mech_composite_oid_desc; + __gss_c_ma_mech_nego_oid_desc; + __gss_c_ma_mech_glue_oid_desc; + __gss_c_ma_not_mech_oid_desc; + __gss_c_ma_deprecated_oid_desc; + __gss_c_ma_not_dflt_mech_oid_desc; + __gss_c_ma_itok_framed_oid_desc; + __gss_c_ma_auth_init_oid_desc; + __gss_c_ma_auth_targ_oid_desc; + __gss_c_ma_auth_init_init_oid_desc; + __gss_c_ma_auth_targ_init_oid_desc; + __gss_c_ma_auth_init_anon_oid_desc; + __gss_c_ma_auth_targ_anon_oid_desc; + __gss_c_ma_deleg_cred_oid_desc; + __gss_c_ma_integ_prot_oid_desc; + __gss_c_ma_conf_prot_oid_desc; + __gss_c_ma_mic_oid_desc; + __gss_c_ma_wrap_oid_desc; + __gss_c_ma_prot_ready_oid_desc; + __gss_c_ma_replay_det_oid_desc; + __gss_c_ma_oos_det_oid_desc; + __gss_c_ma_cbindings_oid_desc; + __gss_c_ma_pfs_oid_desc; + __gss_c_ma_compress_oid_desc; + __gss_c_ma_ctx_trans_oid_desc; + __gss_c_ma_negoex_and_spnego_oid_desc; + __gss_c_inq_negoex_key_oid_desc; + __gss_c_inq_negoex_verify_key_oid_desc; + + local: + *; +}; diff --git a/third_party/heimdal/lib/hcrypto/ChangeLog b/third_party/heimdal/lib/hcrypto/ChangeLog new file mode 100644 index 0000000..1a32025 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ChangeLog @@ -0,0 +1,1227 @@ +2008-06-26 Love Hörnquist Åstrand + + * ui.c: Send newline from use to stderr, just like the + prompt. From Ted Percival. + +2008-05-20 Love Hörnquist Åstrand + + * rand-fortuna.c: If we forked, force a reseed again. Add the pid + as part of the reseed(). + +2008-04-29 Björn Sandell + + * des.h: Add DES_set_key_unchecked + + * version-script.map: Export DES_set_key_unchecked + +2008-04-29 Love Hörnquist Åstrand + + * evp.c: EVP_MD_CTX_init already implemented. + +2008-04-28 Love Hörnquist Åstrand + + * evp.[ch]: deprecate functions that are needed for exported + EVP_MD_CTX. + + * evp.h: Internalize hc_EVP_MD_CTX. + + * evp.c: Internalize hc_EVP_MD_CTX. + + * mdtest.c: Use EVP_MD_CTX_create()/EVP_MD_CTX_destroy(). + + * test_cipher.c: unbreak des-test + + * evp.c: Fixup key parity before going ahead and using the key. + + * evp.c: use DES_set_key_unchecked(). + + * des.c: Remove inifinite loop in DES_set_key(). + +2008-04-27 Love Hörnquist Åstrand + + * des.c: Document missing functions, add DES_check_key_parity(). + + * des.h: Add DES_check_key_parity, deprecate DES_set_key. + + * version-script.map: Export DES_check_key_parity. + + * des.h: DES_set_odd_parity "returns" void. + + * rand.c: Drop const warnings. + + * des.h: Sort options. + +2008-04-18 Love Hörnquist Åstrand + + * pkcs5.c: Document PKCS5_PBKDF2_HMAC_SHA1. + + * des.c: DES is withdrawn. + + * des.c: Document using doxygen. + + * des.c: History of DES. + + * doxygen.c: History of hcrypto. + + * test_rand.c: do a head vs tail test on the random buffer. + + * test_crypto.in: Use --file to test_rand. + + * rand.c: Document, implement RAND_set_rand_engine(). + + * doxygen.c: Add reference to DES, more quick links. + + * rnd_keys.c: Reimplement using RAND_ interface. + + * des.h: Undeprecate DES_new_random_key. + + * des.c: Add documentation. + +2008-04-15 Love Hörnquist Åstrand + + * camellia-ntt.h: Move the typedef u to camellia-ntt.h header + file. Use u32 to define KEY_TABLE_TYPE, avoids warning on + platfors where u32 is not unsigned int. + + * camellia-ntt.c: Move the typedef u to camellia-ntt.h + header file. + + * camellia.h: Drop need to camellia-ntt.h by including some more + defines. + +2008-04-11 Love Hörnquist Åstrand + + * rnd_keys.c: deprecated. + + * des.h: c++ wrappers + deprecated. + + * aes.h: c++ wrappers + + * des.h: c++ wrappers + deprecated + + * rnd_keys.c: Use matching prototypes, prompted by bug report by + David Rosenstrauch. + +2008-03-19 Love Hörnquist Åstrand + + * camellia.h: Drop unused defined that originates from aes. + +2008-01-11 Love Hörnquist Åstrand + + * Makefile.am: Add extra files missing from dist. + +2007-12-30 Love Hörnquist Åstrand + + * rsa.c: ENGINE_get_default_RSA can return NULL. + + * dh.c: more doxygen. + +2007-12-28 Love Hörnquist Åstrand + + * evp.c: Add last of the doxygen documentation for functions in + this module. + + * evp.c: complete the EVP_MD functions doxygen. + +2007-12-11 Love Hörnquist Åstrand + + * version-script.map: export RSA_gmp_method. + + * doxygen.c: More documentation. + + * rsa.h: add RSA_gmp_method + + * rsa-gmp.c: RSA implementation written using GMP. + + * test_dh.c: Test of DH by Matthias Koenig. + +2007-12-09 Love Hörnquist Åstrand + + * bn.h (BN_is_negative): make argument const. + +2007-12-07 Love Hörnquist Åstrand + + * rand.c: Can't call getpwuid(getuid()) at all since that causes + recursive lookups. Pointed out by Hai Zaar. + +2007-08-16 Love Hörnquist Åstrand + + * test_cipher.c: Use test from camellia samples. + + * version-script.map: Export camellia. + + * test_cipher.c: Make camellia-128-cbc tests pass. + +2007-08-07 Love Hörnquist Åstrand + + * test_cipher.c: Sprinkle EVP cipher names. + +2007-07-30 David Love + + * camellia-ntt.c: Include + +2007-07-24 Love Hörnquist Åstrand + + * Add Camellia. + +2007-07-10 Love Hörnquist Åstrand + + * Makefile.am: New library version. + +2007-06-30 Love Hörnquist Åstrand + + * hmac.c (HMAC_Init_ex): also zero out key material on re-init. + +2007-06-20 Love Hörnquist Åstrand + + * rand.c: Default to fortuna due to weired /dev/*random that + failes to deliver random data for us in hi load situations. + + * rand-fortuna.c: Reseed the random generator now and then from + external sources. + +2007-06-19 Love Hörnquist Åstrand + + * rand-egd.c: Avoid stoping unrelated memory. + +2007-06-18 Love Hörnquist Åstrand + + * rand-fortuna.c: Use /etc/shadow, not /dev/shadow, pointed out by + Andrew Bartlett + + * Makefile.am: add rand-timer.c + + * rand-fortuna.c: Fall back to gattering data from timer and + secret files, this is really the last resort. + + * rand-timer.c: Pick up timing diffrences in the timeing info from + realtime timer, only in use as a last resort. + + * version-script.map: Add hc_RAND_timer_method. + +2007-06-10 Love Hörnquist Åstrand + + * test_bn.c: Add . + + * test_crypto.in: Test for random device before running the tests. + + * test_engine_dso.c: Test for random device. + + * test_bn.c (test_BN_rand): skip this test if there is no random + device + +2007-06-07 Love Hörnquist Åstrand + + * Makefile.am: Include more ui.[ch] in libbctest. + + * version-script.map: Unexport _hc_DES_ipfp_test now there is a + separate test lib. + + * Makefile.am: Build library libhctest.la for testing and link + with that when testing. + + * version-script.map: export _hc_DES_ipfp_test + +2007-06-03 Love Hörnquist Åstrand + + * imath: new update from Michael Fromberger + + * test_imath.c: Try to find ABR in mp_int_mul. + + * engine.c: Don't try to load gmp module. + +2007-06-02 Love Hörnquist Åstrand + + * test_bn.c: Plug memory leak. + +2007-05-31 Love Hörnquist Åstrand + + * imath/imath.[ch]: New snapshot for Michael Fromberger, lets see if + this corrupts memory less. + +2007-05-30 Love Hörnquist Åstrand + + * version-script.map: Don't prefix all symbols with _ + +2007-05-10 Love Hörnquist Åstrand + + * test_pkcs12.c: test the difference between "" and NULL password. + + * test_pkcs12.c: one more pkcs12-pbe-s2k check + +2007-04-20 Love Hörnquist Åstrand + + * Add version-script + + * test_crypto.in: try generate a couple of rsa keys of + diffrent (random) sizes, spelling. + + * test_rsa.c: try generate a couple of rsa keys of + diffrent (random) sizes. + +2007-04-19 Love Hörnquist Åstrand + + * mdtest.c: stop leaking memory + + * test_imath.c: fix warnings, make test into function. + + * test_imath.c: shortest program causing the problem. + + * test_imath.c: basic imath test + +2007-04-18 Love Hörnquist Åstrand + + * test_cipher.c (test_cipher): avoid leaking memory + +2007-04-17 Love Hörnquist Åstrand + + * rsa.c: plug memory leak + +2007-04-16 Love Hörnquist Åstrand + + * Makefile.am: CLEANFILES += test.file + +2007-04-15 Love Hörnquist Åstrand + + * Makefile.am: Add randi.h. + +2007-04-11 Love Hörnquist Åstrand + + * rsa.c: spelling. + +2007-02-01 Love Hörnquist Åstrand + + * rand.c: Name the random file ~/.rnd, this is the same as + OpenSSL. + +2007-01-31 Love Hörnquist Åstrand + + * rand-egd.c: Make get_bytes static. + + * rand.c (RAND_write_file): default to failure. + +2007-01-30 Love Hörnquist Åstrand + + * rand.c: Implement RAND_file_name. + + * test_rand.c: test RAND_file_name(). + + * rand.c: Provide dummy implementation of RAND_file_name. + + * rand.h: add RAND_file_name + +2007-01-21 Love Hörnquist Åstrand + + * Makefile.am: clean more files + + * rand-egd.c: access private functions though the RAND_METHOD + switch, move global egd function to rand-egd.c + + * rand-fortuna.c: access private functions though the RAND_METHOD + switch + + * rand-unix.c: unexport private functions. + + * randi.h: Unexport internal functions. + + * rand.c: access private functions though the RAND_METHOD switch, + don't truncate the seed-file, move global egd function to + rand-egd.c + + * test_crypto.in: add basic random tests + + * rand-egd.c: SGI cc doesn' like return void_returning_function(); + in a void returning function. + +2007-01-20 Love Hörnquist Åstrand + + * test_rand.c: Allow select rand method. + + * rand-unix.c: expose _hc_rand_unix_status + + * randi.h: expose _hc_rand_unix_status and the internal + RAND_METHODs + + * rand.c: Implement RAND_load_file and RAND_write_file. Select + UNIX random device if available, otherwise use Fortuna. + + * Add EGD/PRNGD support + +2007-01-17 Love Hörnquist Åstrand + + * fortuna: Add fortuna based on Marko Kreen's pgcrypt, no enabled yet + +2007-01-11 Love Hörnquist Åstrand + + * test_rsa.c: if RAND is unhappy, don't run the tests. + + * test_engine_dso.c: if RAND is unhappy, don't run the tests. + + * imath/imath.c: Update to imath-1.8 from Michael Fromberger + + Fixed a bug in s_udiv() affecting the computation of quotient + digits. Thanks to Love Åstrand for isolating this bug. Also in + this release, defining USELLONG=Y or USELLONG=N on the command + line for make will switch support for the "long long" data type on + or off without having to edit the Makefile. The default is still + to permit use of "long long", even though the type is not standard + ANSI C90. + + * imath/imath.c (s_udiv): Allocate one more for q, remove debug + printfs + +2007-01-10 Love Hörnquist Åstrand + + * imath/imath.c (s_udiv): make a copy of a and b before we start + to make sure there is something un-tainted to print in cause of + failure. XXX remove this delta + (s_embar): make static + +2007-01-09 Love Hörnquist Åstrand + + * rsa.c: Correct the test if the rsa is a complete RSA private + key. + +2007-01-08 Love Hörnquist Åstrand + + * imath/imath.c: More verbose debugging in case of assertion + failure. XXX temporary for AIX problem. + +2007-01-06 Love Hörnquist Åstrand + + * rsa-imath.c: Fix a silly typo, and with that enable CRT since + now it works. + + * rsa-imath.c: With this crt works, but something is wrong in the + key generation, so keep it turned off for now. + + * test_rsa.c: Allow testing effect of key-blinding + + * test_rsa.c: Add timing info to rsa keygen. + + * rsa-imath.c: don't include + +2007-01-05 Love Hörnquist Åstrand + + * imath: prune off stuff we dont use + + * imath/import.sh: Prune off stuff we don't use from imathsource + + * Makefile.am: Prune off stuff we don't use from imathsource + + * rsa-imath.c: Use mp_int_exptmod directly. + + * imath/iprime.c: Use a larger table of small primes, cut down + genenration in best cases to half compared to using a small table. + + * rsa.h: add RSA_FLAG_NO_BLINDING + + * rsa-imath.c: Add keyblinding, add a commented out CRT based RSA. + + * rsa.c: Add iqmp. + +2007-01-04 Love Hörnquist Åstrand + + * rsa.c: add missing ; + + * rsa.c: Add i2d_RSAPrivateKey. + + * rsa.h: Add i2d_RSAPrivateKey. + + * test_rsa.c: test RSA_generate_key_ex + + * rsa-imath.c: Add imath_rsa_generate_key. + +2006-12-31 Love Hörnquist Åstrand + + * rsa.c: add RSA_generate_key_ex + + * rsa.h: add RSA_generate_key_ex + +2006-12-07 Love Hörnquist Åstrand + + * Makefile.am: CLEANFILES += test_crypto + +2006-12-06 Love Hörnquist Åstrand + + * Makefile.am: Add rsakey.der to EXTRA_DIST. + +2006-12-05 Love Hörnquist Åstrand + + * Makefile.am: Add test_crypto.in to EXTRA_DIST. + + * test_crypto.in: Add more spaces to allow sh to parse this + + * test_rsa.c: Explain what the fixed "sha1" checksum test tries to + test. + + * test_crypto.in: test rsa, dh and engine code + +2006-12-04 Love Hörnquist Åstrand + + * Makefile.am: rsa and crypto engine test cases + + * test_rsa.c: Make faster and less verbose + + * rsakey.der: test rsa key + + * test_rsa.c: Test rsa operations + + * rsa-imath.c: Fix the rsa-decrypt failed case that been hauting + me for a while. + +2006-12-02 Love Hörnquist Åstrand + + * rsa-imath.c: Use mp_int_to_binary to encode bignums + + * rsa-imath.c: Check if header is there + +2006-11-27 Love Hörnquist Åstrand + + * rsa-imath.c: Return -1 for failure. + + * rsa-imath.c: Its ok with smaller signatures. + + * rsa-imath.c: Split error codes for now + +2006-10-22 Love Hörnquist Åstrand + + * rsa.c: Try to not leak memory. + +2006-10-21 Love Hörnquist Åstrand + + * rand-unix.c (unix_bytes): read until the other side give us all + or fail. + + * imath: import imath-1.7, fixes buffer overrun problems + + * rsa.c (RSA_free): free the whole key + + * test_engine_dso.c: Add more dh tests. + +2006-10-20 Love Hörnquist Åstrand + + * imath/imath.c: Allocate more bits. + + * dh-imath.c (dh_compute_key): fix signness test + + * dh-imath.c: Try harder to generate a good keypair. + + * dh-imath.c: Return -1 dh_compute_key on failure, pointed out by + Olga Kornievskaia. + +2006-10-19 Love Hörnquist Åstrand + + * Makefile.am: Add hash.h and des-tables.h. + + * dh.c (DH_compute_key): return -1 on bad public key. + + * rsa.c: remove stray ; + + * engine.c: Does function typecasts instead of void * type-casts. + + * evp.c: Does function typecasts instead of void * type-casts. + +2006-10-16 Love Hörnquist Åstrand + + * Makefile.am: add rand-unix.c + + * rand.c: Move out rand-unix functions from the core lib. + + * rand-unix.c: Move out rand-unix functions from the core lib. + +2006-10-15 Love Hörnquist Åstrand + + * hmac.c (HMAC_CTX_cleanup): destroy the EVP_MD_CTX, so it will be + freed. + +2006-10-14 Love Hörnquist Åstrand + + * bn.c: Drop heim_any.h, prefix der primitives with der_ + + * rsa.c: Drop heim_any.h. + +2006-10-11 Love Hörnquist Åstrand + + * rsa.c (RSA_free): Call the meth->finish before releasing the + engine. + +2006-10-06 Love Hörnquist Åstrand + + * imath/imath.c: Cast argument to ctype(3) functions to (unsigned + char). + + * imath/imrat.c: Cast argument to ctype(3) functions to (unsigned + char). + +2006-09-22 Love Hörnquist Åstrand + + * ui.c (read_string): Try to not call signaction for signal 0 and + use NSIG if it exists to determin how many signals there exists, + also, only restore those signalhandlers that we got out. + + Bug reported by and patch tested by Harald Barth. + +2006-09-15 Love Hörnquist Åstrand + + * rsa-imath.c: Add commeted out test that exponent is > 3 + +2006-05-13 Love Hörnquist Åstrand + + * bn.c (BN_rand): avoid shadowing. + +2006-05-12 Love Hörnquist Åstrand + + * rsa-imath.c: Fix the last one of the asserts. + +2006-05-08 Love Hörnquist Åstrand + + * rand.c (get_device_fd): use /dev/urandom first. + + * rctest.c: Less "pointer targets in passing argument differ in + signedness" warnings. + + * rc2test.c: Less "pointer targets in passing argument differ in + signedness" warnings. + +2006-05-07 Love Hörnquist Åstrand + + * rsa-imath.c: Fix a off by one. + + * test_engine_dso.c: print the lengths when they don't match. + + * engine.c (ENGINE_load_builtin_engines): use RSA_imath_method for + the building engine. + + * rsa.h: expose RSA_imath_method + + * rsa.c (RSA_check_key): Do sign/verify instead. + + * dsa.c: rename the DSA_METHOD + + * dh.c: rename the DH_METHOD + + * dh-imath.c: rename the DH_METHOD + + * rsa.c: Default to use rsa-imath. + + * Makefile.am: Add rsa-imath.c to libhcrypto + + * rsa-imath.c: Add RSA support using imath. + +2006-05-06 Love Hörnquist Åstrand + + * imath: Add imath-1.1.9 + + * dh.h: Expose DH_imath_method. + + * Makefile.am: Add imath source, add test_engine_dso to TESTS. + + * engine.c: Lets say we have RSA_null_method(), not really + useable, but still. + + * test_engine_dso.c: If there are no arguments, use the internal + engine. + + * engine.h: Cpp rename some ENGINE symbols. + + * engine.c (ENGINE_load_builtin_engines): Load the internal + engine. + + * dh.c: Default to use DH-imath. + + * dh.c (DH_check_pubkey): describe what the function do + +2006-05-05 Love Hörnquist Åstrand + + * dh.c (DH_compute_key): check return status value from + DH_check_pubkey + + * Rename u_intXX_t to uintXX_t + +2006-04-24 Love Hörnquist Åstrand + + * pkcs5.c: include + + * evp.c: Sprinkel some assertions. + + * des.c: Move assertion and add another restriction, used as hint + to beam that its ok + +2006-04-23 Love Hörnquist Åstrand + + * rsa.c (RSA_check_key): don't do any checking if there is no + private key + + * engine.c (add_engine): reassign engines variable after realloc + +2006-04-21 Love Hörnquist Åstrand + + * evp.h: Add EVP_get_cipherbyname, unbreak EVP_BytesToKey + + * evp.h: Add prototype for EVP_BytesToKey + + * evp.c: Add stub for EVP_BytesToKey + +2006-04-20 Love Hörnquist Åstrand + + * dh.h: Add cpp-rename for DH_check_pubkey + +2006-04-17 Love Hörnquist Åstrand + + * rand.h: Add more RAND functions. + + * rand.c: Split out unix /dev/random to a RAND_METHOD + + * engine.h: add RAND support + + * engine.c: add RAND support + + * evp.h: s/rc4_64/rc2_64/ + + * rand.c: Add RAND_METHOD and some associated functions. + + * rand.h: Add RAND_METHOD and some associated functions. + + * test_bn.c: Test BN_rand + +2006-04-16 Love Hörnquist Åstrand + + * engine.c (ENGINE_by_dso): less printf + + * rsa.h (i2d_RSAPublicKey): fix prototype + + * rsa.c (i2d_RSAPublicKey): fix prototype + +2006-04-15 Love Hörnquist Åstrand + + * evp.h: Add EVP_rc2_64_cbc + + * evp.c: Add EVP_rc2_64_cbc + + * evp.h: Add SHA-256 symbols. + + * evp.c: Add SHA-256. + + * sha.h: Add SHA-256 symbols. + + * mdtest.c: Test SHA-256. + + * sha256.c: Inital (naive) SHA-256 implementation. + +2006-04-14 Love Hörnquist Åstrand + + * des.c (DES_cfb64_encrypt): add asserts that the *num pointers is + >= 0, because if it is, its a programmer error. + +2006-04-09 Love Hörnquist Åstrand + + * rc2.c (RC2_set_key): abort on erroneous input (len <= 0) size + that will case out out bound indexing, and its invalid input. + + * rsa.c: Make compile again. + +2006-04-03 Love Hörnquist Åstrand + + * rsa.c: Implement i2d_RSAPublicKey + + * rsa.h: Add i2d_RSAPublicKey + +2006-03-07 Love Hörnquist Åstrand + + * Makefile.am: EVP interface depends on dlopen, add it to LIBFLAGS + +2006-02-28 Love Hörnquist Åstrand + + * Makefile.am: Add pkcs5 files. + + * test_pkcs5.c: Testcases for pkcs5 pbe2. + + * pkcs5.c (PKCS5_PBKDF2_HMAC_SHA1): new function. + + * hmac.c: Digest key when it exceeds block size, not when it + exceeds the size of the output block. + +2006-02-16 Love Hörnquist Åstrand + + * rand.c (RAND_bytes): Don't abort() on failure, return error. + + * bn.c (BN_rand): check return value from RAND_bytes + +2006-01-18 Love Hörnquist Åstrand + + * dh.c (DH_compute_key): check public key + + * dh.h: Add DH_check_pubkey and defines it uses. + + * dh.c (DH_check_pubkey): New function. + + * bn.c: Remove unused fragment. + + * test_bn.c: Compare numbers with BN_cmp(). + +2006-01-17 David Love + + * bn.c: Include . + +2006-01-13 Love Hörnquist Åstrand + + * *.h: use #include + + * Makefile.am: provide a symlink so the directory hcrypto/ seems + to exists + + * engine.h: Expose dsa symbols + + * Makefile.am: Rename library to hcrypto and install headerfiles + in hcrypto/. + + * test_pkcs12.c: Test for PKCS12_key_gen. + + * hmac.h: Drop HMAC_CTX_create and HMAC_CTX_destroy. + + * engine.c (ENGINE_add_conf_module): Also load DH + + * dh.h: Reorder includes to avoid compile errors, provide + DH_new_method(). + + * dh.c: Indent. + + * bn.c: BN_get_negative was really named BN_is_negative, a comment + confused me. + + * bn.h: BN_get_negative was really named BN_is_negative, a comment + confused me. + + * pkcs12.h: Add PKCS12_key_gen(). + + * pkcs12.c: Add PKCS12_key_gen(). + + * Makefile.am: Add test_cipher, test_pkcs12, add pkcs12.[ch]. + + * evp.c: Rename rc2_40_cbc internal variable to something better. + Unbreak des-ede3-cbc. + +2006-01-11 Love Hörnquist Åstrand + + * test_bn.c: Test BN_uadd. + + * bn.c (BN_rand): don't leak memory on failure, catch malloc(0) + case + + * bn.c (BN_rand): clear the bits above the bits that user + requested. + (BN_uadd): new function. + + * bn.h (BN_uadd): new function. + +2006-01-10 Love Hörnquist Åstrand + + * evp.c (EVP_CIPHER_CTX_cleanup): clean up less aggressively + + * Makefile.am (check_PROGRAMS): add test_hmac + + * test_hmac.c: Simple regression test for HMAC. + + * hmac.c: Make hmac work. + + * evp.c: return the right blocksize for digests. + +2006-01-09 Love Hörnquist Åstrand + + * test_engine_dso.c: Add test for DH. + + * dh.c: Add DH_new_method, add ENGINE refcounting. + + * engine.[ch]: Add ENGINE_set_default_DH and ENGINE_get_default_DH + + * test_engine_dso.c: Add test for RSA encryption. + +2006-01-08 Love Hörnquist Åstrand + + * test_engine_dso.c: Add test for RSA. + + * implement enough glue to support OpenSSLs EVP, RSA, DSA, DH, + HMAC, RAND and ENGINE interfaces for use in hx509. rename all + symbols to start with hc_ to avoid clobbering namespaces. contains + no RSA/DH/DSA code, just glue to support using dynamic + ENGINE. hx509 supports this via pkcs11 and there is a gmp ENGINE + module supporting RSA. Also contains a MD2 digest for completion. + +2005-07-20 Love Hörnquist Åstrand + + * des.c,des.h,rnd_keys.c: change unsigned char * to void * + +2005-06-30 Love Hörnquist Åstrand + + * rnd_keys.c: const poision for unwriteable strings + +2005-06-19 Love Hörnquist Åstrand + + * des.c,aes.c,rc2.c: Rename parameter, as encrypt shadows a + global, from Andrew Bartlett + +2005-06-02 Love Hörnquist Åstrand + + * rnd_keys.c: Include for srandom/random. + +2005-05-29 Love Hörnquist Åstrand + + * des.c (DES_cbc_cksum): init u to make sure it have a value in + case of the empty in data + + * destest.c: add test for the empty password "" + +2005-05-27 Love Hörnquist Åstrand + + * rctest.c (cipher3): used unsigned char to avoid problems with + platforms using "signed char" + +2005-05-13 Love Hörnquist Åstrand + + * rc2.c: use unsigned char to avoid signess warning + + * des.c: use unsigned char to avoid signess warning + + * aes.c (AES_cbc_encrypt): use unsigned char to avoid signess + warning + +2005-05-03 Dave Love + + * mdtest.c: Fix typo for HAVE_STDLIB_H. + +2005-05-03 Love Hörnquist Åstrand + + * rnd_keys.c: Enabled to build on cygwin, based on patch from + David Love + +2005-05-02 Dave Love + + * mdtest.c: Include . + +2005-04-30 Love Hörnquist Åstrand + + * ui.c: Include . + (UI_UTIL_read_pw_string): make the prompt argument const. + + * des.h (UI_UTIL_read_pw_string): make the prompt argument const + + * ui.c (UI_UTIL_read_pw_string): remove unused variable plen + + * des.c: replace with + +2005-04-29 Dave Love + + * Makefile.am: Add LIB_roken. + +2005-04-27 Dave Love + + * sha.c: Include hash.h first. + + * md4.c: Include hash.h first. + + * md5.c: Include hash.h first. + + * hash.h: Include krb5-types.h + +2005-04-26 Dave Love + + * mdtest.c: Maybe include stdlib.h + +2005-04-10 Love Hörnquist Åstrand + + * sha.h,md5.h, md4.h: don't include bit types, the user must do + that #ifdef wrap + + * aes.h: #ifdef wrap + +2005-03-23 Love Hörnquist Åstrand + + * des.h: fix prototype for DES_random_key + + * rnd_keys.c: fix prototype for DES_random_key + + * des.[ch]: provide compatibility function DES_key_sched, same as + DES_set_key + +2005-03-20 Love Hörnquist Åstrand + + * destest.c: include config.h and protect some headers + + * rnd_keys.c: move to after include so the + C99 integer types exists + +2005-03-14 Love Hörnquist Åstrand + + * des.c: add DES_set_key_checked + + * des.h: add DES_set_key_checked + +2005-03-01 Love Hörnquist Åstrand + + * des-tables.h: Add the missing file + +2005-02-23 Love Hörnquist Åstrand + + * ui.c: remove dependency on asprintf + + * Makefile.am: make destest only once + + * Replace the eay DES code with key scheule setup code by me and DES + s-box and p permutation from Richard Outerbridge implemtation (in + public domain). The DES modes are implemented by me. ui.c code are + from appl/login. + + The implementation is about 3 times slower then Eric for encryption, + and about the same speed for key setup. + + +2004-08-10 Love Hörnquist Åstrand + + * rnd_keys.c (DES_rand_data): also try /dev/arandom + +2004-06-02 Love Hörnquist Åstrand + + * rnd_keys.c: don't include krb4 headers + + * rijndael-alg-fst.c: don't include krb4 headers + + * aes.c: don't include krb4 headers + + * aes.h: define AES_{EN,DE}CRYPT; remove #ifdefs, this is an + installed file + +2004-04-25 Love Hörnquist Åstrand + + * rc2.c: handle non blocksized cbc messages + + * aes.[ch]: add AES_cbc_encrypt + +2004-04-24 Love Hörnquist Åstrand + + * rc2test.c: test vectors from RFC2268 + + * rc2.c (RC2_set_key): rewrite the mask calculation + + * rc2.c (RC2_set_key): handle keys where effective bits are + diffrent from keylength + +2004-04-23 Love Hörnquist Åstrand + + * rc2.c: rc2 implementation + + * rc2.h: rc2 implementation + + * rc2test.c: rc2 implementation + + * Makefile.am: rc2 implementation + +2004-03-25 Love Hörnquist Åstrand + + * Makefile.am: new arcfour implementation + + * rc4.c: implemented from description in + draft-kaukonen-cipher-arcfour-03.txt + + * rc4.h: replace with new implementation + + * rc4_enc.c rc4_skey.c: remove + + * rctest.c: test for arcfour + +2003-12-07 Love Hörnquist Åstrand + + * rnd_keys.c: uninitialized variable, from Panasas Inc + +2003-09-03 Love Hörnquist Åstrand + + * md4.c (MD4_Final): make the function threadsafe by removing + static on the local variable zeros + + * md5.c (MD5_Final): make the function threadsafe by removing + static on the local variable zeros + + * switch to the DES_ api, dont provide any compat glue + +2003-08-27 Love Hörnquist Åstrand + + * sha.c: make the function threadsafe by removing static on the + local variable zeros + +2003-07-23 Love Hörnquist Åstrand + + * rijndael-alg-fst.h,rijndael-alg-fst.c,aes.c,aes.h: + Makefile.am: add AES support + +2003-03-19 Love Hörnquist Åstrand + + * des.1: sunOS -> SunOS, from jmc + +2003-03-19 Love Hörnquist Åstrand + + * des.1: spelling, from + +2002-08-28 Johan Danielsson + + * read_pwd.c: move NeXT SGTTY stuff here + +2001-05-17 Assar Westerlund + + * Makefile.am: bump version to 3:1:0 + +2001-05-11 Assar Westerlund + + * str2key.c (des_string_to_key, des_string_to_2keys): avoid weak + keys + +2001-02-16 Assar Westerlund + + * set_key.c: correct weak keys and update comment + +2001-02-14 Assar Westerlund + + * set_key.c: correct the two last weak keys in accordance with + FIPS 74. noted by + +2001-01-30 Assar Westerlund + + * Makefile.am (libdes_la_LDFLAGS): bump version to 3:0:0 + +2000-10-19 Assar Westerlund + + * Makefile.in (LIBSRC, LIBOBJ): add rc4* and enc_{read,write} + files so that this library contains the same things as libdes in + Heimdal + +2000-08-16 Assar Westerlund + + * Makefile.am: bump version to 2:1:0 + +2000-08-03 Johan Danielsson + + * enc_writ.c: BSIZE -> des_BSIZE to avoid conflicts with AIX + jfs/fsparam.h + + * enc_read.c: BSIZE -> des_BSIZE to avoid conflicts with AIX + jfs/fsparam.h + + * des_locl.h: BSIZE -> des_BSIZE to avoid conflicts with AIX + jfs/fsparam.h + +2000-02-07 Assar Westerlund + + * Makefile.am: set version to 2:0:0 + +2000-01-26 Assar Westerlund + + * mdtest.c: update to pseudo-standard APIs for md4,md5,sha. + * md4.c, md4.h, md5.c, md5.h, sha.c, sha.h: move to the + pseudo-standard APIs + +1999-12-06 Assar Westerlund + + * Makefile.am: set version to 1:0:1 + +1999-11-29 Assar Westerlund + + * fcrypt.c (crypt_md5): add trailing $ + +1999-11-13 Assar Westerlund + + * Makefile.am (include_HEADERS): add rc4.h + (libdes_la_SOURCES): add rc4_skey.c + +1999-10-28 Assar Westerlund + + * md5crypt_test.c: change the test case. apparently we should not + include $ after the salt. also make it print more useful stuff + when failing. + +1999-10-20 Assar Westerlund + + * Makefile.am: bump version to 0:2:0 + +1999-09-21 Johan Danielsson + + * des.h: make this work with mips 64-bit abi + +1999-08-14 Johan Danielsson + + * fcrypt.c (crypt_md5): don't use snprintf + +1999-08-13 Assar Westerlund + + * Makefile.am: add md5crypt_test + + * Makefile.in: add md5crypt_test + + * md5crypt_test.c: test md5 crypt + + * fcrypt.c: always enable md5 crypt + +1999-07-26 Johan Danielsson + + * Makefile.am: bump version number (changes to md*, sha) + +1999-06-15 Assar Westerlund + + * sha.c (swap_u_int32_t): add _CRAY + +Sat Apr 10 23:02:30 1999 Johan Danielsson + + * destest.c: fixes for crays + +Thu Apr 1 11:26:38 1999 Johan Danielsson + + * Makefile.am: noinst_PROGRAMS -> check_PROGRAMS; add TESTS; don't + build rpw, and speed + +Mon Mar 22 20:16:26 1999 Johan Danielsson + + * Makefile.am: hash.h + + * sha.c: use hash.h; fixes for crays + + * md5.c: use hash.h; fixes for crays + + * md4.c: use hash.h; fixes for crays + + * hash.h: common stuff from md4, md5, and sha1 + +Sat Mar 20 00:16:53 1999 Assar Westerlund + + * rnd_keys.c (des_rand_data): move declaration to get rid of + warning + +Thu Mar 18 11:22:28 1999 Johan Danielsson + + * Makefile.am: include Makefile.am.common + +Mon Mar 15 17:36:41 1999 Johan Danielsson + + * rnd_keys.c (des_rand_data): if not using setitimer, block + SIGCHLD around fork(), also make sure we get the status of the + child process + (fake_signal): emulate signal using sigaction + +Tue Jan 12 05:06:54 1999 Assar Westerlund + + * des.h: sparcv9 is also 64 bits, use `unsigned int' instead of + `unsigned long' + +Sun Nov 22 10:40:09 1998 Assar Westerlund + + * Makefile.in (WFLAGS): set + +Mon May 25 05:24:56 1998 Assar Westerlund + + * Makefile.in (clean): try to remove shared library debris + +Sun Apr 19 09:50:53 1998 Assar Westerlund + + * Makefile.in: add symlink magic for linux + +Sun Nov 9 07:14:45 1997 Assar Westerlund + + * mdtest.c: print out old and new string + diff --git a/third_party/heimdal/lib/hcrypto/DESperate.txt b/third_party/heimdal/lib/hcrypto/DESperate.txt new file mode 100644 index 0000000..3d793e9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/DESperate.txt @@ -0,0 +1,108 @@ +The hunt for getting a DES with plain BSD license w/o advertisement clause +========================================================================== + +$Id$ + +This all feels very silly given that DES is about 30 years old and now +is deprecated. + +Helpful documents on the way: + +Schider's crypto wasn't that useful since it only told how to do DES, +not how to do des fast or how to not use DES. I find this to be a +common thread in the book, it explain each tool in great detail, but +not its limitations. + +Dag Arne Osvik: Efficient Implementation of the Data Encryption Standard + +Some threads on sci.crypto was also useful. + +PC1 transformations +=================== + + +Getting the PC1 bit mangling working was hard, I never got it to work. + +Printning out the bit usage made me realize a lookup table could be +used since only 12 bits are used from the first half and 16 from the +second. + +01110000 01110000 01110000 01110000 01111000 01111000 01111000 01111000 +00001111 00001111 00001111 00001111 00000111 00000111 00000111 00000111 + +The pattern is getting more obvious if it's printed out where the bits +are coming from. + + 8 16 24 - - - - - + 7 15 23 - - - - - + 6 14 22 - - - - - + 5 13 21 - - - - - + 4 12 20 28 - - - - + 3 11 19 27 - - - - + 2 10 18 26 - - - - + 1 9 17 25 - - - - + + - - - 60 56 48 40 - + - - - 59 55 47 39 - + - - - 58 54 46 38 - + - - - 57 53 45 37 - + - - - - 52 44 36 - + - - - - 51 43 35 - + - - - - 50 42 34 - + - - - - 49 41 33 - + +Only 3 bits-table is needed for the first half and 4 bits for the +second half because they are on diffrent shift offsets. + +So to get the bitpattern bit-pattern + +gen_pattern("pc1_c_3", 7, [ 5, 13, 21 ], 0, 0x1000000); +gen_pattern("pc1_c_4", 15, [ 1, 9, 17, 25 ], 0, 0x1000000); +gen_pattern("pc1_d_3", 7, [ 49, 41, 33 ], 32, 0x1000000); +gen_pattern("pc1_d_4", 15, [ 57, 53, 45, 37 ], 32, 0x1000000); + +PC2 transformations +=================== + +PC2 is also a table lookup, since it's a 24 bit field, I use 4 6-bit +lookup tables. Printing the reverse of the PC2 table reveal that some +of the bits are not used, namely (9, 18, 22, 25) from c and (7, 10, +15, 26) from d. + +pc2 from c +---------- + + 5 24 7 16 6 10 20 +18 - 12 3 15 23 1 + 9 19 2 - 14 22 11 + - 13 4 - 17 21 8 + +pc2 from d +---------- + +51 35 31 52 39 45 - +50 32 - 43 36 29 48 + - 41 38 47 33 40 42 +49 37 30 46 - 34 44 + +So we generate tables for that too. + +gen_pattern("pc2_c_1", 63, [ 5, 24, 7, 16, 6, 10 ], 0, 0x800000); +gen_pattern("pc2_c_2", 63, [ 20, 18, 12, 3, 15, 23 ], 0, 0x800000); +gen_pattern("pc2_c_3", 63, [ 1, 9, 19, 2, 14, 22 ], 0, 0x800000); +gen_pattern("pc2_c_4", 63, [ 11, 13, 4, 17, 21, 8 ], 0, 0x800000); + +gen_pattern("pc2_d_1", 63, [ 51, 35, 31, 52, 39, 45 ], 28, 0x800000); +gen_pattern("pc2_d_2", 63, [ 50, 32, 43, 36, 29, 48 ], 28, 0x800000); +gen_pattern("pc2_d_3", 63, [ 41, 38, 47, 33, 40, 42 ], 28, 0x800000); +gen_pattern("pc2_d_4", 63, [ 49, 37, 30, 46, 34, 44 ], 28, 0x800000); + + +SBOX transformations +==================== + +The SBOX transformations are 6 bit to 4 bit transformations. + +Here I grew tired and used Richard Outerbridge SBOXes. Thank you +Richard. + diff --git a/third_party/heimdal/lib/hcrypto/Makefile.am b/third_party/heimdal/lib/hcrypto/Makefile.am new file mode 100644 index 0000000..878525c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/Makefile.am @@ -0,0 +1,424 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +AUTOMAKE_OPTIONS = subdir-objects + +if HAVE_HCRYPTO_W_OPENSSL +AM_CPPFLAGS += $(INCLUDE_openssl_crypto) +endif + +AM_CPPFLAGS += -I$(top_srcdir)/lib/hx509 \ + -I$(srcdir)/libtommath -DUSE_HCRYPTO_LTM=1 \ + -I$(srcdir)/x25519 \ + -I$(srcdir)/.. + +WFLAGS += $(WFLAGS_LITE) -Wno-error=unused-function +# XXX: Make these not necessary: +WFLAGS += -Wno-error=unused-result -Wno-error=deprecated-declarations +WFLAGS += $(WFLAGS_UNUSED_BUT_SET_VAR) + +lib_LTLIBRARIES = libhcrypto.la +check_LTLIBRARIES = libhctest.la + +libhcrypto_la_LDFLAGS = -version-info 5:0:0 +libhcrypto_la_LIBADD = \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_dlopen) \ + $(LIB_heimbase) \ + $(LIBADD_roken) + +if HAVE_HCRYPTO_W_OPENSSL +libhcrypto_la_LIBADD += $(LIB_openssl_crypto) +endif + +hcryptoincludedir = $(includedir)/hcrypto +buildhcryptoinclude = $(buildinclude)/hcrypto + +hcryptoinclude_HEADERS = \ + aes.h \ + bn.h \ + des.h \ + dh.h \ + dsa.h \ + ec.h \ + ecdh.h \ + ecdsa.h \ + engine.h \ + evp.h \ + evp-hcrypto.h \ + evp-cc.h \ + evp-openssl.h \ + evp-pkcs11.h \ + hmac.h \ + md4.h \ + md5.h \ + pkcs12.h \ + rand.h \ + rc2.h \ + rc4.h \ + rsa.h \ + sha.h \ + ui.h \ + undef.h + +install-build-headers:: $(hcryptoinclude_HEADERS) $(x25519include_HEADERS) + @foo='$(hcryptoinclude_HEADERS)'; \ + for f in $$foo; do \ + f=`basename $$f`; \ + if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \ + else file="$$f"; fi; \ + if cmp -s $$file $(buildhcryptoinclude)/$$f 2> /dev/null ; then \ + : ; else \ + echo "cp $$file $(buildhcryptoinclude)/$$f";\ + cp $$file $(buildhcryptoinclude)/$$f; \ + fi ; \ + done + +PROGRAM_TESTS = \ + destest \ + mdtest \ + rc2test \ + rctest \ + test_bn \ + test_bulk \ + test_cipher \ + test_engine_dso \ + test_hmac \ + test_pkcs12 \ + test_pkcs5 + +libhctest_la_SOURCES = \ + des-tables.h \ + des.c \ + des.h \ + ui.c \ + ui.h + +destest_LDADD = libhctest.la $(LIB_roken) + +SCRIPT_TESTS = \ + test_crypto + +noinst_PROGRAMS = test_rand + +noinst_HEADERS = \ + x25519/ed25519_ref10_fe_51.h \ + x25519/ed25519_ref10_fe_25_5.h \ + x25519/ed25519_ref10.h \ + x25519/fe_25_5/base.h \ + x25519/fe_25_5/base2.h \ + x25519/fe_25_5/constants.h \ + x25519/fe_25_5/fe.h \ + x25519/fe_51/base.h \ + x25519/fe_51/base2.h \ + x25519/fe_51/constants.h \ + x25519/fe_51/fe.h \ + x25519/align.h \ + x25519_ref10.h + + +check_PROGRAMS = $(PROGRAM_TESTS) test_rsa test_dh example_evp_cipher +check_SCRIPTS = $(SCRIPT_TESTS) + +TESTS = $(PROGRAM_TESTS) $(SCRIPT_TESTS) + +LDADD = $(lib_LTLIBRARIES) $(LIB_roken) $(LIB_openssl_crypto) +test_rand_LDADD = $(LDADD) -lm + +libhcrypto_la_SOURCES = \ + $(ltmsources) \ + $(x25519sources)\ + aes.c \ + aes.h \ + bn.c \ + bn.h \ + common.c \ + common.h \ + camellia.h \ + camellia.c \ + camellia-ntt.c \ + camellia-ntt.h \ + des-tables.h \ + des.c \ + des.h \ + dh.c \ + dh.h \ + dh-ltm.c \ + dsa.c \ + dsa.h \ + doxygen.c \ + evp.c \ + evp.h \ + evp-hcrypto.c \ + evp-cc.c \ + evp-openssl.c \ + evp-pkcs11.c \ + engine.c \ + engine.h \ + hash.h \ + hmac.c \ + hmac.h \ + md4.c \ + md4.h \ + md5.c \ + md5.h \ + pkcs5.c \ + pkcs12.c \ + rand-fortuna.c \ + rand-timer.c \ + rand-unix.c \ + rand.c \ + rand.h \ + randi.h \ + rc2.c \ + rc2.h \ + rc4.c \ + rc4.h \ + rijndael-alg-fst.c \ + rijndael-alg-fst.h \ + rnd_keys.c \ + rsa.c \ + rsa-gmp.c \ + rsa-ltm.c \ + rsa.h \ + sha.c \ + sha.h \ + sha256.c \ + sha512.c \ + validate.c \ + ui.c \ + ui.h \ + undef.h + +ltmsources = \ + libtommath/bn_cutoffs.c \ + libtommath/bn_deprecated.c \ + libtommath/bn_mp_2expt.c \ + libtommath/bn_mp_abs.c \ + libtommath/bn_mp_add.c \ + libtommath/bn_mp_add_d.c \ + libtommath/bn_mp_addmod.c \ + libtommath/bn_mp_and.c \ + libtommath/bn_mp_clamp.c \ + libtommath/bn_mp_clear.c \ + libtommath/bn_mp_clear_multi.c \ + libtommath/bn_mp_cmp.c \ + libtommath/bn_mp_cmp_d.c \ + libtommath/bn_mp_cmp_mag.c \ + libtommath/bn_mp_cnt_lsb.c \ + libtommath/bn_mp_complement.c \ + libtommath/bn_mp_copy.c \ + libtommath/bn_mp_count_bits.c \ + libtommath/bn_mp_decr.c \ + libtommath/bn_mp_div.c \ + libtommath/bn_mp_div_2.c \ + libtommath/bn_mp_div_2d.c \ + libtommath/bn_mp_div_3.c \ + libtommath/bn_mp_div_d.c \ + libtommath/bn_mp_dr_is_modulus.c \ + libtommath/bn_mp_dr_reduce.c \ + libtommath/bn_mp_dr_setup.c \ + libtommath/bn_mp_error_to_string.c \ + libtommath/bn_mp_exch.c \ + libtommath/bn_mp_expt_u32.c \ + libtommath/bn_mp_exptmod.c \ + libtommath/bn_mp_exteuclid.c \ + libtommath/bn_mp_fread.c \ + libtommath/bn_mp_from_sbin.c \ + libtommath/bn_mp_from_ubin.c \ + libtommath/bn_mp_fwrite.c \ + libtommath/bn_mp_gcd.c \ + libtommath/bn_mp_get_double.c \ + libtommath/bn_mp_get_i32.c \ + libtommath/bn_mp_get_i64.c \ + libtommath/bn_mp_get_l.c \ + libtommath/bn_mp_get_ll.c \ + libtommath/bn_mp_get_mag_u32.c \ + libtommath/bn_mp_get_mag_u64.c \ + libtommath/bn_mp_get_mag_ul.c \ + libtommath/bn_mp_get_mag_ull.c \ + libtommath/bn_mp_grow.c \ + libtommath/bn_mp_incr.c \ + libtommath/bn_mp_init.c \ + libtommath/bn_mp_init_copy.c \ + libtommath/bn_mp_init_i32.c \ + libtommath/bn_mp_init_i64.c \ + libtommath/bn_mp_init_l.c \ + libtommath/bn_mp_init_ll.c \ + libtommath/bn_mp_init_multi.c \ + libtommath/bn_mp_init_set.c \ + libtommath/bn_mp_init_size.c \ + libtommath/bn_mp_init_u32.c \ + libtommath/bn_mp_init_u64.c \ + libtommath/bn_mp_init_ul.c \ + libtommath/bn_mp_init_ull.c \ + libtommath/bn_mp_invmod.c \ + libtommath/bn_mp_is_square.c \ + libtommath/bn_mp_iseven.c \ + libtommath/bn_mp_isodd.c \ + libtommath/bn_mp_kronecker.c \ + libtommath/bn_mp_lcm.c \ + libtommath/bn_mp_log_u32.c \ + libtommath/bn_mp_lshd.c \ + libtommath/bn_mp_mod.c \ + libtommath/bn_mp_mod_2d.c \ + libtommath/bn_mp_mod_d.c \ + libtommath/bn_mp_montgomery_calc_normalization.c \ + libtommath/bn_mp_montgomery_reduce.c \ + libtommath/bn_mp_montgomery_setup.c \ + libtommath/bn_mp_mul.c \ + libtommath/bn_mp_mul_2.c \ + libtommath/bn_mp_mul_2d.c \ + libtommath/bn_mp_mul_d.c \ + libtommath/bn_mp_mulmod.c \ + libtommath/bn_mp_neg.c \ + libtommath/bn_mp_or.c \ + libtommath/bn_mp_pack.c \ + libtommath/bn_mp_pack_count.c \ + libtommath/bn_mp_prime_fermat.c \ + libtommath/bn_mp_prime_frobenius_underwood.c \ + libtommath/bn_mp_prime_is_prime.c \ + libtommath/bn_mp_prime_miller_rabin.c \ + libtommath/bn_mp_prime_next_prime.c \ + libtommath/bn_mp_prime_rabin_miller_trials.c \ + libtommath/bn_mp_prime_rand.c \ + libtommath/bn_mp_prime_strong_lucas_selfridge.c \ + libtommath/bn_mp_radix_size.c \ + libtommath/bn_mp_radix_smap.c \ + libtommath/bn_mp_rand.c \ + libtommath/bn_mp_read_radix.c \ + libtommath/bn_mp_reduce.c \ + libtommath/bn_mp_reduce_2k.c \ + libtommath/bn_mp_reduce_2k_l.c \ + libtommath/bn_mp_reduce_2k_setup.c \ + libtommath/bn_mp_reduce_2k_setup_l.c \ + libtommath/bn_mp_reduce_is_2k.c \ + libtommath/bn_mp_reduce_is_2k_l.c \ + libtommath/bn_mp_reduce_setup.c \ + libtommath/bn_mp_root_u32.c \ + libtommath/bn_mp_rshd.c \ + libtommath/bn_mp_sbin_size.c \ + libtommath/bn_mp_set.c \ + libtommath/bn_mp_set_double.c \ + libtommath/bn_mp_set_i32.c \ + libtommath/bn_mp_set_i64.c \ + libtommath/bn_mp_set_l.c \ + libtommath/bn_mp_set_ll.c \ + libtommath/bn_mp_set_u32.c \ + libtommath/bn_mp_set_u64.c \ + libtommath/bn_mp_set_ul.c \ + libtommath/bn_mp_set_ull.c \ + libtommath/bn_mp_shrink.c \ + libtommath/bn_mp_signed_rsh.c \ + libtommath/bn_mp_sqr.c \ + libtommath/bn_mp_sqrmod.c \ + libtommath/bn_mp_sqrt.c \ + libtommath/bn_mp_sqrtmod_prime.c \ + libtommath/bn_mp_sub.c \ + libtommath/bn_mp_sub_d.c \ + libtommath/bn_mp_submod.c \ + libtommath/bn_mp_to_radix.c \ + libtommath/bn_mp_to_sbin.c \ + libtommath/bn_mp_to_ubin.c \ + libtommath/bn_mp_ubin_size.c \ + libtommath/bn_mp_unpack.c \ + libtommath/bn_mp_xor.c \ + libtommath/bn_mp_zero.c \ + libtommath/bn_prime_tab.c \ + libtommath/bn_s_mp_add.c \ + libtommath/bn_s_mp_balance_mul.c \ + libtommath/bn_s_mp_exptmod.c \ + libtommath/bn_s_mp_exptmod_fast.c \ + libtommath/bn_s_mp_get_bit.c \ + libtommath/bn_s_mp_invmod_fast.c \ + libtommath/bn_s_mp_invmod_slow.c \ + libtommath/bn_s_mp_karatsuba_mul.c \ + libtommath/bn_s_mp_karatsuba_sqr.c \ + libtommath/bn_s_mp_montgomery_reduce_fast.c \ + libtommath/bn_s_mp_mul_digs.c \ + libtommath/bn_s_mp_mul_digs_fast.c \ + libtommath/bn_s_mp_mul_high_digs.c \ + libtommath/bn_s_mp_mul_high_digs_fast.c \ + libtommath/bn_s_mp_prime_is_divisible.c \ + libtommath/bn_s_mp_rand_jenkins.c \ + libtommath/bn_s_mp_rand_platform.c \ + libtommath/bn_s_mp_reverse.c \ + libtommath/bn_s_mp_sqr.c \ + libtommath/bn_s_mp_sqr_fast.c \ + libtommath/bn_s_mp_sub.c \ + libtommath/bn_s_mp_toom_mul.c \ + libtommath/bn_s_mp_toom_sqr.c \ + libtommath/tommath_private.h \ + libtommath/tommath_cutoffs.h \ + libtommath/tommath_superclass.h \ + libtommath/tommath_class.h \ + libtommath/tommath.h + +x25519sources = \ + x25519/ed25519_ref10.c \ + x25519/x25519_ref10.c + +$(libhcrypto_la_OBJECTS) $(test_rand_OBJECTS): hcrypto-link + +libhcrypto_la_CPPFLAGS = -DBUILD_HCRYPTO_LIB $(AM_CPPFLAGS) + +if versionscript +libhcrypto_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif +$(libhcrypto_la_OBJECTS): $(srcdir)/version-script.map + + +hcrypto-link: + $(LN_S) $(srcdir)/../hcrypto hcrypto + touch hcrypto-link + +do_subst = sed -e 's,[@]srcdir[@],$(srcdir),g' -e 's,[@]exeext[@],$(exeext),g' + +test_crypto: test_crypto.in Makefile + $(do_subst) < $(srcdir)/test_crypto.in > test_crypto.tmp + chmod +x test_crypto.tmp + mv test_crypto.tmp test_crypto + +CLEANFILES = \ + crypto-test \ + crypto-test2 \ + error \ + hcrypto \ + hcrypto-link \ + test.file \ + test_crypto \ + test-out* \ + test_crypto.tmp \ + test_crypto.tmp + +EXTRA_DIST = \ + NTMakefile \ + DESperate.txt \ + passwd_dialog.rc \ + libhcrypto-exports.def \ + dh-tfm.c \ + ec.h \ + ecdh.h \ + ecdsa.h \ + evp-crypt.c \ + evp-w32.c \ + evp-w32.h \ + evp-wincng.c \ + evp-wincng.h \ + gen-des.pl \ + md5crypt_test.c \ + passwd_dialog.aps \ + passwd_dialog.clw \ + passwd_dialog.rc \ + passwd_dialog.res \ + passwd_dlg.c \ + passwd_dlg.h \ + rand-w32.c \ + resource.h \ + rsa-tfm.c \ + rsakey.der \ + rsakey2048.der \ + rsakey4096.der \ + test_crypto.in \ + version-script.map diff --git a/third_party/heimdal/lib/hcrypto/NTMakefile b/third_party/heimdal/lib/hcrypto/NTMakefile new file mode 100644 index 0000000..e3e50a7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/NTMakefile @@ -0,0 +1,272 @@ +######################################################################## +# +# Copyright (c) 2009-2016, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +SUBDIRS=libtommath x25519 + +RELDIR=lib\hcrypto + +!include ../../windows/NTMakefile.w32 + +HCRYPTOINCLUDEDIR = $(INCDIR)\hcrypto + +HEIMBASEDIR = $(SRC)\lib\base + +HX509DIR = $(SRC)\lib\hx509 + +!ifdef INCLUDE_openssl_crypto +openssl_inc=-I$(INCLUDE_openssl_crypto) +!endif + +intcflags=-DKRB5 -DASN1_LIB -I$(HCRYPTOINCLUDEDIR) -DUSE_HCRYPTO_LTM=1 \ + -I$(HX509DIR) $(openssl_inc) + +# Do dependencies first + +all:: subdirs + +clean:: clean-subdirs + +test:: test-subdirs + +# Include files + +INCFILES= \ + $(HCRYPTOINCLUDEDIR)\aes.h \ + $(HCRYPTOINCLUDEDIR)\bn.h \ + $(HCRYPTOINCLUDEDIR)\des.h \ + $(HCRYPTOINCLUDEDIR)\dh.h \ + $(HCRYPTOINCLUDEDIR)\dsa.h \ + $(HCRYPTOINCLUDEDIR)\ec.h \ + $(HCRYPTOINCLUDEDIR)\ecdh.h \ + $(HCRYPTOINCLUDEDIR)\ecdsa.h \ + $(HCRYPTOINCLUDEDIR)\engine.h \ + $(HCRYPTOINCLUDEDIR)\evp.h \ + $(HCRYPTOINCLUDEDIR)\evp-hcrypto.h \ + $(HCRYPTOINCLUDEDIR)\evp-cc.h \ + $(HCRYPTOINCLUDEDIR)\evp-openssl.h \ + $(HCRYPTOINCLUDEDIR)\evp-pkcs11.h \ + $(HCRYPTOINCLUDEDIR)\evp-wincng.h \ + $(HCRYPTOINCLUDEDIR)\evp-w32.h \ + $(HCRYPTOINCLUDEDIR)\hmac.h \ + $(HCRYPTOINCLUDEDIR)\md4.h \ + $(HCRYPTOINCLUDEDIR)\md5.h \ + $(HCRYPTOINCLUDEDIR)\pkcs12.h \ + $(HCRYPTOINCLUDEDIR)\rand.h \ + $(HCRYPTOINCLUDEDIR)\randi.h \ + $(HCRYPTOINCLUDEDIR)\rc2.h \ + $(HCRYPTOINCLUDEDIR)\rc4.h \ + $(HCRYPTOINCLUDEDIR)\rsa.h \ + $(HCRYPTOINCLUDEDIR)\sha.h \ + $(HCRYPTOINCLUDEDIR)\ui.h \ + $(HCRYPTOINCLUDEDIR)\undef.h \ + $(HCRYPTOINCLUDEDIR)\x25519_ref10.h \ + +mkincdir: +!if !exist($(HCRYPTOINCLUDEDIR)) + $(MKDIR) $(HCRYPTOINCLUDEDIR) +!endif + +{}.h{$(HCRYPTOINCLUDEDIR)}.h: + $(CP) $** $@ + +all:: mkincdir + +all:: $(INCFILES) + +# libhcrypto + +libhcrypto_OBJs = \ + $(OBJ)\aes.obj \ + $(OBJ)\bn.obj \ + $(OBJ)\camellia.obj \ + $(OBJ)\camellia-ntt.obj \ + $(OBJ)\common.obj \ + $(OBJ)\des.obj \ + $(OBJ)\dh.obj \ + $(OBJ)\dh-ltm.obj \ + $(OBJ)\dh-tfm.obj \ + $(OBJ)\dsa.obj \ + $(OBJ)\evp.obj \ + $(OBJ)\evp-hcrypto.obj \ + $(OBJ)\evp-cc.obj \ + $(OBJ)\evp-openssl.obj \ + $(OBJ)\evp-pkcs11.obj \ + $(OBJ)\evp-wincng.obj \ + $(OBJ)\evp-w32.obj \ + $(OBJ)\engine.obj \ + $(OBJ)\hmac.obj \ + $(OBJ)\md4.obj \ + $(OBJ)\md5.obj \ + $(OBJ)\pkcs5.obj \ + $(OBJ)\pkcs12.obj \ + $(OBJ)\rand-w32.obj \ + $(OBJ)\rand.obj \ + $(OBJ)\rc2.obj \ + $(OBJ)\rc4.obj \ + $(OBJ)\rijndael-alg-fst.obj \ + $(OBJ)\rnd_keys.obj \ + $(OBJ)\rsa.obj \ + $(OBJ)\rsa-gmp.obj \ + $(OBJ)\rsa-ltm.obj \ + $(OBJ)\rsa-tfm.obj \ + $(OBJ)\sha.obj \ + $(OBJ)\sha256.obj \ + $(OBJ)\sha512.obj \ + $(OBJ)\ui.obj \ + $(OBJ)\validate.obj + +$(LIBHCRYPTO): $(libhcrypto_OBJs) + $(LIBCON) + +all:: $(LIBHCRYPTO) + +clean:: + -$(RM) $(LIBHCRYPTO) + +# Tests + +TESTLIB=$(OBJ)\libhctest.lib + +$(TESTLIB): \ + $(OBJ)\des.obj \ + $(OBJ)\ui.obj + $(LIBCON) + +test-binaries: \ + $(OBJ)\destest.exe \ + $(OBJ)\example_evp_cipher.exe \ + $(OBJ)\mdtest.exe \ + $(OBJ)\rc2test.exe \ + $(OBJ)\rctest.exe \ + $(OBJ)\test_bn.exe \ + $(OBJ)\test_bulk.exe \ + $(OBJ)\test_cipher.exe \ + $(OBJ)\test_engine_dso.exe \ + $(OBJ)\test_hmac.exe \ + $(OBJ)\test_pkcs5.exe \ + $(OBJ)\test_pkcs12.exe \ + $(OBJ)\test_rsa.exe \ + $(OBJ)\test_dh.exe \ + $(OBJ)\test_rand.exe \ + $(OBJ)\test_crypto.sh + +$(OBJ)\destest.exe: $(OBJ)\destest.obj $(TESTLIB) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\example_evp_cipher.exe: $(OBJ)\example_evp_cipher.obj $(TESTLIB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\mdtest.exe: $(OBJ)\mdtest.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(OBJ)\sha512.obj + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\rc2test.exe: $(OBJ)\rc2test.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\rctest.exe: $(OBJ)\rctest.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_bn.exe: $(OBJ)\test_bn.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_bulk.exe: $(OBJ)\test_bulk.obj $(TESTLIB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_cipher.exe: $(OBJ)\test_cipher.obj $(TESTLIB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_engine_dso.exe: $(OBJ)\test_engine_dso.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_hmac.exe: $(OBJ)\test_hmac.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_pkcs5.exe: $(OBJ)\test_pkcs5.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_pkcs12.exe: $(OBJ)\test_pkcs12.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_rsa.exe: $(OBJ)\test_rsa.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_dh.exe: $(OBJ)\test_dh.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_rand.exe: $(OBJ)\test_rand.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHEIMBASE) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +SRCDIR2=$(SRCDIR:\=\\\\) + +$(OBJ)\test_crypto.sh: test_crypto.in NTMakefile + $(SED) -e "s,[@]srcdir[@],$(SRCDIR2),g" -e "s,[@]exeext[@],.exe,g" -e "s,\r,," < test_crypto.in > $@ || $(RM) $@ + +test-run: + cd $(OBJ) +!ifdef SH + -$(SH) test_crypto.sh +!endif + -destest.exe + -mdtest.exe + -rc2test.exe + -rctest.exe + -test_bn.exe + -test_bulk.exe --provider=hcrypto + -test_bulk.exe --provider=w32crypto + -test_cipher.exe + -test_engine_dso.exe + -test_hmac.exe + -test_pkcs5.exe + -test_pkcs12.exe + -test_rsa.exe + -test_dh.exe + cd $(SRCDIR) + +test:: $(TESTLIB) test-binaries test-run + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libhcrypto-exports.def + +test:: test-exports diff --git a/third_party/heimdal/lib/hcrypto/aes.c b/third_party/heimdal/lib/hcrypto/aes.c new file mode 100644 index 0000000..2e15d5d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/aes.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#ifdef KRB5 +#include +#endif + +#include "rijndael-alg-fst.h" +#include "aes.h" + +int +AES_set_encrypt_key(const unsigned char *userkey, const int bits, AES_KEY *key) +{ + key->rounds = rijndaelKeySetupEnc(key->key, userkey, bits); + if (key->rounds == 0) + return -1; + return 0; +} + +int +AES_set_decrypt_key(const unsigned char *userkey, const int bits, AES_KEY *key) +{ + key->rounds = rijndaelKeySetupDec(key->key, userkey, bits); + if (key->rounds == 0) + return -1; + return 0; +} + +void +AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key) +{ + rijndaelEncrypt(key->key, key->rounds, in, out); +} + +void +AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key) +{ + rijndaelDecrypt(key->key, key->rounds, in, out); +} + +void +AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + unsigned long size, const AES_KEY *key, + unsigned char *iv, int forward_encrypt) +{ + unsigned char tmp[AES_BLOCK_SIZE]; + int i; + + if (forward_encrypt) { + while (size >= AES_BLOCK_SIZE) { + for (i = 0; i < AES_BLOCK_SIZE; i++) + tmp[i] = in[i] ^ iv[i]; + AES_encrypt(tmp, out, key); + memcpy(iv, out, AES_BLOCK_SIZE); + size -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (size) { + for (i = 0; i < size; i++) + tmp[i] = in[i] ^ iv[i]; + for (i = size; i < AES_BLOCK_SIZE; i++) + tmp[i] = iv[i]; + AES_encrypt(tmp, out, key); + memcpy(iv, out, AES_BLOCK_SIZE); + } + } else { + while (size >= AES_BLOCK_SIZE) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, out, key); + for (i = 0; i < AES_BLOCK_SIZE; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + size -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (size) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, out, key); + for (i = 0; i < size; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + } + } +} + +void +AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, + unsigned long size, const AES_KEY *key, + unsigned char *iv, int forward_encrypt) +{ + int i; + + for (i = 0; i < size; i++) { + unsigned char tmp[AES_BLOCK_SIZE + 1]; + + memcpy(tmp, iv, AES_BLOCK_SIZE); + AES_encrypt(iv, iv, key); + if (!forward_encrypt) { + tmp[AES_BLOCK_SIZE] = in[i]; + } + out[i] = in[i] ^ iv[0]; + if (forward_encrypt) { + tmp[AES_BLOCK_SIZE] = out[i]; + } + memcpy(iv, &tmp[1], AES_BLOCK_SIZE); + } +} diff --git a/third_party/heimdal/lib/hcrypto/aes.h b/third_party/heimdal/lib/hcrypto/aes.h new file mode 100644 index 0000000..4ba4516 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/aes.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_AES_H +#define HEIM_AES_H 1 + +/* symbol renaming */ +#define AES_set_encrypt_key hc_AES_set_encrypt_key +#define AES_set_decrypt_key hc_AES_decrypt_key +#define AES_encrypt hc_AES_encrypt +#define AES_decrypt hc_AES_decrypt +#define AES_cbc_encrypt hc_AES_cbc_encrypt +#define AES_cfb8_encrypt hc_AES_cfb8_encrypt + +/* + * + */ + +#define AES_BLOCK_SIZE 16 +#define AES_MAXNR 14 + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +typedef struct aes_key { + uint32_t key[(AES_MAXNR+1)*4]; + int rounds; +} AES_KEY; + +#ifdef __cplusplus +extern "C" { +#endif + +int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *); +int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *); + +void AES_encrypt(const unsigned char *, unsigned char *, const AES_KEY *); +void AES_decrypt(const unsigned char *, unsigned char *, const AES_KEY *); + +void AES_cbc_encrypt(const unsigned char *, unsigned char *, + unsigned long, const AES_KEY *, + unsigned char *, int); +void AES_cfb8_encrypt(const unsigned char *, unsigned char *, + unsigned long, const AES_KEY *, + unsigned char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* HEIM_AES_H */ diff --git a/third_party/heimdal/lib/hcrypto/bn.c b/third_party/heimdal/lib/hcrypto/bn.c new file mode 100644 index 0000000..9e9db4e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/bn.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include /* XXX */ +#include + +#include +#include +#include + +BIGNUM * +BN_new(void) +{ + heim_integer *hi; + hi = calloc(1, sizeof(*hi)); + return (BIGNUM *)hi; +} + +void +BN_free(BIGNUM *bn) +{ + BN_clear(bn); + free(bn); +} + +void +BN_clear(BIGNUM *bn) +{ + heim_integer *hi = (heim_integer *)bn; + if (hi->data) { + memset(hi->data, 0, hi->length); + free(hi->data); + } + memset(hi, 0, sizeof(*hi)); +} + +void +BN_clear_free(BIGNUM *bn) +{ + BN_free(bn); +} + +BIGNUM * +BN_dup(const BIGNUM *bn) +{ + BIGNUM *b = BN_new(); + if (der_copy_heim_integer((const heim_integer *)bn, (heim_integer *)b)) { + BN_free(b); + return NULL; + } + return b; +} + +/* + * If the caller really want to know the number of bits used, subtract + * one from the length, multiply by 8, and then lookup in the table + * how many bits the hightest byte uses. + */ +int +BN_num_bits(const BIGNUM *bn) +{ + static unsigned char num2bits[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + }; + const heim_integer *i = (const void *)bn; + if (i->length == 0) + return 0; + return (i->length - 1) * 8 + num2bits[((unsigned char *)i->data)[0]]; +} + +int +BN_num_bytes(const BIGNUM *bn) +{ + return ((const heim_integer *)bn)->length; +} + +/* + * Ignore negative flag. + */ + +BIGNUM * +BN_bin2bn(const void *s, int len, BIGNUM *bn) +{ + heim_integer *hi = (void *)bn; + + if (len < 0) + return NULL; + + if (hi == NULL) { + hi = (heim_integer *)BN_new(); + if (hi == NULL) + return NULL; + } + if (hi->data) + BN_clear((BIGNUM *)hi); + hi->negative = 0; + hi->data = malloc(len); + if (hi->data == NULL && len != 0) { + if (bn == NULL) + BN_free((BIGNUM *)hi); + return NULL; + } + hi->length = len; + if (len) + memcpy(hi->data, s, len); + return (BIGNUM *)hi; +} + +int +BN_bn2bin(const BIGNUM *bn, void *to) +{ + const heim_integer *hi = (const void *)bn; + memcpy(to, hi->data, hi->length); + return hi->length; +} + +int +BN_hex2bn(BIGNUM **bnp, const char *in) +{ + int negative; + ssize_t ret; + size_t len; + void *data; + + len = strlen(in); + data = malloc(len); + if (data == NULL) + return 0; + + if (*in == '-') { + negative = 1; + in++; + } else + negative = 0; + + ret = hex_decode(in, data, len); + if (ret < 0) { + free(data); + return 0; + } + + *bnp = BN_bin2bn(data, ret, NULL); + free(data); + if (*bnp == NULL) + return 0; + BN_set_negative(*bnp, negative); + return 1; +} + +char * +BN_bn2hex(const BIGNUM *bn) +{ + ssize_t ret; + size_t len; + void *data; + char *str; + + len = BN_num_bytes(bn); + data = malloc(len); + if (data == NULL) + return 0; + + len = BN_bn2bin(bn, data); + + ret = hex_encode(data, len, &str); + free(data); + if (ret < 0) + return 0; + + return str; +} + +int +BN_cmp(const BIGNUM *bn1, const BIGNUM *bn2) +{ + return der_heim_integer_cmp((const heim_integer *)bn1, + (const heim_integer *)bn2); +} + +void +BN_set_negative(BIGNUM *bn, int flag) +{ + ((heim_integer *)bn)->negative = (flag ? 1 : 0); +} + +int +BN_is_negative(const BIGNUM *bn) +{ + return ((const heim_integer *)bn)->negative ? 1 : 0; +} + +static const unsigned char is_set[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +int +BN_is_bit_set(const BIGNUM *bn, int bit) +{ + const heim_integer *hi = (const heim_integer *)bn; + unsigned char *p = hi->data; + + if ((bit / 8) >= hi->length || hi->length == 0) + return 0; + + return p[hi->length - 1 - (bit / 8)] & is_set[bit % 8]; +} + +int +BN_set_bit(BIGNUM *bn, int bit) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned char *p; + + if ((bit / 8) > hi->length || hi->length == 0) { + size_t len = bit == 0 ? 1 : (bit + 7) / 8; + void *d = realloc(hi->data, len); + if (d == NULL) + return 0; + hi->data = d; + p = hi->data; + memset(&p[hi->length], 0, len); + hi->length = len; + } else + p = hi->data; + + p[hi->length - 1 - (bit / 8)] |= is_set[bit % 8]; + return 1; +} + +int +BN_clear_bit(BIGNUM *bn, int bit) +{ + heim_integer *hi = (heim_integer *)bn; + unsigned char *p = hi->data; + + if ((bit / 8) > hi->length || hi->length == 0) + return 0; + + p[hi->length - 1 - (bit / 8)] &= (unsigned char)(~(is_set[bit % 8])); + + return 1; +} + +int +BN_set_word(BIGNUM *bn, unsigned long num) +{ + unsigned char p[sizeof(num)]; + unsigned long num2; + int i, len; + + if (bn == NULL) + return 0; + + for (num2 = num, i = 0; num2 > 0; i++) + num2 = num2 >> 8; + + len = i; + for (; i > 0; i--) { + p[i - 1] = (num & 0xff); + num = num >> 8; + } + + bn = BN_bin2bn(p, len, bn); + return bn != NULL; +} + +unsigned long +BN_get_word(const BIGNUM *bn) +{ + const heim_integer *hi = (const heim_integer *)bn; + unsigned long num = 0; + int i; + + if (hi->negative || hi->length > sizeof(num)) + return ULONG_MAX; + + for (i = 0; i < hi->length; i++) + num = ((unsigned char *)hi->data)[i] | (num << 8); + return num; +} + +int +BN_rand(BIGNUM *bn, int bits, int top, int bottom) +{ + size_t len = (bits + 7) / 8; + heim_integer *i = (heim_integer *)bn; + + BN_clear(bn); + + i->negative = 0; + i->data = malloc(len); + if (i->data == NULL && len != 0) + return 0; + i->length = len; + + if (RAND_bytes(i->data, i->length) != 1) { + free(i->data); + i->data = NULL; + return 0; + } + + { + size_t j = len * 8; + while(j > bits) { + BN_clear_bit(bn, j - 1); + j--; + } + } + + if (top == -1) { + ; + } else if (top == 0 && bits > 0) { + BN_set_bit(bn, bits - 1); + } else if (top == 1 && bits > 1) { + BN_set_bit(bn, bits - 1); + BN_set_bit(bn, bits - 2); + } else { + BN_clear(bn); + return 0; + } + + if (bottom && bits > 0) + BN_set_bit(bn, 0); + + return 1; +} + +/* + * + */ + +int +BN_uadd(BIGNUM *res, const BIGNUM *a, const BIGNUM *b) +{ + const heim_integer *ai = (const heim_integer *)a; + const heim_integer *bi = (const heim_integer *)b; + const unsigned char *ap, *bp; + unsigned char *cp; + heim_integer ci; + int carry = 0; + ssize_t len; + + if (ai->negative && bi->negative) + return 0; + if (ai->length < bi->length) { + const heim_integer *si = bi; + bi = ai; ai = si; + } + + ci.negative = 0; + ci.length = ai->length + 1; + ci.data = malloc(ci.length); + if (ci.data == NULL) + return 0; + + ap = &((const unsigned char *)ai->data)[ai->length - 1]; + bp = &((const unsigned char *)bi->data)[bi->length - 1]; + cp = &((unsigned char *)ci.data)[ci.length - 1]; + + for (len = bi->length; len > 0; len--) { + carry = *ap + *bp + carry; + *cp = carry & 0xff; + carry = (carry & ~0xff) ? 1 : 0; + ap--; bp--; cp--; + } + for (len = ai->length - bi->length; len > 0; len--) { + carry = *ap + carry; + *cp = carry & 0xff; + carry = (carry & ~0xff) ? 1 : 0; + ap--; cp--; + } + if (!carry) + memmove(cp, cp + 1, --ci.length); + else + *cp = carry; + + BN_clear(res); + *((heim_integer *)res) = ci; + + return 1; +} + + +/* + * Callback when doing slow generation of numbers, like primes. + */ + +void +BN_GENCB_set(BN_GENCB *gencb, int (*cb_2)(int, int, BN_GENCB *), void *ctx) +{ + gencb->ver = 2; + gencb->cb.cb_2 = cb_2; + gencb->arg = ctx; +} + +int +BN_GENCB_call(BN_GENCB *cb, int a, int b) +{ + if (cb == NULL || cb->cb.cb_2 == NULL) + return 1; + return cb->cb.cb_2(a, b, cb); +} + +/* + * + */ + +struct BN_CTX { + struct { + BIGNUM **val; + size_t used; + size_t len; + } bn; + struct { + size_t *val; + size_t used; + size_t len; + } stack; +}; + +BN_CTX * +BN_CTX_new(void) +{ + struct BN_CTX *c; + c = calloc(1, sizeof(*c)); + return c; +} + +void +BN_CTX_free(BN_CTX *c) +{ + size_t i; + for (i = 0; i < c->bn.len; i++) + BN_free(c->bn.val[i]); + free(c->bn.val); + free(c->stack.val); +} + +BIGNUM * +BN_CTX_get(BN_CTX *c) +{ + if (c->bn.used == c->bn.len) { + void *ptr; + size_t i; + c->bn.len += 16; + ptr = realloc(c->bn.val, c->bn.len * sizeof(c->bn.val[0])); + if (ptr == NULL) + return NULL; + c->bn.val = ptr; + for (i = c->bn.used; i < c->bn.len; i++) { + c->bn.val[i] = BN_new(); + if (c->bn.val[i] == NULL) { + c->bn.len = i; + return NULL; + } + } + } + return c->bn.val[c->bn.used++]; +} + +void +BN_CTX_start(BN_CTX *c) +{ + if (c->stack.used == c->stack.len) { + void *ptr; + c->stack.len += 16; + ptr = realloc(c->stack.val, c->stack.len * sizeof(c->stack.val[0])); + if (ptr == NULL) + abort(); + c->stack.val = ptr; + } + c->stack.val[c->stack.used++] = c->bn.used; +} + +void +BN_CTX_end(BN_CTX *c) +{ + const size_t prev = c->stack.val[c->stack.used - 1]; + size_t i; + + if (c->stack.used == 0) + abort(); + + for (i = prev; i < c->bn.used; i++) + BN_clear(c->bn.val[i]); + + c->stack.used--; + c->bn.used = prev; +} + diff --git a/third_party/heimdal/lib/hcrypto/bn.h b/third_party/heimdal/lib/hcrypto/bn.h new file mode 100644 index 0000000..727b919 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/bn.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_BN_H +#define _HEIM_BN_H 1 + +/* symbol renaming */ +#define BN_GENCB_call hc_BN_GENCB_call +#define BN_GENCB_set hc_BN_GENCB_set +#define BN_bin2bn hc_BN_bin2bn +#define BN_bn2bin hc_BN_bn2bin +#define BN_bn2hex hc_BN_bn2hex +#define BN_clear hc_BN_clear +#define BN_clear_bit hc_BN_clear_bit +#define BN_clear_free hc_BN_clear_free +#define BN_cmp hc_BN_cmp +#define BN_dup hc_BN_dup +#define BN_free hc_BN_free +#define BN_is_negative hc_BN_is_negative +#define BN_get_word hc_BN_get_word +#define BN_hex2bn hc_BN_hex2bn +#define BN_is_bit_set hc_BN_is_bit_set +#define BN_new hc_BN_new +#define BN_num_bits hc_BN_num_bits +#define BN_num_bytes hc_BN_num_bytes +#define BN_rand hc_BN_rand +#define BN_set_bit hc_BN_set_bit +#define BN_set_negative hc_BN_set_negative +#define BN_set_word hc_BN_set_word +#define BN_uadd hc_BN_uadd +#define BN_CTX_new hc_BN_CTX_new +#define BN_CTX_free hc_BN_CTX_free +#define BN_CTX_get hc_BN_CTX_get +#define BN_CTX_start hc_BN_CTX_start +#define BN_CTX_end hc_BN_CTX_end + +#define BIGNUM hc_BIGNUM +#define BN_GENCB hc_BN_GENCB +#define BN_CTX hc_BN_CTX +#define BN_BLINDING hc_BN_BLINDING +#define BN_MONT_CTX hc_BN_MONT_CTX + + +/* + * + */ + +typedef struct BIGNUM BIGNUM; +typedef struct BN_GENCB BN_GENCB; +typedef struct BN_CTX BN_CTX; +typedef struct BN_MONT_CTX BN_MONT_CTX; +typedef struct BN_BLINDING BN_BLINDING; + +struct BN_GENCB { + unsigned int ver; + void *arg; + union { + int (*cb_2)(int, int, BN_GENCB *); + } cb; +}; + +/* + * + */ + +BIGNUM *BN_new(void); +void BN_free(BIGNUM *); +void BN_clear_free(BIGNUM *); +void BN_clear(BIGNUM *); +BIGNUM *BN_dup(const BIGNUM *); + +int BN_num_bits(const BIGNUM *); +int BN_num_bytes(const BIGNUM *); + +int BN_cmp(const BIGNUM *, const BIGNUM *); + +void BN_set_negative(BIGNUM *, int); +int BN_is_negative(const BIGNUM *); + +int BN_is_bit_set(const BIGNUM *, int); +int BN_set_bit(BIGNUM *, int); +int BN_clear_bit(BIGNUM *, int); + +int BN_set_word(BIGNUM *, unsigned long); +unsigned long BN_get_word(const BIGNUM *); + +BIGNUM *BN_bin2bn(const void *,int len,BIGNUM *); +int BN_bn2bin(const BIGNUM *, void *); +int BN_hex2bn(BIGNUM **, const char *); +char * BN_bn2hex(const BIGNUM *); + +int BN_uadd(BIGNUM *, const BIGNUM *, const BIGNUM *); + +int BN_rand(BIGNUM *, int, int, int); + +void BN_GENCB_set(BN_GENCB *, int (*)(int, int, BN_GENCB *), void *); +int BN_GENCB_call(BN_GENCB *, int, int); + +BN_CTX *BN_CTX_new(void); +void BN_CTX_free(BN_CTX *); +BIGNUM *BN_CTX_get(BN_CTX *); +void BN_CTX_start(BN_CTX *); +void BN_CTX_end(BN_CTX *); + +#endif diff --git a/third_party/heimdal/lib/hcrypto/camellia-ntt.c b/third_party/heimdal/lib/hcrypto/camellia-ntt.c new file mode 100644 index 0000000..66873c2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/camellia-ntt.c @@ -0,0 +1,1458 @@ +/* camellia.h ver 1.2.0 + * + * Copyright (C) 2006,2007 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Algorithm Specification + * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html + */ + +#include +#include + +#include +#include "camellia-ntt.h" + +/* key constants */ + +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +/* + * macros + */ + + +#if defined(_MSC_VER) + +# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +# define GETU32(p) SWAP(*((u32 *)(p))) +# define PUTU32(ct, st) {*((u32 *)(ct)) = SWAP((st));} + +#else /* not MS-VC */ + +# define GETU32(pt) \ + (((u32)(pt)[0] << 24) \ + ^ ((u32)(pt)[1] << 16) \ + ^ ((u32)(pt)[2] << 8) \ + ^ ((u32)(pt)[3])) + +# define PUTU32(ct, st) { \ + (ct)[0] = (u8)((st) >> 24); \ + (ct)[1] = (u8)((st) >> 16); \ + (ct)[2] = (u8)((st) >> 8); \ + (ct)[3] = (u8)(st); } + +#endif + +#define CamelliaSubkeyL(INDEX) (subkey[(INDEX)*2]) +#define CamelliaSubkeyR(INDEX) (subkey[(INDEX)*2 + 1]) + +/* rotation right shift 1byte */ +#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24)) + +#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + ll = (ll << bits) + (lr >> (32 - bits)); \ + lr = (lr << bits) + (rl >> (32 - bits)); \ + rl = (rl << bits) + (rr >> (32 - bits)); \ + rr = (rr << bits) + (w0 >> (32 - bits)); \ + } while(0) + +#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + w1 = lr; \ + ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ + lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ + rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ + rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ + } while(0) + +#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)]) +#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)]) +#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)]) +#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)]) + +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + il = xl ^ kl; \ + ir = xr ^ kr; \ + t0 = il >> 16; \ + t1 = ir >> 16; \ + yl = CAMELLIA_SP1110(ir & 0xff) \ + ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \ + ^ CAMELLIA_SP3033(t1 & 0xff) \ + ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \ + yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \ + ^ CAMELLIA_SP0222(t0 & 0xff) \ + ^ CAMELLIA_SP3033((il >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(il & 0xff); \ + yl ^= yr; \ + yr = CAMELLIA_RR8(yr); \ + yr ^= yl; \ + } while(0) + + +/* + * for speed up + * + */ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ + t0 = kll; \ + t0 &= ll; \ + lr ^= CAMELLIA_RL1(t0); \ + t1 = klr; \ + t1 |= lr; \ + ll ^= t1; \ + \ + t2 = krr; \ + t2 |= rr; \ + rl ^= t2; \ + t3 = krl; \ + t3 &= rl; \ + rr ^= CAMELLIA_RL1(t3); \ + } while(0) + +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + ir = CAMELLIA_SP1110(xr & 0xff) \ + ^ CAMELLIA_SP0222((xr >> 24) & 0xff) \ + ^ CAMELLIA_SP3033((xr >> 16) & 0xff) \ + ^ CAMELLIA_SP4404((xr >> 8) & 0xff); \ + il = CAMELLIA_SP1110((xl >> 24) & 0xff) \ + ^ CAMELLIA_SP0222((xl >> 16) & 0xff) \ + ^ CAMELLIA_SP3033((xl >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(xl & 0xff); \ + il ^= kl; \ + ir ^= kr; \ + ir ^= il; \ + il = CAMELLIA_RR8(il); \ + il ^= ir; \ + yl ^= ir; \ + yr ^= il; \ + } while(0) + + +static const u32 camellia_sp1110[256] = { + 0x70707000,0x82828200,0x2c2c2c00,0xececec00, + 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500, + 0xe4e4e400,0x85858500,0x57575700,0x35353500, + 0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100, + 0x23232300,0xefefef00,0x6b6b6b00,0x93939300, + 0x45454500,0x19191900,0xa5a5a500,0x21212100, + 0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00, + 0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00, + 0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00, + 0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00, + 0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00, + 0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00, + 0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00, + 0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00, + 0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600, + 0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00, + 0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600, + 0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00, + 0x74747400,0x12121200,0x2b2b2b00,0x20202000, + 0xf0f0f000,0xb1b1b100,0x84848400,0x99999900, + 0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200, + 0x34343400,0x7e7e7e00,0x76767600,0x05050500, + 0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100, + 0xd1d1d100,0x17171700,0x04040400,0xd7d7d700, + 0x14141400,0x58585800,0x3a3a3a00,0x61616100, + 0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00, + 0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600, + 0x53535300,0x18181800,0xf2f2f200,0x22222200, + 0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200, + 0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100, + 0x24242400,0x08080800,0xe8e8e800,0xa8a8a800, + 0x60606000,0xfcfcfc00,0x69696900,0x50505000, + 0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00, + 0xa1a1a100,0x89898900,0x62626200,0x97979700, + 0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500, + 0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200, + 0x10101000,0xc4c4c400,0x00000000,0x48484800, + 0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00, + 0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00, + 0x09090900,0x3f3f3f00,0xdddddd00,0x94949400, + 0x87878700,0x5c5c5c00,0x83838300,0x02020200, + 0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300, + 0x73737300,0x67676700,0xf6f6f600,0xf3f3f300, + 0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200, + 0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600, + 0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00, + 0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00, + 0x13131300,0xbebebe00,0x63636300,0x2e2e2e00, + 0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00, + 0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00, + 0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600, + 0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900, + 0x78787800,0x98989800,0x06060600,0x6a6a6a00, + 0xe7e7e700,0x46464600,0x71717100,0xbababa00, + 0xd4d4d400,0x25252500,0xababab00,0x42424200, + 0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00, + 0x72727200,0x07070700,0xb9b9b900,0x55555500, + 0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00, + 0x36363600,0x49494900,0x2a2a2a00,0x68686800, + 0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400, + 0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00, + 0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100, + 0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400, + 0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00, +}; + +static const u32 camellia_sp0222[256] = { + 0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9, + 0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb, + 0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a, + 0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282, + 0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727, + 0x008a8a8a,0x00323232,0x004b4b4b,0x00424242, + 0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c, + 0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b, + 0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f, + 0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d, + 0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe, + 0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434, + 0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595, + 0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a, + 0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad, + 0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a, + 0x00171717,0x001a1a1a,0x00353535,0x00cccccc, + 0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a, + 0x00e8e8e8,0x00242424,0x00565656,0x00404040, + 0x00e1e1e1,0x00636363,0x00090909,0x00333333, + 0x00bfbfbf,0x00989898,0x00979797,0x00858585, + 0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a, + 0x00dadada,0x006f6f6f,0x00535353,0x00626262, + 0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf, + 0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2, + 0x00bdbdbd,0x00363636,0x00222222,0x00383838, + 0x00646464,0x001e1e1e,0x00393939,0x002c2c2c, + 0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444, + 0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565, + 0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323, + 0x00484848,0x00101010,0x00d1d1d1,0x00515151, + 0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0, + 0x00555555,0x00a1a1a1,0x00414141,0x00fafafa, + 0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f, + 0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b, + 0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5, + 0x00202020,0x00898989,0x00000000,0x00909090, + 0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7, + 0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5, + 0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929, + 0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404, + 0x009b9b9b,0x00949494,0x00212121,0x00666666, + 0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7, + 0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5, + 0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c, + 0x00919191,0x006e6e6e,0x008d8d8d,0x00767676, + 0x00030303,0x002d2d2d,0x00dedede,0x00969696, + 0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c, + 0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919, + 0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d, + 0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d, + 0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2, + 0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4, + 0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575, + 0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484, + 0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5, + 0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa, + 0x00f1f1f1,0x00dddddd,0x00595959,0x00141414, + 0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0, + 0x00787878,0x00707070,0x00e3e3e3,0x00494949, + 0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6, + 0x00777777,0x00939393,0x00868686,0x00838383, + 0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9, + 0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d, +}; + +static const u32 camellia_sp3033[256] = { + 0x38003838,0x41004141,0x16001616,0x76007676, + 0xd900d9d9,0x93009393,0x60006060,0xf200f2f2, + 0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a, + 0x75007575,0x06000606,0x57005757,0xa000a0a0, + 0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9, + 0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090, + 0xf600f6f6,0x07000707,0xa700a7a7,0x27002727, + 0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede, + 0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7, + 0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767, + 0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf, + 0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d, + 0x53005353,0xf000f0f0,0x9c009c9c,0x65006565, + 0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e, + 0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b, + 0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6, + 0xc500c5c5,0x86008686,0x4d004d4d,0x33003333, + 0xfd00fdfd,0x66006666,0x58005858,0x96009696, + 0x3a003a3a,0x09000909,0x95009595,0x10001010, + 0x78007878,0xd800d8d8,0x42004242,0xcc00cccc, + 0xef00efef,0x26002626,0xe500e5e5,0x61006161, + 0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282, + 0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898, + 0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb, + 0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0, + 0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e, + 0x19001919,0x87008787,0x4e004e4e,0x0b000b0b, + 0xa900a9a9,0x0c000c0c,0x79007979,0x11001111, + 0x7f007f7f,0x22002222,0xe700e7e7,0x59005959, + 0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8, + 0x12001212,0x04000404,0x74007474,0x54005454, + 0x30003030,0x7e007e7e,0xb400b4b4,0x28002828, + 0x55005555,0x68006868,0x50005050,0xbe00bebe, + 0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb, + 0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca, + 0x70007070,0xff00ffff,0x32003232,0x69006969, + 0x08000808,0x62006262,0x00000000,0x24002424, + 0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded, + 0x45004545,0x81008181,0x73007373,0x6d006d6d, + 0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a, + 0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101, + 0xe600e6e6,0x25002525,0x48004848,0x99009999, + 0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9, + 0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171, + 0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313, + 0x64006464,0x9b009b9b,0x63006363,0x9d009d9d, + 0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5, + 0x89008989,0x5f005f5f,0xb100b1b1,0x17001717, + 0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646, + 0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747, + 0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b, + 0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac, + 0x3c003c3c,0x4c004c4c,0x03000303,0x35003535, + 0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d, + 0x6a006a6a,0x92009292,0xd500d5d5,0x21002121, + 0x44004444,0x51005151,0xc600c6c6,0x7d007d7d, + 0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa, + 0x7c007c7c,0x77007777,0x56005656,0x05000505, + 0x1b001b1b,0xa400a4a4,0x15001515,0x34003434, + 0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252, + 0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd, + 0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0, + 0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a, + 0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f, +}; + +static const u32 camellia_sp4404[256] = { + 0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0, + 0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae, + 0x23230023,0x6b6b006b,0x45450045,0xa5a500a5, + 0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092, + 0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f, + 0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b, + 0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d, + 0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c, + 0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0, + 0x74740074,0x2b2b002b,0xf0f000f0,0x84840084, + 0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076, + 0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004, + 0x14140014,0x3a3a003a,0xdede00de,0x11110011, + 0x32320032,0x9c9c009c,0x53530053,0xf2f200f2, + 0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a, + 0x24240024,0xe8e800e8,0x60600060,0x69690069, + 0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062, + 0x54540054,0x1e1e001e,0xe0e000e0,0x64640064, + 0x10100010,0x00000000,0xa3a300a3,0x75750075, + 0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd, + 0x87870087,0x83830083,0xcdcd00cd,0x90900090, + 0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf, + 0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6, + 0x81810081,0x6f6f006f,0x13130013,0x63630063, + 0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc, + 0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4, + 0x78780078,0x06060006,0xe7e700e7,0x71710071, + 0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d, + 0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac, + 0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1, + 0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043, + 0x15150015,0xadad00ad,0x77770077,0x80800080, + 0x82820082,0xecec00ec,0x27270027,0xe5e500e5, + 0x85850085,0x35350035,0x0c0c000c,0x41410041, + 0xefef00ef,0x93930093,0x19190019,0x21210021, + 0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd, + 0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce, + 0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a, + 0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d, + 0x01010001,0xd6d600d6,0x56560056,0x4d4d004d, + 0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d, + 0x12120012,0x20200020,0xb1b100b1,0x99990099, + 0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005, + 0xb7b700b7,0x31310031,0x17170017,0xd7d700d7, + 0x58580058,0x61610061,0x1b1b001b,0x1c1c001c, + 0x0f0f000f,0x16160016,0x18180018,0x22220022, + 0x44440044,0xb2b200b2,0xb5b500b5,0x91910091, + 0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050, + 0xd0d000d0,0x7d7d007d,0x89890089,0x97970097, + 0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2, + 0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db, + 0x03030003,0xdada00da,0x3f3f003f,0x94940094, + 0x5c5c005c,0x02020002,0x4a4a004a,0x33330033, + 0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2, + 0x9b9b009b,0x26260026,0x37370037,0x3b3b003b, + 0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e, + 0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e, + 0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059, + 0x98980098,0x6a6a006a,0x46460046,0xbaba00ba, + 0x25250025,0x42420042,0xa2a200a2,0xfafa00fa, + 0x07070007,0x55550055,0xeeee00ee,0x0a0a000a, + 0x49490049,0x68680068,0x38380038,0xa4a400a4, + 0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1, + 0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e, +}; + + +/** + * Stuff related to the Camellia key schedule + */ +#define subl(x) subL[(x)] +#define subr(x) subR[(x)] + +static void camellia_setup128(const unsigned char *key, u32 *subkey) +{ + u32 kll, klr, krl, krr; + u32 il, ir, t0, t1, w0, w1; + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[26]; + u32 subR[26]; + + /** + * k == kll || klr || krl || krr (|| is concatination) + */ + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + /** + * generate KL dependent subkeys + */ + subl(0) = kll; subr(0) = klr; + subl(1) = krl; subr(1) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(4) = kll; subr(4) = klr; + subl(5) = krl; subr(5) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + subl(10) = kll; subr(10) = klr; + subl(11) = krl; subr(11) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(13) = krl; subr(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(16) = kll; subr(16) = klr; + subl(17) = krl; subr(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(18) = kll; subr(18) = klr; + subl(19) = krl; subr(19) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(22) = kll; subr(22) = klr; + subl(23) = krl; subr(23) = krr; + + /* generate KA */ + kll = subl(0); klr = subr(0); + krl = subl(1); krr = subr(1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KA dependent subkeys */ + subl(2) = kll; subr(2) = klr; + subl(3) = krl; subr(3) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(6) = kll; subr(6) = klr; + subl(7) = krl; subr(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(8) = kll; subr(8) = klr; + subl(9) = krl; subr(9) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(12) = kll; subr(12) = klr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(14) = kll; subr(14) = klr; + subl(15) = krl; subr(15) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subl(20) = kll; subr(20) = klr; + subl(21) = krl; subr(21) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(24) = kll; subr(24) = klr; + subl(25) = krl; subr(25) = krr; + + + /* absorb kw2 to other subkeys */ + subl(3) ^= subl(1); subr(3) ^= subr(1); + subl(5) ^= subl(1); subr(5) ^= subr(1); + subl(7) ^= subl(1); subr(7) ^= subr(1); + subl(1) ^= subr(1) & ~subr(9); + dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); + subl(11) ^= subl(1); subr(11) ^= subr(1); + subl(13) ^= subl(1); subr(13) ^= subr(1); + subl(15) ^= subl(1); subr(15) ^= subr(1); + subl(1) ^= subr(1) & ~subr(17); + dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); + subl(19) ^= subl(1); subr(19) ^= subr(1); + subl(21) ^= subl(1); subr(21) ^= subr(1); + subl(23) ^= subl(1); subr(23) ^= subr(1); + subl(24) ^= subl(1); subr(24) ^= subr(1); + + /* absorb kw4 to other subkeys */ + kw4l = subl(25); kw4r = subr(25); + subl(22) ^= kw4l; subr(22) ^= kw4r; + subl(20) ^= kw4l; subr(20) ^= kw4r; + subl(18) ^= kw4l; subr(18) ^= kw4r; + kw4l ^= kw4r & ~subr(16); + dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw); + subl(14) ^= kw4l; subr(14) ^= kw4r; + subl(12) ^= kw4l; subr(12) ^= kw4r; + subl(10) ^= kw4l; subr(10) ^= kw4r; + kw4l ^= kw4r & ~subr(8); + dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw); + subl(6) ^= kw4l; subr(6) ^= kw4r; + subl(4) ^= kw4l; subr(4) ^= kw4r; + subl(2) ^= kw4l; subr(2) ^= kw4r; + subl(0) ^= kw4l; subr(0) ^= kw4r; + + /* key XOR is end of F-function */ + CamelliaSubkeyL(0) = subl(0) ^ subl(2); + CamelliaSubkeyR(0) = subr(0) ^ subr(2); + CamelliaSubkeyL(2) = subl(3); + CamelliaSubkeyR(2) = subr(3); + CamelliaSubkeyL(3) = subl(2) ^ subl(4); + CamelliaSubkeyR(3) = subr(2) ^ subr(4); + CamelliaSubkeyL(4) = subl(3) ^ subl(5); + CamelliaSubkeyR(4) = subr(3) ^ subr(5); + CamelliaSubkeyL(5) = subl(4) ^ subl(6); + CamelliaSubkeyR(5) = subr(4) ^ subr(6); + CamelliaSubkeyL(6) = subl(5) ^ subl(7); + CamelliaSubkeyR(6) = subr(5) ^ subr(7); + tl = subl(10) ^ (subr(10) & ~subr(8)); + dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(7) = subl(6) ^ tl; + CamelliaSubkeyR(7) = subr(6) ^ tr; + CamelliaSubkeyL(8) = subl(8); + CamelliaSubkeyR(8) = subr(8); + CamelliaSubkeyL(9) = subl(9); + CamelliaSubkeyR(9) = subr(9); + tl = subl(7) ^ (subr(7) & ~subr(9)); + dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(10) = tl ^ subl(11); + CamelliaSubkeyR(10) = tr ^ subr(11); + CamelliaSubkeyL(11) = subl(10) ^ subl(12); + CamelliaSubkeyR(11) = subr(10) ^ subr(12); + CamelliaSubkeyL(12) = subl(11) ^ subl(13); + CamelliaSubkeyR(12) = subr(11) ^ subr(13); + CamelliaSubkeyL(13) = subl(12) ^ subl(14); + CamelliaSubkeyR(13) = subr(12) ^ subr(14); + CamelliaSubkeyL(14) = subl(13) ^ subl(15); + CamelliaSubkeyR(14) = subr(13) ^ subr(15); + tl = subl(18) ^ (subr(18) & ~subr(16)); + dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(15) = subl(14) ^ tl; + CamelliaSubkeyR(15) = subr(14) ^ tr; + CamelliaSubkeyL(16) = subl(16); + CamelliaSubkeyR(16) = subr(16); + CamelliaSubkeyL(17) = subl(17); + CamelliaSubkeyR(17) = subr(17); + tl = subl(15) ^ (subr(15) & ~subr(17)); + dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(18) = tl ^ subl(19); + CamelliaSubkeyR(18) = tr ^ subr(19); + CamelliaSubkeyL(19) = subl(18) ^ subl(20); + CamelliaSubkeyR(19) = subr(18) ^ subr(20); + CamelliaSubkeyL(20) = subl(19) ^ subl(21); + CamelliaSubkeyR(20) = subr(19) ^ subr(21); + CamelliaSubkeyL(21) = subl(20) ^ subl(22); + CamelliaSubkeyR(21) = subr(20) ^ subr(22); + CamelliaSubkeyL(22) = subl(21) ^ subl(23); + CamelliaSubkeyR(22) = subr(21) ^ subr(23); + CamelliaSubkeyL(23) = subl(22); + CamelliaSubkeyR(23) = subr(22); + CamelliaSubkeyL(24) = subl(24) ^ subl(23); + CamelliaSubkeyR(24) = subr(24) ^ subr(23); + + /* apply the inverse of the last half of P-function */ + dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw; + dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw; + dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw; + dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw; + dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw; + dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw; + dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw; + dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw; + dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw; + dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw; + dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw; + dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw; + dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw; + dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw; + dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw; + dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw; + dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw; + dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw; + + return; +} + +static void camellia_setup256(const unsigned char *key, u32 *subkey) +{ + u32 kll,klr,krl,krr; /* left half of key */ + u32 krll,krlr,krrl,krrr; /* right half of key */ + u32 il, ir, t0, t1, w0, w1; /* temporary variables */ + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[34]; + u32 subR[34]; + + /** + * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) + * (|| is concatination) + */ + + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + krll = GETU32(key + 16); + krlr = GETU32(key + 20); + krrl = GETU32(key + 24); + krrr = GETU32(key + 28); + + /* generate KL dependent subkeys */ + subl(0) = kll; subr(0) = klr; + subl(1) = krl; subr(1) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45); + subl(12) = kll; subr(12) = klr; + subl(13) = krl; subr(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(16) = kll; subr(16) = klr; + subl(17) = krl; subr(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(22) = kll; subr(22) = klr; + subl(23) = krl; subr(23) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subl(30) = kll; subr(30) = klr; + subl(31) = krl; subr(31) = krr; + + /* generate KR dependent subkeys */ + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + subl(4) = krll; subr(4) = krlr; + subl(5) = krrl; subr(5) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + subl(8) = krll; subr(8) = krlr; + subl(9) = krrl; subr(9) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(18) = krll; subr(18) = krlr; + subl(19) = krrl; subr(19) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + subl(26) = krll; subr(26) = krlr; + subl(27) = krrl; subr(27) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + + /* generate KA */ + kll = subl(0) ^ krll; klr = subr(0) ^ krlr; + krl = subl(1) ^ krrl; krr = subr(1) ^ krrr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + kll ^= krll; klr ^= krlr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0 ^ krrl; krr ^= w1 ^ krrr; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KB */ + krll ^= kll; krlr ^= klr; + krrl ^= krl; krrr ^= krr; + CAMELLIA_F(krll, krlr, + CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, + w0, w1, il, ir, t0, t1); + krrl ^= w0; krrr ^= w1; + CAMELLIA_F(krrl, krrr, + CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, + w0, w1, il, ir, t0, t1); + krll ^= w0; krlr ^= w1; + + /* generate KA dependent subkeys */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(6) = kll; subr(6) = klr; + subl(7) = krl; subr(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + subl(14) = kll; subr(14) = klr; + subl(15) = krl; subr(15) = krr; + subl(24) = klr; subr(24) = krl; + subl(25) = krr; subr(25) = kll; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49); + subl(28) = kll; subr(28) = klr; + subl(29) = krl; subr(29) = krr; + + /* generate KB dependent subkeys */ + subl(2) = krll; subr(2) = krlr; + subl(3) = krrl; subr(3) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(10) = krll; subr(10) = krlr; + subl(11) = krrl; subr(11) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(20) = krll; subr(20) = krlr; + subl(21) = krrl; subr(21) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); + subl(32) = krll; subr(32) = krlr; + subl(33) = krrl; subr(33) = krrr; + + /* absorb kw2 to other subkeys */ + subl(3) ^= subl(1); subr(3) ^= subr(1); + subl(5) ^= subl(1); subr(5) ^= subr(1); + subl(7) ^= subl(1); subr(7) ^= subr(1); + subl(1) ^= subr(1) & ~subr(9); + dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); + subl(11) ^= subl(1); subr(11) ^= subr(1); + subl(13) ^= subl(1); subr(13) ^= subr(1); + subl(15) ^= subl(1); subr(15) ^= subr(1); + subl(1) ^= subr(1) & ~subr(17); + dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); + subl(19) ^= subl(1); subr(19) ^= subr(1); + subl(21) ^= subl(1); subr(21) ^= subr(1); + subl(23) ^= subl(1); subr(23) ^= subr(1); + subl(1) ^= subr(1) & ~subr(25); + dw = subl(1) & subl(25), subr(1) ^= CAMELLIA_RL1(dw); + subl(27) ^= subl(1); subr(27) ^= subr(1); + subl(29) ^= subl(1); subr(29) ^= subr(1); + subl(31) ^= subl(1); subr(31) ^= subr(1); + subl(32) ^= subl(1); subr(32) ^= subr(1); + + /* absorb kw4 to other subkeys */ + kw4l = subl(33); kw4r = subr(33); + subl(30) ^= kw4l; subr(30) ^= kw4r; + subl(28) ^= kw4l; subr(28) ^= kw4r; + subl(26) ^= kw4l; subr(26) ^= kw4r; + kw4l ^= kw4r & ~subr(24); + dw = kw4l & subl(24), kw4r ^= CAMELLIA_RL1(dw); + subl(22) ^= kw4l; subr(22) ^= kw4r; + subl(20) ^= kw4l; subr(20) ^= kw4r; + subl(18) ^= kw4l; subr(18) ^= kw4r; + kw4l ^= kw4r & ~subr(16); + dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw); + subl(14) ^= kw4l; subr(14) ^= kw4r; + subl(12) ^= kw4l; subr(12) ^= kw4r; + subl(10) ^= kw4l; subr(10) ^= kw4r; + kw4l ^= kw4r & ~subr(8); + dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw); + subl(6) ^= kw4l; subr(6) ^= kw4r; + subl(4) ^= kw4l; subr(4) ^= kw4r; + subl(2) ^= kw4l; subr(2) ^= kw4r; + subl(0) ^= kw4l; subr(0) ^= kw4r; + + /* key XOR is end of F-function */ + CamelliaSubkeyL(0) = subl(0) ^ subl(2); + CamelliaSubkeyR(0) = subr(0) ^ subr(2); + CamelliaSubkeyL(2) = subl(3); + CamelliaSubkeyR(2) = subr(3); + CamelliaSubkeyL(3) = subl(2) ^ subl(4); + CamelliaSubkeyR(3) = subr(2) ^ subr(4); + CamelliaSubkeyL(4) = subl(3) ^ subl(5); + CamelliaSubkeyR(4) = subr(3) ^ subr(5); + CamelliaSubkeyL(5) = subl(4) ^ subl(6); + CamelliaSubkeyR(5) = subr(4) ^ subr(6); + CamelliaSubkeyL(6) = subl(5) ^ subl(7); + CamelliaSubkeyR(6) = subr(5) ^ subr(7); + tl = subl(10) ^ (subr(10) & ~subr(8)); + dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(7) = subl(6) ^ tl; + CamelliaSubkeyR(7) = subr(6) ^ tr; + CamelliaSubkeyL(8) = subl(8); + CamelliaSubkeyR(8) = subr(8); + CamelliaSubkeyL(9) = subl(9); + CamelliaSubkeyR(9) = subr(9); + tl = subl(7) ^ (subr(7) & ~subr(9)); + dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(10) = tl ^ subl(11); + CamelliaSubkeyR(10) = tr ^ subr(11); + CamelliaSubkeyL(11) = subl(10) ^ subl(12); + CamelliaSubkeyR(11) = subr(10) ^ subr(12); + CamelliaSubkeyL(12) = subl(11) ^ subl(13); + CamelliaSubkeyR(12) = subr(11) ^ subr(13); + CamelliaSubkeyL(13) = subl(12) ^ subl(14); + CamelliaSubkeyR(13) = subr(12) ^ subr(14); + CamelliaSubkeyL(14) = subl(13) ^ subl(15); + CamelliaSubkeyR(14) = subr(13) ^ subr(15); + tl = subl(18) ^ (subr(18) & ~subr(16)); + dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(15) = subl(14) ^ tl; + CamelliaSubkeyR(15) = subr(14) ^ tr; + CamelliaSubkeyL(16) = subl(16); + CamelliaSubkeyR(16) = subr(16); + CamelliaSubkeyL(17) = subl(17); + CamelliaSubkeyR(17) = subr(17); + tl = subl(15) ^ (subr(15) & ~subr(17)); + dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(18) = tl ^ subl(19); + CamelliaSubkeyR(18) = tr ^ subr(19); + CamelliaSubkeyL(19) = subl(18) ^ subl(20); + CamelliaSubkeyR(19) = subr(18) ^ subr(20); + CamelliaSubkeyL(20) = subl(19) ^ subl(21); + CamelliaSubkeyR(20) = subr(19) ^ subr(21); + CamelliaSubkeyL(21) = subl(20) ^ subl(22); + CamelliaSubkeyR(21) = subr(20) ^ subr(22); + CamelliaSubkeyL(22) = subl(21) ^ subl(23); + CamelliaSubkeyR(22) = subr(21) ^ subr(23); + tl = subl(26) ^ (subr(26) & ~subr(24)); + dw = tl & subl(24), tr = subr(26) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(23) = subl(22) ^ tl; + CamelliaSubkeyR(23) = subr(22) ^ tr; + CamelliaSubkeyL(24) = subl(24); + CamelliaSubkeyR(24) = subr(24); + CamelliaSubkeyL(25) = subl(25); + CamelliaSubkeyR(25) = subr(25); + tl = subl(23) ^ (subr(23) & ~subr(25)); + dw = tl & subl(25), tr = subr(23) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(26) = tl ^ subl(27); + CamelliaSubkeyR(26) = tr ^ subr(27); + CamelliaSubkeyL(27) = subl(26) ^ subl(28); + CamelliaSubkeyR(27) = subr(26) ^ subr(28); + CamelliaSubkeyL(28) = subl(27) ^ subl(29); + CamelliaSubkeyR(28) = subr(27) ^ subr(29); + CamelliaSubkeyL(29) = subl(28) ^ subl(30); + CamelliaSubkeyR(29) = subr(28) ^ subr(30); + CamelliaSubkeyL(30) = subl(29) ^ subl(31); + CamelliaSubkeyR(30) = subr(29) ^ subr(31); + CamelliaSubkeyL(31) = subl(30); + CamelliaSubkeyR(31) = subr(30); + CamelliaSubkeyL(32) = subl(32) ^ subl(31); + CamelliaSubkeyR(32) = subr(32) ^ subr(31); + + /* apply the inverse of the last half of P-function */ + dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw; + dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw; + dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw; + dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw; + dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw; + dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw; + dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw; + dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw; + dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw; + dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw; + dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw; + dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw; + dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw; + dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw; + dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw; + dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw; + dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw; + dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw; + dw = CamelliaSubkeyL(26) ^ CamelliaSubkeyR(26), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(26) = CamelliaSubkeyL(26) ^ dw, CamelliaSubkeyL(26) = dw; + dw = CamelliaSubkeyL(27) ^ CamelliaSubkeyR(27), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(27) = CamelliaSubkeyL(27) ^ dw, CamelliaSubkeyL(27) = dw; + dw = CamelliaSubkeyL(28) ^ CamelliaSubkeyR(28), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(28) = CamelliaSubkeyL(28) ^ dw, CamelliaSubkeyL(28) = dw; + dw = CamelliaSubkeyL(29) ^ CamelliaSubkeyR(29), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(29) = CamelliaSubkeyL(29) ^ dw, CamelliaSubkeyL(29) = dw; + dw = CamelliaSubkeyL(30) ^ CamelliaSubkeyR(30), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(30) = CamelliaSubkeyL(30) ^ dw, CamelliaSubkeyL(30) = dw; + dw = CamelliaSubkeyL(31) ^ CamelliaSubkeyR(31), dw = CAMELLIA_RL8(dw); + CamelliaSubkeyR(31) = CamelliaSubkeyL(31) ^ dw,CamelliaSubkeyL(31) = dw; + + return; +} + +static void camellia_setup192(const unsigned char *key, u32 *subkey) +{ + unsigned char kk[32]; + u32 krll, krlr, krrl,krrr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krll, key+16,4); + memcpy((unsigned char *)&krlr, key+20,4); + krrl = ~krll; + krrr = ~krlr; + memcpy(kk+24, (unsigned char *)&krrl, 4); + memcpy(kk+28, (unsigned char *)&krrr, 4); + camellia_setup256(kk, subkey); + return; +} + + +/** + * Stuff related to camellia encryption/decryption + * + * "io" must be 4byte aligned and big-endian data. + */ +static void camellia_encrypt128(const u32 *subkey, u32 *io) +{ + u32 il, ir, t0, t1; + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(0); + io[1] ^= CamelliaSubkeyR(0); + /* main iteration */ + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(24); + io[3] ^= CamelliaSubkeyR(24); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + return; +} + +static void camellia_decrypt128(const u32 *subkey, u32 *io) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(24); + io[1] ^= CamelliaSubkeyR(24); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(0); + io[3] ^= CamelliaSubkeyR(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + return; +} + +/** + * stuff for 192 and 256bit encryption/decryption + */ +static void camellia_encrypt256(const u32 *subkey, u32 *io) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(0); + io[1] ^= CamelliaSubkeyR(0); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(24),CamelliaSubkeyR(24), + CamelliaSubkeyL(25),CamelliaSubkeyR(25), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(26),CamelliaSubkeyR(26), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(27),CamelliaSubkeyR(27), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(28),CamelliaSubkeyR(28), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(29),CamelliaSubkeyR(29), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(30),CamelliaSubkeyR(30), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(31),CamelliaSubkeyR(31), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(32); + io[3] ^= CamelliaSubkeyR(32); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + return; +} + +static void camellia_decrypt256(const u32 *subkey, u32 *io) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(32); + io[1] ^= CamelliaSubkeyR(32); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(31),CamelliaSubkeyR(31), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(30),CamelliaSubkeyR(30), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(29),CamelliaSubkeyR(29), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(28),CamelliaSubkeyR(28), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(27),CamelliaSubkeyR(27), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(26),CamelliaSubkeyR(26), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(25),CamelliaSubkeyR(25), + CamelliaSubkeyL(24),CamelliaSubkeyR(24), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(0); + io[3] ^= CamelliaSubkeyR(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + return; +} + +/*** + * + * API for compatibility + */ + +void Camellia_Ekeygen(const int keyBitLength, + const unsigned char *rawKey, + KEY_TABLE_TYPE keyTable) +{ + switch(keyBitLength) { + case 128: + camellia_setup128(rawKey, keyTable); + break; + case 192: + camellia_setup192(rawKey, keyTable); + break; + case 256: + camellia_setup256(rawKey, keyTable); + break; + default: + break; + } +} + + +void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *ciphertext) +{ + u32 tmp[4]; + + tmp[0] = GETU32(plaintext); + tmp[1] = GETU32(plaintext + 4); + tmp[2] = GETU32(plaintext + 8); + tmp[3] = GETU32(plaintext + 12); + + switch (keyBitLength) { + case 128: + camellia_encrypt128(keyTable, tmp); + break; + case 192: + /* fall through */ + case 256: + camellia_encrypt256(keyTable, tmp); + break; + default: + break; + } + + PUTU32(ciphertext, tmp[0]); + PUTU32(ciphertext + 4, tmp[1]); + PUTU32(ciphertext + 8, tmp[2]); + PUTU32(ciphertext + 12, tmp[3]); +} + +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *ciphertext, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext) +{ + u32 tmp[4]; + + tmp[0] = GETU32(ciphertext); + tmp[1] = GETU32(ciphertext + 4); + tmp[2] = GETU32(ciphertext + 8); + tmp[3] = GETU32(ciphertext + 12); + + switch (keyBitLength) { + case 128: + camellia_decrypt128(keyTable, tmp); + break; + case 192: + /* fall through */ + case 256: + camellia_decrypt256(keyTable, tmp); + break; + default: + break; + } + PUTU32(plaintext, tmp[0]); + PUTU32(plaintext + 4, tmp[1]); + PUTU32(plaintext + 8, tmp[2]); + PUTU32(plaintext + 12, tmp[3]); +} diff --git a/third_party/heimdal/lib/hcrypto/camellia-ntt.h b/third_party/heimdal/lib/hcrypto/camellia-ntt.h new file mode 100644 index 0000000..cc0b70d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/camellia-ntt.h @@ -0,0 +1,63 @@ +/* camellia.h ver 1.2.0 + * + * Copyright (C) 2006,2007 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef HEADER_CAMELLIA_H +#define HEADER_CAMELLIA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* symbol renaming */ +#define Camellia_DecryptBlock hc_Camellia_DecryptBlock +#define Camellia_Ekeygen hc_Camellia_Ekeygen +#define Camellia_EncryptBlock hc_Camellia_EncryptBlock + +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 +#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +/* u32 must be 32bit word */ +typedef uint32_t u32; +typedef unsigned char u8; + +typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; + + +void Camellia_Ekeygen(const int keyBitLength, + const unsigned char *rawKey, + KEY_TABLE_TYPE keyTable); + +void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *cipherText); + +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext); + + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_CAMELLIA_H */ diff --git a/third_party/heimdal/lib/hcrypto/camellia.c b/third_party/heimdal/lib/hcrypto/camellia.c new file mode 100644 index 0000000..bc861a0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/camellia.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#ifdef KRB5 +#include +#endif + +#include "camellia-ntt.h" +#include "camellia.h" + +int +CAMELLIA_set_key(const unsigned char *userkey, + const int bits, CAMELLIA_KEY *key) +{ + key->bits = bits; + Camellia_Ekeygen(bits, userkey, key->key); + return 1; +} + +void +CAMELLIA_encrypt(const unsigned char *in, unsigned char *out, + const CAMELLIA_KEY *key) +{ + Camellia_EncryptBlock(key->bits, in, key->key, out); + +} + +void +CAMELLIA_decrypt(const unsigned char *in, unsigned char *out, + const CAMELLIA_KEY *key) +{ + Camellia_DecryptBlock(key->bits, in, key->key, out); +} + +void +CAMELLIA_cbc_encrypt(const unsigned char *in, unsigned char *out, + unsigned long size, const CAMELLIA_KEY *key, + unsigned char *iv, int mode_encrypt) +{ + unsigned char tmp[CAMELLIA_BLOCK_SIZE]; + int i; + + if (mode_encrypt) { + while (size >= CAMELLIA_BLOCK_SIZE) { + for (i = 0; i < CAMELLIA_BLOCK_SIZE; i++) + tmp[i] = in[i] ^ iv[i]; + CAMELLIA_encrypt(tmp, out, key); + memcpy(iv, out, CAMELLIA_BLOCK_SIZE); + size -= CAMELLIA_BLOCK_SIZE; + in += CAMELLIA_BLOCK_SIZE; + out += CAMELLIA_BLOCK_SIZE; + } + if (size) { + for (i = 0; i < size; i++) + tmp[i] = in[i] ^ iv[i]; + for (i = size; i < CAMELLIA_BLOCK_SIZE; i++) + tmp[i] = iv[i]; + CAMELLIA_encrypt(tmp, out, key); + memcpy(iv, out, CAMELLIA_BLOCK_SIZE); + } + } else { + while (size >= CAMELLIA_BLOCK_SIZE) { + memcpy(tmp, in, CAMELLIA_BLOCK_SIZE); + CAMELLIA_decrypt(tmp, out, key); + for (i = 0; i < CAMELLIA_BLOCK_SIZE; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, CAMELLIA_BLOCK_SIZE); + size -= CAMELLIA_BLOCK_SIZE; + in += CAMELLIA_BLOCK_SIZE; + out += CAMELLIA_BLOCK_SIZE; + } + if (size) { + memcpy(tmp, in, CAMELLIA_BLOCK_SIZE); + CAMELLIA_decrypt(tmp, out, key); + for (i = 0; i < size; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, CAMELLIA_BLOCK_SIZE); + } + } +} diff --git a/third_party/heimdal/lib/hcrypto/camellia.h b/third_party/heimdal/lib/hcrypto/camellia.h new file mode 100644 index 0000000..6661f3b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/camellia.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_CAMELLIA_H +#define HEIM_CAMELLIA_H 1 + +/* symbol renaming */ +#define CAMELLIA_set_key hc_CAMELLIA_set_encrypt_key +#define CAMELLIA_encrypt hc_CAMELLIA_encrypt +#define CAMELLIA_decrypt hc_CAMELLIA_decrypt +#define CAMELLIA_cbc_encrypt hc_CAMELLIA_cbc_encrypt + +/* + * + */ + +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 +#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +#define CAMELLIA_ENCRYPT 1 +#define CAMELLIA_DECRYPT 0 + +typedef struct camellia_key { + unsigned int bits; + uint32_t key[CAMELLIA_TABLE_WORD_LEN]; +} CAMELLIA_KEY; + +int CAMELLIA_set_key(const unsigned char *, const int, CAMELLIA_KEY *); + +void CAMELLIA_encrypt(const unsigned char *, unsigned char *, + const CAMELLIA_KEY *); +void CAMELLIA_decrypt(const unsigned char *, unsigned char *, + const CAMELLIA_KEY *); + +void CAMELLIA_cbc_encrypt(const unsigned char *, unsigned char *, + unsigned long, const CAMELLIA_KEY *, + unsigned char *, int); + +#endif /* HEIM_CAMELLIA_H */ diff --git a/third_party/heimdal/lib/hcrypto/common.c b/third_party/heimdal/lib/hcrypto/common.c new file mode 100644 index 0000000..cf30304 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/common.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include + + +#include "common.h" + +int +_hc_BN_to_integer(BIGNUM *bn, heim_integer *integer) +{ + integer->length = BN_num_bytes(bn); + integer->data = malloc(integer->length); + if (integer->data == NULL) + return ENOMEM; + BN_bn2bin(bn, integer->data); + integer->negative = BN_is_negative(bn); + return 0; +} + +BIGNUM * +_hc_integer_to_BN(const heim_integer *i, BIGNUM *bn) +{ + bn = BN_bin2bn(i->data, i->length, bn); + if (bn) + BN_set_negative(bn, i->negative); + return bn; +} diff --git a/third_party/heimdal/lib/hcrypto/common.h b/third_party/heimdal/lib/hcrypto/common.h new file mode 100644 index 0000000..f78f544 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/common.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HCRYPTO_COMMON_H +#define HCRYPTO_COMMON_H 1 + +int +_hc_BN_to_integer(BIGNUM *, heim_integer *); + +BIGNUM * +_hc_integer_to_BN(const heim_integer *i, BIGNUM *bn); + +#endif /* HCRYPTO_COMMON_H */ diff --git a/third_party/heimdal/lib/hcrypto/des-tables.h b/third_party/heimdal/lib/hcrypto/des-tables.h new file mode 100644 index 0000000..95f3711 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/des-tables.h @@ -0,0 +1,196 @@ +/* GENERATE FILE from gen-des.pl, do not edit */ + +/* pc1_c_3 bit pattern 5 13 21 */ +static int pc1_c_3[8] = { + 0x00000000, 0x00000010, 0x00001000, 0x00001010, + 0x00100000, 0x00100010, 0x00101000, 0x00101010 +}; +/* pc1_c_4 bit pattern 1 9 17 25 */ +static int pc1_c_4[16] = { + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; +/* pc1_d_3 bit pattern 49 41 33 */ +static int pc1_d_3[8] = { + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100 +}; +/* pc1_d_4 bit pattern 57 53 45 37 */ +static int pc1_d_4[16] = { + 0x00000000, 0x00100000, 0x00001000, 0x00101000, + 0x00000010, 0x00100010, 0x00001010, 0x00101010, + 0x00000001, 0x00100001, 0x00001001, 0x00101001, + 0x00000011, 0x00100011, 0x00001011, 0x00101011 +}; +/* pc2_c_1 bit pattern 5 24 7 16 6 10 */ +static int pc2_c_1[64] = { + 0x00000000, 0x00004000, 0x00040000, 0x00044000, + 0x00000100, 0x00004100, 0x00040100, 0x00044100, + 0x00020000, 0x00024000, 0x00060000, 0x00064000, + 0x00020100, 0x00024100, 0x00060100, 0x00064100, + 0x00000001, 0x00004001, 0x00040001, 0x00044001, + 0x00000101, 0x00004101, 0x00040101, 0x00044101, + 0x00020001, 0x00024001, 0x00060001, 0x00064001, + 0x00020101, 0x00024101, 0x00060101, 0x00064101, + 0x00080000, 0x00084000, 0x000c0000, 0x000c4000, + 0x00080100, 0x00084100, 0x000c0100, 0x000c4100, + 0x000a0000, 0x000a4000, 0x000e0000, 0x000e4000, + 0x000a0100, 0x000a4100, 0x000e0100, 0x000e4100, + 0x00080001, 0x00084001, 0x000c0001, 0x000c4001, + 0x00080101, 0x00084101, 0x000c0101, 0x000c4101, + 0x000a0001, 0x000a4001, 0x000e0001, 0x000e4001, + 0x000a0101, 0x000a4101, 0x000e0101, 0x000e4101 +}; +/* pc2_c_2 bit pattern 20 18 12 3 15 23 */ +static int pc2_c_2[64] = { + 0x00000000, 0x00000002, 0x00000200, 0x00000202, + 0x00200000, 0x00200002, 0x00200200, 0x00200202, + 0x00001000, 0x00001002, 0x00001200, 0x00001202, + 0x00201000, 0x00201002, 0x00201200, 0x00201202, + 0x00000040, 0x00000042, 0x00000240, 0x00000242, + 0x00200040, 0x00200042, 0x00200240, 0x00200242, + 0x00001040, 0x00001042, 0x00001240, 0x00001242, + 0x00201040, 0x00201042, 0x00201240, 0x00201242, + 0x00000010, 0x00000012, 0x00000210, 0x00000212, + 0x00200010, 0x00200012, 0x00200210, 0x00200212, + 0x00001010, 0x00001012, 0x00001210, 0x00001212, + 0x00201010, 0x00201012, 0x00201210, 0x00201212, + 0x00000050, 0x00000052, 0x00000250, 0x00000252, + 0x00200050, 0x00200052, 0x00200250, 0x00200252, + 0x00001050, 0x00001052, 0x00001250, 0x00001252, + 0x00201050, 0x00201052, 0x00201250, 0x00201252 +}; +/* pc2_c_3 bit pattern 1 9 19 2 14 22 */ +static int pc2_c_3[64] = { + 0x00000000, 0x00000004, 0x00000400, 0x00000404, + 0x00400000, 0x00400004, 0x00400400, 0x00400404, + 0x00000020, 0x00000024, 0x00000420, 0x00000424, + 0x00400020, 0x00400024, 0x00400420, 0x00400424, + 0x00008000, 0x00008004, 0x00008400, 0x00008404, + 0x00408000, 0x00408004, 0x00408400, 0x00408404, + 0x00008020, 0x00008024, 0x00008420, 0x00008424, + 0x00408020, 0x00408024, 0x00408420, 0x00408424, + 0x00800000, 0x00800004, 0x00800400, 0x00800404, + 0x00c00000, 0x00c00004, 0x00c00400, 0x00c00404, + 0x00800020, 0x00800024, 0x00800420, 0x00800424, + 0x00c00020, 0x00c00024, 0x00c00420, 0x00c00424, + 0x00808000, 0x00808004, 0x00808400, 0x00808404, + 0x00c08000, 0x00c08004, 0x00c08400, 0x00c08404, + 0x00808020, 0x00808024, 0x00808420, 0x00808424, + 0x00c08020, 0x00c08024, 0x00c08420, 0x00c08424 +}; +/* pc2_c_4 bit pattern 11 13 4 17 21 8 */ +static int pc2_c_4[64] = { + 0x00000000, 0x00010000, 0x00000008, 0x00010008, + 0x00000080, 0x00010080, 0x00000088, 0x00010088, + 0x00100000, 0x00110000, 0x00100008, 0x00110008, + 0x00100080, 0x00110080, 0x00100088, 0x00110088, + 0x00000800, 0x00010800, 0x00000808, 0x00010808, + 0x00000880, 0x00010880, 0x00000888, 0x00010888, + 0x00100800, 0x00110800, 0x00100808, 0x00110808, + 0x00100880, 0x00110880, 0x00100888, 0x00110888, + 0x00002000, 0x00012000, 0x00002008, 0x00012008, + 0x00002080, 0x00012080, 0x00002088, 0x00012088, + 0x00102000, 0x00112000, 0x00102008, 0x00112008, + 0x00102080, 0x00112080, 0x00102088, 0x00112088, + 0x00002800, 0x00012800, 0x00002808, 0x00012808, + 0x00002880, 0x00012880, 0x00002888, 0x00012888, + 0x00102800, 0x00112800, 0x00102808, 0x00112808, + 0x00102880, 0x00112880, 0x00102888, 0x00112888 +}; +/* pc2_d_1 bit pattern 51 35 31 52 39 45 */ +static int pc2_d_1[64] = { + 0x00000000, 0x00000080, 0x00002000, 0x00002080, + 0x00000001, 0x00000081, 0x00002001, 0x00002081, + 0x00200000, 0x00200080, 0x00202000, 0x00202080, + 0x00200001, 0x00200081, 0x00202001, 0x00202081, + 0x00020000, 0x00020080, 0x00022000, 0x00022080, + 0x00020001, 0x00020081, 0x00022001, 0x00022081, + 0x00220000, 0x00220080, 0x00222000, 0x00222080, + 0x00220001, 0x00220081, 0x00222001, 0x00222081, + 0x00000002, 0x00000082, 0x00002002, 0x00002082, + 0x00000003, 0x00000083, 0x00002003, 0x00002083, + 0x00200002, 0x00200082, 0x00202002, 0x00202082, + 0x00200003, 0x00200083, 0x00202003, 0x00202083, + 0x00020002, 0x00020082, 0x00022002, 0x00022082, + 0x00020003, 0x00020083, 0x00022003, 0x00022083, + 0x00220002, 0x00220082, 0x00222002, 0x00222082, + 0x00220003, 0x00220083, 0x00222003, 0x00222083 +}; +/* pc2_d_2 bit pattern 50 32 43 36 29 48 */ +static int pc2_d_2[64] = { + 0x00000000, 0x00000010, 0x00800000, 0x00800010, + 0x00010000, 0x00010010, 0x00810000, 0x00810010, + 0x00000200, 0x00000210, 0x00800200, 0x00800210, + 0x00010200, 0x00010210, 0x00810200, 0x00810210, + 0x00100000, 0x00100010, 0x00900000, 0x00900010, + 0x00110000, 0x00110010, 0x00910000, 0x00910010, + 0x00100200, 0x00100210, 0x00900200, 0x00900210, + 0x00110200, 0x00110210, 0x00910200, 0x00910210, + 0x00000004, 0x00000014, 0x00800004, 0x00800014, + 0x00010004, 0x00010014, 0x00810004, 0x00810014, + 0x00000204, 0x00000214, 0x00800204, 0x00800214, + 0x00010204, 0x00010214, 0x00810204, 0x00810214, + 0x00100004, 0x00100014, 0x00900004, 0x00900014, + 0x00110004, 0x00110014, 0x00910004, 0x00910014, + 0x00100204, 0x00100214, 0x00900204, 0x00900214, + 0x00110204, 0x00110214, 0x00910204, 0x00910214 +}; +/* pc2_d_3 bit pattern 41 38 47 33 40 42 */ +static int pc2_d_3[64] = { + 0x00000000, 0x00000400, 0x00001000, 0x00001400, + 0x00080000, 0x00080400, 0x00081000, 0x00081400, + 0x00000020, 0x00000420, 0x00001020, 0x00001420, + 0x00080020, 0x00080420, 0x00081020, 0x00081420, + 0x00004000, 0x00004400, 0x00005000, 0x00005400, + 0x00084000, 0x00084400, 0x00085000, 0x00085400, + 0x00004020, 0x00004420, 0x00005020, 0x00005420, + 0x00084020, 0x00084420, 0x00085020, 0x00085420, + 0x00000800, 0x00000c00, 0x00001800, 0x00001c00, + 0x00080800, 0x00080c00, 0x00081800, 0x00081c00, + 0x00000820, 0x00000c20, 0x00001820, 0x00001c20, + 0x00080820, 0x00080c20, 0x00081820, 0x00081c20, + 0x00004800, 0x00004c00, 0x00005800, 0x00005c00, + 0x00084800, 0x00084c00, 0x00085800, 0x00085c00, + 0x00004820, 0x00004c20, 0x00005820, 0x00005c20, + 0x00084820, 0x00084c20, 0x00085820, 0x00085c20 +}; +/* pc2_d_4 bit pattern 49 37 30 46 34 44 */ +static int pc2_d_4[64] = { + 0x00000000, 0x00000100, 0x00040000, 0x00040100, + 0x00000040, 0x00000140, 0x00040040, 0x00040140, + 0x00400000, 0x00400100, 0x00440000, 0x00440100, + 0x00400040, 0x00400140, 0x00440040, 0x00440140, + 0x00008000, 0x00008100, 0x00048000, 0x00048100, + 0x00008040, 0x00008140, 0x00048040, 0x00048140, + 0x00408000, 0x00408100, 0x00448000, 0x00448100, + 0x00408040, 0x00408140, 0x00448040, 0x00448140, + 0x00000008, 0x00000108, 0x00040008, 0x00040108, + 0x00000048, 0x00000148, 0x00040048, 0x00040148, + 0x00400008, 0x00400108, 0x00440008, 0x00440108, + 0x00400048, 0x00400148, 0x00440048, 0x00440148, + 0x00008008, 0x00008108, 0x00048008, 0x00048108, + 0x00008048, 0x00008148, 0x00048048, 0x00048148, + 0x00408008, 0x00408108, 0x00448008, 0x00448108, + 0x00408048, 0x00408148, 0x00448048, 0x00448148 +}; +static unsigned char odd_parity[256] = { + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, +112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, +128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, +145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, +161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, +176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, +193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, +208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, +224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, +241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254, + }; diff --git a/third_party/heimdal/lib/hcrypto/des.c b/third_party/heimdal/lib/hcrypto/des.c new file mode 100644 index 0000000..cb9cac7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/des.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @page page_des DES - Data Encryption Standard crypto interface + * + * See the library functions here: @ref hcrypto_des + * + * DES was created by IBM, modififed by NSA and then adopted by NBS + * (now NIST) and published ad FIPS PUB 46 (updated by FIPS 46-1). + * + * Since the 19th May 2005 DES was withdrawn by NIST and should no + * longer be used. See @ref page_evp for replacement encryption + * algorithms and interfaces. + * + * Read more the iteresting history of DES on Wikipedia + * http://www.wikipedia.org/wiki/Data_Encryption_Standard . + * + * @section des_keygen DES key generation + * + * To generate a DES key safely you have to use the code-snippet + * below. This is because the DES_random_key() can fail with an + * abort() in case of and failure to start the random generator. + * + * There is a replacement function DES_new_random_key(), however that + * function does not exists in OpenSSL. + * + * @code + * DES_cblock key; + * do { + * if (RAND_rand(&key, sizeof(key)) != 1) + * goto failure; + * DES_set_odd_parity(key); + * } while (DES_is_weak_key(&key)); + * @endcode + * + * @section des_impl DES implementation history + * + * There was no complete BSD licensed, fast, GPL compatible + * implementation of DES, so Love wrote the part that was missing, + * fast key schedule setup and adapted the interface to the orignal + * libdes. + * + * The document that got me started for real was "Efficient + * Implementation of the Data Encryption Standard" by Dag Arne Osvik. + * I never got to the PC1 transformation was working, instead I used + * table-lookup was used for all key schedule setup. The document was + * very useful since it de-mystified other implementations for me. + * + * The core DES function (SBOX + P transformation) is from Richard + * Outerbridge public domain DES implementation. My sanity is saved + * thanks to his work. Thank you Richard. + */ + +#include +#include + +#define HC_DEPRECATED +#include +#include + +#include "des.h" +#include "ui.h" + +static void desx(uint32_t [2], DES_key_schedule *, int); +static void IP(uint32_t [2]); +static void FP(uint32_t [2]); + +#include "des-tables.h" + +#define ROTATE_LEFT28(x,one) \ + if (one) { \ + x = ( ((x)<<(1)) & 0xffffffe) | ((x) >> 27); \ + } else { \ + x = ( ((x)<<(2)) & 0xffffffc) | ((x) >> 26); \ + } + +/** + * Set the parity of the key block, used to generate a des key from a + * random key. See @ref des_keygen. + * + * @param key key to fixup the parity for. + * @ingroup hcrypto_des + */ + +void +DES_set_odd_parity(DES_cblock *key) +{ + unsigned int i; + for (i = 0; i < DES_CBLOCK_LEN; i++) + (*key)[i] = odd_parity[(*key)[i]]; +} + +/** + * Check if the key have correct parity. + * + * @param key key to check the parity. + * @return 1 on success, 0 on failure. + * @ingroup hcrypto_des + */ + +int HC_DEPRECATED +DES_check_key_parity(DES_cblock *key) +{ + unsigned int i; + + for (i = 0; i < DES_CBLOCK_LEN; i++) + if ((*key)[i] != odd_parity[(*key)[i]]) + return 0; + return 1; +} + +/* + * + */ + +/* FIPS 74 */ +static DES_cblock weak_keys[] = { + {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, /* weak keys */ + {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, + {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E}, + {0xE0,0xE0,0xE0,0xE0,0xF1,0xF1,0xF1,0xF1}, + {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, /* semi-weak keys */ + {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, + {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, + {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, + {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, + {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, + {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, + {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, + {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, + {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, + {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, + {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1} +}; + +/** + * Checks if the key is any of the weaks keys that makes DES attacks + * trival. + * + * @param key key to check. + * + * @return 1 if the key is weak, 0 otherwise. + * @ingroup hcrypto_des + */ + +int +DES_is_weak_key(DES_cblock *key) +{ + int weak = 0; + int i; + + for (i = 0; i < sizeof(weak_keys)/sizeof(weak_keys[0]); i++) + weak ^= (ct_memcmp(weak_keys[i], key, DES_CBLOCK_LEN) == 0); + + return !!weak; +} + +/** + * Setup a des key schedule from a key. Deprecated function, use + * DES_set_key_unchecked() or DES_set_key_checked() instead. + * + * @param key a key to initialize the key schedule with. + * @param ks a key schedule to initialize. + * + * @return 0 on success + * @ingroup hcrypto_des + */ + +int HC_DEPRECATED +DES_set_key(DES_cblock *key, DES_key_schedule *ks) +{ + return DES_set_key_checked(key, ks); +} + +/** + * Setup a des key schedule from a key. The key is no longer needed + * after this transaction and can cleared. + * + * Does NOT check that the key is weak for or have wrong parity. + * + * @param key a key to initialize the key schedule with. + * @param ks a key schedule to initialize. + * + * @return 0 on success + * @ingroup hcrypto_des + */ + +int +DES_set_key_unchecked(DES_cblock *key, DES_key_schedule *ks) +{ + uint32_t t1, t2; + uint32_t c, d; + int shifts[16] = { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + uint32_t *k = &ks->ks[0]; + int i; + + t1 = (uint32_t)((*key)[0]) << 24 + | (uint32_t)((*key)[1]) << 16 + | (uint32_t)((*key)[2]) << 8 + | (*key)[3]; + t2 = (uint32_t)((*key)[4]) << 24 + | (uint32_t)((*key)[5]) << 16 + | (uint32_t)((*key)[6]) << 8 + | (*key)[7]; + + c = (pc1_c_3[(t1 >> (5 )) & 0x7] << 3) + | (pc1_c_3[(t1 >> (5 + 8 )) & 0x7] << 2) + | (pc1_c_3[(t1 >> (5 + 8 + 8 )) & 0x7] << 1) + | (pc1_c_3[(t1 >> (5 + 8 + 8 + 8)) & 0x7] << 0) + | (pc1_c_4[(t2 >> (4 )) & 0xf] << 3) + | (pc1_c_4[(t2 >> (4 + 8 )) & 0xf] << 2) + | (pc1_c_4[(t2 >> (4 + 8 + 8 )) & 0xf] << 1) + | (pc1_c_4[(t2 >> (4 + 8 + 8 + 8)) & 0xf] << 0); + + + d = (pc1_d_3[(t2 >> (1 )) & 0x7] << 3) + | (pc1_d_3[(t2 >> (1 + 8 )) & 0x7] << 2) + | (pc1_d_3[(t2 >> (1 + 8 + 8 )) & 0x7] << 1) + | (pc1_d_3[(t2 >> (1 + 8 + 8 + 8)) & 0x7] << 0) + | (pc1_d_4[(t1 >> (1 )) & 0xf] << 3) + | (pc1_d_4[(t1 >> (1 + 8 )) & 0xf] << 2) + | (pc1_d_4[(t1 >> (1 + 8 + 8 )) & 0xf] << 1) + | (pc1_d_4[(t1 >> (1 + 8 + 8 + 8)) & 0xf] << 0); + + for (i = 0; i < 16; i++) { + uint32_t kc, kd; + + ROTATE_LEFT28(c, shifts[i]); + ROTATE_LEFT28(d, shifts[i]); + + kc = pc2_c_1[(c >> 22) & 0x3f] | + pc2_c_2[((c >> 16) & 0x30) | ((c >> 15) & 0xf)] | + pc2_c_3[((c >> 9 ) & 0x3c) | ((c >> 8 ) & 0x3)] | + pc2_c_4[((c >> 2 ) & 0x20) | ((c >> 1) & 0x18) | (c & 0x7)]; + kd = pc2_d_1[(d >> 22) & 0x3f] | + pc2_d_2[((d >> 15) & 0x30) | ((d >> 14) & 0xf)] | + pc2_d_3[ (d >> 7 ) & 0x3f] | + pc2_d_4[((d >> 1 ) & 0x3c) | ((d ) & 0x3)]; + + /* Change to byte order used by the S boxes */ + *k = (kc & 0x00fc0000L) << 6; + *k |= (kc & 0x00000fc0L) << 10; + *k |= (kd & 0x00fc0000L) >> 10; + *k++ |= (kd & 0x00000fc0L) >> 6; + *k = (kc & 0x0003f000L) << 12; + *k |= (kc & 0x0000003fL) << 16; + *k |= (kd & 0x0003f000L) >> 4; + *k++ |= (kd & 0x0000003fL); + } + + return 0; +} + +/** + * Just like DES_set_key_unchecked() except checking that the key is + * not weak for or have correct parity. + * + * @param key a key to initialize the key schedule with. + * @param ks a key schedule to initialize. + * + * @return 0 on success, -1 on invalid parity, -2 on weak key. + * @ingroup hcrypto_des + */ + +int +DES_set_key_checked(DES_cblock *key, DES_key_schedule *ks) +{ + if (!DES_check_key_parity(key)) { + memset(ks, 0, sizeof(*ks)); + return -1; + } + if (DES_is_weak_key(key)) { + memset(ks, 0, sizeof(*ks)); + return -2; + } + return DES_set_key_unchecked(key, ks); +} + +/** + * Compatibility function for eay libdes, works just like + * DES_set_key_checked(). + * + * @param key a key to initialize the key schedule with. + * @param ks a key schedule to initialize. + * + * @return 0 on success, -1 on invalid parity, -2 on weak key. + * @ingroup hcrypto_des + */ + +int +DES_key_sched(DES_cblock *key, DES_key_schedule *ks) +{ + return DES_set_key_checked(key, ks); +} + +/* + * + */ + +static void +load(const unsigned char *b, uint32_t v[2]) +{ + v[0] = (uint32_t)(b[0]) << 24; + v[0] |= (uint32_t)(b[1]) << 16; + v[0] |= (uint32_t)(b[2]) << 8; + v[0] |= b[3]; + v[1] = (uint32_t)(b[4]) << 24; + v[1] |= (uint32_t)(b[5]) << 16; + v[1] |= (uint32_t)(b[6]) << 8; + v[1] |= b[7]; +} + +static void +store(const uint32_t v[2], unsigned char *b) +{ + b[0] = (v[0] >> 24) & 0xffU; + b[1] = (v[0] >> 16) & 0xffU; + b[2] = (v[0] >> 8) & 0xffU; + b[3] = (v[0] >> 0) & 0xffU; + b[4] = (v[1] >> 24) & 0xffU; + b[5] = (v[1] >> 16) & 0xffU; + b[6] = (v[1] >> 8) & 0xffU; + b[7] = (v[1] >> 0) & 0xffU; +} + +/** + * Encrypt/decrypt a block using DES. Also called ECB mode + * + * @param u data to encrypt + * @param ks key schedule to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_encrypt(uint32_t u[2], DES_key_schedule *ks, int encp) +{ + IP(u); + desx(u, ks, encp); + FP(u); +} + +/** + * Encrypt/decrypt a block using DES. + * + * @param input data to encrypt + * @param output data to encrypt + * @param ks key schedule to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_ecb_encrypt(DES_cblock *input, DES_cblock *output, + DES_key_schedule *ks, int encp) +{ + uint32_t u[2]; + load(*input, u); + DES_encrypt(u, ks, encp); + store(u, *output); +} + +/** + * Encrypt/decrypt a block using DES in Chain Block Cipher mode (cbc). + * + * The IV must always be diffrent for diffrent input data blocks. + * + * @param in data to encrypt + * @param out data to encrypt + * @param length length of data + * @param ks key schedule to use + * @param iv initial vector to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_cbc_encrypt(const void *in, void *out, long length, + DES_key_schedule *ks, DES_cblock *iv, int encp) +{ + const unsigned char *input = in; + unsigned char *output = out; + uint32_t u[2]; + uint32_t uiv[2]; + + load(*iv, uiv); + + if (encp) { + while (length >= DES_CBLOCK_LEN) { + load(input, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + uiv[0] = u[0]; uiv[1] = u[1]; + store(u, output); + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + store(u, output); + } + } else { + uint32_t t[2]; + while (length >= DES_CBLOCK_LEN) { + load(input, u); + t[0] = u[0]; t[1] = u[1]; + DES_encrypt(u, ks, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + store(u, output); + uiv[0] = t[0]; uiv[1] = t[1]; + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + DES_encrypt(u, ks, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + store(u, output); + } + } + uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0; +} + +/** + * Encrypt/decrypt a block using DES in Propagating Cipher Block + * Chaining mode. This mode is only used for Kerberos 4, and it should + * stay that way. + * + * The IV must always be diffrent for diffrent input data blocks. + * + * @param in data to encrypt + * @param out data to encrypt + * @param length length of data + * @param ks key schedule to use + * @param iv initial vector to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_pcbc_encrypt(const void *in, void *out, long length, + DES_key_schedule *ks, DES_cblock *iv, int encp) +{ + const unsigned char *input = in; + unsigned char *output = out; + uint32_t u[2]; + uint32_t uiv[2]; + + load(*iv, uiv); + + if (encp) { + uint32_t t[2]; + while (length >= DES_CBLOCK_LEN) { + load(input, u); + t[0] = u[0]; t[1] = u[1]; + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + uiv[0] = u[0] ^ t[0]; uiv[1] = u[1] ^ t[1]; + store(u, output); + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + store(u, output); + } + } else { + uint32_t t[2]; + while (length >= DES_CBLOCK_LEN) { + load(input, u); + t[0] = u[0]; t[1] = u[1]; + DES_encrypt(u, ks, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + store(u, output); + uiv[0] = t[0] ^ u[0]; uiv[1] = t[1] ^ u[1]; + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + DES_encrypt(u, ks, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + } + } + uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0; +} + +/* + * + */ + +static void +_des3_encrypt(uint32_t u[2], DES_key_schedule *ks1, DES_key_schedule *ks2, + DES_key_schedule *ks3, int encp) +{ + IP(u); + if (encp) { + desx(u, ks1, 1); /* IP + FP cancel out each other */ + desx(u, ks2, 0); + desx(u, ks3, 1); + } else { + desx(u, ks3, 0); + desx(u, ks2, 1); + desx(u, ks1, 0); + } + FP(u); +} + +/** + * Encrypt/decrypt a block using triple DES using EDE mode, + * encrypt/decrypt/encrypt. + * + * @param input data to encrypt + * @param output data to encrypt + * @param ks1 key schedule to use + * @param ks2 key schedule to use + * @param ks3 key schedule to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_ecb3_encrypt(DES_cblock *input, + DES_cblock *output, + DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + int encp) +{ + uint32_t u[2]; + load(*input, u); + _des3_encrypt(u, ks1, ks2, ks3, encp); + store(u, *output); + return; +} + +/** + * Encrypt/decrypt using Triple DES in Chain Block Cipher mode (cbc). + * + * The IV must always be diffrent for diffrent input data blocks. + * + * @param in data to encrypt + * @param out data to encrypt + * @param length length of data + * @param ks1 key schedule to use + * @param ks2 key schedule to use + * @param ks3 key schedule to use + * @param iv initial vector to use + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_ede3_cbc_encrypt(const void *in, void *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, + DES_cblock *iv, int encp) +{ + const unsigned char *input = in; + unsigned char *output = out; + uint32_t u[2]; + uint32_t uiv[2]; + + load(*iv, uiv); + + if (encp) { + while (length >= DES_CBLOCK_LEN) { + load(input, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + _des3_encrypt(u, ks1, ks2, ks3, 1); + uiv[0] = u[0]; uiv[1] = u[1]; + store(u, output); + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + _des3_encrypt(u, ks1, ks2, ks3, 1); + store(u, output); + } + } else { + uint32_t t[2]; + while (length >= DES_CBLOCK_LEN) { + load(input, u); + t[0] = u[0]; t[1] = u[1]; + _des3_encrypt(u, ks1, ks2, ks3, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + store(u, output); + uiv[0] = t[0]; uiv[1] = t[1]; + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + output += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + _des3_encrypt(u, ks1, ks2, ks3, 0); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + store(u, output); + } + } + store(uiv, *iv); + uiv[0] = 0; u[0] = 0; uiv[1] = 0; u[1] = 0; +} + +/** + * Encrypt/decrypt using DES in cipher feedback mode with 64 bit + * feedback. + * + * The IV must always be diffrent for diffrent input data blocks. + * + * @param in data to encrypt + * @param out data to encrypt + * @param length length of data + * @param ks key schedule to use + * @param iv initial vector to use + * @param num offset into in cipher block encryption/decryption stop last time. + * @param encp if non zero, encrypt. if zero, decrypt. + * + * @ingroup hcrypto_des + */ + +void +DES_cfb64_encrypt(const void *in, void *out, + long length, DES_key_schedule *ks, DES_cblock *iv, + int *num, int encp) +{ + const unsigned char *input = in; + unsigned char *output = out; + unsigned char tmp[DES_CBLOCK_LEN]; + uint32_t uiv[2]; + + load(*iv, uiv); + + assert(*num >= 0 && *num < DES_CBLOCK_LEN); + + if (encp) { + int i = *num; + + while (length > 0) { + if (i == 0) + DES_encrypt(uiv, ks, 1); + store(uiv, tmp); + for (; i < DES_CBLOCK_LEN && i < length; i++) { + output[i] = tmp[i] ^ input[i]; + } + if (i == DES_CBLOCK_LEN) + load(output, uiv); + output += i; + input += i; + length -= i; + if (i == DES_CBLOCK_LEN) + i = 0; + } + store(uiv, *iv); + *num = i; + } else { + int i = *num; + unsigned char c; + + memset(tmp, 0, DES_CBLOCK_LEN); + while (length > 0) { + if (i == 0) { + DES_encrypt(uiv, ks, 1); + store(uiv, tmp); + } + for (; i < DES_CBLOCK_LEN && i < length; i++) { + c = input[i]; + output[i] = tmp[i] ^ input[i]; + (*iv)[i] = c; + } + output += i; + input += i; + length -= i; + if (i == DES_CBLOCK_LEN) { + i = 0; + load(*iv, uiv); + } + } + store(uiv, *iv); + *num = i; + } +} + +/** + * Crete a checksum using DES in CBC encryption mode. This mode is + * only used for Kerberos 4, and it should stay that way. + * + * The IV must always be diffrent for diffrent input data blocks. + * + * @param in data to checksum + * @param output the checksum + * @param length length of data + * @param ks key schedule to use + * @param iv initial vector to use + * + * @ingroup hcrypto_des + */ + +uint32_t +DES_cbc_cksum(const void *in, DES_cblock *output, + long length, DES_key_schedule *ks, DES_cblock *iv) +{ + const unsigned char *input = in; + uint32_t uiv[2]; + uint32_t u[2] = { 0, 0 }; + + load(*iv, uiv); + + while (length >= DES_CBLOCK_LEN) { + load(input, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + uiv[0] = u[0]; uiv[1] = u[1]; + + length -= DES_CBLOCK_LEN; + input += DES_CBLOCK_LEN; + } + if (length) { + unsigned char tmp[DES_CBLOCK_LEN]; + memcpy(tmp, input, length); + memset(tmp + length, 0, DES_CBLOCK_LEN - length); + load(tmp, u); + u[0] ^= uiv[0]; u[1] ^= uiv[1]; + DES_encrypt(u, ks, 1); + } + if (output) + store(u, *output); + + uiv[0] = 0; u[0] = 0; uiv[1] = 0; + return u[1]; +} + +/* + * + */ + +static unsigned char +bitswap8(unsigned char b) +{ + unsigned char r = 0; + int i; + for (i = 0; i < 8; i++) { + r = r << 1 | (b & 1); + b = b >> 1; + } + return r; +} + +/** + * Convert a string to a DES key. Use something like + * PKCS5_PBKDF2_HMAC_SHA1() to create key from passwords. + * + * @param str The string to convert to a key + * @param key the resulting key + * + * @ingroup hcrypto_des + */ + +void +DES_string_to_key(const char *str, DES_cblock *key) +{ + const unsigned char *s; + unsigned char *k; + DES_key_schedule ks; + size_t i, len; + + memset(key, 0, sizeof(*key)); + k = *key; + s = (const unsigned char *)str; + + len = strlen(str); + for (i = 0; i < len; i++) { + if ((i % 16) < 8) + k[i % 8] ^= s[i] << 1; + else + k[7 - (i % 8)] ^= bitswap8(s[i]); + } + DES_set_odd_parity(key); + if (DES_is_weak_key(key)) + k[7] ^= 0xF0; + DES_set_key(key, &ks); + DES_cbc_cksum(s, key, len, &ks, key); + memset_s(&ks, sizeof(ks), 0, sizeof(ks)); + DES_set_odd_parity(key); + if (DES_is_weak_key(key)) + k[7] ^= 0xF0; +} + +/** + * Read password from prompt and create a DES key. Internal uses + * DES_string_to_key(). Really, go use a really string2key function + * like PKCS5_PBKDF2_HMAC_SHA1(). + * + * @param key key to convert to + * @param prompt prompt to display user + * @param verify prompt twice. + * + * @return 1 on success, non 1 on failure. + */ + +int +DES_read_password(DES_cblock *key, char *prompt, int verify) +{ + char buf[512]; + int ret; + + ret = UI_UTIL_read_pw_string(buf, sizeof(buf) - 1, prompt, verify); + if (ret == 1) + DES_string_to_key(buf, key); + return ret; +} + +/* + * + */ + + +void +_DES_ipfp_test(void) +{ + DES_cblock k = "\x01\x02\x04\x08\x10\x20\x40\x80", k2; + uint32_t u[2] = { 1, 0 }; + IP(u); + FP(u); + IP(u); + FP(u); + if (u[0] != 1 || u[1] != 0) + abort(); + + load(k, u); + store(u, k2); + if (memcmp(k, k2, 8) != 0) + abort(); +} + +/* D3DES (V5.09) - + * + * A portable, public domain, version of the Data Encryption Standard. + * + * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. + * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation + * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis + * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, + * for humouring me on. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + */ + +static uint32_t SP1[64] = { + 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, + 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, + 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, + 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, + 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, + 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, + 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, + 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, + 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, + 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, + 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, + 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, + 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, + 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; + +static uint32_t SP2[64] = { + 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, + 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, + 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, + 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, + 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, + 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, + 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, + 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, + 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, + 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, + 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, + 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, + 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, + 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, + 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, + 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; + +static uint32_t SP3[64] = { + 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, + 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, + 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, + 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, + 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, + 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, + 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, + 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, + 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, + 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, + 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, + 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, + 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, + 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, + 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, + 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; + +static uint32_t SP4[64] = { + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, + 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, + 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, + 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, + 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, + 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, + 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, + 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, + 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; + +static uint32_t SP5[64] = { + 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, + 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, + 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, + 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, + 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, + 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, + 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, + 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, + 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, + 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, + 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, + 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, + 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, + 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, + 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, + 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; + +static uint32_t SP6[64] = { + 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, + 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, + 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, + 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, + 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, + 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, + 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, + 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, + 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, + 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, + 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, + 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, + 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, + 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; + +static uint32_t SP7[64] = { + 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, + 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, + 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, + 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, + 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, + 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, + 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, + 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, + 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, + 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, + 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, + 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, + 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, + 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, + 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, + 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; + +static uint32_t SP8[64] = { + 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, + 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, + 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, + 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, + 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, + 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, + 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, + 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, + 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, + 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, + 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, + 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, + 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, + 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, + 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, + 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; + +static void +IP(uint32_t v[2]) +{ + uint32_t work; + + work = ((v[0] >> 4) ^ v[1]) & 0x0f0f0f0fL; + v[1] ^= work; + v[0] ^= (work << 4); + work = ((v[0] >> 16) ^ v[1]) & 0x0000ffffL; + v[1] ^= work; + v[0] ^= (work << 16); + work = ((v[1] >> 2) ^ v[0]) & 0x33333333L; + v[0] ^= work; + v[1] ^= (work << 2); + work = ((v[1] >> 8) ^ v[0]) & 0x00ff00ffL; + v[0] ^= work; + v[1] ^= (work << 8); + v[1] = ((v[1] << 1) | ((v[1] >> 31) & 1L)) & 0xffffffffL; + work = (v[0] ^ v[1]) & 0xaaaaaaaaL; + v[0] ^= work; + v[1] ^= work; + v[0] = ((v[0] << 1) | ((v[0] >> 31) & 1L)) & 0xffffffffL; +} + +static void +FP(uint32_t v[2]) +{ + uint32_t work; + + v[0] = (v[0] << 31) | (v[0] >> 1); + work = (v[1] ^ v[0]) & 0xaaaaaaaaL; + v[1] ^= work; + v[0] ^= work; + v[1] = (v[1] << 31) | (v[1] >> 1); + work = ((v[1] >> 8) ^ v[0]) & 0x00ff00ffL; + v[0] ^= work; + v[1] ^= (work << 8); + work = ((v[1] >> 2) ^ v[0]) & 0x33333333L; + v[0] ^= work; + v[1] ^= (work << 2); + work = ((v[0] >> 16) ^ v[1]) & 0x0000ffffL; + v[1] ^= work; + v[0] ^= (work << 16); + work = ((v[0] >> 4) ^ v[1]) & 0x0f0f0f0fL; + v[1] ^= work; + v[0] ^= (work << 4); +} + +static void +desx(uint32_t block[2], DES_key_schedule *ks, int encp) +{ + uint32_t *keys; + uint32_t fval, work, right, left; + int round; + + left = block[0]; + right = block[1]; + + if (encp) { + keys = &ks->ks[0]; + + for( round = 0; round < 8; round++ ) { + work = (right << 28) | (right >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + left ^= fval; + work = (left << 28) | (left >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = left ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + right ^= fval; + } + } else { + keys = &ks->ks[30]; + + for( round = 0; round < 8; round++ ) { + work = (right << 28) | (right >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + left ^= fval; + work = (left << 28) | (left >> 4); + keys -= 4; + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = left ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + right ^= fval; + keys -= 4; + } + } + block[0] = right; + block[1] = left; +} diff --git a/third_party/heimdal/lib/hcrypto/des.h b/third_party/heimdal/lib/hcrypto/des.h new file mode 100644 index 0000000..0824408 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/des.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef _DESperate_H +#define _DESperate_H 1 + +/* symbol renaming */ +#define _DES_ipfp_test _hc_DES_ipfp_test +#define DES_cbc_cksum hc_DES_cbc_cksum +#define DES_cbc_encrypt hc_DES_cbc_encrypt +#define DES_cfb64_encrypt hc_DES_cfb64_encrypt +#define DES_check_key_parity hc_DES_check_key_parity +#define DES_ecb3_encrypt hc_DES_ecb3_encrypt +#define DES_ecb_encrypt hc_DES_ecb_encrypt +#define DES_ede3_cbc_encrypt hc_DES_ede3_cbc_encrypt +#define DES_encrypt hc_DES_encrypt +#define DES_generate_random_block hc_DES_generate_random_block +#define DES_init_random_number_generator hc_DES_init_random_number_generator +#define DES_is_weak_key hc_DES_is_weak_key +#define DES_key_sched hc_DES_key_sched +#define DES_new_random_key hc_DES_new_random_key +#define DES_pcbc_encrypt hc_DES_pcbc_encrypt +#define DES_rand_data hc_DES_rand_data +#define DES_random_key hc_DES_random_key +#define DES_read_password hc_DES_read_password +#define DES_set_key hc_DES_set_key +#define DES_set_key_checked hc_DES_set_key_checked +#define DES_set_key_unchecked hc_DES_set_key_unchecked +#define DES_set_key_sched hc_DES_set_key_sched +#define DES_set_odd_parity hc_DES_set_odd_parity +#define DES_set_random_generator_seed hc_DES_set_random_generator_seed +#define DES_set_sequence_number hc_DES_set_sequence_number +#define DES_string_to_key hc_DES_string_to_key + +/* + * + */ + +#define DES_CBLOCK_LEN 8 +#define DES_KEY_SZ 8 + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +typedef unsigned char DES_cblock[DES_CBLOCK_LEN]; +typedef struct DES_key_schedule +{ + uint32_t ks[32]; +} DES_key_schedule; + +/* + * + */ + +#ifndef HC_DEPRECATED +#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) +#define HC_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) && (_MSC_VER>1200) +#define HC_DEPRECATED __declspec(deprecated) +#else +#define HC_DEPRECATED +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void DES_set_odd_parity(DES_cblock *); +int DES_check_key_parity(DES_cblock *); +int DES_is_weak_key(DES_cblock *); +int HC_DEPRECATED DES_set_key(DES_cblock *, DES_key_schedule *); +int DES_set_key_checked(DES_cblock *, DES_key_schedule *); +int DES_set_key_unchecked(DES_cblock *, DES_key_schedule *); +int DES_key_sched(DES_cblock *, DES_key_schedule *); +void DES_string_to_key(const char *, DES_cblock *); +int DES_read_password(DES_cblock *, char *, int); + +void HC_DEPRECATED DES_rand_data(void *, int); +void HC_DEPRECATED DES_set_random_generator_seed(DES_cblock *); +void HC_DEPRECATED DES_generate_random_block(DES_cblock *); +void HC_DEPRECATED DES_set_sequence_number(void *); +void HC_DEPRECATED DES_init_random_number_generator(DES_cblock *); +void HC_DEPRECATED DES_random_key(DES_cblock *); +int HC_DEPRECATED DES_new_random_key(DES_cblock *); + + +void DES_encrypt(uint32_t [2], DES_key_schedule *, int); +void DES_ecb_encrypt(DES_cblock *, DES_cblock *, DES_key_schedule *, int); +void DES_ecb3_encrypt(DES_cblock *,DES_cblock *, DES_key_schedule *, + DES_key_schedule *, DES_key_schedule *, int); +void DES_pcbc_encrypt(const void *, void *, long, + DES_key_schedule *, DES_cblock *, int); +void DES_cbc_encrypt(const void *, void *, long, + DES_key_schedule *, DES_cblock *, int); +void DES_ede3_cbc_encrypt(const void *, void *, long, + DES_key_schedule *, DES_key_schedule *, + DES_key_schedule *, DES_cblock *, int); +void DES_cfb64_encrypt(const void *, void *, long, + DES_key_schedule *, DES_cblock *, int *, int); + + +uint32_t DES_cbc_cksum(const void *, DES_cblock *, + long, DES_key_schedule *, DES_cblock *); + + +void _DES_ipfp_test(void); + +#ifdef __cplusplus +} +#endif + + +#endif /* _DESperate_H */ diff --git a/third_party/heimdal/lib/hcrypto/destest.c b/third_party/heimdal/lib/hcrypto/destest.c new file mode 100644 index 0000000..0761ded --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/destest.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#ifdef KRB5 +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#include "des.h" + +static void +ecb_test(char key[8], char in[8], char out[8]) +{ + unsigned char k[8], indata[8], outdata[8], outdata2[8], ansdata[8]; + DES_key_schedule s; + + memcpy(k, key, 8); + memcpy(indata, in, 8); + memcpy(ansdata, out, 8); + DES_set_odd_parity(&k); + DES_set_key_unchecked(&k, &s); + DES_ecb_encrypt(&indata, &outdata, &s, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "des: encrypt"); + DES_ecb_encrypt(&outdata, &outdata2, &s, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "des: decrypt"); +} + +static void +ebc3_test(char key1[8], char key2[8], char key3[8], char in[8], char out[8]) +{ + unsigned char k1[8], k2[8], k3[8], + indata[8], outdata[8], outdata2[8], ansdata[8]; + DES_key_schedule s1, s2, s3; + + memcpy(k1, key1, 8); + memcpy(k2, key2, 8); + memcpy(k3, key3, 8); + memcpy(indata, in, 8); + memcpy(ansdata, out, 8); + DES_set_odd_parity(&k1); + DES_set_odd_parity(&k2); + DES_set_odd_parity(&k3); + DES_set_key_unchecked(&k1, &s1); + DES_set_key_unchecked(&k2, &s2); + DES_set_key_unchecked(&k3, &s3); + DES_ecb3_encrypt(&indata, &outdata, &s1, &s2, &s3, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "des3: encrypt"); + DES_ecb3_encrypt(&outdata, &outdata2, &s1, &s2, &s3, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "des3: decrypt"); +} + +static void +cbc_test(char key1[8], char iv[8], char in[24], char out[24]) +{ + unsigned char k1[8], + indata[24], outdata[24], outdata2[24], ansdata[24]; + DES_key_schedule s1; + DES_cblock ivdata; + + memcpy(k1, key1, 8); + memcpy(ivdata, iv, 8); + memcpy(indata, in, 24); + memcpy(ansdata, out, 24); + DES_set_odd_parity(&k1); + DES_set_key_unchecked(&k1, &s1); + DES_cbc_encrypt(indata, outdata, 24, &s1, &ivdata, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "cbc: encrypt"); + DES_cbc_encrypt(outdata, outdata2, 24, &s1, &ivdata, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "cbc: decrypt"); +} + +static void +cfb64_test(char key1[8], char iv[8], char in[23], char out[23]) +{ + unsigned char k1[8], + indata[23], outdata[23], outdata2[23], ansdata[23]; + DES_key_schedule s1; + DES_cblock ivdata; + int num; + + memcpy(k1, key1, 8); + memcpy(indata, in, 23); + memcpy(ansdata, out, 23); + DES_set_odd_parity(&k1); + DES_set_key_unchecked(&k1, &s1); + num = 0; + memcpy(ivdata, iv, 8); + DES_cfb64_encrypt(indata, outdata, 23, &s1, &ivdata, &num, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "cfb64: encrypt"); + num = 0; + memcpy(ivdata, iv, 8); + DES_cfb64_encrypt(outdata, outdata2, 23, &s1, &ivdata, &num, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "cfb64: decrypt"); +} + +static void +cbc3_test(char key1[8], char key2[8], char key3[8], + char iv[8], char in[24], char out[24]) +{ + unsigned char k1[8], k2[8], k3[8], + indata[24], outdata[24], outdata2[24], ansdata[24]; + DES_key_schedule s1, s2, s3; + DES_cblock ivdata, ivec_copy; + + memcpy(k1, key1, 8); + memcpy(k2, key2, 8); + memcpy(k3, key3, 8); + memcpy(ivdata, iv, 8); + memcpy(indata, in, 24); + memcpy(ansdata, out, 24); + DES_set_odd_parity(&k1); + DES_set_odd_parity(&k2); + DES_set_odd_parity(&k3); + DES_set_key_unchecked(&k1, &s1); + DES_set_key_unchecked(&k2, &s2); + DES_set_key_unchecked(&k3, &s3); + memcpy(&ivec_copy, &ivdata, sizeof(ivec_copy)); + DES_ede3_cbc_encrypt(indata, outdata, 24, + &s1, &s2, &s3, &ivec_copy, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "cbc3: encrypt"); + memcpy(&ivec_copy, &ivdata, sizeof(ivec_copy)); + DES_ede3_cbc_encrypt(outdata, outdata2, 24, + &s1, &s2, &s3, &ivec_copy, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "cbc3: decrypt"); +} + + +static void +pcbc_test(char key1[8], char iv[8], char in[24], char out[24]) +{ + unsigned char k1[8], + indata[24], outdata[24], outdata2[24], ansdata[24]; + DES_key_schedule s1; + DES_cblock ivdata; + + memcpy(k1, key1, 8); + memcpy(ivdata, iv, 8); + memcpy(indata, in, 24); + memcpy(ansdata, out, 24); + DES_set_odd_parity(&k1); + DES_set_key_unchecked(&k1, &s1); + DES_pcbc_encrypt(indata, outdata, 24, &s1, &ivdata, 1); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "pcbc: encrypt"); + DES_pcbc_encrypt(outdata, outdata2, 24, &s1, &ivdata, 0); + if (memcmp(indata, outdata2, sizeof(outdata2)) != 0) + errx(1, "pcbc: decrypt"); +} + +static void +cbc_cksum(char key1[8], char iv[8], char *in, size_t len, + uint32_t ret, char out[8]) +{ + unsigned char k1[8], indata[24], ansdata[8]; + DES_key_schedule s1; + DES_cblock ivdata, outdata; + uint32_t r; + + memcpy(k1, key1, 8); + memcpy(ivdata, iv, 8); + memcpy(indata, in, len); + memcpy(ansdata, out, 8); + DES_set_odd_parity(&k1); + DES_set_key_unchecked(&k1, &s1); + r = DES_cbc_cksum(indata, &outdata, len, &s1, &ivdata); + if (ret != r) + errx(1, "cbc_cksum: cksum error"); + if (memcmp(outdata, ansdata, sizeof(ansdata)) != 0) + errx(1, "cbc_cksum: checksum"); +} + +static void +s2k(char *password, const char *salt, char akey[8]) +{ + DES_cblock k; + size_t l = strlen(password) + strlen(salt); + char *pw = malloc(l + 1); + strcpy(pw, password); + strcat(pw, salt); + + DES_string_to_key(pw, &k); + if (memcmp(akey, &k, 8) != 0) + errx(1, "key wrong for '%s'", pw); + free(pw); +} + +static void +weak_test(int is_weak, const char akey[8]) +{ + DES_cblock key; + memcpy(&key, akey, sizeof(key)); + if (DES_is_weak_key(&key) != is_weak) + errx(1, "weakness is wrong"); +} + +/* + * + */ + +int +main(int argc, char **argv) +{ + _DES_ipfp_test(); + + ecb_test("\x31\x16\xe3\x57\x97\xa8\x68\xe5", + "\xbb\xe4\x48\x6e\xdf\x9a\x05\x4f", + "\xa8\x82\xa0\x15\x76\xeb\xfd\xc7"); + ecb_test("\xfe\x4a\x19\xa1\x45\xa7\xb9\xd0", + "\x2a\x67\x3c\x07\x59\x4d\xde\xb8", + "\x9d\x61\xd5\x1c\xd7\xd0\xd3\x8b"); + ecb_test("\xbf\x13\x25\xec\xa4\xbc\x1a\x54", + "\x16\xa5\xd9\x30\x0f\x55\x20\x71", + "\x04\x44\x6c\xe0\x32\x32\x78\xd2"); + + ebc3_test("\x7c\x2f\x79\xd5\xb5\x37\x01\xcb", + "\xb9\xbc\x86\xea\x04\x45\xab\x2c", + "\x19\x1c\xcd\x83\x8a\x29\x97\x3e", + "\x87\x03\x59\xdd\xf4\xc6\xeb\xb7", + "\xcc\x72\x66\x85\xed\xa2\xee\x09"); + ebc3_test("\x10\x34\x32\x4c\xc4\x9b\x57\x5b", + "\xb0\x6e\xb6\x26\xd6\x52\x2c\x15", + "\xa7\x64\xf8\x20\xc1\x89\x73\xc1", + "\x37\xa4\xad\x4d\x76\xee\x7c\x02", + "\xdf\xb9\x2b\x99\x59\x71\xc4\x89"); + ebc3_test("\xf8\xa7\xfd\xe6\x6d\x73\x34\x26", + "\x4c\xbf\x40\x5d\x5d\xf4\x31\xef", + "\x04\xdf\xf2\x58\xd0\x5e\x54\x68", + "\x44\x2a\xa2\x19\xbd\x0a\x2b\x61", + "\x17\x26\x39\xd5\xd5\xd9\x40\x71"); + ebc3_test("\x13\x5e\x23\x07\x2c\x16\x0d\x25", + "\x64\x6d\x2f\xe0\x68\xa8\x16\x75", + "\x7c\x7c\x19\x64\xbc\xae\xe0\x0e", + "\x7b\x8c\x76\x76\xb0\x95\x7f\xed", + "\xe2\x6e\x05\x1d\xdc\x74\xc1\xb7"); + ebc3_test("\xbc\x92\x32\xb6\x68\x0d\x73\x19", + "\x70\xef\x98\x19\xe9\xec\x04\x1c", + "\x02\x4c\x75\x08\xce\xc4\x34\x16", + "\x73\xab\x28\x69\x6a\x20\x2f\x99", + "\x3b\xb1\x2d\xb6\x21\x0a\x44\xca"); + ebc3_test("\x01\x98\x16\xea\x85\xd5\x3b\x8a", + "\x73\x23\xb5\x49\xd9\x10\x5b\xea", + "\xb6\xc4\xce\xc4\x89\x92\x0e\x15", + "\xd9\x35\xcf\x21\x47\x7b\xdf\xb5", + "\xa1\x71\x57\x1f\x1e\x84\x08\xac"); + ebc3_test("\x58\x6d\xbc\x04\x70\x4f\xe6\x3e", + "\xcd\x76\x26\x01\xae\xce\x0b\xe5", + "\xf2\x4f\x64\x16\x8f\x0d\x4f\x6b", + "\xa7\x0d\xa0\x56\xa0\x8b\x2a\x77", + "\xe5\x12\x9b\x8a\x92\xc8\xdd\xe1"); + ebc3_test("\x40\xd6\xad\x43\x52\x23\xa7\xcd", + "\x04\x19\xae\x94\xce\x46\x31\xd3", + "\x45\x6e\x3b\xb5\x4f\x37\x5e\x9d", + "\xbd\xb0\x60\x75\x91\x02\x48\xf4", + "\xb5\xa1\xe6\x4b\x4e\xa3\x8c\x4b"); + ebc3_test("\x91\xab\x80\x9b\x97\xf4\x58\x5e", + "\xc2\x68\x46\x61\x9e\x04\xa1\x29", + "\xc7\xe5\x5b\x32\xcb\x43\xc8\xa4", + "\x31\x38\x90\x1c\xc8\x78\x12\x50", + "\xf8\x65\xae\xa1\xdf\x4e\xbf\xa8"); + + cbc_test("\x57\x98\x7a\x8a\x29\x7c\xc1\xad", + "\xe1\x28\x69\x58\xd6\x91\x9f\x4e", + "\xa0\x11\x1a\xdd\xeb\x62\xb8\x9e\x28\x08\x6e\x0b\x6d\x6d\x57\x31\x1b\x4c\x82\x4c\xc3\x19\xe0\x93", + "\x42\xa5\x2f\x26\xbb\x92\x3a\x6b\x64\xe0\x3b\x1a\x33\x5a\x9c\x2b\xc8\xd9\x41\x37\x8d\x3e\x58\xbf"); + cbc_test("\x23\xd6\xec\x86\x86\x4f\x02\xcd", + "\xfe\x8e\xa4\x07\x35\x41\x14\x99", + "\xe3\xc2\x5d\x6e\x81\xae\xa0\xe8\xc8\xdd\xd2\x0d\xf4\x26\x90\x10\xca\x8c\x07\x58\xb2\x17\xcc\x1a", + "\x97\xb9\xbc\xa6\xd1\x98\xc1\x7f\x4b\xac\x61\x8a\x16\xec\x1f\xee\x28\x6f\xe8\x25\xf0\x41\xbc\xde"); + cbc_test("\x07\xe5\xc8\x52\xba\x3d\xef\xcd", + "\xa9\x21\x3e\x84\x44\x7c\xce\x1a", + "\xfc\x03\x72\x30\xb0\xcb\xe8\x99\x21\x54\x4d\xfa\x86\xdd\x99\xe1\x96\xe7\x7c\xb5\xbd\x5b\x6f\xd0", + "\x27\x76\x66\x62\x1f\xcf\x48\xdb\x15\x11\x73\x8b\xe0\xc9\xbd\x2b\x40\xae\x0c\x35\xeb\x93\xa3\x1c"); + cbc_test("\xef\x2f\x07\xd6\x2f\x70\x4f\x68", + "\x16\x1e\xaf\x87\x3a\x83\x9f\x33", + "\xb8\x4c\xb3\xbf\xfa\x5d\xa9\xc7\x1c\x15\x8d\x39\xf2\x29\xf5\x5a\x3d\x21\x0d\x61\x05\xaa\x48\x92", + "\x51\x85\x2f\xad\x67\xb6\x0a\x15\xb8\x73\x15\xf1\x79\x9d\xed\xf5\x6c\x11\x22\xe5\x48\x51\xab\xae"); + cbc_test("\xd0\x2c\x68\xc1\xe6\xb0\x76\x98", + "\xc7\x4f\x31\xa9\x5d\xd5\x5b\xcc", + "\x9d\x4b\x2a\x54\x60\xf1\xb0\x10\x34\x87\xdc\x25\xa5\x80\x6c\x4d\x0c\x7f\x53\x37\x58\x42\xc7\x26", + "\x79\xc5\xf0\x21\x0d\x7a\x38\xc0\x66\x9a\x07\x2f\xa4\x9c\x1f\xbb\x66\x4d\x6c\x86\x5b\x47\x44\x60"); + cbc_test("\xd6\xe3\x75\x92\xb0\x8f\x45\x70", + "\xdc\xc6\xab\x3e\xf2\x7e\x13\xd6", + "\x38\x57\x27\x0a\xef\x74\x94\x82\x92\xfa\x28\xed\xff\x24\x1e\x0e\x8f\xaa\x9e\x24\x2f\x41\x65\x78", + "\x1d\xcc\x07\x55\xe8\xea\xd1\x08\x55\x11\x72\xfe\xdb\xdf\xa0\xc9\xb6\x3a\x2e\xdf\xf0\x67\xd3\xf4"); + cbc_test("\xb3\xbc\xb5\x61\x04\xda\x1a\x34", + "\x8e\x4e\xa5\x8a\xeb\x6a\xea\xbb", + "\x72\x73\x51\xe0\x58\xc5\x2e\xe1\x64\x10\x05\x59\x64\x70\x3f\xbe\x43\xa2\xed\x7a\x5d\x1b\x9c\xc7", + "\xa6\xb2\xf2\xea\x96\x62\xfb\x2f\x2a\x6a\xa1\x2f\x8e\xe1\x12\xd2\xe4\x82\x4c\xc1\x00\x74\x9c\x8f"); + cbc_test("\x8f\xdf\x01\x89\xfe\x13\x9b\x2c", + "\x66\x18\xf8\x80\xa1\x3b\x1b\x91", + "\x32\xdb\xae\xa7\x3b\x77\xb2\x6e\xcc\xa5\xa1\x2e\x15\x19\x49\x83\x2f\xfb\x94\xcc\xd1\xa1\x4b\x02", + "\x47\x31\xca\x04\x4d\x1a\x24\x39\xda\x71\xc5\xb8\x7f\xea\x79\xf5\x43\xa6\x53\x15\x78\x84\x34\x75"); + cbc_test("\xe5\x34\xb6\x75\x68\x07\x70\x85", + "\x73\x98\x29\xf7\x7a\xe7\xe7\xb7", + "\x9c\x9e\x4c\xa6\x62\x21\xc4\x15\x47\x43\xd5\xf2\x3a\xf3\xfd\xb5\x53\xa7\x16\x9e\xa6\x4f\x0d\xac", + "\x81\x2d\xa4\x99\x60\xbf\x9c\xf4\x46\x1d\xee\xc6\xb0\xe1\x4a\x29\xea\xfd\xce\x4b\xa1\x45\x93\x7b"); + + cbc3_test("\x61\xcb\x8c\xb0\x32\x2a\xc2\x5d", + "\x98\xe3\x49\xc1\x0d\xb5\x67\xce", + "\xf2\x43\x10\x61\x85\x6b\xa7\x15", + "\x65\xf5\x8f\x1a\x2b\x33\xf2\xb5", + "\x8c\x06\xe0\x60\x68\x25\x9c\x95\x81\x46\xda\x41\x9d\xa8\x9c\x49\x2f\xee\x33\x35\x95\x11\xbd\xa0", + "\x93\x27\xed\xc7\x35\xb9\xe5\x3c\x7b\x10\x3e\x39\x01\x41\x61\x04\xe7\xf2\xd9\x63\x96\xca\x57\xf1"); + cbc3_test("\x15\x61\x6b\x76\xae\x0e\x98\x01", + "\x76\xce\x9d\x94\xa7\xe3\x73\xa4", + "\x19\xd9\x15\x98\x9b\xba\x83\x40", + "\x60\xef\xc2\xc6\xa2\x40\x01\xc7", + "\x8b\x4d\xf4\x37\xad\x1c\xc2\x4e\xcc\xc4\x4b\x17\x67\xf7\xfa\xec\xf8\x94\x6f\x7a\x84\x56\x81\x09", + "\x68\xdf\x82\xcb\xd9\xcd\x3d\xca\x12\x0e\x2e\x39\xba\xf7\x5a\x8c\x41\xbd\x6f\x9d\x85\xfe\x1b\x1d"); + cbc3_test("\xd5\x2a\x4f\xa4\x13\x9e\x73\x15", + "\x6d\x75\xa8\x15\x07\xd3\x7c\x79", + "\xd5\xe0\xa7\x91\xf8\xf2\x9d\xcd", + "\x4c\xdb\x56\xb8\x6f\x0e\x2a\x59", + "\xbe\x64\x20\x24\x7d\x2b\x6b\xf4\xd9\xc0\xa0\x9b\x8d\x88\x6e\x50\x6f\xf8\xb6\x4a\x7e\x52\x52\x93", + "\x01\x83\x75\x7b\xd6\x03\xff\xd8\xe9\x6d\x6c\x92\x24\x25\x35\xfa\x43\x4c\x40\xff\xec\xb0\x8b\x50"); + cbc3_test("\x02\xad\x13\x31\xd5\xd6\xef\x7c", + "\x86\x3e\x02\xce\x94\x97\x37\xba", + "\x01\x07\x20\x04\xf8\x92\xb6\xb3", + "\x26\x79\x1b\xef\x90\x54\xd6\xc1", + "\x55\xee\xea\x81\x42\x8b\xbf\xfb\x6c\x14\xec\xbd\xba\x55\x0d\xc4\xd2\xd6\xf0\xea\xd1\x03\xde\x5b", + "\x69\x49\xc5\x48\x4f\xda\x03\x90\x84\xef\x86\xd2\x98\xa7\xae\xfa\x17\x35\x7e\x06\xbd\xd3\x51\x0b"); + cbc3_test("\x3d\x9b\xae\x5b\x7f\x91\x85\xe0", + "\xdf\x07\xb3\xdf\x97\x0b\x43\x80", + "\xe3\x46\x58\xd9\x68\x79\xb3\xae", + "\xd4\x27\xee\x5d\x73\xb1\x82\xf5", + "\x44\x86\x9a\xa6\x79\x2d\x9e\x94\x11\x6c\x7b\xc6\xe8\xef\x63\x95\x71\xc6\x62\x20\x43\x87\xaf\x65", + "\xc2\xf5\xbc\x91\xc5\x7c\x69\xb2\x05\xcc\x28\x92\xc1\x96\x5a\xc2\xcb\x0c\x71\xc7\x51\x7d\x0c\xcc"); + cbc3_test("\x43\x8c\x23\x92\xd5\x92\x67\xfb", + "\x5b\x5e\xb0\x31\x1c\x9d\x5d\x10", + "\x8a\xa2\x16\x64\xd6\xa4\xc4\x5b", + "\x06\xc5\xdd\xa3\x4a\x2b\x37\xb7", + "\x99\xd5\x76\xee\x7c\x4d\xcc\x18\x39\x78\x16\x7c\xcc\x1a\x0a\x27\xdb\xf1\x5f\xe1\x87\x86\xb7\x2c", + "\x91\xbe\xaf\x79\xd0\x14\x7c\x05\x60\x1c\x7e\xd6\x22\x15\xac\xed\xf3\x78\xa5\xc7\x52\xa0\x60\x49"); + cbc3_test("\x80\xc2\x86\x7a\x51\x45\x29\x1c", + "\xc7\xfd\xad\xd0\x7c\x4a\xd0\x3e", + "\xe6\x89\x98\xfe\x01\x67\x20\x89", + "\x5c\x23\xe4\x26\x82\x27\xad\xeb", + "\xa1\x38\x4e\xf1\x07\x1a\xdd\x25\x47\xe6\xda\x9d\xa9\xfe\x98\x55\x05\x95\x75\xc2\x59\x18\xcf\xf1", + "\x36\x58\xea\xc5\xf8\x41\xa7\x49\xe8\x22\x75\xfe\xb6\x8b\xdd\x0d\xf0\x66\x42\xe6\x84\x23\x29\xff"); + cbc3_test("\xbc\x68\x54\x85\x2c\xc1\xe0\x07", + "\x7c\x6e\x34\x04\x6b\x91\xc4\x54", + "\x9d\xa4\xda\xa1\xda\x6d\xdc\xd3", + "\x1c\x3d\xa9\x41\xa2\xe5\xff\x8a", + "\x0a\x58\xff\x5a\xec\xc1\x7e\x94\x24\xf4\x4f\xdc\x5b\x29\xe2\x78\x62\x8a\xd2\xe2\xd7\x45\x54\x17", + "\x80\x68\xa6\xed\x87\x40\xd5\x32\xd2\xb8\x32\x61\x35\xae\xae\xf7\x14\x1f\x98\xdb\xba\x21\x4f\x9f"); + cbc3_test("\xa1\x2a\x7a\x67\xfe\xea\xd3\xe3", + "\x70\xe5\xd5\x4c\xf1\xce\x4c\x26", + "\x75\x4c\x85\x16\xb5\xc8\x07\xe9", + "\x4c\xa4\xb5\xdd\x86\x86\x70\x5a", + "\x0d\x07\xfd\x23\xc1\x1d\x65\xd8\xb2\x79\xb8\xa3\xc5\x8e\x47\xbe\x0f\xed\x7b\x15\x43\xe9\x7c\x5e", + "\xde\x17\xfe\x05\x43\x80\x85\xd0\x9c\x60\xe0\xbe\x8d\xa2\x65\x0e\x63\x02\x72\xb6\xf3\x7d\xda\x90"); + + + pcbc_test("\xe3\xf2\xb0\x26\x7c\x4a\x94\x80", + "\x40\x08\x4c\x44\xa3\xb5\xf7\x97", + "\xe7\xbd\x54\xa1\xbb\x48\x67\xcd\xe0\xee\xff\x8d\x3d\x25\x2b\xf0\x61\x48\xbe\xf2\x63\x5d\xce\x4a", + "\xf5\xe9\x48\xdc\xb8\x61\x39\xa9\x90\x27\xec\x09\x23\x50\xe0\xa9\x78\xb2\x1c\x29\x3c\xa7\x6c\x88"); + pcbc_test("\xfd\x54\x2a\x5b\x97\xa4\x5b\x52", + "\x37\x36\x6e\x22\x7e\x66\x08\x8c", + "\xe4\x2d\x81\x88\x86\xb2\x44\x55\x80\x3d\x3c\xbd\x42\x9f\x5d\xdb\x4b\x63\x23\x1c\x31\x13\xa6\x0f", + "\x9c\x9f\x65\x05\x79\x91\x71\x96\x82\x2a\xc0\xe5\xa0\x6f\x71\xab\x68\x32\xd4\xd7\x5e\x38\x38\xf6"); + pcbc_test("\x25\x91\x08\xe5\x57\x85\xb6\x20", + "\x47\x6e\xbe\x9f\xb9\x6b\x55\xe9", + "\x44\xfd\xdd\x42\x07\x99\xf0\x8f\xdb\xa5\x14\x1e\x76\x07\x90\x5b\x29\x10\x21\xb9\x7e\xac\xc7\x77", + "\x88\x4f\xdc\x6e\x37\x5e\x4e\xac\x8d\x3f\x9d\xd1\x82\x51\x65\xf5\xf9\x08\xa7\xac\x01\x61\x19\x85"); + pcbc_test("\x6d\x43\xc7\x9d\x6b\x97\x64\x40", + "\x56\xfb\xcb\xb3\x97\xb5\x70\x13", + "\x54\x67\xa9\x42\x86\x85\x81\x8f\xb4\x72\xa2\x5f\x2d\x90\xbb\x5c\xb5\xb9\x9b\x71\x8f\x2b\xae\x05", + "\x2c\xd1\x63\x6f\x11\x1d\x5e\x40\x8c\x47\x49\x12\x31\x48\xb7\x12\x4c\xc1\x6a\xaf\x0e\x33\x11\xe1"); + pcbc_test("\x3b\xa2\xbc\xd5\x5d\x9d\xdf\x73", + "\x43\xb7\x26\x71\xce\x6d\x97\xac", + "\x4e\xf6\x7d\xd7\xfc\x6b\x35\x54\xae\xc9\xfe\xf7\xb7\x1e\x47\xa5\x61\x44\x50\xb3\xe4\xe8\x7d\xdc", + "\x4d\xda\xbd\xad\xc4\xde\xdc\xf4\xfc\xbd\xfc\xa7\xbd\xe4\x7e\x73\x28\xc5\x5c\xd0\x9a\x35\x39\xa6"); + pcbc_test("\x46\x9e\xda\xdf\x0d\x97\x8a\xd3", + "\x6c\x9f\xdf\xc0\x48\x3b\xa5\x17", + "\xb9\xd8\x99\x61\x67\xf3\xec\xa9\xc1\x29\xa3\x8b\x63\xe2\xc2\x28\xaf\x56\x2d\x39\x1d\xeb\x7c\xbc", + "\x70\x5d\xd4\x54\x90\xb9\x6c\x0c\x93\x96\x6a\x4a\x4e\xb8\x80\xce\xb3\xcd\x64\xa7\x6c\xb2\xe4\xc9"); + pcbc_test("\x31\x89\x51\x38\x2f\x97\xfe\xef", + "\x17\xdc\xf8\xde\xcc\x8f\x40\x3e", + "\xef\xcf\xe9\x9e\x11\xd8\x35\xdf\x58\x11\xd0\x0a\x68\xce\xe1\x6b\xb5\xca\x68\x47\xb7\xb9\x9a\x34", + "\x3a\x93\x47\x3c\x1b\xa9\xeb\x88\x13\xfd\x1b\xd8\x76\xb5\xd3\xe2\xb8\x83\x10\x56\x68\xab\xe1\x28"); + pcbc_test("\xba\x1c\x70\x94\x62\x10\x19\xda", + "\x7a\x8b\xc0\x9e\x00\xbb\x7e\xcb", + "\x30\x74\x6b\xa6\xd6\x07\xae\x44\xd6\x5c\xe6\x18\x97\x90\xaa\x08\xcb\xa8\xf4\x8b\xea\x8b\x4f\xe6", + "\x0a\x77\x24\x7c\xcd\xf8\x06\x01\x20\x02\x14\x33\xd6\xf4\x4e\x89\xc0\x38\x65\x44\x6b\x9c\x92\x16"); + pcbc_test("\xfe\x97\xf2\x6d\x8f\x0d\x86\x94", + "\x30\x8a\x7d\x9b\xf4\x28\x6e\x84", + "\x82\xb0\x9b\x42\xf6\xdc\x38\x41\x41\x03\x60\x28\x7f\x90\x08\x8b\x6c\x55\xe7\x76\xcd\xa7\xae\xbc", + "\x35\x0b\xf1\xc0\x56\x64\x6f\x7b\x3e\x1f\xd1\x90\xbd\xda\x10\xb1\xd1\x49\xc6\x62\x5f\xf9\x6c\xf9"); + + + cbc_cksum("\x58\x83\x67\xfb\xdf\x51\x7c\xfd", + "\x46\x0a\xa5\x94\x6b\xd6\xaa\x91", + "\x15\x0b\x16\x3a\x56\x79\x33\xdf\x6e\xa0\xd9\x54\x14\x7b\x37\xa9\xb1\x15\xe1\x28\xfe\x35\xe9\x34", + 24, + 0x16466788, + "\xa7\xbd\x2a\x1b\x16\x46\x67\x88"); + cbc_cksum("\xf1\xe0\x91\x1c\xfe\x10\xe5\xb5", + "\x9c\xc6\x7d\xf3\x3e\x58\x40\x06", + "\x9c\x90\x88\xfe\x9c\x38\xc0\xd5\xaa\xc6\xf2\xc2\x7d\x00\xf6\x5f\xbd\x87\x25\xbe\x41\x64\x9f\xb7", + 24, + 0xd8a127cc, + "\x93\x5d\x75\x62\xd8\xa1\x27\xcc"); + cbc_cksum("\x20\xbf\xdc\xd5\x5b\x9d\xc8\x79", + "\x68\xdc\xe2\xfa\x18\xb3\xa9\xe0", + "\xef\xba\xc4\x8b\x78\xc2\x02\xc2\x74\x71\x9f\xfa\x4b\xa2\x8a\xe5\xfb\x82\x3d\x48\xcf\x28\x08\x42", + 24, + 0x45236285, + "\xc0\xb9\x2c\x86\x45\x23\x62\x85"); + cbc_cksum("\x31\x6d\xa8\xc2\x43\x16\x64\xea", + "\x7b\x5e\x9f\x7c\xb8\xa3\xbd\x89", + "\x8a\xd4\xe4\x77\xbb\x45\x17\x3d\xd2\xef\xe6\xb9\x65\x8b\xb3\xa9\x28\xef\xd7\x0c\xa8\x47\x5d\xb8", + 24, + 0x3f021cb2, + "\x10\x94\x4c\x2f\x3f\x02\x1c\xb2"); + cbc_cksum("\xd5\x75\x51\x8f\xc8\x97\x1a\xc4", + "\xbc\x7a\x70\x58\xae\x29\x60\x3a", + "\x8d\x2c\x70\xdb\x53\xda\x0f\x50\xd9\xb5\x81\x18\x26\x66\x84\xda\xf6\x32\xa0\xe5\xf9\x09\xfd\x35", + 24, + 0x2f64dd4f, + "\x89\xe4\x70\x0d\x2f\x64\xdd\x4f"); + cbc_cksum("\xda\x6e\x32\x80\x20\xbc\x67\x54", + "\xf4\x93\x86\x43\x29\x57\x6e\xec", + "\xfe\xd8\xfe\xad\x4e\x05\xd8\xb8\x9b\x9f\xaa\xa5\x90\x6d\xcb\xff\x40\xab\xc5\x25\x2b\xda\xa7\x09", + 24, + 0x6281ce23, + "\xa1\x88\xc2\x3d\x62\x81\xce\x23"); + cbc_cksum("\xb6\xc7\x75\x8a\xfb\xd3\xf8\xad", + "\xf1\x4f\xd7\x39\x4b\xec\xa3\x99", + "\x31\xd0\x45\x9d\x62\xe3\x49\xbb\x58\xc2\x58\xbe\x13\x51\x1e\x3f\x54\xe5\x31\x7d\xd0\x94\x57\x7a", + 24, + 0x09c7ee4e, + "\x2f\x40\xb3\xd2\x09\xc7\xee\x4e"); + cbc_cksum("\xa8\x4f\x16\xf4\x89\x3d\xf7\xec", + "\x04\x78\xbc\xd3\x4f\x32\xfd\x46", + "\xe5\x44\x30\x5e\x55\xa3\x08\xe9\xcd\xd1\xbe\x63\x66\x26\x27\x62\xc3\x4f\x2a\x50\x69\x21\x24\xde", + 24, + 0xdf3357c7, + "\xa8\x6e\x80\x3b\xdf\x33\x57\xc7"); + cbc_cksum("\xd6\x4f\x40\xef\x8a\x2a\xf1\x20", + "\xd5\x40\xe7\x86\x36\x26\x79\xc9", + "\xcc\x74\x2b\x78\xca\x47\xb0\xd3\xe6\x72\x42\x76\xee\x80\xb0\xe5\x78\x12\x3b\x4e\x76\x91\xda\x1a", + 24, + 0x14a5029a, + "\x33\xd2\xb5\x8a\x14\xa5\x02\x9a"); + + cbc_cksum("\xfb\x89\xa1\x9d\xa7\xec\xc1\x5e", + "\x9c\x7f\x47\xd0\x79\x5d\x4b\x97", + "\xb6\x8b\x48\xe0\x01\x78\xec\x50\x7f\xf1\xfd\xd2\x87\x76\xba\x4b\x9c\x5c\xc7\x25", + 20, + 0xa1471604, + "\x39\x5b\x7d\xb1\xa1\x47\x16\x04"); + cbc_cksum("\x70\xb3\xc4\x0b\x5b\x4f\x98\xe5", + "\x86\xc0\x05\x1a\xd5\x8f\x78\x2c", + "\xef\x01\x7b\xd8\xff\x68\x5d\x66\xb6\xbe\xd8\xf5\xb9\xed\x4e\xec\xe3\x3c\x12\xc5", + 20, + 0xc4b74f9a, + "\x2b\x07\xe3\x90\xc4\xb7\x4f\x9a"); + cbc_cksum("\xfe\x04\xcb\xfe\xef\x34\xe9\x58", + "\xd9\x28\xae\xc0\x2c\xd3\xf6\xb0", + "\x24\x25\x9b\x67\xda\x76\xa6\x64\x6f\x31\x94\x18\x2e\x06\x71\x82\xaf\xbd\x86\x63", + 20, + 0xbd7c84e6, + "\x70\x3e\x91\xf5\xbd\x7c\x84\xe6"); + cbc_cksum("\x10\xc2\x70\x94\x9b\x16\x20\x1c", + "\x62\xed\x5a\x48\x6c\xf3\x51\xa0", + "\x90\x3e\x06\xc1\x63\x6a\x1f\x1a\xfe\x9d\x74\xb6\x13\xde\x62\xd2\x6f\x19\x37\x25", + 20, + 0x26761f96, + "\x8b\x6a\x9c\x85\x26\x76\x1f\x96"); + cbc_cksum("\x61\x32\x7c\x7f\x31\xc7\x98\xe6", + "\xd9\xba\x0d\x9d\x9e\xa3\xcc\x66", + "\x98\x8f\xc6\x5a\x54\x04\x63\xd9\x53\x86\x5d\x75\x53\x48\xcc\xa3\x00\x7a\x12\xe5", + 20, + 0xf0f6ad33, + "\x6a\xfb\xed\xd3\xf0\xf6\xad\x33"); + cbc_cksum("\x85\xdf\x01\x2c\xab\x3b\xec\x13", + "\xc6\x44\x87\x5b\x78\x2a\x74\x92", + "\x8b\xf5\x0d\xff\x5c\xb3\xc1\xcd\x9e\xf7\xb8\x8e\x3b\xf8\x61\x4d\x26\x6a\x7b\xe8", + 20, + 0x7acfe214, + "\x52\xb7\x05\xe9\x7a\xcf\xe2\x14"); + cbc_cksum("\x49\xdf\xb0\x16\x7f\xec\x10\x52", + "\x09\xa3\x36\x8f\xe9\xe0\x06\x19", + "\x3a\x0f\x66\xf7\x7a\x47\x34\xe4\xaa\x09\x36\x90\xe9\x90\x19\xff\x99\x94\x92\x04", + 20, + 0x9a3a59bb, + "\xd3\xe2\xce\xfc\x9a\x3a\x59\xbb"); + cbc_cksum("\x5b\xbf\x4c\xc8\xce\xf4\x51\x1a", + "\x7c\xee\xc0\x5a\x20\x2b\x10\x22", + "\x05\x1d\xec\xdb\x30\x73\xf2\x21\xbf\x64\xe0\x5f\xdf\x02\x79\xe9\x47\xf2\x9c\x4e", + 20, + 0xaf9d3602, + "\xaa\xf3\xa2\x5a\xaf\x9d\x36\x02"); + cbc_cksum("\xad\xda\xa2\x19\x6d\x37\xda\x67", + "\xb2\x10\x0f\xd5\xda\xdd\x17\xfc", + "\x44\x02\x6b\xd6\xd4\x8c\x42\x58\x8b\x59\x35\xce\xd7\x04\x6b\x35\xa6\x5f\x28\x97", + 20, + 0xd112a978, + "\xb2\x5f\x6a\x07\xd1\x12\xa9\x78"); + + + s2k("potatoe", "WHITEHOUSE.GOVdanny", + "\xdf\x3d\x32\xa7\x4f\xd9\x2a\x01"); + s2k("password", "ATHENA.MIT.EDUraeburn", + "\xCB\xC2\x2F\xAE\x23\x52\x98\xE3"); + s2k("\xf0\x9d\x84\x9e", "EXAMPLE.COMpianist", + "\x4f\xfb\x26\xba\xb0\xcd\x94\x13"); + s2k("NNNN6666", "FFFFAAAA", + "\xc4\xbf\x6b\x25\xad\xf7\xa4\xf8"); + s2k("", "", + "\x01\x01\x01\x01\x01\x01\x01\xf1"); + + cfb64_test("\x45\xc2\x0b\x01\x40\x08\x13\x8a", + "\x9a\xef\xf4\x37\x41\x69\x0b\xd6", + "\x5d\x12\x5d\xf5\xae\x1d\xc6\x47\x21\xd3\x16\xba\x45\x0e\x9d\x4c\x00\xfd\xf8\x64\xca\x69\x67", + "\xff\x99\x06\xd8\xe9\xbc\xae\x7e\xde\x49\x7b\x34\x5d\xa0\x74\x61\x9b\x6f\x70\x38\x40\x40\xba"); + cfb64_test("\xdc\xe9\x51\xc4\x0b\xad\x85\xa8", + "\xf5\x56\x6c\xef\x42\xed\x9f\xa8", + "\x7d\xe5\xeb\x04\x5c\xaf\x8c\x5b\xf4\x88\xba\x4a\x99\x6a\x3a\x79\xc0\x88\x01\x05\xac\x98\x3c", + "\x53\x87\x11\xc4\xa6\xf3\x1e\x67\x56\xfc\x8c\x63\xf0\x2e\xd9\x0e\x4a\x86\x8e\x5b\xa7\xde\xcf"); + cfb64_test("\x25\xf7\xa7\x0e\x85\x4f\x5b\xb6", + "\x83\xae\x73\x03\xea\xeb\x82\x05", + "\x1b\x80\x23\xdc\x61\x23\xa7\xde\x80\xf6\xec\xb1\xc1\x6d\x3e\x59\x1f\x76\x6d\xdf\xfa\x42\xc7", + "\xe2\xf7\x8d\x2f\x86\xce\x1f\xfc\xdb\x82\xb9\xb5\x9c\xa9\xf4\x9c\x2b\x3f\x34\x6c\x83\xf7\x7e"); + cfb64_test("\xab\xd5\xd3\x68\xf1\x2c\x0e\x0d", + "\x8a\xea\xe8\xc0\xad\xb9\x51\x83", + "\x3d\xcb\x7d\xcf\x57\xa6\xf6\x16\x4f\x34\xb6\x5f\xc2\xa9\xf0\xec\x90\xc5\x43\xa0\x19\xfc\x3f", + "\xe9\x2c\x22\x20\xd4\x27\x90\x89\x40\x08\x4a\x23\x4d\x41\x05\x67\xe1\xde\xf5\x0b\x8b\x96\xb1"); + cfb64_test("\x92\x38\xd3\xfd\x61\x83\x92\x0e", + "\x25\xb6\x34\x51\x6d\x6a\x35\xa2", + "\x98\x55\xab\x2a\xa2\x9e\xcf\xf4\x92\xdf\xb4\xc6\xc1\x34\x55\xf6\x13\x85\x4c\x50\xdc\x82\x1e", + "\x87\x96\x47\xa6\xcd\xff\xda\xd2\xad\x88\xaa\x25\xbd\xcd\x72\x61\x37\x14\x42\x14\xc7\x4b\x7f"); + cfb64_test("\xf4\xcb\x97\xad\xef\x7f\x80\xb0", + "\xfc\xa0\x7d\xb6\x75\xb8\x48\xea", + "\xc2\x1e\x16\x2b\xb7\xcf\xc6\xa0\x4b\x76\x75\x61\x49\x66\x0d\xce\xd2\x12\xf2\x98\x07\x2f\xac", + "\xe2\x20\xbf\x29\x5b\x34\x20\x2a\x2e\x99\xa5\x50\x97\x1b\x4b\x18\xb4\xd6\x87\x35\x7b\x5f\x43"); + cfb64_test("\x3b\x1c\x15\xec\xb9\x5e\xe0\xda", + "\x7d\x94\x23\x76\x96\x72\x62\xf4", + "\x5d\x83\xdb\x76\x52\x46\xa7\x84\x0a\x71\x2c\x09\x40\xbd\x3d\x75\x73\x28\x0b\x22\x07\x6f\x8a", + "\xf1\x01\x8f\xe2\x32\x35\xe6\x06\xcf\xbb\xe4\x15\x9e\x4e\xf0\xe8\x2e\xcd\xac\xbf\xa6\xc2\xec"); + cfb64_test("\xc2\xcd\x76\x79\x7f\x51\xce\x86", + "\x38\xcf\x55\x7d\x0c\xd5\x35\xfe", + "\xc7\xe5\xe8\x1d\x19\x09\x9f\xd5\xdb\x89\x26\xc1\xf1\xc1\x18\x50\xcf\x8b\xf2\xe1\x87\xeb\xe6", + "\xd4\x5d\xca\x30\xb9\x41\xfa\x36\x83\xfc\x40\x2d\xd2\xe8\x94\x38\x49\xc8\xa3\x35\xb7\x5d\x9c"); + cfb64_test("\x67\xfd\xc4\x31\x45\x40\xf7\xea", + "\xb9\x29\xe6\x78\xdd\x1a\x13\x84", + "\x12\x9b\xe5\xb3\xdd\x42\x6f\x45\x86\x97\x25\x87\x05\xee\x7e\x57\x8f\x22\x79\xb3\x22\xa2\x95", + "\x38\xef\x49\xbc\xdd\xbb\x6b\x73\xc0\xd7\xa6\x70\xe0\x1b\xde\x8d\xe6\xb4\xc6\x69\xca\x5e\x1e"); + + weak_test(1, "\x01\x01\x01\x01\x01\x01\x01\x01"); /* weak keys */ + weak_test(1, "\x01\x01\x01\x01\x01\x01\x01\x01"); + weak_test(1, "\xFE\xFE\xFE\xFE\xFE\xFE\xFE\xFE"); + weak_test(1, "\x1F\x1F\x1F\x1F\x0E\x0E\x0E\x0E"); + weak_test(1, "\xE0\xE0\xE0\xE0\xF1\xF1\xF1\xF1"); + weak_test(1, "\x01\xFE\x01\xFE\x01\xFE\x01\xFE"); /* semi-weak keys */ + weak_test(1, "\xFE\x01\xFE\x01\xFE\x01\xFE\x01"); + weak_test(1, "\x1F\xE0\x1F\xE0\x0E\xF1\x0E\xF1"); + weak_test(1, "\xE0\x1F\xE0\x1F\xF1\x0E\xF1\x0E"); + weak_test(1, "\x01\xE0\x01\xE0\x01\xF1\x01\xF1"); + weak_test(1, "\xE0\x01\xE0\x01\xF1\x01\xF1\x01"); + weak_test(1, "\x1F\xFE\x1F\xFE\x0E\xFE\x0E\xFE"); + weak_test(1, "\xFE\x1F\xFE\x1F\xFE\x0E\xFE\x0E"); + weak_test(1, "\x01\x1F\x01\x1F\x01\x0E\x01\x0E"); + weak_test(1, "\x1F\x01\x1F\x01\x0E\x01\x0E\x01"); + weak_test(1, "\xE0\xFE\xE0\xFE\xF1\xFE\xF1\xFE"); + weak_test(1, "\xFE\xE0\xFE\xE0\xFE\xF1\xFE\xF1"); + + weak_test(0, "\x01\x01\x01\x01\x01\x01\x01\x02"); + weak_test(0, "\xFF\xE0\xFE\xE0\xFE\xF1\xFE\xF1"); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/dh-ltm.c b/third_party/heimdal/lib/hcrypto/dh-ltm.c new file mode 100644 index 0000000..7206621 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dh-ltm.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include + +#include "tommath.h" + +static int +BN2mpz(mp_int *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + if (mp_from_ubin(s, p, len) != MP_OKAY) { + free(p); + return -1; + } + free(p); + return 0; +} + + +static BIGNUM * +mpz2BN(mp_int *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = mp_ubin_size(s); + p = malloc(size); + if (p == NULL) + return NULL; + if (mp_to_ubin(s, p, SIZE_MAX, NULL) != MP_OKAY) { + free(p); + return NULL; + }; + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +/* + * + */ + +#define DH_NUM_TRIES 10 + +static int +ltm_dh_generate_key(DH *dh) +{ + mp_int pub, priv_key, g, p; + int have_private_key = (dh->priv_key != NULL); + int codes, times = 0; + int res; + + if (dh->p == NULL || dh->g == NULL) + return 0; + + while (times++ < DH_NUM_TRIES) { + if (!have_private_key) { + size_t bits = BN_num_bits(dh->p); + + if (dh->priv_key) + BN_free(dh->priv_key); + + dh->priv_key = BN_new(); + if (dh->priv_key == NULL) + return 0; + if (!BN_rand(dh->priv_key, bits - 1, 0, 0)) { + BN_clear_free(dh->priv_key); + dh->priv_key = NULL; + return 0; + } + } + if (dh->pub_key) { + BN_free(dh->pub_key); + dh->pub_key = NULL; + } + + if (mp_init_multi(&pub, &priv_key, &g, &p, NULL) != MP_OKAY) + continue; + + if (BN2mpz(&priv_key, dh->priv_key) != 0) + continue; + + if (BN2mpz(&g, dh->g) != 0) + continue; + + if (BN2mpz(&p, dh->p) != 0) + continue; + + res = mp_exptmod(&g, &priv_key, &p, &pub); + + mp_clear_multi(&priv_key, &g, &p, NULL); + if (res != 0) + continue; + + dh->pub_key = mpz2BN(&pub); + mp_clear(&pub); + if (dh->pub_key == NULL) + return 0; + + if (DH_check_pubkey(dh, dh->pub_key, &codes) && codes == 0) + break; + if (have_private_key) + return 0; + } + + if (times >= DH_NUM_TRIES) { + if (!have_private_key && dh->priv_key) { + BN_free(dh->priv_key); + dh->priv_key = NULL; + } + if (dh->pub_key) { + BN_free(dh->pub_key); + dh->pub_key = NULL; + } + return 0; + } + + return 1; +} + +static int +ltm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) +{ + mp_int s, priv_key, p, peer_pub; + int ret; + + if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL) + return -1; + + if (mp_init_multi(&s, &priv_key, &p, &peer_pub, NULL) != MP_OKAY) + return -1; + + if (BN2mpz(&p, dh->p) != 0) { + ret = -1; + goto out; + } + + if (BN2mpz(&peer_pub, pub) != 0) { + ret = 1; + goto out; + } + + /* check if peers pubkey is reasonable */ + if (mp_isneg(&peer_pub) + || mp_cmp(&peer_pub, &p) >= 0 + || mp_cmp_d(&peer_pub, 1) <= 0) + { + ret = -1; + goto out; + } + + if (BN2mpz(&priv_key, dh->priv_key) != 0) { + ret = -1; + goto out; + } + + ret = mp_exptmod(&peer_pub, &priv_key, &p, &s); + if (ret != 0) { + ret = -1; + goto out; + } + + ret = mp_ubin_size(&s); + if (mp_to_ubin(&s, shared, SIZE_MAX, NULL) != MP_OKAY) + ret = -1; + + out: + mp_clear_multi(&s, &priv_key, &p, &peer_pub, NULL); + + return ret; +} + +static int +ltm_dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback) +{ + /* groups should already be known, we don't care about this */ + return 0; +} + +static int +ltm_dh_init(DH *dh) +{ + return 1; +} + +static int +ltm_dh_finish(DH *dh) +{ + return 1; +} + + +/* + * + */ + +const DH_METHOD _hc_dh_ltm_method = { + "hcrypto ltm DH", + ltm_dh_generate_key, + ltm_dh_compute_key, + NULL, + ltm_dh_init, + ltm_dh_finish, + 0, + NULL, + ltm_dh_generate_params +}; + +/** + * DH implementation using libtommath. + * + * @return the DH_METHOD for the DH implementation using libtommath. + * + * @ingroup hcrypto_dh + */ + +const DH_METHOD * +DH_ltm_method(void) +{ + return &_hc_dh_ltm_method; +} diff --git a/third_party/heimdal/lib/hcrypto/dh-tfm.c b/third_party/heimdal/lib/hcrypto/dh-tfm.c new file mode 100644 index 0000000..dce8a9f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dh-tfm.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +#ifdef USE_HCRYPTO_TFM + +#include "tfm.h" + +static void +BN2mpz(fp_int *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + fp_read_unsigned_bin(s, p, len); + free(p); +} + + +static BIGNUM * +mpz2BN(fp_int *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = fp_unsigned_bin_size(s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + fp_to_unsigned_bin(s, p); + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +/* + * + */ + +#define DH_NUM_TRIES 10 + +static int +tfm_dh_generate_key(DH *dh) +{ + fp_int pub, priv_key, g, p; + int have_private_key = (dh->priv_key != NULL); + int codes, times = 0; + int res; + + if (dh->p == NULL || dh->g == NULL) + return 0; + + while (times++ < DH_NUM_TRIES) { + if (!have_private_key) { + size_t bits = BN_num_bits(dh->p); + + if (dh->priv_key) + BN_free(dh->priv_key); + + dh->priv_key = BN_new(); + if (dh->priv_key == NULL) + return 0; + if (!BN_rand(dh->priv_key, bits - 1, 0, 0)) { + BN_clear_free(dh->priv_key); + dh->priv_key = NULL; + return 0; + } + } + if (dh->pub_key) + BN_free(dh->pub_key); + + fp_init_multi(&pub, &priv_key, &g, &p, NULL); + + BN2mpz(&priv_key, dh->priv_key); + BN2mpz(&g, dh->g); + BN2mpz(&p, dh->p); + + res = fp_exptmod(&g, &priv_key, &p, &pub); + + fp_zero(&priv_key); + fp_zero(&g); + fp_zero(&p); + if (res != 0) + continue; + + dh->pub_key = mpz2BN(&pub); + fp_zero(&pub); + if (dh->pub_key == NULL) + return 0; + + if (DH_check_pubkey(dh, dh->pub_key, &codes) && codes == 0) + break; + if (have_private_key) + return 0; + } + + if (times >= DH_NUM_TRIES) { + if (!have_private_key && dh->priv_key) { + BN_free(dh->priv_key); + dh->priv_key = NULL; + } + if (dh->pub_key) { + BN_free(dh->pub_key); + dh->pub_key = NULL; + } + return 0; + } + + return 1; +} + +static int +tfm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) +{ + fp_int s, priv_key, p, peer_pub; + size_t size = 0; + int ret; + + if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL) + return -1; + + fp_init(&p); + BN2mpz(&p, dh->p); + + fp_init(&peer_pub); + BN2mpz(&peer_pub, pub); + + /* check if peers pubkey is reasonable */ + if (fp_isneg(&peer_pub) + || fp_cmp(&peer_pub, &p) >= 0 + || fp_cmp_d(&peer_pub, 1) <= 0) + { + fp_zero(&p); + fp_zero(&peer_pub); + return -1; + } + + fp_init(&priv_key); + BN2mpz(&priv_key, dh->priv_key); + + fp_init(&s); + + ret = fp_exptmod(&peer_pub, &priv_key, &p, &s); + + fp_zero(&p); + fp_zero(&peer_pub); + fp_zero(&priv_key); + + if (ret != 0) + return -1; + + size = fp_unsigned_bin_size(&s); + fp_to_unsigned_bin(&s, shared); + fp_zero(&s); + + return size; +} + +static int +tfm_dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback) +{ + /* groups should already be known, we don't care about this */ + return 0; +} + +static int +tfm_dh_init(DH *dh) +{ + return 1; +} + +static int +tfm_dh_finish(DH *dh) +{ + return 1; +} + + +/* + * + */ + +const DH_METHOD _hc_dh_tfm_method = { + "hcrypto tfm DH", + tfm_dh_generate_key, + tfm_dh_compute_key, + NULL, + tfm_dh_init, + tfm_dh_finish, + 0, + NULL, + tfm_dh_generate_params +}; + +/** + * DH implementation using tfm. + * + * @return the DH_METHOD for the DH implementation using tfm. + * + * @ingroup hcrypto_dh + */ + +const DH_METHOD * +DH_tfm_method(void) +{ + return &_hc_dh_tfm_method; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/dh.c b/third_party/heimdal/lib/hcrypto/dh.c new file mode 100644 index 0000000..b3b25e5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dh.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include +#include + +#include + +/** + * @page page_dh DH - Diffie-Hellman key exchange + * + * Diffie-Hellman key exchange is a protocol that allows two parties + * to establish a shared secret key. + * + * Include and example how to use DH_new() and friends here. + * + * See the library functions here: @ref hcrypto_dh + */ + +/** + * Create a new DH object using DH_new_method(NULL), see DH_new_method(). + * + * @return a newly allocated DH object. + * + * @ingroup hcrypto_dh + */ + +DH * +DH_new(void) +{ + return DH_new_method(NULL); +} + +/** + * Create a new DH object from the given engine, if the NULL is used, + * the default engine is used. Free the DH object with DH_free(). + * + * @param engine The engine to use to allocate the DH object. + * + * @return a newly allocated DH object. + * + * @ingroup hcrypto_dh + */ + +DH * +DH_new_method(ENGINE *engine) +{ + DH *dh; + + dh = calloc(1, sizeof(*dh)); + if (dh == NULL) + return NULL; + + dh->references = 1; + + if (engine) { + ENGINE_up_ref(engine); + dh->engine = engine; + } else { + dh->engine = ENGINE_get_default_DH(); + } + + if (dh->engine) { + dh->meth = ENGINE_get_DH(dh->engine); + if (dh->meth == NULL) { + ENGINE_finish(dh->engine); + free(dh); + return 0; + } + } + + if (dh->meth == NULL) + dh->meth = DH_get_default_method(); + + (*dh->meth->init)(dh); + + return dh; +} + +/** + * Free a DH object and release related resources, like ENGINE, that + * the object was using. + * + * @param dh object to be freed. + * + * @ingroup hcrypto_dh + */ + +void +DH_free(DH *dh) +{ + if (dh->references <= 0) + abort(); + + if (--dh->references > 0) + return; + + (*dh->meth->finish)(dh); + + if (dh->engine) + ENGINE_finish(dh->engine); + +#define free_if(f) if (f) { BN_free(f); } + free_if(dh->p); + free_if(dh->g); + free_if(dh->pub_key); + free_if(dh->priv_key); + free_if(dh->q); + free_if(dh->j); + free_if(dh->counter); +#undef free_if + + memset_s(dh, sizeof(*dh), 0, sizeof(*dh)); + free(dh); +} + +/** + * Add a reference to the DH object. The object should be free with + * DH_free() to drop the reference. + * + * @param dh the object to increase the reference count too. + * + * @return the updated reference count, can't safely be used except + * for debug printing. + * + * @ingroup hcrypto_dh + */ + +int +DH_up_ref(DH *dh) +{ + return ++dh->references; +} + +/** + * The maximum output size of the DH_compute_key() function. + * + * @param dh The DH object to get the size from. + * + * @return the maximum size in bytes of the out data. + * + * @ingroup hcrypto_dh + */ + +int +DH_size(const DH *dh) +{ + return BN_num_bytes(dh->p); +} + +/** + * Set the data index idx in the DH object to data. + * + * @param dh DH object. + * @param idx index to set the data for. + * @param data data to store for the index idx. + * + * @return 1 on success. + * + * @ingroup hcrypto_dh + */ + +int +DH_set_ex_data(DH *dh, int idx, void *data) +{ + dh->ex_data.sk = data; + return 1; +} + +/** + * Get the data for index idx in the DH object. + * + * @param dh DH object. + * @param idx index to get the data for. + * + * @return the object store in index idx + * + * @ingroup hcrypto_dh + */ + +void * +DH_get_ex_data(DH *dh, int idx) +{ + return dh->ex_data.sk; +} + +/** + * Generate DH parameters for the DH object give parameters. + * + * @param dh The DH object to generate parameters for. + * @param prime_len length of the prime + * @param generator generator, g + * @param cb Callback parameters to show progress, can be NULL. + * + * @return the maximum size in bytes of the out data. + * + * @ingroup hcrypto_dh + */ + +int +DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb) +{ + if (dh->meth->generate_params) + return dh->meth->generate_params(dh, prime_len, generator, cb); + return 0; +} + +/** + * Check that the public key is sane. + * + * @param dh the local peer DH parameters. + * @param pub_key the remote peer public key parameters. + * @param codes return that the failures of the pub_key are. + * + * @return 1 on success, 0 on failure and *codes is set the the + * combined fail check for the public key + * + * @ingroup hcrypto_dh + */ + +int +DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes) +{ + BIGNUM *bn = NULL, *sum = NULL; + int ret = 0; + + *codes = 0; + + /** + * Checks that the function performs are: + * - pub_key is not negative + */ + + if (BN_is_negative(pub_key)) + goto out; + + /** + * - pub_key > 1 and pub_key < p - 1, + * to avoid small subgroups attack. + */ + + bn = BN_new(); + if (bn == NULL) + goto out; + + if (!BN_set_word(bn, 1)) + goto out; + + if (BN_cmp(bn, pub_key) >= 0) + *codes |= DH_CHECK_PUBKEY_TOO_SMALL; + + sum = BN_new(); + if (sum == NULL) + goto out; + + BN_uadd(sum, pub_key, bn); + + if (BN_cmp(sum, dh->p) >= 0) + *codes |= DH_CHECK_PUBKEY_TOO_LARGE; + + /** + * - if g == 2, pub_key have more then one bit set, + * if bits set is 1, log_2(pub_key) is trival + */ + + if (!BN_set_word(bn, 2)) + goto out; + + if (BN_cmp(bn, dh->g) == 0) { + unsigned i, n = BN_num_bits(pub_key); + unsigned bits = 0; + + for (i = 0; i < n; i++) + if (BN_is_bit_set(pub_key, i)) + bits++; + + if (bits < 2) { + *codes |= DH_CHECK_PUBKEY_TOO_SMALL; + goto out; + } + } + + ret = 1; +out: + if (bn) + BN_free(bn); + if (sum) + BN_free(sum); + + return ret; +} + +/** + * Generate a new DH private-public key pair. The dh parameter must be + * allocted first with DH_new(). dh->p and dp->g must be set. + * + * @param dh dh parameter. + * + * @return 1 on success. + * + * @ingroup hcrypto_dh + */ + +int +DH_generate_key(DH *dh) +{ + return dh->meth->generate_key(dh); +} + +/** + * Complute the shared secret key. + * + * @param shared_key the resulting shared key, need to be at least + * DH_size() large. + * @param peer_pub_key the peer's public key. + * @param dh the dh key pair. + * + * @return 1 on success. + * + * @ingroup hcrypto_dh + */ + +int +DH_compute_key(unsigned char *shared_key, + const BIGNUM *peer_pub_key, DH *dh) +{ + int codes; + + /** + * Checks that the pubkey passed in is valid using + * DH_check_pubkey(). + */ + + if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0) + return -1; + + return dh->meth->compute_key(shared_key, peer_pub_key, dh); +} + +/** + * Set a new method for the DH keypair. + * + * @param dh dh parameter. + * @param method the new method for the DH parameter. + * + * @return 1 on success. + * + * @ingroup hcrypto_dh + */ + +int +DH_set_method(DH *dh, const DH_METHOD *method) +{ + (*dh->meth->finish)(dh); + if (dh->engine) { + ENGINE_finish(dh->engine); + dh->engine = NULL; + } + dh->meth = method; + (*dh->meth->init)(dh); + return 1; +} + +/* + * + */ + +static int +dh_null_generate_key(DH *dh) +{ + return 0; +} + +static int +dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh) +{ + return 0; +} + +static int +dh_null_init(DH *dh) +{ + return 1; +} + +static int +dh_null_finish(DH *dh) +{ + return 1; +} + +static int +dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb) +{ + return 0; +} + +static const DH_METHOD dh_null_method = { + "hcrypto null DH", + dh_null_generate_key, + dh_null_compute_key, + NULL, + dh_null_init, + dh_null_finish, + 0, + NULL, + dh_null_generate_params +}; + +extern const DH_METHOD _hc_dh_ltm_method; +static const DH_METHOD *dh_default_method = &_hc_dh_ltm_method; + +/** + * Return the dummy DH implementation. + * + * @return pointer to a DH_METHOD. + * + * @ingroup hcrypto_dh + */ + +const DH_METHOD * +DH_null_method(void) +{ + return &dh_null_method; +} + +/** + * Set the default DH implementation. + * + * @param meth pointer to a DH_METHOD. + * + * @ingroup hcrypto_dh + */ + +void +DH_set_default_method(const DH_METHOD *meth) +{ + dh_default_method = meth; +} + +/** + * Return the default DH implementation. + * + * @return pointer to a DH_METHOD. + * + * @ingroup hcrypto_dh + */ + +const DH_METHOD * +DH_get_default_method(void) +{ + return dh_default_method; +} + +/* + * + */ + +static int +bn2heim_int(BIGNUM *bn, heim_integer *integer) +{ + integer->length = BN_num_bytes(bn); + integer->data = malloc(integer->length); + if (integer->data == NULL) { + integer->length = 0; + return ENOMEM; + } + BN_bn2bin(bn, integer->data); + integer->negative = BN_is_negative(bn); + return 0; +} + +/** + * + */ + +int +i2d_DHparams(DH *dh, unsigned char **pp) +{ + DHParameter data; + size_t size; + int ret; + + memset(&data, 0, sizeof(data)); + + if (bn2heim_int(dh->p, &data.prime) || + bn2heim_int(dh->g, &data.base)) + { + free_DHParameter(&data); + return -1; + } + + if (pp == NULL) { + size = length_DHParameter(&data); + free_DHParameter(&data); + } else { + void *p; + size_t len; + + ASN1_MALLOC_ENCODE(DHParameter, p, len, &data, &size, ret); + free_DHParameter(&data); + if (ret) + return -1; + if (len != size) { + abort(); + return -1; + } + + memcpy(*pp, p, size); + free(p); + + *pp += size; + } + + return size; +} diff --git a/third_party/heimdal/lib/hcrypto/dh.h b/third_party/heimdal/lib/hcrypto/dh.h new file mode 100644 index 0000000..6186805 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dh.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_DH_H +#define _HEIM_DH_H 1 + +/* symbol renaming */ +#define DH hc_DH +#define DH_METHOD hc_DH_METHOD +#define DH_null_method hc_DH_null_method +#define DH_tfm_method hc_DH_tfm_method +#define DH_ltm_method hc_DH_ltm_method +#define DH_new hc_DH_new +#define DH_new_method hc_DH_new_method +#define DH_free hc_DH_free +#define DH_up_ref hc_DH_up_ref +#define DH_size hc_DH_size +#define DH_set_default_method hc_DH_set_default_method +#define DH_get_default_method hc_DH_get_default_method +#define DH_set_method hc_DH_set_method +#define DH_get_method hc_DH_get_method +#define DH_set_ex_data hc_DH_set_ex_data +#define DH_get_ex_data hc_DH_get_ex_data +#define DH_generate_parameters_ex hc_DH_generate_parameters_ex +#define DH_check_pubkey hc_DH_check_pubkey +#define DH_generate_key hc_DH_generate_key +#define DH_compute_key hc_DH_compute_key +#define i2d_DHparams hc_i2d_DHparams + +/* + * + */ + +typedef struct DH DH; +typedef struct DH_METHOD DH_METHOD; + +#include +#include + +struct DH_METHOD { + const char *name; + int (*generate_key)(DH *); + int (*compute_key)(unsigned char *,const BIGNUM *,DH *); + int (*bn_mod_exp)(const DH *, BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, BN_CTX *, + BN_MONT_CTX *); + int (*init)(DH *); + int (*finish)(DH *); + int flags; + void *app_data; + int (*generate_params)(DH *, int, int, BN_GENCB *); +}; + +struct DH { + int pad; + int version; + BIGNUM *p; + BIGNUM *g; + long length; + BIGNUM *pub_key; + BIGNUM *priv_key; + int flags; + void *method_mont_p; + BIGNUM *q; + BIGNUM *j; + void *seed; + int seedlen; + BIGNUM *counter; + int references; + struct CRYPTO_EX_DATA { + void *sk; + int dummy; + } ex_data; + const DH_METHOD *meth; + ENGINE *engine; +}; + +/* DH_check_pubkey return codes in `codes' argument. */ +#define DH_CHECK_PUBKEY_TOO_SMALL 1 +#define DH_CHECK_PUBKEY_TOO_LARGE 2 + +/* + * + */ + +const DH_METHOD *DH_null_method(void); +const DH_METHOD *DH_tfm_method(void); +const DH_METHOD *DH_ltm_method(void); + +DH * DH_new(void); +DH * DH_new_method(ENGINE *); +void DH_free(DH *); +int DH_up_ref(DH *); + +int DH_size(const DH *); + + +void DH_set_default_method(const DH_METHOD *); +const DH_METHOD * + DH_get_default_method(void); +int DH_set_method(DH *, const DH_METHOD *); + +int DH_set_ex_data(DH *, int, void *); +void * DH_get_ex_data(DH *, int); + +int DH_generate_parameters_ex(DH *, int, int, BN_GENCB *); +int DH_check_pubkey(const DH *, const BIGNUM *, int *); +int DH_generate_key(DH *); +int DH_compute_key(unsigned char *,const BIGNUM *,DH *); + +int i2d_DHparams(DH *, unsigned char **); + +#endif /* _HEIM_DH_H */ + diff --git a/third_party/heimdal/lib/hcrypto/doxygen.c b/third_party/heimdal/lib/hcrypto/doxygen.c new file mode 100644 index 0000000..8311dbd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/doxygen.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * + */ + +/*! @mainpage Heimdal crypto library + * + * @section intro Introduction + * + * Heimdal libhcrypto library is a implementation many crypto + * algorithms, among others: AES, SHA, DES, RSA, Camellia and many + * help function. + * + * hcrypto provies a OpenSSL compatible interface libcrypto interface + * and is licensed under a 3 clause BSD license (GPL compatible). + * + * The project web page: http://www.h5l.org/ + * + * Sections of this manual: + * + * - @subpage page_evp, @ref hcrypto_evp + * - @subpage page_rand, @ref hcrypto_rand + * - @subpage page_dh, @ref hcrypto_dh + * - @subpage page_rsa, @ref hcrypto_rsa + * - @ref hcrypto_misc + * + * Older interfaces that you should not use: + * + * - @subpage page_des, @ref hcrypto_des + * + * @subsection control_functions Control functions + * + * Functions controlling general behavior, like adding algorithms, are + * documented in this module: @ref hcrypto_core . + * + * @subsection return_values Return values + * + * Return values are diffrent in this module to be compatible with + * OpenSSL interface. The diffrence is that on success 1 is returned + * instead of the customary 0. + + * @subsection History + * + * Eric Young implemented DES in the library libdes, that grew into + * libcrypto in the ssleay package. ssleay went into recession and + * then got picked up by the OpenSSL (htp://www.openssl.org/) + * project. + * + * libhcrypto is an independent implementation with no code decended + * from ssleay/openssl. Both includes some common imported code, for + * example the AES implementation. + */ + +/** @defgroup hcrypto_dh Diffie-Hellman functions + * See the @ref page_dh for description and examples. + */ +/** @defgroup hcrypto_rsa RSA functions + * See the @ref page_rsa for description and examples. + */ +/** @defgroup hcrypto_evp EVP generic crypto functions + * See the @ref page_evp for description and examples. + */ +/** @defgroup hcrypto_rand RAND crypto functions + * See the @ref page_rand for description and examples. + */ +/** @defgroup hcrypto_des DES crypto functions + * See the @ref page_des for description and examples. + */ +/** @defgroup hcrypto_core hcrypto function controlling behavior */ +/** @defgroup hcrypto_misc hcrypto miscellaneous functions */ diff --git a/third_party/heimdal/lib/hcrypto/dsa.c b/third_party/heimdal/lib/hcrypto/dsa.c new file mode 100644 index 0000000..eac0ae6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dsa.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +/* + * + */ + +DSA * +DSA_new(void) +{ + DSA *dsa = calloc(1, sizeof(*dsa)); + dsa->meth = rk_UNCONST(DSA_get_default_method()); + dsa->references = 1; + return dsa; +} + +void +DSA_free(DSA *dsa) +{ + if (dsa->references <= 0) + abort(); + + if (--dsa->references > 0) + return; + + (*dsa->meth->finish)(dsa); + +#define free_if(f) if (f) { BN_free(f); } + free_if(dsa->p); + free_if(dsa->q); + free_if(dsa->g); + free_if(dsa->pub_key); + free_if(dsa->priv_key); + free_if(dsa->kinv); + free_if(dsa->r); +#undef free_if + + memset_s(dsa, sizeof(*dsa), 0, sizeof(*dsa)); + free(dsa); + +} + +int +DSA_up_ref(DSA *dsa) +{ + return ++dsa->references; +} + +/* + * + */ + +static const DSA_METHOD dsa_null_method = { + "hcrypto null DSA", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + NULL +}; + +const DSA_METHOD * +DSA_null_method(void) +{ + return &dsa_null_method; +} + + +const DSA_METHOD *dsa_default_mech = &dsa_null_method; + +void +DSA_set_default_method(const DSA_METHOD *mech) +{ + dsa_default_mech = mech; +} + +const DSA_METHOD * +DSA_get_default_method(void) +{ + return dsa_default_mech; +} + +int +DSA_verify(int type, const unsigned char * digest, int digest_len, + const unsigned char *sig, int sig_len, DSA *dsa) +{ + return -1; +} diff --git a/third_party/heimdal/lib/hcrypto/dsa.h b/third_party/heimdal/lib/hcrypto/dsa.h new file mode 100644 index 0000000..a8f087f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/dsa.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_DSA_H +#define _HEIM_DSA_H 1 + +#include + +/* symbol renaming */ +#define DSA hc_DSA +#define DSA_METHOD hc_DSA_METHOD +#define DSA_null_method hc_DSA_null_method +#define DSA_new hc_DSA_new +#define DSA_free hc_DSA_free +#define DSA_up_ref hc_DSA_up_ref +#define DSA_set_default_method hc_DSA_set_default_method +#define DSA_get_default_method hc_DSA_get_default_method +#define DSA_set_method hc_DSA_set_method +#define DSA_get_method hc_DSA_get_method +#define DSA_set_app_data hc_DSA_set_app_data +#define DSA_get_app_data hc_DSA_get_app_data +#define DSA_size hc_DSA_size +#define DSA_verify hc_DSA_verify + +/* + * + */ + + +typedef struct DSA DSA; +typedef struct DSA_METHOD DSA_METHOD; +typedef struct DSA_SIG DSA_SIG; + +struct DSA_SIG { + BIGNUM *r; + BIGNUM *s; +}; + +struct DSA_METHOD { + const char *name; + DSA_SIG * (*dsa_do_sign)(const unsigned char *, int, DSA *); + int (*dsa_sign_setup)(DSA *, BN_CTX *, BIGNUM **, BIGNUM **); + int (*dsa_do_verify)(const unsigned char *, int, DSA_SIG *, DSA *); + int (*dsa_mod_exp)(DSA *, BIGNUM *, BIGNUM *, BIGNUM *, + BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *, + BN_MONT_CTX *); + int (*bn_mod_exp)(DSA *, BIGNUM *, BIGNUM *, const BIGNUM *, + const BIGNUM *, BN_CTX *, + BN_MONT_CTX *); + int (*init)(DSA *); + int (*finish)(DSA *); + int flags; + void *app_data; +}; + +struct DSA { + int pad; + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; + BIGNUM *g; + + BIGNUM *pub_key; + BIGNUM *priv_key; + + BIGNUM *kinv; + BIGNUM *r; + int flags; + void *method_mont_p; + int references; + struct dsa_CRYPTO_EX_DATA { + void *sk; + int dummy; + } ex_data; + const DSA_METHOD *meth; + void *engine; +}; + +/* + * + */ + +const DSA_METHOD *DSA_null_method(void); + +/* + * + */ + +DSA * DSA_new(void); +void DSA_free(DSA *); +int DSA_up_ref(DSA *); + +void DSA_set_default_method(const DSA_METHOD *); +const DSA_METHOD * DSA_get_default_method(void); + +const DSA_METHOD * DSA_get_method(const DSA *); +int DSA_set_method(DSA *, const DSA_METHOD *); + +void DSA_set_app_data(DSA *, void *arg); +void * DSA_get_app_data(DSA *); + +int DSA_size(const DSA *); + +int DSA_verify(int, const unsigned char *, int, + const unsigned char *, int, DSA *); + +#endif /* _HEIM_DSA_H */ diff --git a/third_party/heimdal/lib/hcrypto/ec.c b/third_party/heimdal/lib/hcrypto/ec.c new file mode 100644 index 0000000..5a5c3c7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ec.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "ec.h" + +struct EC_POINT { + int inf; + mp_int x; + mp_int y; + mp_int z; +}; + +struct EC_GROUP { + size_t size; + mp_int prime; + mp_int order; + mp_int Gx; + mp_int Gy; +}; + +struct EC_KEY { + int type; + EC_GROUP *group; + EC_POINT *pubkey; + mp_int privkey; +}; + + +unsigned long +EC_GROUP_get_degree(EC_GROUP *) +{ +} + +EC_GROUP * +EC_KEY_get0_group(EC_KEY *) +{ +} + +int +EC_GROUP_get_order(EC_GROUP *, BIGNUM *, BN_CTX *) +{ +} + +EC_KEY * +o2i_ECPublicKey(EC_KEY **key, unsigned char **, size_t) +{ +} + +void +EC_KEY_free(EC_KEY *) +{ + +} + +EC_GROUP * +EC_GROUP_new_by_curve_name(int nid) +{ +} + +EC_KEY * +EC_KEY_new_by_curve_name(EC_GROUP_ID nid) +{ + EC_KEY *key; + + key = calloc(1, sizeof(*key)); + return key; +} + +void +EC_POINT_free(EC_POINT *p) +{ + mp_clear_multi(&p->x, p->y, p->z, NULL); + free(p); +} + +static int +ec_point_mul(EC_POINT *res, const EC_GROUP *group, const mp_int *point) +{ +} + +EC_POINT * +EC_POINT_new(void) +{ + EC_POINT *p; + + p = calloc(1, sizeof(*p)); + + if (mp_init_multi(&p->x, &p->y, &p->z, NULL) != 0) { + EC_POINT_free(p); + return NULL; + } + + return p; +} + +int +EC_KEY_generate_key(EC_KEY *key) +{ + int ret = 0; + + if (key->group == NULL) + return 0; + + do { + random(key->privkey, key->group->size); + } while(mp_cmp(key->privkey, key->group->order) >= 0); + + if (key->pubkey == NULL) + key->pubkey = EC_POINT_new(); + + if (ec_point_mul(&key->pubkey, key->group, key->privkey) != 1) + goto error; + + ret = 1; + error: + ECPOINT_free(&base); + + return ret; +} + +void +EC_KEY_set_group(EC_KEY *, EC_GROUP *) +{ + +} + +void +EC_GROUP_free(EC_GROUP *) +{ +} + +int +EC_KEY_check_key(const EC_KEY *) +{ +} + +const BIGNUM * +EC_KEY_get0_private_key(const EC_KEY *key) +{ +} + +int +EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *bn) +{ +} diff --git a/third_party/heimdal/lib/hcrypto/ec.h b/third_party/heimdal/lib/hcrypto/ec.h new file mode 100644 index 0000000..8fa4d11 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ec.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_EC_H +#define HEIM_EC_H 1 + +#define EC_KEY hc_EC_KEY +#define EC_GROUP hc_EC_GROUP +#define EC_GROUP_ID hc_EC_GROUP_ID +#define EC_GROUP_ID_s hc_EC_GROUP_ID_s +#define EC_GROUP_get_degree hc_EC_GROUP_get_degree +#define EC_KEY_get0_group hc_EC_KEY_get0_group +#define EC_GROUP_get_order hc_EC_GROUP_get_order +#define o2i_ECPublicKey hc_o2i_ECPublicKey +#define EC_KEY_free hc_EC_KEY_free +#define EC_GROUP_new_by_curve_name hc_EC_GROUP_new_by_curve_name +#define EC_KEY_set_group hc_EC_KEY_set_group +#define EC_GROUP_free hc_EC_GROUP_free +#define EC_KEY_check_key hc_EC_KEY_check_key +#define EC_KEY_get0_private_key hc_EC_KEY_get0_private_key +#define EC_KEY_set_private_key hc_EC_KEY_set_private_key + +#include +#include + +typedef struct EC_KEY EC_KEY; +typedef struct EC_GROUP EC_GROUP; +typedef struct EC_GROUP_ID_s *EC_GROUP_ID; + +unsigned long +EC_GROUP_get_degree(EC_GROUP *); + +EC_GROUP * +EC_KEY_get0_group(EC_KEY *); + +int +EC_GROUP_get_order(EC_GROUP *, BIGNUM *, BN_CTX *); + +EC_KEY * +o2i_ECPublicKey(EC_KEY **key, unsigned char **, size_t); + +EC_KEY * +EC_KEY_new_by_curve_name(EC_GROUP_ID); + +int +EC_KEY_generate_key(EC_KEY *); + +void +EC_KEY_free(EC_KEY *); + +EC_GROUP * +EC_GROUP_new_by_curve_name(int nid); + +void +EC_KEY_set_group(EC_KEY *, EC_GROUP *); + +void +EC_GROUP_free(EC_GROUP *); + +int +EC_KEY_check_key(const EC_KEY *); + +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *); + +int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *); + +#endif /* HEIM_EC_H */ diff --git a/third_party/heimdal/lib/hcrypto/ecdh.h b/third_party/heimdal/lib/hcrypto/ecdh.h new file mode 100644 index 0000000..f224afd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ecdh.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_ECDH_H +#define HEIM_ECDH_H 1 + +#define ECDH_compute_key hc_ECDH_compute_key + +#include + +int +ECDH_compute_key(void *, size_t, + const EC_KEY *, const EC_KEY *, + void *(*KDF)(const void *, size_t, void *, size_t *)); + + +#endif /* HEIM_ECDH_H */ diff --git a/third_party/heimdal/lib/hcrypto/ecdsa.h b/third_party/heimdal/lib/hcrypto/ecdsa.h new file mode 100644 index 0000000..ffae17b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ecdsa.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_ECDSA_H +#define HEIM_ECDSA_H 1 + +#define ECDSA_verify hc_ECDSA_verify +#define ECDSA_sign hc_ECDSA_sign +#define ECDSA_size hc_ECDSA_size + +#include + +int ECDSA_verify(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int, EC_KEY *); + +int ECDSA_sign(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int *, EC_KEY *); + +int ECDSA_size(EC_KEY *); + + +#endif /* HEIM_ECDSA_H */ diff --git a/third_party/heimdal/lib/hcrypto/engine.c b/third_party/heimdal/lib/hcrypto/engine.c new file mode 100644 index 0000000..6a79b7c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/engine.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +struct hc_engine { + int references; + char *name; + char *id; + void (*destroy)(ENGINE *); + const RSA_METHOD *rsa; + const DH_METHOD *dh; + const RAND_METHOD *rand; + void *dso_handle; +}; + +ENGINE * +ENGINE_new(void) +{ + ENGINE *engine; + + engine = calloc(1, sizeof(*engine)); + if (engine == NULL) + return NULL; + engine->references = 1; + engine->destroy = 0; + engine->dh = 0; + engine->rand = 0; + engine->dso_handle = 0; + + return engine; +} + +int +ENGINE_free(ENGINE *engine) +{ + return ENGINE_finish(engine); +} + +int +ENGINE_finish(ENGINE *engine) +{ + if (engine->references-- <= 0) + abort(); + if (engine->references > 0) + return 1; + + if (engine->name) + free(engine->name); + if (engine->id) + free(engine->id); + if(engine->destroy) + (*engine->destroy)(engine); + if (engine->dso_handle) + dlclose(engine->dso_handle); + + memset_s(engine, sizeof(*engine), 0, sizeof(*engine)); + engine->references = -1; + + + free(engine); + return 1; +} + +int +ENGINE_up_ref(ENGINE *engine) +{ + if (engine->references < 0) + abort(); + engine->references++; + return 1; +} + +int +ENGINE_set_id(ENGINE *engine, const char *id) +{ + engine->id = strdup(id); + return (engine->id == NULL) ? 0 : 1; +} + +int +ENGINE_set_name(ENGINE *engine, const char *name) +{ + engine->name = strdup(name); + return (engine->name == NULL) ? 0 : 1; +} + +int +ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method) +{ + engine->rsa = method; + return 1; +} + +int +ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method) +{ + engine->dh = method; + return 1; +} + +int +ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *)) +{ + e->destroy = destroy; + return 1; +} + +const char * +ENGINE_get_id(const ENGINE *engine) +{ + return engine->id; +} + +const char * +ENGINE_get_name(const ENGINE *engine) +{ + return engine->name; +} + +const RSA_METHOD * +ENGINE_get_RSA(const ENGINE *engine) +{ + return engine->rsa; +} + +const DH_METHOD * +ENGINE_get_DH(const ENGINE *engine) +{ + return engine->dh; +} + +const RAND_METHOD * +ENGINE_get_RAND(const ENGINE *engine) +{ + return engine->rand; +} + +/* + * + */ + +#define SG_default_engine(type) \ +static ENGINE *type##_engine; \ +int \ +ENGINE_set_default_##type(ENGINE *engine) \ +{ \ + if (type##_engine) \ + ENGINE_finish(type##_engine); \ + type##_engine = engine; \ + if (type##_engine) \ + ENGINE_up_ref(type##_engine); \ + return 1; \ +} \ +ENGINE * \ +ENGINE_get_default_##type(void) \ +{ \ + if (type##_engine) \ + ENGINE_up_ref(type##_engine); \ + return type##_engine; \ +} + +SG_default_engine(RSA) +SG_default_engine(DH) + +#undef SG_default_engine + +/* + * + */ + +static ENGINE **engines; +static unsigned int num_engines; + +static int +add_engine(ENGINE *engine) +{ + ENGINE **d, *dup; + + dup = ENGINE_by_id(engine->id); + if (dup) + return 0; + + d = realloc(engines, (num_engines + 1) * sizeof(*engines)); + if (d == NULL) + return 1; + engines = d; + engines[num_engines++] = engine; + + return 1; +} + +void +ENGINE_load_builtin_engines(void) +{ + ENGINE *engine; + int ret; + + engine = ENGINE_new(); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "builtin"); + ENGINE_set_name(engine, + "Heimdal crypto builtin (ltm) engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_ltm_method()); + ENGINE_set_DH(engine, DH_ltm_method()); + + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); + +#ifdef USE_HCRYPTO_TFM + /* + * TFM + */ + + engine = ENGINE_new(); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "tfm"); + ENGINE_set_name(engine, + "Heimdal crypto tfm engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_tfm_method()); + ENGINE_set_DH(engine, DH_tfm_method()); + + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); +#endif /* USE_HCRYPTO_TFM */ + +#ifdef USE_HCRYPTO_LTM + /* + * ltm + */ + + engine = ENGINE_new(); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "ltm"); + ENGINE_set_name(engine, + "Heimdal crypto ltm engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_ltm_method()); + ENGINE_set_DH(engine, DH_ltm_method()); + + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); +#endif + +#ifdef HAVE_GMP + /* + * gmp + */ + + engine = ENGINE_new(); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "gmp"); + ENGINE_set_name(engine, + "Heimdal crypto gmp engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_gmp_method()); + + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); +#endif +} + +ENGINE * +ENGINE_by_dso(const char *path, const char *id) +{ +#ifdef HAVE_DLOPEN + ENGINE *engine; + int ret; + + engine = calloc(1, sizeof(*engine)); + if (engine == NULL) + return NULL; + engine->references = 0; /* ref will be added below */ + engine->destroy = 0; + engine->dh = 0; + engine->rand = 0; + engine->dso_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); + if (engine->dso_handle == NULL) { + /* printf("error: %s\n", dlerror()); */ + free(engine); + return NULL; + } + + { + unsigned long version; + openssl_v_check v_check; + + v_check = (openssl_v_check)dlsym(engine->dso_handle, "v_check"); + if (v_check == NULL) { + dlclose(engine->dso_handle); + free(engine); + return NULL; + } + + version = (*v_check)(OPENSSL_DYNAMIC_VERSION); + if (version == 0) { + dlclose(engine->dso_handle); + free(engine); + return NULL; + } + } + + { + openssl_bind_engine bind_engine; + + bind_engine = + (openssl_bind_engine)dlsym(engine->dso_handle, "bind_engine"); + if (bind_engine == NULL) { + dlclose(engine->dso_handle); + free(engine); + return NULL; + } + + ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */ + if (ret != 1) { + dlclose(engine->dso_handle); + free(engine); + return NULL; + } + } + + ENGINE_up_ref(engine); + + ret = add_engine(engine); + if (ret != 1) { + ENGINE_finish(engine); + return NULL; + } + + return engine; +#else + return NULL; +#endif +} + +ENGINE * +ENGINE_by_id(const char *id) +{ + int i; + + for (i = 0; i < num_engines; i++) { + if (strcmp(id, engines[i]->id) == 0) { + ENGINE_up_ref(engines[i]); + return engines[i]; + } + } + return NULL; +} + +void +ENGINE_add_conf_module(void) +{ +} diff --git a/third_party/heimdal/lib/hcrypto/engine.h b/third_party/heimdal/lib/hcrypto/engine.h new file mode 100644 index 0000000..27c6ab6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/engine.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_ENGINE_H +#define _HEIM_ENGINE_H 1 + +/* symbol renaming */ +#define ENGINE_add_conf_module hc_ENGINE_add_conf_module +#define ENGINE_by_dso hc_ENGINE_by_dso +#define ENGINE_by_id hc_ENGINE_by_id +#define ENGINE_finish hc_ENGINE_finish +#define ENGINE_get_DH hc_ENGINE_get_DH +#define ENGINE_get_RSA hc_ENGINE_get_RSA +#define ENGINE_get_RAND hc_ENGINE_get_RAND +#define ENGINE_get_id hc_ENGINE_get_id +#define ENGINE_get_name hc_ENGINE_get_name +#define ENGINE_load_builtin_engines hc_ENGINE_load_builtin_engines +#define ENGINE_set_DH hc_ENGINE_set_DH +#define ENGINE_set_RSA hc_ENGINE_set_RSA +#define ENGINE_set_id hc_ENGINE_set_id +#define ENGINE_set_name hc_ENGINE_set_name +#define ENGINE_set_destroy_function hc_ENGINE_set_destroy_function +#define ENGINE_new hc_ENGINE_new +#define ENGINE_free hc_ENGINE_free +#define ENGINE_up_ref hc_ENGINE_up_ref +#define ENGINE_get_default_DH hc_ENGINE_get_default_DH +#define ENGINE_get_default_RSA hc_ENGINE_get_default_RSA +#define ENGINE_set_default_DH hc_ENGINE_set_default_DH +#define ENGINE_set_default_RSA hc_ENGINE_set_default_RSA + +#define ENGINE hc_ENGINE + +/* + * + */ + +typedef struct hc_engine ENGINE; + +/*#define NID_md2 0 */ +#define NID_md4 1 +#define NID_md5 2 +#define NID_sha1 4 +#define NID_sha256 5 + +/* + * + */ + +#include +#include +#include +#include + +#define OPENSSL_DYNAMIC_VERSION (unsigned long)0x00020000 + +typedef int (*openssl_bind_engine)(ENGINE *, const char *, const void *); +typedef unsigned long (*openssl_v_check)(unsigned long); + +ENGINE * + ENGINE_new(void); +int ENGINE_free(ENGINE *); +void ENGINE_add_conf_module(void); +void ENGINE_load_builtin_engines(void); +ENGINE *ENGINE_by_id(const char *); +ENGINE *ENGINE_by_dso(const char *, const char *); +int ENGINE_finish(ENGINE *); +int ENGINE_up_ref(ENGINE *); +int ENGINE_set_id(ENGINE *, const char *); +int ENGINE_set_name(ENGINE *, const char *); +int ENGINE_set_RSA(ENGINE *, const RSA_METHOD *); +int ENGINE_set_DH(ENGINE *, const DH_METHOD *); +int ENGINE_set_destroy_function(ENGINE *, void (*)(ENGINE *)); + +const char * ENGINE_get_id(const ENGINE *); +const char * ENGINE_get_name(const ENGINE *); +const RSA_METHOD * ENGINE_get_RSA(const ENGINE *); +const DH_METHOD * ENGINE_get_DH(const ENGINE *); +const RAND_METHOD * ENGINE_get_RAND(const ENGINE *); + +int ENGINE_set_default_RSA(ENGINE *); +ENGINE * ENGINE_get_default_RSA(void); +int ENGINE_set_default_DH(ENGINE *); +ENGINE * ENGINE_get_default_DH(void); + + +#endif /* _HEIM_ENGINE_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-cc.c b/third_party/heimdal/lib/hcrypto/evp-cc.c new file mode 100644 index 0000000..7798519 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-cc.c @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* CommonCrypto provider */ + +#ifdef __APPLE__ + +#include +#include + +#include + +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H +#include +#endif +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H +#include +#endif + +#include +#include +#include + +/* + * + */ + +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + +struct cc_key { + CCCryptorRef href; +}; + +static int +cc_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct cc_key *cc = ctx->cipher_data; + CCCryptorStatus ret; + size_t moved; + + memcpy(out, in, size); + + ret = CCCryptorUpdate(cc->href, in, size, out, size, &moved); + if (ret) + return 0; + + if (moved != size) + return 0; + + return 1; +} + +static int +cc_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct cc_key *cc = ctx->cipher_data; + if (cc->href) + CCCryptorRelease(cc->href); + return 1; +} + +static int +init_cc_key(int encp, unsigned long flags, + CCAlgorithm alg, const void *key, size_t keylen, + const void *iv, CCCryptorRef *ref) +{ + CCOperation op = encp ? kCCEncrypt : kCCDecrypt; + CCMode mode; + CCModeOptions options = 0; + CCCryptorStatus ret; + + if (*ref) { + if (key == NULL && iv) { + CCCryptorReset(*ref, iv); + return 1; + } + CCCryptorRelease(*ref); + } + + if (key) { + switch (flags & EVP_CIPH_MODE) { + case EVP_CIPH_STREAM_CIPHER: + mode = kCCModeRC4; + break; + case EVP_CIPH_CFB8_MODE: + mode = kCCModeCFB8; + break; + default: + mode = kCCModeCBC; + break; + } + + ret = CCCryptorCreateWithMode(op, mode, alg, ccNoPadding, + iv, key, keylen, NULL, 0, 0, + options, ref); + if (ret) + return 0; + } + + return 1; +} + +static int +cc_des_ede3_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithm3DES, + key, kCCKeySize3DES, iv, &cc->href); +} + +#endif /* HAVE_COMMONCRYPTO_COMMONCRYPTOR_H */ + +/** + * The triple DES cipher type (Apple CommonCrypto provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_des_ede3_cbc(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER des_ede3_cbc = { + 0, + 8, + 24, + 8, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_des_ede3_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &des_ede3_cbc; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_des_ede3_cbc(); +#else + return NULL; +#endif +} + +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H +/* + * + */ + +static int +cc_des_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithmDES, + key, kCCBlockSizeDES, iv, &cc->href); +} +#endif + +/** + * The DES cipher type (Apple CommonCrypto provider) + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_des_cbc(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER des_ede3_cbc = { + 0, + kCCBlockSizeDES, + kCCBlockSizeDES, + kCCBlockSizeDES, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_des_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &des_ede3_cbc; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_des_cbc(); +#else + return NULL; +#endif +} + +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H +/* + * + */ + +static int +cc_aes_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithmAES128, + key, ctx->cipher->key_len, iv, &cc->href); +} +#endif + +/** + * The AES-128 cipher type (Apple CommonCrypto provider) + * + * @return the AES-128-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_128_cbc(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + kCCBlockSizeAES128, + kCCKeySizeAES128, + kCCBlockSizeAES128, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_128_cbc(); +#else + return NULL; +#endif +} + +/** + * The AES-192 cipher type (Apple CommonCrypto provider) + * + * @return the AES-192-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_192_cbc(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + kCCBlockSizeAES128, + kCCKeySizeAES192, + kCCBlockSizeAES128, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_192_cbc(); +#else + return NULL; +#endif +} + +/** + * The AES-256 cipher type (Apple CommonCrypto provider) + * + * @return the AES-256-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_256_cbc(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + kCCBlockSizeAES128, + kCCKeySizeAES256, + kCCBlockSizeAES128, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_256_cbc(); +#else + return NULL; +#endif +} + +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H +/* + * + */ + +static int +cc_aes_cfb8_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithmAES128, + key, ctx->cipher->key_len, NULL, &cc->href); +} +#endif + +/** + * The AES-128 CFB8 cipher type (Apple CommonCrypto provider) + * + * @return the AES-128-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_128_cfb8(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + 1, + kCCKeySizeAES128, + kCCBlockSizeAES128, + EVP_CIPH_CFB8_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cfb8_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_128_cfb8(); +#else + return NULL; +#endif +} + +/** + * The AES-192 CFB8 cipher type (Apple CommonCrypto provider) + * + * @return the AES-192-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_192_cfb8(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + 1, + kCCKeySizeAES192, + kCCBlockSizeAES128, + EVP_CIPH_CFB8_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cfb8_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_192_cfb8(); +#else + return NULL; +#endif +} + +/** + * The AES-256 CFB8 cipher type (Apple CommonCrypto provider) + * + * @return the AES-256-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_aes_256_cfb8(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER c = { + 0, + kCCBlockSizeAES128, + kCCKeySizeAES256, + kCCBlockSizeAES128, + EVP_CIPH_CFB8_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_aes_cfb8_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &c; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_aes_256_cfb8(); +#else + return NULL; +#endif +} + +/* + * + */ + +#ifdef COMMONCRYPTO_SUPPORTS_RC2 +static int +cc_rc2_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithmRC2, + key, ctx->cipher->key_len, iv, &cc->href); +} +#endif + +/** + * The RC2 cipher type - common crypto + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + + +const EVP_CIPHER * +EVP_cc_rc2_cbc(void) +{ +#ifdef COMMONCRYPTO_SUPPORTS_RC2 + static const EVP_CIPHER rc2_cbc = { + 0, + kCCBlockSizeRC2, + 16, + kCCBlockSizeRC2, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_rc2_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_cbc; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_rc2_cbc(); +#else + return NULL; +#endif +} + +/** + * The RC2-40 cipher type - common crypto + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + + +const EVP_CIPHER * +EVP_cc_rc2_40_cbc(void) +{ +#ifdef COMMONCRYPTO_SUPPORTS_RC2 + static const EVP_CIPHER rc2_40_cbc = { + 0, + kCCBlockSizeRC2, + 5, + kCCBlockSizeRC2, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_rc2_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_40_cbc; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_rc2_40_cbc(); +#else + return NULL; +#endif +} + + +/** + * The RC2-64 cipher type - common crypto + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + + +const EVP_CIPHER * +EVP_cc_rc2_64_cbc(void) +{ +#ifdef COMMONCRYPTO_SUPPORTS_RC2 + static const EVP_CIPHER rc2_64_cbc = { + 0, + kCCBlockSizeRC2, + 8, + kCCBlockSizeRC2, + EVP_CIPH_CBC_MODE|EVP_CIPH_ALWAYS_CALL_INIT, + cc_rc2_cbc_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_64_cbc; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_rc2_64_cbc(); +#else + return NULL; +#endif +} + + +/** + * The CommonCrypto md4 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_md4(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md md4 = { + CC_MD4_DIGEST_LENGTH, + CC_MD4_BLOCK_BYTES, + sizeof(CC_MD4_CTX), + (hc_evp_md_init)CC_MD4_Init, + (hc_evp_md_update)CC_MD4_Update, + (hc_evp_md_final)CC_MD4_Final, + (hc_evp_md_cleanup)NULL + }; + return &md4; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_md4(); +#else + return NULL; +#endif +} + +/** + * The CommonCrypto md5 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_md5(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md md5 = { + CC_MD5_DIGEST_LENGTH, + CC_MD5_BLOCK_BYTES, + sizeof(CC_MD5_CTX), + (hc_evp_md_init)CC_MD5_Init, + (hc_evp_md_update)CC_MD5_Update, + (hc_evp_md_final)CC_MD5_Final, + (hc_evp_md_cleanup)NULL + }; + return &md5; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_md5(); +#else + return NULL; +#endif +} + +/** + * The CommonCrypto sha1 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_sha1(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md sha1 = { + CC_SHA1_DIGEST_LENGTH, + CC_SHA1_BLOCK_BYTES, + sizeof(CC_SHA1_CTX), + (hc_evp_md_init)CC_SHA1_Init, + (hc_evp_md_update)CC_SHA1_Update, + (hc_evp_md_final)CC_SHA1_Final, + (hc_evp_md_cleanup)NULL + }; + return &sha1; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_sha1(); +#else + return NULL; +#endif +} + +/** + * The CommonCrypto sha256 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_sha256(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md sha256 = { + CC_SHA256_DIGEST_LENGTH, + CC_SHA256_BLOCK_BYTES, + sizeof(CC_SHA256_CTX), + (hc_evp_md_init)CC_SHA256_Init, + (hc_evp_md_update)CC_SHA256_Update, + (hc_evp_md_final)CC_SHA256_Final, + (hc_evp_md_cleanup)NULL + }; + return &sha256; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_sha256(); +#else + return NULL; +#endif +} + +/** + * The CommonCrypto sha384 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_sha384(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md sha384 = { + CC_SHA384_DIGEST_LENGTH, + CC_SHA384_BLOCK_BYTES, + sizeof(CC_SHA512_CTX), + (hc_evp_md_init)CC_SHA384_Init, + (hc_evp_md_update)CC_SHA384_Update, + (hc_evp_md_final)CC_SHA384_Final, + (hc_evp_md_cleanup)NULL + }; + return &sha384; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_sha384(); +#else + return NULL; +#endif +} + +/** + * The CommonCrypto sha512 provider + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_cc_sha512(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H + static const struct hc_evp_md sha512 = { + CC_SHA512_DIGEST_LENGTH, + CC_SHA512_BLOCK_BYTES, + sizeof(CC_SHA512_CTX), + (hc_evp_md_init)CC_SHA512_Init, + (hc_evp_md_update)CC_SHA512_Update, + (hc_evp_md_final)CC_SHA512_Final, + (hc_evp_md_cleanup)NULL + }; + return &sha512; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_sha512(); +#else + return NULL; +#endif +} + +/** + * The Camellia-128 cipher type - CommonCrypto + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_camellia_128_cbc(void) +{ +#if HCRYPTO_FALLBACK + return EVP_hcrypto_camellia_128_cbc(); +#else + return NULL; +#endif +} + +/** + * The Camellia-198 cipher type - CommonCrypto + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_camellia_192_cbc(void) +{ +#if HCRYPTO_FALLBACK + return EVP_hcrypto_camellia_192_cbc(); +#else + return NULL; +#endif +} + +/** + * The Camellia-256 cipher type - CommonCrypto + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_camellia_256_cbc(void) +{ +#if HCRYPTO_FALLBACK + return EVP_hcrypto_camellia_256_cbc(); +#else + return NULL; +#endif +} + +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + +/* + * + */ + +static int +cc_rc4_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct cc_key *cc = ctx->cipher_data; + return init_cc_key(encp, ctx->cipher->flags, kCCAlgorithmRC4, + key, ctx->key_len, iv, &cc->href); +} + +#endif + +/** + + * The RC4 cipher type (Apple CommonCrypto provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_rc4(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER rc4 = { + 0, + 1, + 16, + 0, + EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH, + cc_rc4_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &rc4; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_rc4(); +#else + return NULL; +#endif +} + + +/** + * The RC4-40 cipher type (Apple CommonCrypto provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_cc_rc4_40(void) +{ +#ifdef HAVE_COMMONCRYPTO_COMMONCRYPTOR_H + static const EVP_CIPHER rc4_40 = { + 0, + 1, + 5, + 0, + EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH, + cc_rc4_init, + cc_do_cipher, + cc_cleanup, + sizeof(struct cc_key), + NULL, + NULL, + NULL, + NULL + }; + return &rc4_40; +#elif HCRYPTO_FALLBACK + return EVP_hcrypto_rc4_40(); +#else + return NULL; +#endif +} + +#endif /* __APPLE__ */ + diff --git a/third_party/heimdal/lib/hcrypto/evp-cc.h b/third_party/heimdal/lib/hcrypto/evp-cc.h new file mode 100644 index 0000000..f857645 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-cc.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_CC_H +#define HEIM_EVP_CC_H 1 + +/* symbol renaming */ +#define EVP_cc_md4 hc_EVP_cc_md4 +#define EVP_cc_md5 hc_EVP_cc_md5 +#define EVP_cc_sha1 hc_EVP_cc_sha1 +#define EVP_cc_sha256 hc_EVP_cc_sha256 +#define EVP_cc_sha384 hc_EVP_cc_sha384 +#define EVP_cc_sha512 hc_EVP_cc_sha512 +#define EVP_cc_des_cbc hc_EVP_cc_des_cbc +#define EVP_cc_des_ede3_cbc hc_EVP_cc_des_ede3_cbc +#define EVP_cc_aes_128_cbc hc_EVP_cc_aes_128_cbc +#define EVP_cc_aes_192_cbc hc_EVP_cc_aes_192_cbc +#define EVP_cc_aes_256_cbc hc_EVP_cc_aes_256_cbc +#define EVP_cc_aes_128_cfb8 hc_EVP_cc_aes_128_cfb8 +#define EVP_cc_aes_192_cfb8 hc_EVP_cc_aes_192_cfb8 +#define EVP_cc_aes_256_cfb8 hc_EVP_cc_aes_256_cfb8 +#define EVP_cc_rc4 hc_EVP_cc_rc4 +#define EVP_cc_rc4_40 hc_EVP_cc_rc4_40 +#define EVP_cc_rc2_40_cbc hc_EVP_cc_rc2_40_cbc +#define EVP_cc_rc2_64_cbc hc_EVP_cc_rc2_64_cbc +#define EVP_cc_rc2_cbc hc_EVP_cc_rc2_cbc +#define EVP_cc_camellia_128_cbc hc_EVP_cc_camellia_128_cbc +#define EVP_cc_camellia_192_cbc hc_EVP_cc_camellia_192_cbc +#define EVP_cc_camellia_256_cbc hc_EVP_cc_camellia_256_cbc + +/* + * + */ + +HC_CPP_BEGIN + +const EVP_MD * EVP_cc_md4(void); +const EVP_MD * EVP_cc_md5(void); +const EVP_MD * EVP_cc_sha1(void); +const EVP_MD * EVP_cc_sha256(void); +const EVP_MD * EVP_cc_sha384(void); +const EVP_MD * EVP_cc_sha512(void); + +const EVP_CIPHER * EVP_cc_rc2_cbc(void); +const EVP_CIPHER * EVP_cc_rc2_40_cbc(void); +const EVP_CIPHER * EVP_cc_rc2_64_cbc(void); + +const EVP_CIPHER * EVP_cc_rc4(void); +const EVP_CIPHER * EVP_cc_rc4_40(void); + +const EVP_CIPHER * EVP_cc_des_cbc(void); +const EVP_CIPHER * EVP_cc_des_ede3_cbc(void); + +const EVP_CIPHER * EVP_cc_aes_128_cbc(void); +const EVP_CIPHER * EVP_cc_aes_192_cbc(void); +const EVP_CIPHER * EVP_cc_aes_256_cbc(void); + +const EVP_CIPHER * EVP_cc_aes_128_cfb8(void); +const EVP_CIPHER * EVP_cc_aes_192_cfb8(void); +const EVP_CIPHER * EVP_cc_aes_256_cfb8(void); + +const EVP_CIPHER * EVP_cc_camellia_128_cbc(void); +const EVP_CIPHER * EVP_cc_camellia_192_cbc(void); +const EVP_CIPHER * EVP_cc_camellia_256_cbc(void); + +HC_CPP_END + +#endif /* HEIM_EVP_CC_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-crypt.c b/third_party/heimdal/lib/hcrypto/evp-crypt.c new file mode 100644 index 0000000..4e8489e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-crypt.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Windows crypto provider plugin, sample */ + +#include +#include + +#define HC_DEPRECATED + +#include + +#include + +#include + + +static HCRYPTPROV hCryptProv = NULL; + +/* + * + */ + +struct generic_key { + HCRYPTKEY *hKey; +}; + +static int +generic_cbc_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct generic_key *gk = ctx->cipher_data; + BOOL bResult; + DWORD length = size; + + bResult = CryptSetKeyParam(gk->hKey, KP_IV, ctx->iv, 0); + _ASSERT(bResult); + + memcpy(out, in, size); + + if (ctx->encrypt) + bResult = CryptEncrypt(gk->hKey, 0, TRUE, 0, out, &length, size); + else + bResult = CryptDecrypt(gk->hKey, 0, TRUE, 0, out, &length); + _ASSERT(bResult); + + return 1; +} + +static int +generic_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct generic_key *gk = ctx->cipher_data; + CryptDestroyKey(gk->hKey); + gk->hKey = NULL; + return 1; +} + +static HCRYPTKEY +import_key(int alg, const unsigned char *key, size_t keylen) +{ + struct { + BLOBHEADER hdr; + DWORD len; + BYTE key[1]; + } *key_blob; + size_t bloblen = sizeof(*key_blob) - 1 + keylen; + + key_blob = malloc(bloblen); + + key_blob->hdr.bType = PLAINTEXTKEYBLOB; + key_blob->hdr.bVersion = CUR_BLOB_VERSION; + key_blob->hdr.reserved = 0; + key_blob->hdr.aiKeyAlg = alg; + key_blob->len = 24; + memcpy(key_blob->key, key, keylen); + + bResult = CryptImportKey(hCryptProv, + (void *)key_blob, bloblen, 0, 0, + &gk->hKey); + free(key_blob); + _ASSERT(bResult); + + return hKey; +} + +static int +crypto_des_ede3_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct generic_key *gk = ctx->cipher_data; + DWORD paramData; + + gk->hKey = import_key(CALG_3DES, + key->key->keyvalue.data, + key->key->keyvalue.len); + + return 1; +} + +/** + * The triple DES cipher type (Micrsoft crypt provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_wincrypt_des_ede3_cbc(void) +{ + static const EVP_CIPHER des_ede3_cbc = { + 0, + 8, + 24, + 8, + EVP_CIPH_CBC_MODE, + crypto_des_ede3_cbc_init, + generic_cbc_do_cipher, + generic_cleanup, + sizeof(struct generic_key), + NULL, + NULL, + NULL, + NULL + }; + return &des_ede3_cbc; +} + +/* + * + */ + +struct generic_hash { + HCRYPTHASH hHash; +}; + +static void +crypto_md5_init(struct generic_hash *m); +{ + BOOL bResult; + bResult = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &m->hHash); + _ASSERT(bResult); +} + +static void +generic_hash_update (struct generic_hash *m, const void *p, size_t len) +{ + BOOL bResult; + bResult = CryptHashData(m->hHash, data, ( DWORD )len, 0 ); + _ASSERT(bResult); +} + +static void +generic_hash_final (void *res, struct generic_hash *m); +{ + DWORD length; + BOOL bResult; + bResult = CryptGetHashParam(m->hHash, HP_HASHVAL, res, &length, 0) + _ASSERT(bResult); +} + +static void +generic_hash_cleanup(struct generic_hash *m) +{ + CryptDestroyHash(m->hHash); + m->hHash = NULL; +} + +const EVP_MD * +EVP_wincrypt_md5(void) +{ + static const struct hc_evp_md md5 = { + 16, + 64, + sizeof(struct generic_hash), + (hc_evp_md_init)crypto_md5_init, + (hc_evp_md_update)generic_hash_update, + (hc_evp_md_final)generic_hash_final, + (hc_evp_md_cleanup)generic_hash_cleanup + }; + return &md5; +} diff --git a/third_party/heimdal/lib/hcrypto/evp-hcrypto.c b/third_party/heimdal/lib/hcrypto/evp-hcrypto.c new file mode 100644 index 0000000..ee43e10 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-hcrypto.c @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#define HC_DEPRECATED + +#include + +#include +#include + +#include + +#include +#include "camellia.h" +#include + +#include +#include + +#include +#include +#include + +/* + * + */ + +static int +aes_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + AES_KEY *k = ctx->cipher_data; + if (ctx->encrypt || EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB8_MODE) + AES_set_encrypt_key(key, ctx->cipher->key_len * 8, k); + else + AES_set_decrypt_key(key, ctx->cipher->key_len * 8, k); + return 1; +} + +static int +aes_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + AES_KEY *k = ctx->cipher_data; + if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB8_MODE) + AES_cfb8_encrypt(in, out, size, k, ctx->iv, ctx->encrypt); + else + AES_cbc_encrypt(in, out, size, k, ctx->iv, ctx->encrypt); + return 1; +} + +/** + * The AES-128 cipher type (hcrypto) + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_128_cbc(void) +{ + static const EVP_CIPHER aes_128_cbc = { + 0, + 16, + 16, + 16, + EVP_CIPH_CBC_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + + return &aes_128_cbc; +} + +/** + * The AES-192 cipher type (hcrypto) + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_192_cbc(void) +{ + static const EVP_CIPHER aes_192_cbc = { + 0, + 16, + 24, + 16, + EVP_CIPH_CBC_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &aes_192_cbc; +} + +/** + * The AES-256 cipher type (hcrypto) + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_256_cbc(void) +{ + static const EVP_CIPHER aes_256_cbc = { + 0, + 16, + 32, + 16, + EVP_CIPH_CBC_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &aes_256_cbc; +} + +/** + * The AES-128 CFB8 cipher type (hcrypto) + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_128_cfb8(void) +{ + static const EVP_CIPHER aes_128_cfb8 = { + 0, + 1, + 16, + 16, + EVP_CIPH_CFB8_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + + return &aes_128_cfb8; +} + +/** + * The AES-192 CFB8 cipher type (hcrypto) + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_192_cfb8(void) +{ + static const EVP_CIPHER aes_192_cfb8 = { + 0, + 1, + 24, + 16, + EVP_CIPH_CFB8_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &aes_192_cfb8; +} + +/** + * The AES-256 CFB8 cipher type (hcrypto) + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_aes_256_cfb8(void) +{ + static const EVP_CIPHER aes_256_cfb8 = { + 0, + 1, + 32, + 16, + EVP_CIPH_CFB8_MODE, + aes_init, + aes_do_cipher, + NULL, + sizeof(AES_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &aes_256_cfb8; +} + +/** + * The message digest SHA256 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_sha256(void) +{ + static const struct hc_evp_md sha256 = { + 32, + 64, + sizeof(SHA256_CTX), + (hc_evp_md_init)SHA256_Init, + (hc_evp_md_update)SHA256_Update, + (hc_evp_md_final)SHA256_Final, + NULL + }; + return &sha256; +} + +/** + * The message digest SHA384 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_sha384(void) +{ + static const struct hc_evp_md sha384 = { + 48, + 128, + sizeof(SHA384_CTX), + (hc_evp_md_init)SHA384_Init, + (hc_evp_md_update)SHA384_Update, + (hc_evp_md_final)SHA384_Final, + NULL + }; + return &sha384; +} + +/** + * The message digest SHA512 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_sha512(void) +{ + static const struct hc_evp_md sha512 = { + 64, + 128, + sizeof(SHA512_CTX), + (hc_evp_md_init)SHA512_Init, + (hc_evp_md_update)SHA512_Update, + (hc_evp_md_final)SHA512_Final, + NULL + }; + return &sha512; +} + +/** + * The message digest SHA1 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_sha1(void) +{ + static const struct hc_evp_md sha1 = { + 20, + 64, + sizeof(SHA_CTX), + (hc_evp_md_init)SHA1_Init, + (hc_evp_md_update)SHA1_Update, + (hc_evp_md_final)SHA1_Final, + NULL + }; + return &sha1; +} + +/** + * The message digest MD5 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_md5(void) +{ + static const struct hc_evp_md md5 = { + 16, + 64, + sizeof(MD5_CTX), + (hc_evp_md_init)MD5_Init, + (hc_evp_md_update)MD5_Update, + (hc_evp_md_final)MD5_Final, + NULL + }; + return &md5; +} + +/** + * The message digest MD4 - hcrypto + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_hcrypto_md4(void) +{ + static const struct hc_evp_md md4 = { + 16, + 64, + sizeof(MD4_CTX), + (hc_evp_md_init)MD4_Init, + (hc_evp_md_update)MD4_Update, + (hc_evp_md_final)MD4_Final, + NULL + }; + return &md4; +} + + +/* + * + */ + +static int +des_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + DES_key_schedule *k = ctx->cipher_data; + DES_cblock deskey; + memcpy(&deskey, key, sizeof(deskey)); + DES_set_key_unchecked(&deskey, k); + return 1; +} + +static int +des_cbc_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + DES_key_schedule *k = ctx->cipher_data; + DES_cbc_encrypt(in, out, size, + k, (DES_cblock *)ctx->iv, ctx->encrypt); + return 1; +} + +/** + * The DES cipher type + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_des_cbc(void) +{ + static const EVP_CIPHER des_cbc = { + 0, + 8, + 8, + 8, + EVP_CIPH_CBC_MODE, + des_cbc_init, + des_cbc_do_cipher, + NULL, + sizeof(DES_key_schedule), + NULL, + NULL, + NULL, + NULL + }; + return &des_cbc; +} + +/* + * + */ + +struct des_ede3_cbc { + DES_key_schedule ks[3]; +}; + +static int +des_ede3_cbc_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct des_ede3_cbc *k = ctx->cipher_data; + DES_cblock deskey; + + memcpy(&deskey, key, sizeof(deskey)); + DES_set_odd_parity(&deskey); + DES_set_key_unchecked(&deskey, &k->ks[0]); + + memcpy(&deskey, key + 8, sizeof(deskey)); + DES_set_odd_parity(&deskey); + DES_set_key_unchecked(&deskey, &k->ks[1]); + + memcpy(&deskey, key + 16, sizeof(deskey)); + DES_set_odd_parity(&deskey); + DES_set_key_unchecked(&deskey, &k->ks[2]); + + return 1; +} + +static int +des_ede3_cbc_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct des_ede3_cbc *k = ctx->cipher_data; + DES_ede3_cbc_encrypt(in, out, size, + &k->ks[0], &k->ks[1], &k->ks[2], + (DES_cblock *)ctx->iv, ctx->encrypt); + return 1; +} + +/** + * The triple DES cipher type - hcrypto + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_des_ede3_cbc(void) +{ + static const EVP_CIPHER des_ede3_cbc = { + 0, + 8, + 24, + 8, + EVP_CIPH_CBC_MODE, + des_ede3_cbc_init, + des_ede3_cbc_do_cipher, + NULL, + sizeof(struct des_ede3_cbc), + NULL, + NULL, + NULL, + NULL + }; + return &des_ede3_cbc; +} + +/* + * + */ + +struct rc2_cbc { + unsigned int maximum_effective_key; + RC2_KEY key; +}; + +static int +rc2_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + struct rc2_cbc *k = ctx->cipher_data; + k->maximum_effective_key = EVP_CIPHER_CTX_key_length(ctx) * 8; + RC2_set_key(&k->key, + EVP_CIPHER_CTX_key_length(ctx), + key, + k->maximum_effective_key); + return 1; +} + +static int +rc2_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct rc2_cbc *k = ctx->cipher_data; + RC2_cbc_encrypt(in, out, size, &k->key, ctx->iv, ctx->encrypt); + return 1; +} + +/** + * The RC2 cipher type - hcrypto + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_rc2_cbc(void) +{ + static const EVP_CIPHER rc2_cbc = { + 0, + RC2_BLOCK_SIZE, + RC2_KEY_LENGTH, + RC2_BLOCK_SIZE, + EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH, + rc2_init, + rc2_do_cipher, + NULL, + sizeof(struct rc2_cbc), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_cbc; +} + +/** + * The RC2-40 cipher type + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_rc2_40_cbc(void) +{ + static const EVP_CIPHER rc2_40_cbc = { + 0, + RC2_BLOCK_SIZE, + 5, + RC2_BLOCK_SIZE, + EVP_CIPH_CBC_MODE, + rc2_init, + rc2_do_cipher, + NULL, + sizeof(struct rc2_cbc), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_40_cbc; +} + +/** + * The RC2-64 cipher type + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_rc2_64_cbc(void) +{ + static const EVP_CIPHER rc2_64_cbc = { + 0, + RC2_BLOCK_SIZE, + 8, + RC2_BLOCK_SIZE, + EVP_CIPH_CBC_MODE, + rc2_init, + rc2_do_cipher, + NULL, + sizeof(struct rc2_cbc), + NULL, + NULL, + NULL, + NULL + }; + return &rc2_64_cbc; +} + +static int +camellia_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + CAMELLIA_KEY *k = ctx->cipher_data; + k->bits = ctx->cipher->key_len * 8; + CAMELLIA_set_key(key, ctx->cipher->key_len * 8, k); + return 1; +} + +static int +camellia_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + CAMELLIA_KEY *k = ctx->cipher_data; + CAMELLIA_cbc_encrypt(in, out, size, k, ctx->iv, ctx->encrypt); + return 1; +} + +/** + * The Camellia-128 cipher type - hcrypto + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_camellia_128_cbc(void) +{ + static const EVP_CIPHER cipher = { + 0, + 16, + 16, + 16, + EVP_CIPH_CBC_MODE, + camellia_init, + camellia_do_cipher, + NULL, + sizeof(CAMELLIA_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &cipher; +} + +/** + * The Camellia-198 cipher type - hcrypto + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_camellia_192_cbc(void) +{ + static const EVP_CIPHER cipher = { + 0, + 16, + 24, + 16, + EVP_CIPH_CBC_MODE, + camellia_init, + camellia_do_cipher, + NULL, + sizeof(CAMELLIA_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &cipher; +} + +/** + * The Camellia-256 cipher type - hcrypto + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_hcrypto_camellia_256_cbc(void) +{ + static const EVP_CIPHER cipher = { + 0, + 16, + 32, + 16, + EVP_CIPH_CBC_MODE, + camellia_init, + camellia_do_cipher, + NULL, + sizeof(CAMELLIA_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &cipher; +} + +static int +rc4_init(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, + int enc) +{ + RC4_KEY *k = ctx->cipher_data; + RC4_set_key(k, ctx->key_len, key); + return 1; +} + +static int +rc4_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + RC4_KEY *k = ctx->cipher_data; + RC4(k, size, in, out); + return 1; +} + +const EVP_CIPHER * +EVP_hcrypto_rc4(void) +{ + static const EVP_CIPHER rc4 = { + 0, + 1, + 16, + 0, + EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH, + rc4_init, + rc4_do_cipher, + NULL, + sizeof(RC4_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &rc4; +} + + +const EVP_CIPHER * +EVP_hcrypto_rc4_40(void) +{ + static const EVP_CIPHER rc4_40 = { + 0, + 1, + 5, + 0, + EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH, + rc4_init, + rc4_do_cipher, + NULL, + sizeof(RC4_KEY), + NULL, + NULL, + NULL, + NULL + }; + return &rc4_40; +} diff --git a/third_party/heimdal/lib/hcrypto/evp-hcrypto.h b/third_party/heimdal/lib/hcrypto/evp-hcrypto.h new file mode 100644 index 0000000..6d4f1c8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-hcrypto.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_HCRYPTO_H +#define HEIM_EVP_HCRYPTO_H 1 + +/* symbol renaming */ +#define EVP_hcrypto_md4 hc_EVP_hcrypto_md4 +#define EVP_hcrypto_md5 hc_EVP_hcrypto_md5 +#define EVP_hcrypto_sha1 hc_EVP_hcrypto_sha1 +#define EVP_hcrypto_sha256 hc_EVP_hcrypto_sha256 +#define EVP_hcrypto_sha384 hc_EVP_hcrypto_sha384 +#define EVP_hcrypto_sha512 hc_EVP_hcrypto_sha512 +#define EVP_hcrypto_des_cbc hc_EVP_hcrypto_des_cbc +#define EVP_hcrypto_des_ede3_cbc hc_EVP_hcrypto_des_ede3_cbc +#define EVP_hcrypto_aes_128_cbc hc_EVP_hcrypto_aes_128_cbc +#define EVP_hcrypto_aes_192_cbc hc_EVP_hcrypto_aes_192_cbc +#define EVP_hcrypto_aes_256_cbc hc_EVP_hcrypto_aes_256_cbc +#define EVP_hcrypto_aes_128_cfb8 hc_EVP_hcrypto_aes_128_cfb8 +#define EVP_hcrypto_aes_192_cfb8 hc_EVP_hcrypto_aes_192_cfb8 +#define EVP_hcrypto_aes_256_cfb8 hc_EVP_hcrypto_aes_256_cfb8 +#define EVP_hcrypto_rc4 hc_EVP_hcrypto_rc4 +#define EVP_hcrypto_rc4_40 hc_EVP_hcrypto_rc4_40 +#define EVP_hcrypto_rc2_40_cbc hc_EVP_hcrypto_rc2_40_cbc +#define EVP_hcrypto_rc2_64_cbc hc_EVP_hcrypto_rc2_64_cbc +#define EVP_hcrypto_rc2_cbc hc_EVP_hcrypto_rc2_cbc +#define EVP_hcrypto_camellia_128_cbc hc_EVP_hcrypto_camellia_128_cbc +#define EVP_hcrypto_camellia_192_cbc hc_EVP_hcrypto_camellia_192_cbc +#define EVP_hcrypto_camellia_256_cbc hc_EVP_hcrypto_camellia_256_cbc + +/* + * + */ + +HC_CPP_BEGIN + +const EVP_MD * EVP_hcrypto_md4(void); +const EVP_MD * EVP_hcrypto_md5(void); +const EVP_MD * EVP_hcrypto_sha1(void); +const EVP_MD * EVP_hcrypto_sha256(void); +const EVP_MD * EVP_hcrypto_sha384(void); +const EVP_MD * EVP_hcrypto_sha512(void); + +const EVP_CIPHER * EVP_hcrypto_rc4(void); +const EVP_CIPHER * EVP_hcrypto_rc4_40(void); + +const EVP_CIPHER * EVP_hcrypto_rc2_cbc(void); +const EVP_CIPHER * EVP_hcrypto_rc2_40_cbc(void); +const EVP_CIPHER * EVP_hcrypto_rc2_64_cbc(void); + +const EVP_CIPHER * EVP_hcrypto_des_cbc(void); +const EVP_CIPHER * EVP_hcrypto_des_ede3_cbc(void); + +const EVP_CIPHER * EVP_hcrypto_aes_128_cbc(void); +const EVP_CIPHER * EVP_hcrypto_aes_192_cbc(void); +const EVP_CIPHER * EVP_hcrypto_aes_256_cbc(void); + +const EVP_CIPHER * EVP_hcrypto_aes_128_cfb8(void); +const EVP_CIPHER * EVP_hcrypto_aes_192_cfb8(void); +const EVP_CIPHER * EVP_hcrypto_aes_256_cfb8(void); + +const EVP_CIPHER * EVP_hcrypto_camellia_128_cbc(void); +const EVP_CIPHER * EVP_hcrypto_camellia_192_cbc(void); +const EVP_CIPHER * EVP_hcrypto_camellia_256_cbc(void); + + +HC_CPP_END + +#endif /* HEIM_EVP_HCRYPTO_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-openssl.c b/third_party/heimdal/lib/hcrypto/evp-openssl.c new file mode 100644 index 0000000..f6cf687 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-openssl.c @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2016, Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* OpenSSL provider */ + +#include "config.h" +#include +#include + +#include +#include + +#ifdef HAVE_HCRYPTO_W_OPENSSL + +/* + * This is the OpenSSL 1.x backend for hcrypto. It has been tested with + * OpenSSL 1.0.1f and OpenSSL 1.1.0-pre3-dev. + * + * NOTE: In order for this to work with OpenSSL 1.1.x and up, it is + * critical to use opaque OpenSSL type accessors everywhere / + * never use knowledge of opaque OpenSSL type internals. + */ + +#include + +/* + * This being an OpenSSL backend for hcrypto... we need to be able to + * refer to types and objects (functions) from both, OpenSSL and + * hcrypto. + * + * The hcrypto API is *very* similar to the OpenSSL 1.0.x API, with the + * same type and symbol names in many cases, except that the hcrypto + * names are prefixed with hc_*. hcrypto has convenience macros that + * provide OpenSSL aliases for the hcrypto interfaces, and hcrypto + * applications are expected to use the OpenSSL names. + * + * Since here we must be able to refer to types and objects from both + * OpenSSL and from hcrypto, we disable the hcrypto renaming for the + * rest of this file. These #undefs could be collected into an + * for the purpose of permitting other applications to + * use both, hcrypto and OpenSSL in the same source files (provided that + * such applications refer to hcrypto types and objects by their proper + * hc_-prefixed names). + */ +#include + +/* Now it's safe to include OpenSSL headers */ +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) +int _heim_openssl_fips_enabled(void); +int +_heim_openssl_fips_enabled(void) +{ + static int fips_enabled_res = -1; + + if (fips_enabled_res != -1) + return fips_enabled_res; + +#ifdef HAVE_OPENSSL_30 + return fips_enabled_res = !!EVP_default_properties_is_fips_enabled(NULL); +#else + return fips_enabled_res = !!FIPS_mode(); +#endif +} +#endif + +/* A HEIM_BASE_ONCE argument struct for per-EVP one-time initialization */ +struct once_init_cipher_ctx { + const hc_EVP_CIPHER **hc_memoizep; + hc_EVP_CIPHER *hc_memoize; + const hc_EVP_CIPHER *fallback; + unsigned long flags; + int nid; +}; + +/* Our wrapper for OpenSSL EVP_CIPHER_CTXs */ +struct ossl_cipher_ctx { + EVP_CIPHER_CTX *ossl_cipher_ctx; /* OpenSSL cipher ctx */ + const EVP_CIPHER *ossl_cipher; /* OpenSSL cipher */ + int initialized; +}; + +/* + * Our hc_EVP_CIPHER init() method; wraps around OpenSSL + * EVP_CipherInit_ex(). + * + * This is very similar to the init() function pointer in an OpenSSL + * EVP_CIPHER, but a) we can't access them in 1.1, and b) the method + * invocation protocols in hcrypto and OpenSSL are similar but not the + * same, thus we must have this wrapper. + */ +static int +cipher_ctx_init(hc_EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; /* EVP_CIPHER_CTX wrapper */ + const EVP_CIPHER *c; + + assert(ossl_ctx != NULL); + assert(ctx->cipher != NULL); + assert(ctx->cipher->app_data != NULL); + + /* + * Here be dragons. + * + * We need to make sure that the OpenSSL EVP_CipherInit_ex() is + * called with cipher!=NULL just once per EVP_CIPHER_CTX, otherwise + * state in the OpenSSL EVP_CIPHER_CTX will get cleaned up and then + * we'll segfault. + * + * hcrypto applications can re-initialize an (hc_)EVP_CIPHER_CTX as + * usual by calling (hc)EVP_CipherInit_ex() with a non-NULL cipher + * argument, and that will cause cipher_cleanup() (below) to be + * called. + */ + c = ossl_ctx->ossl_cipher = ctx->cipher->app_data; /* OpenSSL's EVP_CIPHER * */ + if (!ossl_ctx->initialized) { + ossl_ctx->ossl_cipher_ctx = EVP_CIPHER_CTX_new(); + if (ossl_ctx->ossl_cipher_ctx == NULL) + return 0; + /* + * So we always call EVP_CipherInit_ex() with c!=NULL, but other + * things NULL... + */ + if (!EVP_CipherInit_ex(ossl_ctx->ossl_cipher_ctx, c, NULL, NULL, NULL, enc)) + return 0; + ossl_ctx->initialized = 1; + } + + /* ...and from here on always call EVP_CipherInit_ex() with c=NULL */ + if ((ctx->cipher->flags & hc_EVP_CIPH_VARIABLE_LENGTH) && + ctx->key_len > 0) + EVP_CIPHER_CTX_set_key_length(ossl_ctx->ossl_cipher_ctx, ctx->key_len); + + return EVP_CipherInit_ex(ossl_ctx->ossl_cipher_ctx, NULL, NULL, key, iv, enc); +} + +static int +cipher_do_cipher(hc_EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int len) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + assert(ossl_ctx != NULL); + return EVP_Cipher(ossl_ctx->ossl_cipher_ctx, out, in, len) == 0 ? 0 : 1; +} + +static int +cipher_cleanup(hc_EVP_CIPHER_CTX *ctx) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + if (ossl_ctx == NULL || !ossl_ctx->initialized) + return 1; + + if (ossl_ctx->ossl_cipher_ctx != NULL) + EVP_CIPHER_CTX_free(ossl_ctx->ossl_cipher_ctx); + + ossl_ctx->ossl_cipher_ctx = NULL; + ossl_ctx->ossl_cipher = NULL; + ossl_ctx->initialized = 0; + return 1; +} + +static int +cipher_ctrl(hc_EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + assert(ossl_ctx != NULL); + return EVP_CIPHER_CTX_ctrl(ossl_ctx->ossl_cipher_ctx, type, arg, ptr); +} + + +static void +get_EVP_CIPHER_once_cb(void *d) +{ + struct once_init_cipher_ctx *arg = d; + const EVP_CIPHER *ossl_evp; + hc_EVP_CIPHER *hc_evp; + + hc_evp = arg->hc_memoize; + + /* + * We lookup EVP_CIPHER *s by NID so that we don't fail to find a + * symbol such as EVP_aes...() when libcrypto changes after build + * time (e.g., updates, LD_LIBRARY_PATH/LD_PRELOAD). + */ + ossl_evp = EVP_get_cipherbynid(arg->nid); + if (ossl_evp == NULL) { + (void) memset_s(hc_evp, sizeof(*hc_evp), 0, sizeof(*hc_evp)); +#if HCRYPTO_FALLBACK + *arg->hc_memoizep = arg->fallback; +#endif + return; + } + + /* Build the hc_EVP_CIPHER */ + hc_evp->nid = EVP_CIPHER_nid(ossl_evp); /* We would an hcrypto NIDs if we had them */ + hc_evp->block_size = EVP_CIPHER_block_size(ossl_evp); + hc_evp->key_len = EVP_CIPHER_key_length(ossl_evp); + hc_evp->iv_len = EVP_CIPHER_iv_length(ossl_evp); + + /* + * We force hc_EVP_CipherInit_ex to always call our init() function, + * otherwise we don't get a chance to call EVP_CipherInit_ex() + * correctly. + */ + hc_evp->flags = hc_EVP_CIPH_ALWAYS_CALL_INIT | arg->flags; + + /* Our cipher context */ + hc_evp->ctx_size = sizeof(struct ossl_cipher_ctx); + + /* Our wrappers */ + hc_evp->init = cipher_ctx_init; + hc_evp->do_cipher = cipher_do_cipher; + hc_evp->cleanup = cipher_cleanup; + hc_evp->set_asn1_parameters = NULL; + hc_evp->get_asn1_parameters = NULL; + hc_evp->ctrl = cipher_ctrl; + + /* Our link to the OpenSSL EVP_CIPHER */ + hc_evp->app_data = (void *)ossl_evp; + + /* Finally, set the static hc_EVP_CIPHER * to the one we just built */ + *arg->hc_memoizep = hc_evp; +} + +static const hc_EVP_CIPHER * +get_EVP_CIPHER(heim_base_once_t *once, hc_EVP_CIPHER *hc_memoize, + const hc_EVP_CIPHER **hc_memoizep, + const hc_EVP_CIPHER *fallback, + unsigned long flags, int nid) +{ + struct once_init_cipher_ctx arg; + + arg.flags = flags; + arg.hc_memoizep = hc_memoizep; + arg.hc_memoize = hc_memoize; + arg.fallback = fallback; + arg.nid = nid; + heim_base_once_f(once, &arg, get_EVP_CIPHER_once_cb); + return *hc_memoizep; /* May be NULL */ +} + +#define OSSL_CIPHER_ALGORITHM(name, flags) \ + extern const hc_EVP_CIPHER *hc_EVP_hcrypto_##name(void); \ + const hc_EVP_CIPHER *hc_EVP_ossl_##name(void) \ + { \ + static hc_EVP_CIPHER ossl_##name##_st; \ + static const hc_EVP_CIPHER *ossl_##name; \ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; \ + return get_EVP_CIPHER(&once, &ossl_##name##_st, &ossl_##name, \ + hc_EVP_hcrypto_##name(), \ + flags, NID_##name); \ + } + +/* As above, but for EVP_MDs */ + +struct ossl_md_ctx { + EVP_MD_CTX *ossl_md_ctx; /* OpenSSL md ctx */ + const EVP_MD *ossl_md; /* OpenSSL md */ + int initialized; +}; + +static int +ossl_md_init(struct ossl_md_ctx *ctx, const EVP_MD *md) +{ + if (ctx->initialized) + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->initialized = 0; + + ctx->ossl_md = md; + ctx->ossl_md_ctx = EVP_MD_CTX_new(); + if (!EVP_DigestInit(ctx->ossl_md_ctx, md)) { + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->ossl_md_ctx = NULL; + ctx->ossl_md = NULL; + return 0; + } + ctx->initialized = 1; + return 1; +} + +static int +ossl_md_update(hc_EVP_MD_CTX *d, const void *data, size_t count) +{ + struct ossl_md_ctx *ctx = (void *)d; + + return EVP_DigestUpdate(ctx->ossl_md_ctx, data, count); +} + +static int +ossl_md_final(void *md_data, hc_EVP_MD_CTX *d) +{ + struct ossl_md_ctx *ctx = (void *)d; + + return EVP_DigestFinal(ctx->ossl_md_ctx, md_data, NULL); +} + +static int +ossl_md_cleanup(hc_EVP_MD_CTX *d) +{ + struct ossl_md_ctx *ctx = (void *)d; + + if (!ctx->initialized) + return 1; + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->ossl_md = NULL; + ctx->initialized = 0; + + return 1; +} + +struct once_init_md_ctx { + const EVP_MD **ossl_memoizep; + const hc_EVP_MD **hc_memoizep; + hc_EVP_MD *hc_memoize; + const hc_EVP_MD *fallback; + hc_evp_md_init md_init; + int nid; +}; + +static void +get_EVP_MD_once_cb(void *d) +{ + struct once_init_md_ctx *arg = d; + const EVP_MD *ossl_evp; + hc_EVP_MD *hc_evp; + + hc_evp = arg->hc_memoize; + *arg->ossl_memoizep = ossl_evp = EVP_get_digestbynid(arg->nid); + + if (ossl_evp == NULL) { + (void) memset_s(hc_evp, sizeof(*hc_evp), 0, sizeof(*hc_evp)); +#if HCRYPTO_FALLBACK + *arg->hc_memoizep = arg->fallback; +#endif + return; + } + + /* Build the hc_EVP_MD */ + hc_evp->block_size = EVP_MD_block_size(ossl_evp); + hc_evp->hash_size = EVP_MD_size(ossl_evp); + hc_evp->ctx_size = sizeof(struct ossl_md_ctx); + hc_evp->init = arg->md_init; + hc_evp->update = ossl_md_update; + hc_evp->final = ossl_md_final; + hc_evp->cleanup = ossl_md_cleanup; + + *arg->hc_memoizep = hc_evp; +} + +static const hc_EVP_MD * +get_EVP_MD(heim_base_once_t *once, hc_EVP_MD *hc_memoize, + const hc_EVP_MD **hc_memoizep, const EVP_MD **ossl_memoizep, + const hc_EVP_MD *fallback, + hc_evp_md_init md_init, int nid) +{ + struct once_init_md_ctx ctx; + + ctx.ossl_memoizep = ossl_memoizep; + ctx.hc_memoizep = hc_memoizep; + ctx.hc_memoize = hc_memoize; + ctx.fallback = fallback; + ctx.md_init = md_init; + ctx.nid = nid; + heim_base_once_f(once, &ctx, get_EVP_MD_once_cb); + return *hc_memoizep; /* May be NULL */ +} + +#define OSSL_MD_ALGORITHM(name) \ + extern const hc_EVP_MD *hc_EVP_hcrypto_##name(void); \ + static const EVP_MD *ossl_EVP_##name; \ + static const hc_EVP_MD *ossl_##name; \ + static int ossl_init_##name(hc_EVP_MD_CTX *d) \ + { \ + return ossl_md_init((void *)d, ossl_EVP_##name); \ + } \ + const hc_EVP_MD *hc_EVP_ossl_##name(void) \ + { \ + static hc_EVP_MD ossl_##name##_st; \ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; \ + return get_EVP_MD(&once, &ossl_##name##_st, &ossl_##name, \ + &ossl_EVP_##name, hc_EVP_hcrypto_##name(), \ + ossl_init_##name, NID_##name); \ + } + +#else /* HAVE_HCRYPTO_W_OPENSSL */ + +#include "evp-hcrypto.h" + +#define OSSL_CIPHER_ALGORITHM(name, flags) \ + extern const hc_EVP_CIPHER *hc_EVP_ossl_##name(void); \ + const hc_EVP_CIPHER *hc_EVP_ossl_##name(void) \ + { \ + return hc_EVP_hcrypto_##name(); \ + } + +#define OSSL_MD_ALGORITHM(name) \ + extern const hc_EVP_MD *hc_EVP_ossl_##name(void); \ + const hc_EVP_MD *hc_EVP_ossl_##name(void) \ + { \ + return hc_EVP_hcrypto_##name(); \ + } + +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +/** + * The triple DES cipher type (OpenSSL provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(des_ede3_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The DES cipher type (OpenSSL provider) + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +#ifndef HAVE_OPENSSL_30 +OSSL_CIPHER_ALGORITHM(des_cbc, hc_EVP_CIPH_CBC_MODE) +#endif + +/** + * The AES-128 cipher type (OpenSSL provider) + * + * @return the AES-128-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_128_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-192 cipher type (OpenSSL provider) + * + * @return the AES-192-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_192_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-256 cipher type (OpenSSL provider) + * + * @return the AES-256-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_256_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-128 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-128-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_128_cfb8, hc_EVP_CIPH_CFB8_MODE) + +/** + * The AES-192 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-192-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_192_cfb8, hc_EVP_CIPH_CFB8_MODE) + +/** + * The AES-256 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-256-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_256_cfb8, hc_EVP_CIPH_CFB8_MODE) + +#ifndef HAVE_OPENSSL_30 +/* + * RC2 is only needed for tests of PKCS#12 support, which currently uses + * the RC2 PBE. So no RC2 -> tests fail. + */ + +/** + * The RC2 cipher type - OpenSSL + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_cbc, + hc_EVP_CIPH_CBC_MODE | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC2-40 cipher type - OpenSSL + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_40_cbc, + hc_EVP_CIPH_CBC_MODE) + +/** + * The RC2-64 cipher type - OpenSSL + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_64_cbc, + hc_EVP_CIPH_CBC_MODE | + hc_EVP_CIPH_VARIABLE_LENGTH) +#endif + +/** + * The Camellia-128 cipher type - OpenSSL + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_128_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The Camellia-198 cipher type - OpenSSL + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_192_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The Camellia-256 cipher type - OpenSSL + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_256_cbc, hc_EVP_CIPH_CBC_MODE) + +#ifndef HAVE_OPENSSL_30 +/** + * The RC4 cipher type (OpenSSL provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc4, + hc_EVP_CIPH_STREAM_CIPHER | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC4-40 cipher type (OpenSSL provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc4_40, + hc_EVP_CIPH_STREAM_CIPHER | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The MD4 hash algorithm (OpenSSL provider) + * + * @return the MD4 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(md4) +#endif + +/** + * The MD5 hash algorithm (OpenSSL provider) + * + * @return the MD5 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(md5) + +/** + * The SHA-1 hash algorithm (OpenSSL provider) + * + * @return the SHA-1 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha1) + +/** + * The SHA-256 hash algorithm (OpenSSL provider) + * + * @return the SHA-256 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha256) + +/** + * The SHA-384 hash algorithm (OpenSSL provider) + * + * @return the SHA-384 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha384) + +/** + * The SHA-512 hash algorithm (OpenSSL provider) + * + * @return the SHA-512 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha512) diff --git a/third_party/heimdal/lib/hcrypto/evp-openssl.h b/third_party/heimdal/lib/hcrypto/evp-openssl.h new file mode 100644 index 0000000..ff285ad --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-openssl.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_OSSL_H +#define HEIM_EVP_OSSL_H 1 + +/* symbol renaming */ +#define EVP_ossl_md4 hc_EVP_ossl_md4 +#define EVP_ossl_md5 hc_EVP_ossl_md5 +#define EVP_ossl_sha1 hc_EVP_ossl_sha1 +#define EVP_ossl_sha256 hc_EVP_ossl_sha256 +#define EVP_ossl_sha384 hc_EVP_ossl_sha384 +#define EVP_ossl_sha512 hc_EVP_ossl_sha512 +#define EVP_ossl_des_cbc hc_EVP_ossl_des_cbc +#define EVP_ossl_des_ede3_cbc hc_EVP_ossl_des_ede3_cbc +#define EVP_ossl_aes_128_cbc hc_EVP_ossl_aes_128_cbc +#define EVP_ossl_aes_192_cbc hc_EVP_ossl_aes_192_cbc +#define EVP_ossl_aes_256_cbc hc_EVP_ossl_aes_256_cbc +#define EVP_ossl_aes_128_cfb8 hc_EVP_ossl_aes_128_cfb8 +#define EVP_ossl_aes_192_cfb8 hc_EVP_ossl_aes_192_cfb8 +#define EVP_ossl_aes_256_cfb8 hc_EVP_ossl_aes_256_cfb8 +#define EVP_ossl_rc4 hc_EVP_ossl_rc4 +#define EVP_ossl_rc4_40 hc_EVP_ossl_rc4_40 +#define EVP_ossl_rc2_40_cbc hc_EVP_ossl_rc2_40_cbc +#define EVP_ossl_rc2_64_cbc hc_EVP_ossl_rc2_64_cbc +#define EVP_ossl_rc2_cbc hc_EVP_ossl_rc2_cbc +#define EVP_ossl_camellia_128_cbc hc_EVP_ossl_camellia_128_cbc +#define EVP_ossl_camellia_192_cbc hc_EVP_ossl_camellia_192_cbc +#define EVP_ossl_camellia_256_cbc hc_EVP_ossl_camellia_256_cbc + +/* + * + */ + +HC_CPP_BEGIN + +const hc_EVP_MD * hc_EVP_ossl_md4(void); +const hc_EVP_MD * hc_EVP_ossl_md5(void); +const hc_EVP_MD * hc_EVP_ossl_sha1(void); +const hc_EVP_MD * hc_EVP_ossl_sha256(void); +const hc_EVP_MD * hc_EVP_ossl_sha384(void); +const hc_EVP_MD * hc_EVP_ossl_sha512(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_40_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_64_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_rc4(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc4_40(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_des_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_des_ede3_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_aes_128_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_192_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_256_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_aes_128_cfb8(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_192_cfb8(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_256_cfb8(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_128_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_192_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_256_cbc(void); + +HC_CPP_END + +#endif /* HEIM_EVP_OSSL_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-pkcs11.c b/third_party/heimdal/lib/hcrypto/evp-pkcs11.c new file mode 100644 index 0000000..90e2b91 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-pkcs11.c @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2015-2016, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* PKCS#11 provider */ + +#include +#include +#include + +#ifndef HAVE_DLFCN_H +#error PKCS11 support requires dlfcn.h +#endif + +#include + +#include +#include +#include + +#include + +#if __sun && !defined(PKCS11_MODULE_PATH) +# ifdef _LP64 +# define PKCS11_MODULE_PATH "/usr/lib/64/libpkcs11.so" +# else +# define PKCS11_MODULE_PATH "/usr/lib/libpkcs11.so" +# endif +#elif defined(__linux__) +/* + * XXX We should have an autoconf check for OpenCryptoki and such + * things. However, there's no AC_CHECK_OBJECT(), and we'd have to + * write one. Today I'm feeling lazy. Another possibility would be to + * have a symlink from the libdir we'll install into, and then we could + * dlopen() that on all platforms. + * + * XXX Also, we should pick an appropriate shared object based on 32- vs + * 64-bits. + */ +# define PKCS11_MODULE_PATH "/usr/lib/pkcs11/PKCS11_API.so" +#endif + +static CK_FUNCTION_LIST_PTR p11_module; + +static int +p11_cleanup(EVP_CIPHER_CTX *ctx); + +struct pkcs11_cipher_ctx { + CK_SESSION_HANDLE hSession; + CK_OBJECT_HANDLE hSecret; +}; + +struct pkcs11_md_ctx { + CK_SESSION_HANDLE hSession; +}; + +static void *pkcs11_module_handle; + +static CK_RV +p11_module_load(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) +{ + CK_RV rv; + CK_RV (*C_GetFunctionList_fn)(CK_FUNCTION_LIST_PTR_PTR); + char *pkcs11ModulePath = secure_getenv("PKCS11_MODULE_PATH"); + + *ppFunctionList = NULL; + + if (pkcs11ModulePath != NULL) { + pkcs11_module_handle = + dlopen(pkcs11ModulePath, + RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE); + if (pkcs11_module_handle == NULL) + fprintf(stderr, "p11_module_load(%s): %s\n", pkcs11ModulePath, dlerror()); + } +#ifdef PKCS11_MODULE_PATH + if (pkcs11_module_handle == NULL) { + pkcs11_module_handle = + dlopen(PKCS11_MODULE_PATH, + RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE); + if (pkcs11_module_handle == NULL) + fprintf(stderr, "p11_module_load(%s): %s\n", PKCS11_MODULE_PATH, dlerror()); + } +#endif + if (pkcs11_module_handle == NULL) + return CKR_LIBRARY_LOAD_FAILED; + + C_GetFunctionList_fn = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) + dlsym(pkcs11_module_handle, "C_GetFunctionList"); + if (C_GetFunctionList_fn == NULL) { + dlclose(pkcs11_module_handle); + return CKR_LIBRARY_LOAD_FAILED; + } + + rv = C_GetFunctionList_fn(ppFunctionList); + if (rv != CKR_OK) { + dlclose(pkcs11_module_handle); + return rv; + } + + return CKR_OK; +} + +static void +p11_module_load_once(void *context) +{ + p11_module_load((CK_FUNCTION_LIST_PTR_PTR)context); +} + +static CK_RV +p11_module_init(void) +{ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + CK_RV rv; + + heim_base_once_f(&once, &p11_module, p11_module_load_once); + + if (p11_module == NULL) + return CKR_LIBRARY_LOAD_FAILED; + + /* + * Call C_Initialize() on every call, because it will be invalid after fork(). + * Caching the initialization status using a once control and invalidating it + * on fork provided no measurable performance benefit on Solaris 11. Other + * approaches would not be thread-safe or would involve more intrusive code + * changes, such as exposing heimbase's atomics. + */ + rv = p11_module->C_Initialize(NULL); + if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) + rv = CKR_OK; + + return rv; +} + +static CK_RV +p11_session_init(CK_MECHANISM_TYPE mechanismType, + CK_SESSION_HANDLE_PTR phSession, + CK_FLAGS *pFlags) +{ + CK_RV rv; + CK_ULONG i, ulSlotCount = 0; + CK_SLOT_ID_PTR pSlotList = NULL; + CK_MECHANISM_INFO info; + + if (phSession != NULL) + *phSession = CK_INVALID_HANDLE; + + *pFlags = 0; + + rv = p11_module_init(); + if (rv != CKR_OK) + goto cleanup; + + assert(p11_module != NULL); + + rv = p11_module->C_GetSlotList(CK_FALSE, NULL, &ulSlotCount); + if (rv != CKR_OK) + goto cleanup; + + pSlotList = (CK_SLOT_ID_PTR)calloc(ulSlotCount, sizeof(CK_SLOT_ID)); + if (pSlotList == NULL) { + rv = CKR_HOST_MEMORY; + goto cleanup; + } + + rv = p11_module->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + goto cleanup; + + /* + * Note that this approach of using the first slot that supports the desired + * mechanism may not always be what the user wants (for example it may prefer + * software to hardware crypto). We're going to assume that this code will be + * principally used on Solaris (which has a meta-slot provider that sorts by + * hardware first) or in situations where the user can configure the slots in + * order of provider preference. In the future we should make this configurable. + */ + for (i = 0; i < ulSlotCount; i++) { + rv = p11_module->C_GetMechanismInfo(pSlotList[i], mechanismType, &info); + if (rv == CKR_OK) { + *pFlags = info.flags; + break; + } + } + + if (i == ulSlotCount) { + rv = CKR_MECHANISM_INVALID; + goto cleanup; + } + + if (phSession != NULL) { + rv = p11_module->C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION, NULL, NULL, phSession); + if (rv != CKR_OK) + goto cleanup; + } + +cleanup: + free(pSlotList); + + return rv; +} + +static int +p11_mech_available_p(CK_MECHANISM_TYPE mechanismType, CK_FLAGS reqFlags) +{ + CK_RV rv; + CK_FLAGS flags; + + rv = p11_session_init(mechanismType, NULL, &flags); + if (rv != CKR_OK) + return 0; + + return (flags & reqFlags) == reqFlags; +} + +static CK_KEY_TYPE +p11_key_type_for_mech(CK_MECHANISM_TYPE mechanismType) +{ + CK_KEY_TYPE keyType = 0; + + switch (mechanismType) { + case CKM_RC2_CBC: + keyType = CKK_RC2; + break; + case CKM_RC4: + keyType = CKK_RC4; + break; + case CKM_DES_CBC: + keyType = CKK_DES; + break; + case CKM_DES3_CBC: + keyType = CKK_DES3; + break; + case CKM_AES_CBC: + case CKM_AES_CFB8: + keyType = CKK_AES; + break; + case CKM_CAMELLIA_CBC: + keyType = CKK_CAMELLIA; + break; + default: + assert(0 && "Unknown PKCS#11 mechanism type"); + break; + } + + return keyType; +} + +static int +p11_key_init(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, + int encp) +{ + CK_RV rv; + CK_BBOOL bFalse = CK_FALSE; + CK_BBOOL bTrue = CK_TRUE; + CK_MECHANISM_TYPE mechanismType = (CK_MECHANISM_TYPE)ctx->cipher->app_data; + CK_KEY_TYPE keyType = p11_key_type_for_mech(mechanismType); + CK_OBJECT_CLASS objectClass = CKO_SECRET_KEY; + CK_ATTRIBUTE_TYPE op = encp ? CKA_ENCRYPT : CKA_DECRYPT; + CK_ATTRIBUTE attributes[] = { + { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }, + { CKA_CLASS, &objectClass, sizeof(objectClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_TOKEN, &bFalse, sizeof(bFalse) }, + { CKA_PRIVATE, &bFalse, sizeof(bFalse) }, + { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, + { CKA_VALUE, (void *)key, ctx->key_len }, + { op, &bTrue, sizeof(bTrue) } + }; + CK_MECHANISM mechanism = { + mechanismType, + ctx->cipher->iv_len ? ctx->iv : NULL, + ctx->cipher->iv_len + }; + struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data; + CK_FLAGS flags; + + rv = CKR_OK; + + if (p11ctx->hSession != CK_INVALID_HANDLE && key != NULL) + p11_cleanup(ctx); /* refresh session with new key */ + + if (p11ctx->hSession == CK_INVALID_HANDLE) { + rv = p11_session_init(mechanismType, &p11ctx->hSession, &flags); + if (rv != CKR_OK) + goto cleanup; + + if ((flags & (CKF_ENCRYPT|CKF_DECRYPT)) != (CKF_ENCRYPT|CKF_DECRYPT)) { + rv = CKR_MECHANISM_INVALID; + goto cleanup; + } + } + + if (key != NULL) { + assert(p11_module != NULL); + assert(p11ctx->hSecret == CK_INVALID_HANDLE); + + rv = p11_module->C_CreateObject(p11ctx->hSession, attributes, + sizeof(attributes) / sizeof(attributes[0]), + &p11ctx->hSecret); + if (rv != CKR_OK) + goto cleanup; + } + + if (p11ctx->hSecret != CK_INVALID_HANDLE) { + if (op == CKA_ENCRYPT) + rv = p11_module->C_EncryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret); + else + rv = p11_module->C_DecryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret); + if (rv != CKR_OK) + goto cleanup; + } + +cleanup: + if (rv != CKR_OK) + p11_cleanup(ctx); + + return rv == CKR_OK; +} + +static int +p11_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data; + CK_RV rv; + CK_ULONG ulCipherTextLen = size; + + assert(p11_module != NULL); + assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER || + (size % ctx->cipher->block_size) == 0); + + if (ctx->encrypt) + rv = p11_module->C_EncryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen); + else + rv = p11_module->C_DecryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen); + + return rv == CKR_OK; +} + +static int +p11_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data; + + if (p11ctx->hSecret != CK_INVALID_HANDLE) { + p11_module->C_DestroyObject(p11ctx->hSession, p11ctx->hSecret); + p11ctx->hSecret = CK_INVALID_HANDLE; + } + if (p11ctx->hSession != CK_INVALID_HANDLE) { + p11_module->C_CloseSession(p11ctx->hSession); + p11ctx->hSession = CK_INVALID_HANDLE; + } + + return 1; +} + +static int +p11_md_cleanup(EVP_MD_CTX *ctx); + +static int +p11_md_hash_init(CK_MECHANISM_TYPE mechanismType, EVP_MD_CTX *ctx) +{ + struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx; + CK_RV rv; + CK_FLAGS flags; + CK_MECHANISM mechanism = { mechanismType, NULL, 0 }; + + if (p11ctx->hSession != CK_INVALID_HANDLE) + p11_md_cleanup(ctx); + + rv = p11_session_init(mechanismType, &p11ctx->hSession, &flags); + if (rv != CKR_OK) + goto cleanup; + + if ((flags & CKF_DIGEST) != CKF_DIGEST) { + rv = CKR_MECHANISM_INVALID; + goto cleanup; + } + + assert(p11_module != NULL); + + rv = p11_module->C_DigestInit(p11ctx->hSession, &mechanism); + + cleanup: + return rv == CKR_OK; +} + +static int +p11_md_update(EVP_MD_CTX *ctx, const void *data, size_t length) +{ + struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx; + CK_RV rv; + + assert(p11_module != NULL); + assert(data != NULL || length == 0); + + rv = p11_module->C_DigestUpdate(p11ctx->hSession, + data ? (CK_BYTE_PTR)data : (CK_BYTE_PTR)"", + length); + + return rv == CKR_OK; +} + +static int +p11_md_final(void *digest, EVP_MD_CTX *ctx) +{ + struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx; + CK_RV rv; + CK_ULONG digestLen = 0; + + assert(p11_module != NULL); + + rv = p11_module->C_DigestFinal(p11ctx->hSession, NULL, &digestLen); + if (rv == CKR_OK) + rv = p11_module->C_DigestFinal(p11ctx->hSession, digest, &digestLen); + + return rv == CKR_OK; +} + +static int +p11_md_cleanup(EVP_MD_CTX *ctx) +{ + struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx; + CK_RV rv; + + assert(p11_module != NULL); + + rv = p11_module->C_CloseSession(p11ctx->hSession); + if (rv == CKR_OK) + p11ctx->hSession = CK_INVALID_HANDLE; + + return rv == CKR_OK; +} + +#define PKCS11_CIPHER_ALGORITHM(name, mechanismType, block_size, \ + key_len, iv_len, flags) \ + \ + static EVP_CIPHER \ + pkcs11_##name = { \ + 0, \ + block_size, \ + key_len, \ + iv_len, \ + (flags) | EVP_CIPH_ALWAYS_CALL_INIT, \ + p11_key_init, \ + p11_do_cipher, \ + p11_cleanup, \ + sizeof(struct pkcs11_cipher_ctx), \ + NULL, \ + NULL, \ + NULL, \ + (void *)mechanismType \ + }; \ + \ + const EVP_CIPHER * \ + hc_EVP_pkcs11_##name(void) \ + { \ + if (p11_mech_available_p(mechanismType, CKF_ENCRYPT|CKF_DECRYPT)) \ + return &pkcs11_##name; \ + else \ + return NULL; \ + } \ + \ + static void \ + pkcs11_hcrypto_##name##_init_once(void *context) \ + { \ + const EVP_CIPHER *cipher; \ + \ + cipher = hc_EVP_pkcs11_ ##name(); \ + if (cipher == NULL && HCRYPTO_FALLBACK) \ + cipher = hc_EVP_hcrypto_ ##name(); \ + \ + *((const EVP_CIPHER **)context) = cipher; \ + } \ + \ + const EVP_CIPHER * \ + hc_EVP_pkcs11_hcrypto_##name(void) \ + { \ + static const EVP_CIPHER *__cipher; \ + static heim_base_once_t __init = HEIM_BASE_ONCE_INIT; \ + \ + heim_base_once_f(&__init, &__cipher, \ + pkcs11_hcrypto_##name##_init_once); \ + \ + return __cipher; \ + } + +#define PKCS11_MD_ALGORITHM(name, mechanismType, hash_size, block_size) \ + \ + static int p11_##name##_init(EVP_MD_CTX *ctx) \ + { \ + return p11_md_hash_init(mechanismType, ctx); \ + } \ + \ + const EVP_MD * \ + hc_EVP_pkcs11_##name(void) \ + { \ + static struct hc_evp_md name = { \ + hash_size, \ + block_size, \ + sizeof(struct pkcs11_md_ctx), \ + p11_##name##_init, \ + p11_md_update, \ + p11_md_final, \ + p11_md_cleanup \ + }; \ + \ + if (p11_mech_available_p(mechanismType, CKF_DIGEST)) \ + return &name; \ + else \ + return NULL; \ + } \ + \ + static void \ + pkcs11_hcrypto_##name##_init_once(void *context) \ + { \ + const EVP_MD *md; \ + \ + md = hc_EVP_pkcs11_ ##name(); \ + if (md == NULL && HCRYPTO_FALLBACK) \ + md = hc_EVP_hcrypto_ ##name(); \ + \ + *((const EVP_MD **)context) = md; \ + } \ + \ + const EVP_MD * \ + hc_EVP_pkcs11_hcrypto_##name(void) \ + { \ + static const EVP_MD *__md; \ + static heim_base_once_t __init = HEIM_BASE_ONCE_INIT; \ + \ + heim_base_once_f(&__init, &__md, \ + pkcs11_hcrypto_##name##_init_once); \ + \ + return __md; \ + } + +#define PKCS11_MD_ALGORITHM_UNAVAILABLE(name) \ + \ + const EVP_MD * \ + hc_EVP_pkcs11_##name(void) \ + { \ + return NULL; \ + } \ + \ + const EVP_MD * \ + hc_EVP_pkcs11_hcrypto_##name(void) \ + { \ + return hc_EVP_hcrypto_ ##name(); \ + } + +/** + * The triple DES cipher type (PKCS#11 provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(des_ede3_cbc, + CKM_DES3_CBC, + 8, + 24, + 8, + EVP_CIPH_CBC_MODE) + +/** + * The DES cipher type (PKCS#11 provider) + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(des_cbc, + CKM_DES_CBC, + 8, + 8, + 8, + EVP_CIPH_CBC_MODE) + +/** + * The AES-128 cipher type (PKCS#11 provider) + * + * @return the AES-128-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_128_cbc, + CKM_AES_CBC, + 16, + 16, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The AES-192 cipher type (PKCS#11 provider) + * + * @return the AES-192-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_192_cbc, + CKM_AES_CBC, + 16, + 24, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The AES-256 cipher type (PKCS#11 provider) + * + * @return the AES-256-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_256_cbc, + CKM_AES_CBC, + 16, + 32, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The AES-128 CFB8 cipher type (PKCS#11 provider) + * + * @return the AES-128-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_128_cfb8, + CKM_AES_CFB8, + 16, + 16, + 16, + EVP_CIPH_CFB8_MODE) + +/** + * The AES-192 CFB8 cipher type (PKCS#11 provider) + * + * @return the AES-192-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_192_cfb8, + CKM_AES_CFB8, + 16, + 24, + 16, + EVP_CIPH_CFB8_MODE) + +/** + * The AES-256 CFB8 cipher type (PKCS#11 provider) + * + * @return the AES-256-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(aes_256_cfb8, + CKM_AES_CFB8, + 16, + 32, + 16, + EVP_CIPH_CFB8_MODE) + +/** + * The RC2 cipher type - PKCS#11 + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(rc2_cbc, + CKM_RC2_CBC, + 8, + 16, + 8, + EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC2-40 cipher type - PKCS#11 + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(rc2_40_cbc, + CKM_RC2_CBC, + 8, + 5, + 8, + EVP_CIPH_CBC_MODE) + +/** + * The RC2-64 cipher type - PKCS#11 + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(rc2_64_cbc, + CKM_RC2_CBC, + 8, + 8, + 8, + EVP_CIPH_CBC_MODE) + +/** + * The Camellia-128 cipher type - PKCS#11 + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(camellia_128_cbc, + CKM_CAMELLIA_CBC, + 16, + 16, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The Camellia-198 cipher type - PKCS#11 + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(camellia_192_cbc, + CKM_CAMELLIA_CBC, + 16, + 24, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The Camellia-256 cipher type - PKCS#11 + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(camellia_256_cbc, + CKM_CAMELLIA_CBC, + 16, + 32, + 16, + EVP_CIPH_CBC_MODE) + +/** + * The RC4 cipher type (PKCS#11 provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(rc4, + CKM_RC4, + 1, + 16, + 0, + EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC4-40 cipher type (PKCS#11 provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +PKCS11_CIPHER_ALGORITHM(rc4_40, + CKM_RC4, + 1, + 5, + 0, + EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH) + +#ifdef CKM_MD4 /* non-standard extension */ +PKCS11_MD_ALGORITHM(md4, CKM_MD4, 16, 64) +#else +PKCS11_MD_ALGORITHM_UNAVAILABLE(md4) +#endif +PKCS11_MD_ALGORITHM(md5, CKM_MD5, 16, 64) +PKCS11_MD_ALGORITHM(sha1, CKM_SHA_1, 20, 64) +PKCS11_MD_ALGORITHM(sha256, CKM_SHA256, 32, 64) +PKCS11_MD_ALGORITHM(sha384, CKM_SHA384, 48, 128) +PKCS11_MD_ALGORITHM(sha512, CKM_SHA512, 64, 128) diff --git a/third_party/heimdal/lib/hcrypto/evp-pkcs11.h b/third_party/heimdal/lib/hcrypto/evp-pkcs11.h new file mode 100644 index 0000000..49d020a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-pkcs11.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_PKCS11_H +#define HEIM_EVP_PKCS11_H 1 + +/* symbol renaming */ + +#define EVP_pkcs11_md4() hc_EVP_pkcs11_md4() +#define EVP_pkcs11_md5() hc_EVP_pkcs11_md5() +#define EVP_pkcs11_sha1() hc_EVP_pkcs11_sha1() +#define EVP_pkcs11_sha256() hc_EVP_pkcs11_sha256() +#define EVP_pkcs11_sha384() hc_EVP_pkcs11_sha384() +#define EVP_pkcs11_sha512() hc_EVP_pkcs11_sha512() +#define EVP_pkcs11_des_cbc() hc_EVP_pkcs11_des_cbc() +#define EVP_pkcs11_des_ede3_cbc() hc_EVP_pkcs11_des_ede3_cbc() +#define EVP_pkcs11_aes_128_cbc() hc_EVP_pkcs11_aes_128_cbc() +#define EVP_pkcs11_aes_192_cbc() hc_EVP_pkcs11_aes_192_cbc() +#define EVP_pkcs11_aes_256_cbc() hc_EVP_pkcs11_aes_256_cbc() +#define EVP_pkcs11_aes_128_cfb8() hc_EVP_pkcs11_aes_128_cfb8() +#define EVP_pkcs11_aes_192_cfb8() hc_EVP_pkcs11_aes_192_cfb8() +#define EVP_pkcs11_aes_256_cfb8() hc_EVP_pkcs11_aes_256_cfb8() +#define EVP_pkcs11_rc4() hc_EVP_pkcs11_rc4() +#define EVP_pkcs11_rc4_40() hc_EVP_pkcs11_rc4_40() +#define EVP_pkcs11_rc2_40_cbc() hc_EVP_pkcs11_rc2_40_cbc() +#define EVP_pkcs11_rc2_64_cbc() hc_EVP_pkcs11_rc2_64_cbc() +#define EVP_pkcs11_rc2_cbc() hc_EVP_pkcs11_rc2_cbc() +#define EVP_pkcs11_camellia_128_cbc() hc_EVP_pkcs11_camellia_128_cbc() +#define EVP_pkcs11_camellia_192_cbc() hc_EVP_pkcs11_camellia_192_cbc() +#define EVP_pkcs11_camellia_256_cbc() hc_EVP_pkcs11_camellia_256_cbc() + +#define EVP_pkcs11_hcrypto_md4() hc_EVP_pkcs11_hcrypto_md4() +#define EVP_pkcs11_hcrypto_md5() hc_EVP_pkcs11_hcrypto_md5() +#define EVP_pkcs11_hcrypto_sha1() hc_EVP_pkcs11_hcrypto_sha1() +#define EVP_pkcs11_hcrypto_sha256() hc_EVP_pkcs11_hcrypto_sha256() +#define EVP_pkcs11_hcrypto_sha384() hc_EVP_pkcs11_hcrypto_sha384() +#define EVP_pkcs11_hcrypto_sha512() hc_EVP_pkcs11_hcrypto_sha512() +#define EVP_pkcs11_hcrypto_des_cbc() hc_EVP_pkcs11_hcrypto_des_cbc() +#define EVP_pkcs11_hcrypto_des_ede3_cbc() hc_EVP_pkcs11_hcrypto_des_ede3_cbc() +#define EVP_pkcs11_hcrypto_aes_128_cbc() hc_EVP_pkcs11_hcrypto_aes_128_cbc() +#define EVP_pkcs11_hcrypto_aes_192_cbc() hc_EVP_pkcs11_hcrypto_aes_192_cbc() +#define EVP_pkcs11_hcrypto_aes_256_cbc() hc_EVP_pkcs11_hcrypto_aes_256_cbc() +#define EVP_pkcs11_hcrypto_aes_128_cfb8() hc_EVP_pkcs11_hcrypto_aes_128_cfb8() +#define EVP_pkcs11_hcrypto_aes_192_cfb8() hc_EVP_pkcs11_hcrypto_aes_192_cfb8() +#define EVP_pkcs11_hcrypto_aes_256_cfb8() hc_EVP_pkcs11_hcrypto_aes_256_cfb8() +#define EVP_pkcs11_hcrypto_rc4() hc_EVP_pkcs11_hcrypto_rc4() +#define EVP_pkcs11_hcrypto_rc4_40() hc_EVP_pkcs11_hcrypto_rc4_40() +#define EVP_pkcs11_hcrypto_rc2_40_cbc() hc_EVP_pkcs11_hcrypto_rc2_40_cbc() +#define EVP_pkcs11_hcrypto_rc2_64_cbc() hc_EVP_pkcs11_hcrypto_rc2_64_cbc() +#define EVP_pkcs11_hcrypto_rc2_cbc() hc_EVP_pkcs11_hcrypto_rc2_cbc() +#define EVP_pkcs11_hcrypto_camellia_128_cbc() hc_EVP_pkcs11_hcrypto_camellia_128_cbc() +#define EVP_pkcs11_hcrypto_camellia_192_cbc() hc_EVP_pkcs11_hcrypto_camellia_192_cbc() +#define EVP_pkcs11_hcrypto_camellia_256_cbc() hc_EVP_pkcs11_hcrypto_camellia_256_cbc() + +HC_CPP_BEGIN + +/* + * Strict PKCS#11 implementations (these will return NULL if the underlying + * PKCS#11 implementation does not implement the cipher or hash). + */ +const EVP_MD * hc_EVP_pkcs11_md4(void); +const EVP_MD * hc_EVP_pkcs11_md5(void); +const EVP_MD * hc_EVP_pkcs11_sha1(void); +const EVP_MD * hc_EVP_pkcs11_sha256(void); +const EVP_MD * hc_EVP_pkcs11_sha384(void); +const EVP_MD * hc_EVP_pkcs11_sha512(void); + +const EVP_CIPHER * hc_EVP_pkcs11_rc2_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_rc2_40_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_rc2_64_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_rc4(void); +const EVP_CIPHER * hc_EVP_pkcs11_rc4_40(void); + +const EVP_CIPHER * hc_EVP_pkcs11_des_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_des_ede3_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_aes_128_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_aes_192_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_aes_256_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_aes_128_cfb8(void); +const EVP_CIPHER * hc_EVP_pkcs11_aes_192_cfb8(void); +const EVP_CIPHER * hc_EVP_pkcs11_aes_256_cfb8(void); + +const EVP_CIPHER * hc_EVP_pkcs11_camellia_128_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_camellia_192_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_camellia_256_cbc(void); + +/* + * PKCS#11 implementations with fallback to hcrypto. + */ +const EVP_MD * hc_EVP_pkcs11_hcrypto_md4(void); +const EVP_MD * hc_EVP_pkcs11_hcrypto_md5(void); +const EVP_MD * hc_EVP_pkcs11_hcrypto_sha1(void); +const EVP_MD * hc_EVP_pkcs11_hcrypto_sha256(void); +const EVP_MD * hc_EVP_pkcs11_hcrypto_sha384(void); +const EVP_MD * hc_EVP_pkcs11_hcrypto_sha512(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_rc2_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_rc2_40_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_rc2_64_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_rc4(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_rc4_40(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_des_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_des_ede3_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_128_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_192_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_256_cbc(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_128_cfb8(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_192_cfb8(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_aes_256_cfb8(void); + +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_camellia_128_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_camellia_192_cbc(void); +const EVP_CIPHER * hc_EVP_pkcs11_hcrypto_camellia_256_cbc(void); + +HC_CPP_END + +#endif /* HEIM_EVP_PKCS11_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-w32.c b/third_party/heimdal/lib/hcrypto/evp-w32.c new file mode 100644 index 0000000..ac2c6a5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-w32.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Windows fallback provider: decides whether to use hcrypto or + * wincng depending on whether bcrypt.dll is available (i.e. it + * is runtime compatible back to XP, but will use the native + * crypto APIs from Vista onwards). + */ + +#include +#include + +#include + +#include +#include +#include + +#include + +static LONG wincng_available = -1; + +static __inline int +wincng_check_availability(void) +{ + if (wincng_available == -1) { + char szBCryptDllPath[MAX_PATH]; + UINT cbBCryptDllPath; + + cbBCryptDllPath = GetSystemDirectory(szBCryptDllPath, + sizeof(szBCryptDllPath)); + if (cbBCryptDllPath > 0 && + cbBCryptDllPath < sizeof(szBCryptDllPath) && + strncat_s(szBCryptDllPath, + sizeof(szBCryptDllPath), "\\bcrypt.dll", 11) == 0) { + HANDLE hBCryptDll = LoadLibrary(szBCryptDllPath); + + InterlockedCompareExchangeRelease(&wincng_available, + !!hBCryptDll, -1); + if (hBCryptDll) + FreeLibrary(hBCryptDll); + } + } + + return wincng_available == 1; +} + +BOOL WINAPI +_hc_w32crypto_DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_DETACH) { + /* + * Don't bother cleaning up on process exit, only on + * FreeLibrary() (in which case lpvReserved will be NULL). + */ + if (lpvReserved == NULL) + _hc_wincng_cleanup(); + } + + return TRUE; +} + +#define EVP_W32CRYPTO_PROVIDER(type, name) \ + \ + const type *hc_EVP_w32crypto_ ##name (void) \ + { \ + if (wincng_check_availability()) \ + return hc_EVP_wincng_ ##name (); \ + else if (HCRYPTO_FALLBACK) \ + return hc_EVP_hcrypto_ ##name (); \ + else \ + return NULL; \ + } + +#define EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(type, name) \ + \ + const type *hc_EVP_w32crypto_ ##name (void) \ + { \ + return hc_EVP_hcrypto_ ##name (); \ + } + +EVP_W32CRYPTO_PROVIDER(EVP_MD, md4) +EVP_W32CRYPTO_PROVIDER(EVP_MD, md5) +EVP_W32CRYPTO_PROVIDER(EVP_MD, sha1) +EVP_W32CRYPTO_PROVIDER(EVP_MD, sha256) +EVP_W32CRYPTO_PROVIDER(EVP_MD, sha384) +EVP_W32CRYPTO_PROVIDER(EVP_MD, sha512) + +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_cbc) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_40_cbc) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_64_cbc) + +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc4) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc4_40) + +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, des_cbc) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, des_ede3_cbc) + +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_128_cbc) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_192_cbc) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_256_cbc) + +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_128_cfb8) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_192_cfb8) +EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_256_cfb8) + +EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_128_cbc) +EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_192_cbc) +EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_256_cbc) diff --git a/third_party/heimdal/lib/hcrypto/evp-w32.h b/third_party/heimdal/lib/hcrypto/evp-w32.h new file mode 100644 index 0000000..6d3ba45 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-w32.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_W32_H +#define HEIM_EVP_W32_H 1 + +/* symbol renaming */ +#define EVP_w32crypto_md4() hc_EVP_w32crypto_md4() +#define EVP_w32crypto_md5() hc_EVP_w32crypto_md5() +#define EVP_w32crypto_sha1() hc_EVP_w32crypto_sha1() +#define EVP_w32crypto_sha256() hc_EVP_w32crypto_sha256() +#define EVP_w32crypto_sha384() hc_EVP_w32crypto_sha384() +#define EVP_w32crypto_sha512() hc_EVP_w32crypto_sha512() +#define EVP_w32crypto_des_cbc() hc_EVP_w32crypto_des_cbc() +#define EVP_w32crypto_des_ede3_cbc() hc_EVP_w32crypto_des_ede3_cbc() +#define EVP_w32crypto_aes_128_cbc() hc_EVP_w32crypto_aes_128_cbc() +#define EVP_w32crypto_aes_192_cbc() hc_EVP_w32crypto_aes_192_cbc() +#define EVP_w32crypto_aes_256_cbc() hc_EVP_w32crypto_aes_256_cbc() +#define EVP_w32crypto_aes_128_cfb8() hc_EVP_w32crypto_aes_128_cfb8() +#define EVP_w32crypto_aes_192_cfb8() hc_EVP_w32crypto_aes_192_cfb8() +#define EVP_w32crypto_aes_256_cfb8() hc_EVP_w32crypto_aes_256_cfb8() +#define EVP_w32crypto_rc4() hc_EVP_w32crypto_rc4() +#define EVP_w32crypto_rc4_40() hc_EVP_w32crypto_rc4_40() +#define EVP_w32crypto_rc2_40_cbc() hc_EVP_w32crypto_rc2_40_cbc() +#define EVP_w32crypto_rc2_64_cbc() hc_EVP_w32crypto_rc2_64_cbc() +#define EVP_w32crypto_rc2_cbc() hc_EVP_w32crypto_rc2_cbc() +#define EVP_w32crypto_camellia_128_cbc() hc_EVP_w32crypto_camellia_128_cbc() +#define EVP_w32crypto_camellia_192_cbc() hc_EVP_w32crypto_camellia_192_cbc() +#define EVP_w32crypto_camellia_256_cbc() hc_EVP_w32crypto_camellia_256_cbc() + +/* + * This provider dynamically selects between Windows CNG (if running + * on Vista or above) or the inbuilt provider (if running on XP). + */ + +HC_CPP_BEGIN + +const EVP_MD * hc_EVP_w32crypto_md4(void); +const EVP_MD * hc_EVP_w32crypto_md5(void); +const EVP_MD * hc_EVP_w32crypto_sha1(void); +const EVP_MD * hc_EVP_w32crypto_sha256(void); +const EVP_MD * hc_EVP_w32crypto_sha384(void); +const EVP_MD * hc_EVP_w32crypto_sha512(void); + +const EVP_CIPHER * hc_EVP_w32crypto_des_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_des_ede3_cbc(void); + +const EVP_CIPHER * hc_EVP_w32crypto_aes_128_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_aes_192_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_aes_256_cbc(void); + +const EVP_CIPHER * hc_EVP_w32crypto_aes_128_cfb8(void); +const EVP_CIPHER * hc_EVP_w32crypto_aes_192_cfb8(void); +const EVP_CIPHER * hc_EVP_w32crypto_aes_256_cfb8(void); + +const EVP_CIPHER * hc_EVP_w32crypto_rc4(void); +const EVP_CIPHER * hc_EVP_w32crypto_rc4_40(void); + +const EVP_CIPHER * hc_EVP_w32crypto_rc2_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_rc2_40_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_rc2_64_cbc(void); + +const EVP_CIPHER * hc_EVP_w32crypto_camellia_128_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_camellia_192_cbc(void); +const EVP_CIPHER * hc_EVP_w32crypto_camellia_256_cbc(void); + +HC_CPP_END + +#endif /* HEIM_EVP_W32_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp-wincng.c b/third_party/heimdal/lib/hcrypto/evp-wincng.c new file mode 100644 index 0000000..34ac3b3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-wincng.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Windows CNG provider */ + +#include +#include +#include +#include + +#include +#include + +#include + +#ifndef BCRYPT_HASH_REUSABLE_FLAG +#define BCRYPT_HASH_REUSABLE_FLAG 0x00000020 +#endif + +/* + * CNG cipher provider + */ + +struct wincng_key { + BCRYPT_KEY_HANDLE hKey; + UCHAR rgbKeyObject[1]; +}; + +#define WINCNG_KEY_OBJECT_SIZE(ctx) \ + ((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1) + +static int +wincng_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + struct wincng_key *cng = ctx->cipher_data; + NTSTATUS status; + ULONG cbResult; + + assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER || + (size % ctx->cipher->block_size) == 0); + + if (ctx->encrypt) { + status = BCryptEncrypt(cng->hKey, + (PUCHAR)in, + size, + NULL, /* pPaddingInfo */ + ctx->cipher->iv_len ? ctx->iv : NULL, + ctx->cipher->iv_len, + out, + size, + &cbResult, + 0); + } else { + status = BCryptDecrypt(cng->hKey, + (PUCHAR)in, + size, + NULL, /* pPaddingInfo */ + ctx->cipher->iv_len ? ctx->iv : NULL, + ctx->cipher->iv_len, + out, + size, + &cbResult, + 0); + } + + return BCRYPT_SUCCESS(status) && cbResult == size; +} + +static int +wincng_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct wincng_key *cng = ctx->cipher_data; + + if (cng->hKey) { + BCryptDestroyKey(cng->hKey); + cng->hKey = (BCRYPT_KEY_HANDLE)0; + } + SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx)); + + return 1; +} + +static int +wincng_cipher_algorithm_init(EVP_CIPHER *cipher, + LPWSTR pszAlgId) +{ + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + NTSTATUS status; + LPCWSTR pszChainingMode; + ULONG cbKeyObject, cbChainingMode, cbData; + + if (cipher->app_data) + return 1; + + status = BCryptOpenAlgorithmProvider(&hAlgorithm, + pszAlgId, + NULL, + 0); + if (!BCRYPT_SUCCESS(status)) + return 0; + + status = BCryptGetProperty(hAlgorithm, + BCRYPT_OBJECT_LENGTH, + (PUCHAR)&cbKeyObject, + sizeof(ULONG), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return 0; + } + + cipher->ctx_size = sizeof(struct wincng_key) + cbKeyObject - 1; + + switch (cipher->flags & EVP_CIPH_MODE) { + case EVP_CIPH_CBC_MODE: + pszChainingMode = BCRYPT_CHAIN_MODE_CBC; + cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CBC); + break; + case EVP_CIPH_CFB8_MODE: + pszChainingMode = BCRYPT_CHAIN_MODE_CFB; + cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB); + break; + default: + pszChainingMode = NULL; + cbChainingMode = 0; + break; + } + + if (cbChainingMode) { + status = BCryptSetProperty(hAlgorithm, + BCRYPT_CHAINING_MODE, + (PUCHAR)pszChainingMode, + cbChainingMode, + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return 0; + } + } + + if (wcscmp(pszAlgId, BCRYPT_RC2_ALGORITHM) == 0) { + ULONG cbEffectiveKeyLength = EVP_CIPHER_key_length(cipher) * 8; + + status = BCryptSetProperty(hAlgorithm, + BCRYPT_EFFECTIVE_KEY_LENGTH, + (PUCHAR)&cbEffectiveKeyLength, + sizeof(cbEffectiveKeyLength), + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return 0; + } + } + + InterlockedCompareExchangePointerRelease(&cipher->app_data, + hAlgorithm, NULL); + return 1; +} + +static int +wincng_key_init(EVP_CIPHER_CTX *ctx, + const unsigned char *key, + const unsigned char *iv, + int encp) +{ + struct wincng_key *cng = ctx->cipher_data; + NTSTATUS status; + + assert(cng != NULL); + assert(ctx->cipher != NULL); + + if (ctx->cipher->app_data == NULL) + return 0; + + wincng_cleanup(ctx); + + /* + * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for + * variable length key support. + */ + status = BCryptGenerateSymmetricKey(ctx->cipher->app_data, + &cng->hKey, + cng->rgbKeyObject, + WINCNG_KEY_OBJECT_SIZE(ctx), + (PUCHAR)key, + ctx->key_len, + 0); + + return BCRYPT_SUCCESS(status); +} + +#define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len, \ + iv_len, flags) \ + \ + static EVP_CIPHER \ + wincng_##name = { \ + 0, \ + block_size, \ + key_len, \ + iv_len, \ + flags, \ + wincng_key_init, \ + wincng_do_cipher, \ + wincng_cleanup, \ + 0, \ + NULL, \ + NULL, \ + NULL, \ + NULL \ + }; \ + \ + const EVP_CIPHER * \ + hc_EVP_wincng_##name(void) \ + { \ + wincng_cipher_algorithm_init(&wincng_##name, alg_id); \ + return wincng_##name.app_data ? &wincng_##name : NULL; \ + } + +#define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do { \ + if (wincng_##name.app_data) { \ + BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0); \ + wincng_##name.app_data = NULL; \ + } \ + } while (0) + +#define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name) \ + \ + const EVP_CIPHER * \ + hc_EVP_wincng_##name(void) \ + { \ + return NULL; \ + } + +/** + * The triple DES cipher type (Windows CNG provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(des_ede3_cbc, + BCRYPT_3DES_ALGORITHM, + 8, + 24, + 8, + EVP_CIPH_CBC_MODE); + +/** + * The DES cipher type (Windows CNG provider) + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(des_cbc, + BCRYPT_DES_ALGORITHM, + 8, + 8, + 8, + EVP_CIPH_CBC_MODE); + +/** + * The AES-128 cipher type (Windows CNG provider) + * + * @return the AES-128-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_128_cbc, + BCRYPT_AES_ALGORITHM, + 16, + 16, + 16, + EVP_CIPH_CBC_MODE); + +/** + * The AES-192 cipher type (Windows CNG provider) + * + * @return the AES-192-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_192_cbc, + BCRYPT_AES_ALGORITHM, + 16, + 24, + 16, + EVP_CIPH_CBC_MODE); + +/** + * The AES-256 cipher type (Windows CNG provider) + * + * @return the AES-256-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_256_cbc, + BCRYPT_AES_ALGORITHM, + 16, + 32, + 16, + EVP_CIPH_CBC_MODE); + +/** + * The AES-128 CFB8 cipher type (Windows CNG provider) + * + * @return the AES-128-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_128_cfb8, + BCRYPT_AES_ALGORITHM, + 16, + 16, + 16, + EVP_CIPH_CFB8_MODE); + +/** + * The AES-192 CFB8 cipher type (Windows CNG provider) + * + * @return the AES-192-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_192_cfb8, + BCRYPT_AES_ALGORITHM, + 16, + 24, + 16, + EVP_CIPH_CFB8_MODE); + +/** + * The AES-256 CFB8 cipher type (Windows CNG provider) + * + * @return the AES-256-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(aes_256_cfb8, + BCRYPT_AES_ALGORITHM, + 16, + 32, + 16, + EVP_CIPH_CFB8_MODE); + +/** + * The RC2 cipher type - Windows CNG + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(rc2_cbc, + BCRYPT_RC2_ALGORITHM, + 8, + 16, + 8, + EVP_CIPH_CBC_MODE); + +/** + * The RC2-40 cipher type - Windows CNG + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(rc2_40_cbc, + BCRYPT_RC2_ALGORITHM, + 8, + 5, + 8, + EVP_CIPH_CBC_MODE); + +/** + * The RC2-64 cipher type - Windows CNG + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(rc2_64_cbc, + BCRYPT_RC2_ALGORITHM, + 8, + 8, + 8, + EVP_CIPH_CBC_MODE); + +/** + * The Camellia-128 cipher type - CommonCrypto + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc); + +/** + * The Camellia-198 cipher type - CommonCrypto + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc); + +/** + * The Camellia-256 cipher type - CommonCrypto + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc); + +/** + * The RC4 cipher type (Windows CNG provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(rc4, + BCRYPT_RC4_ALGORITHM, + 1, + 16, + 0, + EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH); + +/** + * The RC4-40 cipher type (Windows CNG provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +WINCNG_CIPHER_ALGORITHM(rc4_40, + BCRYPT_RC4_ALGORITHM, + 1, + 5, + 0, + EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH); + +static void +wincng_cipher_algorithm_cleanup(void) +{ + WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8); + WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8); + WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc); + WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4); + WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40); +} + +/* + * CNG digest provider + */ + +struct wincng_md_ctx { + BCRYPT_HASH_HANDLE hHash; + ULONG cbHashObject; + UCHAR rgbHashObject[1]; +}; + +static BCRYPT_ALG_HANDLE +wincng_md_algorithm_init(EVP_MD *md, + LPCWSTR pszAlgId) +{ + BCRYPT_ALG_HANDLE hAlgorithm; + NTSTATUS status; + ULONG cbHashObject, cbData; + ULONG cbHash = 0, cbBlock = 0; + + status = BCryptOpenAlgorithmProvider(&hAlgorithm, + pszAlgId, + NULL, + 0); + if (!BCRYPT_SUCCESS(status)) + return NULL; + + status = BCryptGetProperty(hAlgorithm, + BCRYPT_HASH_LENGTH, + (PUCHAR)&cbHash, + sizeof(ULONG), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return NULL; + } + + status = BCryptGetProperty(hAlgorithm, + BCRYPT_HASH_BLOCK_LENGTH, + (PUCHAR)&cbBlock, + sizeof(ULONG), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return NULL; + } + + status = BCryptGetProperty(hAlgorithm, + BCRYPT_OBJECT_LENGTH, + (PUCHAR)&cbHashObject, + sizeof(ULONG), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(hAlgorithm, 0); + return NULL; + } + + md->hash_size = cbHash; + md->block_size = cbBlock; + md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1; + + return hAlgorithm; +} + +static int +wincng_md_cleanup(EVP_MD_CTX *ctx); + +static int +wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm, + EVP_MD_CTX *ctx) +{ + struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx; + NTSTATUS status; + ULONG cbData, dwFlags = 0; + + if (IsWindows8OrGreaterCached()) { + if (cng->hHash) + return 1; + else + dwFlags |= BCRYPT_HASH_REUSABLE_FLAG; + } else + wincng_md_cleanup(ctx); + + status = BCryptGetProperty(hAlgorithm, + BCRYPT_OBJECT_LENGTH, + (PUCHAR)&cng->cbHashObject, + sizeof(ULONG), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) + return 0; + + status = BCryptCreateHash(hAlgorithm, + &cng->hHash, + cng->rgbHashObject, + cng->cbHashObject, + NULL, + 0, + dwFlags); + + return BCRYPT_SUCCESS(status); +} + +static int +wincng_md_update(EVP_MD_CTX *ctx, + const void *data, + size_t length) +{ + struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx; + NTSTATUS status; + + status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0); + + return BCRYPT_SUCCESS(status); +} + +static int +wincng_md_final(void *digest, + EVP_MD_CTX *ctx) +{ + struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx; + NTSTATUS status; + ULONG cbHash, cbData; + + status = BCryptGetProperty(cng->hHash, + BCRYPT_HASH_LENGTH, + (PUCHAR)&cbHash, + sizeof(DWORD), + &cbData, + 0); + if (!BCRYPT_SUCCESS(status)) + return 0; + + status = BCryptFinishHash(cng->hHash, + digest, + cbHash, + 0); + + return BCRYPT_SUCCESS(status); +} + +static int +wincng_md_cleanup(EVP_MD_CTX *ctx) +{ + struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx; + + if (cng->hHash) { + BCryptDestroyHash(cng->hHash); + cng->hHash = (BCRYPT_HASH_HANDLE)0; + } + SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject); + + return 1; +} + +#define WINCNG_MD_ALGORITHM(name, alg_id) \ + \ + static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name; \ + \ + static int wincng_##name##_init(EVP_MD_CTX *ctx) \ + { \ + return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx); \ + } \ + \ + const EVP_MD * \ + hc_EVP_wincng_##name(void) \ + { \ + static struct hc_evp_md name = { \ + 0, \ + 0, \ + 0, \ + wincng_##name##_init, \ + wincng_md_update, \ + wincng_md_final, \ + wincng_md_cleanup \ + }; \ + \ + if (wincng_hAlgorithm_##name == NULL) { \ + BCRYPT_ALG_HANDLE hAlgorithm = \ + wincng_md_algorithm_init(&name, alg_id); \ + InterlockedCompareExchangePointerRelease( \ + &wincng_hAlgorithm_##name, hAlgorithm, NULL); \ + } \ + return wincng_hAlgorithm_##name ? &name : NULL; \ + } + +#define WINCNG_MD_ALGORITHM_CLEANUP(name) do { \ + if (wincng_hAlgorithm_##name) { \ + BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0); \ + wincng_hAlgorithm_##name = NULL; \ + } \ + } while (0) + +WINCNG_MD_ALGORITHM(md4, BCRYPT_MD4_ALGORITHM); +WINCNG_MD_ALGORITHM(md5, BCRYPT_MD5_ALGORITHM); +WINCNG_MD_ALGORITHM(sha1, BCRYPT_SHA1_ALGORITHM); +WINCNG_MD_ALGORITHM(sha256, BCRYPT_SHA256_ALGORITHM); +WINCNG_MD_ALGORITHM(sha384, BCRYPT_SHA384_ALGORITHM); +WINCNG_MD_ALGORITHM(sha512, BCRYPT_SHA512_ALGORITHM); + +static void +wincng_md_algorithm_cleanup(void) +{ + WINCNG_MD_ALGORITHM_CLEANUP(md4); + WINCNG_MD_ALGORITHM_CLEANUP(md5); + WINCNG_MD_ALGORITHM_CLEANUP(sha1); + WINCNG_MD_ALGORITHM_CLEANUP(sha256); + WINCNG_MD_ALGORITHM_CLEANUP(sha384); + WINCNG_MD_ALGORITHM_CLEANUP(sha512); +} + +void _hc_wincng_cleanup(void) +{ + wincng_md_algorithm_cleanup(); + wincng_cipher_algorithm_cleanup(); +} diff --git a/third_party/heimdal/lib/hcrypto/evp-wincng.h b/third_party/heimdal/lib/hcrypto/evp-wincng.h new file mode 100644 index 0000000..88d9830 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp-wincng.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_WINCNG_H +#define HEIM_EVP_WINCNG_H 1 + +/* symbol renaming */ +#define EVP_wincng_md4() EVP_wincng_md4() +#define EVP_wincng_md5() EVP_wincng_md5() +#define EVP_wincng_sha1() EVP_wincng_sha1() +#define EVP_wincng_sha256() EVP_wincng_sha256() +#define EVP_wincng_sha384() EVP_wincng_sha384() +#define EVP_wincng_sha512() EVP_wincng_sha512() +#define EVP_wincng_des_cbc() EVP_wincng_des_cbc() +#define EVP_wincng_des_ede3_cbc() EVP_wincng_des_ede3_cbc() +#define EVP_wincng_aes_128_cbc() EVP_wincng_aes_128_cbc() +#define EVP_wincng_aes_192_cbc() EVP_wincng_aes_192_cbc() +#define EVP_wincng_aes_256_cbc() EVP_wincng_aes_256_cbc() +#define EVP_wincng_aes_128_cfb8() EVP_wincng_aes_128_cfb8() +#define EVP_wincng_aes_192_cfb8() EVP_wincng_aes_192_cfb8() +#define EVP_wincng_aes_256_cfb8() EVP_wincng_aes_256_cfb8() +#define EVP_wincng_rc4() EVP_wincng_rc4() +#define EVP_wincng_rc4_40() EVP_wincng_rc4_40() +#define EVP_wincng_rc2_40_cbc() EVP_wincng_rc2_40_cbc() +#define EVP_wincng_rc2_64_cbc() EVP_wincng_rc2_64_cbc() +#define EVP_wincng_rc2_cbc() EVP_wincng_rc2_cbc() +#define EVP_wincng_camellia_128_cbc() EVP_wincng_camellia_128_cbc() +#define EVP_wincng_camellia_192_cbc() EVP_wincng_camellia_192_cbc() +#define EVP_wincng_camellia_256_cbc() EVP_wincng_camellia_256_cbc() + +/* + * + */ + +HC_CPP_BEGIN + +const EVP_MD * hc_EVP_wincng_md4(void); +const EVP_MD * hc_EVP_wincng_md5(void); +const EVP_MD * hc_EVP_wincng_sha1(void); +const EVP_MD * hc_EVP_wincng_sha256(void); +const EVP_MD * hc_EVP_wincng_sha384(void); +const EVP_MD * hc_EVP_wincng_sha512(void); + +const EVP_CIPHER * hc_EVP_wincng_rc2_cbc(void); +const EVP_CIPHER * hc_EVP_wincng_rc2_40_cbc(void); +const EVP_CIPHER * hc_EVP_wincng_rc2_64_cbc(void); + +const EVP_CIPHER * hc_EVP_wincng_rc4(void); +const EVP_CIPHER * hc_EVP_wincng_rc4_40(void); + +const EVP_CIPHER * hc_EVP_wincng_des_cbc(void); +const EVP_CIPHER * hc_EVP_wincng_des_ede3_cbc(void); + +const EVP_CIPHER * hc_EVP_wincng_aes_128_cbc(void); +const EVP_CIPHER * hc_EVP_wincng_aes_192_cbc(void); +const EVP_CIPHER * hc_EVP_wincng_aes_256_cbc(void); + +const EVP_CIPHER * hc_EVP_wincng_aes_128_cfb8(void); +const EVP_CIPHER * hc_EVP_wincng_aes_192_cfb8(void); +const EVP_CIPHER * hc_EVP_wincng_aes_256_cfb8(void); + +void _hc_wincng_cleanup(void); + +HC_CPP_END + +#endif /* HEIM_EVP_WINCNG_H */ diff --git a/third_party/heimdal/lib/hcrypto/evp.c b/third_party/heimdal/lib/hcrypto/evp.c new file mode 100644 index 0000000..3874179 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp.c @@ -0,0 +1,1562 @@ +/* + * Copyright (c) 2006 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#define HC_DEPRECATED +#define HC_DEPRECATED_CRYPTO + +#include + +#include +#include +#include +#if defined(_WIN32) +#include +#endif +#include +#include + +#include + +#ifndef HCRYPTO_DEF_PROVIDER +# ifdef __APPLE__ +# define HCRYPTO_DEF_PROVIDER cc +# elif __sun +# define HCRYPTO_DEF_PROVIDER pkcs11_hcrypto +# elif HAVE_HCRYPTO_W_OPENSSL +# define HCRYPTO_DEF_PROVIDER ossl +# define HCRYPTO_DEF_PROVIDER_IS_OPENSSL +# else +# define HCRYPTO_DEF_PROVIDER hcrypto +# endif +#endif + +#define HC_CONCAT4(x,y,z,aa) x ## y ## z ## aa + + +#define EVP_DEF_OP(_prov,_op) HC_CONCAT4(EVP_,_prov,_,_op)() + +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) +extern int _heim_openssl_fips_enabled(void); +#endif + + +/** + * @page page_evp EVP - generic crypto interface + * + * See the library functions here: @ref hcrypto_evp + * + * @section evp_cipher EVP Cipher + * + * The use of EVP_CipherInit_ex() and EVP_Cipher() is pretty easy to + * understand forward, then EVP_CipherUpdate() and + * EVP_CipherFinal_ex() really needs an example to explain @ref + * example_evp_cipher.c . + * + * @example example_evp_cipher.c + * + * This is an example how to use EVP_CipherInit_ex(), + * EVP_CipherUpdate() and EVP_CipherFinal_ex(). + */ + +struct hc_EVP_MD_CTX { + const EVP_MD *md; + ENGINE *engine; + void *ptr; +}; + + +/** + * Return the output size of the message digest function. + * + * @param md the evp message + * + * @return size output size of the message digest function. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_size(const EVP_MD *md) +{ + return md->hash_size; +} + +/** + * Return the blocksize of the message digest function. + * + * @param md the evp message + * + * @return size size of the message digest block size + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_block_size(const EVP_MD *md) +{ + return md->block_size; +} + +/** + * Allocate a messsage digest context object. Free with + * EVP_MD_CTX_destroy(). + * + * @return a newly allocated message digest context object. + * + * @ingroup hcrypto_evp + */ + +EVP_MD_CTX * +EVP_MD_CTX_create(void) +{ + return calloc(1, sizeof(EVP_MD_CTX)); +} + +/** + * Initiate a messsage digest context object. Deallocate with + * EVP_MD_CTX_cleanup(). Please use EVP_MD_CTX_create() instead. + * + * @param ctx variable to initiate. + * + * @ingroup hcrypto_evp + */ + +void +EVP_MD_CTX_init(EVP_MD_CTX *ctx) HC_DEPRECATED +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/** + * Free a messsage digest context object. + * + * @param ctx context to free. + * + * @ingroup hcrypto_evp + */ + +void +EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + free(ctx); +} + +/** + * Free the resources used by the EVP_MD context. + * + * @param ctx the context to free the resources from. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) HC_DEPRECATED +{ + if (ctx->md && ctx->md->cleanup) { + int ret = (ctx->md->cleanup)(ctx->ptr); + if (!ret) + return ret; + } else if (ctx->md) { + memset_s(ctx->ptr, ctx->md->ctx_size, 0, ctx->md->ctx_size); + } + ctx->md = NULL; + ctx->engine = NULL; + free(ctx->ptr); + memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); + return 1; +} + +/** + * Get the EVP_MD use for a specified context. + * + * @param ctx the EVP_MD context to get the EVP_MD for. + * + * @return the EVP_MD used for the context. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_MD_CTX_md(EVP_MD_CTX *ctx) +{ + return ctx->md; +} + +/** + * Return the output size of the message digest function. + * + * @param ctx the evp message digest context + * + * @return size output size of the message digest function. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_CTX_size(EVP_MD_CTX *ctx) +{ + return EVP_MD_size(ctx->md); +} + +/** + * Return the blocksize of the message digest function. + * + * @param ctx the evp message digest context + * + * @return size size of the message digest block size + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_CTX_block_size(EVP_MD_CTX *ctx) +{ + return EVP_MD_block_size(ctx->md); +} + +/** + * Init a EVP_MD_CTX for use a specific message digest and engine. + * + * @param ctx the message digest context to init. + * @param md the message digest to use. + * @param engine the engine to use, NULL to use the default engine. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, ENGINE *engine) +{ + if (ctx->md != md || ctx->engine != engine) { + EVP_MD_CTX_cleanup(ctx); + ctx->md = md; + ctx->engine = engine; + if (md == NULL) + return 0; + + ctx->ptr = calloc(1, md->ctx_size); + if (ctx->ptr == NULL) + return 0; + } + if (ctx->md == 0) + return 0; + return (ctx->md->init)(ctx->ptr); +} + +/** + * Update the digest with some data. + * + * @param ctx the context to update + * @param data the data to update the context with + * @param size length of data + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t size) +{ + (ctx->md->update)(ctx->ptr, data, size); + return 1; +} + +/** + * Complete the message digest. + * + * @param ctx the context to complete. + * @param hash the output of the message digest function. At least + * EVP_MD_size(). + * @param size the output size of hash. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestFinal_ex(EVP_MD_CTX *ctx, void *hash, unsigned int *size) +{ + (ctx->md->final)(hash, ctx->ptr); + if (size) + *size = ctx->md->hash_size; + return 1; +} + +/** + * Do the whole EVP_MD_CTX_create(), EVP_DigestInit_ex(), + * EVP_DigestUpdate(), EVP_DigestFinal_ex(), EVP_MD_CTX_destroy() + * dance in one call. + * + * @param data the data to update the context with + * @param dsize length of data + * @param hash output data of at least EVP_MD_size() length. + * @param hsize output length of hash. + * @param md message digest to use + * @param engine engine to use, NULL for default engine. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_Digest(const void *data, size_t dsize, void *hash, unsigned int *hsize, + const EVP_MD *md, ENGINE *engine) +{ + EVP_MD_CTX *ctx; + int ret; + + ctx = EVP_MD_CTX_create(); + if (ctx == NULL) + return 0; + ret = EVP_DigestInit_ex(ctx, md, engine); + if (ret != 1) { + EVP_MD_CTX_destroy(ctx); + return ret; + } + ret = EVP_DigestUpdate(ctx, data, dsize); + if (ret != 1) { + EVP_MD_CTX_destroy(ctx); + return ret; + } + ret = EVP_DigestFinal_ex(ctx, hash, hsize); + EVP_MD_CTX_destroy(ctx); + return ret; +} + +/** + * The message digest SHA256 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha256(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha256); +} + +/** + * The message digest SHA384 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha384(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha384); +} + +/** + * The message digest SHA512 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha512(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha512); +} + +/** + * The message digest SHA1 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha1(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha1); +} + +/** + * The message digest SHA1 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha(void) HC_DEPRECATED + +{ + hcrypto_validate(); + return EVP_sha1(); +} + +/** + * The message digest MD5 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md5(void) HC_DEPRECATED_CRYPTO +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, md5); +} + +/** + * The message digest MD4 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md4(void) HC_DEPRECATED_CRYPTO +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, md4); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, md4); +} + +/* + * + */ + +static int +null_Init (void *m) +{ + return 1; +} +static int +null_Update (void *m, const void * data, size_t size) +{ + return 1; +} +static int +null_Final(void *res, void *m) +{ + return 1; +} + +/** + * The null message digest + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md_null(void) +{ + static const struct hc_evp_md null = { + 0, + 0, + 0, + (hc_evp_md_init)null_Init, + (hc_evp_md_update)null_Update, + (hc_evp_md_final)null_Final, + NULL + }; + return &null; +} + +/** + * Return the block size of the cipher. + * + * @param c cipher to get the block size from. + * + * @return the block size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_block_size(const EVP_CIPHER *c) +{ + return c->block_size; +} + +/** + * Return the key size of the cipher. + * + * @param c cipher to get the key size from. + * + * @return the key size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_key_length(const EVP_CIPHER *c) +{ + return c->key_len; +} + +/** + * Return the IV size of the cipher. + * + * @param c cipher to get the IV size from. + * + * @return the IV size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_iv_length(const EVP_CIPHER *c) +{ + return c->iv_len; +} + +/** + * Initiate a EVP_CIPHER_CTX context. Clean up with + * EVP_CIPHER_CTX_cleanup(). + * + * @param c the cipher initiate. + * + * @ingroup hcrypto_evp + */ + +void +EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *c) +{ + memset(c, 0, sizeof(*c)); +} + +/** + * Clean up the EVP_CIPHER_CTX context. + * + * @param c the cipher to clean up. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) +{ + if (c->cipher && c->cipher->cleanup) { + int ret = c->cipher->cleanup(c); + if (!ret) + return ret; + } + if (c->cipher_data) { + if (c->cipher) + memset_s(c->cipher_data, c->cipher->ctx_size, 0, c->cipher->ctx_size); + free(c->cipher_data); + c->cipher_data = NULL; + } + return 1; +} + +/** + * If the cipher type supports it, change the key length + * + * @param c the cipher context to change the key length for + * @param length new key length + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int length) +{ + if ((c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH) && length > 0) { + c->key_len = length; + return 1; + } + return 0; +} + +#if 0 +int +EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad) +{ + return 0; +} +#endif + +/** + * Return the EVP_CIPHER for a EVP_CIPHER_CTX context. + * + * @param ctx the context to get the cipher type from. + * + * @return the EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx) +{ + return ctx->cipher; +} + +/** + * Return the block size of the cipher context. + * + * @param ctx cipher context to get the block size from. + * + * @return the block size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_block_size(ctx->cipher); +} + +/** + * Return the key size of the cipher context. + * + * @param ctx cipher context to get the key size from. + * + * @return the key size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_key_length(ctx->cipher); +} + +/** + * Return the IV size of the cipher context. + * + * @param ctx cipher context to get the IV size from. + * + * @return the IV size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_iv_length(ctx->cipher); +} + +/** + * Get the flags for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the flags from + * + * @return the flags for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +unsigned long +EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) +{ + return ctx->cipher->flags; +} + +/** + * Get the mode for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the mode from + * + * @return the mode for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_MODE; +} + +/** + * Get the app data for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the app data from + * + * @return the app data for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +void * +EVP_CIPHER_CTX_get_app_data(EVP_CIPHER_CTX *ctx) +{ + return ctx->app_data; +} + +/** + * Set the app data for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to set the app data for + * @param data the app data to set for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +void +EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) +{ + ctx->app_data = data; +} + +/** + * Initiate the EVP_CIPHER_CTX context to encrypt or decrypt data. + * Clean up with EVP_CIPHER_CTX_cleanup(). + * + * @param ctx context to initiate + * @param c cipher to use. + * @param engine crypto engine to use, NULL to select default. + * @param key the crypto key to use, NULL will use the previous value. + * @param iv the IV to use, NULL will use the previous value. + * @param encp non zero will encrypt, -1 use the previous value. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *c, ENGINE *engine, + const void *key, const void *iv, int encp) +{ + ctx->buf_len = 0; + + if (encp == -1) + encp = ctx->encrypt; + else + ctx->encrypt = (encp ? 1 : 0); + + if (c && (c != ctx->cipher)) { + EVP_CIPHER_CTX_cleanup(ctx); + ctx->cipher = c; + ctx->key_len = c->key_len; + + ctx->cipher_data = calloc(1, c->ctx_size); + if (ctx->cipher_data == NULL && c->ctx_size != 0) + return 0; + + /* assume block size is a multiple of 2 */ + ctx->block_mask = EVP_CIPHER_block_size(c) - 1; + + if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) && + !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) + return 0; + + } else if (ctx->cipher == NULL) { + /* reuse of cipher, but not any cipher ever set! */ + return 0; + } + + switch (EVP_CIPHER_CTX_mode(ctx)) { + case EVP_CIPH_CBC_MODE: + + assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv)); + + if (iv) + memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + case EVP_CIPH_STREAM_CIPHER: + break; + case EVP_CIPH_CFB8_MODE: + if (iv) + memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + default: + return 0; + } + + if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) + return ctx->cipher->init(ctx, key, iv, encp); + + return 1; +} + +/** + * Encipher/decipher partial data + * + * @param ctx the cipher context. + * @param out output data from the operation. + * @param outlen output length + * @param in input data to the operation. + * @param inlen length of data. + * + * The output buffer length should at least be EVP_CIPHER_block_size() + * byte longer then the input length. + * + * See @ref evp_cipher for an example how to use this function. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, void *out, int *outlen, + void *in, size_t inlen) +{ + int ret, left, blocksize; + + *outlen = 0; + + /* + * If there in no bytes left over from the last Update and the + * input length is on a block boundary, then we can take a + * shortcut (and preformance gain) and directly encrypt the + * data. + */ + if (ctx->buf_len == 0 && inlen && (inlen & ctx->block_mask) == 0) { + ret = (*ctx->cipher->do_cipher)(ctx, out, in, inlen); + if (ret == 1) + *outlen = inlen; + else + *outlen = 0; + return ret; + } + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + left = blocksize - ctx->buf_len; + assert(left > 0); + + if (ctx->buf_len) { + /* If we can't fill one block in the buffer, save the input there */ + if (inlen < left) { + memcpy(ctx->buf + ctx->buf_len, in, inlen); + ctx->buf_len += inlen; + return 1; + } + + /* Fill the buffer and encrypt */ + memcpy(ctx->buf + ctx->buf_len, in, left); + ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); + if (ret != 1) + return ret; + + *outlen += blocksize; + inlen -= left; + in = ((unsigned char *)in) + left; + out = ((unsigned char *)out) + blocksize; + ctx->buf_len = 0; + } + + if (inlen) { + ctx->buf_len = (inlen & ctx->block_mask); + inlen &= ~ctx->block_mask; + + if (inlen) { + /* Encrypt all the whole blocks of input that we have */ + ret = (*ctx->cipher->do_cipher)(ctx, out, in, inlen); + if (ret != 1) + return ret; + } + + *outlen += inlen; + + /* Save the tail of the input, if any */ + in = ((unsigned char *)in) + inlen; + memcpy(ctx->buf, in, ctx->buf_len); + } + + return 1; +} + +/** + * Encipher/decipher final data + * + * @param ctx the cipher context. + * @param out output data from the operation. + * @param outlen output length + * + * The input length needs to be at least EVP_CIPHER_block_size() bytes + * long. + * + * See @ref evp_cipher for an example how to use this function. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, void *out, int *outlen) +{ + *outlen = 0; + + if (ctx->buf_len) { + int ret, left, blocksize; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + left = blocksize - ctx->buf_len; + assert(left > 0); + + /* zero fill local buffer */ + memset(ctx->buf + ctx->buf_len, 0, left); + ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); + if (ret != 1) + return ret; + + *outlen += blocksize; + } + + return 1; +} + +/** + * Encipher/decipher data + * + * @param ctx the cipher context. + * @param out out data from the operation. + * @param in in data to the operation. + * @param size length of data. + * + * @return bytes encrypted on success, zero on failure. + */ + +int +EVP_Cipher(EVP_CIPHER_CTX *ctx, void *out, const void *in,size_t size) +{ + return ctx->cipher->do_cipher(ctx, out, in, size); +} + +/* + * + */ + +static int +enc_null_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + return 1; +} + +static int +enc_null_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + memmove(out, in, size); + return 1; +} + +static int +enc_null_cleanup(EVP_CIPHER_CTX *ctx) +{ + return 1; +} + +/** + * The NULL cipher type, does no encryption/decryption. + * + * @return the null EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_enc_null(void) +{ + static const EVP_CIPHER enc_null = { + 0, + 0, + 0, + 0, + EVP_CIPH_CBC_MODE, + enc_null_init, + enc_null_do_cipher, + enc_null_cleanup, + 0, + NULL, + NULL, + NULL, + NULL + }; + return &enc_null; +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_cbc); +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_40_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_40_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_40_cbc); +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_64_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_64_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_64_cbc); +} + +/** + * The RC4 cipher type + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc4(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc4); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc4); +} + +/** + * The RC4-40 cipher type + * + * @return the RC4-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc4_40(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc4_40); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc4_40); +} + +/** + * The DES cipher type + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_des_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, des_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, des_cbc); +} + +/** + * The triple DES cipher type + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_des_ede3_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, des_ede3_cbc); +} + +/** + * The AES-128 cipher type + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_128_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_128_cbc); +} + +/** + * The AES-192 cipher type + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_192_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_192_cbc); +} + +/** + * The AES-256 cipher type + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_256_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_256_cbc); +} + +/** + * The AES-128 cipher type + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_128_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_128_cfb8); +} + +/** + * The AES-192 cipher type + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_192_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_192_cfb8); +} + +/** + * The AES-256 cipher type + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_256_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_256_cfb8); +} + +/** + * The Camellia-128 cipher type + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_128_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_128_cbc); +} + +/** + * The Camellia-198 cipher type + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_192_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_192_cbc); +} + +/** + * The Camellia-256 cipher type + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_256_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_256_cbc); +} + +/* + * + */ + +static const struct cipher_name { + const char *name; + const EVP_CIPHER *(*func)(void); +} cipher_name[] = { + { "des-ede3-cbc", EVP_des_ede3_cbc }, + { "aes-128-cbc", EVP_aes_128_cbc }, + { "aes-192-cbc", EVP_aes_192_cbc }, + { "aes-256-cbc", EVP_aes_256_cbc }, + { "aes-128-cfb8", EVP_aes_128_cfb8 }, + { "aes-192-cfb8", EVP_aes_192_cfb8 }, + { "aes-256-cfb8", EVP_aes_256_cfb8 }, + { "camellia-128-cbc", EVP_camellia_128_cbc }, + { "camellia-192-cbc", EVP_camellia_192_cbc }, + { "camellia-256-cbc", EVP_camellia_256_cbc } +}; + +/** + * Get the cipher type using their name. + * + * @param name the name of the cipher. + * + * @return the selected EVP_CIPHER pointer or NULL if not found. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_get_cipherbyname(const char *name) +{ + int i; + for (i = 0; i < sizeof(cipher_name)/sizeof(cipher_name[0]); i++) { + if (strcasecmp(cipher_name[i].name, name) == 0) + return (*cipher_name[i].func)(); + } + return NULL; +} + + +/* + * + */ + +#ifndef min +#define min(a,b) (((a)>(b))?(b):(a)) +#endif + +/** + * Provides a legancy string to key function, used in PEM files. + * + * New protocols should use new string to key functions like NIST + * SP56-800A or PKCS#5 v2.0 (see PKCS5_PBKDF2_HMAC_SHA1()). + * + * @param type type of cipher to use + * @param md message digest to use + * @param salt salt salt string, should be an binary 8 byte buffer. + * @param data the password/input key string. + * @param datalen length of data parameter. + * @param count iteration counter. + * @param keydata output keydata, needs to of the size EVP_CIPHER_key_length(). + * @param ivdata output ivdata, needs to of the size EVP_CIPHER_block_size(). + * + * @return the size of derived key. + * + * @ingroup hcrypto_evp + */ + +int +EVP_BytesToKey(const EVP_CIPHER *type, + const EVP_MD *md, + const void *salt, + const void *data, size_t datalen, + unsigned int count, + void *keydata, + void *ivdata) +{ + unsigned int ivlen, keylen; + int first = 0; + unsigned int mds = 0, i; + unsigned char *key = keydata; + unsigned char *iv = ivdata; + unsigned char *buf; + EVP_MD_CTX c; + + keylen = EVP_CIPHER_key_length(type); + ivlen = EVP_CIPHER_iv_length(type); + + if (data == NULL) + return keylen; + + buf = malloc(EVP_MD_size(md)); + if (buf == NULL) + return -1; + + EVP_MD_CTX_init(&c); + + first = 1; + while (1) { + EVP_DigestInit_ex(&c, md, NULL); + if (!first) + EVP_DigestUpdate(&c, buf, mds); + first = 0; + EVP_DigestUpdate(&c,data,datalen); + +#define PKCS5_SALT_LEN 8 + + if (salt) + EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN); + + EVP_DigestFinal_ex(&c, buf, &mds); + assert(mds == EVP_MD_size(md)); + + for (i = 1; i < count; i++) { + EVP_DigestInit_ex(&c, md, NULL); + EVP_DigestUpdate(&c, buf, mds); + EVP_DigestFinal_ex(&c, buf, &mds); + assert(mds == EVP_MD_size(md)); + } + + i = 0; + if (keylen) { + size_t sz = min(keylen, mds); + if (key) { + memcpy(key, buf, sz); + key += sz; + } + keylen -= sz; + i += sz; + } + if (ivlen && mds > i) { + size_t sz = min(ivlen, (mds - i)); + if (iv) { + memcpy(iv, &buf[i], sz); + iv += sz; + } + ivlen -= sz; + } + if (keylen == 0 && ivlen == 0) + break; + } + + EVP_MD_CTX_cleanup(&c); + free(buf); + + return EVP_CIPHER_key_length(type); +} + +/** + * Generate a random key for the specificed EVP_CIPHER. + * + * @param ctx EVP_CIPHER_CTX type to build the key for. + * @param key return key, must be at least EVP_CIPHER_key_length() byte long. + * + * @return 1 for success, 0 for failure. + * + * @ingroup hcrypto_core + */ + +int +EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, void *key) +{ + if (ctx->cipher->flags & EVP_CIPH_RAND_KEY) + return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key); + if (RAND_bytes(key, ctx->key_len) != 1) + return 0; + return 1; +} + +/** + * Perform a operation on a ctx + * + * @param ctx context to perform operation on. + * @param type type of operation. + * @param arg argument to operation. + * @param data addition data to operation. + + * @return 1 for success, 0 for failure. + * + * @ingroup hcrypto_core + */ + +int +EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *data) +{ + if (ctx->cipher == NULL || ctx->cipher->ctrl == NULL) + return 0; + return (*ctx->cipher->ctrl)(ctx, type, arg, data); +} + +/** + * Add all algorithms to the crypto core. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms(void) +{ + return; +} + +/** + * Add all algorithms to the crypto core using configuration file. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms_conf(void) +{ + return; +} + +/** + * Add all algorithms to the crypto core, but don't use the + * configuration file. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms_noconf(void) +{ + return; +} diff --git a/third_party/heimdal/lib/hcrypto/evp.h b/third_party/heimdal/lib/hcrypto/evp.h new file mode 100644 index 0000000..7019aba --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2005 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_H +#define HEIM_EVP_H 1 + +#include + +/* symbol renaming */ +#define EVP_CIPHER_CTX_block_size hc_EVP_CIPHER_CTX_block_size +#define EVP_CIPHER_CTX_cipher hc_EVP_CIPHER_CTX_cipher +#define EVP_CIPHER_CTX_cleanup hc_EVP_CIPHER_CTX_cleanup +#define EVP_CIPHER_CTX_flags hc_EVP_CIPHER_CTX_flags +#define EVP_CIPHER_CTX_get_app_data hc_EVP_CIPHER_CTX_get_app_data +#define EVP_CIPHER_CTX_init hc_EVP_CIPHER_CTX_init +#define EVP_CIPHER_CTX_iv_length hc_EVP_CIPHER_CTX_iv_length +#define EVP_CIPHER_CTX_key_length hc_EVP_CIPHER_CTX_key_length +#define EVP_CIPHER_CTX_mode hc_EVP_CIPHER_CTX_mode +#define EVP_CIPHER_CTX_set_app_data hc_EVP_CIPHER_CTX_set_app_data +#define EVP_CIPHER_CTX_set_key_length hc_EVP_CIPHER_CTX_set_key_length +#define EVP_CIPHER_CTX_set_padding hc_EVP_CIPHER_CTX_set_padding +#define EVP_CIPHER_block_size hc_EVP_CIPHER_block_size +#define EVP_CIPHER_iv_length hc_EVP_CIPHER_iv_length +#define EVP_CIPHER_key_length hc_EVP_CIPHER_key_length +#define EVP_Cipher hc_EVP_Cipher +#define EVP_CipherInit_ex hc_EVP_CipherInit_ex +#define EVP_CipherUpdate hc_EVP_CipherUpdate +#define EVP_CipherFinal_ex hc_EVP_CipherFinal_ex +#define EVP_Digest hc_EVP_Digest +#define EVP_DigestFinal_ex hc_EVP_DigestFinal_ex +#define EVP_DigestInit_ex hc_EVP_DigestInit_ex +#define EVP_DigestUpdate hc_EVP_DigestUpdate +#define EVP_MD_CTX_block_size hc_EVP_MD_CTX_block_size +#define EVP_MD_CTX_cleanup hc_EVP_MD_CTX_cleanup +#define EVP_MD_CTX_create hc_EVP_MD_CTX_create +#define EVP_MD_CTX_init hc_EVP_MD_CTX_init +#define EVP_MD_CTX_destroy hc_EVP_MD_CTX_destroy +#define EVP_MD_CTX_md hc_EVP_MD_CTX_md +#define EVP_MD_CTX_size hc_EVP_MD_CTX_size +#define EVP_MD_block_size hc_EVP_MD_block_size +#define EVP_MD_size hc_EVP_MD_size +#define EVP_aes_128_cbc hc_EVP_aes_128_cbc +#define EVP_aes_192_cbc hc_EVP_aes_192_cbc +#define EVP_aes_256_cbc hc_EVP_aes_256_cbc +#define EVP_aes_128_cfb8 hc_EVP_aes_128_cfb8 +#define EVP_aes_192_cfb8 hc_EVP_aes_192_cfb8 +#define EVP_aes_256_cfb8 hc_EVP_aes_256_cfb8 + +#define EVP_des_cbc hc_EVP_des_cbc +#define EVP_des_ede3_cbc hc_EVP_des_ede3_cbc +#define EVP_enc_null hc_EVP_enc_null +#define EVP_md4 hc_EVP_md4 +#define EVP_md5 hc_EVP_md5 +#define EVP_md_null hc_EVP_md_null +#define EVP_rc2_40_cbc hc_EVP_rc2_40_cbc +#define EVP_rc2_64_cbc hc_EVP_rc2_64_cbc +#define EVP_rc2_cbc hc_EVP_rc2_cbc +#define EVP_rc4 hc_EVP_rc4 +#define EVP_rc4_40 hc_EVP_rc4_40 +#define EVP_camellia_128_cbc hc_EVP_camellia_128_cbc +#define EVP_camellia_192_cbc hc_EVP_camellia_192_cbc +#define EVP_camellia_256_cbc hc_EVP_camellia_256_cbc +#define EVP_sha hc_EVP_sha +#define EVP_sha1 hc_EVP_sha1 +#define EVP_sha256 hc_EVP_sha256 +#define EVP_sha384 hc_EVP_sha384 +#define EVP_sha512 hc_EVP_sha512 +#define PKCS5_PBKDF2_HMAC hc_PKCS5_PBKDF2_HMAC +#define PKCS5_PBKDF2_HMAC_SHA1 hc_PKCS5_PBKDF2_HMAC_SHA1 +#define EVP_BytesToKey hc_EVP_BytesToKey +#define EVP_get_cipherbyname hc_EVP_get_cipherbyname +#define OpenSSL_add_all_algorithms hc_OpenSSL_add_all_algorithms +#define OpenSSL_add_all_algorithms_conf hc_OpenSSL_add_all_algorithms_conf +#define OpenSSL_add_all_algorithms_noconf hc_OpenSSL_add_all_algorithms_noconf +#define EVP_CIPHER_CTX_ctrl hc_EVP_CIPHER_CTX_ctrl +#define EVP_CIPHER_CTX_rand_key hc_EVP_CIPHER_CTX_rand_key +#define hcrypto_validate hc_hcrypto_validate + +/* Type name renaming */ +#define EVP_MD_CTX hc_EVP_MD_CTX +#define EVP_PKEY hc_EVP_PKEY +#define EVP_MD hc_EVP_MD +#define EVP_CIPHER hc_EVP_CIPHER +#define EVP_CIPHER_CTX hc_EVP_CIPHER_CTX + +/* Constant renaming */ +#define EVP_CIPH_STREAM_CIPHER hc_EVP_CIPH_STREAM_CIPHER +#define EVP_CIPH_CBC_MODE hc_EVP_CIPH_CBC_MODE +#define EVP_CIPH_CFB8_MODE hc_EVP_CIPH_CFB8_MODE +#define EVP_CIPH_MODE hc_EVP_CIPH_MODE +#define EVP_CIPH_CTRL_INIT hc_EVP_CIPH_CTRL_INIT + +#define EVP_CIPH_VARIABLE_LENGTH hc_EVP_CIPH_VARIABLE_LENGTH +#define EVP_CIPH_ALWAYS_CALL_INIT hc_EVP_CIPH_ALWAYS_CALL_INIT +#define EVP_CIPH_RAND_KEY hc_EVP_CIPH_RAND_KEY + +#define EVP_CTRL_INIT hc_EVP_CTRL_INIT + + +/* + * + */ + +typedef struct hc_EVP_MD_CTX EVP_MD_CTX; +typedef struct hc_evp_pkey EVP_PKEY; +typedef struct hc_evp_md EVP_MD; +typedef struct hc_CIPHER EVP_CIPHER; +typedef struct hc_CIPHER_CTX EVP_CIPHER_CTX; + +#define EVP_MAX_IV_LENGTH 16 +#define EVP_MAX_BLOCK_LENGTH 32 + +#define EVP_MAX_MD_SIZE 64 + +struct hc_CIPHER { + int nid; + int block_size; + int key_len; + int iv_len; + unsigned long flags; + /* The lowest 3 bits is used as integer field for the mode the + * cipher is used in (use EVP_CIPHER.._mode() to extract the + * mode). The rest of the flag field is a bitfield. + */ +#define hc_EVP_CIPH_STREAM_CIPHER 0 +#define hc_EVP_CIPH_CBC_MODE 2 +#define hc_EVP_CIPH_CFB8_MODE 4 +#define hc_EVP_CIPH_MODE 0x7 +#define hc_EVP_CIPH_CTRL_INIT 0x40 + +#define hc_EVP_CTRL_INIT 0x0 + +#define hc_EVP_CIPH_VARIABLE_LENGTH 0x008 /* variable key length */ +#define hc_EVP_CIPH_ALWAYS_CALL_INIT 0x020 /* backend maintains own cipherstate */ +#define hc_EVP_CIPH_RAND_KEY 0x200 + + int (*init)(EVP_CIPHER_CTX*,const unsigned char*,const unsigned char*,int); + int (*do_cipher)(EVP_CIPHER_CTX *, unsigned char *, + const unsigned char *, unsigned int); + int (*cleanup)(EVP_CIPHER_CTX *); + int ctx_size; + int (*set_asn1_parameters)(void); + int (*get_asn1_parameters)(void); + int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); +#define EVP_CTRL_RAND_KEY 0x6 + + void *app_data; +}; + +struct hc_CIPHER_CTX { + const EVP_CIPHER *cipher; + ENGINE *engine; + int encrypt; + int buf_len; /* bytes stored in buf for EVP_CipherUpdate */ + unsigned char oiv[EVP_MAX_IV_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char buf[EVP_MAX_BLOCK_LENGTH]; + int num; + void *app_data; + int key_len; + unsigned long flags; + void *cipher_data; + int final_used; + unsigned block_mask; + unsigned char final[EVP_MAX_BLOCK_LENGTH]; +}; + +/* + * LIES. It's not an EVP_MD_CTX that gets passed to these functions + * here in hcrypto, but an object of ctx_size. + */ +typedef int (*hc_evp_md_init)(EVP_MD_CTX *); +typedef int (*hc_evp_md_update)(EVP_MD_CTX *,const void *, size_t); +typedef int (*hc_evp_md_final)(void *, EVP_MD_CTX *); +typedef int (*hc_evp_md_cleanup)(EVP_MD_CTX *); + +struct hc_evp_md { + int hash_size; + int block_size; + int ctx_size; + hc_evp_md_init init; + hc_evp_md_update update; + hc_evp_md_final final; + hc_evp_md_cleanup cleanup; +}; + +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(x) +#endif + +#ifndef HC_DEPRECATED +#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) +#define HC_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) && (_MSC_VER>1200) +#define HC_DEPRECATED __declspec(deprecated) +#else +#define HC_DEPRECATED +#endif +#endif + +#ifndef HC_DEPRECATED_CRYPTO +#define HC_DEPRECATED_CRYPTO HC_DEPRECATED +#endif + +#ifdef __cplusplus +#define HC_CPP_BEGIN extern "C" { +#define HC_CPP_END } +#else +#define HC_CPP_BEGIN +#define HC_CPP_END +#endif + +HC_CPP_BEGIN + +/* + * Avaible crypto algs + */ + +const EVP_MD *EVP_md_null(void); +HC_DEPRECATED_CRYPTO const EVP_MD *EVP_md4(void); +HC_DEPRECATED_CRYPTO const EVP_MD *EVP_md5(void); +const EVP_MD *EVP_sha(void); +const EVP_MD *EVP_sha1(void); +const EVP_MD *EVP_sha256(void); +const EVP_MD *EVP_sha384(void); +const EVP_MD *EVP_sha512(void); + +const EVP_CIPHER * EVP_aes_128_cbc(void); +const EVP_CIPHER * EVP_aes_192_cbc(void); +const EVP_CIPHER * EVP_aes_256_cbc(void); +const EVP_CIPHER * EVP_aes_128_cfb8(void); +const EVP_CIPHER * EVP_aes_192_cfb8(void); +const EVP_CIPHER * EVP_aes_256_cfb8(void); +HC_DEPRECATED_CRYPTO const EVP_CIPHER * EVP_des_cbc(void); +const EVP_CIPHER * EVP_des_ede3_cbc(void); +const EVP_CIPHER * EVP_enc_null(void); +HC_DEPRECATED_CRYPTO const EVP_CIPHER * EVP_rc2_40_cbc(void); +HC_DEPRECATED_CRYPTO const EVP_CIPHER * EVP_rc2_64_cbc(void); +HC_DEPRECATED_CRYPTO const EVP_CIPHER * EVP_rc2_cbc(void); +const EVP_CIPHER * EVP_rc4(void); +HC_DEPRECATED_CRYPTO const EVP_CIPHER * EVP_rc4_40(void); +const EVP_CIPHER * EVP_camellia_128_cbc(void); +const EVP_CIPHER * EVP_camellia_192_cbc(void); +const EVP_CIPHER * EVP_camellia_256_cbc(void); + +size_t EVP_MD_size(const EVP_MD *); +size_t EVP_MD_block_size(const EVP_MD *); + +const EVP_MD * + EVP_MD_CTX_md(EVP_MD_CTX *); +size_t EVP_MD_CTX_size(EVP_MD_CTX *); +size_t EVP_MD_CTX_block_size(EVP_MD_CTX *); + +EVP_MD_CTX * + EVP_MD_CTX_create(void); +void HC_DEPRECATED EVP_MD_CTX_init(EVP_MD_CTX *); +void EVP_MD_CTX_destroy(EVP_MD_CTX *); +int HC_DEPRECATED EVP_MD_CTX_cleanup(EVP_MD_CTX *); + +int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); +int EVP_DigestUpdate(EVP_MD_CTX *,const void *, size_t); +int EVP_DigestFinal_ex(EVP_MD_CTX *, void *, unsigned int *); +int EVP_Digest(const void *, size_t, void *, unsigned int *, + const EVP_MD *, ENGINE *); +/* + * + */ + +const EVP_CIPHER * + EVP_get_cipherbyname(const char *); + +size_t EVP_CIPHER_block_size(const EVP_CIPHER *); +size_t EVP_CIPHER_key_length(const EVP_CIPHER *); +size_t EVP_CIPHER_iv_length(const EVP_CIPHER *); + +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); +int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int); +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); +unsigned long + EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *); +int EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *); + +const EVP_CIPHER * + EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *); +size_t EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *); +size_t EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *); +size_t EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *); +void * EVP_CIPHER_CTX_get_app_data(EVP_CIPHER_CTX *); +void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *, void *); + +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); +int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *, void *); + + +int EVP_CipherInit_ex(EVP_CIPHER_CTX *,const EVP_CIPHER *, ENGINE *, + const void *, const void *, int); +int EVP_CipherUpdate(EVP_CIPHER_CTX *, void *, int *, void *, size_t); +int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, void *, int *); + +int EVP_Cipher(EVP_CIPHER_CTX *,void *,const void *,size_t); + +int PKCS5_PBKDF2_HMAC(const void *, size_t, const void *, size_t, + unsigned long, const EVP_MD *, size_t, void *); + +int PKCS5_PBKDF2_HMAC_SHA1(const void *, size_t, const void *, size_t, + unsigned long, size_t, void *); + +int EVP_BytesToKey(const EVP_CIPHER *, const EVP_MD *, + const void *, const void *, size_t, + unsigned int, void *, void *); + + +/* + * + */ + +void OpenSSL_add_all_algorithms(void); +void OpenSSL_add_all_algorithms_conf(void); +void OpenSSL_add_all_algorithms_noconf(void); + +void +hcrypto_validate(void); + +HC_CPP_END + +#endif /* HEIM_EVP_H */ diff --git a/third_party/heimdal/lib/hcrypto/example_evp_cipher.c b/third_party/heimdal/lib/hcrypto/example_evp_cipher.c new file mode 100644 index 0000000..3bf76b9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/example_evp_cipher.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include /* should really be stdint.h */ +#include +#include +#ifdef __APPLE__ +#include +#endif +#ifdef _WIN32 +#include +#endif + +#include +#include + +/* key and initial vector */ +static char key[16] = + "\xaa\xbb\x45\xd4\xaa\xbb\x45\xd4" + "\xaa\xbb\x45\xd4\xaa\xbb\x45\xd4"; +static char ivec[16] = + "\xaa\xbb\x45\xd4\xaa\xbb\x45\xd4" + "\xaa\xbb\x45\xd4\xaa\xbb\x45\xd4"; + +static void +usage(int exit_code) __attribute__((noreturn)); + +static void +usage(int exit_code) +{ + printf("usage: %s in out [pkcs11 | cc | w32]\n", getprogname()); + exit(exit_code); +} + + +int +main(int argc, char **argv) +{ + int encryptp = 1; + const char *ifn = NULL, *ofn = NULL; + FILE *in, *out; + void *ibuf, *obuf; + int ilen, olen; + size_t block_size = 0; + const EVP_CIPHER *c = EVP_aes_128_cbc(); + EVP_CIPHER_CTX ctx; + int ret; + + setprogname(argv[0]); + + if (argc == 2) { + if (strcmp(argv[1], "--version") == 0) { + printf("version"); + exit(0); + } + if (strcmp(argv[1], "--help") == 0) + usage(0); + usage(1); + } else if (argc == 4 || argc == 5) { + block_size = atoi(argv[1]); + if (block_size == 0) + errx(1, "invalid blocksize %s", argv[1]); + ifn = argv[2]; + ofn = argv[3]; + if (argc == 5) { + if (strcmp(argv[4], "pkcs11") == 0) + c = hc_EVP_pkcs11_aes_128_cbc(); +#ifdef __APPLE__ + else if (strcmp(argv[4], "cc") == 0) + c = hc_EVP_cc_aes_128_cbc(); +#endif +#ifdef _WIN32 + else if (strcmp(argv[4], "w32") == 0) + c = hc_EVP_w32crypto_aes_128_cbc(); +#endif + else + usage(1); + } + } else + usage(1); + + in = fopen(ifn, "r"); + if (in == NULL) + errx(1, "failed to open input file"); + out = fopen(ofn, "w+"); + if (out == NULL) + errx(1, "failed to open output file"); + + /* Check that key and ivec are long enough */ + assert(EVP_CIPHER_key_length(c) <= sizeof(key)); + assert(EVP_CIPHER_iv_length(c) <= sizeof(ivec)); + + /* + * Allocate buffer, the output buffer is at least + * EVP_CIPHER_block_size() longer + */ + ibuf = malloc(block_size); + obuf = malloc(block_size + EVP_CIPHER_block_size(c)); + + /* + * Init the memory used for EVP_CIPHER_CTX and set the key and + * ivec. + */ + EVP_CIPHER_CTX_init(&ctx); + EVP_CipherInit_ex(&ctx, c, NULL, key, ivec, encryptp); + + /* read in buffer */ + while ((ilen = fread(ibuf, 1, block_size, in)) > 0) { + /* encrypto/decrypt */ + ret = EVP_CipherUpdate(&ctx, obuf, &olen, ibuf, ilen); + if (ret != 1) { + EVP_CIPHER_CTX_cleanup(&ctx); + errx(1, "EVP_CipherUpdate failed"); + } + /* write out to output file */ + fwrite(obuf, 1, olen, out); + } + /* done reading */ + fclose(in); + + /* clear up any last bytes left in the output buffer */ + ret = EVP_CipherFinal_ex(&ctx, obuf, &olen); + EVP_CIPHER_CTX_cleanup(&ctx); + if (ret != 1) + errx(1, "EVP_CipherFinal_ex failed"); + + /* write the last bytes out and close */ + fwrite(obuf, 1, olen, out); + fclose(out); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/gen-des.pl b/third_party/heimdal/lib/hcrypto/gen-des.pl new file mode 100644 index 0000000..a71a682 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/gen-des.pl @@ -0,0 +1,217 @@ +#!/usr/pkg/bin/perl +# +# $Id$ + +use strict; + +print "/* GENERATE FILE from gen-des.pl, do not edit */\n\n"; + +my $gen = 1; + +sub gen_pattern +{ + my $n = shift; + my $r = shift; + my $a = shift; + my $o = shift; + my $s = shift; + print "/* $n bit pattern "; + foreach my $k (@$a) { + print "$k "; + } + print "*/\n"; + print "static int $n\[", $r + 1, "\] = {\n "; + foreach my $i (0..$r) { + my $j = 0; + my $b = 1; + foreach my $k (reverse @$a) { + if ($i & $b) { + $j |= ($s >>($k - $o - 1)); + } + $b = $b << 1; + } + printf "0x%08x", $j; + print ", " if ($i != $r); + if (($i % 4) == 3) { + print "\n"; + print " " if ($i != $r); + } + } + print "};\n"; +} + +if ($gen) { + gen_pattern("pc1_c_3", 7, [ 5, 13, 21 ], 0, 0x1000000); + gen_pattern("pc1_c_4", 15, [ 1, 9, 17, 25 ], 0, 0x1000000); + gen_pattern("pc1_d_3", 7, [ 49, 41, 33 ], 32, 0x1000000); + gen_pattern("pc1_d_4", 15, [ 57, 53, 45, 37 ], 32, 0x1000000); + + gen_pattern("pc2_c_1", 63, [ 5, 24, 7, 16, 6, 10 ], 0, 0x800000); + gen_pattern("pc2_c_2", 63, [ 20, 18, 12, 3, 15, 23 ], 0, 0x800000); + gen_pattern("pc2_c_3", 63, [ 1, 9, 19, 2, 14, 22 ], 0, 0x800000); + gen_pattern("pc2_c_4", 63, [ 11, 13, 4, 17, 21, 8 ], 0, 0x800000); + + gen_pattern("pc2_d_1", 63, [ 51, 35, 31, 52, 39, 45 ], 28, 0x800000); + gen_pattern("pc2_d_2", 63, [ 50, 32, 43, 36, 29, 48 ], 28, 0x800000); + gen_pattern("pc2_d_3", 63, [ 41, 38, 47, 33, 40, 42 ], 28, 0x800000); + gen_pattern("pc2_d_4", 63, [ 49, 37, 30, 46, 34, 44 ], 28, 0x800000); +} + +sub +pbox_mutation +{ + my $n = shift; + my $res = 0; + + my @pbox = ( + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 + ); + + foreach my $i (0..31) { + if ($n & (1 << ($pbox[$i] - 1))) { +# print "$i ", ($pbox[$i] - 1), "\n"; + $res |= 1 << $i; + } + } + + return $res; +} + + +my @S1 = ( + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + ); +my @S2 = ( + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + ); +my @S3 = ( + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + ); +my @S4 = ( + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + ); +my @S5 = ( + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + ); +my @S6 = ( + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + ); +my @S7 = ( + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + ); + +my @S8 = ( + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, + ); + +my @SBox = ( \@S1, \@S2, \@S3, \@S4, \@S5, \@S6, \@S7, \@S8 ); + +sub +one_num_in_one_sbox +{ + my $i = shift; + my $n = shift; + my $r = shift; + + my $index = (($n & 1) << 4) | (($n & 0x20)) | + (($n >> 1) & 0x1) << 0 | + (($n >> 2) & 0x1) << 1 | + (($n >> 3) & 0x1) << 2 | + (($n >> 4) & 0x1) << 3; + + die "argh" if ($index > 63 || $index < 0); + + my $S = $SBox[$i - 1]; + my $val = $$S[$index]; + + my $res = $val << (($i - 1) * 4); + + my $p = &pbox_mutation($res); + + print " $r "; + +# $p = ($p >> $r) | ($p << (32 - $r - 1)); + + printf "0x%08x", $p; + print ", " if ($n != 63 or 1); + if (($n % 4) == 3) { + print " /* $i */" if ($n == 3); + print "\n"; + print "\t" if ($n != 63); + } +} + +sub +one_sbox +{ + my $i = shift; + my $s = 0; + +# print "static uint32_t sbox". $i ."[] = {\n\t"; + print "\t"; + foreach my $n (0..63) { + one_num_in_one_sbox($i, $n, $s); + } + print "\n"; +# print "};\n"; +} + +if ($gen and 0) { + foreach my $sbox (7, 1, 3, 5, 4, 6, 8, 2) { + one_sbox($sbox, 1); + } +} + +#my $num = 1; +#printf "pbox: %d -> 0x%08x\n", $num, pbox_mutation($num); +#$num = 0xc000000; +#printf "pbox: 0x%08x -> 0x%08x\n", $num, pbox_mutation($num); + +print "static unsigned char odd_parity[256] = { \n"; +foreach my $i (0..255) { + my $num = 0; + foreach my $b (1..7) { + $num++ if (($i >> $b) & 1); + } + my $t; + if (($num & 1) == 0) { + $t = $i | 1; + } else { + $t = 0xfe & $i; + } + printf "%3d,", $t; + printf "\n" if (($i % 16) == 15); + +}; +print " };\n"; diff --git a/third_party/heimdal/lib/hcrypto/hash.h b/third_party/heimdal/lib/hcrypto/hash.h new file mode 100644 index 0000000..0190814 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/hash.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* $Id$ */ + +/* stuff in common between md4, md5, and sha1 */ + +#ifndef __hash_h__ +#define __hash_h__ + +#ifdef KRB5 +#include +#endif + +#ifndef min +#define min(a,b) (((a)>(b))?(b):(a)) +#endif + +/* Vector Crays doesn't have a good 32-bit type, or more precisely, + int32_t as defined by isn't 32 bits, and we don't + want to depend in being able to redefine this type. To cope with + this we have to clamp the result in some places to [0,2^32); no + need to do this on other machines. Did I say this was a mess? + */ + +#ifdef _CRAY +#define CRAYFIX(X) ((X) & 0xffffffff) +#else +#define CRAYFIX(X) (X) +#endif + +static inline uint32_t +cshift (uint32_t x, unsigned int n) +{ + x = CRAYFIX(x); + return CRAYFIX((x << n) | (x >> (32 - n))); +} + +static inline uint64_t +cshift64 (uint64_t x, unsigned int n) +{ + return ((uint64_t)x << (uint64_t)n) | ((uint64_t)x >> ((uint64_t)64 - (uint64_t)n)); +} + +#endif /* __hash_h__ */ diff --git a/third_party/heimdal/lib/hcrypto/hmac.c b/third_party/heimdal/lib/hcrypto/hmac.c new file mode 100644 index 0000000..b646d56 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/hmac.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +void +HMAC_CTX_init(HMAC_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +void +HMAC_CTX_cleanup(HMAC_CTX *ctx) +{ + if (ctx->buf) { + memset_s(ctx->buf, ctx->key_length, 0, ctx->key_length); + free(ctx->buf); + ctx->buf = NULL; + } + if (ctx->opad) { + memset_s(ctx->opad, EVP_MD_block_size(ctx->md), 0, EVP_MD_block_size(ctx->md)); + free(ctx->opad); + ctx->opad = NULL; + } + if (ctx->ipad) { + memset_s(ctx->ipad, EVP_MD_block_size(ctx->md), 0, EVP_MD_block_size(ctx->md)); + free(ctx->ipad); + ctx->ipad = NULL; + } + if (ctx->ctx) { + EVP_MD_CTX_destroy(ctx->ctx); + ctx->ctx = NULL; + } +} + +HMAC_CTX * +HMAC_CTX_new(void) +{ + return calloc(1, sizeof(HMAC_CTX)); +} + +void +HMAC_CTX_free(HMAC_CTX *ctx) +{ + HMAC_CTX_cleanup(ctx); + free(ctx); +} + +size_t +HMAC_size(const HMAC_CTX *ctx) +{ + return EVP_MD_size(ctx->md); +} + +int +HMAC_Init_ex(HMAC_CTX *ctx, + const void *key, + size_t keylen, + const EVP_MD *md, + ENGINE *engine) +{ + unsigned char *p; + size_t i, blockSize; + + blockSize = EVP_MD_block_size(md); + + if (ctx->md != md) { + if (ctx->md != NULL) + HMAC_CTX_cleanup(ctx); + + ctx->md = md; + ctx->key_length = EVP_MD_size(ctx->md); + ctx->opad = NULL; + ctx->ipad = NULL; + ctx->ctx = NULL; + ctx->buf = malloc(ctx->key_length); + if (ctx->buf) + ctx->opad = malloc(blockSize); + if (ctx->opad) + ctx->ipad = malloc(blockSize); + if (ctx->ipad) + ctx->ctx = EVP_MD_CTX_create(); + } + /* We do this check here to quiet scan-build */ + if (!ctx->buf || !ctx->opad || !ctx->ipad || !ctx->ctx) + return 0; +#if 0 + ctx->engine = engine; +#endif + + if (keylen > blockSize) { + if (EVP_Digest(key, keylen, ctx->buf, NULL, ctx->md, engine) == 0) + return 0; + key = ctx->buf; + keylen = EVP_MD_size(ctx->md); + } + + memset(ctx->ipad, 0x36, blockSize); + memset(ctx->opad, 0x5c, blockSize); + + for (i = 0, p = ctx->ipad; i < keylen; i++) + p[i] ^= ((const unsigned char *)key)[i]; + for (i = 0, p = ctx->opad; i < keylen; i++) + p[i] ^= ((const unsigned char *)key)[i]; + + if (EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine) == 0) + return 0; + EVP_DigestUpdate(ctx->ctx, ctx->ipad, EVP_MD_block_size(ctx->md)); + return 1; +} + +void +HMAC_Update(HMAC_CTX *ctx, const void *data, size_t len) +{ + EVP_DigestUpdate(ctx->ctx, data, len); +} + +void +HMAC_Final(HMAC_CTX *ctx, void *md, unsigned int *len) +{ + EVP_DigestFinal_ex(ctx->ctx, ctx->buf, NULL); + + EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine); + EVP_DigestUpdate(ctx->ctx, ctx->opad, EVP_MD_block_size(ctx->md)); + EVP_DigestUpdate(ctx->ctx, ctx->buf, ctx->key_length); + EVP_DigestFinal_ex(ctx->ctx, md, len); +} + +void * +HMAC(const EVP_MD *md, + const void *key, size_t key_size, + const void *data, size_t data_size, + void *hash, unsigned int *hash_len) +{ + HMAC_CTX ctx; + + HMAC_CTX_init(&ctx); + if (HMAC_Init_ex(&ctx, key, key_size, md, NULL) == 0) { + HMAC_CTX_cleanup(&ctx); + return NULL; + } + HMAC_Update(&ctx, data, data_size); + HMAC_Final(&ctx, hash, hash_len); + HMAC_CTX_cleanup(&ctx); + return hash; +} diff --git a/third_party/heimdal/lib/hcrypto/hmac.h b/third_party/heimdal/lib/hcrypto/hmac.h new file mode 100644 index 0000000..cc99c87 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/hmac.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_HMAC_H +#define HEIM_HMAC_H 1 + +#include + +/* symbol renaming */ +#define HMAC_CTX_new hc_HMAC_CTX_new +#define HMAC_CTX_free hc_HMAC_CTX_free +#define HMAC_CTX_init hc_HMAC_CTX_init +#define HMAC_CTX_cleanup hc_HMAC_CTX_cleanup +#define HMAC_size hc_HMAC_size +#define HMAC_Init_ex hc_HMAC_Init_ex +#define HMAC_Update hc_HMAC_Update +#define HMAC_Final hc_HMAC_Final +#define HMAC hc_HMAC + +/* + * + */ + +#define HMAC_MAX_MD_CBLOCK 64 + +typedef struct hc_HMAC_CTX HMAC_CTX; + +struct hc_HMAC_CTX { + const EVP_MD *md; + ENGINE *engine; + EVP_MD_CTX *ctx; + size_t key_length; + void *opad; + void *ipad; + void *buf; +}; + + +void HMAC_CTX_init(HMAC_CTX *); +void HMAC_CTX_cleanup(HMAC_CTX *ctx); +HMAC_CTX *HMAC_CTX_new(void); +void HMAC_CTX_free(HMAC_CTX *ctx); + +size_t HMAC_size(const HMAC_CTX *ctx); + +int HMAC_Init_ex(HMAC_CTX *, const void *, size_t, + const EVP_MD *, ENGINE *); +void HMAC_Update(HMAC_CTX *ctx, const void *data, size_t len); +void HMAC_Final(HMAC_CTX *ctx, void *md, unsigned int *len); + +void * HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, + const void *data, size_t n, void *md, unsigned int *md_len); + +#endif /* HEIM_HMAC_H */ diff --git a/third_party/heimdal/lib/hcrypto/libhcrypto-exports.def b/third_party/heimdal/lib/hcrypto/libhcrypto-exports.def new file mode 100644 index 0000000..b1e2d34 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libhcrypto-exports.def @@ -0,0 +1,345 @@ +EXPORTS + hc_AES_cbc_encrypt + hc_AES_cfb8_encrypt + hc_AES_decrypt + hc_AES_decrypt_key + hc_BN_CTX_end + hc_BN_CTX_free + hc_BN_CTX_get + hc_BN_CTX_new + hc_BN_CTX_start + hc_AES_encrypt + hc_AES_set_encrypt_key + hc_BN_GENCB_call + hc_BN_GENCB_set + hc_BN_bin2bn + hc_BN_bn2bin + hc_BN_bn2hex + hc_BN_clear + hc_BN_clear_bit + hc_BN_clear_free + hc_BN_cmp + hc_BN_dup + hc_BN_free + hc_BN_get_word + hc_BN_hex2bn + hc_BN_is_bit_set + hc_BN_is_negative + hc_BN_new + hc_BN_num_bits + hc_BN_num_bytes + hc_BN_rand + hc_BN_set_bit + hc_BN_set_negative + hc_BN_set_word + hc_BN_uadd + hc_DES_cbc_cksum + hc_DES_cbc_encrypt + hc_DES_cfb64_encrypt + hc_DES_check_key_parity + hc_DES_ecb3_encrypt + hc_DES_ecb_encrypt + hc_DES_ede3_cbc_encrypt + hc_DES_encrypt + hc_DES_generate_random_block + hc_DES_init_random_number_generator + hc_DES_is_weak_key + hc_DES_key_sched +;! hc_DES_mem_rand8 + hc_DES_new_random_key + hc_DES_pcbc_encrypt + hc_DES_rand_data + hc_DES_rand_data_key + hc_DES_random_key + hc_DES_read_password + hc_DES_set_key + hc_DES_set_key_checked + hc_DES_set_key_unchecked + hc_DES_set_odd_parity + hc_DES_set_random_generator_seed + hc_DES_set_sequence_number + hc_DES_string_to_key + hc_DH_check_pubkey + hc_DH_compute_key + hc_DH_free + hc_DH_generate_key + hc_DH_generate_parameters_ex + hc_DH_get_default_method + hc_DH_get_ex_data + hc_DH_ltm_method +;! hc_DH_gmp_method + hc_DH_new + hc_DH_new_method + hc_DH_null_method + hc_DH_set_default_method + hc_DH_set_ex_data + hc_DH_set_method + hc_DH_size + hc_DH_up_ref + hc_DSA_free + hc_DSA_get_default_method + hc_DSA_new + hc_DSA_null_method + hc_DSA_set_default_method + hc_DSA_up_ref + hc_DSA_verify + hc_ENGINE_add_conf_module + hc_ENGINE_by_dso + hc_ENGINE_by_id + hc_ENGINE_finish + hc_ENGINE_free + hc_ENGINE_get_DH + hc_ENGINE_get_RAND + hc_ENGINE_get_RSA + hc_ENGINE_get_default_DH + hc_ENGINE_get_default_RSA + hc_ENGINE_get_id + hc_ENGINE_get_name + hc_ENGINE_load_builtin_engines + hc_ENGINE_new + hc_ENGINE_set_DH + hc_ENGINE_set_RSA + hc_ENGINE_set_default_DH + hc_ENGINE_set_default_RSA + hc_ENGINE_set_destroy_function + hc_ENGINE_set_id + hc_ENGINE_set_name + hc_ENGINE_up_ref + hc_EVP_BytesToKey + hc_EVP_CIPHER_CTX_block_size + hc_EVP_CIPHER_CTX_cipher + hc_EVP_CIPHER_CTX_cleanup + hc_EVP_CIPHER_CTX_flags + hc_EVP_CIPHER_CTX_get_app_data + hc_EVP_CIPHER_CTX_init + hc_EVP_CIPHER_CTX_iv_length + hc_EVP_CIPHER_CTX_key_length + hc_EVP_CIPHER_CTX_mode + hc_EVP_CIPHER_CTX_set_app_data + hc_EVP_CIPHER_block_size + hc_EVP_CIPHER_iv_length + hc_EVP_CIPHER_key_length + hc_EVP_Cipher + hc_EVP_CipherInit_ex + hc_EVP_Digest + hc_EVP_DigestFinal_ex + hc_EVP_DigestInit_ex + hc_EVP_DigestUpdate + hc_EVP_MD_CTX_block_size + hc_EVP_MD_CTX_cleanup + hc_EVP_MD_CTX_create + hc_EVP_MD_CTX_destroy + hc_EVP_MD_CTX_init + hc_EVP_MD_CTX_md + hc_EVP_MD_CTX_size + hc_EVP_MD_block_size + hc_EVP_MD_size + hc_EVP_aes_128_cbc + hc_EVP_aes_128_cfb8 + hc_EVP_aes_192_cbc + hc_EVP_aes_192_cfb8 + hc_EVP_aes_256_cbc + hc_EVP_aes_256_cfb8 + hc_EVP_des_cbc + hc_EVP_des_ede3_cbc + hc_EVP_camellia_128_cbc + hc_EVP_camellia_192_cbc + hc_EVP_camellia_256_cbc + hc_EVP_enc_null + hc_EVP_get_cipherbyname + hc_EVP_md4 + hc_EVP_md5 + hc_EVP_md_null + hc_EVP_rc2_40_cbc + hc_EVP_rc2_64_cbc + hc_EVP_rc2_cbc + hc_EVP_rc4 + hc_EVP_rc4_40 + hc_EVP_sha + hc_EVP_sha1 + hc_EVP_sha256 + hc_EVP_sha384 + hc_EVP_sha512 + +;! hc_EVP_cc_md4 +;! hc_EVP_cc_md5 +;! hc_EVP_cc_sha1 +;! hc_EVP_cc_sha256 +;! hc_EVP_cc_sha384 +;! hc_EVP_cc_sha512 +;! hc_EVP_cc_des_ede3_cbc +;! hc_EVP_cc_aes_128_cbc +;! hc_EVP_cc_aes_192_cbc +;! hc_EVP_cc_aes_256_cbc +;! hc_EVP_cc_aes_128_cfb8 +;! hc_EVP_cc_aes_192_cfb8 +;! hc_EVP_cc_aes_256_cfb8 + + hc_EVP_ossl_md4 + hc_EVP_ossl_md5 + hc_EVP_ossl_sha1 + hc_EVP_ossl_sha256 + hc_EVP_ossl_sha384 + hc_EVP_ossl_sha512 + hc_EVP_ossl_des_ede3_cbc + hc_EVP_ossl_aes_128_cbc + hc_EVP_ossl_aes_192_cbc + hc_EVP_ossl_aes_256_cbc + hc_EVP_ossl_aes_128_cfb8 + hc_EVP_ossl_aes_192_cfb8 + hc_EVP_ossl_aes_256_cfb8 + hc_EVP_ossl_rc2_cbc + hc_EVP_ossl_rc2_40_cbc + hc_EVP_ossl_rc4 + hc_EVP_ossl_rc4_40 + + hc_EVP_pkcs11_md4 + hc_EVP_pkcs11_md5 + hc_EVP_pkcs11_sha1 + hc_EVP_pkcs11_sha256 + hc_EVP_pkcs11_des_ede3_cbc + hc_EVP_pkcs11_aes_128_cbc + hc_EVP_pkcs11_aes_192_cbc + hc_EVP_pkcs11_aes_256_cbc + hc_EVP_pkcs11_aes_128_cfb8 + hc_EVP_pkcs11_aes_192_cfb8 + hc_EVP_pkcs11_aes_256_cfb8 + hc_EVP_pkcs11_rc2_40_cbc + hc_EVP_pkcs11_rc2_64_cbc + hc_EVP_pkcs11_rc2_cbc + hc_EVP_pkcs11_rc4 + hc_EVP_pkcs11_rc4_40 + + hc_EVP_w32crypto_md4 ;! + hc_EVP_w32crypto_md5 ;! + hc_EVP_w32crypto_sha1 ;! + hc_EVP_w32crypto_sha256 ;! + hc_EVP_w32crypto_sha384 ;! + hc_EVP_w32crypto_sha512 ;! + hc_EVP_w32crypto_des_ede3_cbc ;! + hc_EVP_w32crypto_aes_128_cbc ;! + hc_EVP_w32crypto_aes_192_cbc ;! + hc_EVP_w32crypto_aes_256_cbc ;! + hc_EVP_w32crypto_rc2_40_cbc ;! + hc_EVP_w32crypto_rc2_cbc ;! + hc_EVP_w32crypto_rc4 ;! + hc_EVP_w32crypto_rc4_40 ;! + + hc_EVP_w32crypto_aes_128_cfb8 ;! + hc_EVP_w32crypto_aes_192_cfb8 ;! + hc_EVP_w32crypto_aes_256_cfb8 ;! + + hc_EVP_hcrypto_md4 + hc_EVP_hcrypto_md5 + hc_EVP_hcrypto_sha1 + hc_EVP_hcrypto_sha256 + hc_EVP_hcrypto_sha384 + hc_EVP_hcrypto_sha512 + hc_EVP_hcrypto_des_ede3_cbc + hc_EVP_hcrypto_aes_128_cbc + hc_EVP_hcrypto_aes_192_cbc + hc_EVP_hcrypto_aes_256_cbc + hc_EVP_hcrypto_rc4 + hc_EVP_hcrypto_rc4_40 + + hc_EVP_hcrypto_aes_128_cfb8 + hc_EVP_hcrypto_aes_192_cfb8 + hc_EVP_hcrypto_aes_256_cfb8 + +;! hc_EVP_hcrypto_aes_128_cts +;! hc_EVP_hcrypto_aes_192_cts +;! hc_EVP_hcrypto_aes_256_cts + + hc_HMAC + hc_HMAC_CTX_cleanup + hc_HMAC_CTX_init + hc_HMAC_CTX_free + hc_HMAC_CTX_new + hc_HMAC_Final + hc_HMAC_Init_ex + hc_HMAC_Update + hc_HMAC_size + hc_MD4_Final + hc_MD4_Init + hc_MD4_Update + hc_MD5_Final + hc_MD5_Init + hc_MD5_Update + hc_OpenSSL_add_all_algorithms + hc_OpenSSL_add_all_algorithms_conf + hc_OpenSSL_add_all_algorithms_noconf + hc_PKCS12_key_gen + hc_PKCS5_PBKDF2_HMAC + hc_PKCS5_PBKDF2_HMAC_SHA1 + hc_RAND_add + hc_RAND_bytes + hc_RAND_cleanup + hc_RAND_file_name +;! hc_RAND_fortuna_method + hc_RAND_get_rand_method + hc_RAND_load_file + hc_RAND_pseudo_bytes + hc_RAND_seed + hc_RAND_set_rand_engine + hc_RAND_set_rand_method + hc_RAND_status +;! hc_RAND_unix_method +;! hc_RAND_timer_method + hc_RAND_w32crypto_method ;! + hc_RAND_write_file + hc_RC2_cbc_encrypt + hc_RC2_decryptc + hc_RC2_encryptc + hc_RC2_set_key + hc_RC4 + hc_RC4_set_key + hc_RSA_check_key + hc_RSA_free + hc_RSA_generate_key_ex + hc_RSA_get_app_data + hc_RSA_get_default_method + hc_RSA_get_method + hc_RSA_new + hc_RSA_new_method + hc_RSA_null_method + hc_RSA_private_decrypt + hc_RSA_private_encrypt + hc_RSA_public_decrypt + hc_RSA_public_encrypt + hc_RSA_set_app_data + hc_RSA_set_default_method + hc_RSA_set_method + hc_RSA_sign + hc_RSA_size + hc_RSA_up_ref + hc_RSA_verify + hc_SHA1_Final + hc_SHA1_Init + hc_SHA1_Update + hc_SHA256_Final + hc_SHA256_Init + hc_SHA256_Update + hc_SHA384_Final + hc_SHA384_Init + hc_SHA384_Update + hc_SHA512_Final + hc_SHA512_Init + hc_SHA512_Update + hc_UI_UTIL_read_pw_string + hc_i2d_DHparams + hc_d2i_RSAPrivateKey + hc_i2d_RSAPrivateKey + hc_i2d_RSAPublicKey + hc_d2i_RSAPublicKey + hc_EVP_CIPHER_CTX_ctrl + hc_EVP_CIPHER_CTX_rand_key + hc_EVP_CIPHER_CTX_set_key_length + hc_EVP_hcrypto_rc2_cbc + hc_EVP_hcrypto_rc2_40_cbc + hc_EVP_hcrypto_camellia_128_cbc + hc_EVP_CipherUpdate + hc_EVP_CipherFinal_ex + + hc_hcrypto_validate + hc_hcrypto_scalarmult_curve25519 + hc_hcrypto_scalarmult_curve25519_base diff --git a/third_party/heimdal/lib/hcrypto/libtommath/LICENSE b/third_party/heimdal/lib/hcrypto/libtommath/LICENSE new file mode 100644 index 0000000..b23b3c8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/LICENSE @@ -0,0 +1,26 @@ + The LibTom license + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/third_party/heimdal/lib/hcrypto/libtommath/NTMakefile b/third_party/heimdal/lib/hcrypto/libtommath/NTMakefile new file mode 100644 index 0000000..082054a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/NTMakefile @@ -0,0 +1,203 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\hcrypto\libtommath + +!include ../../../windows/NTMakefile.w32 + +INCFILES= \ + $(INCDIR)\tommath.h \ + $(INCDIR)\tommath_class.h \ + $(INCDIR)\tommath_superclass.h + +libltm_OBJs= \ + $(OBJ)\bn_cutoffs.obj \ + $(OBJ)\bn_deprecated.obj \ + $(OBJ)\bn_mp_2expt.obj \ + $(OBJ)\bn_mp_abs.obj \ + $(OBJ)\bn_mp_add.obj \ + $(OBJ)\bn_mp_add_d.obj \ + $(OBJ)\bn_mp_addmod.obj \ + $(OBJ)\bn_mp_and.obj \ + $(OBJ)\bn_mp_clamp.obj \ + $(OBJ)\bn_mp_clear.obj \ + $(OBJ)\bn_mp_clear_multi.obj \ + $(OBJ)\bn_mp_cmp.obj \ + $(OBJ)\bn_mp_cmp_d.obj \ + $(OBJ)\bn_mp_cmp_mag.obj \ + $(OBJ)\bn_mp_cnt_lsb.obj \ + $(OBJ)\bn_mp_complement.obj \ + $(OBJ)\bn_mp_copy.obj \ + $(OBJ)\bn_mp_count_bits.obj \ + $(OBJ)\bn_mp_decr.obj \ + $(OBJ)\bn_mp_div.obj \ + $(OBJ)\bn_mp_div_2.obj \ + $(OBJ)\bn_mp_div_2d.obj \ + $(OBJ)\bn_mp_div_3.obj \ + $(OBJ)\bn_mp_div_d.obj \ + $(OBJ)\bn_mp_dr_is_modulus.obj \ + $(OBJ)\bn_mp_dr_reduce.obj \ + $(OBJ)\bn_mp_dr_setup.obj \ + $(OBJ)\bn_mp_error_to_string.obj\ + $(OBJ)\bn_mp_exch.obj \ + $(OBJ)\bn_mp_expt_u32.obj \ + $(OBJ)\bn_mp_exptmod.obj \ + $(OBJ)\bn_mp_exteuclid.obj \ + $(OBJ)\bn_mp_fread.obj \ + $(OBJ)\bn_mp_from_sbin.obj \ + $(OBJ)\bn_mp_from_ubin.obj \ + $(OBJ)\bn_mp_fwrite.obj \ + $(OBJ)\bn_mp_gcd.obj \ + $(OBJ)\bn_mp_get_double.obj \ + $(OBJ)\bn_mp_get_i32.obj \ + $(OBJ)\bn_mp_get_i64.obj \ + $(OBJ)\bn_mp_get_l.obj \ + $(OBJ)\bn_mp_get_ll.obj \ + $(OBJ)\bn_mp_get_mag_u32.obj \ + $(OBJ)\bn_mp_get_mag_u64.obj \ + $(OBJ)\bn_mp_get_mag_ul.obj \ + $(OBJ)\bn_mp_get_mag_ull.obj \ + $(OBJ)\bn_mp_grow.obj \ + $(OBJ)\bn_mp_incr.obj \ + $(OBJ)\bn_mp_init.obj \ + $(OBJ)\bn_mp_init_copy.obj \ + $(OBJ)\bn_mp_init_i32.obj \ + $(OBJ)\bn_mp_init_i64.obj \ + $(OBJ)\bn_mp_init_l.obj \ + $(OBJ)\bn_mp_init_ll.obj \ + $(OBJ)\bn_mp_init_multi.obj \ + $(OBJ)\bn_mp_init_set.obj \ + $(OBJ)\bn_mp_init_size.obj \ + $(OBJ)\bn_mp_init_u32.obj \ + $(OBJ)\bn_mp_init_u64.obj \ + $(OBJ)\bn_mp_init_ul.obj \ + $(OBJ)\bn_mp_init_ull.obj \ + $(OBJ)\bn_mp_invmod.obj \ + $(OBJ)\bn_mp_is_square.obj \ + $(OBJ)\bn_mp_iseven.obj \ + $(OBJ)\bn_mp_isodd.obj \ + $(OBJ)\bn_mp_kronecker.obj \ + $(OBJ)\bn_mp_lcm.obj \ + $(OBJ)\bn_mp_log_u32.obj \ + $(OBJ)\bn_mp_lshd.obj \ + $(OBJ)\bn_mp_mod.obj \ + $(OBJ)\bn_mp_mod_2d.obj \ + $(OBJ)\bn_mp_mod_d.obj \ + $(OBJ)\bn_mp_montgomery_calc_normalization.obj \ + $(OBJ)\bn_mp_montgomery_reduce.obj \ + $(OBJ)\bn_mp_montgomery_setup.obj \ + $(OBJ)\bn_mp_mul.obj \ + $(OBJ)\bn_mp_mul_2.obj \ + $(OBJ)\bn_mp_mul_2d.obj \ + $(OBJ)\bn_mp_mul_d.obj \ + $(OBJ)\bn_mp_mulmod.obj \ + $(OBJ)\bn_mp_neg.obj \ + $(OBJ)\bn_mp_or.obj \ + $(OBJ)\bn_mp_pack.obj \ + $(OBJ)\bn_mp_pack_count.obj \ + $(OBJ)\bn_mp_prime_fermat.obj \ + $(OBJ)\bn_mp_prime_frobenius_underwood.obj \ + $(OBJ)\bn_mp_prime_is_prime.obj \ + $(OBJ)\bn_mp_prime_miller_rabin.obj \ + $(OBJ)\bn_mp_prime_next_prime.obj \ + $(OBJ)\bn_mp_prime_rabin_miller_trials.obj \ + $(OBJ)\bn_mp_prime_rand.obj \ + $(OBJ)\bn_mp_prime_strong_lucas_selfridge.obj \ + $(OBJ)\bn_mp_radix_size.obj \ + $(OBJ)\bn_mp_radix_smap.obj \ + $(OBJ)\bn_mp_rand.obj \ + $(OBJ)\bn_mp_read_radix.obj \ + $(OBJ)\bn_mp_reduce.obj \ + $(OBJ)\bn_mp_reduce_2k.obj \ + $(OBJ)\bn_mp_reduce_2k_l.obj \ + $(OBJ)\bn_mp_reduce_2k_setup.obj \ + $(OBJ)\bn_mp_reduce_2k_setup_l.obj \ + $(OBJ)\bn_mp_reduce_is_2k.obj \ + $(OBJ)\bn_mp_reduce_is_2k_l.obj \ + $(OBJ)\bn_mp_reduce_setup.obj \ + $(OBJ)\bn_mp_root_u32.obj \ + $(OBJ)\bn_mp_rshd.obj \ + $(OBJ)\bn_mp_sbin_size.obj \ + $(OBJ)\bn_mp_set.obj \ + $(OBJ)\bn_mp_set_double.obj \ + $(OBJ)\bn_mp_set_i32.obj \ + $(OBJ)\bn_mp_set_i64.obj \ + $(OBJ)\bn_mp_set_l.obj \ + $(OBJ)\bn_mp_set_ll.obj \ + $(OBJ)\bn_mp_set_u32.obj \ + $(OBJ)\bn_mp_set_u64.obj \ + $(OBJ)\bn_mp_set_ul.obj \ + $(OBJ)\bn_mp_set_ull.obj \ + $(OBJ)\bn_mp_shrink.obj \ + $(OBJ)\bn_mp_signed_rsh.obj \ + $(OBJ)\bn_mp_sqr.obj \ + $(OBJ)\bn_mp_sqrmod.obj \ + $(OBJ)\bn_mp_sqrt.obj \ + $(OBJ)\bn_mp_sqrtmod_prime.obj \ + $(OBJ)\bn_mp_sub.obj \ + $(OBJ)\bn_mp_sub_d.obj \ + $(OBJ)\bn_mp_submod.obj \ + $(OBJ)\bn_mp_to_radix.obj \ + $(OBJ)\bn_mp_to_sbin.obj \ + $(OBJ)\bn_mp_to_ubin.obj \ + $(OBJ)\bn_mp_ubin_size.obj \ + $(OBJ)\bn_mp_unpack.obj \ + $(OBJ)\bn_mp_xor.obj \ + $(OBJ)\bn_mp_zero.obj \ + $(OBJ)\bn_prime_tab.obj \ + $(OBJ)\bn_s_mp_add.obj \ + $(OBJ)\bn_s_mp_balance_mul.obj \ + $(OBJ)\bn_s_mp_exptmod.obj \ + $(OBJ)\bn_s_mp_exptmod_fast.obj \ + $(OBJ)\bn_s_mp_get_bit.obj \ + $(OBJ)\bn_s_mp_invmod_fast.obj \ + $(OBJ)\bn_s_mp_invmod_slow.obj \ + $(OBJ)\bn_s_mp_karatsuba_mul.obj\ + $(OBJ)\bn_s_mp_karatsuba_sqr.obj\ + $(OBJ)\bn_s_mp_montgomery_reduce_fast.obj \ + $(OBJ)\bn_s_mp_mul_digs.obj \ + $(OBJ)\bn_s_mp_mul_digs_fast.obj\ + $(OBJ)\bn_s_mp_mul_high_digs.obj\ + $(OBJ)\bn_s_mp_mul_high_digs_fast.obj \ + $(OBJ)\bn_s_mp_prime_is_divisible.obj \ + $(OBJ)\bn_s_mp_rand_jenkins.obj \ + $(OBJ)\bn_s_mp_rand_platform.obj\ + $(OBJ)\bn_s_mp_reverse.obj \ + $(OBJ)\bn_s_mp_sqr.obj \ + $(OBJ)\bn_s_mp_sqr_fast.obj \ + $(OBJ)\bn_s_mp_sub.obj \ + $(OBJ)\bn_s_mp_toom_mul.obj \ + $(OBJ)\bn_s_mp_toom_sqr.obj + +$(LIBLTM): $(libltm_OBJs) + $(LIBCON) + +all:: $(INCFILES) $(LIBLTM) diff --git a/third_party/heimdal/lib/hcrypto/libtommath/README.md b/third_party/heimdal/lib/hcrypto/libtommath/README.md new file mode 100644 index 0000000..be5b207 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/README.md @@ -0,0 +1,44 @@ +# libtommath + +This is the git repository for [LibTomMath](http://www.libtom.net/LibTomMath/), a free open source portable number theoretic multiple-precision integer (MPI) library written entirely in C. + +## Build Status + +### Travis CI + +master: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=master)](https://travis-ci.org/libtom/libtommath) + +develop: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=develop)](https://travis-ci.org/libtom/libtommath) + +### AppVeyor + +master: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/master?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/master) + +develop: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/develop?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/develop) + +### ABI Laboratory + +API/ABI changes: [check here](https://abi-laboratory.pro/tracker/timeline/libtommath/) + +## Summary + +The `develop` branch contains the in-development version. Stable releases are tagged. + +Documentation is built from the LaTeX file `bn.tex`. There is also limited documentation in `tommath.h`. +There is also a document, `tommath.pdf`, which describes the goals of the project and many of the algorithms used. + +The project can be build by using `make`. Along with the usual `make`, `make clean` and `make install`, +there are several other build targets, see the makefile for details. +There are also makefiles for certain specific platforms. + +## Testing + +Tests are located in `demo/` and can be built in two flavors. +* `make test` creates a stand-alone test binary that executes several test routines. +* `make mtest_opponent` creates a test binary that is intended to be run against `mtest`. + `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./mtest_opponent`. + `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm + +## Building and Installing + +Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details. diff --git a/third_party/heimdal/lib/hcrypto/libtommath/appveyor.yml b/third_party/heimdal/lib/hcrypto/libtommath/appveyor.yml new file mode 100644 index 0000000..efe4568 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/appveyor.yml @@ -0,0 +1,20 @@ +version: 1.2.0-{build} +branches: + only: + - master + - develop + - /^release/ + - /^travis/ +image: +- Visual Studio 2019 +- Visual Studio 2017 +- Visual Studio 2015 +build_script: +- cmd: >- + if "Visual Studio 2019"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" + if "Visual Studio 2017"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 + if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 + nmake -f makefile.msvc all +test_script: +- cmd: test.exe diff --git a/third_party/heimdal/lib/hcrypto/libtommath/astylerc b/third_party/heimdal/lib/hcrypto/libtommath/astylerc new file mode 100644 index 0000000..c5ff779 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/astylerc @@ -0,0 +1,30 @@ +# Artistic Style, see http://astyle.sourceforge.net/ +# full documentation, see: http://astyle.sourceforge.net/astyle.html +# +# usage: +# astyle --options=astylerc *.[ch] + +# Do not create backup, annonying in the times of git +suffix=none + +## Bracket Style Options +style=kr + +## Tab Options +indent=spaces=3 + +## Bracket Modify Options + +## Indentation Options +min-conditional-indent=0 + +## Padding Options +pad-header +unpad-paren +align-pointer=name + +## Formatting Options +break-after-logical +max-code-length=120 +convert-tabs +mode=c diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_cutoffs.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_cutoffs.c new file mode 100644 index 0000000..b02ab71 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_cutoffs.c @@ -0,0 +1,14 @@ +#include "tommath_private.h" +#ifdef BN_CUTOFFS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_FIXED_CUTOFFS +#include "tommath_cutoffs.h" +int KARATSUBA_MUL_CUTOFF = MP_DEFAULT_KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF = MP_DEFAULT_KARATSUBA_SQR_CUTOFF, + TOOM_MUL_CUTOFF = MP_DEFAULT_TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF = MP_DEFAULT_TOOM_SQR_CUTOFF; +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_deprecated.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_deprecated.c new file mode 100644 index 0000000..2056b20 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_deprecated.c @@ -0,0 +1,321 @@ +#include "tommath_private.h" +#ifdef BN_DEPRECATED_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef BN_MP_GET_BIT_C +int mp_get_bit(const mp_int *a, int b) +{ + if (b < 0) { + return MP_VAL; + } + return (s_mp_get_bit(a, (unsigned int)b) == MP_YES) ? MP_YES : MP_NO; +} +#endif +#ifdef BN_MP_JACOBI_C +mp_err mp_jacobi(const mp_int *a, const mp_int *n, int *c) +{ + if (a->sign == MP_NEG) { + return MP_VAL; + } + if (mp_cmp_d(n, 0uL) != MP_GT) { + return MP_VAL; + } + return mp_kronecker(a, n, c); +} +#endif +#ifdef BN_MP_PRIME_RANDOM_EX_C +mp_err mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat) +{ + return s_mp_prime_random_ex(a, t, size, flags, cb, dat); +} +#endif +#ifdef BN_MP_RAND_DIGIT_C +mp_err mp_rand_digit(mp_digit *r) +{ + mp_err err = s_mp_rand_source(r, sizeof(mp_digit)); + *r &= MP_MASK; + return err; +} +#endif +#ifdef BN_FAST_MP_INVMOD_C +mp_err fast_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_invmod_fast(a, b, c); +} +#endif +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +mp_err fast_mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) +{ + return s_mp_montgomery_reduce_fast(x, n, rho); +} +#endif +#ifdef BN_FAST_S_MP_MUL_DIGS_C +mp_err fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + return s_mp_mul_digs_fast(a, b, c, digs); +} +#endif +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C +mp_err fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + return s_mp_mul_high_digs_fast(a, b, c, digs); +} +#endif +#ifdef BN_FAST_S_MP_SQR_C +mp_err fast_s_mp_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_sqr_fast(a, b); +} +#endif +#ifdef BN_MP_BALANCE_MUL_C +mp_err mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_balance_mul(a, b, c); +} +#endif +#ifdef BN_MP_EXPTMOD_FAST_C +mp_err mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + return s_mp_exptmod_fast(G, X, P, Y, redmode); +} +#endif +#ifdef BN_MP_INVMOD_SLOW_C +mp_err mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_invmod_slow(a, b, c); +} +#endif +#ifdef BN_MP_KARATSUBA_MUL_C +mp_err mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_karatsuba_mul(a, b, c); +} +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +mp_err mp_karatsuba_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_karatsuba_sqr(a, b); +} +#endif +#ifdef BN_MP_TOOM_MUL_C +mp_err mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_toom_mul(a, b, c); +} +#endif +#ifdef BN_MP_TOOM_SQR_C +mp_err mp_toom_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_toom_sqr(a, b); +} +#endif +#ifdef S_MP_REVERSE_C +void bn_reverse(unsigned char *s, int len) +{ + if (len > 0) { + s_mp_reverse(s, (size_t)len); + } +} +#endif +#ifdef BN_MP_TC_AND_C +mp_err mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_and(a, b, c); +} +#endif +#ifdef BN_MP_TC_OR_C +mp_err mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_or(a, b, c); +} +#endif +#ifdef BN_MP_TC_XOR_C +mp_err mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_xor(a, b, c); +} +#endif +#ifdef BN_MP_TC_DIV_2D_C +mp_err mp_tc_div_2d(const mp_int *a, int b, mp_int *c) +{ + return mp_signed_rsh(a, b, c); +} +#endif +#ifdef BN_MP_INIT_SET_INT_C +mp_err mp_init_set_int(mp_int *a, unsigned long b) +{ + return mp_init_u32(a, (uint32_t)b); +} +#endif +#ifdef BN_MP_SET_INT_C +mp_err mp_set_int(mp_int *a, unsigned long b) +{ + mp_set_u32(a, (uint32_t)b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_SET_LONG_C +mp_err mp_set_long(mp_int *a, unsigned long b) +{ + mp_set_u64(a, b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_SET_LONG_LONG_C +mp_err mp_set_long_long(mp_int *a, unsigned long long b) +{ + mp_set_u64(a, b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_GET_INT_C +unsigned long mp_get_int(const mp_int *a) +{ + return (unsigned long)mp_get_mag_u32(a); +} +#endif +#ifdef BN_MP_GET_LONG_C +unsigned long mp_get_long(const mp_int *a) +{ + return (unsigned long)mp_get_mag_ul(a); +} +#endif +#ifdef BN_MP_GET_LONG_LONG_C +unsigned long long mp_get_long_long(const mp_int *a) +{ + return mp_get_mag_ull(a); +} +#endif +#ifdef BN_MP_PRIME_IS_DIVISIBLE_C +mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result) +{ + return s_mp_prime_is_divisible(a, result); +} +#endif +#ifdef BN_MP_EXPT_D_EX_C +mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) +{ + (void)fast; + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_expt_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_EXPT_D_C +mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c) +{ + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_expt_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_N_ROOT_EX_C +mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) +{ + (void)fast; + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_root_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_N_ROOT_C +mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c) +{ + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_root_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_UNSIGNED_BIN_SIZE_C +int mp_unsigned_bin_size(const mp_int *a) +{ + return (int)mp_ubin_size(a); +} +#endif +#ifdef BN_MP_READ_UNSIGNED_BIN_C +mp_err mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c) +{ + return mp_from_ubin(a, b, (size_t) c); +} +#endif +#ifdef BN_MP_TO_UNSIGNED_BIN_C +mp_err mp_to_unsigned_bin(const mp_int *a, unsigned char *b) +{ + return mp_to_ubin(a, b, SIZE_MAX, NULL); +} +#endif +#ifdef BN_MP_TO_UNSIGNED_BIN_N_C +mp_err mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) +{ + size_t n = mp_ubin_size(a); + if (*outlen < (unsigned long)n) { + return MP_VAL; + } + *outlen = (unsigned long)n; + return mp_to_ubin(a, b, n, NULL); +} +#endif +#ifdef BN_MP_SIGNED_BIN_SIZE_C +int mp_signed_bin_size(const mp_int *a) +{ + return (int)mp_sbin_size(a); +} +#endif +#ifdef BN_MP_READ_SIGNED_BIN_C +mp_err mp_read_signed_bin(mp_int *a, const unsigned char *b, int c) +{ + return mp_from_sbin(a, b, (size_t) c); +} +#endif +#ifdef BN_MP_TO_SIGNED_BIN_C +mp_err mp_to_signed_bin(const mp_int *a, unsigned char *b) +{ + return mp_to_sbin(a, b, SIZE_MAX, NULL); +} +#endif +#ifdef BN_MP_TO_SIGNED_BIN_N_C +mp_err mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) +{ + size_t n = mp_sbin_size(a); + if (*outlen < (unsigned long)n) { + return MP_VAL; + } + *outlen = (unsigned long)n; + return mp_to_sbin(a, b, n, NULL); +} +#endif +#ifdef BN_MP_TORADIX_N_C +mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen) +{ + if (maxlen < 0) { + return MP_VAL; + } + return mp_to_radix(a, str, (size_t)maxlen, NULL, radix); +} +#endif +#ifdef BN_MP_TORADIX_C +mp_err mp_toradix(const mp_int *a, char *str, int radix) +{ + return mp_to_radix(a, str, SIZE_MAX, NULL, radix); +} +#endif +#ifdef BN_MP_IMPORT_C +mp_err mp_import(mp_int *rop, size_t count, int order, size_t size, int endian, size_t nails, + const void *op) +{ + return mp_unpack(rop, count, order, size, endian, nails, op); +} +#endif +#ifdef BN_MP_EXPORT_C +mp_err mp_export(void *rop, size_t *countp, int order, size_t size, + int endian, size_t nails, const mp_int *op) +{ + return mp_pack(rop, SIZE_MAX, countp, order, size, endian, nails, op); +} +#endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_2expt.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_2expt.c new file mode 100644 index 0000000..0ae3df1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_2expt.c @@ -0,0 +1,31 @@ +#include "tommath_private.h" +#ifdef BN_MP_2EXPT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +mp_err mp_2expt(mp_int *a, int b) +{ + mp_err err; + + /* zero a as per default */ + mp_zero(a); + + /* grow a to accomodate the single bit */ + if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { + return err; + } + + /* set the used count of where the bit will go */ + a->used = (b / MP_DIGIT_BIT) + 1; + + /* put the single bit in its place */ + a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT); + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_abs.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_abs.c new file mode 100644 index 0000000..00900bb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_abs.c @@ -0,0 +1,26 @@ +#include "tommath_private.h" +#ifdef BN_MP_ABS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +mp_err mp_abs(const mp_int *a, mp_int *b) +{ + mp_err err; + + /* copy a to b */ + if (a != b) { + if ((err = mp_copy(a, b)) != MP_OKAY) { + return err; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add.c new file mode 100644 index 0000000..dfa78de --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add.c @@ -0,0 +1,38 @@ +#include "tommath_private.h" +#ifdef BN_MP_ADD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level addition (handles signs) */ +mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_sign sa, sb; + mp_err err; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + err = s_mp_add(a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag(a, b) == MP_LT) { + c->sign = sb; + err = s_mp_sub(b, a, c); + } else { + c->sign = sa; + err = s_mp_sub(a, b, c); + } + } + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add_d.c new file mode 100644 index 0000000..f301575 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_add_d.c @@ -0,0 +1,89 @@ +#include "tommath_private.h" +#ifdef BN_MP_ADD_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit addition */ +mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_err err; + int ix, oldused; + mp_digit *tmpa, *tmpc; + + /* grow c as required */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if ((a->sign == MP_NEG) && ((a->used > 1) || (a->dp[0] >= b))) { + mp_int a_ = *a; + /* temporarily fix sign of a */ + a_.sign = MP_ZPOS; + + /* c = |a| - b */ + err = mp_sub_d(&a_, b, c); + + /* fix sign */ + c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return err; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digits, mu is carry */ + mp_digit mu = b; + for (ix = 0; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> MP_DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* now zero to oldused */ + MP_ZERO_DIGITS(tmpc, oldused - ix); + mp_clamp(c); + + return MP_OKAY; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_addmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_addmod.c new file mode 100644 index 0000000..1dcfb67 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_addmod.c @@ -0,0 +1,25 @@ +#include "tommath_private.h" +#ifdef BN_MP_ADDMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a + b (mod c) */ +mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_add(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_and.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_and.c new file mode 100644 index 0000000..c259f8d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_and.c @@ -0,0 +1,56 @@ +#include "tommath_private.h" +#ifdef BN_MP_AND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement and */ +mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = ((a->sign == MP_NEG) && (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x & y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clamp.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clamp.c new file mode 100644 index 0000000..ac23bfd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clamp.c @@ -0,0 +1,27 @@ +#include "tommath_private.h" +#ifdef BN_MP_CLAMP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void mp_clamp(mp_int *a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear.c new file mode 100644 index 0000000..ff78324 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear.c @@ -0,0 +1,20 @@ +#include "tommath_private.h" +#ifdef BN_MP_CLEAR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* clear one (frees) */ +void mp_clear(mp_int *a) +{ + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* free ram */ + MP_FREE_DIGITS(a->dp, a->alloc); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear_multi.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear_multi.c new file mode 100644 index 0000000..794e45f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_clear_multi.c @@ -0,0 +1,19 @@ +#include "tommath_private.h" +#ifdef BN_MP_CLEAR_MULTI_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int *next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int *); + } + va_end(args); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp.c new file mode 100644 index 0000000..ced4840 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp.c @@ -0,0 +1,26 @@ +#include "tommath_private.h" +#ifdef BN_MP_CMP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare two ints (signed)*/ +mp_ord mp_cmp(const mp_int *a, const mp_int *b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_d.c new file mode 100644 index 0000000..5a8337b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_d.c @@ -0,0 +1,28 @@ +#include "tommath_private.h" +#ifdef BN_MP_CMP_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare a digit */ +mp_ord mp_cmp_d(const mp_int *a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_mag.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_mag.c new file mode 100644 index 0000000..f144ea9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cmp_mag.c @@ -0,0 +1,39 @@ +#include "tommath_private.h" +#ifdef BN_MP_CMP_MAG_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare maginitude of two ints (unsigned) */ +mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) +{ + int n; + const mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cnt_lsb.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cnt_lsb.c new file mode 100644 index 0000000..4b2d206 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_cnt_lsb.c @@ -0,0 +1,37 @@ +#include "tommath_private.h" +#ifdef BN_MP_CNT_LSB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(const mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (MP_IS_ZERO(a)) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {} + q = a->dp[x]; + x *= MP_DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1u) == 0u) { + do { + qq = q & 15u; + x += lnz[qq]; + q >>= 4; + } while (qq == 0u); + } + return x; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_complement.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_complement.c new file mode 100644 index 0000000..fef1423 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_complement.c @@ -0,0 +1,12 @@ +#include "tommath_private.h" +#ifdef BN_MP_COMPLEMENT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = ~a */ +mp_err mp_complement(const mp_int *a, mp_int *b) +{ + mp_err err = mp_neg(a, b); + return (err == MP_OKAY) ? mp_sub_d(b, 1uL, b) : err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_copy.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_copy.c new file mode 100644 index 0000000..e72fcf6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_copy.c @@ -0,0 +1,47 @@ +#include "tommath_private.h" +#ifdef BN_MP_COPY_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* copy, b = a */ +mp_err mp_copy(const mp_int *a, mp_int *b) +{ + int n; + mp_digit *tmpa, *tmpb; + mp_err err; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((err = mp_grow(b, a->used)) != MP_OKAY) { + return err; + } + } + + /* zero b and copy the parameters over */ + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + MP_ZERO_DIGITS(tmpb, b->used - n); + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_count_bits.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_count_bits.c new file mode 100644 index 0000000..b7c2cad --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_count_bits.c @@ -0,0 +1,28 @@ +#include "tommath_private.h" +#ifdef BN_MP_COUNT_BITS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* returns the number of bits in an int */ +int mp_count_bits(const mp_int *a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (MP_IS_ZERO(a)) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * MP_DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > 0u) { + ++r; + q >>= 1u; + } + return r; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_decr.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_decr.c new file mode 100644 index 0000000..c6a1572 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_decr.c @@ -0,0 +1,34 @@ +#include "tommath_private.h" +#ifdef BN_MP_DECR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Decrement "a" by one like "a--". Changes input! */ +mp_err mp_decr(mp_int *a) +{ + if (MP_IS_ZERO(a)) { + mp_set(a,1uL); + a->sign = MP_NEG; + return MP_OKAY; + } else if (a->sign == MP_NEG) { + mp_err err; + a->sign = MP_ZPOS; + if ((err = mp_incr(a)) != MP_OKAY) { + return err; + } + /* There is no -0 in LTM */ + if (!MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + return MP_OKAY; + } else if (a->dp[0] > 1uL) { + a->dp[0]--; + if (a->dp[0] == 0u) { + mp_zero(a); + } + return MP_OKAY; + } else { + return mp_sub_d(a, 1uL,a); + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div.c new file mode 100644 index 0000000..71de55b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div.c @@ -0,0 +1,250 @@ +#include "tommath_private.h" +#ifdef BN_MP_DIV_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) +{ + mp_int ta, tb, tq, q; + int n, n2; + mp_err err; + + /* is divisor zero ? */ + if (MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag(a, b) == MP_LT) { + if (d != NULL) { + err = mp_copy(a, d); + } else { + err = MP_OKAY; + } + if (c != NULL) { + mp_zero(c); + } + return err; + } + + /* init our temps */ + if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) { + return err; + } + + + mp_set(&tq, 1uL); + n = mp_count_bits(a) - mp_count_bits(b); + if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR; + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR; + } + if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR; + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + if (c != NULL) { + mp_exch(c, &q); + c->sign = MP_IS_ZERO(c) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = MP_IS_ZERO(d) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return err; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) +{ + mp_int q, x, y, t1, t2; + int n, t, i, norm; + mp_sign neg; + mp_err err; + + /* is divisor zero ? */ + if (MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag(a, b) == MP_LT) { + if (d != NULL) { + err = mp_copy(a, d); + } else { + err = MP_OKAY; + } + if (c != NULL) { + mp_zero(c); + } + return err; + } + + if ((err = mp_init_size(&q, a->used + 2)) != MP_OKAY) { + return err; + } + q.used = a->used + 2; + + if ((err = mp_init(&t1)) != MP_OKAY) goto LBL_Q; + + if ((err = mp_init(&t2)) != MP_OKAY) goto LBL_T1; + + if ((err = mp_init_copy(&x, a)) != MP_OKAY) goto LBL_T2; + + if ((err = mp_init_copy(&y, b)) != MP_OKAY) goto LBL_X; + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**MP_DIGIT_BIT] */ + norm = mp_count_bits(&y) % MP_DIGIT_BIT; + if (norm < (MP_DIGIT_BIT - 1)) { + norm = (MP_DIGIT_BIT - 1) - norm; + if ((err = mp_mul_2d(&x, norm, &x)) != MP_OKAY) goto LBL_Y; + if ((err = mp_mul_2d(&y, norm, &y)) != MP_OKAY) goto LBL_Y; + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + /* y = y*b**{n-t} */ + if ((err = mp_lshd(&y, n - t)) != MP_OKAY) goto LBL_Y; + + while (mp_cmp(&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((err = mp_sub(&x, &y, &x)) != MP_OKAY) goto LBL_Y; + } + + /* reset y by shifting it back down */ + mp_rshd(&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)MP_DIGIT_BIT) - (mp_digit)1; + } else { + mp_word tmp; + tmp = (mp_word)x.dp[i] << (mp_word)MP_DIGIT_BIT; + tmp |= (mp_word)x.dp[i - 1]; + tmp /= (mp_word)y.dp[t]; + if (tmp > (mp_word)MP_MASK) { + tmp = MP_MASK; + } + q.dp[(i - t) - 1] = (mp_digit)(tmp & (mp_word)MP_MASK); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] + 1uL) & (mp_digit)MP_MASK; + do { + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & (mp_digit)MP_MASK; + + /* find left hand */ + mp_zero(&t1); + t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((err = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y; + + /* find right hand */ + t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2]; + t2.dp[1] = x.dp[i - 1]; /* i >= 1 always holds */ + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((err = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y; + + if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y; + + if ((err = mp_sub(&x, &t1, &x)) != MP_OKAY) goto LBL_Y; + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((err = mp_copy(&y, &t1)) != MP_OKAY) goto LBL_Y; + if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y; + if ((err = mp_add(&x, &t1, &x)) != MP_OKAY) goto LBL_Y; + + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = (x.used == 0) ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + c->sign = neg; + } + + if (d != NULL) { + if ((err = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) goto LBL_Y; + mp_exch(&x, d); + } + + err = MP_OKAY; + +LBL_Y: + mp_clear(&y); +LBL_X: + mp_clear(&x); +LBL_T2: + mp_clear(&t2); +LBL_T1: + mp_clear(&t1); +LBL_Q: + mp_clear(&q); + return err; +} + +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2.c new file mode 100644 index 0000000..f56ea81 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2.c @@ -0,0 +1,49 @@ +#include "tommath_private.h" +#ifdef BN_MP_DIV_2_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = a/2 */ +mp_err mp_div_2(const mp_int *a, mp_int *b) +{ + int x, oldused; + mp_digit r, rr, *tmpa, *tmpb; + mp_err err; + + /* copy */ + if (b->alloc < a->used) { + if ((err = mp_grow(b, a->used)) != MP_OKAY) { + return err; + } + } + + oldused = b->used; + b->used = a->used; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1u; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (MP_DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used); + + b->sign = a->sign; + mp_clamp(b); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2d.c new file mode 100644 index 0000000..c47d5ce --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_2d.c @@ -0,0 +1,71 @@ +#include "tommath_private.h" +#ifdef BN_MP_DIV_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) +{ + mp_digit D, r, rr; + int x; + mp_err err; + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + err = mp_copy(a, c); + if (d != NULL) { + mp_zero(d); + } + return err; + } + + /* copy */ + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + /* 'a' should not be used after here - it might be the same as d */ + + /* get the remainder */ + if (d != NULL) { + if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) { + return err; + } + } + + /* shift by as many digits in the bit count */ + if (b >= MP_DIGIT_BIT) { + mp_rshd(c, b / MP_DIGIT_BIT); + } + + /* shift any bit count < MP_DIGIT_BIT */ + D = (mp_digit)(b % MP_DIGIT_BIT); + if (D != 0u) { + mp_digit *tmpc, mask, shift; + + /* mask */ + mask = ((mp_digit)1 << D) - 1uL; + + /* shift for lsb */ + shift = (mp_digit)MP_DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_3.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_3.c new file mode 100644 index 0000000..3a23fdf --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_3.c @@ -0,0 +1,63 @@ +#include "tommath_private.h" +#ifdef BN_MP_DIV_3_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* divide by three (based on routine from MPI and the GMP manual) */ +mp_err mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + mp_err err; + int ix; + + /* b = 2**MP_DIGIT_BIT / 3 */ + b = ((mp_word)1 << (mp_word)MP_DIGIT_BIT) / (mp_word)3; + + if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { + return err; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; + + if (w >= 3u) { + /* multiply w by [1/3] */ + t = (w * (mp_word)b) >> (mp_word)MP_DIGIT_BIT; + + /* now subtract 3 * [w/3] from w, to get the remainder */ + w -= t+t+t; + + /* fixup the remainder as required since + * the optimization is not exact. + */ + while (w >= 3u) { + t += 1u; + w -= 3u; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + /* [optional] store the remainder */ + if (d != NULL) { + *d = (mp_digit)w; + } + + /* [optional] store the quotient */ + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_d.c new file mode 100644 index 0000000..b9d718b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_div_d.c @@ -0,0 +1,84 @@ +#include "tommath_private.h" +#ifdef BN_MP_DIV_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit division (based on routine from MPI) */ +mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) +{ + mp_int q; + mp_word w; + mp_digit t; + mp_err err; + int ix; + + /* cannot divide by zero */ + if (b == 0u) { + return MP_VAL; + } + + /* quick outs */ + if ((b == 1u) || MP_IS_ZERO(a)) { + if (d != NULL) { + *d = 0; + } + if (c != NULL) { + return mp_copy(a, c); + } + return MP_OKAY; + } + + /* power of two ? */ + if ((b & (b - 1u)) == 0u) { + ix = 1; + while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL); + } + if (c != NULL) { + return mp_div_2d(a, ix, c, NULL); + } + return MP_OKAY; + } + + /* three? */ + if (MP_HAS(MP_DIV_3) && (b == 3u)) { + return mp_div_3(a, c, d); + } + + /* no easy answer [c'est la vie]. Just division */ + if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { + return err; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; + + if (w >= b) { + t = (mp_digit)(w / b); + w -= (mp_word)t * (mp_word)b; + } else { + t = 0; + } + q.dp[ix] = t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_is_modulus.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_is_modulus.c new file mode 100644 index 0000000..83760ea --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_is_modulus.c @@ -0,0 +1,27 @@ +#include "tommath_private.h" +#ifdef BN_MP_DR_IS_MODULUS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if a number is a valid DR modulus */ +mp_bool mp_dr_is_modulus(const mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return MP_NO; + } + + /* must be of the form b**k - a [a <= b] so all + * but the first digit must be equal to -1 (mod b). + */ + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return MP_NO; + } + } + return MP_YES; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_reduce.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_reduce.c new file mode 100644 index 0000000..ffc33a6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_reduce.c @@ -0,0 +1,78 @@ +#include "tommath_private.h" +#ifdef BN_MP_DR_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Joong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) +{ + mp_err err; + int i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < (m + m)) { + if ((err = mp_grow(x, m + m)) != MP_OKAY) { + return err; + } + } + + /* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++ * (mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + MP_ZERO_DIGITS(tmpx1, (x->used - m) - 1); + + /* clamp, sub and return */ + mp_clamp(x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag(x, n) != MP_LT) { + if ((err = s_mp_sub(x, n, x)) != MP_OKAY) { + return err; + } + goto top; + } + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_setup.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_setup.c new file mode 100644 index 0000000..32d5f38 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_dr_setup.c @@ -0,0 +1,15 @@ +#include "tommath_private.h" +#ifdef BN_MP_DR_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +void mp_dr_setup(const mp_int *a, mp_digit *d) +{ + /* the casts are required if MP_DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31] + */ + *d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]); +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_error_to_string.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_error_to_string.c new file mode 100644 index 0000000..2e2adb0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_error_to_string.c @@ -0,0 +1,27 @@ +#include "tommath_private.h" +#ifdef BN_MP_ERROR_TO_STRING_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* return a char * string for a given code */ +const char *mp_error_to_string(mp_err code) +{ + switch (code) { + case MP_OKAY: + return "Successful"; + case MP_ERR: + return "Unknown error"; + case MP_MEM: + return "Out of heap"; + case MP_VAL: + return "Value out of range"; + case MP_ITER: + return "Max. iterations reached"; + case MP_BUF: + return "Buffer overflow"; + default: + return "Invalid error code"; + } +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exch.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exch.c new file mode 100644 index 0000000..552094c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exch.c @@ -0,0 +1,17 @@ +#include "tommath_private.h" +#ifdef BN_MP_EXCH_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void mp_exch(mp_int *a, mp_int *b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_expt_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_expt_u32.c new file mode 100644 index 0000000..2ab67ba --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_expt_u32.c @@ -0,0 +1,46 @@ +#include "tommath_private.h" +#ifdef BN_MP_EXPT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* calculate c = a**b using a square-multiply algorithm */ +mp_err mp_expt_u32(const mp_int *a, uint32_t b, mp_int *c) +{ + mp_err err; + + mp_int g; + + if ((err = mp_init_copy(&g, a)) != MP_OKAY) { + return err; + } + + /* set initial result */ + mp_set(c, 1uL); + + while (b > 0u) { + /* if the bit is set multiply */ + if ((b & 1u) != 0u) { + if ((err = mp_mul(c, &g, c)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* square */ + if (b > 1u) { + if ((err = mp_sqr(&g, &g)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* shift to next bit */ + b >>= 1; + } + + err = MP_OKAY; + +LBL_ERR: + mp_clear(&g); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exptmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exptmod.c new file mode 100644 index 0000000..5f811eb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exptmod.c @@ -0,0 +1,76 @@ +#include "tommath_private.h" +#ifdef BN_MP_EXPTMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + mp_err err; + + if (!MP_HAS(MP_INVMOD)) { + return MP_VAL; + } + + if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) { + return err; + } + + /* first compute 1/G mod P */ + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + goto LBL_ERR; + } + + /* now get |X| */ + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + goto LBL_ERR; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); +LBL_ERR: + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* modified diminished radix reduction */ + if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) && + (mp_reduce_is_2k_l(P) == MP_YES)) { + return s_mp_exptmod(G, X, P, Y, 1); + } + + /* is it a DR modulus? default to no */ + dr = (MP_HAS(MP_DR_IS_MODULUS) && (mp_dr_is_modulus(P) == MP_YES)) ? 1 : 0; + + /* if not, is it a unrestricted DR modulus? */ + if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) { + dr = (mp_reduce_is_2k(P) == MP_YES) ? 2 : 0; + } + + /* if the modulus is odd or dr != 0 use the montgomery method */ + if (MP_HAS(S_MP_EXPTMOD_FAST) && (MP_IS_ODD(P) || (dr != 0))) { + return s_mp_exptmod_fast(G, X, P, Y, dr); + } else if (MP_HAS(S_MP_EXPTMOD)) { + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod(G, X, P, Y, 0); + } else { + /* no exptmod for evens */ + return MP_VAL; + } +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exteuclid.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exteuclid.c new file mode 100644 index 0000000..faf47ba --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_exteuclid.c @@ -0,0 +1,73 @@ +#include "tommath_private.h" +#ifdef BN_MP_EXTEUCLID_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Extended euclidean algorithm of (a, b) produces + a*u1 + b*u2 = u3 + */ +mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) +{ + mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp; + mp_err err; + + if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) { + return err; + } + + /* initialize, (u1,u2,u3) = (1,0,a) */ + mp_set(&u1, 1uL); + if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR; + + /* initialize, (v1,v2,v3) = (0,1,b) */ + mp_set(&v2, 1uL); + if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR; + + /* loop while v3 != 0 */ + while (!MP_IS_ZERO(&v3)) { + /* q = u3/v3 */ + if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR; + + /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ + if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR; + + /* (u1,u2,u3) = (v1,v2,v3) */ + if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR; + + /* (v1,v2,v3) = (t1,t2,t3) */ + if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR; + } + + /* make sure U3 >= 0 */ + if (u3.sign == MP_NEG) { + if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR; + } + + /* copy result out */ + if (U1 != NULL) { + mp_exch(U1, &u1); + } + if (U2 != NULL) { + mp_exch(U2, &u2); + } + if (U3 != NULL) { + mp_exch(U3, &u3); + } + + err = MP_OKAY; +LBL_ERR: + mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fread.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fread.c new file mode 100644 index 0000000..52ea773 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fread.c @@ -0,0 +1,60 @@ +#include "tommath_private.h" +#ifdef BN_MP_FREAD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +/* read a bigint from a file stream in ASCII */ +mp_err mp_fread(mp_int *a, int radix, FILE *stream) +{ + mp_err err; + mp_sign neg; + + /* if first digit is - then set negative */ + int ch = fgetc(stream); + if (ch == (int)'-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + /* no digits, return error */ + if (ch == EOF) { + return MP_ERR; + } + + /* clear a */ + mp_zero(a); + + do { + int y; + unsigned pos = (unsigned)(ch - (int)'('); + if (mp_s_rmap_reverse_sz < pos) { + break; + } + + y = (int)mp_s_rmap_reverse[pos]; + + if ((y == 0xff) || (y >= radix)) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) { + return err; + } + } while ((ch = fgetc(stream)) != EOF); + + if (a->used != 0) { + a->sign = neg; + } + + return MP_OKAY; +} +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_sbin.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_sbin.c new file mode 100644 index 0000000..20e4597 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_sbin.c @@ -0,0 +1,25 @@ +#include "tommath_private.h" +#ifdef BN_MP_FROM_SBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +mp_err mp_from_sbin(mp_int *a, const unsigned char *buf, size_t size) +{ + mp_err err; + + /* read magnitude */ + if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) { + return err; + } + + /* first byte is 0 for positive, non-zero for negative */ + if (buf[0] == (unsigned char)0) { + a->sign = MP_ZPOS; + } else { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_ubin.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_ubin.c new file mode 100644 index 0000000..7f73cbc --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_from_ubin.c @@ -0,0 +1,39 @@ +#include "tommath_private.h" +#ifdef BN_MP_FROM_UBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +mp_err mp_from_ubin(mp_int *a, const unsigned char *buf, size_t size) +{ + mp_err err; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((err = mp_grow(a, 2)) != MP_OKAY) { + return err; + } + } + + /* zero the int */ + mp_zero(a); + + /* read the bytes in */ + while (size-- > 0u) { + if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) { + return err; + } + +#ifndef MP_8BIT + a->dp[0] |= *buf++; + a->used += 1; +#else + a->dp[0] = (*buf & MP_MASK); + a->dp[1] |= ((*buf++ >> 7) & 1u); + a->used += 2; +#endif + } + mp_clamp(a); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fwrite.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fwrite.c new file mode 100644 index 0000000..abe2e67 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_fwrite.c @@ -0,0 +1,45 @@ +#include "tommath_private.h" +#ifdef BN_MP_FWRITE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) +{ + char *buf; + mp_err err; + int len; + size_t written; + + /* TODO: this function is not in this PR */ + if (MP_HAS(MP_RADIX_SIZE_OVERESTIMATE)) { + /* if ((err = mp_radix_size_overestimate(&t, base, &len)) != MP_OKAY) goto LBL_ERR; */ + } else { + if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) { + return err; + } + } + + buf = (char *) MP_MALLOC((size_t)len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_to_radix(a, buf, (size_t)len, &written, radix)) != MP_OKAY) { + goto LBL_ERR; + } + + if (fwrite(buf, written, 1uL, stream) != 1uL) { + err = MP_ERR; + goto LBL_ERR; + } + err = MP_OKAY; + + +LBL_ERR: + MP_FREE_BUFFER(buf, (size_t)len); + return err; +} +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_gcd.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_gcd.c new file mode 100644 index 0000000..53029ba --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_gcd.c @@ -0,0 +1,92 @@ +#include "tommath_private.h" +#ifdef BN_MP_GCD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Greatest Common Divisor using the binary method */ +mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int u, v; + int k, u_lsb, v_lsb; + mp_err err; + + /* either zero than gcd is the largest */ + if (MP_IS_ZERO(a)) { + return mp_abs(b, c); + } + if (MP_IS_ZERO(b)) { + return mp_abs(a, c); + } + + /* get copies of a and b we can modify */ + if ((err = mp_init_copy(&u, a)) != MP_OKAY) { + return err; + } + + if ((err = mp_init_copy(&v, b)) != MP_OKAY) { + goto LBL_U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MP_MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + + if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + if (v_lsb != k) { + if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + while (!MP_IS_ZERO(&v)) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + /* swap u and v to make sure v is >= u */ + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto LBL_V; + } + + /* Divide out all factors of two */ + if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) { + goto LBL_V; + } + c->sign = MP_ZPOS; + err = MP_OKAY; +LBL_V: + mp_clear(&u); +LBL_U: + mp_clear(&v); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_double.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_double.c new file mode 100644 index 0000000..c9b1b19 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_double.c @@ -0,0 +1,18 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_DOUBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +double mp_get_double(const mp_int *a) +{ + int i; + double d = 0.0, fac = 1.0; + for (i = 0; i < MP_DIGIT_BIT; ++i) { + fac *= 2.0; + } + for (i = a->used; i --> 0;) { + d = (d * fac) + (double)a->dp[i]; + } + return (a->sign == MP_NEG) ? -d : d; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i32.c new file mode 100644 index 0000000..030b657 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i64.c new file mode 100644 index 0000000..969c8d2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_i64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_l.c new file mode 100644 index 0000000..55d78ec --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_l.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_ll.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_ll.c new file mode 100644 index 0000000..2687534 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_ll.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_ll, mp_get_mag_ull, long long, unsigned long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u32.c new file mode 100644 index 0000000..d77189b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_u32, uint32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u64.c new file mode 100644 index 0000000..36dd73f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_u64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_u64, uint64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ul.c new file mode 100644 index 0000000..e8819ae --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ul.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_ul, unsigned long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ull.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ull.c new file mode 100644 index 0000000..63a2741 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_get_mag_ull.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_ull, unsigned long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_grow.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_grow.c new file mode 100644 index 0000000..9e904c5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_grow.c @@ -0,0 +1,38 @@ +#include "tommath_private.h" +#ifdef BN_MP_GROW_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* grow as required */ +mp_err mp_grow(mp_int *a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = (mp_digit *) MP_REALLOC(a->dp, + (size_t)a->alloc * sizeof(mp_digit), + (size_t)size * sizeof(mp_digit)); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + MP_ZERO_DIGITS(a->dp + i, a->alloc - i); + } + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_incr.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_incr.c new file mode 100644 index 0000000..7695ac7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_incr.c @@ -0,0 +1,30 @@ +#include "tommath_private.h" +#ifdef BN_MP_INCR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Increment "a" by one like "a++". Changes input! */ +mp_err mp_incr(mp_int *a) +{ + if (MP_IS_ZERO(a)) { + mp_set(a,1uL); + return MP_OKAY; + } else if (a->sign == MP_NEG) { + mp_err err; + a->sign = MP_ZPOS; + if ((err = mp_decr(a)) != MP_OKAY) { + return err; + } + /* There is no -0 in LTM */ + if (!MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + return MP_OKAY; + } else if (a->dp[0] < MP_DIGIT_MAX) { + a->dp[0]++; + return MP_OKAY; + } else { + return mp_add_d(a, 1uL,a); + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init.c new file mode 100644 index 0000000..2eb7924 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init.c @@ -0,0 +1,23 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* init a new mp_int */ +mp_err mp_init(mp_int *a) +{ + /* allocate memory required and clear it */ + a->dp = (mp_digit *) MP_CALLOC((size_t)MP_PREC, sizeof(mp_digit)); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_copy.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_copy.c new file mode 100644 index 0000000..1888203 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_copy.c @@ -0,0 +1,21 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_COPY_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* creates "a" then copies b into it */ +mp_err mp_init_copy(mp_int *a, const mp_int *b) +{ + mp_err err; + + if ((err = mp_init_size(a, b->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_copy(b, a)) != MP_OKAY) { + mp_clear(a); + } + + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i32.c new file mode 100644 index 0000000..bc4de8d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i64.c new file mode 100644 index 0000000..2fa1516 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_i64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_l.c new file mode 100644 index 0000000..bc380b5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_l.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_l, mp_set_l, long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ll.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ll.c new file mode 100644 index 0000000..dc7c4a4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ll.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ll, mp_set_ll, long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_multi.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_multi.c new file mode 100644 index 0000000..d8390b5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_multi.c @@ -0,0 +1,41 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_MULTI_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include + +mp_err mp_init_multi(mp_int *mp, ...) +{ + mp_err err = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int *cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n-- != 0) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int *); + } + va_end(clean_args); + err = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int *); + } + va_end(args); + return err; /* Assumed ok, if error flagged above. */ +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_set.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_set.c new file mode 100644 index 0000000..5068f2b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_set.c @@ -0,0 +1,16 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_SET_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* initialize and set a digit */ +mp_err mp_init_set(mp_int *a, mp_digit b) +{ + mp_err err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + mp_set(a, b); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_size.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_size.c new file mode 100644 index 0000000..d622687 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_size.c @@ -0,0 +1,24 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* init an mp_init for a given size */ +mp_err mp_init_size(mp_int *a, int size) +{ + size = MP_MAX(MP_MIN_PREC, size); + + /* alloc mem */ + a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit)); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u32.c new file mode 100644 index 0000000..015d89b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u64.c new file mode 100644 index 0000000..2b35f7e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_u64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ul.c new file mode 100644 index 0000000..5164f72 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ul.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ull.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ull.c new file mode 100644 index 0000000..84110c0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_init_ull.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_INIT_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ull, mp_set_ull, unsigned long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_invmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_invmod.c new file mode 100644 index 0000000..7b35a24 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_invmod.c @@ -0,0 +1,23 @@ +#include "tommath_private.h" +#ifdef BN_MP_INVMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* hac 14.61, pp608 */ +mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + /* b cannot be negative and has to be >1 */ + if ((b->sign == MP_NEG) || (mp_cmp_d(b, 1uL) != MP_GT)) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (MP_HAS(S_MP_INVMOD_FAST) && MP_IS_ODD(b)) { + return s_mp_invmod_fast(a, b, c); + } + + return MP_HAS(S_MP_INVMOD_SLOW) + ? s_mp_invmod_slow(a, b, c) + : MP_VAL; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_is_square.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_is_square.c new file mode 100644 index 0000000..69e77a2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_is_square.c @@ -0,0 +1,93 @@ +#include "tommath_private.h" +#ifdef BN_MP_IS_SQUARE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Check if remainders are possible squares - fast exclude non-squares */ +static const char rem_128[128] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 +}; + +static const char rem_105[105] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 +}; + +/* Store non-zero to ret if arg is square, and zero if not */ +mp_err mp_is_square(const mp_int *arg, mp_bool *ret) +{ + mp_err err; + mp_digit c; + mp_int t; + unsigned long r; + + /* Default to Non-square :) */ + *ret = MP_NO; + + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + if (MP_IS_ZERO(arg)) { + return MP_OKAY; + } + + /* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */ + if (rem_128[127u & arg->dp[0]] == (char)1) { + return MP_OKAY; + } + + /* Next check mod 105 (3*5*7) */ + if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) { + return err; + } + if (rem_105[c] == (char)1) { + return MP_OKAY; + } + + + if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) { + return err; + } + if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) { + goto LBL_ERR; + } + r = mp_get_u32(&t); + /* Check for other prime modules, note it's not an ERROR but we must + * free "t" so the easiest way is to goto LBL_ERR. We know that err + * is already equal to MP_OKAY from the mp_mod call + */ + if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR; + + /* Final check - is sqr(sqrt(arg)) == arg ? */ + if ((err = mp_sqrt(arg, &t)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sqr(&t, &t)) != MP_OKAY) { + goto LBL_ERR; + } + + *ret = (mp_cmp_mag(&t, arg) == MP_EQ) ? MP_YES : MP_NO; +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_iseven.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_iseven.c new file mode 100644 index 0000000..5cb9622 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_iseven.c @@ -0,0 +1,10 @@ +#include "tommath_private.h" +#ifdef BN_MP_ISEVEN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_bool mp_iseven(const mp_int *a) +{ + return MP_IS_EVEN(a) ? MP_YES : MP_NO; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_isodd.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_isodd.c new file mode 100644 index 0000000..bf17646 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_isodd.c @@ -0,0 +1,10 @@ +#include "tommath_private.h" +#ifdef BN_MP_ISODD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_bool mp_isodd(const mp_int *a) +{ + return MP_IS_ODD(a) ? MP_YES : MP_NO; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_kronecker.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_kronecker.c new file mode 100644 index 0000000..525a820 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_kronecker.c @@ -0,0 +1,129 @@ +#include "tommath_private.h" +#ifdef BN_MP_KRONECKER_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + Kronecker symbol (a|p) + Straightforward implementation of algorithm 1.4.10 in + Henri Cohen: "A Course in Computational Algebraic Number Theory" + + @book{cohen2013course, + title={A course in computational algebraic number theory}, + author={Cohen, Henri}, + volume={138}, + year={2013}, + publisher={Springer Science \& Business Media} + } + */ +mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) +{ + mp_int a1, p1, r; + mp_err err; + int v, k; + + static const int table[8] = {0, 1, 0, -1, 0, -1, 0, 1}; + + if (MP_IS_ZERO(p)) { + if ((a->used == 1) && (a->dp[0] == 1u)) { + *c = 1; + } else { + *c = 0; + } + return MP_OKAY; + } + + if (MP_IS_EVEN(a) && MP_IS_EVEN(p)) { + *c = 0; + return MP_OKAY; + } + + if ((err = mp_init_copy(&a1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_init_copy(&p1, p)) != MP_OKAY) { + goto LBL_KRON_0; + } + + v = mp_cnt_lsb(&p1); + if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) { + goto LBL_KRON_1; + } + + if ((v & 1) == 0) { + k = 1; + } else { + k = table[a->dp[0] & 7u]; + } + + if (p1.sign == MP_NEG) { + p1.sign = MP_ZPOS; + if (a1.sign == MP_NEG) { + k = -k; + } + } + + if ((err = mp_init(&r)) != MP_OKAY) { + goto LBL_KRON_1; + } + + for (;;) { + if (MP_IS_ZERO(&a1)) { + if (mp_cmp_d(&p1, 1uL) == MP_EQ) { + *c = k; + goto LBL_KRON; + } else { + *c = 0; + goto LBL_KRON; + } + } + + v = mp_cnt_lsb(&a1); + if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) { + goto LBL_KRON; + } + + if ((v & 1) == 1) { + k = k * table[p1.dp[0] & 7u]; + } + + if (a1.sign == MP_NEG) { + /* + * Compute k = (-1)^((a1)*(p1-1)/4) * k + * a1.dp[0] + 1 cannot overflow because the MSB + * of the type mp_digit is not set by definition + */ + if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) { + k = -k; + } + } else { + /* compute k = (-1)^((a1-1)*(p1-1)/4) * k */ + if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) { + k = -k; + } + } + + if ((err = mp_copy(&a1, &r)) != MP_OKAY) { + goto LBL_KRON; + } + r.sign = MP_ZPOS; + if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) { + goto LBL_KRON; + } + if ((err = mp_copy(&r, &p1)) != MP_OKAY) { + goto LBL_KRON; + } + } + +LBL_KRON: + mp_clear(&r); +LBL_KRON_1: + mp_clear(&p1); +LBL_KRON_0: + mp_clear(&a1); + + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lcm.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lcm.c new file mode 100644 index 0000000..c32b269 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lcm.c @@ -0,0 +1,44 @@ +#include "tommath_private.h" +#ifdef BN_MP_LCM_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes least common multiple as |a*b|/(a, b) */ +mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + mp_int t1, t2; + + + if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) { + return err; + } + + /* t1 = get the GCD of the two inputs */ + if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) { + goto LBL_T; + } + + /* divide the smallest by the GCD */ + if (mp_cmp_mag(a, b) == MP_LT) { + /* store quotient in t2 such that t2 * b is the LCM */ + if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + err = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + err = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +LBL_T: + mp_clear_multi(&t1, &t2, NULL); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_log_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_log_u32.c new file mode 100644 index 0000000..c9cc157 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_log_u32.c @@ -0,0 +1,191 @@ +#include "tommath_private.h" +#ifdef BN_MP_LOG_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Compute log_{base}(a) */ +static mp_word s_pow(mp_word base, mp_word exponent) +{ + mp_word result = 1uLL; + while (exponent != 0u) { + if ((exponent & 1u) == 1u) { + result *= base; + } + exponent >>= 1; + base *= base; + } + + return result; +} + +static mp_digit s_digit_ilogb(mp_digit base, mp_digit n) +{ + mp_word bracket_low = 1uLL, bracket_mid, bracket_high, N; + mp_digit ret, high = 1uL, low = 0uL, mid; + + if (n < base) { + return 0uL; + } + if (n == base) { + return 1uL; + } + + bracket_high = (mp_word) base ; + N = (mp_word) n; + + while (bracket_high < N) { + low = high; + bracket_low = bracket_high; + high <<= 1; + bracket_high *= bracket_high; + } + + while (((mp_digit)(high - low)) > 1uL) { + mid = (low + high) >> 1; + bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low)); + + if (N < bracket_mid) { + high = mid ; + bracket_high = bracket_mid ; + } + if (N > bracket_mid) { + low = mid ; + bracket_low = bracket_mid ; + } + if (N == bracket_mid) { + return (mp_digit) mid; + } + } + + if (bracket_high == N) { + ret = high; + } else { + ret = low; + } + + return ret; +} + +/* TODO: output could be "int" because the output of mp_radix_size is int, too, + as is the output of mp_bitcount. + With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only! +*/ +mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c) +{ + mp_err err; + mp_ord cmp; + uint32_t high, low, mid; + mp_int bracket_low, bracket_high, bracket_mid, t, bi_base; + + err = MP_OKAY; + + if (a->sign == MP_NEG) { + return MP_VAL; + } + + if (MP_IS_ZERO(a)) { + return MP_VAL; + } + + if (base < 2u) { + return MP_VAL; + } + + /* `base' is at least 2 */ + + /* A small shortcut for bases that are powers of two. */ + if ((base & (base - 1u)) == 0u) { + int y, bit_count; + + for (y=0; (y < 7) && ((base & 1u) == 0u); y++) { + /* We must go through this loop at least once */ + base >>= 1; + } + bit_count = mp_count_bits(a) - 1; + /* + * `y' is necessarily at least 1 because `base' is a power of two and + * larger than 1, so we must have gone through the loop at least once, so + * we can't be dividing by zero. + * + * scan-build thinks we can be dividing by zero... WAT. + */ + *c = (uint32_t)(bit_count/y); + return MP_OKAY; + } + + if (a->used == 1) { + *c = (uint32_t)s_digit_ilogb(base, a->dp[0]); + return err; + } + + cmp = mp_cmp_d(a, base); + if ((cmp == MP_LT) || (cmp == MP_EQ)) { + *c = cmp == MP_EQ; + return err; + } + + if ((err = + mp_init_multi(&bracket_low, &bracket_high, + &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) { + return err; + } + + low = 0u; + mp_set(&bracket_low, 1uL); + high = 1u; + + mp_set(&bracket_high, base); + + /* + A kind of Giant-step/baby-step algorithm. + Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/ + The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped + for small n. + */ + while (mp_cmp(&bracket_high, a) == MP_LT) { + low = high; + if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) { + goto LBL_ERR; + } + high <<= 1; + if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_set(&bi_base, base); + + while ((high - low) > 1u) { + mid = (high + low) >> 1; + + if ((err = mp_expt_u32(&bi_base, (uint32_t)(mid - low), &t)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) { + goto LBL_ERR; + } + cmp = mp_cmp(a, &bracket_mid); + if (cmp == MP_LT) { + high = mid; + mp_exch(&bracket_mid, &bracket_high); + } + if (cmp == MP_GT) { + low = mid; + mp_exch(&bracket_mid, &bracket_low); + } + if (cmp == MP_EQ) { + *c = mid; + goto LBL_END; + } + } + + *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low; + +LBL_END: +LBL_ERR: + mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid, + &t, &bi_base, NULL); + return err; +} + + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lshd.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lshd.c new file mode 100644 index 0000000..8234580 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_lshd.c @@ -0,0 +1,51 @@ +#include "tommath_private.h" +#ifdef BN_MP_LSHD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift left a certain amount of digits */ +mp_err mp_lshd(mp_int *a, int b) +{ + int x; + mp_err err; + mp_digit *top, *bottom; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + /* no need to shift 0 around */ + if (MP_IS_ZERO(a)) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < (a->used + b)) { + if ((err = mp_grow(a, a->used + b)) != MP_OKAY) { + return err; + } + } + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = (a->dp + a->used - 1) - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + MP_ZERO_DIGITS(a->dp, b); + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod.c new file mode 100644 index 0000000..8fbfe08 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod.c @@ -0,0 +1,31 @@ +#include "tommath_private.h" +#ifdef BN_MP_MOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */ +mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int t; + mp_err err; + + if ((err = mp_init_size(&t, b->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_div(a, b, NULL, &t)) != MP_OKAY) { + goto LBL_ERR; + } + + if (MP_IS_ZERO(&t) || (t.sign == b->sign)) { + err = MP_OKAY; + mp_exch(&t, c); + } else { + err = mp_add(b, &t, c); + } + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_2d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_2d.c new file mode 100644 index 0000000..5bf57a1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_2d.c @@ -0,0 +1,38 @@ +#include "tommath_private.h" +#ifdef BN_MP_MOD_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* calc a value mod 2**b */ +mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) +{ + int x; + mp_err err; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero(c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (a->used * MP_DIGIT_BIT)) { + return mp_copy(a, c); + } + + /* copy */ + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + + /* zero digits above the last digit of the modulus */ + x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1); + MP_ZERO_DIGITS(c->dp + x, c->used - x); + + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / MP_DIGIT_BIT] &= + ((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1; + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_d.c new file mode 100644 index 0000000..0b6c12a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mod_d.c @@ -0,0 +1,10 @@ +#include "tommath_private.h" +#ifdef BN_MP_MOD_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_err mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c) +{ + return mp_div_d(a, b, NULL, c); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_calc_normalization.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_calc_normalization.c new file mode 100644 index 0000000..8379789 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_calc_normalization.c @@ -0,0 +1,44 @@ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) +{ + int x, bits; + mp_err err; + + /* how many bits of last digit does b use */ + bits = mp_count_bits(b) % MP_DIGIT_BIT; + + if (b->used > 1) { + if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) { + return err; + } + } else { + mp_set(a, 1uL); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) { + if ((err = mp_mul_2(a, a)) != MP_OKAY) { + return err; + } + if (mp_cmp_mag(a, b) != MP_LT) { + if ((err = s_mp_sub(a, b, a)) != MP_OKAY) { + return err; + } + } + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_reduce.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_reduce.c new file mode 100644 index 0000000..ffe8341 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_reduce.c @@ -0,0 +1,102 @@ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) +{ + int ix, digs; + mp_err err; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = (n->used * 2) + 1; + if ((digs < MP_WARRAY) && + (x->used <= MP_WARRAY) && + (n->used < MP_MAXFAST)) { + return s_mp_montgomery_reduce_fast(x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((err = mp_grow(x, digs)) != MP_OKAY) { + return err; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + int iy; + mp_digit *tmpn, *tmpx, u; + mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu * (mp_word)*tmpn++) + + (mp_word)u + (mp_word)*tmpx; + + /* get carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & (mp_word)MP_MASK); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u != 0u) { + *tmpx += u; + u = *tmpx >> MP_DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd(x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag(x, n) != MP_LT) { + return s_mp_sub(x, n, x); + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_setup.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_setup.c new file mode 100644 index 0000000..39f6e9d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_montgomery_setup.c @@ -0,0 +1,42 @@ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* setups the montgomery reduction stuff */ +mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) +{ + mp_digit x, b; + + /* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1u) == 0u) { + return MP_VAL; + } + + x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2u - (b * x); /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2u - (b * x); /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2u - (b * x); /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2u - (b * x); /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK; + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul.c new file mode 100644 index 0000000..561913a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul.c @@ -0,0 +1,52 @@ +#include "tommath_private.h" +#ifdef BN_MP_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level multiplication (handles sign) */ +mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + int min_len = MP_MIN(a->used, b->used), + max_len = MP_MAX(a->used, b->used), + digs = a->used + b->used + 1; + mp_sign neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + if (MP_HAS(S_MP_BALANCE_MUL) && + /* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off. + * The bigger one needs to be at least about one MP_KARATSUBA_MUL_CUTOFF bigger + * to make some sense, but it depends on architecture, OS, position of the + * stars... so YMMV. + * Using it to cut the input into slices small enough for fast_s_mp_mul_digs + * was actually slower on the author's machine, but YMMV. + */ + (min_len >= MP_KARATSUBA_MUL_CUTOFF) && + ((max_len / 2) >= MP_KARATSUBA_MUL_CUTOFF) && + /* Not much effect was observed below a ratio of 1:2, but again: YMMV. */ + (max_len >= (2 * min_len))) { + err = s_mp_balance_mul(a,b,c); + } else if (MP_HAS(S_MP_TOOM_MUL) && + (min_len >= MP_TOOM_MUL_CUTOFF)) { + err = s_mp_toom_mul(a, b, c); + } else if (MP_HAS(S_MP_KARATSUBA_MUL) && + (min_len >= MP_KARATSUBA_MUL_CUTOFF)) { + err = s_mp_karatsuba_mul(a, b, c); + } else if (MP_HAS(S_MP_MUL_DIGS_FAST) && + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + (digs < MP_WARRAY) && + (min_len <= MP_MAXFAST)) { + err = s_mp_mul_digs_fast(a, b, c, digs); + } else if (MP_HAS(S_MP_MUL_DIGS)) { + err = s_mp_mul_digs(a, b, c, digs); + } else { + err = MP_VAL; + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2.c new file mode 100644 index 0000000..bc0691a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2.c @@ -0,0 +1,64 @@ +#include "tommath_private.h" +#ifdef BN_MP_MUL_2_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = a*2 */ +mp_err mp_mul_2(const mp_int *a, mp_int *b) +{ + int x, oldused; + mp_err err; + + /* grow to accomodate result */ + if (b->alloc < (a->used + 1)) { + if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) { + return err; + } + } + + oldused = b->used; + b->used = a->used; + + { + mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> (mp_digit)(MP_DIGIT_BIT - 1); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << 1uL) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0u) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used); + } + b->sign = a->sign; + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2d.c new file mode 100644 index 0000000..87354de --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_2d.c @@ -0,0 +1,69 @@ +#include "tommath_private.h" +#ifdef BN_MP_MUL_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift left by a certain bit count */ +mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) +{ + mp_digit d; + mp_err err; + + /* copy */ + if (a != c) { + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + } + + if (c->alloc < (c->used + (b / MP_DIGIT_BIT) + 1)) { + if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { + return err; + } + } + + /* shift by as many digits in the bit count */ + if (b >= MP_DIGIT_BIT) { + if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) { + return err; + } + } + + /* shift any bit count < MP_DIGIT_BIT */ + d = (mp_digit)(b % MP_DIGIT_BIT); + if (d != 0u) { + mp_digit *tmpc, shift, mask, r, rr; + int x; + + /* bitmask for carries */ + mask = ((mp_digit)1 << d) - (mp_digit)1; + + /* shift for msbs */ + shift = (mp_digit)MP_DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0u) { + c->dp[(c->used)++] = r; + } + } + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_d.c new file mode 100644 index 0000000..b56dfa3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mul_d.c @@ -0,0 +1,61 @@ +#include "tommath_private.h" +#ifdef BN_MP_MUL_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiply by a digit */ +mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + mp_err err; + int ix, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = (mp_word)u + ((mp_word)*tmpa++ * (mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* send carry into next iteration */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mulmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mulmod.c new file mode 100644 index 0000000..160d162 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_mulmod.c @@ -0,0 +1,25 @@ +#include "tommath_private.h" +#ifdef BN_MP_MULMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a * b (mod c) */ +mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init_size(&t, c->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_mul(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_neg.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_neg.c new file mode 100644 index 0000000..264d900 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_neg.c @@ -0,0 +1,24 @@ +#include "tommath_private.h" +#ifdef BN_MP_NEG_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = -a */ +mp_err mp_neg(const mp_int *a, mp_int *b) +{ + mp_err err; + if (a != b) { + if ((err = mp_copy(a, b)) != MP_OKAY) { + return err; + } + } + + if (!MP_IS_ZERO(b)) { + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } else { + b->sign = MP_ZPOS; + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_or.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_or.c new file mode 100644 index 0000000..cdacbfb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_or.c @@ -0,0 +1,56 @@ +#include "tommath_private.h" +#ifdef BN_MP_OR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement or */ +mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = ((a->sign == MP_NEG) || (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x | y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack.c new file mode 100644 index 0000000..6e00b6f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack.c @@ -0,0 +1,69 @@ +#include "tommath_private.h" +#ifdef BN_MP_PACK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* based on gmp's mpz_export. + * see http://gmplib.org/manual/Integer-Import-and-Export.html + */ +mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size, + mp_endian endian, size_t nails, const mp_int *op) +{ + mp_err err; + size_t odd_nails, nail_bytes, i, j, count; + unsigned char odd_nail_mask; + + mp_int t; + + count = mp_pack_count(op, nails, size); + + if (count > maxcount) { + return MP_BUF; + } + + if ((err = mp_init_copy(&t, op)) != MP_OKAY) { + return err; + } + + if (endian == MP_NATIVE_ENDIAN) { + MP_GET_ENDIANNESS(endian); + } + + odd_nails = (nails % 8u); + odd_nail_mask = 0xff; + for (i = 0u; i < odd_nails; ++i) { + odd_nail_mask ^= (unsigned char)(1u << (7u - i)); + } + nail_bytes = nails / 8u; + + for (i = 0u; i < count; ++i) { + for (j = 0u; j < size; ++j) { + unsigned char *byte = (unsigned char *)rop + + (((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) + + ((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j)); + + if (j >= (size - nail_bytes)) { + *byte = 0; + continue; + } + + *byte = (unsigned char)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL)); + + if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + + } + } + + if (written != NULL) { + *written = count; + } + err = MP_OKAY; + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack_count.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack_count.c new file mode 100644 index 0000000..dfecdf9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_pack_count.c @@ -0,0 +1,12 @@ +#include "tommath_private.h" +#ifdef BN_MP_PACK_COUNT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) +{ + size_t bits = (size_t)mp_count_bits(a); + return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u)); +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_fermat.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_fermat.c new file mode 100644 index 0000000..af3e884 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_fermat.c @@ -0,0 +1,47 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_FERMAT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* performs one Fermat test. + * + * If "a" were prime then b**a == b (mod a) since the order of + * the multiplicative sub-group would be phi(a) = a-1. That means + * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a). + * + * Sets result to 1 if the congruence holds, or zero otherwise. + */ +mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, mp_bool *result) +{ + mp_int t; + mp_err err; + + /* default to composite */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1uL) != MP_GT) { + return MP_VAL; + } + + /* init t */ + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + /* compute t = b**a mod a */ + if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) { + goto LBL_T; + } + + /* is it equal to b? */ + if (mp_cmp(&t, b) == MP_EQ) { + *result = MP_YES; + } + + err = MP_OKAY; +LBL_T: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_frobenius_underwood.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_frobenius_underwood.c new file mode 100644 index 0000000..253e8d5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_frobenius_underwood.c @@ -0,0 +1,132 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_FROBENIUS_UNDERWOOD_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details + */ +#ifndef LTM_USE_ONLY_MR + +#ifdef MP_8BIT +/* + * floor of positive solution of + * (2^16)-1 = (a+4)*(2*a+5) + * TODO: Both values are smaller than N^(1/4), would have to use a bigint + * for a instead but any a biger than about 120 are already so rare that + * it is possible to ignore them and still get enough pseudoprimes. + * But it is still a restriction of the set of available pseudoprimes + * which makes this implementation less secure if used stand-alone. + */ +#define LTM_FROBENIUS_UNDERWOOD_A 177 +#else +#define LTM_FROBENIUS_UNDERWOOD_A 32764 +#endif +mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result) +{ + mp_int T1z, T2z, Np1z, sz, tz; + + int a, ap2, length, i, j; + mp_err err; + + *result = MP_NO; + + if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) { + return err; + } + + for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) { + /* TODO: That's ugly! No, really, it is! */ + if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) || + (a==14) || (a==18) || (a==23) || (a==26) || (a==28)) { + continue; + } + /* (32764^2 - 4) < 2^31, no bigint for >MP_8BIT needed) */ + mp_set_u32(&T1z, (uint32_t)a); + + if ((err = mp_sqr(&T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if ((err = mp_sub_d(&T1z, 4uL, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_FU_ERR; + + if (j == -1) { + break; + } + + if (j == 0) { + /* composite */ + goto LBL_FU_ERR; + } + } + /* Tell it a composite and set return value accordingly */ + if (a >= LTM_FROBENIUS_UNDERWOOD_A) { + err = MP_ITER; + goto LBL_FU_ERR; + } + /* Composite if N and (a+4)*(2*a+5) are not coprime */ + mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5))); + + if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) goto LBL_FU_ERR; + + ap2 = a + 2; + if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_FU_ERR; + + mp_set(&sz, 1uL); + mp_set(&tz, 2uL); + length = mp_count_bits(&Np1z); + + for (i = length - 2; i >= 0; i--) { + /* + * temp = (sz*(a*sz+2*tz))%N; + * tz = ((tz-sz)*(tz+sz))%N; + * sz = temp; + */ + if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + + /* a = 0 at about 50% of the cases (non-square and odd input) */ + if (a != 0) { + if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + } + + if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_FU_ERR; + if (s_mp_get_bit(&Np1z, (unsigned int)i) == MP_YES) { + /* + * temp = (a+2) * sz + tz + * tz = 2 * tz - sz + * sz = temp + */ + if (a == 0) { + if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + } else { + if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + } + if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_FU_ERR; + mp_exch(&sz, &T1z); + } + } + + mp_set_u32(&T1z, (uint32_t)((2 * a) + 5)); + if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if (MP_IS_ZERO(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ)) { + *result = MP_YES; + } + +LBL_FU_ERR: + mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL); + return err; +} + +#endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_is_prime.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_is_prime.c new file mode 100644 index 0000000..7f9fc0b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_is_prime.c @@ -0,0 +1,314 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_IS_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* portable integer log of two with small footprint */ +static unsigned int s_floor_ilog2(int value) +{ + unsigned int r = 0; + while ((value >>= 1) != 0) { + r++; + } + return r; +} + + +mp_err mp_prime_is_prime(const mp_int *a, int t, mp_bool *result) +{ + mp_int b; + int ix, p_max = 0, size_a, len; + mp_bool res; + mp_err err; + unsigned int fips_rand, mask; + + /* default to no */ + *result = MP_NO; + + /* Some shortcuts */ + /* N > 3 */ + if (a->used == 1) { + if ((a->dp[0] == 0u) || (a->dp[0] == 1u)) { + *result = MP_NO; + return MP_OKAY; + } + if (a->dp[0] == 2u) { + *result = MP_YES; + return MP_OKAY; + } + } + + /* N must be odd */ + if (MP_IS_EVEN(a)) { + return MP_OKAY; + } + /* N is not a perfect square: floor(sqrt(N))^2 != N */ + if ((err = mp_is_square(a, &res)) != MP_OKAY) { + return err; + } + if (res != MP_NO) { + return MP_OKAY; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) { + if (mp_cmp_d(a, s_mp_prime_tab[ix]) == MP_EQ) { + *result = MP_YES; + return MP_OKAY; + } + } +#ifdef MP_8BIT + /* The search in the loop above was exhaustive in this case */ + if ((a->used == 1) && (PRIVATE_MP_PRIME_TAB_SIZE >= 31)) { + return MP_OKAY; + } +#endif + + /* first perform trial division */ + if ((err = s_mp_prime_is_divisible(a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* + Run the Miller-Rabin test with base 2 for the BPSW test. + */ + if ((err = mp_init_set(&b, 2uL)) != MP_OKAY) { + return err; + } + + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + /* + Rumours have it that Mathematica does a second M-R test with base 3. + Other rumours have it that their strong L-S test is slightly different. + It does not hurt, though, beside a bit of extra runtime. + */ + b.dp[0]++; + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + + /* + * Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite + * slow so if speed is an issue, define LTM_USE_ONLY_MR to use M-R tests with + * bases 2, 3 and t random bases. + */ +#ifndef LTM_USE_ONLY_MR + if (t >= 0) { + /* + * Use a Frobenius-Underwood test instead of the Lucas-Selfridge test for + * MP_8BIT (It is unknown if the Lucas-Selfridge test works with 16-bit + * integers but the necesssary analysis is on the todo-list). + */ +#if defined (MP_8BIT) || defined (LTM_USE_FROBENIUS_TEST) + err = mp_prime_frobenius_underwood(a, &res); + if ((err != MP_OKAY) && (err != MP_ITER)) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } +#else + if ((err = mp_prime_strong_lucas_selfridge(a, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } +#endif + } +#endif + + /* run at least one Miller-Rabin test with a random base */ + if (t == 0) { + t = 1; + } + + /* + Only recommended if the input range is known to be < 3317044064679887385961981 + + It uses the bases necessary for a deterministic M-R test if the input is + smaller than 3317044064679887385961981 + The caller has to check the size. + TODO: can be made a bit finer grained but comparing is not free. + */ + if (t < 0) { + /* + Sorenson, Jonathan; Webster, Jonathan (2015). + "Strong Pseudoprimes to Twelve Prime Bases". + */ + /* 0x437ae92817f9fc85b7e5 = 318665857834031151167461 */ + if ((err = mp_read_radix(&b, "437ae92817f9fc85b7e5", 16)) != MP_OKAY) { + goto LBL_B; + } + + if (mp_cmp(a, &b) == MP_LT) { + p_max = 12; + } else { + /* 0x2be6951adc5b22410a5fd = 3317044064679887385961981 */ + if ((err = mp_read_radix(&b, "2be6951adc5b22410a5fd", 16)) != MP_OKAY) { + goto LBL_B; + } + + if (mp_cmp(a, &b) == MP_LT) { + p_max = 13; + } else { + err = MP_VAL; + goto LBL_B; + } + } + + /* we did bases 2 and 3 already, skip them */ + for (ix = 2; ix < p_max; ix++) { + mp_set(&b, s_mp_prime_tab[ix]); + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + } + } + /* + Do "t" M-R tests with random bases between 3 and "a". + See Fips 186.4 p. 126ff + */ + else if (t > 0) { + /* + * The mp_digit's have a defined bit-size but the size of the + * array a.dp is a simple 'int' and this library can not assume full + * compliance to the current C-standard (ISO/IEC 9899:2011) because + * it gets used for small embeded processors, too. Some of those MCUs + * have compilers that one cannot call standard compliant by any means. + * Hence the ugly type-fiddling in the following code. + */ + size_a = mp_count_bits(a); + mask = (1u << s_floor_ilog2(size_a)) - 1u; + /* + Assuming the General Rieman hypothesis (never thought to write that in a + comment) the upper bound can be lowered to 2*(log a)^2. + E. Bach, "Explicit bounds for primality testing and related problems," + Math. Comp. 55 (1990), 355-380. + + size_a = (size_a/10) * 7; + len = 2 * (size_a * size_a); + + E.g.: a number of size 2^2048 would be reduced to the upper limit + + floor(2048/10)*7 = 1428 + 2 * 1428^2 = 4078368 + + (would have been ~4030331.9962 with floats and natural log instead) + That number is smaller than 2^28, the default bit-size of mp_digit. + */ + + /* + How many tests, you might ask? Dana Jacobsen of Math::Prime::Util fame + does exactly 1. In words: one. Look at the end of _GMP_is_prime() in + Math-Prime-Util-GMP-0.50/primality.c if you do not believe it. + + The function mp_rand() goes to some length to use a cryptographically + good PRNG. That also means that the chance to always get the same base + in the loop is non-zero, although very low. + If the BPSW test and/or the addtional Frobenious test have been + performed instead of just the Miller-Rabin test with the bases 2 and 3, + a single extra test should suffice, so such a very unlikely event + will not do much harm. + + To preemptivly answer the dangling question: no, a witness does not + need to be prime. + */ + for (ix = 0; ix < t; ix++) { + /* mp_rand() guarantees the first digit to be non-zero */ + if ((err = mp_rand(&b, 1)) != MP_OKAY) { + goto LBL_B; + } + /* + * Reduce digit before casting because mp_digit might be bigger than + * an unsigned int and "mask" on the other side is most probably not. + */ + fips_rand = (unsigned int)(b.dp[0] & (mp_digit) mask); +#ifdef MP_8BIT + /* + * One 8-bit digit is too small, so concatenate two if the size of + * unsigned int allows for it. + */ + if ((MP_SIZEOF_BITS(unsigned int)/2) >= MP_SIZEOF_BITS(mp_digit)) { + if ((err = mp_rand(&b, 1)) != MP_OKAY) { + goto LBL_B; + } + fips_rand <<= MP_SIZEOF_BITS(mp_digit); + fips_rand |= (unsigned int) b.dp[0]; + fips_rand &= mask; + } +#endif + if (fips_rand > (unsigned int)(INT_MAX - MP_DIGIT_BIT)) { + len = INT_MAX / MP_DIGIT_BIT; + } else { + len = (((int)fips_rand + MP_DIGIT_BIT) / MP_DIGIT_BIT); + } + /* Unlikely. */ + if (len < 0) { + ix--; + continue; + } + /* + * As mentioned above, one 8-bit digit is too small and + * although it can only happen in the unlikely case that + * an "unsigned int" is smaller than 16 bit a simple test + * is cheap and the correction even cheaper. + */ +#ifdef MP_8BIT + /* All "a" < 2^8 have been caught before */ + if (len == 1) { + len++; + } +#endif + if ((err = mp_rand(&b, len)) != MP_OKAY) { + goto LBL_B; + } + /* + * That number might got too big and the witness has to be + * smaller than "a" + */ + len = mp_count_bits(&b); + if (len >= size_a) { + len = (len - size_a) + 1; + if ((err = mp_div_2d(&b, len, &b, NULL)) != MP_OKAY) { + goto LBL_B; + } + } + /* Although the chance for b <= 3 is miniscule, try again. */ + if (mp_cmp_d(&b, 3uL) != MP_GT) { + ix--; + continue; + } + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + } + } + + /* passed the test */ + *result = MP_YES; +LBL_B: + mp_clear(&b); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_miller_rabin.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_miller_rabin.c new file mode 100644 index 0000000..96470db --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_miller_rabin.c @@ -0,0 +1,91 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_MILLER_RABIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, mp_bool *result) +{ + mp_int n1, y, r; + mp_err err; + int s, j; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1uL) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy(&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) { + goto LBL_R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init(&y)) != MP_OKAY) { + goto LBL_R; + } + if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y != 1 and y != n1 do */ + if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) { + if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d(&y, 1uL) == MP_EQ) { + goto LBL_Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp(&y, &n1) != MP_EQ) { + goto LBL_Y; + } + } + + /* probably prime now */ + *result = MP_YES; +LBL_Y: + mp_clear(&y); +LBL_R: + mp_clear(&r); +LBL_N1: + mp_clear(&n1); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_next_prime.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_next_prime.c new file mode 100644 index 0000000..d656565 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_next_prime.c @@ -0,0 +1,132 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_NEXT_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +mp_err mp_prime_next_prime(mp_int *a, int t, int bbs_style) +{ + int x, y; + mp_ord cmp; + mp_err err; + mp_bool res = MP_NO; + mp_digit res_tab[PRIVATE_MP_PRIME_TAB_SIZE], step, kstep; + mp_int b; + + /* force positive */ + a->sign = MP_ZPOS; + + /* simple algo if a is less than the largest prime in the table */ + if (mp_cmp_d(a, s_mp_prime_tab[PRIVATE_MP_PRIME_TAB_SIZE-1]) == MP_LT) { + /* find which prime it is bigger than "a" */ + for (x = 0; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + cmp = mp_cmp_d(a, s_mp_prime_tab[x]); + if (cmp == MP_EQ) { + continue; + } + if (cmp != MP_GT) { + if ((bbs_style == 1) && ((s_mp_prime_tab[x] & 3u) != 3u)) { + /* try again until we get a prime congruent to 3 mod 4 */ + continue; + } else { + mp_set(a, s_mp_prime_tab[x]); + return MP_OKAY; + } + } + } + /* fall through to the sieve */ + } + + /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */ + if (bbs_style == 1) { + kstep = 4; + } else { + kstep = 2; + } + + /* at this point we will use a combination of a sieve and Miller-Rabin */ + + if (bbs_style == 1) { + /* if a mod 4 != 3 subtract the correct value to make it so */ + if ((a->dp[0] & 3u) != 3u) { + if ((err = mp_sub_d(a, (a->dp[0] & 3u) + 1u, a)) != MP_OKAY) { + return err; + } + } + } else { + if (MP_IS_EVEN(a)) { + /* force odd */ + if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) { + return err; + } + } + } + + /* generate the restable */ + for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + if ((err = mp_mod_d(a, s_mp_prime_tab[x], res_tab + x)) != MP_OKAY) { + return err; + } + } + + /* init temp used for Miller-Rabin Testing */ + if ((err = mp_init(&b)) != MP_OKAY) { + return err; + } + + for (;;) { + /* skip to the next non-trivially divisible candidate */ + step = 0; + do { + /* y == 1 if any residue was zero [e.g. cannot be prime] */ + y = 0; + + /* increase step to next candidate */ + step += kstep; + + /* compute the new residue without using division */ + for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + /* add the step to each residue */ + res_tab[x] += kstep; + + /* subtract the modulus [instead of using division] */ + if (res_tab[x] >= s_mp_prime_tab[x]) { + res_tab[x] -= s_mp_prime_tab[x]; + } + + /* set flag if zero */ + if (res_tab[x] == 0u) { + y = 1; + } + } + } while ((y == 1) && (step < (((mp_digit)1 << MP_DIGIT_BIT) - kstep))); + + /* add the step */ + if ((err = mp_add_d(a, step, a)) != MP_OKAY) { + goto LBL_ERR; + } + + /* if didn't pass sieve and step == MP_MAX then skip test */ + if ((y == 1) && (step >= (((mp_digit)1 << MP_DIGIT_BIT) - kstep))) { + continue; + } + + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto LBL_ERR; + } + if (res == MP_YES) { + break; + } + } + + err = MP_OKAY; +LBL_ERR: + mp_clear(&b); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rabin_miller_trials.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rabin_miller_trials.c new file mode 100644 index 0000000..8bbaf6c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rabin_miller_trials.c @@ -0,0 +1,47 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +static const struct { + int k, t; +} sizes[] = { + { 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */ + { 81, 37 }, /* max. error = 2^(-96)*/ + { 96, 32 }, /* max. error = 2^(-96)*/ + { 128, 40 }, /* max. error = 2^(-112)*/ + { 160, 35 }, /* max. error = 2^(-112)*/ + { 256, 27 }, /* max. error = 2^(-128)*/ + { 384, 16 }, /* max. error = 2^(-128)*/ + { 512, 18 }, /* max. error = 2^(-160)*/ + { 768, 11 }, /* max. error = 2^(-160)*/ + { 896, 10 }, /* max. error = 2^(-160)*/ + { 1024, 12 }, /* max. error = 2^(-192)*/ + { 1536, 8 }, /* max. error = 2^(-192)*/ + { 2048, 6 }, /* max. error = 2^(-192)*/ + { 3072, 4 }, /* max. error = 2^(-192)*/ + { 4096, 5 }, /* max. error = 2^(-256)*/ + { 5120, 4 }, /* max. error = 2^(-256)*/ + { 6144, 4 }, /* max. error = 2^(-256)*/ + { 8192, 3 }, /* max. error = 2^(-256)*/ + { 9216, 3 }, /* max. error = 2^(-256)*/ + { 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */ +}; + +/* returns # of RM trials required for a given bit size */ +int mp_prime_rabin_miller_trials(int size) +{ + int x; + + for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) { + if (sizes[x].k == size) { + return sizes[x].t; + } else if (sizes[x].k > size) { + return (x == 0) ? sizes[0].t : sizes[x - 1].t; + } + } + return sizes[x-1].t; +} + + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rand.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rand.c new file mode 100644 index 0000000..23a1c4f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_rand.c @@ -0,0 +1,141 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_RAND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * MP_PRIME_BBS - make prime congruent to 3 mod 4 + * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS) + * MP_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ + +/* This is possibly the mother of all prime generation functions, muahahahahaha! */ +mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int bsize, maskOR_msb_offset; + mp_bool res; + mp_err err; + + /* sanity check the input */ + if ((size <= 1) || (t <= 0)) { + return MP_VAL; + } + + /* MP_PRIME_SAFE implies MP_PRIME_BBS */ + if ((flags & MP_PRIME_SAFE) != 0) { + flags |= MP_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3) + ((size&7)?1:0); + + /* we need a buffer of bsize bytes */ + tmp = (unsigned char *) MP_CALLOC(1, (size_t)bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = ((size&7) == 0) ? 0xFFu : (unsigned char)(0xFFu >> (8 - (size & 7))); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0; + if ((flags & MP_PRIME_2MSB_ON) != 0) { + maskOR_msb |= (unsigned char)(0x80 >> ((9 - size) & 7)); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 1u; + if ((flags & MP_PRIME_BBS) != 0) { + maskOR_lsb |= 3u; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= (unsigned char)(1 << ((size - 1) & 7)); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + /* TODO: casting only for now until all lengths have been changed to the type "size_t"*/ + if ((err = mp_from_ubin(a, tmp, (size_t)bsize)) != MP_OKAY) { + goto error; + } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto error; + } + if (res == MP_NO) { + continue; + } + + if ((flags & MP_PRIME_SAFE) != 0) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) { + goto error; + } + if ((err = mp_div_2(a, a)) != MP_OKAY) { + goto error; + } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto error; + } + } + } while (res == MP_NO); + + if ((flags & MP_PRIME_SAFE) != 0) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { + goto error; + } + if ((err = mp_add_d(a, 1uL, a)) != MP_OKAY) { + goto error; + } + } + + err = MP_OKAY; +error: + MP_FREE_BUFFER(tmp, (size_t)bsize); + return err; +} + +static int s_mp_rand_cb(unsigned char *dst, int len, void *dat) +{ + (void)dat; + if (len <= 0) { + return len; + } + if (s_mp_rand_source(dst, (size_t)len) != MP_OKAY) { + return 0; + } + return len; +} + +mp_err mp_prime_rand(mp_int *a, int t, int size, int flags) +{ + return s_mp_prime_random_ex(a, t, size, flags, s_mp_rand_cb, NULL); +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_strong_lucas_selfridge.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_strong_lucas_selfridge.c new file mode 100644 index 0000000..b50bbcd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_prime_strong_lucas_selfridge.c @@ -0,0 +1,289 @@ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details + */ +#ifndef LTM_USE_ONLY_MR + +/* + * 8-bit is just too small. You can try the Frobenius test + * but that frobenius test can fail, too, for the same reason. + */ +#ifndef MP_8BIT + +/* + * multiply bigint a with int d and put the result in c + * Like mp_mul_d() but with a signed long as the small input + */ +static mp_err s_mp_mul_si(const mp_int *a, int32_t d, mp_int *c) +{ + mp_int t; + mp_err err; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + /* + * mp_digit might be smaller than a long, which excludes + * the use of mp_mul_d() here. + */ + mp_set_i32(&t, d); + err = mp_mul(a, &t, c); + mp_clear(&t); + return err; +} +/* + Strong Lucas-Selfridge test. + returns MP_YES if it is a strong L-S prime, MP_NO if it is composite + + Code ported from Thomas Ray Nicely's implementation of the BPSW test + at http://www.trnicely.net/misc/bpsw.html + + Freeware copyright (C) 2016 Thomas R. Nicely . + Released into the public domain by the author, who disclaims any legal + liability arising from its use + + The multi-line comments are made by Thomas R. Nicely and are copied verbatim. + Additional comments marked "CZ" (without the quotes) are by the code-portist. + + (If that name sounds familiar, he is the guy who found the fdiv bug in the + Pentium (P5x, I think) Intel processor) +*/ +mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, mp_bool *result) +{ + /* CZ TODO: choose better variable names! */ + mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz; + /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */ + int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits; + mp_err err; + mp_bool oddness; + + *result = MP_NO; + /* + Find the first element D in the sequence {5, -7, 9, -11, 13, ...} + such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory + indicates that, if N is not a perfect square, D will "nearly + always" be "small." Just in case, an overflow trap for D is + included. + */ + + if ((err = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz, + NULL)) != MP_OKAY) { + return err; + } + + D = 5; + sign = 1; + + for (;;) { + Ds = sign * D; + sign = -sign; + mp_set_u32(&Dz, (uint32_t)D); + if ((err = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) goto LBL_LS_ERR; + + /* if 1 < GCD < N then N is composite with factor "D", and + Jacobi(D,N) is technically undefined (but often returned + as zero). */ + if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) { + goto LBL_LS_ERR; + } + if (Ds < 0) { + Dz.sign = MP_NEG; + } + if ((err = mp_kronecker(&Dz, a, &J)) != MP_OKAY) goto LBL_LS_ERR; + + if (J == -1) { + break; + } + D += 2; + + if (D > (INT_MAX - 2)) { + err = MP_VAL; + goto LBL_LS_ERR; + } + } + + + + P = 1; /* Selfridge's choice */ + Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */ + + /* NOTE: The conditions (a) N does not divide Q, and + (b) D is square-free or not a perfect square, are included by + some authors; e.g., "Prime numbers and computer methods for + factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston), + p. 130. For this particular application of Lucas sequences, + these conditions were found to be immaterial. */ + + /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the + odd positive integer d and positive integer s for which + N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test). + The strong Lucas-Selfridge test then returns N as a strong + Lucas probable prime (slprp) if any of the following + conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0, + V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0 + (all equalities mod N). Thus d is the highest index of U that + must be computed (since V_2m is independent of U), compared + to U_{N+1} for the standard Lucas-Selfridge test; and no + index of V beyond (N+1)/2 is required, just as in the + standard Lucas-Selfridge test. However, the quantity Q^d must + be computed for use (if necessary) in the latter stages of + the test. The result is that the strong Lucas-Selfridge test + has a running time only slightly greater (order of 10 %) than + that of the standard Lucas-Selfridge test, while producing + only (roughly) 30 % as many pseudoprimes (and every strong + Lucas pseudoprime is also a standard Lucas pseudoprime). Thus + the evidence indicates that the strong Lucas-Selfridge test is + more effective than the standard Lucas-Selfridge test, and a + Baillie-PSW test based on the strong Lucas-Selfridge test + should be more reliable. */ + + if ((err = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) goto LBL_LS_ERR; + s = mp_cnt_lsb(&Np1); + + /* CZ + * This should round towards zero because + * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp() + * and mp_div_2d() is equivalent. Additionally: + * dividing an even number by two does not produce + * any leftovers. + */ + if ((err = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) goto LBL_LS_ERR; + /* We must now compute U_d and V_d. Since d is odd, the accumulated + values U and V are initialized to U_1 and V_1 (if the target + index were even, U and V would be initialized instead to U_0=0 + and V_0=2). The values of U_2m and V_2m are also initialized to + U_1 and V_1; the FOR loop calculates in succession U_2 and V_2, + U_4 and V_4, U_8 and V_8, etc. If the corresponding bits + (1, 2, 3, ...) of t are on (the zero bit having been accounted + for in the initialization of U and V), these values are then + combined with the previous totals for U and V, using the + composition formulas for addition of indices. */ + + mp_set(&Uz, 1uL); /* U=U_1 */ + mp_set(&Vz, (mp_digit)P); /* V=V_1 */ + mp_set(&U2mz, 1uL); /* U_1 */ + mp_set(&V2mz, (mp_digit)P); /* V_1 */ + + mp_set_i32(&Qmz, Q); + if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR; + /* Initializes calculation of Q^d */ + mp_set_i32(&Qkdz, Q); + + Nbits = mp_count_bits(&Dz); + + for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */ + /* Formulas for doubling of indices (carried out mod N). Note that + * the indices denoted as "2m" are actually powers of 2, specifically + * 2^(ul-1) beginning each loop and 2^ul ending each loop. + * + * U_2m = U_m*V_m + * V_2m = V_m*V_m - 2*Q^m + */ + + if ((err = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + + /* Must calculate powers of Q for use in V_2m, also for Q^d later */ + if ((err = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) goto LBL_LS_ERR; + + /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */ + if ((err = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR; + + if (s_mp_get_bit(&Dz, (unsigned int)u) == MP_YES) { + /* Formulas for addition of indices (carried out mod N); + * + * U_(m+n) = (U_m*V_n + U_n*V_m)/2 + * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2 + * + * Be careful with division by 2 (mod N)! + */ + if ((err = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = s_mp_mul_si(&T4z, Ds, &T4z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ODD(&Uz)) { + if ((err = mp_add(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + } + /* CZ + * This should round towards negative infinity because + * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp(). + * But mp_div_2() does not do so, it is truncating instead. + */ + oddness = MP_IS_ODD(&Uz) ? MP_YES : MP_NO; + if ((err = mp_div_2(&Uz, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if ((Uz.sign == MP_NEG) && (oddness != MP_NO)) { + if ((err = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + } + if ((err = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ODD(&Vz)) { + if ((err = mp_add(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + } + oddness = MP_IS_ODD(&Vz) ? MP_YES : MP_NO; + if ((err = mp_div_2(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((Vz.sign == MP_NEG) && (oddness != MP_NO)) { + if ((err = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + } + if ((err = mp_mod(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + + /* Calculating Q^d for later use */ + if ((err = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + } + } + + /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a + strong Lucas pseudoprime. */ + if (MP_IS_ZERO(&Uz) || MP_IS_ZERO(&Vz)) { + *result = MP_YES; + goto LBL_LS_ERR; + } + + /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed., + 1995/6) omits the condition V0 on p.142, but includes it on + p. 130. The condition is NECESSARY; otherwise the test will + return false negatives---e.g., the primes 29 and 2000029 will be + returned as composite. */ + + /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d} + by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of + these are congruent to 0 mod N, then N is a prime or a strong + Lucas pseudoprime. */ + + /* Initialize 2*Q^(d*2^r) for V_2m */ + if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR; + + for (r = 1; r < s; r++) { + if ((err = mp_sqr(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ZERO(&Vz)) { + *result = MP_YES; + goto LBL_LS_ERR; + } + /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */ + if (r < (s - 1)) { + if ((err = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR; + } + } +LBL_LS_ERR: + mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL); + return err; +} +#endif +#endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_size.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_size.c new file mode 100644 index 0000000..b96f487 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_size.c @@ -0,0 +1,65 @@ +#include "tommath_private.h" +#ifdef BN_MP_RADIX_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* returns size of ASCII representation */ +mp_err mp_radix_size(const mp_int *a, int radix, int *size) +{ + mp_err err; + int digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* make sure the radix is in range */ + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + if (MP_IS_ZERO(a)) { + *size = 2; + return MP_OKAY; + } + + /* special case for binary */ + if (radix == 2) { + *size = (mp_count_bits(a) + ((a->sign == MP_NEG) ? 1 : 0) + 1); + return MP_OKAY; + } + + /* digs is the digit count */ + digs = 0; + + /* if it's negative add one for the sign */ + if (a->sign == MP_NEG) { + ++digs; + } + + /* init a copy of the input */ + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + /* force temp to positive */ + t.sign = MP_ZPOS; + + /* fetch out all of the digits */ + while (!MP_IS_ZERO(&t)) { + if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { + goto LBL_ERR; + } + ++digs; + } + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + err = MP_OKAY; + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_smap.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_smap.c new file mode 100644 index 0000000..a16128d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_radix_smap.c @@ -0,0 +1,22 @@ +#include "tommath_private.h" +#ifdef BN_MP_RADIX_SMAP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* chars used in radix conversions */ +const char *const mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; +const uint8_t mp_s_rmap_reverse[] = { + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* ()*+,-./ */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */ + 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 89:;<=>? */ + 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* @ABCDEFG */ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* HIJKLMNO */ + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* PQRSTUVW */ + 0x21, 0x22, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, /* XYZ[\]^_ */ + 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, /* `abcdefg */ + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, /* hijklmno */ + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, /* pqrstuvw */ + 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, /* xyz{|}~. */ +}; +const size_t mp_s_rmap_reverse_sz = sizeof(mp_s_rmap_reverse); +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rand.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rand.c new file mode 100644 index 0000000..7e9052c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rand.c @@ -0,0 +1,46 @@ +#include "tommath_private.h" +#ifdef BN_MP_RAND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform; + +void mp_rand_source(mp_err(*source)(void *out, size_t size)) +{ + s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source; +} + +mp_err mp_rand(mp_int *a, int digits) +{ + int i; + mp_err err; + + mp_zero(a); + + if (digits <= 0) { + return MP_OKAY; + } + + if ((err = mp_grow(a, digits)) != MP_OKAY) { + return err; + } + + if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) { + return err; + } + + /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */ + while ((a->dp[digits - 1] & MP_MASK) == 0u) { + if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) { + return err; + } + } + + a->used = digits; + for (i = 0; i < digits; ++i) { + a->dp[i] &= MP_MASK; + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_read_radix.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_read_radix.c new file mode 100644 index 0000000..de18e06 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_read_radix.c @@ -0,0 +1,79 @@ +#include "tommath_private.h" +#ifdef BN_MP_READ_RADIX_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#define MP_TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (((c) + 'A') - 'a') : (c)) + +/* read a string [ASCII] in a given radix */ +mp_err mp_read_radix(mp_int *a, const char *str, int radix) +{ + mp_err err; + int y; + mp_sign neg; + unsigned pos; + char ch; + + /* zero the digit bignum */ + mp_zero(a); + + /* make sure the radix is ok */ + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + /* set the integer to the default of zero */ + mp_zero(a); + + /* process each digit of the string */ + while (*str != '\0') { + /* if the radix <= 36 the conversion is case insensitive + * this allows numbers like 1AB and 1ab to represent the same value + * [e.g. in hex] + */ + ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str; + pos = (unsigned)(ch - '('); + if (mp_s_rmap_reverse_sz < pos) { + break; + } + y = (int)mp_s_rmap_reverse[pos]; + + /* if the char was found in the map + * and is less than the given radix add it + * to the number, otherwise exit the loop. + */ + if ((y == 0xff) || (y >= radix)) { + break; + } + if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) { + return err; + } + ++str; + } + + /* if an illegal character was found, fail. */ + if (!((*str == '\0') || (*str == '\r') || (*str == '\n'))) { + mp_zero(a); + return MP_VAL; + } + + /* set the sign only if a != 0 */ + if (!MP_IS_ZERO(a)) { + a->sign = neg; + } + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce.c new file mode 100644 index 0000000..3c669d4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce.c @@ -0,0 +1,83 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) +{ + mp_int q; + mp_err err; + int um = m->used; + + /* q = x */ + if ((err = mp_init_copy(&q, x)) != MP_OKAY) { + return err; + } + + /* q1 = x / b**(k-1) */ + mp_rshd(&q, um - 1); + + /* according to HAC this optimization is ok */ + if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) { + if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else if (MP_HAS(S_MP_MUL_HIGH_DIGS)) { + if ((err = s_mp_mul_high_digs(&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } + } else if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)) { + if ((err = s_mp_mul_high_digs_fast(&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } + } else { + err = MP_VAL; + goto CLEANUP; + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd(&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((err = s_mp_mul_digs(&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((err = mp_sub(x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d(x, 0uL) == MP_LT) { + mp_set(&q, 1uL); + if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((err = mp_add(x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp(x, m) != MP_LT) { + if ((err = s_mp_sub(x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear(&q); + + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k.c new file mode 100644 index 0000000..1cea6cb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k.c @@ -0,0 +1,48 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces a modulo n where n is of the form 2**p - d */ +mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) +{ + mp_int q; + mp_err err; + int p; + + if ((err = mp_init(&q)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (d != 1u) { + /* q = q * d */ + if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* a = a + q */ + if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { + goto LBL_ERR; + } + goto top; + } + +LBL_ERR: + mp_clear(&q); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_l.c new file mode 100644 index 0000000..6a9f3d3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_l.c @@ -0,0 +1,49 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) +{ + mp_int q; + mp_err err; + int p; + + if ((err = mp_init(&q)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + /* q = q * d */ + if ((err = mp_mul(&q, d, &q)) != MP_OKAY) { + goto LBL_ERR; + } + + /* a = a + q */ + if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { + goto LBL_ERR; + } + goto top; + } + +LBL_ERR: + mp_clear(&q); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup.c new file mode 100644 index 0000000..2eaf7ad --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup.c @@ -0,0 +1,32 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) +{ + mp_err err; + mp_int tmp; + int p; + + if ((err = mp_init(&tmp)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(a); + if ((err = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return err; + } + + if ((err = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return err; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup_l.c new file mode 100644 index 0000000..4f9aa14 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_2k_setup_l.c @@ -0,0 +1,28 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_SETUP_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) +{ + mp_err err; + mp_int tmp; + + if ((err = mp_init(&tmp)) != MP_OKAY) { + return err; + } + + if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto LBL_ERR; + } + +LBL_ERR: + mp_clear(&tmp); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k.c new file mode 100644 index 0000000..a9f4f9f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k.c @@ -0,0 +1,38 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_IS_2K_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if mp_reduce_2k can be used */ +mp_bool mp_reduce_is_2k(const mp_int *a) +{ + int ix, iy, iw; + mp_digit iz; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + iy = mp_count_bits(a); + iz = 1; + iw = 1; + + /* Test every bit from the second digit up, must be 1 */ + for (ix = MP_DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0u) { + return MP_NO; + } + iz <<= 1; + if (iz > MP_DIGIT_MAX) { + ++iw; + iz = 1; + } + } + return MP_YES; + } else { + return MP_YES; + } +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k_l.c new file mode 100644 index 0000000..4bc69be --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_is_2k_l.c @@ -0,0 +1,28 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_IS_2K_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if reduce_2k_l can be used */ +mp_bool mp_reduce_is_2k_l(const mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + /* if more than half of the digits are -1 we're sold */ + for (iy = ix = 0; ix < a->used; ix++) { + if (a->dp[ix] == MP_DIGIT_MAX) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + } else { + return MP_NO; + } +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_setup.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_setup.c new file mode 100644 index 0000000..f02160f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_reduce_setup.c @@ -0,0 +1,17 @@ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +mp_err mp_reduce_setup(mp_int *a, const mp_int *b) +{ + mp_err err; + if ((err = mp_2expt(a, b->used * 2 * MP_DIGIT_BIT)) != MP_OKAY) { + return err; + } + return mp_div(a, b, a, NULL); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_root_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_root_u32.c new file mode 100644 index 0000000..97b1b2e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_root_u32.c @@ -0,0 +1,142 @@ +#include "tommath_private.h" +#ifdef BN_MP_ROOT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* find the n'th root of an integer + * + * Result found such that (c)**b <= a and (c+1)**b > a + * + * This algorithm uses Newton's approximation + * x[i+1] = x[i] - f(x[i])/f'(x[i]) + * which will find the root in log(N) time where + * each step involves a fair bit. + */ +mp_err mp_root_u32(const mp_int *a, uint32_t b, mp_int *c) +{ + mp_int t1, t2, t3, a_; + mp_ord cmp; + int ilog2; + mp_err err; + + /* input must be positive if b is even */ + if (((b & 1u) == 0u) && (a->sign == MP_NEG)) { + return MP_VAL; + } + if (b == 0) { + return MP_VAL; + } + + if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) { + return err; + } + + /* if a is negative fudge the sign but keep track */ + a_ = *a; + a_.sign = MP_ZPOS; + + /* Compute seed: 2^(log_2(n)/b + 2)*/ + ilog2 = mp_count_bits(a); + + /* + If "b" is larger than INT_MAX it is also larger than + log_2(n) because the bit-length of the "n" is measured + with an int and hence the root is always < 2 (two). + */ + if (b > (uint32_t)(INT_MAX/2)) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + + /* "b" is smaller than INT_MAX, we can cast safely */ + if (ilog2 < (int)b) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + ilog2 = ilog2 / ((int)b); + if (ilog2 == 0) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + /* Start value must be larger than root */ + ilog2 += 2; + if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) goto LBL_ERR; + do { + /* t1 = t2 */ + if ((err = mp_copy(&t2, &t1)) != MP_OKAY) goto LBL_ERR; + + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((err = mp_expt_u32(&t1, b - 1u, &t3)) != MP_OKAY) goto LBL_ERR; + + /* numerator */ + /* t2 = t1**b */ + if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) goto LBL_ERR; + + /* t2 = t1**b - a */ + if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) goto LBL_ERR; + + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((err = mp_mul_d(&t3, b, &t3)) != MP_OKAY) goto LBL_ERR; + + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) goto LBL_ERR; + + /* + Number of rounds is at most log_2(root). If it is more it + got stuck, so break out of the loop and do the rest manually. + */ + if (ilog2-- == 0) { + break; + } + } while (mp_cmp(&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + /* Loop beneath can overshoot by one if found root is smaller than actual root */ + for (;;) { + if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; + cmp = mp_cmp(&t2, &a_); + if (cmp == MP_EQ) { + err = MP_OKAY; + goto LBL_ERR; + } + if (cmp == MP_LT) { + if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; + } else { + break; + } + } + /* correct overshoot from above or from recurrence */ + for (;;) { + if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; + if (mp_cmp(&t2, &a_) == MP_GT) { + if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; + } else { + break; + } + } + + /* set the result */ + mp_exch(&t1, c); + + /* set the sign of the result */ + c->sign = a->sign; + + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&t1, &t2, &t3, NULL); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rshd.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rshd.c new file mode 100644 index 0000000..bb8743e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_rshd.c @@ -0,0 +1,51 @@ +#include "tommath_private.h" +#ifdef BN_MP_RSHD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right a certain amount of digits */ +void mp_rshd(mp_int *a, int b) +{ + int x; + mp_digit *bottom, *top; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero(a); + return; + } + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + MP_ZERO_DIGITS(bottom, a->used - x); + + /* remove excess digits */ + a->used -= b; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sbin_size.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sbin_size.c new file mode 100644 index 0000000..e0993d6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sbin_size.c @@ -0,0 +1,11 @@ +#include "tommath_private.h" +#ifdef BN_MP_SBIN_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* get the size for an signed equivalent */ +size_t mp_sbin_size(const mp_int *a) +{ + return 1u + mp_ubin_size(a); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set.c new file mode 100644 index 0000000..44ac6df --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set.c @@ -0,0 +1,14 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b) +{ + a->dp[0] = b & MP_MASK; + a->sign = MP_ZPOS; + a->used = (a->dp[0] != 0u) ? 1 : 0; + MP_ZERO_DIGITS(a->dp + a->used, a->alloc - a->used); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c new file mode 100644 index 0000000..6f91b64 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_double.c @@ -0,0 +1,47 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_DOUBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(_M_X86) || defined(__aarch64__) || defined(__arm__) +mp_err mp_set_double(mp_int *a, double b) +{ + uint64_t frac; + int exp; + mp_err err; + union { + double dbl; + uint64_t bits; + } cast; + cast.dbl = b; + + exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFu); + frac = (cast.bits & ((1uLL << 52) - 1uLL)) | (1uLL << 52); + + if (exp == 0x7FF) { /* +-inf, NaN */ + return MP_VAL; + } + exp -= 1023 + 52; + + mp_set_u64(a, frac); + + err = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); + if (err != MP_OKAY) { + return err; + } + + if (((cast.bits >> 63) != 0uLL) && !MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format") +# else +# warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" +# endif +#endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i32.c new file mode 100644 index 0000000..df4513d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_i32, mp_set_u32, int32_t, uint32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i64.c new file mode 100644 index 0000000..395103b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_i64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_i64, mp_set_u64, int64_t, uint64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_l.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_l.c new file mode 100644 index 0000000..1e445fb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_l.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_l, mp_set_ul, long, unsigned long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ll.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ll.c new file mode 100644 index 0000000..3e2324f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ll.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_ll, mp_set_ull, long long, unsigned long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u32.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u32.c new file mode 100644 index 0000000..18ba5e1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u32.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_u32, uint32_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u64.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u64.c new file mode 100644 index 0000000..88fab6c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_u64.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_u64, uint64_t) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ul.c new file mode 100644 index 0000000..adfd85c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ul.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_ul, unsigned long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ull.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ull.c new file mode 100644 index 0000000..8fbc1bd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_set_ull.c @@ -0,0 +1,7 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_ull, unsigned long long) +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_shrink.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_shrink.c new file mode 100644 index 0000000..cf27ed9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_shrink.c @@ -0,0 +1,22 @@ +#include "tommath_private.h" +#ifdef BN_MP_SHRINK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shrink a bignum */ +mp_err mp_shrink(mp_int *a) +{ + mp_digit *tmp; + int alloc = MP_MAX(MP_MIN_PREC, a->used); + if (a->alloc != alloc) { + if ((tmp = (mp_digit *) MP_REALLOC(a->dp, + (size_t)a->alloc * sizeof(mp_digit), + (size_t)alloc * sizeof(mp_digit))) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = alloc; + } + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_signed_rsh.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_signed_rsh.c new file mode 100644 index 0000000..8d8d841 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_signed_rsh.c @@ -0,0 +1,22 @@ +#include "tommath_private.h" +#ifdef BN_MP_SIGNED_RSH_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right by a certain bit count with sign extension */ +mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) +{ + mp_err res; + if (a->sign == MP_ZPOS) { + return mp_div_2d(a, b, c, NULL); + } + + res = mp_add_d(a, 1uL, c); + if (res != MP_OKAY) { + return res; + } + + res = mp_div_2d(c, b, c, NULL); + return (res == MP_OKAY) ? mp_sub_d(c, 1uL, c) : res; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqr.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqr.c new file mode 100644 index 0000000..e0d0a73 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqr.c @@ -0,0 +1,28 @@ +#include "tommath_private.h" +#ifdef BN_MP_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes b = a*a */ +mp_err mp_sqr(const mp_int *a, mp_int *b) +{ + mp_err err; + if (MP_HAS(S_MP_TOOM_SQR) && /* use Toom-Cook? */ + (a->used >= MP_TOOM_SQR_CUTOFF)) { + err = s_mp_toom_sqr(a, b); + } else if (MP_HAS(S_MP_KARATSUBA_SQR) && /* Karatsuba? */ + (a->used >= MP_KARATSUBA_SQR_CUTOFF)) { + err = s_mp_karatsuba_sqr(a, b); + } else if (MP_HAS(S_MP_SQR_FAST) && /* can we use the fast comba multiplier? */ + (((a->used * 2) + 1) < MP_WARRAY) && + (a->used < (MP_MAXFAST / 2))) { + err = s_mp_sqr_fast(a, b); + } else if (MP_HAS(S_MP_SQR)) { + err = s_mp_sqr(a, b); + } else { + err = MP_VAL; + } + b->sign = MP_ZPOS; + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrmod.c new file mode 100644 index 0000000..626ea2c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrmod.c @@ -0,0 +1,25 @@ +#include "tommath_private.h" +#ifdef BN_MP_SQRMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = a * a (mod b) */ +mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_sqr(a, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, b, c); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrt.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrt.c new file mode 100644 index 0000000..82d6824 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrt.c @@ -0,0 +1,67 @@ +#include "tommath_private.h" +#ifdef BN_MP_SQRT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this function is less generic than mp_n_root, simpler and faster */ +mp_err mp_sqrt(const mp_int *arg, mp_int *ret) +{ + mp_err err; + mp_int t1, t2; + + /* must be positive */ + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* easy out */ + if (MP_IS_ZERO(arg)) { + mp_zero(ret); + return MP_OKAY; + } + + if ((err = mp_init_copy(&t1, arg)) != MP_OKAY) { + return err; + } + + if ((err = mp_init(&t2)) != MP_OKAY) { + goto E2; + } + + /* First approx. (not very bad for large arg) */ + mp_rshd(&t1, t1.used/2); + + /* t1 > 0 */ + if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { + goto E1; + } + if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { + goto E1; + } + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { + goto E1; + } + /* And now t1 > sqrt(arg) */ + do { + if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { + goto E1; + } + if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { + goto E1; + } + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { + goto E1; + } + /* t1 >= sqrt(arg) >= t2 at this point */ + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + mp_exch(&t1, ret); + +E1: + mp_clear(&t2); +E2: + mp_clear(&t1); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrtmod_prime.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrtmod_prime.c new file mode 100644 index 0000000..a833ed7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sqrtmod_prime.c @@ -0,0 +1,118 @@ +#include "tommath_private.h" +#ifdef BN_MP_SQRTMOD_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Tonelli-Shanks algorithm + * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm + * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html + * + */ + +mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret) +{ + mp_err err; + int legendre; + mp_int t1, C, Q, S, Z, M, T, R, two; + mp_digit i; + + /* first handle the simple cases */ + if (mp_cmp_d(n, 0uL) == MP_EQ) { + mp_zero(ret); + return MP_OKAY; + } + if (mp_cmp_d(prime, 2uL) == MP_EQ) return MP_VAL; /* prime must be odd */ + if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err; + if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */ + + if ((err = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) { + return err; + } + + /* SPECIAL CASE: if prime mod 4 == 3 + * compute directly: err = n^(prime+1)/4 mod prime + * Handbook of Applied Cryptography algorithm 3.36 + */ + if ((err = mp_mod_d(prime, 4uL, &i)) != MP_OKAY) goto cleanup; + if (i == 3u) { + if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup; + err = MP_OKAY; + goto cleanup; + } + + /* NOW: Tonelli-Shanks algorithm */ + + /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */ + if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup; + if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto cleanup; + /* Q = prime - 1 */ + mp_zero(&S); + /* S = 0 */ + while (MP_IS_EVEN(&Q)) { + if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup; + /* Q = Q / 2 */ + if ((err = mp_add_d(&S, 1uL, &S)) != MP_OKAY) goto cleanup; + /* S = S + 1 */ + } + + /* find a Z such that the Legendre symbol (Z|prime) == -1 */ + mp_set_u32(&Z, 2u); + /* Z = 2 */ + for (;;) { + if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto cleanup; + if (legendre == -1) break; + if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto cleanup; + /* Z = Z + 1 */ + } + + if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup; + /* C = Z ^ Q mod prime */ + if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + /* t1 = (Q + 1) / 2 */ + if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup; + /* R = n ^ ((Q + 1) / 2) mod prime */ + if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup; + /* T = n ^ Q mod prime */ + if ((err = mp_copy(&S, &M)) != MP_OKAY) goto cleanup; + /* M = S */ + mp_set_u32(&two, 2u); + + for (;;) { + if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup; + i = 0; + for (;;) { + if (mp_cmp_d(&t1, 1uL) == MP_EQ) break; + if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup; + i++; + } + if (i == 0u) { + if ((err = mp_copy(&R, ret)) != MP_OKAY) goto cleanup; + err = MP_OKAY; + goto cleanup; + } + if ((err = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup; + /* t1 = 2 ^ (M - i - 1) */ + if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup; + /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ + if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup; + /* C = (t1 * t1) mod prime */ + if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup; + /* R = (R * t1) mod prime */ + if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup; + /* T = (T * C) mod prime */ + mp_set(&M, i); + /* M = i */ + } + +cleanup: + mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub.c new file mode 100644 index 0000000..c1ea39e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub.c @@ -0,0 +1,40 @@ +#include "tommath_private.h" +#ifdef BN_MP_SUB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level subtraction (handles signs) */ +mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_sign sa = a->sign, sb = b->sign; + mp_err err; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + err = s_mp_add(a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag(a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + err = s_mp_sub(a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + err = s_mp_sub(b, a, c); + } + } + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub_d.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub_d.c new file mode 100644 index 0000000..3ebf9b4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_sub_d.c @@ -0,0 +1,74 @@ +#include "tommath_private.h" +#ifdef BN_MP_SUB_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit subtraction */ +mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_digit *tmpa, *tmpc; + mp_err err; + int ix, oldused; + + /* grow c as required */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + mp_int a_ = *a; + a_.sign = MP_ZPOS; + err = mp_add_d(&a_, b, c); + c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return err; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if (((a->used == 1) && (a->dp[0] <= b)) || (a->used == 0)) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + mp_digit mu = b; + + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract digits, mu is carry */ + for (ix = 0; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + MP_ZERO_DIGITS(tmpc, oldused - ix); + + mp_clamp(c); + return MP_OKAY; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_submod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_submod.c new file mode 100644 index 0000000..5ebd374 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_submod.c @@ -0,0 +1,25 @@ +#include "tommath_private.h" +#ifdef BN_MP_SUBMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a - b (mod c) */ +mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_sub(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_radix.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_radix.c new file mode 100644 index 0000000..7fa86ca --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_radix.c @@ -0,0 +1,84 @@ +#include "tommath_private.h" +#ifdef BN_MP_TO_RADIX_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto "size - 1" chars and always a NULL byte, puts the number of characters + * written, including the '\0', in "written". + */ +mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) +{ + size_t digs; + mp_err err; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of radix and size*/ + if (maxlen < 2u) { + return MP_BUF; + } + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + /* quick out if its zero */ + if (MP_IS_ZERO(a)) { + *str++ = '0'; + *str = '\0'; + if (written != NULL) { + *written = 2u; + } + return MP_OKAY; + } + + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + /* we have to reverse our digits later... but not the - sign!! */ + ++_s; + + /* store the flag and mark the number as positive */ + *str++ = '-'; + t.sign = MP_ZPOS; + + /* subtract a char */ + --maxlen; + } + digs = 0u; + while (!MP_IS_ZERO(&t)) { + if (--maxlen < 1u) { + /* no more room */ + err = MP_BUF; + goto LBL_ERR; + } + if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { + goto LBL_ERR; + } + *str++ = mp_s_rmap[d]; + ++digs; + } + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number + */ + s_mp_reverse((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + digs++; + + if (written != NULL) { + *written = (a->sign == MP_NEG) ? (digs + 1u): digs; + } + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_sbin.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_sbin.c new file mode 100644 index 0000000..dbaf53e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_sbin.c @@ -0,0 +1,22 @@ +#include "tommath_private.h" +#ifdef BN_MP_TO_SBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* store in signed [big endian] format */ +mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) +{ + mp_err err; + if (maxlen == 0u) { + return MP_BUF; + } + if ((err = mp_to_ubin(a, buf + 1, maxlen - 1u, written)) != MP_OKAY) { + return err; + } + if (written != NULL) { + (*written)++; + } + buf[0] = (a->sign == MP_ZPOS) ? (unsigned char)0 : (unsigned char)1; + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_ubin.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_ubin.c new file mode 100644 index 0000000..1681ca7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_to_ubin.c @@ -0,0 +1,41 @@ +#include "tommath_private.h" +#ifdef BN_MP_TO_UBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* store in unsigned [big endian] format */ +mp_err mp_to_ubin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) +{ + size_t x, count; + mp_err err; + mp_int t; + + count = mp_ubin_size(a); + if (count > maxlen) { + return MP_BUF; + } + + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + for (x = count; x --> 0u;) { +#ifndef MP_8BIT + buf[x] = (unsigned char)(t.dp[0] & 255u); +#else + buf[x] = (unsigned char)(t.dp[0] | ((t.dp[1] & 1u) << 7)); +#endif + if ((err = mp_div_2d(&t, 8, &t, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + } + + if (written != NULL) { + *written = count; + } + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_ubin_size.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_ubin_size.c new file mode 100644 index 0000000..21230b4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_ubin_size.c @@ -0,0 +1,12 @@ +#include "tommath_private.h" +#ifdef BN_MP_UBIN_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* get the size for an unsigned equivalent */ +size_t mp_ubin_size(const mp_int *a) +{ + size_t size = (size_t)mp_count_bits(a); + return (size / 8u) + (((size & 7u) != 0u) ? 1u : 0u); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_unpack.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_unpack.c new file mode 100644 index 0000000..d4eb90e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_unpack.c @@ -0,0 +1,49 @@ +#include "tommath_private.h" +#ifdef BN_MP_UNPACK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* based on gmp's mpz_import. + * see http://gmplib.org/manual/Integer-Import-and-Export.html + */ +mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, + mp_endian endian, size_t nails, const void *op) +{ + mp_err err; + size_t odd_nails, nail_bytes, i, j; + unsigned char odd_nail_mask; + + mp_zero(rop); + + if (endian == MP_NATIVE_ENDIAN) { + MP_GET_ENDIANNESS(endian); + } + + odd_nails = (nails % 8u); + odd_nail_mask = 0xff; + for (i = 0; i < odd_nails; ++i) { + odd_nail_mask ^= (unsigned char)(1u << (7u - i)); + } + nail_bytes = nails / 8u; + + for (i = 0; i < count; ++i) { + for (j = 0; j < (size - nail_bytes); ++j) { + unsigned char byte = *((const unsigned char *)op + + (((order == MP_MSB_FIRST) ? i : ((count - 1u) - i)) * size) + + ((endian == MP_BIG_ENDIAN) ? (j + nail_bytes) : (((size - 1u) - j) - nail_bytes))); + + if ((err = mp_mul_2d(rop, (j == 0u) ? (int)(8u - odd_nails) : 8, rop)) != MP_OKAY) { + return err; + } + + rop->dp[0] |= (j == 0u) ? (mp_digit)(byte & odd_nail_mask) : (mp_digit)byte; + rop->used += 1; + } + } + + mp_clamp(rop); + + return MP_OKAY; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_xor.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_xor.c new file mode 100644 index 0000000..71e7ca1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_xor.c @@ -0,0 +1,56 @@ +#include "tommath_private.h" +#ifdef BN_MP_XOR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement xor */ +mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x ^ y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_zero.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_zero.c new file mode 100644 index 0000000..72a255e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_mp_zero.c @@ -0,0 +1,13 @@ +#include "tommath_private.h" +#ifdef BN_MP_ZERO_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* set to zero */ +void mp_zero(mp_int *a) +{ + a->sign = MP_ZPOS; + a->used = 0; + MP_ZERO_DIGITS(a->dp, a->alloc); +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_prime_tab.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_prime_tab.c new file mode 100644 index 0000000..a6c07f8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_prime_tab.c @@ -0,0 +1,61 @@ +#include "tommath_private.h" +#ifdef BN_PRIME_TAB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +const mp_digit ltm_prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif +}; + +#if defined(__GNUC__) && __GNUC__ >= 4 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) && _MSC_VER >= 1500 +#pragma warning(push) +#pragma warning(disable: 4996) +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#pragma warning(pop) +#else +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_add.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_add.c new file mode 100644 index 0000000..c946aa8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_add.c @@ -0,0 +1,91 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_ADD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) +{ + const mp_int *x; + mp_err err; + int olduse, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < (max + 1)) { + if ((err = mp_grow(c, max + 1)) != MP_OKAY) { + return err; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (mp_digit)MP_DIGIT_BIT; + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (mp_digit)MP_DIGIT_BIT; + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + MP_ZERO_DIGITS(tmpc, olduse - c->used); + } + + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_balance_mul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_balance_mul.c new file mode 100644 index 0000000..7ece5d7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_balance_mul.c @@ -0,0 +1,81 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_BALANCE_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single-digit multiplication with the smaller number as the single-digit */ +mp_err s_mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + int count, len_a, len_b, nblocks, i, j, bsize; + mp_int a0, tmp, A, B, r; + mp_err err; + + len_a = a->used; + len_b = b->used; + + nblocks = MP_MAX(a->used, b->used) / MP_MIN(a->used, b->used); + bsize = MP_MIN(a->used, b->used) ; + + if ((err = mp_init_size(&a0, bsize + 2)) != MP_OKAY) { + return err; + } + if ((err = mp_init_multi(&tmp, &r, NULL)) != MP_OKAY) { + mp_clear(&a0); + return err; + } + + /* Make sure that A is the larger one*/ + if (len_a < len_b) { + B = *a; + A = *b; + } else { + A = *a; + B = *b; + } + + for (i = 0, j=0; i < nblocks; i++) { + /* Cut a slice off of a */ + a0.used = 0; + for (count = 0; count < bsize; count++) { + a0.dp[count] = A.dp[ j++ ]; + a0.used++; + } + mp_clamp(&a0); + /* Multiply with b */ + if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) { + goto LBL_ERR; + } + /* Shift tmp to the correct position */ + if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { + goto LBL_ERR; + } + /* Add to output. No carry needed */ + if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* The left-overs; there are always left-overs */ + if (j < A.used) { + a0.used = 0; + for (count = 0; j < A.used; count++) { + a0.dp[count] = A.dp[ j++ ]; + a0.used++; + } + mp_clamp(&a0); + if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { + goto LBL_ERR; + } + } + + mp_exch(&r,c); +LBL_ERR: + mp_clear_multi(&a0, &tmp, &r,NULL); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod.c new file mode 100644 index 0000000..c3bfa95 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod.c @@ -0,0 +1,198 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_EXPTMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef MP_LOW_MEM +# define TAB_SIZE 32 +# define MAX_WINSIZE 5 +#else +# define TAB_SIZE 256 +# define MAX_WINSIZE 0 +#endif + +mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + mp_err err; + int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + mp_err(*redux)(mp_int *x, const mp_int *m, const mp_int *mu); + + /* find window size */ + x = mp_count_bits(X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize; + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear(&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init(&mu)) != MP_OKAY) goto LBL_M; + + if (redmode == 0) { + if ((err = mp_reduce_setup(&mu, P)) != MP_OKAY) goto LBL_MU; + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l(P, &mu)) != MP_OKAY) goto LBL_MU; + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_MU; + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU; + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], + &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU; + + /* reduce modulo P */ + if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, &mu)) != MP_OKAY) goto LBL_MU; + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_MU; + if ((err = redux(&M[x], P, &mu)) != MP_OKAY) goto LBL_MU; + } + + /* setup result */ + if ((err = mp_init(&res)) != MP_OKAY) goto LBL_MU; + mp_set(&res, 1uL); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)MP_DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(MP_DIGIT_BIT - 1)) & 1uL; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if ((mode == 0) && (y == 0)) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if ((mode == 1) && (y == 0)) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + } + + /* then multiply */ + if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if ((mode == 2) && (bitcpy > 0)) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + } + } + } + + mp_exch(&res, Y); + err = MP_OKAY; +LBL_RES: + mp_clear(&res); +LBL_MU: + mp_clear(&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear(&M[x]); + } + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod_fast.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod_fast.c new file mode 100644 index 0000000..682ded8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_exptmod_fast.c @@ -0,0 +1,254 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_EXPTMOD_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +#ifdef MP_LOW_MEM +# define TAB_SIZE 32 +# define MAX_WINSIZE 5 +#else +# define TAB_SIZE 256 +# define MAX_WINSIZE 0 +#endif + +mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + mp_err err; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + mp_err(*redux)(mp_int *x, const mp_int *n, mp_digit rho); + + /* find window size */ + x = mp_count_bits(X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize; + + /* init M array */ + /* init first cell */ + if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear(&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + if (MP_HAS(MP_MONTGOMERY_SETUP)) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) goto LBL_M; + } else { + err = MP_VAL; + goto LBL_M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (MP_HAS(S_MP_MONTGOMERY_REDUCE_FAST) && + (((P->used * 2) + 1) < MP_WARRAY) && + (P->used < MP_MAXFAST)) { + redux = s_mp_montgomery_reduce_fast; + } else if (MP_HAS(MP_MONTGOMERY_REDUCE)) { + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; + } else { + err = MP_VAL; + goto LBL_M; + } + } else if (redmode == 1) { + if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) { + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + err = MP_VAL; + goto LBL_M; + } + } else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) { + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) goto LBL_M; + redux = mp_reduce_2k; + } else { + err = MP_VAL; + goto LBL_M; + } + + /* setup result */ + if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) goto LBL_M; + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) goto LBL_RES; + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) goto LBL_RES; + } else { + err = MP_VAL; + goto LBL_RES; + } + } else { + mp_set(&res, 1uL); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_RES; + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES; + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES; + if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_RES; + if ((err = redux(&M[x], P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)MP_DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (MP_DIGIT_BIT - 1)) & 1uL; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if ((mode == 0) && (y == 0)) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if ((mode == 1) && (y == 0)) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* then multiply */ + if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if ((mode == 2) && (bitcpy > 0)) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* swap res with Y */ + mp_exch(&res, Y); + err = MP_OKAY; +LBL_RES: + mp_clear(&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear(&M[x]); + } + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_get_bit.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_get_bit.c new file mode 100644 index 0000000..28598df --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_get_bit.c @@ -0,0 +1,21 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_GET_BIT_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Get bit at position b and return MP_YES if the bit is 1, MP_NO if it is 0 */ +mp_bool s_mp_get_bit(const mp_int *a, unsigned int b) +{ + mp_digit bit; + int limb = (int)(b / MP_DIGIT_BIT); + + if (limb >= a->used) { + return MP_NO; + } + + bit = (mp_digit)1 << (b % MP_DIGIT_BIT); + return ((a->dp[limb] & bit) != 0u) ? MP_YES : MP_NO; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_fast.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_fast.c new file mode 100644 index 0000000..677d7ab --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_fast.c @@ -0,0 +1,118 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_INVMOD_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on slow invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x, y, u, v, B, D; + mp_sign neg; + mp_err err; + + /* 2. [modified] b must be odd */ + if (MP_IS_EVEN(b)) { + return MP_VAL; + } + + /* init all our temps */ + if ((err = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return err; + } + + /* x == modulus, y == value to invert */ + if ((err = mp_copy(b, &x)) != MP_OKAY) goto LBL_ERR; + + /* we need y = |a| */ + if ((err = mp_mod(a, b, &y)) != MP_OKAY) goto LBL_ERR; + + /* if one of x,y is zero return an error! */ + if (MP_IS_ZERO(&x) || MP_IS_ZERO(&y)) { + err = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR; + mp_set(&D, 1uL); + +top: + /* 4. while u is even do */ + while (MP_IS_EVEN(&u)) { + /* 4.1 u = u/2 */ + if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR; + + /* 4.2 if B is odd then */ + if (MP_IS_ODD(&B)) { + if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR; + } + /* B = B/2 */ + if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR; + } + + /* 5. while v is even do */ + while (MP_IS_EVEN(&v)) { + /* 5.1 v = v/2 */ + if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR; + + /* 5.2 if D is odd then */ + if (MP_IS_ODD(&D)) { + /* D = (D-x)/2 */ + if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR; + } + /* D = D/2 */ + if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* 6. if u >= v then */ + if (mp_cmp(&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR; + } else { + /* v - v - u, D = D - B */ + if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* if not zero goto step 4 */ + if (!MP_IS_ZERO(&u)) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d(&v, 1uL) != MP_EQ) { + err = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((err = mp_add(&D, b, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* too big */ + while (mp_cmp_mag(&D, b) != MP_LT) { + if ((err = mp_sub(&D, b, &D)) != MP_OKAY) goto LBL_ERR; + } + + mp_exch(&D, c); + c->sign = neg; + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_slow.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_slow.c new file mode 100644 index 0000000..4c5db33 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_invmod_slow.c @@ -0,0 +1,119 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_INVMOD_SLOW_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* hac 14.61, pp608 */ +mp_err s_mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x, y, u, v, A, B, C, D; + mp_err err; + + /* b cannot be negative */ + if ((b->sign == MP_NEG) || MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* init temps */ + if ((err = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return err; + } + + /* x = a, y = b */ + if ((err = mp_mod(a, b, &x)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(b, &y)) != MP_OKAY) goto LBL_ERR; + + /* 2. [modified] if x,y are both even then return an error! */ + if (MP_IS_EVEN(&x) && MP_IS_EVEN(&y)) { + err = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR; + mp_set(&A, 1uL); + mp_set(&D, 1uL); + +top: + /* 4. while u is even do */ + while (MP_IS_EVEN(&u)) { + /* 4.1 u = u/2 */ + if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR; + + /* 4.2 if A or B is odd then */ + if (MP_IS_ODD(&A) || MP_IS_ODD(&B)) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((err = mp_add(&A, &y, &A)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR; + } + /* A = A/2, B = B/2 */ + if ((err = mp_div_2(&A, &A)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR; + } + + /* 5. while v is even do */ + while (MP_IS_EVEN(&v)) { + /* 5.1 v = v/2 */ + if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR; + + /* 5.2 if C or D is odd then */ + if (MP_IS_ODD(&C) || MP_IS_ODD(&D)) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((err = mp_add(&C, &y, &C)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR; + } + /* C = C/2, D = D/2 */ + if ((err = mp_div_2(&C, &C)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* 6. if u >= v then */ + if (mp_cmp(&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&A, &C, &A)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR; + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&C, &A, &C)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* if not zero goto step 4 */ + if (!MP_IS_ZERO(&u)) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d(&v, 1uL) != MP_EQ) { + err = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0uL) == MP_LT) { + if ((err = mp_add(&C, b, &C)) != MP_OKAY) goto LBL_ERR; + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((err = mp_sub(&C, b, &C)) != MP_OKAY) goto LBL_ERR; + } + + /* C is now the inverse */ + mp_exch(&C, c); + err = MP_OKAY; +LBL_ERR: + mp_clear_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return err; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_karatsuba_mul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_karatsuba_mul.c new file mode 100644 index 0000000..85899fb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_karatsuba_mul.c @@ -0,0 +1,174 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_KARATSUBA_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**MP_DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1+b1)(a0+b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +mp_err s_mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B; + mp_err err = MP_MEM; /* default the return code to an error */ + + /* min # of digits */ + B = MP_MIN(a->used, b->used); + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size(&x0, B) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_init_size(&x1, a->used - B) != MP_OKAY) { + goto X0; + } + if (mp_init_size(&y0, B) != MP_OKAY) { + goto X1; + } + if (mp_init_size(&y1, b->used - B) != MP_OKAY) { + goto Y0; + } + + /* init temps */ + if (mp_init_size(&t1, B * 2) != MP_OKAY) { + goto Y1; + } + if (mp_init_size(&x0y0, B * 2) != MP_OKAY) { + goto T1; + } + if (mp_init_size(&x1y1, B * 2) != MP_OKAY) { + goto X0Y0; + } + + /* now shift the digits */ + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + int x; + mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp(&x0); + mp_clamp(&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul(&x0, &y0, &x0y0) != MP_OKAY) { + goto X1Y1; /* x0y0 = x0*y0 */ + } + if (mp_mul(&x1, &y1, &x1y1) != MP_OKAY) { + goto X1Y1; /* x1y1 = x1*y1 */ + } + + /* now calc x1+x0 and y1+y0 */ + if (s_mp_add(&x1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = x1 - x0 */ + } + if (s_mp_add(&y1, &y0, &x0) != MP_OKAY) { + goto X1Y1; /* t2 = y1 - y0 */ + } + if (mp_mul(&t1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */ + } + + /* add x0y0 */ + if (mp_add(&x0y0, &x1y1, &x0) != MP_OKAY) { + goto X1Y1; /* t2 = x0y0 + x1y1 */ + } + if (s_mp_sub(&t1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */ + } + + /* shift by B */ + if (mp_lshd(&t1, B) != MP_OKAY) { + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size(&x0, B) != MP_OKAY) + goto LBL_ERR; + if (mp_init_size(&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size(&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size(&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size(&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size(&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + int x; + mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp(&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr(&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr(&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1+x0)**2 */ + if (s_mp_add(&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr(&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add(&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (s_mp_sub(&t1, &t2, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */ + + /* shift by B */ + if (mp_lshd(&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<used > MP_WARRAY) { + return MP_VAL; + } + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < (n->used + 1)) { + if ((err = mp_grow(x, n->used + 1)) != MP_OKAY) { + return err; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + mp_word *_W; + mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + if (ix < ((n->used * 2) + 1)) { + MP_ZERO_BUFFER(_W, sizeof(mp_word) * (size_t)(((n->used * 2) + 1) - ix)); + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + mp_digit mu; + mu = ((W[ix] & MP_MASK) * rho) & MP_MASK; + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + int iy; + mp_digit *tmpn; + mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += (mp_word)mu * (mp_word)*tmpn++; + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> (mp_word)MP_DIGIT_BIT; + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + mp_digit *tmpx; + mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix < ((n->used * 2) + 1); ix++) { + *_W++ += *_W1++ >> (mp_word)MP_DIGIT_BIT; + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < (n->used + 1); ix++) { + *tmpx++ = *_W++ & (mp_word)MP_MASK; + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + MP_ZERO_DIGITS(tmpx, olduse - ix); + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp(x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag(x, n) != MP_LT) { + return s_mp_sub(x, n, x); + } + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs.c new file mode 100644 index 0000000..64509d4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs.c @@ -0,0 +1,74 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_DIGS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +mp_err s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + mp_int t; + mp_err err; + int pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if ((digs < MP_WARRAY) && + (MP_MIN(a->used, b->used) < MP_MAXFAST)) { + return s_mp_mul_digs_fast(a, b, c, digs); + } + + if ((err = mp_init_size(&t, digs)) != MP_OKAY) { + return err; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MP_MIN(b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = (mp_word)*tmpt + + ((mp_word)tmpx * (mp_word)*tmpy++) + + (mp_word)u; + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* get the carry word from the result */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + /* set carry if it is placed below digs */ + if ((ix + iy) < digs) { + *tmpt = u; + } + } + + mp_clamp(&t); + mp_exch(&t, c); + + mp_clear(&t); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs_fast.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs_fast.c new file mode 100644 index 0000000..b2a287b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_digs_fast.c @@ -0,0 +1,90 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_DIGS_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +mp_err s_mp_mul_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + int olduse, pa, ix, iz; + mp_err err; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((err = mp_grow(c, digs)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + pa = MP_MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MP_MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + + } + + /* store term */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + _W = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + } + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs.c new file mode 100644 index 0000000..2bb2a50 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs.c @@ -0,0 +1,64 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_HIGH_DIGS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + mp_int t; + int pa, pb, ix, iy; + mp_err err; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST) + && ((a->used + b->used + 1) < MP_WARRAY) + && (MP_MIN(a->used, b->used) < MP_MAXFAST)) { + return s_mp_mul_high_digs_fast(a, b, c, digs); + } + + if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) { + return err; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = (mp_word)*tmpt + + ((mp_word)tmpx * (mp_word)*tmpy++) + + (mp_word)u; + + /* get the lower part */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* carry the carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + *tmpt = u; + } + mp_clamp(&t); + mp_exch(&t, c); + mp_clear(&t); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs_fast.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs_fast.c new file mode 100644 index 0000000..a2c4fb6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_mul_high_digs_fast.c @@ -0,0 +1,81 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_HIGH_DIGS_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +mp_err s_mp_mul_high_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + int olduse, pa, ix, iz; + mp_err err; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((err = mp_grow(c, pa)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + pa = a->used + b->used; + _W = 0; + for (ix = digs; ix < pa; ix++) { + int tx, ty, iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MP_MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + } + + /* store term */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + _W = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + + tmpc = c->dp + digs; + for (ix = digs; ix < pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + } + mp_clamp(c); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_prime_is_divisible.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_prime_is_divisible.c new file mode 100644 index 0000000..ffd5093 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_prime_is_divisible.c @@ -0,0 +1,35 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_PRIME_IS_DIVISIBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not + * + * sets result to 0 if not, 1 if yes + */ +mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result) +{ + int ix; + mp_err err; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d(a, s_mp_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0u) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_jenkins.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_jenkins.c new file mode 100644 index 0000000..da0771c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_jenkins.c @@ -0,0 +1,52 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_RAND_JENKINS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Bob Jenkins' http://burtleburtle.net/bob/rand/smallprng.html */ +/* Chosen for speed and a good "mix" */ +typedef struct { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +} ranctx; + +static ranctx jenkins_x; + +#define rot(x,k) (((x)<<(k))|((x)>>(64-(k)))) +static uint64_t s_rand_jenkins_val(void) +{ + uint64_t e = jenkins_x.a - rot(jenkins_x.b, 7); + jenkins_x.a = jenkins_x.b ^ rot(jenkins_x.c, 13); + jenkins_x.b = jenkins_x.c + rot(jenkins_x.d, 37); + jenkins_x.c = jenkins_x.d + e; + jenkins_x.d = e + jenkins_x.a; + return jenkins_x.d; +} + +void s_mp_rand_jenkins_init(uint64_t seed) +{ + uint64_t i; + jenkins_x.a = 0xf1ea5eedULL; + jenkins_x.b = jenkins_x.c = jenkins_x.d = seed; + for (i = 0uLL; i < 20uLL; ++i) { + (void)s_rand_jenkins_val(); + } +} + +mp_err s_mp_rand_jenkins(void *p, size_t n) +{ + char *q = (char *)p; + while (n > 0u) { + int i; + uint64_t x = s_rand_jenkins_val(); + for (i = 0; (i < 8) && (n > 0u); ++i, --n) { + *q++ = (char)(x & 0xFFuLL); + x >>= 8; + } + } + return MP_OKAY; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c new file mode 100644 index 0000000..79879c3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_rand_platform.c @@ -0,0 +1,168 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_RAND_PLATFORM_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* First the OS-specific special cases + * - *BSD + * - Windows + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#define BN_S_READ_ARC4RANDOM_C +static mp_err s_read_arc4random(void *p, size_t n) +{ + arc4random_buf(p, n); + return MP_OKAY; +} +#endif + +#if defined(_WIN32) || defined(_WIN32_WCE) +#define BN_S_READ_WINCSP_C + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#ifdef _WIN32_WCE +#define UNDER_CE +#define ARM +#endif + +#define WIN32_LEAN_AND_MEAN +#include +#include + +static mp_err s_read_wincsp(void *p, size_t n) +{ + static HCRYPTPROV hProv = 0; + if (hProv == 0) { + HCRYPTPROV h = 0; + if (!CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && + !CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) { + return MP_ERR; + } + hProv = h; + } + return CryptGenRandom(hProv, (DWORD)n, (BYTE *)p) == TRUE ? MP_OKAY : MP_ERR; +} +#endif /* WIN32 */ + +#if !defined(BN_S_READ_WINCSP_C) && defined(__linux__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2, 25) +#define BN_S_READ_GETRANDOM_C +#include +#include + +static mp_err s_read_getrandom(void *p, size_t n) +{ + char *q = (char *)p; + while (n > 0u) { + ssize_t ret = getrandom(q, n, 0); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + return MP_ERR; + } + q += ret; + n -= (size_t)ret; + } + return MP_OKAY; +} +#endif +#endif + +/* We assume all platforms besides windows provide "/dev/urandom". + * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time. + */ +#if !defined(BN_S_READ_WINCSP_C) && !defined(MP_NO_DEV_URANDOM) +#define BN_S_READ_URANDOM_C +#ifndef MP_DEV_URANDOM +#define MP_DEV_URANDOM "/dev/urandom" +#endif +#include +#include +#include + +static mp_err s_read_urandom(void *p, size_t n) +{ + int fd; + char *q = (char *)p; + + do { + fd = open(MP_DEV_URANDOM, O_RDONLY); + } while ((fd == -1) && (errno == EINTR)); + if (fd == -1) return MP_ERR; + + while (n > 0u) { + ssize_t ret = read(fd, q, n); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + close(fd); + return MP_ERR; + } + q += ret; + n -= (size_t)ret; + } + + close(fd); + return MP_OKAY; +} +#endif + +#if defined(MP_PRNG_ENABLE_LTM_RNG) +#define BN_S_READ_LTM_RNG +unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void)); +void (*ltm_rng_callback)(void); + +static mp_err s_read_ltm_rng(void *p, size_t n) +{ + unsigned long res; + if (ltm_rng == NULL) return MP_ERR; + res = ltm_rng(p, n, ltm_rng_callback); + if (res != n) return MP_ERR; + return MP_OKAY; +} +#endif + +#ifdef BN_S_READ_ARC4RANDOM_C +mp_err s_read_arc4random(void *p, size_t n); +#endif +#ifdef BN_S_READ_WINCSP_C +mp_err s_read_wincsp(void *p, size_t n); +#endif +#ifdef BN_S_READ_GETRANDOM_C +mp_err s_read_getrandom(void *p, size_t n); +#endif +#ifdef BN_S_READ_URANDOM_C +mp_err s_read_urandom(void *p, size_t n); +#endif +#ifdef BN_S_READ_LTM_RNG +mp_err s_read_ltm_rng(void *p, size_t n); +#endif + +mp_err s_mp_rand_platform(void *p, size_t n) +{ + mp_err err = MP_ERR; +#ifdef BN_S_READ_ARC4RANDOM_C + if ((err != MP_OKAY) && MP_HAS(S_READ_ARC4RANDOM)) err = s_read_arc4random(p, n); +#endif +#ifdef BN_S_READ_WINCSP_C + if ((err != MP_OKAY) && MP_HAS(S_READ_WINCSP)) err = s_read_wincsp(p, n); +#endif +#ifdef BN_S_READ_GETRANDOM_C + if ((err != MP_OKAY) && MP_HAS(S_READ_GETRANDOM)) err = s_read_getrandom(p, n); +#endif +#ifdef BN_S_READ_URANDOM_C + if ((err != MP_OKAY) && MP_HAS(S_READ_URANDOM)) err = s_read_urandom(p, n); +#endif +#ifdef BN_S_READ_LTM_RNG + if ((err != MP_OKAY) && MP_HAS(S_READ_LTM_RNG)) err = s_read_ltm_rng(p, n); +#endif + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_reverse.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_reverse.c new file mode 100644 index 0000000..c549e60 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_reverse.c @@ -0,0 +1,22 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_REVERSE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reverse an array, used for radix code */ +void s_mp_reverse(unsigned char *s, size_t len) +{ + size_t ix, iy; + unsigned char t; + + ix = 0u; + iy = len - 1u; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr.c new file mode 100644 index 0000000..505c9f0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr.c @@ -0,0 +1,69 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +mp_err s_mp_sqr(const mp_int *a, mp_int *b) +{ + mp_int t; + int ix, iy, pa; + mp_err err; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((err = mp_init_size(&t, (2 * pa) + 1)) != MP_OKAY) { + return err; + } + + /* default used is maximum possible size */ + t.used = (2 * pa) + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = (mp_word)t.dp[2*ix] + + ((mp_word)a->dp[ix] * (mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit)(r & (mp_word)MP_MASK); + + /* get the carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + ((2 * ix) + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = (mp_word)tmpx * (mp_word)a->dp[iy]; + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = (mp_word)*tmpt + r + r + (mp_word)u; + + /* store lower part */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* get carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + /* propagate upwards */ + while (u != 0uL) { + r = (mp_word)*tmpt + (mp_word)u; + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + } + + mp_clamp(&t); + mp_exch(&t, b); + mp_clear(&t); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr_fast.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr_fast.c new file mode 100644 index 0000000..4a8a891 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sqr_fast.c @@ -0,0 +1,97 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_SQR_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +mp_err s_mp_sqr_fast(const mp_int *a, mp_int *b) +{ + int olduse, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + mp_err err; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((err = mp_grow(b, pa)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MP_MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MP_MIN(iy, ((ty-tx)+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if (((unsigned)ix & 1u) == 0u) { + _W += (mp_word)a->dp[ix>>1] * (mp_word)a->dp[ix>>1]; + } + + /* store it */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + W1 = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpb, olduse - ix); + } + mp_clamp(b); + return MP_OKAY; +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sub.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sub.c new file mode 100644 index 0000000..5672dab --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_sub.c @@ -0,0 +1,71 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_SUB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) +{ + int olduse, min, max; + mp_err err; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((err = mp_grow(c, max)) != MP_OKAY) { + return err; + } + } + olduse = c->used; + c->used = max; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = (*tmpa++ - *tmpb++) - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + MP_ZERO_DIGITS(tmpc, olduse - c->used); + } + + mp_clamp(c); + return MP_OKAY; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_mul.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_mul.c new file mode 100644 index 0000000..86901b0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_mul.c @@ -0,0 +1,215 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_TOOM_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplication using the Toom-Cook 3-way algorithm + * + * Much more complicated than Karatsuba but has a lower + * asymptotic running time of O(N**1.464). This algorithm is + * only particularly useful on VERY large inputs + * (we're talking 1000s of digits here...). +*/ + +/* + This file contains code from J. Arndt's book "Matters Computational" + and the accompanying FXT-library with permission of the author. +*/ + +/* + Setup from + + Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae." + 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007. + + The interpolation from above needed one temporary variable more + than the interpolation here: + + Bodrato, Marco, and Alberto Zanoni. "What about Toom-Cook matrices optimality." + Centro Vito Volterra Universita di Roma Tor Vergata (2006) +*/ + +mp_err s_mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int S1, S2, T1, a0, a1, a2, b0, b1, b2; + int B, count; + mp_err err; + + /* init temps */ + if ((err = mp_init_multi(&S1, &S2, &T1, NULL)) != MP_OKAY) { + return err; + } + + /* B */ + B = MP_MIN(a->used, b->used) / 3; + + /** a = a2 * x^2 + a1 * x + a0; */ + if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0; + + for (count = 0; count < B; count++) { + a0.dp[count] = a->dp[count]; + a0.used++; + } + mp_clamp(&a0); + if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1; + for (; count < (2 * B); count++) { + a1.dp[count - B] = a->dp[count]; + a1.used++; + } + mp_clamp(&a1); + if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2; + for (; count < a->used; count++) { + a2.dp[count - (2 * B)] = a->dp[count]; + a2.used++; + } + mp_clamp(&a2); + + /** b = b2 * x^2 + b1 * x + b0; */ + if ((err = mp_init_size(&b0, B)) != MP_OKAY) goto LBL_ERRb0; + for (count = 0; count < B; count++) { + b0.dp[count] = b->dp[count]; + b0.used++; + } + mp_clamp(&b0); + if ((err = mp_init_size(&b1, B)) != MP_OKAY) goto LBL_ERRb1; + for (; count < (2 * B); count++) { + b1.dp[count - B] = b->dp[count]; + b1.used++; + } + mp_clamp(&b1); + if ((err = mp_init_size(&b2, B + (b->used - (3 * B)))) != MP_OKAY) goto LBL_ERRb2; + for (; count < b->used; count++) { + b2.dp[count - (2 * B)] = b->dp[count]; + b2.used++; + } + mp_clamp(&b2); + + /** \\ S1 = (a2+a1+a0) * (b2+b1+b0); */ + /** T1 = a2 + a1; */ + if ((err = mp_add(&a2, &a1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = T1 + a0; */ + if ((err = mp_add(&T1, &a0, &S2)) != MP_OKAY) goto LBL_ERR; + + /** c = b2 + b1; */ + if ((err = mp_add(&b2, &b1, c)) != MP_OKAY) goto LBL_ERR; + + /** S1 = c + b0; */ + if ((err = mp_add(c, &b0, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 * S2; */ + if ((err = mp_mul(&S1, &S2, &S1)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = (4*a2+2*a1+a0) * (4*b2+2*b1+b0); */ + /** T1 = T1 + a2; */ + if ((err = mp_add(&T1, &a2, &T1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = T1 << 1; */ + if ((err = mp_mul_2(&T1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = T1 + a0; */ + if ((err = mp_add(&T1, &a0, &T1)) != MP_OKAY) goto LBL_ERR; + + /** c = c + b2; */ + if ((err = mp_add(c, &b2, c)) != MP_OKAY) goto LBL_ERR; + + /** c = c << 1; */ + if ((err = mp_mul_2(c, c)) != MP_OKAY) goto LBL_ERR; + + /** c = c + b0; */ + if ((err = mp_add(c, &b0, c)) != MP_OKAY) goto LBL_ERR; + + /** S2 = T1 * c; */ + if ((err = mp_mul(&T1, c, &S2)) != MP_OKAY) goto LBL_ERR; + + /** \\S3 = (a2-a1+a0) * (b2-b1+b0); */ + /** a1 = a2 - a1; */ + if ((err = mp_sub(&a2, &a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 + a0; */ + if ((err = mp_add(&a1, &a0, &a1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = b2 - b1; */ + if ((err = mp_sub(&b2, &b1, &b1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = b1 + b0; */ + if ((err = mp_add(&b1, &b0, &b1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 * b1; */ + if ((err = mp_mul(&a1, &b1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = a2 * b2; */ + if ((err = mp_mul(&a2, &b2, &b1)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = (S2 - S3)/3; */ + /** S2 = S2 - a1; */ + if ((err = mp_sub(&S2, &a1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 / 3; \\ this is an exact division */ + if ((err = mp_div_3(&S2, &S2, NULL)) != MP_OKAY) goto LBL_ERR; + + /** a1 = S1 - a1; */ + if ((err = mp_sub(&S1, &a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 >> 1; */ + if ((err = mp_div_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a0 = a0 * b0; */ + if ((err = mp_mul(&a0, &b0, &a0)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - a0; */ + if ((err = mp_sub(&S1, &a0, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 - S1; */ + if ((err = mp_sub(&S2, &S1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 >> 1; */ + if ((err = mp_div_2(&S2, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - a1; */ + if ((err = mp_sub(&S1, &a1, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - b1; */ + if ((err = mp_sub(&S1, &b1, &S1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = b1 << 1; */ + if ((err = mp_mul_2(&b1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 - T1; */ + if ((err = mp_sub(&S2, &T1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 - S2; */ + if ((err = mp_sub(&a1, &S2, &a1)) != MP_OKAY) goto LBL_ERR; + + + /** P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0; */ + if ((err = mp_lshd(&b1, 4 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&S2, 3 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &S2, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&S1, 2 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &S1, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a1, 1 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &a1, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &a0, c)) != MP_OKAY) goto LBL_ERR; + + /** a * b - P */ + + +LBL_ERR: + mp_clear(&b2); +LBL_ERRb2: + mp_clear(&b1); +LBL_ERRb1: + mp_clear(&b0); +LBL_ERRb0: + mp_clear(&a2); +LBL_ERRa2: + mp_clear(&a1); +LBL_ERRa1: + mp_clear(&a0); +LBL_ERRa0: + mp_clear_multi(&S1, &S2, &T1, NULL); + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_sqr.c b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_sqr.c new file mode 100644 index 0000000..f2ffb30 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/bn_s_mp_toom_sqr.c @@ -0,0 +1,147 @@ +#include "tommath_private.h" +#ifdef BN_S_MP_TOOM_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* squaring using Toom-Cook 3-way algorithm */ + +/* + This file contains code from J. Arndt's book "Matters Computational" + and the accompanying FXT-library with permission of the author. +*/ + +/* squaring using Toom-Cook 3-way algorithm */ +/* + Setup and interpolation from algorithm SQR_3 in + + Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae." + 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007. + +*/ +mp_err s_mp_toom_sqr(const mp_int *a, mp_int *b) +{ + mp_int S0, a0, a1, a2; + mp_digit *tmpa, *tmpc; + int B, count; + mp_err err; + + + /* init temps */ + if ((err = mp_init(&S0)) != MP_OKAY) { + return err; + } + + /* B */ + B = a->used / 3; + + /** a = a2 * x^2 + a1 * x + a0; */ + if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0; + + a0.used = B; + if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1; + a1.used = B; + if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2; + + tmpa = a->dp; + tmpc = a0.dp; + for (count = 0; count < B; count++) { + *tmpc++ = *tmpa++; + } + tmpc = a1.dp; + for (; count < (2 * B); count++) { + *tmpc++ = *tmpa++; + } + tmpc = a2.dp; + for (; count < a->used; count++) { + *tmpc++ = *tmpa++; + a2.used++; + } + mp_clamp(&a0); + mp_clamp(&a1); + mp_clamp(&a2); + + /** S0 = a0^2; */ + if ((err = mp_sqr(&a0, &S0)) != MP_OKAY) goto LBL_ERR; + + /** \\S1 = (a2 + a1 + a0)^2 */ + /** \\S2 = (a2 - a1 + a0)^2 */ + /** \\S1 = a0 + a2; */ + /** a0 = a0 + a2; */ + if ((err = mp_add(&a0, &a2, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S1 - a1; */ + /** b = a0 - a1; */ + if ((err = mp_sub(&a0, &a1, b)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1 + a1; */ + /** a0 = a0 + a1; */ + if ((err = mp_add(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1^2; */ + /** a0 = a0^2; */ + if ((err = mp_sqr(&a0, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S2^2; */ + /** b = b^2; */ + if ((err = mp_sqr(b, b)) != MP_OKAY) goto LBL_ERR; + + /** \\ S3 = 2 * a1 * a2 */ + /** \\S3 = a1 * a2; */ + /** a1 = a1 * a2; */ + if ((err = mp_mul(&a1, &a2, &a1)) != MP_OKAY) goto LBL_ERR; + /** \\S3 = S3 << 1; */ + /** a1 = a1 << 1; */ + if ((err = mp_mul_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** \\S4 = a2^2; */ + /** a2 = a2^2; */ + if ((err = mp_sqr(&a2, &a2)) != MP_OKAY) goto LBL_ERR; + + /** \\ tmp = (S1 + S2)/2 */ + /** \\tmp = S1 + S2; */ + /** b = a0 + b; */ + if ((err = mp_add(&a0, b, b)) != MP_OKAY) goto LBL_ERR; + /** \\tmp = tmp >> 1; */ + /** b = b >> 1; */ + if ((err = mp_div_2(b, b)) != MP_OKAY) goto LBL_ERR; + + /** \\ S1 = S1 - tmp - S3 */ + /** \\S1 = S1 - tmp; */ + /** a0 = a0 - b; */ + if ((err = mp_sub(&a0, b, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1 - S3; */ + /** a0 = a0 - a1; */ + if ((err = mp_sub(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = tmp - S4 -S0 */ + /** \\S2 = tmp - S4; */ + /** b = b - a2; */ + if ((err = mp_sub(b, &a2, b)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S2 - S0; */ + /** b = b - S0; */ + if ((err = mp_sub(b, &S0, b)) != MP_OKAY) goto LBL_ERR; + + + /** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */ + /** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */ + + if ((err = mp_lshd(&a2, 4 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a1, 3 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(b, 2 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a0, 1 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&a2, &a1, &a2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&a2, b, b)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(b, &a0, b)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(b, &S0, b)) != MP_OKAY) goto LBL_ERR; + /** a^2 - P */ + + +LBL_ERR: + mp_clear(&a2); +LBL_ERRa2: + mp_clear(&a1); +LBL_ERRa1: + mp_clear(&a0); +LBL_ERRa0: + mp_clear(&S0); + + return err; +} + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/changes.txt b/third_party/heimdal/lib/hcrypto/libtommath/changes.txt new file mode 100644 index 0000000..ebf7382 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/changes.txt @@ -0,0 +1,497 @@ +XXX XXth, 2019 +v1.2.0 + -- A huge refactoring of the library happened - renaming, + deprecating and replacing existing functions by improved API's. + + All deprecated functions, macros and symbols are only marked as such + so this version is still API and ABI compatible to v1.x. + + -- Daniel Mendler was pushing for those changes and contributing a load of patches, + refactorings, code reviews and whatnotelse. + -- Christoph Zurnieden re-worked internals of the library, improved the performance, + did code reviews and wrote documentation. + -- Francois Perrad did some refactoring and took again care of linting the sources and + provided all fixes. + -- Jan Nijtmans, Karel Miko and Joachim Breitner contributed various patches. + + -- Private symbols can now be hidden for the shared library builds, disabled by default. + -- All API's follow a single code style, are prefixed the same etc. + -- Unified, safer and improved API's + -- Less magic numbers - return values (where appropriate) and most flags are now enums, + this was implemented in a backwards compatible way where return values were int. + -- API's with return values are now by default marked as "warn on unsused result", this + can be disabled if required (which will most likely hide bugs), c.f. MP_WUR in tommath.h + -- Provide a whole set of setters&getters for different primitive types (long, uint32_t, etc.) + -- All those primitive setters are now optimized. + -- It's possible to automatically tune the cutoff values for Karatsuba&Toom-Cook + -- The custom allocators which were formerly known as XMALLOC(), XFREE() etc. are now available + as MP_MALLOC(), MP_REALLOC(), MP_CALLOC() and MP_FREE(). MP_REALLOC() and MP_FREE() now also + provide the allocated size to ease the usage of simple allocators without tracking. + -- Building is now also possible with MSVC 2015, 2017 and 2019 (use makefile.msvc) + -- Added mp_decr() and mp_incr() + -- Added mp_log_u32() + -- Improved prime-checking + -- Improved Toom-Cook multiplication + -- Removed the LTM book (`make docs` now builds the user manual) + + +Jan 28th, 2019 +v1.1.0 + -- Christoph Zurnieden contributed FIPS 186.4 compliant + prime-checking (PR #113), several other fixes and a load of documentation + -- Daniel Mendler provided two's-complement functions (PR #124) + and mp_{set,get}_double() (PR #123) + -- Francois Perrad took care of linting the sources, provided all fixes and + a astylerc to auto-format the sources. + -- A bunch of patches by Kevin B Kenny have been back-ported from TCL + -- Jan Nijtmans provided the patches to `const`ify all API + function arguments (also from TCL) + -- mp_rand() has now several native random provider implementations + and doesn't rely on `rand()` anymore + -- Karel Miko provided fixes when building for MS Windows + and re-worked the makefile generating process + -- The entire environment and build logic has been extended and improved + regarding auto-detection of platforms, libtool and a lot more + -- Prevent some potential BOF cases + -- Improved/fixed mp_lshd() and mp_invmod() + -- A load more bugs were fixed by various contributors + + +Aug 29th, 2017 +v1.0.1 + -- Dmitry Kovalenko provided fixes to mp_add_d() and mp_init_copy() + -- Matt Johnston contributed some improvements to mp_div_2d(), + mp_exptmod_fast(), mp_mod() and mp_mulmod() + -- Julien Nabet provided a fix to the error handling in mp_init_multi() + -- Ben Gardner provided a fix regarding usage of reserved keywords + -- Fixed mp_rand() to fill the correct number of bits + -- Fixed mp_invmod() + -- Use the same 64-bit detection code as in libtomcrypt + -- Correct usage of DESTDIR, PREFIX, etc. when installing the library + -- Francois Perrad updated all the perl scripts to an actual perl version + + +Feb 5th, 2016 +v1.0 + -- Bump to 1.0 + -- Dirkjan Bussink provided a faster version of mp_expt_d() + -- Moritz Lenz contributed a fix to mp_mod() + and provided mp_get_long() and mp_set_long() + -- Fixed bugs in mp_read_radix(), mp_radix_size + Thanks to shameister, Gerhard R, + -- Christopher Brown provided mp_export() and mp_import() + -- Improvements in the code of mp_init_copy() + Thanks to ramkumarkoppu, + -- lomereiter provided mp_balance_mul() + -- Alexander Boström from the heimdal project contributed patches to + mp_prime_next_prime() and mp_invmod() and added a mp_isneg() macro + -- Fix build issues for Linux x32 ABI + -- Added mp_get_long_long() and mp_set_long_long() + -- Carlin provided a patch to use arc4random() instead of rand() + on platforms where it is supported + -- Karel Miko provided mp_sqrtmod_prime() + + +July 23rd, 2010 +v0.42.0 + -- Fix for mp_prime_next_prime() bug when checking generated prime + -- allow mp_shrink to shrink initialized, but empty MPI's + -- Added project and solution files for Visual Studio 2005 and Visual Studio 2008. + +March 10th, 2007 +v0.41 -- Wolfgang Ehrhardt suggested a quick fix to mp_div_d() which makes the detection of powers of two quicker. + -- [CRI] Added libtommath.dsp for Visual C++ users. + +December 24th, 2006 +v0.40 -- Updated makefile to properly support LIBNAME + -- Fixed bug in fast_s_mp_mul_high_digs() which overflowed (line 83), thanks Valgrind! + +April 4th, 2006 +v0.39 -- Jim Wigginton pointed out my Montgomery examples in figures 6.4 and 6.6 were off by one, k should be 9 not 8 + -- Bruce Guenter suggested I use --tag=CC for libtool builds where the compiler may think it's C++. + -- "mm" from sci.crypt pointed out that my mp_gcd was sub-optimal (I also updated and corrected the book) + -- updated some of the @@ tags in tommath.src to reflect source changes. + -- updated email and url info in all source files + +Jan 26th, 2006 +v0.38 -- broken makefile.shared fixed + -- removed some carry stores that were not required [updated text] + +November 18th, 2005 +v0.37 -- [Don Porter] reported on a TCL list [HEY SEND ME BUGREPORTS ALREADY!!!] that mp_add_d() would compute -0 with some inputs. Fixed. + -- [rinick@gmail.com] reported the makefile.bcc was messed up. Fixed. + -- [Kevin Kenny] reported some issues with mp_toradix_n(). Now it doesn't require a min of 3 chars of output. + -- Made the make command renamable. Wee + +August 1st, 2005 +v0.36 -- LTM_PRIME_2MSB_ON was fixed and the "OFF" flag was removed. + -- [Peter LaDow] found a typo in the XREALLOC macro + -- [Peter LaDow] pointed out that mp_read_(un)signed_bin should have "const" on the input + -- Ported LTC patch to fix the prime_random_ex() function to get the bitsize correct [and the maskOR flags] + -- Kevin Kenny pointed out a stray // + -- David Hulton pointed out a typo in the textbook [mp_montgomery_setup() pseudo-code] + -- Neal Hamilton (Elliptic Semiconductor) pointed out that my Karatsuba notation was backwards and that I could use + unsigned operations in the routine. + -- Paul Schmidt pointed out a linking error in mp_exptmod() when BN_S_MP_EXPTMOD_C is undefined (and another for read_radix) + -- Updated makefiles to be way more flexible + +March 12th, 2005 +v0.35 -- Stupid XOR function missing line again... oops. + -- Fixed bug in invmod not handling negative inputs correctly [Wolfgang Ehrhardt] + -- Made exteuclid always give positive u3 output...[ Wolfgang Ehrhardt ] + -- [Wolfgang Ehrhardt] Suggested a fix for mp_reduce() which avoided underruns. ;-) + -- mp_rand() would emit one too many digits and it was possible to get a 0 out of it ... oops + -- Added montgomery to the testing to make sure it handles 1..10 digit moduli correctly + -- Fixed bug in comba that would lead to possible erroneous outputs when "pa < digs" + -- Fixed bug in mp_toradix_size for "0" [Kevin Kenny] + -- Updated chapters 1-5 of the textbook ;-) It now talks about the new comba code! + +February 12th, 2005 +v0.34 -- Fixed two more small errors in mp_prime_random_ex() + -- Fixed overflow in mp_mul_d() [Kevin Kenny] + -- Added mp_to_(un)signed_bin_n() functions which do bounds checking for ya [and report the size] + -- Added "large" diminished radix support. Speeds up things like DSA where the moduli is of the form 2^k - P for some P < 2^(k/2) or so + Actually is faster than Montgomery on my AMD64 (and probably much faster on a P4) + -- Updated the manual a bit + -- Ok so I haven't done the textbook work yet... My current freelance gig has landed me in France till the + end of Feb/05. Once I get back I'll have tons of free time and I plan to go to town on the book. + As of this release the API will freeze. At least until the book catches up with all the changes. I welcome + bug reports but new algorithms will have to wait. + +December 23rd, 2004 +v0.33 -- Fixed "small" variant for mp_div() which would munge with negative dividends... + -- Fixed bug in mp_prime_random_ex() which would set the most significant byte to zero when + no special flags were set + -- Fixed overflow [minor] bug in fast_s_mp_sqr() + -- Made the makefiles easier to configure the group/user that ltm will install as + -- Fixed "final carry" bug in comba multipliers. (Volkan Ceylan) + -- Matt Johnston pointed out a missing semi-colon in mp_exptmod + +October 29th, 2004 +v0.32 -- Added "makefile.shared" for shared object support + -- Added more to the build options/configs in the manual + -- Started the Depends framework, wrote dep.pl to scan deps and + produce "callgraph.txt" ;-) + -- Wrote SC_RSA_1 which will enable close to the minimum required to perform + RSA on 32-bit [or 64-bit] platforms with LibTomCrypt + -- Merged in the small/slower mp_div replacement. You can now toggle which + you want to use as your mp_div() at build time. Saves roughly 8KB or so. + -- Renamed a few files and changed some comments to make depends system work better. + (No changes to function names) + -- Merged in new Combas that perform 2 reads per inner loop instead of the older + 3reads/2writes per inner loop of the old code. Really though if you want speed + learn to use TomsFastMath ;-) + +August 9th, 2004 +v0.31 -- "profiled" builds now :-) new timings for Intel Northwoods + -- Added "pretty" build target + -- Update mp_init() to actually assign 0's instead of relying on calloc() + -- "Wolfgang Ehrhardt" found a bug in mp_mul() where if + you multiply a negative by zero you get negative zero as the result. Oops. + -- J Harper from PeerSec let me toy with his AMD64 and I got 60-bit digits working properly + [this also means that I fixed a bug where if sizeof(int) < sizeof(mp_digit) it would bug] + +April 11th, 2004 +v0.30 -- Added "mp_toradix_n" which stores upto "n-1" least significant digits of an mp_int + -- Johan Lindh sent a patch so MSVC wouldn't whine about redefining malloc [in weird dll modes] + -- Henrik Goldman spotted a missing OPT_CAST in mp_fwrite() + -- Tuned tommath.h so that when MP_LOW_MEM is defined MP_PREC shall be reduced. + [I also allow MP_PREC to be externally defined now] + -- Sped up mp_cnt_lsb() by using a 4x4 table [e.g. 4x speedup] + -- Added mp_prime_random_ex() which is a more versatile prime generator accurate to + exact bit lengths (unlike the deprecated but still available mp_prime_random() which + is only accurate to byte lengths). See the new LTM_PRIME_* flags ;-) + -- Alex Polushin contributed an optimized mp_sqrt() as well as mp_get_int() and mp_is_square(). + I've cleaned them all up to be a little more consistent [along with one bug fix] for this release. + -- Added mp_init_set and mp_init_set_int to initialize and set small constants with one function + call. + -- Removed /etclib directory [um LibTomPoly deprecates this]. + -- Fixed mp_mod() so the sign of the result agrees with the sign of the modulus. + ++ N.B. My semester is almost up so expect updates to the textbook to be posted to the libtomcrypt.org + website. + +Jan 25th, 2004 +v0.29 ++ Note: "Henrik" from the v0.28 changelog refers to Henrik Goldman ;-) + -- Added fix to mp_shrink to prevent a realloc when used == 0 [e.g. realloc zero bytes???] + -- Made the mp_prime_rabin_miller_trials() function internal table smaller and also + set the minimum number of tests to two (sounds a bit safer). + -- Added a mp_exteuclid() which computes the extended euclidean algorithm. + -- Fixed a memory leak in s_mp_exptmod() [called when Barrett reduction is to be used] which would arise + if a multiplication or subsequent reduction failed [would not free the temp result]. + -- Made an API change to mp_radix_size(). It now returns an error code and stores the required size + through an "int star" passed to it. + +Dec 24th, 2003 +v0.28 -- Henrik Goldman suggested I add casts to the montomgery code [stores into mu...] so compilers wouldn't + spew [erroneous] diagnostics... fixed. + -- Henrik Goldman also spotted two typos. One in mp_radix_size() and another in mp_toradix(). + -- Added fix to mp_shrink() to avoid a memory leak. + -- Added mp_prime_random() which requires a callback to make truly random primes of a given nature + (idea from chat with Niels Ferguson at Crypto'03) + -- Picked up a second wind. I'm filled with Gooo. Mission Gooo! + -- Removed divisions from mp_reduce_is_2k() + -- Sped up mp_div_d() [general case] to use only one division per digit instead of two. + -- Added the heap macros from LTC to LTM. Now you can easily [by editing four lines of tommath.h] + change the name of the heap functions used in LTM [also compatible with LTC via MPI mode] + -- Added bn_prime_rabin_miller_trials() which gives the number of Rabin-Miller trials to achieve + a failure rate of less than 2^-96 + -- fixed bug in fast_mp_invmod(). The initial testing logic was wrong. An invalid input is not when + "a" and "b" are even it's when "b" is even [the algo is for odd moduli only]. + -- Started a new manual [finally]. It is incomplete and will be finished as time goes on. I had to stop + adding full demos around half way in chapter three so I could at least get a good portion of the + manual done. If you really need help using the library you can always email me! + -- My Textbook is now included as part of the package [all Public Domain] + +Sept 19th, 2003 +v0.27 -- Removed changes.txt~ which was made by accident since "kate" decided it was + a good time to re-enable backups... [kde is fun!] + -- In mp_grow() "a->dp" is not overwritten by realloc call [re: memory leak] + Now if mp_grow() fails the mp_int is still valid and can be cleared via + mp_clear() to reclaim the memory. + -- Henrik Goldman found a buffer overflow bug in mp_add_d(). Fixed. + -- Cleaned up mp_mul_d() to be much easier to read and follow. + +Aug 29th, 2003 +v0.26 -- Fixed typo that caused warning with GCC 3.2 + -- Martin Marcel noticed a bug in mp_neg() that allowed negative zeroes. + Also, Martin is the fellow who noted the bugs in mp_gcd() of 0.24/0.25. + -- Martin Marcel noticed an optimization [and slight bug] in mp_lcm(). + -- Added fix to mp_read_unsigned_bin to prevent a buffer overflow. + -- Beefed up the comments in the baseline multipliers [and montgomery] + -- Added "mont" demo to the makefile.msvc in etc/ + -- Optimized sign compares in mp_cmp from 4 to 2 cases. + +Aug 4th, 2003 +v0.25 -- Fix to mp_gcd again... oops (0,-a) == (-a, 0) == a + -- Fix to mp_clear which didn't reset the sign [Greg Rose] + -- Added mp_error_to_string() to convert return codes to strings. [Greg Rose] + -- Optimized fast_mp_invmod() to do the test for invalid inputs [both even] + first so temps don't have to be initialized if it's going to fail. + -- Optimized mp_gcd() by removing mp_div_2d calls for when one of the inputs + is odd. + -- Tons of new comments, some indentation fixups, etc. + -- mp_jacobi() returns MP_VAL if the modulus is less than or equal to zero. + -- fixed two typos in the header of each file :-) + -- LibTomMath is officially Public Domain [see LICENSE] + +July 15th, 2003 +v0.24 -- Optimized mp_add_d and mp_sub_d to not allocate temporary variables + -- Fixed mp_gcd() so the gcd of 0,0 is 0. Allows the gcd operation to be chained + e.g. (0,0,a) == a [instead of 1] + -- Should be one of the last release for a while. Working on LibTomMath book now. + -- optimized the pprime demo [/etc/pprime.c] to first make a huge table of single + digit primes then it reads them randomly instead of randomly choosing/testing single + digit primes. + +July 12th, 2003 +v0.23 -- Optimized mp_prime_next_prime() to not use mp_mod [via is_divisible()] in each + iteration. Instead now a smaller table is kept of the residues which can be updated + without division. + -- Fixed a bug in next_prime() where an input of zero would be treated as odd and + have two added to it [to move to the next odd]. + -- fixed a bug in prime_fermat() and prime_miller_rabin() which allowed the base + to be negative, zero or one. Normally the test is only valid if the base is + greater than one. + -- changed the next_prime() prototype to accept a new parameter "bbs_style" which + will find the next prime congruent to 3 mod 4. The default [bbs_style==0] will + make primes which are either congruent to 1 or 3 mod 4. + -- fixed mp_read_unsigned_bin() so that it doesn't include both code for + the case DIGIT_BIT < 8 and >= 8 + -- optimized div_d() to easy out on division by 1 [or if a == 0] and use + logical shifts if the divisor is a power of two. + -- the default DIGIT_BIT type was not int for non-default builds. Fixed. + +July 2nd, 2003 +v0.22 -- Fixed up mp_invmod so the result is properly in range now [was always congruent to the inverse...] + -- Fixed up s_mp_exptmod and mp_exptmod_fast so the lower half of the pre-computed table isn't allocated + which makes the algorithm use half as much ram. + -- Fixed the install script not to make the book :-) [which isn't included anyways] + -- added mp_cnt_lsb() which counts how many of the lsbs are zero + -- optimized mp_gcd() to use the new mp_cnt_lsb() to replace multiple divisions by two by a single division. + -- applied similar optimization to mp_prime_miller_rabin(). + -- Fixed a bug in both mp_invmod() and fast_mp_invmod() which tested for odd + via "mp_iseven() == 0" which is not valid [since zero is not even either]. + +June 19th, 2003 +v0.21 -- Fixed bug in mp_mul_d which would not handle sign correctly [would not always forward it] + -- Removed the #line lines from gen.pl [was in violation of ISO C] + +June 8th, 2003 +v0.20 -- Removed the book from the package. Added the TDCAL license document. + -- This release is officially pure-bred TDCAL again [last officially TDCAL based release was v0.16] + +June 6th, 2003 +v0.19 -- Fixed a bug in mp_montgomery_reduce() which was introduced when I tweaked mp_rshd() in the previous release. + Essentially the digits were not trimmed before the compare which cause a subtraction to occur all the time. + -- Fixed up etc/tune.c a bit to stop testing new cutoffs after 16 failures [to find more optimal points]. + Brute force ho! + + +May 29th, 2003 +v0.18 -- Fixed a bug in s_mp_sqr which would handle carries properly just not very elegantly. + (e.g. correct result, just bad looking code) + -- Fixed bug in mp_sqr which still had a 512 constant instead of MP_WARRAY + -- Added Toom-Cook multipliers [needs tuning!] + -- Added efficient divide by 3 algorithm mp_div_3 + -- Re-wrote mp_div_d to be faster than calling mp_div + -- Added in a donated BCC makefile and a single page LTM poster (ahalhabsi@sbcglobal.net) + -- Added mp_reduce_2k which reduces an input modulo n = 2**p - k for any single digit k + -- Made the exptmod system be aware of the 2k reduction algorithms. + -- Rewrote mp_dr_reduce to be smaller, simpler and easier to understand. + +May 17th, 2003 +v0.17 -- Benjamin Goldberg submitted optimized mp_add and mp_sub routines. A new gen.pl as well + as several smaller suggestions. Thanks! + -- removed call to mp_cmp in inner loop of mp_div and put mp_cmp_mag in its place :-) + -- Fixed bug in mp_exptmod that would cause it to fail for odd moduli when DIGIT_BIT != 28 + -- mp_exptmod now also returns errors if the modulus is negative and will handle negative exponents + -- mp_prime_is_prime will now return true if the input is one of the primes in the prime table + -- Damian M Gryski (dgryski@uwaterloo.ca) found a index out of bounds error in the + mp_fast_s_mp_mul_high_digs function which didn't come up before. (fixed) + -- Refactored the DR reduction code so there is only one function per file. + -- Fixed bug in the mp_mul() which would erroneously avoid the faster multiplier [comba] when it was + allowed. The bug would not cause the incorrect value to be produced just less efficient (fixed) + -- Fixed similar bug in the Montgomery reduction code. + -- Added tons of (mp_digit) casts so the 7/15/28/31 bit digit code will work flawlessly out of the box. + Also added limited support for 64-bit machines with a 60-bit digit. Both thanks to Tom Wu (tom@arcot.com) + -- Added new comments here and there, cleaned up some code [style stuff] + -- Fixed a lingering typo in mp_exptmod* that would set bitcnt to zero then one. Very silly stuff :-) + -- Fixed up mp_exptmod_fast so it would set "redux" to the comba Montgomery reduction if allowed. This + saves quite a few calls and if statements. + -- Added etc/mont.c a test of the Montgomery reduction [assuming all else works :-| ] + -- Fixed up etc/tune.c to use a wider test range [more appropriate] also added a x86 based addition which + uses RDTSC for high precision timing. + -- Updated demo/demo.c to remove MPI stuff [won't work anyways], made the tests run for 2 seconds each so its + not so insanely slow. Also made the output space delimited [and fixed up various errors] + -- Added logs directory, logs/graph.dem which will use gnuplot to make a series of PNG files + that go with the pre-made index.html. You have to build [via make timing] and run ltmtest first in the + root of the package. + -- Fixed a bug in mp_sub and mp_add where "-a - -a" or "-a + a" would produce -0 as the result [obviously invalid]. + -- Fixed a bug in mp_rshd. If the count == a.used it should zero/return [instead of shifting] + -- Fixed a "off-by-one" bug in mp_mul2d. The initial size check on alloc would be off by one if the residue + shifting caused a carry. + -- Fixed a bug where s_mp_mul_digs() would not call the Comba based routine if allowed. This made Barrett reduction + slower than it had to be. + +Mar 29th, 2003 +v0.16 -- Sped up mp_div by making normalization one shift call + -- Sped up mp_mul_2d/mp_div_2d by aliasing pointers :-) + -- Cleaned up mp_gcd to use the macros for odd/even detection + -- Added comments here and there, mostly there but occasionally here too. + +Mar 22nd, 2003 +v0.15 -- Added series of prime testing routines to lib + -- Fixed up etc/tune.c + -- Added DR reduction algorithm + -- Beefed up the manual more. + -- Fixed up demo/demo.c so it doesn't have so many warnings and it does the full series of + tests + -- Added "pre-gen" directory which will hold a "gen.pl"'ed copy of the entire lib [done at + zipup time so its always the latest] + -- Added conditional casts for C++ users [boo!] + +Mar 15th, 2003 +v0.14 -- Tons of manual updates + -- cleaned up the directory + -- added MSVC makefiles + -- source changes [that I don't recall] + -- Fixed up the lshd/rshd code to use pointer aliasing + -- Fixed up the mul_2d and div_2d to not call rshd/lshd unless needed + -- Fixed up etc/tune.c a tad + -- fixed up demo/demo.c to output comma-delimited results of timing + also fixed up timing demo to use a finer granularity for various functions + -- fixed up demo/demo.c testing to pause during testing so my Duron won't catch on fire + [stays around 31-35C during testing :-)] + +Feb 13th, 2003 +v0.13 -- tons of minor speed-ups in low level add, sub, mul_2 and div_2 which propagate + to other functions like mp_invmod, mp_div, etc... + -- Sped up mp_exptmod_fast by using new code to find R mod m [e.g. B^n mod m] + -- minor fixes + +Jan 17th, 2003 +v0.12 -- re-wrote the majority of the makefile so its more portable and will + install via "make install" on most *nix platforms + -- Re-packaged all the source as seperate files. Means the library a single + file packagage any more. Instead of just adding "bn.c" you have to add + libtommath.a + -- Renamed "bn.h" to "tommath.h" + -- Changes to the manual to reflect all of this + -- Used GNU Indent to clean up the source + +Jan 15th, 2003 +v0.11 -- More subtle fixes + -- Moved to gentoo linux [hurrah!] so made *nix specific fixes to the make process + -- Sped up the montgomery reduction code quite a bit + -- fixed up demo so when building timing for the x86 it assumes ELF format now + +Jan 9th, 2003 +v0.10 -- Pekka Riikonen suggested fixes to the radix conversion code. + -- Added baseline montgomery and comba montgomery reductions, sped up exptmods + [to a point, see bn.h for MONTGOMERY_EXPT_CUTOFF] + +Jan 6th, 2003 +v0.09 -- Updated the manual to reflect recent changes. :-) + -- Added Jacobi function (mp_jacobi) to supplement the number theory side of the lib + -- Added a Mersenne prime finder demo in ./etc/mersenne.c + +Jan 2nd, 2003 +v0.08 -- Sped up the multipliers by moving the inner loop variables into a smaller scope + -- Corrected a bunch of small "warnings" + -- Added more comments + -- Made "mtest" be able to use /dev/random, /dev/urandom or stdin for RNG data + -- Corrected some bugs where error messages were potentially ignored + -- add etc/pprime.c program which makes numbers which are provably prime. + +Jan 1st, 2003 +v0.07 -- Removed alot of heap operations from core functions to speed them up + -- Added a root finding function [and mp_sqrt macro like from MPI] + -- Added more to manual + +Dec 31st, 2002 +v0.06 -- Sped up the s_mp_add, s_mp_sub which inturn sped up mp_invmod, mp_exptmod, etc... + -- Cleaned up the header a bit more + +Dec 30th, 2002 +v0.05 -- Builds with MSVC out of the box + -- Fixed a bug in mp_invmod w.r.t. even moduli + -- Made mp_toradix and mp_read_radix use char instead of unsigned char arrays + -- Fixed up exptmod to use fewer multiplications + -- Fixed up mp_init_size to use only one heap operation + -- Note there is a slight "off-by-one" bug in the library somewhere + without the padding (see the source for comment) the library + crashes in libtomcrypt. Anyways a reasonable workaround is to pad the + numbers which will always correct it since as the numbers grow the padding + will still be beyond the end of the number + -- Added more to the manual + +Dec 29th, 2002 +v0.04 -- Fixed a memory leak in mp_to_unsigned_bin + -- optimized invmod code + -- Fixed bug in mp_div + -- use exchange instead of copy for results + -- added a bit more to the manual + +Dec 27th, 2002 +v0.03 -- Sped up s_mp_mul_high_digs by not computing the carries of the lower digits + -- Fixed a bug where mp_set_int wouldn't zero the value first and set the used member. + -- fixed a bug in s_mp_mul_high_digs where the limit placed on the result digits was not calculated properly + -- fixed bugs in add/sub/mul/sqr_mod functions where if the modulus and dest were the same it wouldn't work + -- fixed a bug in mp_mod and mp_mod_d concerning negative inputs + -- mp_mul_d didn't preserve sign + -- Many many many many fixes + -- Works in LibTomCrypt now :-) + -- Added iterations to the timing demos... more accurate. + -- Tom needs a job. + +Dec 26th, 2002 +v0.02 -- Fixed a few "slips" in the manual. This is "LibTomMath" afterall :-) + -- Added mp_cmp_mag, mp_neg, mp_abs and mp_radix_size that were missing. + -- Sped up the fast [comba] multipliers more [yahoo!] + +Dec 25th,2002 +v0.01 -- Initial release. Gimme a break. + -- Todo list, + add details to manual [e.g. algorithms] + more comments in code + example programs diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/mtest_opponent.c b/third_party/heimdal/lib/hcrypto/libtommath/demo/mtest_opponent.c new file mode 100644 index 0000000..7fbd35e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/mtest_opponent.c @@ -0,0 +1,402 @@ +#include "shared.h" + +#ifdef LTM_MTEST_REAL_RAND +#define LTM_MTEST_RAND_SEED time(NULL) +#else +#define LTM_MTEST_RAND_SEED 23 +#endif + +static void draw(mp_int *a) +{ + ndraw(a, ""); +} + +#define FGETS(str, size, stream) \ + { \ + char *ret = fgets(str, size, stream); \ + if (!ret) { fprintf(stderr, "\n%d: fgets failed\n", __LINE__); goto LBL_ERR; } \ + } + +static int mtest_opponent(void) +{ + char cmd[4096]; + char buf[4096]; + int ix; + unsigned rr; + mp_int a, b, c, d, e, f; + unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, + gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n; + + srand(LTM_MTEST_RAND_SEED); + + if (mp_init_multi(&a, &b, &c, &d, &e, &f, NULL)!= MP_OKAY) + return EXIT_FAILURE; + + div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = + sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = add_d_n = sub_d_n = 0; + +#ifndef MP_FIXED_CUTOFFS + /* force KARA and TOOM to enable despite cutoffs */ + KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8; + TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16; +#endif + + for (;;) { + /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ + switch (abs(rand()) % 7) { + case 0: + mp_clear(&a); + mp_init(&a); + break; + case 1: + mp_clear(&b); + mp_init(&b); + break; + case 2: + mp_clear(&c); + mp_init(&c); + break; + case 3: + mp_clear(&d); + mp_init(&d); + break; + case 4: + mp_clear(&e); + mp_init(&e); + break; + case 5: + mp_clear(&f); + mp_init(&f); + break; + case 6: + break; /* don't clear any */ + } + + + printf("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", + add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, + expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); + FGETS(cmd, 4095, stdin); + cmd[strlen(cmd) - 1u] = '\0'; + printf("%-6s ]\r", cmd); + fflush(stdout); + if (strcmp(cmd, "mul2d") == 0) { + ++mul2d_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + sscanf(buf, "%u", &rr); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + + mp_mul_2d(&a, (int)rr, &a); + a.sign = b.sign; + if (mp_cmp(&a, &b) != MP_EQ) { + printf("mul2d failed, rr == %u\n", rr); + draw(&a); + draw(&b); + goto LBL_ERR; + } + } else if (strcmp(cmd, "div2d") == 0) { + ++div2d_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + sscanf(buf, "%u", &rr); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + + mp_div_2d(&a, (int)rr, &a, &e); + a.sign = b.sign; + if ((a.used == b.used) && (a.used == 0)) { + a.sign = b.sign = MP_ZPOS; + } + if (mp_cmp(&a, &b) != MP_EQ) { + printf("div2d failed, rr == %u\n", rr); + draw(&a); + draw(&b); + goto LBL_ERR; + } + } else if (strcmp(cmd, "add") == 0) { + ++add_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_add(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("add %lu failure!\n", add_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + goto LBL_ERR; + } + + /* test the sign/unsigned storage functions */ + + rr = (unsigned)mp_sbin_size(&c); + mp_to_sbin(&c, (unsigned char *) cmd, (size_t)rr, NULL); + memset(cmd + rr, rand() & 0xFF, sizeof(cmd) - rr); + mp_from_sbin(&d, (unsigned char *) cmd, (size_t)rr); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("mp_signed_bin failure!\n"); + draw(&c); + draw(&d); + goto LBL_ERR; + } + + rr = (unsigned)mp_ubin_size(&c); + mp_to_ubin(&c, (unsigned char *) cmd, (size_t)rr, NULL); + memset(cmd + rr, rand() & 0xFF, sizeof(cmd) - rr); + mp_from_ubin(&d, (unsigned char *) cmd, (size_t)rr); + if (mp_cmp_mag(&c, &d) != MP_EQ) { + printf("mp_unsigned_bin failure!\n"); + draw(&c); + draw(&d); + goto LBL_ERR; + } + + } else if (strcmp(cmd, "sub") == 0) { + ++sub_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_sub(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("sub %lu failure!\n", sub_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + goto LBL_ERR; + } + } else if (strcmp(cmd, "mul") == 0) { + ++mul_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_mul(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("mul %lu failure!\n", mul_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + goto LBL_ERR; + } + } else if (strcmp(cmd, "div") == 0) { + ++div_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&d, buf, 64); + + mp_div(&a, &b, &e, &f); + if ((mp_cmp(&c, &e) != MP_EQ) || (mp_cmp(&d, &f) != MP_EQ)) { + printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), + mp_cmp(&d, &f)); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + draw(&e); + draw(&f); + goto LBL_ERR; + } + + } else if (strcmp(cmd, "sqr") == 0) { + ++sqr_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_copy(&a, &c); + mp_sqr(&c, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("sqr %lu failure!\n", sqr_n); + draw(&a); + draw(&b); + draw(&c); + goto LBL_ERR; + } + } else if (strcmp(cmd, "gcd") == 0) { + ++gcd_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_gcd(&d, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("gcd %lu failure!\n", gcd_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + goto LBL_ERR; + } + } else if (strcmp(cmd, "lcm") == 0) { + ++lcm_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_lcm(&d, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("lcm %lu failure!\n", lcm_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + goto LBL_ERR; + } + } else if (strcmp(cmd, "expt") == 0) { + ++expt_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&d, buf, 64); + mp_copy(&a, &e); + mp_exptmod(&e, &b, &c, &e); + if (mp_cmp(&d, &e) != MP_EQ) { + printf("expt %lu failure!\n", expt_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + draw(&e); + goto LBL_ERR; + } + } else if (strcmp(cmd, "invmod") == 0) { + ++inv_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_invmod(&a, &b, &d); + mp_mulmod(&d, &a, &b, &e); + if (mp_cmp_d(&e, 1uL) != MP_EQ) { + printf("inv [wrong value from MPI?!] failure\n"); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + draw(&e); + mp_gcd(&a, &b, &e); + draw(&e); + goto LBL_ERR; + } + + } else if (strcmp(cmd, "div2") == 0) { + ++div2_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_div_2(&a, &c); + if (mp_cmp(&c, &b) != MP_EQ) { + printf("div_2 %lu failure\n", div2_n); + draw(&a); + draw(&b); + draw(&c); + goto LBL_ERR; + } + } else if (strcmp(cmd, "mul2") == 0) { + ++mul2_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_mul_2(&a, &c); + if (mp_cmp(&c, &b) != MP_EQ) { + printf("mul_2 %lu failure\n", mul2_n); + draw(&a); + draw(&b); + draw(&c); + goto LBL_ERR; + } + } else if (strcmp(cmd, "add_d") == 0) { + ++add_d_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + sscanf(buf, "%d", &ix); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_add_d(&a, (mp_digit)ix, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("add_d %lu failure\n", add_d_n); + draw(&a); + draw(&b); + draw(&c); + printf("d == %d\n", ix); + goto LBL_ERR; + } + } else if (strcmp(cmd, "sub_d") == 0) { + ++sub_d_n; + FGETS(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + FGETS(buf, 4095, stdin); + sscanf(buf, "%d", &ix); + FGETS(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_sub_d(&a, (mp_digit)ix, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("sub_d %lu failure\n", sub_d_n); + draw(&a); + draw(&b); + draw(&c); + printf("d == %d\n", ix); + goto LBL_ERR; + } + } else if (strcmp(cmd, "exit") == 0) { + printf("\nokay, exiting now\n"); + break; + } + } + + mp_clear_multi(&a, &b, &c, &d, &e, &f, NULL); + printf("\n"); + return 0; + +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, &e, &f, NULL); + printf("\n"); + return EXIT_FAILURE; +} + +int main(void) +{ + print_header(); + + return mtest_opponent(); +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.c b/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.c new file mode 100644 index 0000000..dc8e05a --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.c @@ -0,0 +1,42 @@ +#include "shared.h" + +void ndraw(mp_int *a, const char *name) +{ + char *buf = NULL; + int size; + + mp_radix_size(a, 10, &size); + buf = (char *)malloc((size_t) size); + if (buf == NULL) { + fprintf(stderr, "\nndraw: malloc(%d) failed\n", size); + exit(EXIT_FAILURE); + } + + printf("%s: ", name); + mp_to_decimal(a, buf, (size_t) size); + printf("%s\n", buf); + mp_to_hex(a, buf, (size_t) size); + printf("0x%s\n", buf); + + free(buf); +} + +void print_header(void) +{ +#ifdef MP_8BIT + printf("Digit size 8 Bit \n"); +#endif +#ifdef MP_16BIT + printf("Digit size 16 Bit \n"); +#endif +#ifdef MP_32BIT + printf("Digit size 32 Bit \n"); +#endif +#ifdef MP_64BIT + printf("Digit size 64 Bit \n"); +#endif + printf("Size of mp_digit: %u\n", (unsigned int)sizeof(mp_digit)); + printf("Size of mp_word: %u\n", (unsigned int)sizeof(mp_word)); + printf("MP_DIGIT_BIT: %d\n", MP_DIGIT_BIT); + printf("MP_PREC: %d\n", MP_PREC); +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.h b/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.h new file mode 100644 index 0000000..4d5eb53 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/shared.h @@ -0,0 +1,21 @@ +#include +#include +#include + +/* + * Configuration + */ +#ifndef LTM_DEMO_TEST_REDUCE_2K_L +/* This test takes a moment so we disable it by default, but it can be: + * 0 to disable testing + * 1 to make the test with P = 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF + * 2 to make the test with P = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F + */ +#define LTM_DEMO_TEST_REDUCE_2K_L 0 +#endif + +#define MP_WUR /* TODO: result checks disabled for now */ +#include "tommath_private.h" + +extern void ndraw(mp_int* a, const char* name); +extern void print_header(void); diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c b/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c new file mode 100644 index 0000000..9049fa8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/test.c @@ -0,0 +1,2522 @@ +#include +#include "shared.h" + +static long rand_long(void) +{ + long x; + if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) { + fprintf(stderr, "s_mp_rand_source failed\n"); + exit(EXIT_FAILURE); + } + return x; +} + +static int rand_int(void) +{ + int x; + if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) { + fprintf(stderr, "s_mp_rand_source failed\n"); + exit(EXIT_FAILURE); + } + return x; +} + +static int32_t rand_int32(void) +{ + int32_t x; + if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) { + fprintf(stderr, "s_mp_rand_source failed\n"); + exit(EXIT_FAILURE); + } + return x; +} + +static int64_t rand_int64(void) +{ + int64_t x; + if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) { + fprintf(stderr, "s_mp_rand_source failed\n"); + exit(EXIT_FAILURE); + } + return x; +} + +static uint32_t uabs32(int32_t x) +{ + return x > 0 ? (uint32_t)x : -(uint32_t)x; +} + +static uint64_t uabs64(int64_t x) +{ + return x > 0 ? (uint64_t)x : -(uint64_t)x; +} + +/* This function prototype is needed + * to test dead code elimination + * which is used for feature detection. + * + * If the feature detection does not + * work as desired we will get a linker error. + */ +void does_not_exist(void); + +static int test_feature_detection(void) +{ +#define BN_TEST_FEATURE1_C + if (!MP_HAS(TEST_FEATURE1)) { + does_not_exist(); + return EXIT_FAILURE; + } + +#define BN_TEST_FEATURE2_C 1 + if (MP_HAS(TEST_FEATURE2)) { + does_not_exist(); + return EXIT_FAILURE; + } + +#define BN_TEST_FEATURE3_C 0 + if (MP_HAS(TEST_FEATURE3)) { + does_not_exist(); + return EXIT_FAILURE; + } + +#define BN_TEST_FEATURE4_C something + if (MP_HAS(TEST_FEATURE4)) { + does_not_exist(); + return EXIT_FAILURE; + } + + if (MP_HAS(TEST_FEATURE5)) { + does_not_exist(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int test_trivial_stuff(void) +{ + mp_int a, b, c, d; + mp_err e; + if ((e = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) { + return EXIT_FAILURE; + } + (void)mp_error_to_string(e); + + /* a: 0->5 */ + mp_set(&a, 5u); + /* a: 5-> b: -5 */ + mp_neg(&a, &b); + if (mp_cmp(&a, &b) != MP_GT) { + goto LBL_ERR; + } + if (mp_cmp(&b, &a) != MP_LT) { + goto LBL_ERR; + } + /* a: 5-> a: -5 */ + mp_neg(&a, &a); + if (mp_cmp(&b, &a) != MP_EQ) { + goto LBL_ERR; + } + /* a: -5-> b: 5 */ + mp_abs(&a, &b); + if (mp_isneg(&b) != MP_NO) { + goto LBL_ERR; + } + /* a: -5-> b: -4 */ + mp_add_d(&a, 1uL, &b); + if (mp_isneg(&b) != MP_YES) { + goto LBL_ERR; + } + if (mp_get_i32(&b) != -4) { + goto LBL_ERR; + } + if (mp_get_u32(&b) != (uint32_t)-4) { + goto LBL_ERR; + } + if (mp_get_mag_u32(&b) != 4) { + goto LBL_ERR; + } + /* a: -5-> b: 1 */ + mp_add_d(&a, 6uL, &b); + if (mp_get_u32(&b) != 1) { + goto LBL_ERR; + } + /* a: -5-> a: 1 */ + mp_add_d(&a, 6uL, &a); + if (mp_get_u32(&a) != 1) { + goto LBL_ERR; + } + mp_zero(&a); + /* a: 0-> a: 6 */ + mp_add_d(&a, 6uL, &a); + if (mp_get_u32(&a) != 6) { + goto LBL_ERR; + } + + mp_set(&a, 42u); + mp_set(&b, 1u); + mp_neg(&b, &b); + mp_set(&c, 1u); + mp_exptmod(&a, &b, &c, &d); + + mp_set(&c, 7u); + mp_exptmod(&a, &b, &c, &d); + + if (mp_iseven(&a) == mp_isodd(&a)) { + goto LBL_ERR; + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int check_get_set_i32(mp_int *a, int32_t b) +{ + mp_clear(a); + if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE; + + mp_set_i32(a, b); + if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE; + if (mp_get_i32(a) != b) return EXIT_FAILURE; + if (mp_get_u32(a) != (uint32_t)b) return EXIT_FAILURE; + if (mp_get_mag_u32(a) != uabs32(b)) return EXIT_FAILURE; + + mp_set_u32(a, (uint32_t)b); + if (mp_get_u32(a) != (uint32_t)b) return EXIT_FAILURE; + if (mp_get_i32(a) != (int32_t)(uint32_t)b) return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int test_mp_get_set_i32(void) +{ + int i; + mp_int a; + + if (mp_init(&a) != MP_OKAY) { + return EXIT_FAILURE; + } + + check_get_set_i32(&a, 0); + check_get_set_i32(&a, -1); + check_get_set_i32(&a, 1); + check_get_set_i32(&a, INT32_MIN); + check_get_set_i32(&a, INT32_MAX); + + for (i = 0; i < 1000; ++i) { + int32_t b = rand_int32(); + if (check_get_set_i32(&a, b) != EXIT_SUCCESS) { + goto LBL_ERR; + } + } + + mp_clear(&a); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear(&a); + return EXIT_FAILURE; +} + +static int check_get_set_i64(mp_int *a, int64_t b) +{ + mp_clear(a); + if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE; + + mp_set_i64(a, b); + if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE; + if (mp_get_i64(a) != b) return EXIT_FAILURE; + if (mp_get_u64(a) != (uint64_t)b) return EXIT_FAILURE; + if (mp_get_mag_u64(a) != uabs64(b)) return EXIT_FAILURE; + + mp_set_u64(a, (uint64_t)b); + if (mp_get_u64(a) != (uint64_t)b) return EXIT_FAILURE; + if (mp_get_i64(a) != (int64_t)(uint64_t)b) return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int test_mp_get_set_i64(void) +{ + int i; + mp_int a; + + if (mp_init(&a) != MP_OKAY) { + return EXIT_FAILURE; + } + + check_get_set_i64(&a, 0); + check_get_set_i64(&a, -1); + check_get_set_i64(&a, 1); + check_get_set_i64(&a, INT64_MIN); + check_get_set_i64(&a, INT64_MAX); + + for (i = 0; i < 1000; ++i) { + int64_t b = rand_int64(); + if (check_get_set_i64(&a, b) != EXIT_SUCCESS) { + goto LBL_ERR; + } + } + + mp_clear(&a); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear(&a); + return EXIT_FAILURE; +} + +static int test_mp_fread_fwrite(void) +{ + mp_int a, b; + mp_err e; + FILE *tmp = NULL; + if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) { + return EXIT_FAILURE; + } + + mp_set_ul(&a, 123456uL); + tmp = tmpfile(); + if ((e = mp_fwrite(&a, 64, tmp)) != MP_OKAY) { + goto LBL_ERR; + } + rewind(tmp); + if ((e = mp_fread(&b, 64, tmp)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_get_u32(&b) != 123456uL) { + goto LBL_ERR; + } + fclose(tmp); + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + if (tmp != NULL) fclose(tmp); + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static mp_err very_random_source(void *out, size_t size) +{ + memset(out, 0xff, size); + return MP_OKAY; +} + +static int test_mp_rand(void) +{ + mp_int a, b; + int n; + mp_err err; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + mp_rand_source(very_random_source); + for (n = 1; n < 1024; ++n) { + if ((err = mp_rand(&a, n)) != MP_OKAY) { + printf("Failed mp_rand() %s.\n", mp_error_to_string(err)); + break; + } + if ((err = mp_incr(&a)) != MP_OKAY) { + printf("Failed mp_incr() %s.\n", mp_error_to_string(err)); + break; + } + if ((err = mp_div_2d(&a, n * MP_DIGIT_BIT, &b, NULL)) != MP_OKAY) { + printf("Failed mp_div_2d() %s.\n", mp_error_to_string(err)); + break; + } + if (mp_cmp_d(&b, 1) != MP_EQ) { + ndraw(&a, "mp_rand() a"); + ndraw(&b, "mp_rand() b"); + err = MP_ERR; + break; + } + } + mp_rand_source(s_mp_rand_jenkins); + mp_clear_multi(&a, &b, NULL); + return err == MP_OKAY ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static int test_mp_kronecker(void) +{ + struct mp_kronecker_st { + long n; + int c[21]; + }; + static struct mp_kronecker_st kronecker[] = { + /*-10, -9, -8, -7,-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10*/ + { -10, { 0, -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, 0, -1, 0, 0, 0, 1, 0, 1, 0 } }, + { -9, { -1, 0, -1, 1, 0, -1, -1, 0, -1, -1, 0, 1, 1, 0, 1, 1, 0, -1, 1, 0, 1 } }, + { -8, { 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0 } }, + { -7, { 1, -1, -1, 0, 1, 1, -1, 1, -1, -1, 0, 1, 1, -1, 1, -1, -1, 0, 1, 1, -1 } }, + { -6, { 0, 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0 } }, + { -5, { 0, -1, 1, -1, 1, 0, -1, -1, 1, -1, 0, 1, -1, 1, 1, 0, -1, 1, -1, 1, 0 } }, + { -4, { 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0 } }, + { -3, { -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1 } }, + { -2, { 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0 } }, + { -1, { -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1 } }, + { 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, + { 1, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }, + { 2, { 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0 } }, + { 3, { 1, 0, -1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0, 1 } }, + { 4, { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 } }, + { 5, { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0 } }, + { 6, { 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0 } }, + { 7, { -1, 1, 1, 0, 1, -1, 1, 1, 1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1, 1, -1 } }, + { 8, { 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0 } }, + { 9, { 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 } }, + { 10, { 0, 1, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0 } } + }; + + long k, m; + int i, cnt; + mp_err err; + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + mp_set_ul(&a, 0uL); + mp_set_ul(&b, 1uL); + if ((err = mp_kronecker(&a, &b, &i)) != MP_OKAY) { + printf("Failed executing mp_kronecker(0 | 1) %s.\n", mp_error_to_string(err)); + goto LBL_ERR; + } + if (i != 1) { + printf("Failed trivial mp_kronecker(0 | 1) %d != 1\n", i); + goto LBL_ERR; + } + for (cnt = 0; cnt < (int)(sizeof(kronecker)/sizeof(kronecker[0])); ++cnt) { + k = kronecker[cnt].n; + mp_set_l(&a, k); + /* only test positive values of a */ + for (m = -10; m <= 10; m++) { + mp_set_l(&b, m); + if ((err = mp_kronecker(&a, &b, &i)) != MP_OKAY) { + printf("Failed executing mp_kronecker(%ld | %ld) %s.\n", kronecker[cnt].n, m, mp_error_to_string(err)); + goto LBL_ERR; + } + if ((err == MP_OKAY) && (i != kronecker[cnt].c[m + 10])) { + printf("Failed trivial mp_kronecker(%ld | %ld) %d != %d\n", kronecker[cnt].n, m, i, kronecker[cnt].c[m + 10]); + goto LBL_ERR; + } + } + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_complement(void) +{ + int i; + + mp_int a, b, c; + if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + long l = rand_long(); + mp_set_l(&a, l); + mp_complement(&a, &b); + + l = ~l; + mp_set_l(&c, l); + + if (mp_cmp(&b, &c) != MP_EQ) { + printf("\nmp_complement() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_signed_rsh(void) +{ + int i; + + mp_int a, b, d; + if (mp_init_multi(&a, &b, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + long l; + int em; + + l = rand_long(); + mp_set_l(&a, l); + + em = abs(rand_int()) % 32; + + mp_set_l(&d, l >> em); + + mp_signed_rsh(&a, em, &b); + if (mp_cmp(&b, &d) != MP_EQ) { + printf("\nmp_signed_rsh() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &d, NULL); + return EXIT_FAILURE; + +} + +static int test_mp_xor(void) +{ + int i; + + mp_int a, b, c, d; + if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + long l, em; + + l = rand_long(); + mp_set_l(&a,l); + + em = rand_long(); + mp_set_l(&b, em); + + mp_set_l(&d, l ^ em); + + mp_xor(&a, &b, &c); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("\nmp_xor() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; + +} + +static int test_mp_or(void) +{ + int i; + + mp_int a, b, c, d; + if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + long l, em; + + l = rand_long(); + mp_set_l(&a, l); + + em = rand_long(); + mp_set_l(&b, em); + + mp_set_l(&d, l | em); + + mp_or(&a, &b, &c); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("\nmp_or() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int test_mp_and(void) +{ + int i; + + mp_int a, b, c, d; + if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + long l, em; + + l = rand_long(); + mp_set_l(&a, l); + + em = rand_long(); + mp_set_l(&b, em); + + mp_set_l(&d, l & em); + + mp_and(&a, &b, &c); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("\nmp_and() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int test_mp_invmod(void) +{ + mp_int a, b, c, d; + if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* mp_invmod corner-case of https://github.com/libtom/libtommath/issues/118 */ + { + const char *a_ = "47182BB8DF0FFE9F61B1F269BACC066B48BA145D35137D426328DC3F88A5EA44"; + const char *b_ = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"; + const char *should_ = "0521A82E10376F8E4FDEF9A32A427AC2A0FFF686E00290D39E3E4B5522409596"; + + if (mp_read_radix(&a, a_, 16) != MP_OKAY) { + printf("\nmp_read_radix(a) failed!"); + goto LBL_ERR; + } + if (mp_read_radix(&b, b_, 16) != MP_OKAY) { + printf("\nmp_read_radix(b) failed!"); + goto LBL_ERR; + } + if (mp_read_radix(&c, should_, 16) != MP_OKAY) { + printf("\nmp_read_radix(should) failed!"); + goto LBL_ERR; + } + + if (mp_invmod(&a, &b, &d) != MP_OKAY) { + printf("\nmp_invmod() failed!"); + goto LBL_ERR; + } + + if (mp_cmp(&c, &d) != MP_EQ) { + printf("\nmp_invmod() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; + +} + +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(_M_X86) || defined(__aarch64__) || defined(__arm__) +static int test_mp_set_double(void) +{ + int i; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test mp_get_double/mp_set_double */ + if (mp_set_double(&a, +1.0/0.0) != MP_VAL) { + printf("\nmp_set_double should return MP_VAL for +inf"); + goto LBL_ERR; + } + if (mp_set_double(&a, -1.0/0.0) != MP_VAL) { + printf("\nmp_set_double should return MP_VAL for -inf"); + goto LBL_ERR; + } + if (mp_set_double(&a, +0.0/0.0) != MP_VAL) { + printf("\nmp_set_double should return MP_VAL for NaN"); + goto LBL_ERR; + } + if (mp_set_double(&a, -0.0/0.0) != MP_VAL) { + printf("\nmp_set_double should return MP_VAL for NaN"); + goto LBL_ERR; + } + + for (i = 0; i < 1000; ++i) { + int tmp = rand_int(); + double dbl = (double)tmp * rand_int() + 1; + if (mp_set_double(&a, dbl) != MP_OKAY) { + printf("\nmp_set_double() failed"); + goto LBL_ERR; + } + if (dbl != mp_get_double(&a)) { + printf("\nmp_get_double() bad result!"); + goto LBL_ERR; + } + if (mp_set_double(&a, -dbl) != MP_OKAY) { + printf("\nmp_set_double() failed"); + goto LBL_ERR; + } + if (-dbl != mp_get_double(&a)) { + printf("\nmp_get_double() bad result!"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; + +} +#endif + +static int test_mp_get_u32(void) +{ + unsigned long t; + int i; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + t = (unsigned long)rand_long() & 0xFFFFFFFFuL; + mp_set_ul(&a, t); + if (t != mp_get_u32(&a)) { + printf("\nmp_get_u32() bad result!"); + goto LBL_ERR; + } + } + mp_set_ul(&a, 0uL); + if (mp_get_u32(&a) != 0) { + printf("\nmp_get_u32() bad result!"); + goto LBL_ERR; + } + mp_set_ul(&a, 0xFFFFFFFFuL); + if (mp_get_u32(&a) != 0xFFFFFFFFuL) { + printf("\nmp_get_u32() bad result!"); + goto LBL_ERR; + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_get_ul(void) +{ + unsigned long s, t; + int i; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < ((int)MP_SIZEOF_BITS(unsigned long) - 1); ++i) { + t = (1UL << (i+1)) - 1; + if (!t) + t = ~0UL; + printf(" t = 0x%lx i = %d\r", t, i); + do { + mp_set_ul(&a, t); + s = mp_get_ul(&a); + if (s != t) { + printf("\nmp_get_ul() bad result! 0x%lx != 0x%lx", s, t); + goto LBL_ERR; + } + t <<= 1; + } while (t != 0uL); + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_get_u64(void) +{ + unsigned long long q, r; + int i; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < (int)(MP_SIZEOF_BITS(unsigned long long) - 1); ++i) { + r = (1ULL << (i+1)) - 1; + if (!r) + r = ~0ULL; + printf(" r = 0x%llx i = %d\r", r, i); + do { + mp_set_u64(&a, r); + q = mp_get_u64(&a); + if (q != r) { + printf("\nmp_get_u64() bad result! 0x%llx != 0x%llx", q, r); + goto LBL_ERR; + } + r <<= 1; + } while (r != 0uLL); + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; + +} + +static int test_mp_sqrt(void) +{ + int i, n; + + mp_int a, b, c; + if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + printf("%6d\r", i); + fflush(stdout); + n = (rand_int() & 15) + 1; + mp_rand(&a, n); + if (mp_sqrt(&a, &b) != MP_OKAY) { + printf("\nmp_sqrt() error!"); + goto LBL_ERR; + } + mp_root_u32(&a, 2uL, &c); + if (mp_cmp_mag(&b, &c) != MP_EQ) { + printf("mp_sqrt() bad result!\n"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_is_square(void) +{ + int i, n; + + mp_int a, b; + mp_bool res; + + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + for (i = 0; i < 1000; ++i) { + printf("%6d\r", i); + fflush(stdout); + + /* test mp_is_square false negatives */ + n = (rand_int() & 7) + 1; + mp_rand(&a, n); + mp_sqr(&a, &a); + if (mp_is_square(&a, &res) != MP_OKAY) { + printf("\nfn:mp_is_square() error!"); + goto LBL_ERR; + } + if (res == MP_NO) { + printf("\nfn:mp_is_square() bad result!"); + goto LBL_ERR; + } + + /* test for false positives */ + mp_add_d(&a, 1uL, &a); + if (mp_is_square(&a, &res) != MP_OKAY) { + printf("\nfp:mp_is_square() error!"); + goto LBL_ERR; + } + if (res == MP_YES) { + printf("\nfp:mp_is_square() bad result!"); + goto LBL_ERR; + } + + } + printf("\n\n"); + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_sqrtmod_prime(void) +{ + struct mp_sqrtmod_prime_st { + unsigned long p; + unsigned long n; + mp_digit r; + }; + + static struct mp_sqrtmod_prime_st sqrtmod_prime[] = { + { 5, 14, 3 }, + { 7, 9, 4 }, + { 113, 2, 62 } + }; + int i; + + mp_int a, b, c; + if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* r^2 = n (mod p) */ + for (i = 0; i < (int)(sizeof(sqrtmod_prime)/sizeof(sqrtmod_prime[0])); ++i) { + mp_set_ul(&a, sqrtmod_prime[i].p); + mp_set_ul(&b, sqrtmod_prime[i].n); + if (mp_sqrtmod_prime(&b, &a, &c) != MP_OKAY) { + printf("Failed executing %d. mp_sqrtmod_prime\n", (i+1)); + goto LBL_ERR; + } + if (mp_cmp_d(&c, sqrtmod_prime[i].r) != MP_EQ) { + printf("Failed %d. trivial mp_sqrtmod_prime\n", (i+1)); + ndraw(&c, "r"); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_prime_rand(void) +{ + int ix; + mp_err err; + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test for size */ + for (ix = 10; ix < 128; ix++) { + printf("Testing (not safe-prime): %9d bits \r", ix); + fflush(stdout); + err = mp_prime_rand(&a, 8, ix, (rand_int() & 1) ? 0 : MP_PRIME_2MSB_ON); + if (err != MP_OKAY) { + printf("\nfailed with error: %s\n", mp_error_to_string(err)); + goto LBL_ERR; + } + if (mp_count_bits(&a) != ix) { + printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); + goto LBL_ERR; + } + } + printf("\n"); + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_prime_is_prime(void) +{ + int ix; + mp_err err; + mp_bool cnt, fu; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* strong Miller-Rabin pseudoprime to the first 200 primes (F. Arnault) */ + puts("Testing mp_prime_is_prime() with Arnault's pseudoprime 803...901 \n"); + mp_read_radix(&a, + "91xLNF3roobhzgTzoFIG6P13ZqhOVYSN60Fa7Cj2jVR1g0k89zdahO9/kAiRprpfO1VAp1aBHucLFV/qLKLFb+zonV7R2Vxp1K13ClwUXStpV0oxTNQVjwybmFb5NBEHImZ6V7P6+udRJuH8VbMEnS0H8/pSqQrg82OoQQ2fPpAk6G1hkjqoCv5s/Yr", + 64); + mp_prime_is_prime(&a, mp_prime_rabin_miller_trials(mp_count_bits(&a)), &cnt); + if (cnt == MP_YES) { + printf("Arnault's pseudoprime is not prime but mp_prime_is_prime says it is.\n"); + goto LBL_ERR; + } + /* About the same size as Arnault's pseudoprime */ + puts("Testing mp_prime_is_prime() with certified prime 2^1119 + 53\n"); + mp_set(&a, 1uL); + mp_mul_2d(&a,1119,&a); + mp_add_d(&a, 53uL, &a); + err = mp_prime_is_prime(&a, mp_prime_rabin_miller_trials(mp_count_bits(&a)), &cnt); + /* small problem */ + if (err != MP_OKAY) { + printf("\nfailed with error: %s\n", mp_error_to_string(err)); + } + /* large problem */ + if (cnt == MP_NO) { + printf("A certified prime is a prime but mp_prime_is_prime says it is not.\n"); + } + if ((err != MP_OKAY) || (cnt == MP_NO)) { + printf("prime tested was: 0x"); + mp_fwrite(&a,16,stdout); + putchar('\n'); + goto LBL_ERR; + } + for (ix = 16; ix < 128; ix++) { + printf("Testing ( safe-prime): %9d bits \r", ix); + fflush(stdout); + err = mp_prime_rand(&a, 8, ix, ((rand_int() & 1) ? 0 : MP_PRIME_2MSB_ON) | MP_PRIME_SAFE); + if (err != MP_OKAY) { + printf("\nfailed with error: %s\n", mp_error_to_string(err)); + goto LBL_ERR; + } + if (mp_count_bits(&a) != ix) { + printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); + goto LBL_ERR; + } + /* let's see if it's really a safe prime */ + mp_sub_d(&a, 1uL, &b); + mp_div_2(&b, &b); + err = mp_prime_is_prime(&b, mp_prime_rabin_miller_trials(mp_count_bits(&b)), &cnt); + /* small problem */ + if (err != MP_OKAY) { + printf("\nfailed with error: %s\n", mp_error_to_string(err)); + } + /* large problem */ + if (cnt == MP_NO) { + printf("\nsub is not prime!\n"); + } + mp_prime_frobenius_underwood(&b, &fu); + if (fu == MP_NO) { + printf("\nfrobenius-underwood says sub is not prime!\n"); + } + if ((err != MP_OKAY) || (cnt == MP_NO)) { + printf("prime tested was: 0x"); + mp_fwrite(&a,16,stdout); + putchar('\n'); + printf("sub tested was: 0x"); + mp_fwrite(&b,16,stdout); + putchar('\n'); + goto LBL_ERR; + } + + } + /* Check regarding problem #143 */ +#ifndef MP_8BIT + mp_read_radix(&a, + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", + 16); + err = mp_prime_strong_lucas_selfridge(&a, &cnt); + /* small problem */ + if (err != MP_OKAY) { + printf("\nmp_prime_strong_lucas_selfridge failed with error: %s\n", mp_error_to_string(err)); + } + /* large problem */ + if (cnt == MP_NO) { + printf("\n\nissue #143 - mp_prime_strong_lucas_selfridge FAILED!\n"); + } + if ((err != MP_OKAY) || (cnt == MP_NO)) { + printf("prime tested was: 0x"); + mp_fwrite(&a,16,stdout); + putchar('\n'); + goto LBL_ERR; + } +#endif + + printf("\n\n"); + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; + +} + + +static int test_mp_prime_next_prime(void) +{ + mp_err err; + mp_int a, b, c; + + mp_init_multi(&a, &b, &c, NULL); + + + /* edge cases */ + mp_set(&a, 0u); + if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp_d(&a, 2u) != MP_EQ) { + printf("mp_prime_next_prime: output should have been 2 but was: "); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + + mp_set(&a, 0u); + if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp_d(&a, 3u) != MP_EQ) { + printf("mp_prime_next_prime: output should have been 3 but was: "); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + + mp_set(&a, 2u); + if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp_d(&a, 3u) != MP_EQ) { + printf("mp_prime_next_prime: output should have been 3 but was: "); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + + mp_set(&a, 2u); + if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp_d(&a, 3u) != MP_EQ) { + printf("mp_prime_next_prime: output should have been 3 but was: "); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + mp_set(&a, 8); + if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp_d(&a, 11u) != MP_EQ) { + printf("mp_prime_next_prime: output should have been 11 but was: "); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + /* 2^300 + 157 is a 300 bit large prime to guarantee a multi-limb bigint */ + if ((err = mp_2expt(&a, 300)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set_u32(&b, 157); + if ((err = mp_add(&a, &b, &a)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_copy(&a, &b)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2^300 + 385 is the next prime */ + mp_set_u32(&c, 228); + if ((err = mp_add(&b, &c, &b)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp(&a, &b) != MP_EQ) { + printf("mp_prime_next_prime: output should have been\n"); + mp_fwrite(&b,10,stdout); + putchar('\n'); + printf("but was:\n"); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + + /* Use another temporary variable or recompute? Mmh... */ + if ((err = mp_2expt(&a, 300)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set_u32(&b, 157); + if ((err = mp_add(&a, &b, &a)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_copy(&a, &b)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2^300 + 631 is the next prime congruent to 3 mod 4*/ + mp_set_u32(&c, 474); + if ((err = mp_add(&b, &c, &b)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_cmp(&a, &b) != MP_EQ) { + printf("mp_prime_next_prime (bbs): output should have been\n"); + mp_fwrite(&b,10,stdout); + putchar('\n'); + printf("but was:\n"); + mp_fwrite(&a,10,stdout); + putchar('\n'); + goto LBL_ERR; + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_montgomery_reduce(void) +{ + mp_digit mp; + int ix, i, n; + char buf[4096]; + + /* size_t written; */ + + mp_int a, b, c, d, e; + if (mp_init_multi(&a, &b, &c, &d, &e, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test montgomery */ + for (i = 1; i <= 10; i++) { + if (i == 10) + i = 1000; + printf(" digit size: %2d\r", i); + fflush(stdout); + for (n = 0; n < 1000; n++) { + mp_rand(&a, i); + a.dp[0] |= 1; + + /* let's see if R is right */ + mp_montgomery_calc_normalization(&b, &a); + mp_montgomery_setup(&a, &mp); + + /* now test a random reduction */ + for (ix = 0; ix < 100; ix++) { + mp_rand(&c, 1 + abs(rand_int()) % (2*i)); + mp_copy(&c, &d); + mp_copy(&c, &e); + + mp_mod(&d, &a, &d); + mp_montgomery_reduce(&c, &a, mp); + mp_mulmod(&c, &b, &a, &c); + + if (mp_cmp(&c, &d) != MP_EQ) { +/* *INDENT-OFF* */ + printf("d = e mod a, c = e MOD a\n"); + mp_to_decimal(&a, buf, sizeof(buf)); printf("a = %s\n", buf); + mp_to_decimal(&e, buf, sizeof(buf)); printf("e = %s\n", buf); + mp_to_decimal(&d, buf, sizeof(buf)); printf("d = %s\n", buf); + mp_to_decimal(&c, buf, sizeof(buf)); printf("c = %s\n", buf); + + printf("compare no compare!\n"); goto LBL_ERR; +/* *INDENT-ON* */ + } + /* only one big montgomery reduction */ + if (i > 10) { + n = 1000; + ix = 100; + } + } + } + } + + printf("\n\n"); + + mp_clear_multi(&a, &b, &c, &d, &e, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, &e, NULL); + return EXIT_FAILURE; + +} + +static int test_mp_read_radix(void) +{ + char buf[4096]; + size_t written; + mp_err err; + + mp_int a; + if (mp_init_multi(&a, NULL)!= MP_OKAY) goto LTM_ERR; + + if ((err = mp_read_radix(&a, "123456", 10)) != MP_OKAY) goto LTM_ERR; + + if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR; + printf(" '123456' a == %s, length = %zu\n", buf, written); + + /* See comment in bn_mp_to_radix.c */ + /* + if( (err = mp_to_radix(&a, buf, 3u, &written, 10) ) != MP_OKAY) goto LTM_ERR; + printf(" '56' a == %s, length = %zu\n", buf, written); + + if( (err = mp_to_radix(&a, buf, 4u, &written, 10) ) != MP_OKAY) goto LTM_ERR; + printf(" '456' a == %s, length = %zu\n", buf, written); + if( (err = mp_to_radix(&a, buf, 30u, &written, 10) ) != MP_OKAY) goto LTM_ERR; + printf(" '123456' a == %s, length = %zu, error = %s\n", + buf, written, mp_error_to_string(err)); + */ + if ((err = mp_read_radix(&a, "-123456", 10)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR; + printf(" '-123456' a == %s, length = %zu\n", buf, written); + + if ((err = mp_read_radix(&a, "0", 10)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR; + printf(" '0' a == %s, length = %zu\n", buf, written); + + + + /* Although deprecated it needs to function as long as it isn't dropped */ + /* + printf("Testing deprecated mp_toradix_n\n"); + if( (err = mp_read_radix(&a, "-123456", 10) ) != MP_OKAY) goto LTM_ERR; + if( (err = mp_toradix_n(&a, buf, 10, 3) ) != MP_OKAY) goto LTM_ERR; + printf("a == %s\n", buf); + if( (err = mp_toradix_n(&a, buf, 10, 4) ) != MP_OKAY) goto LTM_ERR; + printf("a == %s\n", buf); + if( (err = mp_toradix_n(&a, buf, 10, 30) ) != MP_OKAY) goto LTM_ERR; + printf("a == %s\n", buf); + */ + + + while (0) { + char *s = fgets(buf, sizeof(buf), stdin); + if (s != buf) break; + mp_read_radix(&a, buf, 10); + mp_prime_next_prime(&a, 5, 1); + mp_to_radix(&a, buf, sizeof(buf), NULL, 10); + printf("%s, %lu\n", buf, (unsigned long)a.dp[0] & 3uL); + } + + mp_clear(&a); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear(&a); + return EXIT_FAILURE; +} + +static int test_mp_cnt_lsb(void) +{ + int ix; + + mp_int a, b; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + mp_set(&a, 1uL); + for (ix = 0; ix < 1024; ix++) { + if (mp_cnt_lsb(&a) != ix) { + printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a)); + goto LBL_ERR; + } + mp_mul_2(&a, &a); + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; + +} + +static int test_mp_reduce_2k(void) +{ + int ix, cnt; + + mp_int a, b, c, d; + if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test mp_reduce_2k */ + for (cnt = 3; cnt <= 128; ++cnt) { + mp_digit tmp; + + mp_2expt(&a, cnt); + mp_sub_d(&a, 2uL, &a); /* a = 2**cnt - 2 */ + + printf("\r %4d bits", cnt); + printf("(%d)", mp_reduce_is_2k(&a)); + mp_reduce_2k_setup(&a, &tmp); + printf("(%lu)", (unsigned long) tmp); + for (ix = 0; ix < 1000; ix++) { + if (!(ix & 127)) { + printf("."); + fflush(stdout); + } + mp_rand(&b, (cnt / MP_DIGIT_BIT + 1) * 2); + mp_copy(&c, &b); + mp_mod(&c, &a, &c); + mp_reduce_2k(&b, &a, 2uL); + if (mp_cmp(&c, &b) != MP_EQ) { + printf("FAILED\n"); + goto LBL_ERR; + } + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int test_mp_div_3(void) +{ + int cnt; + + mp_int a, b, c, d, e; + if (mp_init_multi(&a, &b, &c, &d, &e, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test mp_div_3 */ + mp_set(&d, 3uL); + for (cnt = 0; cnt < 10000;) { + mp_digit r2; + + if (!(++cnt & 127)) { + printf("%9d\r", cnt); + fflush(stdout); + } + mp_rand(&a, abs(rand_int()) % 128 + 1); + mp_div(&a, &d, &b, &e); + mp_div_3(&a, &c, &r2); + + if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) { + printf("\nmp_div_3 => Failure\n"); + goto LBL_ERR; + } + } + printf("\nPassed div_3 testing"); + + mp_clear_multi(&a, &b, &c, &d, &e, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, &d, &e, NULL); + return EXIT_FAILURE; +} + +static int test_mp_dr_reduce(void) +{ + mp_digit mp; + int cnt; + unsigned rr; + int ix; + + mp_int a, b, c; + if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + + /* test the DR reduction */ + for (cnt = 2; cnt < 32; cnt++) { + printf("\r%d digit modulus", cnt); + mp_grow(&a, cnt); + mp_zero(&a); + for (ix = 1; ix < cnt; ix++) { + a.dp[ix] = MP_MASK; + } + a.used = cnt; + a.dp[0] = 3; + + mp_rand(&b, cnt - 1); + mp_copy(&b, &c); + + rr = 0; + do { + if (!(rr & 127)) { + printf("."); + fflush(stdout); + } + mp_sqr(&b, &b); + mp_add_d(&b, 1uL, &b); + mp_copy(&b, &c); + + mp_mod(&b, &a, &b); + mp_dr_setup(&a, &mp); + mp_dr_reduce(&c, &a, mp); + + if (mp_cmp(&b, &c) != MP_EQ) { + printf("Failed on trial %u\n", rr); + goto LBL_ERR; + } + } while (++rr < 500); + printf(" passed"); + fflush(stdout); + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_reduce_2k_l(void) +{ +# if LTM_DEMO_TEST_REDUCE_2K_L + mp_int a, b, c, d; + int cnt; + char buf[4096]; + size_t length[1]; + if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { + return EXIT_FAILURE; + } + /* test the mp_reduce_2k_l code */ +# if LTM_DEMO_TEST_REDUCE_2K_L == 1 + /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */ + mp_2expt(&a, 1024); + mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16); + mp_sub(&a, &b, &a); +# elif LTM_DEMO_TEST_REDUCE_2K_L == 2 + /* p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F */ + mp_2expt(&a, 2048); + mp_read_radix(&b, + "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F", + 16); + mp_sub(&a, &b, &a); +# else +# error oops +# endif + *length = sizeof(buf); + mp_to_radix(&a, buf, length, 10); + printf("\n\np==%s, length = %zu\n", buf, *length); + /* now mp_reduce_is_2k_l() should return */ + if (mp_reduce_is_2k_l(&a) != 1) { + printf("mp_reduce_is_2k_l() return 0, should be 1\n"); + goto LBL_ERR; + } + mp_reduce_2k_setup_l(&a, &d); + /* now do a million square+1 to see if it varies */ + mp_rand(&b, 64); + mp_mod(&b, &a, &b); + mp_copy(&b, &c); + printf("Testing: mp_reduce_2k_l..."); + fflush(stdout); + for (cnt = 0; cnt < (int)(1uL << 20); cnt++) { + mp_sqr(&b, &b); + mp_add_d(&b, 1uL, &b); + mp_reduce_2k_l(&b, &a, &d); + mp_sqr(&c, &c); + mp_add_d(&c, 1uL, &c); + mp_mod(&c, &a, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("mp_reduce_2k_l() failed at step %d\n", cnt); + mp_to_hex(&b, buf, sizeof(buf)); + printf("b == %s\n", buf); + mp_to_hex(&c, buf, sizeof(buf)); + printf("c == %s\n", buf); + goto LBL_ERR; + } + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +#else + return EXIT_SUCCESS; +# endif /* LTM_DEMO_TEST_REDUCE_2K_L */ +} +/* stripped down version of mp_radix_size. The faster version can be off by up t +o +3 */ +/* TODO: This function should be removed, replaced by mp_radix_size, mp_radix_size_overestimate in 2.0 */ +static mp_err s_rs(const mp_int *a, int radix, uint32_t *size) +{ + mp_err res; + uint32_t digs = 0u; + mp_int t; + mp_digit d; + *size = 0u; + if (mp_iszero(a) == MP_YES) { + *size = 2u; + return MP_OKAY; + } + if (radix == 2) { + *size = (uint32_t)mp_count_bits(a) + 1u; + return MP_OKAY; + } + if ((res = mp_init_copy(&t, a)) != MP_OKAY) { + return res; + } + t.sign = MP_ZPOS; + while (mp_iszero(&t) == MP_NO) { + if ((res = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { + mp_clear(&t); + return res; + } + ++digs; + } + mp_clear(&t); + *size = digs + 1; + return MP_OKAY; +} +static int test_mp_log_u32(void) +{ + mp_int a; + mp_digit d; + uint32_t base, lb, size; + const uint32_t max_base = MP_MIN(UINT32_MAX, MP_DIGIT_MAX); + + if (mp_init(&a) != MP_OKAY) { + goto LBL_ERR; + } + + /* + base a result + 0 x MP_VAL + 1 x MP_VAL + */ + mp_set(&a, 42uL); + base = 0u; + if (mp_log_u32(&a, base, &lb) != MP_VAL) { + goto LBL_ERR; + } + base = 1u; + if (mp_log_u32(&a, base, &lb) != MP_VAL) { + goto LBL_ERR; + } + /* + base a result + 2 0 MP_VAL + 2 1 0 + 2 2 1 + 2 3 1 + */ + base = 2u; + mp_zero(&a); + if (mp_log_u32(&a, base, &lb) != MP_VAL) { + goto LBL_ERR; + } + + for (d = 1; d < 4; d++) { + mp_set(&a, d); + if (mp_log_u32(&a, base, &lb) != MP_OKAY) { + goto LBL_ERR; + } + if (lb != ((d == 1)?0uL:1uL)) { + goto LBL_ERR; + } + } + /* + base a result + 3 0 MP_VAL + 3 1 0 + 3 2 0 + 3 3 1 + */ + base = 3u; + mp_zero(&a); + if (mp_log_u32(&a, base, &lb) != MP_VAL) { + goto LBL_ERR; + } + for (d = 1; d < 4; d++) { + mp_set(&a, d); + if (mp_log_u32(&a, base, &lb) != MP_OKAY) { + goto LBL_ERR; + } + if (lb != ((d < base)?0uL:1uL)) { + goto LBL_ERR; + } + } + + /* + bases 2..64 with "a" a random large constant. + The range of bases tested allows to check with + radix_size. + */ + if (mp_rand(&a, 10) != MP_OKAY) { + goto LBL_ERR; + } + for (base = 2u; base < 65u; base++) { + if (mp_log_u32(&a, base, &lb) != MP_OKAY) { + goto LBL_ERR; + } + if (s_rs(&a,(int)base, &size) != MP_OKAY) { + goto LBL_ERR; + } + /* radix_size includes the memory needed for '\0', too*/ + size -= 2; + if (lb != size) { + goto LBL_ERR; + } + } + + /* + bases 2..64 with "a" a random small constant to + test the part of mp_ilogb that uses native types. + */ + if (mp_rand(&a, 1) != MP_OKAY) { + goto LBL_ERR; + } + for (base = 2u; base < 65u; base++) { + if (mp_log_u32(&a, base, &lb) != MP_OKAY) { + goto LBL_ERR; + } + if (s_rs(&a,(int)base, &size) != MP_OKAY) { + goto LBL_ERR; + } + size -= 2; + if (lb != size) { + goto LBL_ERR; + } + } + + /*Test upper edgecase with base UINT32_MAX and number (UINT32_MAX/2)*UINT32_MAX^10 */ + mp_set(&a, max_base); + if (mp_expt_u32(&a, 10uL, &a) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_add_d(&a, max_base / 2, &a) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_log_u32(&a, max_base, &lb) != MP_OKAY) { + goto LBL_ERR; + } + if (lb != 10u) { + goto LBL_ERR; + } + + mp_clear(&a); + return EXIT_SUCCESS; +LBL_ERR: + mp_clear(&a); + return EXIT_FAILURE; +} + +static int test_mp_incr(void) +{ + mp_int a, b; + mp_err e = MP_OKAY; + + if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + + /* Does it increment inside the limits of a MP_xBIT limb? */ + mp_set(&a, MP_MASK/2); + if ((e = mp_incr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp_d(&a, (MP_MASK/2uL) + 1uL) != MP_EQ) { + goto LTM_ERR; + } + + /* Does it increment outside of the limits of a MP_xBIT limb? */ + mp_set(&a, MP_MASK); + mp_set(&b, MP_MASK); + if ((e = mp_incr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if ((e = mp_add_d(&b, 1uL, &b)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&a, &b) != MP_EQ) { + goto LTM_ERR; + } + + /* Does it increment from -1 to 0? */ + mp_set(&a, 1uL); + a.sign = MP_NEG; + if ((e = mp_incr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp_d(&a, 0uL) != MP_EQ) { + goto LTM_ERR; + } + + /* Does it increment from -(MP_MASK + 1) to -MP_MASK? */ + mp_set(&a, MP_MASK); + if ((e = mp_add_d(&a, 1uL, &a)) != MP_OKAY) { + goto LTM_ERR; + } + a.sign = MP_NEG; + if ((e = mp_incr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (a.sign != MP_NEG) { + goto LTM_ERR; + } + a.sign = MP_ZPOS; + if (mp_cmp_d(&a, MP_MASK) != MP_EQ) { + goto LTM_ERR; + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int test_mp_decr(void) +{ + mp_int a, b; + mp_err e = MP_OKAY; + + if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + + /* Does it decrement inside the limits of a MP_xBIT limb? */ + mp_set(&a, MP_MASK/2); + if ((e = mp_decr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp_d(&a, (MP_MASK/2uL) - 1uL) != MP_EQ) { + goto LTM_ERR; + } + + /* Does it decrement outside of the limits of a MP_xBIT limb? */ + mp_set(&a, MP_MASK); + if ((e = mp_add_d(&a, 1uL, &a)) != MP_OKAY) { + goto LTM_ERR; + } + if ((e = mp_decr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp_d(&a, MP_MASK) != MP_EQ) { + goto LTM_ERR; + } + + /* Does it decrement from 0 to -1? */ + mp_zero(&a); + if ((e = mp_decr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (a.sign == MP_NEG) { + a.sign = MP_ZPOS; + if (mp_cmp_d(&a, 1uL) != MP_EQ) { + goto LTM_ERR; + } + } else { + goto LTM_ERR; + } + + + /* Does it decrement from -MP_MASK to -(MP_MASK + 1)? */ + mp_set(&a, MP_MASK); + a.sign = MP_NEG; + mp_set(&b, MP_MASK); + b.sign = MP_NEG; + if ((e = mp_sub_d(&b, 1uL, &b)) != MP_OKAY) { + goto LTM_ERR; + } + if ((e = mp_decr(&a)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&a, &b) != MP_EQ) { + goto LTM_ERR; + } + + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +/* + Cannot test mp_exp(_d) without mp_root and vice versa. + So one of the two has to be tested from scratch. + + Numbers generated by + for i in {1..10} + do + seed=$(head -c 10000 /dev/urandom | tr -dc '[:digit:]' | head -c 120); + echo $seed; + convertbase $seed 10 64; + done + + (The program "convertbase" uses libtommath's to/from_radix functions) + + Roots were precalculated with Pari/GP + + default(realprecision,1000); + for(n=3,100,r = floor(a^(1/n));printf("\"" r "\", ")) + + All numbers as strings to simplifiy things, especially for the + low-mp branch. +*/ + +static int test_mp_root_u32(void) +{ + mp_int a, c, r; + mp_err e; + int i, j; + + const char *input[] = { + "4n9cbk886QtLQmofprid3l2Q0GD8Yv979Lh8BdZkFE8g2pDUUSMBET/+M/YFyVZ3mBp", + "5NlgzHhmIX05O5YoW5yW5reAlVNtRAlIcN2dfoATnNdc1Cw5lHZUTwNthmK6/ZLKfY6", + "3gweiHDX+ji5utraSe46IJX+uuh7iggs63xIpMP5MriU4Np+LpHI5are8RzS9pKh9xP", + "5QOJUSKMrfe7LkeyJOlupS8h7bjT+TXmZkDzOjZtfj7mdA7cbg0lRX3CuafhjIrpK8S", + "4HtYFldVkyVbrlg/s7kmaA7j45PvLQm+1bbn6ehgP8tVoBmGbv2yDQI1iQQze4AlHyN", + "3bwCUx79NAR7c68OPSp5ZabhZ9aBEr7rWNTO2oMY7zhbbbw7p6shSMxqE9K9nrTNucf", + "4j5RGb78TfuYSzrXn0z6tiAoWiRI81hGY3el9AEa9S+gN4x/AmzotHT2Hvj6lyBpE7q", + "4lwg30SXqZhEHNsl5LIXdyu7UNt0VTWebP3m7+WUL+hsnFW9xJe7UnzYngZsvWh14IE", + "1+tcqFeRuGqjRADRoRUJ8gL4UUSFQVrVVoV6JpwVcKsuBq5G0pABn0dLcQQQMViiVRj", + "hXwxuFySNSFcmbrs/coz4FUAaUYaOEt+l4V5V8vY71KyBvQPxRq/6lsSrG2FHvWDax" + }; + /* roots 3-100 of the above */ + const char *root[10][100] = { + { + "9163694094944489658600517465135586130944", + "936597377180979771960755204040", "948947857956884030956907", + "95727185767390496595", "133844854039712620", "967779611885360", + "20926191452627", "974139547476", "79203891950", "9784027073", + "1667309744", "365848129", "98268452", "31109156", "11275351", + "4574515", "2040800", "986985", "511525", "281431", "163096", + "98914", "62437", "40832", "27556", "19127", "13614", "9913", + "7367", "5577", "4294", "3357", "2662", "2138", "1738", "1428", + "1185", "993", "839", "715", "613", "530", "461", "403", "355", + "314", "279", "249", "224", "202", "182", "166", "151", "138", + "126", "116", "107", "99", "92", "85", "79", "74", "69", "65", "61", + "57", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34", + "32", "31", "30", "28", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "9534798256755061606359588498764080011382", + "964902943621813525741417593772", "971822399862464674540423", + "97646291566833512831", "136141536090599560", "982294733581430", + "21204945933335", "985810529393", "80066084985", "9881613813", + "1682654547", "368973625", "99051783", "31341581", "11354620", + "4604882", "2053633", "992879", "514434", "282959", "163942", + "99406", "62736", "41020", "27678", "19208", "13670", "9952", + "7395", "5598", "4310", "3369", "2671", "2145", "1744", "1433", + "1189", "996", "842", "717", "615", "531", "462", "404", "356", + "315", "280", "250", "224", "202", "183", "166", "151", "138", + "127", "116", "107", "99", "92", "85", "80", "74", "70", "65", "61", + "58", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34", + "32", "31", "30", "29", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "8398539113202579297642815367509019445624", + "877309458945432597462853440936", "900579899458998599215071", + "91643543761699761637", "128935656335800903", "936647990947203", + "20326748623514", "948988882684", "77342677787", "9573063447", + "1634096832", "359076114", "96569670", "30604705", "11103188", + "4508519", "2012897", "974160", "505193", "278105", "161251", + "97842", "61788", "40423", "27291", "18949", "13492", "9826", + "7305", "5532", "4260", "3332", "2642", "2123", "1726", "1418", + "1177", "986", "834", "710", "610", "527", "458", "401", "353", + "312", "278", "248", "223", "201", "181", "165", "150", "137", + "126", "116", "107", "99", "91", "85", "79", "74", "69", "65", "61", + "57", "54", "51", "48", "46", "43", "41", "39", "37", "35", "34", + "32", "31", "30", "28", "27", "26", "25", "24", "23", "22", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "9559098494021810340217797724866627755195", + "966746709063325235560830083787", "973307706084821682248292", + "97770642291138756434", "136290128605981259", "983232784778520", + "21222944848922", "986563584410", "80121684894", "9887903837", + "1683643206", "369174929", "99102220", "31356542", "11359721", + "4606836", "2054458", "993259", "514621", "283057", "163997", + "99437", "62755", "41032", "27686", "19213", "13674", "9955", + "7397", "5599", "4311", "3370", "2672", "2146", "1744", "1433", + "1189", "996", "842", "717", "615", "532", "462", "404", "356", + "315", "280", "250", "224", "202", "183", "166", "151", "138", + "127", "116", "107", "99", "92", "86", "80", "74", "70", "65", "61", + "58", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34", + "32", "31", "30", "29", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "8839202025813295923132694443541993309220", + "911611499784863252820288596270", "928640961450376817534853", + "94017030509441723821", "131792686685970629", "954783483196511", + "20676214073400", "963660189823", "78428929840", "9696237956", + "1653495486", "363032624", "97562430", "30899570", "11203842", + "4547110", "2029216", "981661", "508897", "280051", "162331", + "98469", "62168", "40663", "27446", "19053", "13563", "9877", + "7341", "5558", "4280", "3347", "2654", "2132", "1733", "1424", + "1182", "990", "837", "713", "612", "529", "460", "402", "354", + "313", "279", "249", "223", "201", "182", "165", "150", "138", + "126", "116", "107", "99", "92", "85", "79", "74", "69", "65", "61", + "57", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34", + "32", "31", "30", "28", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "8338442683973420410660145045849076963795", + "872596990706967613912664152945", "896707843885562730147307", + "91315073695274540969", "128539440806486007", "934129001105825", + "20278149285734", "946946589774", "77191347471", "9555892093", + "1631391010", "358523975", "96431070", "30563524", "11089126", + "4503126", "2010616", "973111", "504675", "277833", "161100", + "97754", "61734", "40390", "27269", "18934", "13482", "9819", + "7300", "5528", "4257", "3330", "2641", "2122", "1725", "1417", + "1177", "986", "833", "710", "609", "527", "458", "401", "353", + "312", "278", "248", "222", "200", "181", "165", "150", "137", + "126", "116", "107", "99", "91", "85", "79", "74", "69", "65", "61", + "57", "54", "51", "48", "46", "43", "41", "39", "37", "35", "34", + "32", "31", "30", "28", "27", "26", "25", "24", "23", "22", "22", + "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15" + }, { + "9122818552483814953977703257848970704164", + "933462289569511464780529972314", "946405863353935713909178", + "95513446972056321834", "133588658082928446", + "966158521967027", "20895030642048", "972833934108", + "79107381638", "9773098125", "1665590516", "365497822", + "98180628", "31083090", "11266459", "4571108", "2039360", + "986323", "511198", "281260", "163001", "98858", + "62404", "40811", "27543", "19117", "13608", "9908", + "7363", "5575", "4292", "3356", "2661", "2138", + "1737", "1428", "1185", "993", "839", "714", "613", + "530", "461", "403", "355", "314", "279", "249", + "224", "202", "182", "165", "151", "138", "126", + "116", "107", "99", "92", "85", "79", "74", "69", + "65", "61", "57", "54", "51", "48", "46", "43", + "41", "39", "37", "36", "34", "32", "31", "30", + "28", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", + "16", "16", "15" + }, { + "9151329724083804100369546479681933027521", + "935649419557299174433860420387", "948179413831316112751907", + "95662582675170358900", "133767426788182384", + "967289728859610", "20916775466497", "973745045600", + "79174731802", "9780725058", "1666790321", "365742295", + "98241919", "31101281", "11272665", "4573486", "2040365", + "986785", "511426", "281380", "163067", "98897", + "62427", "40826", "27552", "19124", "13612", "9911", + "7366", "5576", "4294", "3357", "2662", "2138", + "1738", "1428", "1185", "993", "839", "715", "613", + "530", "461", "403", "355", "314", "279", "249", + "224", "202", "182", "165", "151", "138", "126", + "116", "107", "99", "92", "85", "79", "74", "69", + "65", "61", "57", "54", "51", "48", "46", "43", + "41", "39", "37", "36", "34", "32", "31", "30", + "28", "27", "26", "25", "24", "23", "23", "22", + "21", "20", "20", "19", "18", "18", "17", "17", + "16", "16", "15" + }, { + "6839396355168045468586008471269923213531", + "752078770083218822016981965090", "796178899357307807726034", + "82700643015444840424", "118072966296549115", + "867224751770392", "18981881485802", "892288574037", + "73130030771", "9093989389", "1558462688", "343617470", + "92683740", "29448679", "10708016", "4356820", "1948676", + "944610", "490587", "270425", "156989", "95362", + "60284", "39477", "26675", "18536", "13208", "9627", + "7161", "5426", "4181", "3272", "2596", "2087", + "1697", "1395", "1159", "971", "821", "700", "601", + "520", "452", "396", "348", "308", "274", "245", + "220", "198", "179", "163", "148", "136", "124", + "114", "106", "98", "91", "84", "78", "73", "68", + "64", "60", "57", "53", "50", "48", "45", "43", + "41", "39", "37", "35", "34", "32", "31", "29", + "28", "27", "26", "25", "24", "23", "22", "22", + "21", "20", "19", "19", "18", "18", "17", "17", + "16", "16", "15" + }, { + "4788090721380022347683138981782307670424", + "575601315594614059890185238256", "642831903229558719812840", + "69196031110028430211", "101340693763170691", + "758683936560287", "16854690815260", "801767985909", + "66353290503", "8318415180", "1435359033", "318340531", + "86304307", "27544217", "10054988", "4105446", "1841996", + "895414", "466223", "257591", "149855", "91205", + "57758", "37886", "25639", "17842", "12730", "9290", + "6918", "5248", "4048", "3170", "2518", "2026", + "1649", "1357", "1128", "946", "800", "682", "586", + "507", "441", "387", "341", "302", "268", "240", + "215", "194", "176", "160", "146", "133", "122", + "112", "104", "96", "89", "83", "77", "72", "67", + "63", "59", "56", "53", "50", "47", "45", "42", + "40", "38", "36", "35", "33", "32", "30", "29", + "28", "27", "26", "25", "24", "23", "22", "21", + "21", "20", "19", "19", "18", "17", "17", "16", + "16", "15", "15" + } + }; + + if ((e = mp_init_multi(&a, &c, &r, NULL)) != MP_OKAY) { + return EXIT_FAILURE; + } +#ifdef MP_8BIT + for (i = 0; i < 1; i++) { +#else + for (i = 0; i < 10; i++) { +#endif + mp_read_radix(&a, input[i], 64); +#ifdef MP_8BIT + for (j = 3; j < 10; j++) { +#else + for (j = 3; j < 100; j++) { +#endif + mp_root_u32(&a, (uint32_t)j, &c); + mp_read_radix(&r, root[i][j-3], 10); + if (mp_cmp(&r, &c) != MP_EQ) { + fprintf(stderr, "mp_root_u32 failed at input #%d, root #%d\n", i, j); + goto LTM_ERR; + } + } + } + mp_clear_multi(&a, &c, &r, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &c, &r, NULL); + return EXIT_FAILURE; +} + +static int test_s_mp_balance_mul(void) +{ + mp_int a, b, c; + mp_err e = MP_OKAY; + + const char *na = + "4b0I5uMTujCysw+1OOuOyH2FX2WymrHUqi8BBDb7XpkV/4i7vXTbEYUy/kdIfCKu5jT5JEqYkdmnn3jAYo8XShPzNLxZx9yoLjxYRyptSuOI2B1DspvbIVYXY12sxPZ4/HCJ4Usm2MU5lO/006KnDMxuxiv1rm6YZJZ0eZU"; + const char *nb = "3x9vs0yVi4hIq7poAeVcggC3WoRt0zRLKO"; + const char *nc = + "HzrSq9WVt1jDTVlwUxSKqxctu2GVD+N8+SVGaPFRqdxyld6IxDBbj27BPJzYUdR96k3sWpkO8XnDBvupGPnehpQe4KlO/KmN1PjFov/UTZYM+LYzkFcBPyV6hkkL8ePC1rlFLAHzgJMBCXVp4mRqtkQrDsZXXlcqlbTFu69wF6zDEysiX2cAtn/kP9ldblJiwYPCD8hG"; + + if ((e = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((e = mp_read_radix(&a, na, 64)) != MP_OKAY) { + goto LTM_ERR; + } + if ((e = mp_read_radix(&b, nb, 64)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((e = s_mp_balance_mul(&a, &b, &c)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((e = mp_read_radix(&b, nc, 64)) != MP_OKAY) { + goto LTM_ERR; + } + + if (mp_cmp(&b, &c) != MP_EQ) { + goto LTM_ERR; + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static int test_s_mp_karatsuba_mul(void) +{ + mp_int a, b, c, d; + int size, err; + + if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + for (size = MP_KARATSUBA_MUL_CUTOFF; size < MP_KARATSUBA_MUL_CUTOFF + 20; size++) { + if ((err = mp_rand(&a, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_rand(&b, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_karatsuba_mul(&a, &b, &c)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_mul(&a,&b,&d)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&c, &d) != MP_EQ) { + fprintf(stderr, "Karatsuba multiplication failed at size %d\n", size); + goto LTM_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int test_s_mp_karatsuba_sqr(void) +{ + mp_int a, b, c; + int size, err; + + if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + for (size = MP_KARATSUBA_SQR_CUTOFF; size < MP_KARATSUBA_SQR_CUTOFF + 20; size++) { + if ((err = mp_rand(&a, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_karatsuba_sqr(&a, &b)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_sqr(&a, &c)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&b, &c) != MP_EQ) { + fprintf(stderr, "Karatsuba squaring failed at size %d\n", size); + goto LTM_ERR; + } + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_s_mp_toom_mul(void) +{ + mp_int a, b, c, d; + int size, err; + +#if (MP_DIGIT_BIT == 60) + int tc_cutoff; +#endif + + if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + /* This number construction is limb-size specific */ +#if (MP_DIGIT_BIT == 60) + if ((err = mp_rand(&a, 1196)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_mul_2d(&a,71787 - mp_count_bits(&a), &a)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((err = mp_rand(&b, 1338)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_mul_2d(&b, 80318 - mp_count_bits(&b), &b)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_mul_2d(&b, 6310, &b)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_2expt(&c, 99000 - 1000)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_add(&b, &c, &b)) != MP_OKAY) { + goto LTM_ERR; + } + + tc_cutoff = TOOM_MUL_CUTOFF; + TOOM_MUL_CUTOFF = INT_MAX; + if ((err = mp_mul(&a, &b, &c)) != MP_OKAY) { + goto LTM_ERR; + } + TOOM_MUL_CUTOFF = tc_cutoff; + if ((err = mp_mul(&a, &b, &d)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&c, &d) != MP_EQ) { + fprintf(stderr, "Toom-Cook 3-way multiplication failed for edgecase f1 * f2\n"); + goto LTM_ERR; + } +#endif + + for (size = MP_TOOM_MUL_CUTOFF; size < MP_TOOM_MUL_CUTOFF + 20; size++) { + if ((err = mp_rand(&a, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = mp_rand(&b, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_toom_mul(&a, &b, &c)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_mul(&a,&b,&d)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&c, &d) != MP_EQ) { + fprintf(stderr, "Toom-Cook 3-way multiplication failed at size %d\n", size); + goto LTM_ERR; + } + } + + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return EXIT_FAILURE; +} + +static int test_s_mp_toom_sqr(void) +{ + mp_int a, b, c; + int size, err; + + if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + for (size = MP_TOOM_SQR_CUTOFF; size < MP_TOOM_SQR_CUTOFF + 20; size++) { + if ((err = mp_rand(&a, size)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_toom_sqr(&a, &b)) != MP_OKAY) { + goto LTM_ERR; + } + if ((err = s_mp_sqr(&a, &c)) != MP_OKAY) { + goto LTM_ERR; + } + if (mp_cmp(&b, &c) != MP_EQ) { + fprintf(stderr, "Toom-Cook 3-way squaring failed at size %d\n", size); + goto LTM_ERR; + } + } + + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LTM_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_read_write_ubin(void) +{ + mp_int a, b, c; + int err; + size_t size, len; + unsigned char *buf = NULL; + + if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_neg(&a, &b)) != MP_OKAY) goto LTM_ERR; + + size = mp_ubin_size(&a); + printf("mp_to_ubin_size %zu\n", size); + buf = malloc(sizeof(*buf) * size); + if (buf == NULL) { + fprintf(stderr, "test_read_write_binaries (u) failed to allocate %zu bytes\n", + sizeof(*buf) * size); + goto LTM_ERR; + } + + if ((err = mp_to_ubin(&a, buf, size, &len)) != MP_OKAY) goto LTM_ERR; + printf("mp_to_ubin len = %zu\n", len); + + if ((err = mp_from_ubin(&c, buf, len)) != MP_OKAY) goto LTM_ERR; + + if (mp_cmp(&a, &c) != MP_EQ) { + fprintf(stderr, "to/from ubin cycle failed\n"); + goto LTM_ERR; + } + free(buf); + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LTM_ERR: + free(buf); + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_read_write_sbin(void) +{ + mp_int a, b, c; + int err; + size_t size, len; + unsigned char *buf = NULL; + + if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + goto LTM_ERR; + } + + if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_neg(&a, &b)) != MP_OKAY) goto LTM_ERR; + + size = mp_sbin_size(&a); + printf("mp_to_sbin_size %zu\n", size); + buf = malloc(sizeof(*buf) * size); + if (buf == NULL) { + fprintf(stderr, "test_read_write_binaries (s) failed to allocate %zu bytes\n", + sizeof(*buf) * size); + goto LTM_ERR; + } + + if ((err = mp_to_sbin(&b, buf, size, &len)) != MP_OKAY) goto LTM_ERR; + printf("mp_to_sbin len = %zu\n", len); + + if ((err = mp_from_sbin(&c, buf, len)) != MP_OKAY) goto LTM_ERR; + + if (mp_cmp(&b, &c) != MP_EQ) { + fprintf(stderr, "to/from ubin cycle failed\n"); + goto LTM_ERR; + } + + free(buf); + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_SUCCESS; +LTM_ERR: + free(buf); + mp_clear_multi(&a, &b, &c, NULL); + return EXIT_FAILURE; +} + +static int test_mp_pack_unpack(void) +{ + mp_int a, b; + int err; + size_t written, count; + unsigned char *buf = NULL; + + mp_order order = MP_LSB_FIRST; + mp_endian endianess = MP_NATIVE_ENDIAN; + + if ((err = mp_init_multi(&a, &b, NULL)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR; + + count = mp_pack_count(&a, 0, 1); + + buf = malloc(count); + if (buf == NULL) { + fprintf(stderr, "test_pack_unpack failed to allocate\n"); + goto LTM_ERR; + } + + if ((err = mp_pack((void *)buf, count, &written, order, 1, + endianess, 0, &a)) != MP_OKAY) goto LTM_ERR; + if ((err = mp_unpack(&b, count, order, 1, + endianess, 0, (const void *)buf)) != MP_OKAY) goto LTM_ERR; + + if (mp_cmp(&a, &b) != MP_EQ) { + fprintf(stderr, "pack/unpack cycle failed\n"); + goto LTM_ERR; + } + + free(buf); + mp_clear_multi(&a, &b, NULL); + return EXIT_SUCCESS; +LTM_ERR: + free(buf); + mp_clear_multi(&a, &b, NULL); + return EXIT_FAILURE; +} + +static int unit_tests(int argc, char **argv) +{ + static const struct { + const char *name; + int (*fn)(void); + } test[] = { +#define T0(n) { #n, test_##n } +#define T1(n, o) { #n, MP_HAS(o) ? test_##n : NULL } +#define T2(n, o1, o2) { #n, MP_HAS(o1) && MP_HAS(o2) ? test_##n : NULL } + T0(feature_detection), + T0(trivial_stuff), + T2(mp_get_set_i32, MP_GET_I32, MP_GET_MAG_U32), + T2(mp_get_set_i64, MP_GET_I64, MP_GET_MAG_U64), + T1(mp_and, MP_AND), + T1(mp_cnt_lsb, MP_CNT_LSB), + T1(mp_complement, MP_COMPLEMENT), + T1(mp_decr, MP_DECR), + T1(mp_div_3, MP_DIV_3), + T1(mp_dr_reduce, MP_DR_REDUCE), + T2(mp_pack_unpack,MP_PACK, MP_UNPACK), + T2(mp_fread_fwrite, MP_FREAD, MP_FWRITE), + T1(mp_get_u32, MP_GET_I32), + T1(mp_get_u64, MP_GET_I64), + T1(mp_get_ul, MP_GET_L), + T1(mp_log_u32, MP_LOG_U32), + T1(mp_incr, MP_INCR), + T1(mp_invmod, MP_INVMOD), + T1(mp_is_square, MP_IS_SQUARE), + T1(mp_kronecker, MP_KRONECKER), + T1(mp_montgomery_reduce, MP_MONTGOMERY_REDUCE), + T1(mp_root_u32, MP_ROOT_U32), + T1(mp_or, MP_OR), + T1(mp_prime_is_prime, MP_PRIME_IS_PRIME), + T1(mp_prime_next_prime, MP_PRIME_NEXT_PRIME), + T1(mp_prime_rand, MP_PRIME_RAND), + T1(mp_rand, MP_RAND), + T1(mp_read_radix, MP_READ_RADIX), + T1(mp_read_write_ubin, MP_TO_UBIN), + T1(mp_read_write_sbin, MP_TO_SBIN), + T1(mp_reduce_2k, MP_REDUCE_2K), + T1(mp_reduce_2k_l, MP_REDUCE_2K_L), +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) + T1(mp_set_double, MP_SET_DOUBLE), +#endif + T1(mp_signed_rsh, MP_SIGNED_RSH), + T1(mp_sqrt, MP_SQRT), + T1(mp_sqrtmod_prime, MP_SQRTMOD_PRIME), + T1(mp_xor, MP_XOR), + T1(s_mp_balance_mul, S_MP_BALANCE_MUL), + T1(s_mp_karatsuba_mul, S_MP_KARATSUBA_MUL), + T1(s_mp_karatsuba_sqr, S_MP_KARATSUBA_SQR), + T1(s_mp_toom_mul, S_MP_TOOM_MUL), + T1(s_mp_toom_sqr, S_MP_TOOM_SQR) +#undef T2 +#undef T1 + }; + unsigned long i, ok, fail, nop; + uint64_t t; + int j; + + ok = fail = nop = 0; + + t = (uint64_t)time(NULL); + printf("SEED: 0x%"PRIx64"\n\n", t); + s_mp_rand_jenkins_init(t); + mp_rand_source(s_mp_rand_jenkins); + + for (i = 0; i < sizeof(test) / sizeof(test[0]); ++i) { + if (argc > 1) { + for (j = 1; j < argc; ++j) { + if (strstr(test[i].name, argv[j]) != NULL) { + break; + } + } + if (j == argc) continue; + } + printf("TEST %s\n\n", test[i].name); + if (test[i].fn == NULL) { + nop++; + printf("NOP %s\n\n", test[i].name); + } else if (test[i].fn() == EXIT_SUCCESS) { + ok++; + printf("\n\n"); + } else { + fail++; + printf("\n\nFAIL %s\n\n", test[i].name); + } + } + printf("Tests OK/NOP/FAIL: %lu/%lu/%lu\n", ok, nop, fail); + + if (fail != 0) return EXIT_FAILURE; + else return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + print_header(); + + return unit_tests(argc, argv); +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/demo/timing.c b/third_party/heimdal/lib/hcrypto/libtommath/demo/timing.c new file mode 100644 index 0000000..f620b8c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/demo/timing.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include + +#define MP_WUR +#include + +#ifdef IOWNANATHLON +#include +#define SLEEP sleep(4) +#else +#define SLEEP +#endif + +#ifdef LTM_TIMING_REAL_RAND +#define LTM_TIMING_RAND_SEED time(NULL) +#else +#define LTM_TIMING_RAND_SEED 23 +#endif + + +static void ndraw(mp_int *a, const char *name) +{ + char buf[4096]; + + printf("%s: ", name); + mp_to_radix(a, buf, sizeof(buf), NULL, 64); + printf("%s\n", buf); +} + +static void draw(mp_int *a) +{ + ndraw(a, ""); +} + + +static unsigned long lfsr = 0xAAAAAAAAuL; + +static unsigned int lbit(void) +{ + if ((lfsr & 0x80000000uL) != 0uL) { + lfsr = ((lfsr << 1) ^ 0x8000001BuL) & 0xFFFFFFFFuL; + return 1u; + } else { + lfsr <<= 1; + return 0u; + } +} + +/* RDTSC from Scott Duplichan */ +static uint64_t TIMFUNC(void) +{ +#if defined __GNUC__ +#if defined(__i386__) || defined(__x86_64__) + /* version from http://www.mcs.anl.gov/~kazutomo/rdtsc.html + * the old code always got a warning issued by gcc, clang did not complain... + */ + unsigned hi, lo; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)lo)|(((uint64_t)hi)<<32); +#else /* gcc-IA64 version */ + unsigned long result; + __asm__ __volatile__("mov %0=ar.itc":"=r"(result)::"memory"); + + while (__builtin_expect((int) result == -1, 0)) + __asm__ __volatile__("mov %0=ar.itc":"=r"(result)::"memory"); + + return result; +#endif + + /* Microsoft and Intel Windows compilers */ +#elif defined _M_IX86 + __asm rdtsc +#elif defined _M_AMD64 + return __rdtsc(); +#elif defined _M_IA64 +#if defined __INTEL_COMPILER +#include +#endif + return __getReg(3116); +#else +#error need rdtsc function for this build +#endif +} + +#if 1 +#define DO(x) x; x; +#else +#define DO2(x) x; x; +#define DO4(x) DO2(x); DO2(x); +#define DO8(x) DO4(x); DO4(x); +#define DO(x) DO8(x); DO8(x); +#endif + +#ifdef TIMING_NO_LOGS +#define FOPEN(a, b) NULL +#define FPRINTF(a,b,c,d) +#define FFLUSH(a) +#define FCLOSE(a) (void)(a) +#else +#define FOPEN(a,b) fopen(a,b) +#define FPRINTF(a,b,c,d) fprintf(a,b,c,d) +#define FFLUSH(a) fflush(a) +#define FCLOSE(a) fclose(a) +#endif + +static int should_test(const char *test, int argc, char **argv) +{ + int j; + if (argc > 1) { + for (j = 1; j < argc; ++j) { + if (strstr(test, argv[j]) != NULL) { + return 1; + } + } + if (j == argc) return 0; + } + return 1; +} + +int main(int argc, char **argv) +{ + uint64_t tt, gg, CLK_PER_SEC; + FILE *log, *logb, *logc, *logd; + mp_int a, b, c, d, e, f; +#ifdef LTM_TIMING_PRIME_IS_PRIME + const char *name; + int m; +#endif + int n, cnt, ix, old_kara_m, old_kara_s, old_toom_m, old_toom_s; + unsigned rr; + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + mp_init(&f); + + srand(LTM_TIMING_RAND_SEED); + + + CLK_PER_SEC = TIMFUNC(); + sleep(1); + CLK_PER_SEC = TIMFUNC() - CLK_PER_SEC; + + printf("CLK_PER_SEC == %" PRIu64 "\n", CLK_PER_SEC); + +#ifdef LTM_TIMING_PRIME_IS_PRIME + if (should_test("prime", argc, argv)) { + for (m = 0; m < 2; ++m) { + if (m == 0) { + name = " Arnault"; + mp_read_radix(&a, + "91xLNF3roobhzgTzoFIG6P13ZqhOVYSN60Fa7Cj2jVR1g0k89zdahO9/kAiRprpfO1VAp1aBHucLFV/qLKLFb+zonV7R2Vxp1K13ClwUXStpV0oxTNQVjwybmFb5NBEHImZ6V7P6+udRJuH8VbMEnS0H8/pSqQrg82OoQQ2fPpAk6G1hkjqoCv5s/Yr", + 64); + } else { + name = "2^1119 + 53"; + mp_set(&a,1u); + mp_mul_2d(&a,1119,&a); + mp_add_d(&a,53,&a); + } + cnt = mp_prime_rabin_miller_trials(mp_count_bits(&a)); + ix = -cnt; + for (; cnt >= ix; cnt += ix) { + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_prime_is_prime(&a, cnt, &n)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + if ((m == 0) && (n == MP_YES)) { + printf("Arnault's pseudoprime is not prime but mp_prime_is_prime says it is.\n"); + return EXIT_FAILURE; + } + } while (++rr < 100u); + printf("Prime-check\t%s(%2d) => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + name, cnt, CLK_PER_SEC / tt, tt); + } + } + } +#endif + + if (should_test("add", argc, argv)) { + log = FOPEN("logs/add.log", "w"); + for (cnt = 8; cnt <= 128; cnt += 8) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_add(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100000u); + printf("Adding\t\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF(log, "%6d %9" PRIu64 "\n", cnt * MP_DIGIT_BIT, tt); + FFLUSH(log); + } + FCLOSE(log); + } + + if (should_test("sub", argc, argv)) { + log = FOPEN("logs/sub.log", "w"); + for (cnt = 8; cnt <= 128; cnt += 8) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_sub(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100000u); + + printf("Subtracting\t\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF(log, "%6d %9" PRIu64 "\n", cnt * MP_DIGIT_BIT, tt); + FFLUSH(log); + } + FCLOSE(log); + } + + if (should_test("mulsqr", argc, argv)) { + /* do mult/square twice, first without karatsuba and second with */ + old_kara_m = KARATSUBA_MUL_CUTOFF; + old_kara_s = KARATSUBA_SQR_CUTOFF; + /* currently toom-cook cut-off is too high to kick in, so we just use the karatsuba values */ + old_toom_m = old_kara_m; + old_toom_s = old_kara_s; + for (ix = 0; ix < 3; ix++) { + printf("With%s Karatsuba, With%s Toom\n", (ix == 1) ? "" : "out", (ix == 2) ? "" : "out"); + + KARATSUBA_MUL_CUTOFF = (ix == 1) ? old_kara_m : 9999; + KARATSUBA_SQR_CUTOFF = (ix == 1) ? old_kara_s : 9999; + TOOM_MUL_CUTOFF = (ix == 2) ? old_toom_m : 9999; + TOOM_SQR_CUTOFF = (ix == 2) ? old_toom_s : 9999; + + log = FOPEN((ix == 0) ? "logs/mult.log" : (ix == 1) ? "logs/mult_kara.log" : "logs/mult_toom.log", "w"); + for (cnt = 4; cnt <= (10240 / MP_DIGIT_BIT); cnt += 2) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_mul(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100u); + printf("Multiplying\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF(log, "%6d %9" PRIu64 "\n", mp_count_bits(&a), tt); + FFLUSH(log); + } + FCLOSE(log); + + log = FOPEN((ix == 0) ? "logs/sqr.log" : (ix == 1) ? "logs/sqr_kara.log" : "logs/sqr_toom.log", "w"); + for (cnt = 4; cnt <= (10240 / MP_DIGIT_BIT); cnt += 2) { + SLEEP; + mp_rand(&a, cnt); + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_sqr(&a, &b)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100u); + printf("Squaring\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF(log, "%6d %9" PRIu64 "\n", mp_count_bits(&a), tt); + FFLUSH(log); + } + FCLOSE(log); + + } + } + + if (should_test("expt", argc, argv)) { + const char *primes[] = { + /* 2K large moduli */ + "179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586239334100047359817950870678242457666208137217", + "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638099733077152121140120031150424541696791951097529546801429027668869927491725169", + "1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085902995208257421855249796721729039744118165938433694823325696642096892124547425283", + /* 2K moduli mersenne primes */ + "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", + "531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127", + "10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087", + "1475979915214180235084898622737381736312066145333169775147771216478570297878078949377407337049389289382748507531496480477281264838760259191814463365330269540496961201113430156902396093989090226259326935025281409614983499388222831448598601834318536230923772641390209490231836446899608210795482963763094236630945410832793769905399982457186322944729636418890623372171723742105636440368218459649632948538696905872650486914434637457507280441823676813517852099348660847172579408422316678097670224011990280170474894487426924742108823536808485072502240519452587542875349976558572670229633962575212637477897785501552646522609988869914013540483809865681250419497686697771007", + "259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071", + "190797007524439073807468042969529173669356994749940177394741882673528979787005053706368049835514900244303495954950709725762186311224148828811920216904542206960744666169364221195289538436845390250168663932838805192055137154390912666527533007309292687539092257043362517857366624699975402375462954490293259233303137330643531556539739921926201438606439020075174723029056838272505051571967594608350063404495977660656269020823960825567012344189908927956646011998057988548630107637380993519826582389781888135705408653045219655801758081251164080554609057468028203308718724654081055323215860189611391296030471108443146745671967766308925858547271507311563765171008318248647110097614890313562856541784154881743146033909602737947385055355960331855614540900081456378659068370317267696980001187750995491090350108417050917991562167972281070161305972518044872048331306383715094854938415738549894606070722584737978176686422134354526989443028353644037187375385397838259511833166416134323695660367676897722287918773420968982326089026150031515424165462111337527431154890666327374921446276833564519776797633875503548665093914556482031482248883127023777039667707976559857333357013727342079099064400455741830654320379350833236245819348824064783585692924881021978332974949906122664421376034687815350484991", + + /* DR moduli */ + "14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368612079", + "101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039", + "736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821797602431", + "38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783", + "542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147", + "1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503", + "1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679", + + /* generic unrestricted moduli */ + "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", + "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", + "347743159439876626079252796797422223177535447388206607607181663903045907591201940478223621722118173270898487582987137708656414344685816179420855160986340457973820182883508387588163122354089264395604796675278966117567294812714812796820596564876450716066283126720010859041484786529056457896367683122960411136319", + "47266428956356393164697365098120418976400602706072312735924071745438532218237979333351774907308168340693326687317443721193266215155735814510792148768576498491199122744351399489453533553203833318691678263241941706256996197460424029012419012634671862283532342656309677173602509498417976091509154360039893165037637034737020327399910409885798185771003505320583967737293415979917317338985837385734747478364242020380416892056650841470869294527543597349250299539682430605173321029026555546832473048600327036845781970289288898317888427517364945316709081173840186150794397479045034008257793436817683392375274635794835245695887", + "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", + "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", + "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", + NULL + }; + log = FOPEN("logs/expt.log", "w"); + logb = FOPEN("logs/expt_dr.log", "w"); + logc = FOPEN("logs/expt_2k.log", "w"); + logd = FOPEN("logs/expt_2kl.log", "w"); + for (n = 0; primes[n] != NULL; n++) { + SLEEP; + mp_read_radix(&a, primes[n], 10); + mp_zero(&b); + for (rr = 0; rr < (unsigned) mp_count_bits(&a); rr++) { + mp_mul_2(&b, &b); + b.dp[0] |= lbit(); + b.used += 1; + } + mp_sub_d(&a, 1uL, &c); + mp_mod(&b, &c, &b); + mp_set(&c, 3uL); + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_exptmod(&c, &b, &a, &d)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 10u); + mp_sub_d(&a, 1uL, &e); + mp_sub(&e, &b, &b); + mp_exptmod(&c, &b, &a, &e); /* c^(p-1-b) mod a */ + mp_mulmod(&e, &d, &a, &d); /* c^b * c^(p-1-b) == c^p-1 == 1 */ + if (mp_cmp_d(&d, 1uL) != MP_EQ) { + printf("Different (%d)!!!\n", mp_count_bits(&a)); + draw(&d); + exit(0); + } + printf("Exponentiating\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF((n < 3) ? logd : (n < 9) ? logc : (n < 16) ? logb : log, + "%6d %9" PRIu64 "\n", mp_count_bits(&a), tt); + } + FCLOSE(log); + FCLOSE(logb); + FCLOSE(logc); + FCLOSE(logd); + } + + if (should_test("invmod", argc, argv)) { + log = FOPEN("logs/invmod.log", "w"); + for (cnt = 4; cnt <= 32; cnt += 4) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + + do { + mp_add_d(&b, 1uL, &b); + mp_gcd(&a, &b, &c); + } while (mp_cmp_d(&c, 1uL) != MP_EQ); + + rr = 0u; + tt = UINT64_MAX; + do { + gg = TIMFUNC(); + DO(mp_invmod(&b, &a, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 1000u); + mp_mulmod(&b, &c, &a, &d); + if (mp_cmp_d(&d, 1uL) != MP_EQ) { + printf("Failed to invert\n"); + return 0; + } + printf("Inverting mod\t%4d-bit => %9" PRIu64 "/sec, %9" PRIu64 " cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + FPRINTF(log, "%6d %9" PRIu64 "\n", cnt * MP_DIGIT_BIT, tt); + } + FCLOSE(log); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.pdf b/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.pdf new file mode 100644 index 0000000..fbf05ea Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.pdf differ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.tex b/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.tex new file mode 100644 index 0000000..5937fee --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/doc/bn.tex @@ -0,0 +1,2507 @@ +\documentclass[synpaper]{book} +\usepackage{hyperref} +\usepackage{makeidx} +\usepackage{amssymb} +\usepackage{color} +\usepackage{alltt} +\usepackage{graphicx} +\usepackage{layout} +\usepackage{appendix} +\def\union{\cup} +\def\intersect{\cap} +\def\getsrandom{\stackrel{\rm R}{\gets}} +\def\cross{\times} +\def\cat{\hspace{0.5em} \| \hspace{0.5em}} +\def\catn{$\|$} +\def\divides{\hspace{0.3em} | \hspace{0.3em}} +\def\nequiv{\not\equiv} +\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} +\def\lcm{{\rm lcm}} +\def\gcd{{\rm gcd}} +\def\log{{\rm log}} +\def\ord{{\rm ord}} +\def\abs{{\mathit abs}} +\def\rep{{\mathit rep}} +\def\mod{{\mathit\ mod\ }} +\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} +\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} +\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} +\def\Or{{\rm\ or\ }} +\def\And{{\rm\ and\ }} +\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} +\def\implies{\Rightarrow} +\def\undefined{{\rm ``undefined"}} +\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} +\let\oldphi\phi +\def\phi{\varphi} +\def\Pr{{\rm Pr}} +\newcommand{\str}[1]{{\mathbf{#1}}} +\def\F{{\mathbb F}} +\def\N{{\mathbb N}} +\def\Z{{\mathbb Z}} +\def\R{{\mathbb R}} +\def\C{{\mathbb C}} +\def\Q{{\mathbb Q}} +\definecolor{DGray}{gray}{0.5} +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\frontmatter +\pagestyle{empty} +\title{LibTomMath User Manual \\ v1.2.0} +\author{LibTom Projects \\ www.libtom.net} +\maketitle +This text, the library and the accompanying textbook are all hereby placed in the public domain. This book has been +formatted for B5 [176x250] paper using the \LaTeX{} {\em book} macro package. + +\vspace{10cm} + +\begin{flushright}Open Source. Open Academia. Open Minds. + +\mbox{ } +LibTom Projects + +\& originally + +Tom St Denis, + +Ontario, Canada +\end{flushright} + +\tableofcontents +\listoffigures +\mainmatter +\pagestyle{headings} +\chapter{Introduction} +\section{What is LibTomMath?} +LibTomMath is a library of source code which provides a series of efficient and carefully written functions for manipulating +large integer numbers. It was written in portable ISO C source code so that it will build on any platform with a conforming +C compiler. + +In a nutshell the library was written from scratch with verbose comments to help instruct computer science students how +to implement ``bignum'' math. However, the resulting code has proven to be very useful. It has been used by numerous +universities, commercial and open source software developers. It has been used on a variety of platforms ranging from +Linux and Windows based x86 to ARM based Gameboys and PPC based MacOS machines. + +\section{License} +As of the v0.25 the library source code has been placed in the public domain with every new release. As of the v0.28 +release the textbook ``Implementing Multiple Precision Arithmetic'' has been placed in the public domain with every new +release as well. This textbook is meant to compliment the project by providing a more solid walkthrough of the development +algorithms used in the library. + +Since both\footnote{Note that the MPI files under mtest/ are copyrighted by Michael Fromberger. They are not required to use LibTomMath.} are in the +public domain everyone is entitled to do with them as they see fit. + +\section{Building LibTomMath} + +LibTomMath is meant to be very ``GCC friendly'' as it comes with a makefile well suited for GCC. However, the library will +also build in MSVC, Borland C out of the box. For any other ISO C compiler a makefile will have to be made by the end +developer. Please consider to commit such a makefile to the LibTomMath developers, currently residing at +\url{http://github.com/libtom/libtommath}, if successfully done so. + +Intel's C-compiler (ICC) is sufficiently compatible with GCC, at least the newer versions, to replace GCC for building the static and the shared library. Editing the makefiles is not needed, just set the shell variable \texttt{CC} as shown below. +\begin{alltt} +CC=/home/czurnieden/intel/bin/icc make +\end{alltt} + +ICC does not know all options available for GCC and LibTomMath uses two diagnostics \texttt{-Wbad-function-cast} and \texttt{-Wcast-align} that are not supported by ICC resulting in the warnings: +\begin{alltt} +icc: command line warning #10148: option '-Wbad-function-cast' not supported +icc: command line warning #10148: option '-Wcast-align' not supported +\end{alltt} +It is possible to mute this ICC warning with the compiler flag \texttt{-diag-disable=10148}\footnote{It is not recommended to suppress warnings without a very good reason but there is no harm in doing so in this very special case.}. + +\subsection{Static Libraries} +To build as a static library for GCC issue the following +\begin{alltt} +make +\end{alltt} + +command. This will build the library and archive the object files in ``libtommath.a''. Now you link against +that and include ``tommath.h'' within your programs. Alternatively to build with MSVC issue the following +\begin{alltt} +nmake -f makefile.msvc +\end{alltt} + +This will build the library and archive the object files in ``tommath.lib''. This has been tested with MSVC +version 6.00 with service pack 5. + +To run a program to adapt the Toom-Cook cut-off values to your architecture type +\begin{alltt} +make tune +\end{alltt} +This will take some time. + +\subsection{Shared Libraries} +\subsubsection{GNU based Operating Systems} +To build as a shared library for GCC issue the following +\begin{alltt} +make -f makefile.shared +\end{alltt} +This requires the ``libtool'' package (common on most Linux/BSD systems). It will build LibTomMath as both shared +and static then install (by default) into /usr/lib as well as install the header files in /usr/include. The shared +library (resource) will be called ``libtommath.la'' while the static library called ``libtommath.a''. Generally +you use libtool to link your application against the shared object. + +To run a program to adapt the Toom-Cook cut-off values to your architecture type +\begin{alltt} +make -f makefile.shared tune +\end{alltt} +This will take some time. + +\subsubsection{Microsoft Windows based Operating Systems} +There is limited support for making a ``DLL'' in windows via the ``makefile.cygwin\_dll'' makefile. It requires +Cygwin to work with since it requires the auto-export/import functionality. The resulting DLL and import library +``libtommath.dll.a'' can be used to link LibTomMath dynamically to any Windows program using Cygwin. +\subsubsection{OpenBSD} +OpenBSD replaced some of their GNU-tools, especially \texttt{libtool} with their own, slightly different versions. To ease the workload of LibTomMath's developer team, only a static library can be build with the included \texttt{makefile.unix}. + +The wrong \texttt{make} will result in errors like: +\begin{alltt} +*** Parse error in /home/user/GITHUB/libtommath: Need an operator in 'LIBNAME' ) +*** Parse error: Need an operator in 'endif' (makefile.shared:8) +*** Parse error: Need an operator in 'CROSS_COMPILE' (makefile_include.mk:16) +*** Parse error: Need an operator in 'endif' (makefile_include.mk:18) +*** Parse error: Missing dependency operator (makefile_include.mk:22) +*** Parse error: Missing dependency operator (makefile_include.mk:23) +... +\end{alltt} +The wrong \texttt{libtool} will build it all fine but when it comes to the final linking fails with +\begin{alltt} +... +cc -I./ -Wall -Wsign-compare -Wextra -Wshadow -Wsystem-headers -Wdeclaration-afo... +cc -I./ -Wall -Wsign-compare -Wextra -Wshadow -Wsystem-headers -Wdeclaration-afo... +cc -I./ -Wall -Wsign-compare -Wextra -Wshadow -Wsystem-headers -Wdeclaration-afo... +libtool --mode=link --tag=CC cc bn_error.lo bn_s_mp_invmod_fast.lo bn_fast_mp_mo +libtool: link: cc bn_error.lo bn_s_mp_invmod_fast.lo bn_s_mp_montgomery_reduce_fast0 +bn_error.lo: file not recognized: File format not recognized +cc: error: linker command failed with exit code 1 (use -v to see invocation) +Error while executing cc bn_error.lo bn_s_mp_invmod_fast.lo bn_fast_mp_montgomery0 +gmake: *** [makefile.shared:64: libtommath.la] Error 1 +\end{alltt} + +To build a shared library with OpenBSD\footnote{Tested with OpenBSD version 6.4} the GNU versions of \texttt{make} and \texttt{libtool} are needed. +\begin{alltt} +$ sudo pkg_add gmake libtool +\end{alltt} +At this time two versions of \texttt{libtool} are installed and both are named \texttt{libtool}, unfortunately but GNU \texttt{libtool} has been placed in \texttt{/usr/local/bin/} and the native version in \texttt{/usr/bin/}. The path might be different in other versions of OpenBSD but both programms differ in the output of \texttt{libtool --version} +\begin{alltt} +$ /usr/local/bin/libtool --version +libtool (GNU libtool) 2.4.2 +Written by Gordon Matzigkeit , 1996 + +Copyright (C) 2011 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +$ libtool --version +libtool (not (GNU libtool)) 1.5.26 +\end{alltt} + +The shared library should build now with +\begin{alltt} +LIBTOOL="/usr/local/bin/libtool" gmake -f makefile.shared +\end{alltt} +You might need to run a \texttt{gmake -f makefile.shared clean} first. + +\subsubsection{NetBSD} +NetBSD is not as strict as OpenBSD but still needs \texttt{gmake} to build the shared library. \texttt{libtool} may also not exist in a fresh install. +\begin{alltt} +pkg_add gmake libtool +\end{alltt} +Please check with \texttt{libtool --version} that installed libtool is indeed a GNU libtool. +Build the shared library by typing: +\begin{alltt} +gmake -f makefile.shared +\end{alltt} + +\subsection{Testing} +To build the library and the test harness type + +\begin{alltt} +make test +\end{alltt} + +This will build the library, ``test'' and ``mtest/mtest''. The ``test'' program will accept test vectors and verify the +results. ``mtest/mtest'' will generate test vectors using the MPI library by Michael Fromberger\footnote{A copy of MPI +is included in the package}. Simply pipe mtest into test using + +\begin{alltt} +mtest/mtest | test +\end{alltt} + +If you do not have a ``/dev/urandom'' style RNG source you will have to write your own PRNG and simply pipe that into +mtest. For example, if your PRNG program is called ``myprng'' simply invoke + +\begin{alltt} +myprng | mtest/mtest | test +\end{alltt} + +This will output a row of numbers that are increasing. Each column is a different test (such as addition, multiplication, etc) +that is being performed. The numbers represent how many times the test was invoked. If an error is detected the program +will exit with a dump of the relevant numbers it was working with. + +\section{Build Configuration} +LibTomMath can configured at build time in three phases we shall call ``depends'', ``tweaks'' and ``trims''. +Each phase changes how the library is built and they are applied one after another respectively. + +To make the system more powerful you can tweak the build process. Classes are defined in the file +``tommath\_superclass.h''. By default, the symbol ``LTM\_ALL'' shall be defined which simply +instructs the system to build all of the functions. This is how LibTomMath used to be packaged. This will give you +access to every function LibTomMath offers. + +However, there are cases where such a build is not optional. For instance, you want to perform RSA operations. You +don't need the vast majority of the library to perform these operations. Aside from LTM\_ALL there is +another pre--defined class ``SC\_RSA\_1'' which works in conjunction with the RSA from LibTomCrypt. Additional +classes can be defined base on the need of the user. + +\subsection{Build Depends} +In the file tommath\_class.h you will see a large list of C ``defines'' followed by a series of ``ifdefs'' +which further define symbols. All of the symbols (technically they're macros $\ldots$) represent a given C source +file. For instance, BN\_MP\_ADD\_C represents the file ``bn\_mp\_add.c''. When a define has been enabled the +function in the respective file will be compiled and linked into the library. Accordingly when the define +is absent the file will not be compiled and not contribute any size to the library. + +You will also note that the header tommath\_class.h is actually recursively included (it includes itself twice). +This is to help resolve as many dependencies as possible. In the last pass the symbol LTM\_LAST will be defined. +This is useful for ``trims''. + +\subsection{Build Tweaks} +A tweak is an algorithm ``alternative''. For example, to provide tradeoffs (usually between size and space). +They can be enabled at any pass of the configuration phase. + +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Define} & \textbf{Purpose} \\ +\hline BN\_MP\_DIV\_SMALL & Enables a slower, smaller and equally \\ + & functional mp\_div() function \\ +\hline +\end{tabular} +\end{center} +\end{small} + +\subsection{Build Trims} +A trim is a manner of removing functionality from a function that is not required. For instance, to perform +RSA cryptography you only require exponentiation with odd moduli so even moduli support can be safely removed. +Build trims are meant to be defined on the last pass of the configuration which means they are to be defined +only if LTM\_LAST has been defined. + +\subsubsection{Moduli Related} +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Restriction} & \textbf{Undefine} \\ +\hline Exponentiation with odd moduli only & BN\_S\_MP\_EXPTMOD\_C \\ + & BN\_MP\_REDUCE\_C \\ + & BN\_MP\_REDUCE\_SETUP\_C \\ + & BN\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ + & BN\_FAST\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ +\hline Exponentiation with random odd moduli & (The above plus the following) \\ + & BN\_MP\_REDUCE\_2K\_C \\ + & BN\_MP\_REDUCE\_2K\_SETUP\_C \\ + & BN\_MP\_REDUCE\_IS\_2K\_C \\ + & BN\_MP\_DR\_IS\_MODULUS\_C \\ + & BN\_MP\_DR\_REDUCE\_C \\ + & BN\_MP\_DR\_SETUP\_C \\ +\hline Modular inverse odd moduli only & BN\_MP\_INVMOD\_SLOW\_C \\ +\hline Modular inverse (both, smaller/slower) & BN\_FAST\_MP\_INVMOD\_C \\ +\hline +\end{tabular} +\end{center} +\end{small} + +\subsubsection{Operand Size Related} +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Restriction} & \textbf{Undefine} \\ +\hline Moduli $\le 2560$ bits & BN\_MP\_MONTGOMERY\_REDUCE\_C \\ + & BN\_S\_MP\_MUL\_DIGS\_C \\ + & BN\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ + & BN\_S\_MP\_SQR\_C \\ +\hline Polynomial Schmolynomial & BN\_MP\_KARATSUBA\_MUL\_C \\ + & BN\_MP\_KARATSUBA\_SQR\_C \\ + & BN\_MP\_TOOM\_MUL\_C \\ + & BN\_MP\_TOOM\_SQR\_C \\ + +\hline +\end{tabular} +\end{center} +\end{small} + + +\section{Purpose of LibTomMath} +Unlike GNU MP (GMP) Library, LIP, OpenSSL or various other commercial kits (Miracl), LibTomMath was not written with +bleeding edge performance in mind. First and foremost LibTomMath was written to be entirely open. Not only is the +source code public domain (unlike various other GPL/etc licensed code), not only is the code freely downloadable but the +source code is also accessible for computer science students attempting to learn ``BigNum'' or multiple precision +arithmetic techniques. + +LibTomMath was written to be an instructive collection of source code. This is why there are many comments, only one +function per source file and often I use a ``middle-road'' approach where I don't cut corners for an extra 2\% speed +increase. + +Source code alone cannot really teach how the algorithms work which is why I also wrote a textbook that accompanies +the library (beat that!). + +So you may be thinking ``should I use LibTomMath?'' and the answer is a definite maybe. Let me tabulate what I think +are the pros and cons of LibTomMath by comparing it to the math routines from GnuPG\footnote{GnuPG v1.2.3 versus LibTomMath v0.28}. + +\newpage\begin{figure}[h] +\begin{small} +\begin{center} +\begin{tabular}{|l|c|c|l|} +\hline \textbf{Criteria} & \textbf{Pro} & \textbf{Con} & \textbf{Notes} \\ +\hline Few lines of code per file & X & & GnuPG $ = 300.9$, LibTomMath $ = 71.97$ \\ +\hline Commented function prototypes & X && GnuPG function names are cryptic. \\ +\hline Speed && X & LibTomMath is slower. \\ +\hline Totally free & X & & GPL has unfavourable restrictions.\\ +\hline Large function base & X & & GnuPG is barebones. \\ +\hline Five modular reduction algorithms & X & & Faster modular exponentiation for a variety of moduli. \\ +\hline Portable & X & & GnuPG requires configuration to build. \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{LibTomMath Valuation} +\end{figure} + +It may seem odd to compare LibTomMath to GnuPG since the math in GnuPG is only a small portion of the entire application. +However, LibTomMath was written with cryptography in mind. It provides essentially all of the functions a cryptosystem +would require when working with large integers. + +So it may feel tempting to just rip the math code out of GnuPG (or GnuMP where it was taken from originally) in your +own application but I think there are reasons not to. While LibTomMath is slower than libraries such as GnuMP it is +not normally significantly slower. On x86 machines the difference is normally a factor of two when performing modular +exponentiations. It depends largely on the processor, compiler and the moduli being used. + +Essentially the only time you wouldn't use LibTomMath is when blazing speed is the primary concern. However, +on the other side of the coin LibTomMath offers you a totally free (public domain) well structured math library +that is very flexible, complete and performs well in resource constrained environments. Fast RSA for example can +be performed with as little as 8KB of ram for data (again depending on build options). + +\chapter{Getting Started with LibTomMath} +\section{Building Programs} +In order to use LibTomMath you must include ``tommath.h'' and link against the appropriate library file (typically +libtommath.a). There is no library initialization required and the entire library is thread safe. + +\section{Return Codes} +There are three possible return codes a function may return. + +\index{MP\_OKAY}\index{MP\_YES}\index{MP\_NO}\index{MP\_VAL}\index{MP\_MEM} +\begin{figure}[h!] +\begin{center} +\begin{small} +\begin{tabular}{|l|l|} +\hline \textbf{Code} & \textbf{Meaning} \\ +\hline MP\_OKAY & The function succeeded. \\ +\hline MP\_VAL & The function input was invalid. \\ +\hline MP\_MEM & Heap memory exhausted. \\ +\hline &\\ +\hline MP\_YES & Response is yes. \\ +\hline MP\_NO & Response is no. \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Return Codes} +\end{figure} + +The last two codes listed are not actually ``return'ed'' by a function. They are placed in an integer (the caller must +provide the address of an integer it can store to) which the caller can access. To convert one of the three return codes +to a string use the following function. + +\index{mp\_error\_to\_string} +\begin{alltt} +char *mp_error_to_string(int code); +\end{alltt} + +This will return a pointer to a string which describes the given error code. It will not work for the return codes +MP\_YES and MP\_NO. + +\section{Data Types} +The basic ``multiple precision integer'' type is known as the ``mp\_int'' within LibTomMath. This data type is used to +organize all of the data required to manipulate the integer it represents. Within LibTomMath it has been prototyped +as the following. + +\index{mp\_int} +\begin{alltt} +typedef struct \{ + int used, alloc, sign; + mp_digit *dp; +\} mp_int; +\end{alltt} + +Where ``mp\_digit'' is a data type that represents individual digits of the integer. By default, an mp\_digit is the +ISO C ``unsigned long'' data type and each digit is $28-$bits long. The mp\_digit type can be configured to suit other +platforms by defining the appropriate macros. + +All LTM functions that use the mp\_int type will expect a pointer to mp\_int structure. You must allocate memory to +hold the structure itself by yourself (whether off stack or heap it doesn't matter). The very first thing that must be +done to use an mp\_int is that it must be initialized. + +\section{Function Organization} + +The arithmetic functions of the library are all organized to have the same style prototype. That is source operands +are passed on the left and the destination is on the right. For instance, + +\begin{alltt} +mp_add(&a, &b, &c); /* c = a + b */ +mp_mul(&a, &a, &c); /* c = a * a */ +mp_div(&a, &b, &c, &d); /* c = [a/b], d = a mod b */ +\end{alltt} + +Another feature of the way the functions have been implemented is that source operands can be destination operands as well. +For instance, + +\begin{alltt} +mp_add(&a, &b, &b); /* b = a + b */ +mp_div(&a, &b, &a, &c); /* a = [a/b], c = a mod b */ +\end{alltt} + +This allows operands to be re-used which can make programming simpler. + +\section{Initialization} +\subsection{Single Initialization} +A single mp\_int can be initialized with the ``mp\_init'' function. + +\index{mp\_init} +\begin{alltt} +int mp_init (mp_int * a); +\end{alltt} + +This function expects a pointer to an mp\_int structure and will initialize the members of the structure so the mp\_int +represents the default integer which is zero. If the functions returns MP\_OKAY then the mp\_int is ready to be used +by the other LibTomMath functions. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Single Free} +When you are finished with an mp\_int it is ideal to return the heap it used back to the system. The following function +provides this functionality. + +\index{mp\_clear} +\begin{alltt} +void mp_clear (mp_int * a); +\end{alltt} + +The function expects a pointer to a previously initialized mp\_int structure and frees the heap it uses. It sets the +pointer\footnote{The ``dp'' member.} within the mp\_int to \textbf{NULL} which is used to prevent double free situations. +Is is legal to call mp\_clear() twice on the same mp\_int in a row. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + /* We're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Multiple Initializations} +Certain algorithms require more than one large integer. In these instances it is ideal to initialize all of the mp\_int +variables in an ``all or nothing'' fashion. That is, they are either all initialized successfully or they are all +not initialized. + +The mp\_init\_multi() function provides this functionality. + +\index{mp\_init\_multi} \index{mp\_clear\_multi} +\begin{alltt} +int mp_init_multi(mp_int *mp, ...); +\end{alltt} + +It accepts a \textbf{NULL} terminated list of pointers to mp\_int structures. It will attempt to initialize them all +at once. If the function returns MP\_OKAY then all of the mp\_int variables are ready to use, otherwise none of them +are available for use. A complementary mp\_clear\_multi() function allows multiple mp\_int variables to be free'd +from the heap at the same time. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int num1, num2, num3; + int result; + + if ((result = mp_init_multi(&num1, + &num2, + &num3, NULL)) != MP\_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the numbers */ + + /* We're done with them. */ + mp_clear_multi(&num1, &num2, &num3, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Other Initializers} +To initialized and make a copy of an mp\_int the mp\_init\_copy() function has been provided. + +\index{mp\_init\_copy} +\begin{alltt} +int mp_init_copy (mp_int * a, mp_int * b); +\end{alltt} + +This function will initialize $a$ and make it a copy of $b$ if all goes well. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int num1, num2; + int result; + + /* initialize and do work on num1 ... */ + + /* We want a copy of num1 in num2 now */ + if ((result = mp_init_copy(&num2, &num1)) != MP_OKAY) \{ + printf("Error initializing the copy. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now num2 is ready and contains a copy of num1 */ + + /* We're done with them. */ + mp_clear_multi(&num1, &num2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +Another less common initializer is mp\_init\_size() which allows the user to initialize an mp\_int with a given +default number of digits. By default, all initializers allocate \textbf{MP\_PREC} digits. This function lets +you override this behaviour. + +\index{mp\_init\_size} +\begin{alltt} +int mp_init_size (mp_int * a, int size); +\end{alltt} + +The $size$ parameter must be greater than zero. If the function succeeds the mp\_int $a$ will be initialized +to have $size$ digits (which are all initially zero). + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + /* we need a 60-digit number */ + if ((result = mp_init_size(&number, 60)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\section{Maintenance Functions} +\subsection{Clear Leading Zeros} + +This is used to ensure that leading zero digits are trimed and the leading "used" digit will be non-zero. +It also fixes the sign if there are no more leading digits. + +\index{mp\_clamp} +\begin{alltt} +void mp_clamp(mp_int *a); +\end{alltt} + +\subsection{Zero Out} + +This function will set the ``bigint'' to zeros without changing the amount of allocated memory. + +\index{mp\_zero} +\begin{alltt} +void mp_zero(mp_int *a); +\end{alltt} + + +\subsection{Reducing Memory Usage} +When an mp\_int is in a state where it won't be changed again\footnote{A Diffie-Hellman modulus for instance.} excess +digits can be removed to return memory to the heap with the mp\_shrink() function. + +\index{mp\_shrink} +\begin{alltt} +int mp_shrink (mp_int * a); +\end{alltt} + +This will remove excess digits of the mp\_int $a$. If the operation fails the mp\_int should be intact without the +excess digits being removed. Note that you can use a shrunk mp\_int in further computations, however, such operations +will require heap operations which can be slow. It is not ideal to shrink mp\_int variables that you will further +modify in the system (unless you are seriously low on memory). + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number [e.g. pre-computation] */ + + /* We're done with it for now. */ + if ((result = mp_shrink(&number)) != MP_OKAY) \{ + printf("Error shrinking the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use it .... */ + + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Adding additional digits} + +Within the mp\_int structure are two parameters which control the limitations of the array of digits that represent +the integer the mp\_int is meant to equal. The \textit{used} parameter dictates how many digits are significant, that is, +contribute to the value of the mp\_int. The \textit{alloc} parameter dictates how many digits are currently available in +the array. If you need to perform an operation that requires more digits you will have to mp\_grow() the mp\_int to +your desired size. + +\index{mp\_grow} +\begin{alltt} +int mp_grow (mp_int * a, int size); +\end{alltt} + +This will grow the array of digits of $a$ to $size$. If the \textit{alloc} parameter is already bigger than +$size$ the function will not do anything. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + /* We need to add 20 digits to the number */ + if ((result = mp_grow(&number, number.alloc + 20)) != MP_OKAY) \{ + printf("Error growing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + + /* use the number */ + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\chapter{Basic Operations} +\section{Copying} + +A so called ``deep copy'', where new memory is allocated and all contents of $a$ are copied verbatim into $b$ such that $b = a$ at the end. + +\index{mp\_copy} +\begin{alltt} +int mp_copy (mp_int * a, mp_int *b); +\end{alltt} + +You can also just swap $a$ and $b$. It does the normal pointer changing with a temporary pointer variable, just that you do not have to. + +\index{mp\_exch} +\begin{alltt} +void mp_exch (mp_int * a, mp_int *b); +\end{alltt} + +\section{Bit Counting} + +To get the position of the lowest bit set (LSB, the Lowest Significant Bit; the number of bits which are zero before the first zero bit ) + +\index{mp\_cnt\_lsb} +\begin{alltt} +int mp_cnt_lsb(const mp_int *a); +\end{alltt} + +To get the position of the highest bit set (MSB, the Most Significant Bit; the number of bits in teh ``bignum'') + +\index{mp\_count\_bits} +\begin{alltt} +int mp_count_bits(const mp_int *a); +\end{alltt} + + +\section{Small Constants} +Setting mp\_ints to small constants is a relatively common operation. To accommodate these instances there is a +small constant assignment function. This function is used to set a single digit constant. +The reason for this function is efficiency. Setting a single digit is quick but the +domain of a digit can change (it's always at least $0 \ldots 127$). + +\subsection{Single Digit} + +Setting a single digit can be accomplished with the following function. + +\index{mp\_set} +\begin{alltt} +void mp_set (mp_int * a, mp_digit b); +\end{alltt} + +This will zero the contents of $a$ and make it represent an integer equal to the value of $b$. Note that this +function has a return type of \textbf{void}. It cannot cause an error so it is safe to assume the function +succeeded. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Int32 and Int64 Constants} + +These functions can be used to set a constant with 32 or 64 bits. + +\index{mp\_set\_i32} \index{mp\_set\_u32} +\index{mp\_set\_i64} \index{mp\_set\_u64} +\begin{alltt} +void mp_set_i32 (mp_int * a, int32_t b); +void mp_set_u32 (mp_int * a, uint32_t b); +void mp_set_i64 (mp_int * a, int64_t b); +void mp_set_u64 (mp_int * a, uint64_t b); +\end{alltt} + +These functions assign the sign and value of the input \texttt{b} to \texttt{mp\_int a}. +The value can be obtained again by calling the following functions. + +\index{mp\_get\_i32} \index{mp\_get\_u32} \index{mp\_get\_mag\_u32} +\index{mp\_get\_i64} \index{mp\_get\_u64} \index{mp\_get\_mag\_u64} +\begin{alltt} +int32_t mp_get_i32 (mp_int * a); +uint32_t mp_get_u32 (mp_int * a); +uint32_t mp_get_mag_u32 (mp_int * a); +int64_t mp_get_i64 (mp_int * a); +uint64_t mp_get_u64 (mp_int * a); +uint64_t mp_get_mag_u64 (mp_int * a); +\end{alltt} + +These functions return the 32 or 64 least significant bits of $a$ respectively. The unsigned functions +return negative values in a twos complement representation. The absolute value or magnitude can be obtained using the mp\_get\_mag functions. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 654321 (note this is bigger than 127) */ + mp_set_u32(&number, 654321); + + printf("number == \%" PRIi32, mp_get_i32(&number)); + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +This should output the following if the program succeeds. + +\begin{alltt} +number == 654321 +\end{alltt} + +\subsection{Long Constants - platform dependant} + +\index{mp\_set\_l} \index{mp\_set\_ul} +\begin{alltt} +void mp_set_l (mp_int * a, long b); +void mp_set_ul (mp_int * a, unsigned long b); +\end{alltt} + +This will assign the value of the platform-dependent sized variable $b$ to the mp\_int $a$. + +To retrieve the value, the following functions can be used. + +\index{mp\_get\_l} \index{mp\_get\_ul} \index{mp\_get\_mag\_ul} +\begin{alltt} +long mp_get_l (mp_int * a); +unsigned long mp_get_ul (mp_int * a); +unsigned long mp_get_mag_ul (mp_int * a); +\end{alltt} + +This will return the least significant bits of the mp\_int $a$ that fit into a ``long''. + +\subsection{Long Long Constants - platform dependant} + +\index{mp\_set\_ll} \index{mp\_set\_ull} +\begin{alltt} +void mp_set_ll (mp_int * a, long long b); +void mp_set_ull (mp_int * a, unsigned long long b); +\end{alltt} + +This will assign the value of the platform-dependent sized variable $b$ to the mp\_int $a$. + +To retrieve the value, the following functions can be used. + +\index{mp\_get\_ll} +\index{mp\_get\_ull} +\index{mp\_get\_mag\_ull} +\begin{alltt} +long long mp_get_ll (mp_int * a); +unsigned long long mp_get_ull (mp_int * a); +unsigned long long mp_get_mag_ull (mp_int * a); +\end{alltt} + +This will return the least significant bits of the mp\_int $a$ that fit into a ``long long''. + +\subsection{Initialize and Setting Constants} +To both initialize and set small constants the following two functions are available. +\index{mp\_init\_set} \index{mp\_init\_set\_int} +\begin{alltt} +int mp_init_set (mp_int * a, mp_digit b); +int mp_init_i32 (mp_int * a, int32_t b); +int mp_init_u32 (mp_int * a, uint32_t b); +int mp_init_i64 (mp_int * a, int64_t b); +int mp_init_u64 (mp_int * a, uint64_t b); +int mp_init_l (mp_int * a, long b); +int mp_init_ul (mp_int * a, unsigned long b); +int mp_init_ll (mp_int * a, long long b); +int mp_init_ull (mp_int * a, unsigned long long b); +\end{alltt} + +Both functions work like the previous counterparts except they first mp\_init $a$ before setting the values. + +\begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + /* initialize and set a single digit */ + if ((result = mp_init_set(&number1, 100)) != MP_OKAY) \{ + printf("Error setting number1: \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* initialize and set a long */ + if ((result = mp_init_l(&number2, 1023)) != MP_OKAY) \{ + printf("Error setting number2: \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* display */ + printf("Number1, Number2 == \%" PRIi32 ", \%" PRIi32, + mp_get_i32(&number1), mp_get_i32(&number2)); + + /* clear */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +If this program succeeds it shall output. +\begin{alltt} +Number1, Number2 == 100, 1023 +\end{alltt} + +\section{Comparisons} + +Comparisons in LibTomMath are always performed in a ``left to right'' fashion. There are three possible return codes +for any comparison. + +\index{MP\_GT} \index{MP\_EQ} \index{MP\_LT} +\begin{figure}[h] +\begin{center} +\begin{tabular}{|c|c|} +\hline \textbf{Result Code} & \textbf{Meaning} \\ +\hline MP\_GT & $a > b$ \\ +\hline MP\_EQ & $a = b$ \\ +\hline MP\_LT & $a < b$ \\ +\hline +\end{tabular} +\end{center} +\caption{Comparison Codes for $a, b$} +\label{fig:CMP} +\end{figure} + +In figure \ref{fig:CMP} two integers $a$ and $b$ are being compared. In this case $a$ is said to be ``to the left'' of +$b$. + +\subsection{Unsigned comparison} + +An unsigned comparison considers only the digits themselves and not the associated \textit{sign} flag of the +mp\_int structures. This is analogous to an absolute comparison. The function mp\_cmp\_mag() will compare two +mp\_int variables based on their digits only. + +\index{mp\_cmp\_mag} +\begin{alltt} +int mp_cmp_mag(mp_int * a, mp_int * b); +\end{alltt} +This will compare $a$ to $b$ placing $a$ to the left of $b$. This function cannot fail and will return one of the +three compare codes listed in figure \ref{fig:CMP}. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + if ((result = mp_init_multi(&number1, &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number1 to 5 */ + mp_set(&number1, 5); + + /* set the number2 to -6 */ + mp_set(&number2, 6); + if ((result = mp_neg(&number2, &number2)) != MP_OKAY) \{ + printf("Error negating number2. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + switch(mp_cmp_mag(&number1, &number2)) \{ + case MP_GT: printf("|number1| > |number2|"); break; + case MP_EQ: printf("|number1| = |number2|"); break; + case MP_LT: printf("|number1| < |number2|"); break; + \} + + /* we're done with it. */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program\footnote{This function uses the mp\_neg() function which is discussed in section \ref{sec:NEG}.} completes +successfully it should print the following. + +\begin{alltt} +|number1| < |number2| +\end{alltt} + +This is because $\vert -6 \vert = 6$ and obviously $5 < 6$. + +\subsection{Signed comparison} + +To compare two mp\_int variables based on their signed value the mp\_cmp() function is provided. + +\index{mp\_cmp} +\begin{alltt} +int mp_cmp(mp_int * a, mp_int * b); +\end{alltt} + +This will compare $a$ to the left of $b$. It will first compare the signs of the two mp\_int variables. If they +differ it will return immediately based on their signs. If the signs are equal then it will compare the digits +individually. This function will return one of the compare conditions codes listed in figure \ref{fig:CMP}. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + if ((result = mp_init_multi(&number1, &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number1 to 5 */ + mp_set(&number1, 5); + + /* set the number2 to -6 */ + mp_set(&number2, 6); + if ((result = mp_neg(&number2, &number2)) != MP_OKAY) \{ + printf("Error negating number2. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + switch(mp_cmp(&number1, &number2)) \{ + case MP_GT: printf("number1 > number2"); break; + case MP_EQ: printf("number1 = number2"); break; + case MP_LT: printf("number1 < number2"); break; + \} + + /* we're done with it. */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program\footnote{This function uses the mp\_neg() function which is discussed in section \ref{sec:NEG}.} completes +successfully it should print the following. + +\begin{alltt} +number1 > number2 +\end{alltt} + +\subsection{Single Digit} + +To compare a single digit against an mp\_int the following function has been provided. + +\index{mp\_cmp\_d} +\begin{alltt} +int mp_cmp_d(mp_int * a, mp_digit b); +\end{alltt} + +This will compare $a$ to the left of $b$ using a signed comparison. Note that it will always treat $b$ as +positive. This function is rather handy when you have to compare against small values such as $1$ (which often +comes up in cryptography). The function cannot fail and will return one of the tree compare condition codes +listed in figure \ref{fig:CMP}. + + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("number > 7"); break; + case MP_EQ: printf("number = 7"); break; + case MP_LT: printf("number < 7"); break; + \} + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program functions properly it will print out the following. + +\begin{alltt} +number < 7 +\end{alltt} + +\section{Logical Operations} + +Logical operations are operations that can be performed either with simple shifts or boolean operators such as +AND, XOR and OR directly. These operations are very quick. + +\subsection{Multiplication by two} + +Multiplications and divisions by any power of two can be performed with quick logical shifts either left or +right depending on the operation. + +When multiplying or dividing by two a special case routine can be used which are as follows. +\index{mp\_mul\_2} \index{mp\_div\_2} +\begin{alltt} +int mp_mul_2(mp_int * a, mp_int * b); +int mp_div_2(mp_int * a, mp_int * b); +\end{alltt} + +The former will assign twice $a$ to $b$ while the latter will assign half $a$ to $b$. These functions are fast +since the shift counts and maskes are hardcoded into the routines. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + /* multiply by two */ + if ((result = mp\_mul\_2(&number, &number)) != MP_OKAY) \{ + printf("Error multiplying the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("2*number > 7"); break; + case MP_EQ: printf("2*number = 7"); break; + case MP_LT: printf("2*number < 7"); break; + \} + + /* now divide by two */ + if ((result = mp\_div\_2(&number, &number)) != MP_OKAY) \{ + printf("Error dividing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("2*number/2 > 7"); break; + case MP_EQ: printf("2*number/2 = 7"); break; + case MP_LT: printf("2*number/2 < 7"); break; + \} + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program is successful it will print out the following text. + +\begin{alltt} +2*number > 7 +2*number/2 < 7 +\end{alltt} + +Since $10 > 7$ and $5 < 7$. + +To multiply by a power of two the following function can be used. + +\index{mp\_mul\_2d} +\begin{alltt} +int mp_mul_2d(mp_int * a, int b, mp_int * c); +\end{alltt} + +This will multiply $a$ by $2^b$ and store the result in ``c''. If the value of $b$ is less than or equal to +zero the function will copy $a$ to ``c'' without performing any further actions. The multiplication itself +is implemented as a right-shift operation of $a$ by $b$ bits. + +To divide by a power of two use the following. + +\index{mp\_div\_2d} +\begin{alltt} +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); +\end{alltt} +Which will divide $a$ by $2^b$, store the quotient in ``c'' and the remainder in ``d'. If $b \le 0$ then the +function simply copies $a$ over to ``c'' and zeroes $d$. The variable $d$ may be passed as a \textbf{NULL} +value to signal that the remainder is not desired. The division itself is implemented as a left-shift +operation of $a$ by $b$ bits. + +It is also not very uncommon to need just the power of two $2^b$; for example the startvalue for the Newton method. + +\index{mp\_2expt} +\begin{alltt} +int mp_2expt(mp_int *a, int b); +\end{alltt} +It is faster than doing it by shifting $1$ with \texttt{mp\_mul\_2d}. + +\subsection{Polynomial Basis Operations} + +Strictly speaking the organization of the integers within the mp\_int structures is what is known as a +``polynomial basis''. This simply means a field element is stored by divisions of a radix. For example, if +$f(x) = \sum_{i=0}^{k} y_ix^k$ for any vector $\vec y$ then the array of digits in $\vec y$ are said to be +the polynomial basis representation of $z$ if $f(\beta) = z$ for a given radix $\beta$. + +To multiply by the polynomial $g(x) = x$ all you have todo is shift the digits of the basis left one place. The +following function provides this operation. + +\index{mp\_lshd} +\begin{alltt} +int mp_lshd (mp_int * a, int b); +\end{alltt} + +This will multiply $a$ in place by $x^b$ which is equivalent to shifting the digits left $b$ places and inserting zeroes +in the least significant digits. Similarly to divide by a power of $x$ the following function is provided. + +\index{mp\_rshd} +\begin{alltt} +void mp_rshd (mp_int * a, int b) +\end{alltt} +This will divide $a$ in place by $x^b$ and discard the remainder. This function cannot fail as it performs the operations +in place and no new digits are required to complete it. + +\subsection{AND, OR, XOR and COMPLEMENT Operations} + +While AND, OR and XOR operations compute arbitrary-precision bitwise operations. Negative numbers +are treated as if they are in two-complement representation, while internally they are sign-magnitude however. + +\index{mp\_or} \index{mp\_and} \index{mp\_xor} \index{mp\_complement} +\begin{alltt} +int mp_or (mp_int * a, mp_int * b, mp_int * c); +int mp_and (mp_int * a, mp_int * b, mp_int * c); +int mp_xor (mp_int * a, mp_int * b, mp_int * c); +int mp_complement(const mp_int *a, mp_int *b); +int mp_signed_rsh(mp_int * a, int b, mp_int * c, mp_int * d); +\end{alltt} + +The function \texttt{mp\_complement} computes a two-complement $b = \sim a$. The function \texttt{mp\_signed\_rsh} performs +sign extending right shift. For positive numbers it is equivalent to \texttt{mp\_div\_2d}. + +\subsection{Bit Picking} +\index{mp\_get\_bit} +\begin{alltt} +int mp_get_bit(mp_int *a, int b) +\end{alltt} + +Pick a bit: returns \texttt{MP\_YES} if the bit at position $b$ (0-index) is set, that is if it is 1 (one), \texttt{MP\_NO} +if the bit is 0 (zero) and \texttt{MP\_VAL} if $b < 0$. + +\section{Addition and Subtraction} + +To compute an addition or subtraction the following two functions can be used. + +\index{mp\_add} \index{mp\_sub} +\begin{alltt} +int mp_add (mp_int * a, mp_int * b, mp_int * c); +int mp_sub (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} + +Which perform $c = a \odot b$ where $\odot$ is one of signed addition or subtraction. The operations are fully sign +aware. + +\section{Sign Manipulation} +\subsection{Negation} +\label{sec:NEG} +Simple integer negation can be performed with the following. + +\index{mp\_neg} +\begin{alltt} +int mp_neg (mp_int * a, mp_int * b); +\end{alltt} + +Which assigns $-a$ to $b$. + +\subsection{Absolute} +Simple integer absolutes can be performed with the following. + +\index{mp\_abs} +\begin{alltt} +int mp_abs (mp_int * a, mp_int * b); +\end{alltt} + +Which assigns $\vert a \vert$ to $b$. + +\section{Integer Division and Remainder} +To perform a complete and general integer division with remainder use the following function. + +\index{mp\_div} +\begin{alltt} +int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d); +\end{alltt} + +This divides $a$ by $b$ and stores the quotient in $c$ and $d$. The signed quotient is computed such that +$bc + d = a$. Note that either of $c$ or $d$ can be set to \textbf{NULL} if their value is not required. If +$b$ is zero the function returns \textbf{MP\_VAL}. + + +\chapter{Multiplication and Squaring} +\section{Multiplication} +A full signed integer multiplication can be performed with the following. +\index{mp\_mul} +\begin{alltt} +int mp_mul (mp_int * a, mp_int * b, mp_int * c); +\end{alltt} +Which assigns the full signed product $ab$ to $c$. This function actually breaks into one of four cases which are +specific multiplication routines optimized for given parameters. First there are the Toom-Cook multiplications which +should only be used with very large inputs. This is followed by the Karatsuba multiplications which are for moderate +sized inputs. Then followed by the Comba and baseline multipliers. + +Fortunately for the developer you don't really need to know this unless you really want to fine tune the system. mp\_mul() +will determine on its own\footnote{Some tweaking may be required but \texttt{make tune} will put some reasonable values in \texttt{bncore.c}} what routine to use automatically when it is called. + +\begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + /* Initialize the numbers */ + if ((result = mp_init_multi(&number1, + &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the terms */ + mp_set_i32(&number, 257); + mp_set_i32(&number2, 1023); + + /* multiply them */ + if ((result = mp_mul(&number1, &number2, + &number1)) != MP_OKAY) \{ + printf("Error multiplying terms. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* display */ + printf("number1 * number2 == \%" PRIi32, mp_get_i32(&number1)); + + /* free terms and return */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +If this program succeeds it shall output the following. + +\begin{alltt} +number1 * number2 == 262911 +\end{alltt} + +\section{Squaring} +Since squaring can be performed faster than multiplication it is performed it's own function instead of just using +mp\_mul(). + +\index{mp\_sqr} +\begin{alltt} +int mp_sqr (mp_int * a, mp_int * b); +\end{alltt} + +Will square $a$ and store it in $b$. Like the case of multiplication there are four different squaring +algorithms all which can be called from mp\_sqr(). It is ideal to use mp\_sqr over mp\_mul when squaring terms because +of the speed difference. + +\section{Tuning Polynomial Basis Routines} + +Both of the Toom-Cook and Karatsuba multiplication algorithms are faster than the traditional $O(n^2)$ approach that +the Comba and baseline algorithms use. At $O(n^{1.464973})$ and $O(n^{1.584962})$ running times respectively they require +considerably less work. For example, a 10000-digit multiplication would take roughly 724,000 single precision +multiplications with Toom-Cook or 100,000,000 single precision multiplications with the standard Comba (a factor +of 138). + +So why not always use Karatsuba or Toom-Cook? The simple answer is that they have so much overhead that they're not +actually faster than Comba until you hit distinct ``cutoff'' points. For Karatsuba with the default configuration, +GCC 3.3.1 and an Athlon XP processor the cutoff point is roughly 110 digits (about 70 for the Intel P4). That is, at +110 digits Karatsuba and Comba multiplications just about break even and for 110+ digits Karatsuba is faster. + +Toom-Cook has incredible overhead and is probably only useful for very large inputs. So far no known cutoff points +exist and for the most part I just set the cutoff points very high to make sure they're not called. + +To get reasonable values for the cut-off points for your architecture, type + +\begin{alltt} +make tune +\end{alltt} + +This will run a benchmark, computes the medians, rewrites \texttt{bncore.c}, and recompiles \texttt{bncore.c} and relinks the library. + +The benchmark itself can be fine-tuned in the file \texttt{etc/tune\_it.sh}. + +The program \texttt{etc/tune} is also able to print a list of values for printing curves with e.g.: \texttt{gnuplot}. type \texttt{./etc/tune -h} to get a list of all available options. + +\chapter{Modular Reduction} + +Modular reduction is process of taking the remainder of one quantity divided by another. Expressed +as (\ref{eqn:mod}) the modular reduction is equivalent to the remainder of $b$ divided by $c$. + +\begin{equation} +a \equiv b \mbox{ (mod }c\mbox{)} +\label{eqn:mod} +\end{equation} + +Of particular interest to cryptography are reductions where $b$ is limited to the range $0 \le b < c^2$ since particularly +fast reduction algorithms can be written for the limited range. + +Note that one of the four optimized reduction algorithms are automatically chosen in the modular exponentiation +algorithm mp\_exptmod when an appropriate modulus is detected. + +\section{Straight Division} +In order to effect an arbitrary modular reduction the following algorithm is provided. + +\index{mp\_mod} +\begin{alltt} +int mp_mod(mp_int *a, mp_int *b, mp_int *c); +\end{alltt} + +This reduces $a$ modulo $b$ and stores the result in $c$. The sign of $c$ shall agree with the sign +of $b$. This algorithm accepts an input $a$ of any range and is not limited by $0 \le a < b^2$. + +\section{Barrett Reduction} + +Barrett reduction is a generic optimized reduction algorithm that requires pre--computation to achieve +a decent speedup over straight division. First a $\mu$ value must be precomputed with the following function. + +\index{mp\_reduce\_setup} +\begin{alltt} +int mp_reduce_setup(mp_int *a, mp_int *b); +\end{alltt} + +Given a modulus in $b$ this produces the required $\mu$ value in $a$. For any given modulus this only has to +be computed once. Modular reduction can now be performed with the following. + +\index{mp\_reduce} +\begin{alltt} +int mp_reduce(mp_int *a, mp_int *b, mp_int *c); +\end{alltt} + +This will reduce $a$ in place modulo $b$ with the precomputed $\mu$ value in $c$. $a$ must be in the range +$0 \le a < b^2$. + +\begin{alltt} +int main(void) +\{ + mp_int a, b, c, mu; + int result; + + /* initialize a,b to desired values, mp_init mu, + * c and set c to 1...we want to compute a^3 mod b + */ + + /* get mu value */ + if ((result = mp_reduce_setup(&mu, b)) != MP_OKAY) \{ + printf("Error getting mu. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* square a to get c = a^2 */ + if ((result = mp_sqr(&a, &c)) != MP_OKAY) \{ + printf("Error squaring. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' modulo b */ + if ((result = mp_reduce(&c, &b, &mu)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* multiply a to get c = a^3 */ + if ((result = mp_mul(&a, &c, &c)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' modulo b */ + if ((result = mp_reduce(&c, &b, &mu)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* c now equals a^3 mod b */ + + return EXIT_SUCCESS; +\} +\end{alltt} + +This program will calculate $a^3 \mbox{ mod }b$ if all the functions succeed. + +\section{Montgomery Reduction} + +Montgomery is a specialized reduction algorithm for any odd moduli. Like Barrett reduction a pre--computation +step is required. This is accomplished with the following. + +\index{mp\_montgomery\_setup} +\begin{alltt} +int mp_montgomery_setup(mp_int *a, mp_digit *mp); +\end{alltt} + +For the given odd moduli $a$ the precomputation value is placed in $mp$. The reduction is computed with the +following. + +\index{mp\_montgomery\_reduce} +\begin{alltt} +int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +\end{alltt} +This reduces $a$ in place modulo $m$ with the pre--computed value $mp$. $a$ must be in the range +$0 \le a < b^2$. + +Montgomery reduction is faster than Barrett reduction for moduli smaller than the ``comba'' limit. With the default +setup for instance, the limit is $127$ digits ($3556$--bits). Note that this function is not limited to +$127$ digits just that it falls back to a baseline algorithm after that point. + +An important observation is that this reduction does not return $a \mbox{ mod }m$ but $aR^{-1} \mbox{ mod }m$ +where $R = \beta^n$, $n$ is the n number of digits in $m$ and $\beta$ is radix used (default is $2^{28}$). + +To quickly calculate $R$ the following function was provided. + +\index{mp\_montgomery\_calc\_normalization} +\begin{alltt} +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); +\end{alltt} +Which calculates $a = R$ for the odd moduli $b$ without using multiplication or division. + +The normal modus operandi for Montgomery reductions is to normalize the integers before entering the system. For +example, to calculate $a^3 \mbox { mod }b$ using Montgomery reduction the value of $a$ can be normalized by +multiplying it by $R$. Consider the following code snippet. + +\begin{alltt} +int main(void) +\{ + mp_int a, b, c, R; + mp_digit mp; + int result; + + /* initialize a,b to desired values, + * mp_init R, c and set c to 1.... + */ + + /* get normalization */ + if ((result = mp_montgomery_calc_normalization(&R, b)) != MP_OKAY) \{ + printf("Error getting norm. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* get mp value */ + if ((result = mp_montgomery_setup(&c, &mp)) != MP_OKAY) \{ + printf("Error setting up montgomery. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* normalize `a' so now a is equal to aR */ + if ((result = mp_mulmod(&a, &R, &b, &a)) != MP_OKAY) \{ + printf("Error computing aR. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* square a to get c = a^2R^2 */ + if ((result = mp_sqr(&a, &c)) != MP_OKAY) \{ + printf("Error squaring. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' back down to c = a^2R^2 * R^-1 == a^2R */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* multiply a to get c = a^3R^2 */ + if ((result = mp_mul(&a, &c, &c)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' back down to c = a^3R^2 * R^-1 == a^3R */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce (again) `c' back down to c = a^3R * R^-1 == a^3 */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* c now equals a^3 mod b */ + + return EXIT_SUCCESS; +\} +\end{alltt} + +This particular example does not look too efficient but it demonstrates the point of the algorithm. By +normalizing the inputs the reduced results are always of the form $aR$ for some variable $a$. This allows +a single final reduction to correct for the normalization and the fast reduction used within the algorithm. + +For more details consider examining the file \textit{bn\_mp\_exptmod\_fast.c}. + +\section{Restricted Diminished Radix} + +``Diminished Radix'' reduction refers to reduction with respect to moduli that are amenable to simple +digit shifting and small multiplications. In this case the ``restricted'' variant refers to moduli of the +form $\beta^k - p$ for some $k \ge 0$ and $0 < p < \beta$ where $\beta$ is the radix (default to $2^{28}$). + +As in the case of Montgomery reduction there is a pre--computation phase required for a given modulus. + +\index{mp\_dr\_setup} +\begin{alltt} +void mp_dr_setup(mp_int *a, mp_digit *d); +\end{alltt} + +This computes the value required for the modulus $a$ and stores it in $d$. This function cannot fail +and does not return any error codes. After the pre--computation a reduction can be performed with the +following. + +\index{mp\_dr\_reduce} +\begin{alltt} +int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); +\end{alltt} + +This reduces $a$ in place modulo $b$ with the pre--computed value $mp$. $b$ must be of a restricted +diminished radix form and $a$ must be in the range $0 \le a < b^2$. Diminished radix reductions are +much faster than both Barrett and Montgomery reductions as they have a much lower asymptotic running time. + +Since the moduli are restricted this algorithm is not particularly useful for something like Rabin, RSA or +BBS cryptographic purposes. This reduction algorithm is useful for Diffie-Hellman and ECC where fixed +primes are acceptable. + +Note that unlike Montgomery reduction there is no normalization process. The result of this function is +equal to the correct residue. + +\section{Unrestricted Diminished Radix} + +Unrestricted reductions work much like the restricted counterparts except in this case the moduli is of the +form $2^k - p$ for $0 < p < \beta$. In this sense the unrestricted reductions are more flexible as they +can be applied to a wider range of numbers. + +\index{mp\_reduce\_2k\_setup} +\begin{alltt} +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); +\end{alltt} + +This will compute the required $d$ value for the given moduli $a$. + +\index{mp\_reduce\_2k} +\begin{alltt} +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); +\end{alltt} + +This will reduce $a$ in place modulo $n$ with the pre--computed value $d$. From my experience this routine is +slower than mp\_dr\_reduce but faster for most moduli sizes than the Montgomery reduction. + +\section{Combined Modular Reduction} + +Some of the combinations of an arithmetic operations followed by a modular reduction can be done in a faster way. The ones implemented are: + +Addition $d = (a + b) \mod c$ +\index{mp\_addmod} +\begin{alltt} +int mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d); +\end{alltt} + +Subtraction $d = (a - b) \mod c$ +\begin{alltt} +int mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d); +\end{alltt} + +Multiplication $d = (ab) \mod c$ +\begin{alltt} +int mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d); +\end{alltt} + +Squaring $d = (a^2) \mod c$ +\begin{alltt} +int mp_sqrmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d); +\end{alltt} + + + +\chapter{Exponentiation} +\section{Single Digit Exponentiation} +\index{mp\_expt\_d} +\begin{alltt} +int mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +\end{alltt} +This function computes $c = a^b$. + +\section{Modular Exponentiation} +\index{mp\_exptmod} +\begin{alltt} +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +\end{alltt} +This computes $Y \equiv G^X \mbox{ (mod }P\mbox{)}$ using a variable width sliding window algorithm. This function +will automatically detect the fastest modular reduction technique to use during the operation. For negative values of +$X$ the operation is performed as $Y \equiv (G^{-1} \mbox{ mod }P)^{\vert X \vert} \mbox{ (mod }P\mbox{)}$ provided that +$gcd(G, P) = 1$. + +This function is actually a shell around the two internal exponentiation functions. This routine will automatically +detect when Barrett, Montgomery, Restricted and Unrestricted Diminished Radix based exponentiation can be used. Generally +moduli of the a ``restricted diminished radix'' form lead to the fastest modular exponentiations. Followed by Montgomery +and the other two algorithms. + +\section{Modulus a Power of Two} +\index{mp\_mod\_2d} +\begin{alltt} +int mp_mod_2d(const mp_int *a, int b, mp_int *c) +\end{alltt} +It calculates $c = a \mod 2^b$. + +\section{Root Finding} +\index{mp\_n\_root} +\begin{alltt} +int mp_n_root (mp_int * a, mp_digit b, mp_int * c) +\end{alltt} +This computes $c = a^{1/b}$ such that $c^b \le a$ and $(c+1)^b > a$. Will return a positive root only for even roots and return +a root with the sign of the input for odd roots. For example, performing $4^{1/2}$ will return $2$ whereas $(-8)^{1/3}$ +will return $-2$. + +This algorithm uses the ``Newton Approximation'' method and will converge on the correct root fairly quickly. + +The square root $c = a^{1/2}$ (with the same conditions $c^2 \le a$ and $(c+1)^2 > a$) is implemented with a faster algorithm. + +\index{mp\_sqrt} +\begin{alltt} +int mp_sqrt (mp_int * a, mp_digit b, mp_int * c) +\end{alltt} + + +\chapter{Logarithm} +\section{Integer Logarithm} +A logarithm function for positive integer input \texttt{a, base} computing $\floor{\log_bx}$ such that $(\log_b x)^b \le x$. +\index{mp\_ilogb} +\begin{alltt} +int mp_ilogb(mp_int *a, mp_digit base, mp_int *c) +\end{alltt} +\subsection{Example} +\begin{alltt} +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + mp_int x, output; + mp_digit base; + int e; + + if (argc != 3) { + fprintf(stderr,"Usage %s base x\textbackslash{}n", argv[0]); + exit(EXIT_FAILURE); + } + if ((e = mp_init_multi(&x, &output, NULL)) != MP_OKAY) { + fprintf(stderr,"mp_init failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n", + mp_error_to_string(e)); + exit(EXIT_FAILURE); + } + errno = 0; +#ifdef MP_64BIT + base = (mp_digit)strtoull(argv[1], NULL, 10); +#else + base = (mp_digit)strtoul(argv[1], NULL, 10); +#endif + if ((errno == ERANGE) || (base > (base & MP_MASK))) { + fprintf(stderr,"strtoul(l) failed: input out of range\textbackslash{}n"); + exit(EXIT_FAILURE); + } + if ((e = mp_read_radix(&x, argv[2], 10)) != MP_OKAY) { + fprintf(stderr,"mp_read_radix failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n", + mp_error_to_string(e)); + exit(EXIT_FAILURE); + } + if ((e = mp_ilogb(&x, base, &output)) != MP_OKAY) { + fprintf(stderr,"mp_ilogb failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n", + mp_error_to_string(e)); + exit(EXIT_FAILURE); + } + + if ((e = mp_fwrite(&output, 10, stdout)) != MP_OKAY) { + fprintf(stderr,"mp_fwrite failed: \textbackslash{}"%s\textbackslash{}"\textbackslash{}n", + mp_error_to_string(e)); + exit(EXIT_FAILURE); + } + putchar('\textbackslash{}n'); + + mp_clear_multi(&x, &output, NULL); + exit(EXIT_SUCCESS); +} +\end{alltt} + + + +\chapter{Prime Numbers} +\section{Trial Division} +\index{mp\_prime\_is\_divisible} +\begin{alltt} +int mp_prime_is_divisible (mp_int * a, int *result) +\end{alltt} +This will attempt to evenly divide $a$ by a list of primes\footnote{Default is the first 256 primes.} and store the +outcome in ``result''. That is if $result = 0$ then $a$ is not divisible by the primes, otherwise it is. Note that +if the function does not return \textbf{MP\_OKAY} the value in ``result'' should be considered undefined\footnote{Currently +the default is to set it to zero first.}. + +\section{Fermat Test} +\index{mp\_prime\_fermat} +\begin{alltt} +int mp_prime_fermat (mp_int * a, mp_int * b, int *result) +\end{alltt} +Performs a Fermat primality test to the base $b$. That is it computes $b^a \mbox{ mod }a$ and tests whether the value is +equal to $b$ or not. If the values are equal then $a$ is probably prime and $result$ is set to one. Otherwise $result$ +is set to zero. + +\section{Miller-Rabin Test} +\index{mp\_prime\_miller\_rabin} +\begin{alltt} +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +\end{alltt} +Performs a Miller-Rabin test to the base $b$ of $a$. This test is much stronger than the Fermat test and is very hard to +fool (besides with Carmichael numbers). If $a$ passes the test (therefore is probably prime) $result$ is set to one. +Otherwise $result$ is set to zero. + +Note that is suggested that you use the Miller-Rabin test instead of the Fermat test since all of the failures of +Miller-Rabin are a subset of the failures of the Fermat test. + +\subsection{Required Number of Tests} +Generally to ensure a number is very likely to be prime you have to perform the Miller-Rabin with at least a half-dozen +or so unique bases. However, it has been proven that the probability of failure goes down as the size of the input goes up. +This is why a simple function has been provided to help out. + +\index{mp\_prime\_rabin\_miller\_trials} +\begin{alltt} +int mp_prime_rabin_miller_trials(int size) +\end{alltt} +This returns the number of trials required for a low probability of failure for a given ``size'' expressed in bits. This comes in handy specially since larger numbers are slower to test. For example, a 512-bit number would require 18 tests for a probability of $2^{-160}$ whereas a 1024-bit number would only require 12 tests for a probability of $2^{-192}$. The exact values as implemented are listed in table \ref{table:millerrabinrunsimpl}. + +\begin{table}[h] +\begin{center} +\begin{tabular}{c c c} +\textbf{bits} & \textbf{Rounds} & \textbf{Error}\\ + 80 & -1 & Use deterministic algorithm for size <= 80 bits \\ + 81 & 37 & $2^{-96}$ \\ + 96 & 32 & $2^{-96}$ \\ + 128 & 40 & $2^{-112}$ \\ + 160 & 35 & $2^{-112}$ \\ + 256 & 27 & $2^{-128}$ \\ + 384 & 16 & $2^{-128}$ \\ + 512 & 18 & $2^{-160}$ \\ + 768 & 11 & $2^{-160}$ \\ + 896 & 10 & $2^{-160}$ \\ + 1024 & 12 & $2^{-192}$ \\ + 1536 & 8 & $2^{-192}$ \\ + 2048 & 6 & $2^{-192}$ \\ + 3072 & 4 & $2^{-192}$ \\ + 4096 & 5 & $2^{-256}$ \\ + 5120 & 4 & $2^{-256}$ \\ + 6144 & 4 & $2^{-256}$ \\ + 8192 & 3 & $2^{-256}$ \\ + 9216 & 3 & $2^{-256}$ \\ + 10240 & 2 & $2^{-256}$ +\end{tabular} +\caption{ Number of Miller-Rabin rounds as implemented } \label{table:millerrabinrunsimpl} +\end{center} +\end{table} + +You should always still perform a trial division before a Miller-Rabin test though. + +A small table, broke in two for typographical reasons, with the number of rounds of Miller-Rabin tests is shown below. The numbers have been compute with a PARI/GP script listed in appendix \ref{app:numberofmrcomp}. +The first column is the number of bits $b$ in the prime $p = 2^b$, the numbers in the first row represent the +probability that the number that all of the Miller-Rabin tests deemed a pseudoprime is actually a composite. There is a deterministic test for numbers smaller than $2^{80}$. + +\begin{table}[h] +\begin{center} +\begin{tabular}{c c c c c c c} +\textbf{bits} & $\mathbf{2^{-80}}$ & $\mathbf{2^{-96}}$ & $\mathbf{2^{-112}}$ & $\mathbf{2^{-128}}$ & $\mathbf{2^{-160}}$ & $\mathbf{2^{-192}}$ \\ +80 & 31 & 39 & 47 & 55 & 71 & 87 \\ +96 & 29 & 37 & 45 & 53 & 69 & 85 \\ +128 & 24 & 32 & 40 & 48 & 64 & 80 \\ +160 & 19 & 27 & 35 & 43 & 59 & 75 \\ +192 & 15 & 21 & 29 & 37 & 53 & 69 \\ +256 & 10 & 15 & 20 & 27 & 43 & 59 \\ +384 & 7 & 9 & 12 & 16 & 25 & 38 \\ +512 & 5 & 7 & 9 & 12 & 18 & 26 \\ +768 & 4 & 5 & 6 & 8 & 11 & 16 \\ +1024 & 3 & 4 & 5 & 6 & 9 & 12 \\ +1536 & 2 & 3 & 3 & 4 & 6 & 8 \\ +2048 & 2 & 2 & 3 & 3 & 4 & 6 \\ +3072 & 1 & 2 & 2 & 2 & 3 & 4 \\ +4096 & 1 & 1 & 2 & 2 & 2 & 3 \\ +6144 & 1 & 1 & 1 & 1 & 2 & 2 \\ +8192 & 1 & 1 & 1 & 1 & 2 & 2 \\ +12288 & 1 & 1 & 1 & 1 & 1 & 1 \\ +16384 & 1 & 1 & 1 & 1 & 1 & 1 \\ +24576 & 1 & 1 & 1 & 1 & 1 & 1 \\ +32768 & 1 & 1 & 1 & 1 & 1 & 1 +\end{tabular} +\caption{ Number of Miller-Rabin rounds. Part I } \label{table:millerrabinrunsp1} +\end{center} +\end{table} +\newpage +\begin{table}[h] +\begin{center} +\begin{tabular}{c c c c c c c c} +\textbf{bits} &$\mathbf{2^{-224}}$ & $\mathbf{2^{-256}}$ & $\mathbf{2^{-288}}$ & $\mathbf{2^{-320}}$ & $\mathbf{2^{-352}}$ & $\mathbf{2^{-384}}$ & $\mathbf{2^{-416}}$\\ +80 & 103 & 119 & 135 & 151 & 167 & 183 & 199 \\ +96 & 101 & 117 & 133 & 149 & 165 & 181 & 197 \\ +128 & 96 & 112 & 128 & 144 & 160 & 176 & 192 \\ +160 & 91 & 107 & 123 & 139 & 155 & 171 & 187 \\ +192 & 85 & 101 & 117 & 133 & 149 & 165 & 181 \\ +256 & 75 & 91 & 107 & 123 & 139 & 155 & 171 \\ +384 & 54 & 70 & 86 & 102 & 118 & 134 & 150 \\ +512 & 36 & 49 & 65 & 81 & 97 & 113 & 129 \\ +768 & 22 & 29 & 37 & 47 & 58 & 70 & 86 \\ +1024 & 16 & 21 & 26 & 33 & 40 & 48 & 58 \\ +1536 & 10 & 13 & 17 & 21 & 25 & 30 & 35 \\ +2048 & 8 & 10 & 13 & 15 & 18 & 22 & 26 \\ +3072 & 5 & 7 & 8 & 10 & 12 & 14 & 17 \\ +4096 & 4 & 5 & 6 & 8 & 9 & 11 & 12 \\ +6144 & 3 & 4 & 4 & 5 & 6 & 7 & 8 \\ +8192 & 2 & 3 & 3 & 4 & 5 & 6 & 6 \\ +12288 & 2 & 2 & 2 & 3 & 3 & 4 & 4 \\ +16384 & 1 & 2 & 2 & 2 & 3 & 3 & 3 \\ +24576 & 1 & 1 & 2 & 2 & 2 & 2 & 2 \\ +32768 & 1 & 1 & 1 & 1 & 2 & 2 & 2 +\end{tabular} +\caption{ Number of Miller-Rabin rounds. Part II } \label{table:millerrabinrunsp2} +\end{center} +\end{table} + +Determining the probability needed to pick the right column is a bit harder. Fips 186.4, for example has $2^{-80}$ for $512$ bit large numbers, $2^{-112}$ for $1024$ bits, and $2^{128}$ for $1536$ bits. It can be seen in table \ref{table:millerrabinrunsp1} that those combinations follow the diagonal from $(512,2^{-80})$ downwards and to the right to gain a lower probabilty of getting a composite declared a pseudoprime for the same amount of work or less. + +If this version of the library has the strong Lucas-Selfridge and/or the Frobenius-Underwood test implemented only one or two rounds of the Miller-Rabin test with a random base is necesssary for numbers larger than or equal to $1024$ bits. + +This function is meant for RSA. The number of rounds for DSA is $\lceil -log_2(p)/2\rceil$ with $p$ the probability which is just the half of the absolute value of $p$ if given as a power of two. E.g.: with $p = 2^{-128}$, $\lceil -log_2(p)/2\rceil = 64$. + +This function can be used to test a DSA prime directly if these rounds are followed by a Lucas test. + +See also table C.1 in FIPS 186-4. + +\section{Strong Lucas-Selfridge Test} +\index{mp\_prime\_strong\_lucas\_selfridge} +\begin{alltt} +int mp_prime_strong_lucas_selfridge(const mp_int *a, int *result) +\end{alltt} +Performs a strong Lucas-Selfridge test. The strong Lucas-Selfridge test together with the Rabin-Miler test with bases $2$ and $3$ resemble the BPSW test. The single internal use is a compile-time option in \texttt{mp\_prime\_is\_prime} and can be excluded +from the Libtommath build if not needed. + +\section{Frobenius (Underwood) Test} +\index{mp\_prime\_frobenius\_underwood} +\begin{alltt} +int mp_prime_frobenius_underwood(const mp_int *N, int *result) +\end{alltt} +Performs the variant of the Frobenius test as described by Paul Underwood. The single internal use is in +\texttt{mp\_prime\_is\_prime} for \texttt{MP\_8BIT} only but can be included at build-time for all other sizes +if the preprocessor macro \texttt{LTM\_USE\_FROBENIUS\_TEST} is defined. + +It returns \texttt{MP\_ITER} if the number of iterations is exhausted, assumes a composite as the input and sets \texttt{result} accordingly. This will reduce the set of available pseudoprimes by a very small amount: test with large datasets (more than $10^{10}$ numbers, both randomly chosen and sequences of odd numbers with a random start point) found only 31 (thirty-one) numbers with $a > 120$ and none at all with just an additional simple check for divisors $d < 2^8$. + +\section{Primality Testing} +Testing if a number is a square can be done a bit faster than just by calculating the square root. It is used by the primality testing function described below. +\index{mp\_is\_square} +\begin{alltt} +int mp_is_square(const mp_int *arg, int *ret); +\end{alltt} + + +\index{mp\_prime\_is\_prime} +\begin{alltt} +int mp_prime_is_prime (mp_int * a, int t, int *result) +\end{alltt} +This will perform a trial division followed by two rounds of Miller-Rabin with bases 2 and 3 and a Lucas-Selfridge test. The Lucas-Selfridge test is replaced with a Frobenius-Underwood for \texttt{MP\_8BIT}. The Frobenius-Underwood test for all other sizes is available as a compile-time option with the preprocessor macro \texttt{LTM\_USE\_FROBENIUS\_TEST}. See file +\texttt{bn\_mp\_prime\_is\_prime.c} for the necessary details. It shall be noted that both functions are much slower than +the Miller-Rabin test and if speed is an essential issue, the macro \texttt{LTM\_USE\_ONLY\_MR} switches both functions, the Frobenius-Underwood test and the Lucas-Selfridge test off and their code will not even be compiled into the library. + +If $t$ is set to a positive value $t$ additional rounds of the Miller-Rabin test with random bases will be performed to allow for Fips 186.4 (vid.~p.~126ff) compliance. The function \texttt{mp\_prime\_rabin\_miller\_trials} can be used to determine the number of rounds. It is vital that the function \texttt{mp\_rand()} has a cryptographically strong random number generator available. + +One Miller-Rabin tests with a random base will be run automatically, so by setting $t$ to a positive value this function will run $t + 1$ Miller-Rabin tests with random bases. + +If $t$ is set to a negative value the test will run the deterministic Miller-Rabin test for the primes up to $3317044064679887385961981$. That limit has to be checked by the caller. + +If $a$ passes all of the tests $result$ is set to one, otherwise it is set to zero. + +\section{Next Prime} +\index{mp\_prime\_next\_prime} +\begin{alltt} +int mp_prime_next_prime(mp_int *a, int t, int bbs_style) +\end{alltt} +This finds the next prime after $a$ that passes mp\_prime\_is\_prime() with $t$ tests but see the documentation for +mp\_prime\_is\_prime for details regarding the use of the argument $t$. Set $bbs\_style$ to one if you +want only the next prime congruent to $3 \mbox{ mod } 4$, otherwise set it to zero to find any next prime. + +\section{Random Primes} +\index{mp\_prime\_rand} +\begin{alltt} +int mp_prime_rand(mp_int *a, int t, + int size, int flags); +\end{alltt} +This will generate a prime in $a$ using $t$ tests of the primality testing algorithms. +See the documentation for mp\_prime\_is\_prime for details regarding the use of the argument $t$. +The variable $size$ specifies the bit length of the prime desired. +The variable $flags$ specifies one of several options available +(see fig. \ref{fig:primeopts}) which can be OR'ed together. + +The function mp\_prime\_rand() is suitable for generating primes which must be secret (as in the case of RSA) since there +is no skew on the least significant bits. + +\textit{Note:} This function replaces the deprecated mp\_prime\_random and mp\_prime\_random\_ex functions. + +\begin{figure}[h] +\begin{center} +\begin{small} +\begin{tabular}{|r|l|} +\hline \textbf{Flag} & \textbf{Meaning} \\ +\hline LTM\_PRIME\_BBS & Make the prime congruent to $3$ modulo $4$ \\ +\hline LTM\_PRIME\_SAFE & Make a prime $p$ such that $(p - 1)/2$ is also prime. \\ + & This option implies LTM\_PRIME\_BBS as well. \\ +\hline LTM\_PRIME\_2MSB\_OFF & Makes sure that the bit adjacent to the most significant bit \\ + & Is forced to zero. \\ +\hline LTM\_PRIME\_2MSB\_ON & Makes sure that the bit adjacent to the most significant bit \\ + & Is forced to one. \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Primality Generation Options} +\label{fig:primeopts} +\end{figure} + +\chapter{Random Number Generation} +\section{PRNG} +\index{mp\_rand\_digit} +\begin{alltt} +int mp_rand_digit(mp_digit *r) +\end{alltt} +This function generates a random number in \texttt{r} of the size given in \texttt{r} (that is, the variable is used for in- and output) but not more than \texttt{MP\_MASK} bits. + +\index{mp\_rand} +\begin{alltt} +int mp_rand(mp_int *a, int digits) +\end{alltt} +This function generates a random number of \texttt{digits} bits. + +The random number generated with these two functions is cryptographically secure if the source of random numbers the operating systems offers is cryptographically secure. It will use \texttt{arc4random()} if the OS is a BSD flavor, Wincrypt on Windows, or \texttt{/dev/urandom} on all operating systems that have it. + + +\chapter{Input and Output} +\section{ASCII Conversions} +\subsection{To ASCII} +\index{mp\_to\_radix} +\begin{alltt} +int mp_to_radix (mp_int *a, char *str, size_t maxlen, size_t *written, int radix); +\end{alltt} +This stores $a$ in \texttt{str} of maximum length \texttt{maxlen} as a base-\texttt{radix} string of ASCII chars and appends a \texttt{NUL} character to terminate the string. + +Valid values of \texttt{radix} line in the range $[2, 64]$. + +The exact number of characters in \texttt{str} plus the \texttt{NUL} will be put in \texttt{written} if that variable is not set to \texttt{NULL}. + +If \texttt{str} is not big enough to hold $a$, \texttt{str} will be filled with the least-significant digits +of length \texttt{maxlen-1}, then \texttt{str} will be \texttt{NUL} terminated and the error \texttt{MP\_VAL} is returned. + +Please be aware that this function cannot evaluate the actual size of the buffer, it relies on the correctness of \texttt{maxlen}! + + +\index{mp\_radix\_size} +\begin{alltt} +int mp_radix_size (mp_int * a, int radix, int *size) +\end{alltt} +This stores in ``size'' the number of characters (including space for the NUL terminator) required. Upon error this +function returns an error code and ``size'' will be zero. + +If \texttt{LTM\_NO\_FILE} is not defined a function to write to a file is also available. +\index{mp\_fwrite} +\begin{alltt} +int mp_fwrite(const mp_int *a, int radix, FILE *stream); +\end{alltt} + + +\subsection{From ASCII} +\index{mp\_read\_radix} +\begin{alltt} +int mp_read_radix (mp_int * a, char *str, int radix); +\end{alltt} +This will read the base-``radix'' NUL terminated string from ``str'' into $a$. It will stop reading when it reads a +character it does not recognize (which happens to include th NUL char... imagine that...). A single leading $-$ sign +can be used to denote a negative number. + +If \texttt{LTM\_NO\_FILE} is not defined a function to read from a file is also available. +\index{mp\_fread} +\begin{alltt} +int mp_fread(mp_int *a, int radix, FILE *stream); +\end{alltt} + + +\section{Binary Conversions} + +Converting an mp\_int to and from binary is another keen idea. + +\index{mp\_ubin\_size} +\begin{alltt} +size_t mp_ubin_size(mp_int *a); +\end{alltt} + +This will return the number of bytes (octets) required to store the unsigned copy of the integer $a$. + +\index{mp\_to\_ubin} +\begin{alltt} +int mp_to_unsigned_bin(mp_int *a, unsigned char *b, size_t maxlen, size_t *len); +\end{alltt} +This will store $a$ into the buffer $b$ of size \texttt{maxlen} in big--endian format storing the number of bytes written in \texttt{len}. Fortunately this is exactly what DER (or is it ASN?) requires. It does not store the sign of the integer. + +\index{mp\_from\_ubin} +\begin{alltt} +int mp_from_ubin(mp_int *a, unsigned char *b, size_t size); +\end{alltt} +This will read in an unsigned big--endian array of bytes (octets) from $b$ of length \texttt{size} into $a$. The resulting big-integer $a$ will always be positive. + +For those who acknowledge the existence of negative numbers (heretic!) there are ``signed'' versions of the +previous functions. +\index{mp\_signed\_bin\_size} \index{mp\_to\_signed\_bin} \index{mp\_read\_signed\_bin} +\begin{alltt} +int mp_sbin_size(mp_int *a); +int mp_from_sbin(mp_int *a, unsigned char *b, size_t size); +int mp_to_sbin(mp_int *a, unsigned char *b, size_t maxsize, size_t *len); +\end{alltt} +They operate essentially the same as the unsigned copies except they prefix the data with zero or non--zero +byte depending on the sign. If the sign is zpos (e.g. not negative) the prefix is zero, otherwise the prefix +is non--zero. + +The two functions \texttt{mp\_unpack} (get your gifts out of the box, import binary data) and \texttt{mp\_pack} (put your gifts into the box, export binary data) implement the similarly working GMP functions as described at \url{http://gmplib.org/manual/Integer-Import-and-Export.html} with the exception that \texttt{mp\_pack} will not allocate memory if \texttt{rop} is \texttt{NULL}. +\index{mp\_unpack} \index{mp\_pack} +\begin{alltt} +int mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, + mp_endian endian, size_t nails, const void *op, size_t maxsize); +int mp_pack(void *rop, size_t *countp, mp_order order, size_t size, + mp_endian endian, size_t nails, const mp_int *op); +\end{alltt} +The function \texttt{mp\_pack} has the additional variable \texttt{maxsize} which must hold the size of the buffer \texttt{rop} in bytes. Use +\begin{alltt} +/* Parameters "nails" and "size" are the same as in mp_pack */ +size_t mp_pack_size(mp_int *a, size_t nails, size_t size); +\end{alltt} +To get the size in bytes necessary to be put in \texttt{maxsize}). + +To enhance the readability of your code, the following enums have been wrought for your convenience. +\begin{alltt} +typedef enum { + MP_LSB_FIRST = -1, + MP_MSB_FIRST = 1 +} mp_order; +typedef enum { + MP_LITTLE_ENDIAN = -1, + MP_NATIVE_ENDIAN = 0, + MP_BIG_ENDIAN = 1 +} mp_endian; +\end{alltt} + +\chapter{Algebraic Functions} +\section{Extended Euclidean Algorithm} +\index{mp\_exteuclid} +\begin{alltt} +int mp_exteuclid(mp_int *a, mp_int *b, + mp_int *U1, mp_int *U2, mp_int *U3); +\end{alltt} + +This finds the triple U1/U2/U3 using the Extended Euclidean algorithm such that the following equation holds. + +\begin{equation} +a \cdot U1 + b \cdot U2 = U3 +\end{equation} + +Any of the U1/U2/U3 parameters can be set to \textbf{NULL} if they are not desired. + +\section{Greatest Common Divisor} +\index{mp\_gcd} +\begin{alltt} +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +This will compute the greatest common divisor of $a$ and $b$ and store it in $c$. + +\section{Least Common Multiple} +\index{mp\_lcm} +\begin{alltt} +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +This will compute the least common multiple of $a$ and $b$ and store it in $c$. + +\section{Jacobi Symbol} +\index{mp\_jacobi} +\begin{alltt} +int mp_jacobi (mp_int * a, mp_int * p, int *c) +\end{alltt} +This will compute the Jacobi symbol for $a$ with respect to $p$. If $p$ is prime this essentially computes the Legendre +symbol. The result is stored in $c$ and can take on one of three values $\lbrace -1, 0, 1 \rbrace$. If $p$ is prime +then the result will be $-1$ when $a$ is not a quadratic residue modulo $p$. The result will be $0$ if $a$ divides $p$ +and the result will be $1$ if $a$ is a quadratic residue modulo $p$. + +\section{Kronecker Symbol} +\index{mp\_kronecker} +\begin{alltt} +int mp_kronecker (mp_int * a, mp_int * p, int *c) +\end{alltt} +Extension of the Jacoby symbol to all $\lbrace a, p \rbrace \in \mathbb{Z}$ . + + +\section{Modular square root} +\index{mp\_sqrtmod\_prime} +\begin{alltt} +int mp_sqrtmod_prime(mp_int *n, mp_int *p, mp_int *r) +\end{alltt} + +This will solve the modular equatioon $r^2 = n \mod p$ where $p$ is a prime number greater than 2 (odd prime). +The result is returned in the third argument $r$, the function returns \textbf{MP\_OKAY} on success, +other return values indicate failure. + +The implementation is split for two different cases: + +1. if $p \mod 4 == 3$ we apply \href{http://cacr.uwaterloo.ca/hac/}{Handbook of Applied Cryptography algorithm 3.36} and compute $r$ directly as +$r = n^{(p+1)/4} \mod p$ + +2. otherwise we use \href{https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm}{Tonelli-Shanks algorithm} + +The function does not check the primality of parameter $p$ thus it is up to the caller to assure that this parameter +is a prime number. When $p$ is a composite the function behaviour is undefined, it may even return a false-positive +\textbf{MP\_OKAY}. + +\section{Modular Inverse} +\index{mp\_invmod} +\begin{alltt} +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +Computes the multiplicative inverse of $a$ modulo $b$ and stores the result in $c$ such that $ac \equiv 1 \mbox{ (mod }b\mbox{)}$. + +\section{Single Digit Functions} + +For those using small numbers (\textit{snicker snicker}) there are several ``helper'' functions + +\index{mp\_add\_d} \index{mp\_sub\_d} \index{mp\_mul\_d} \index{mp\_div\_d} \index{mp\_mod\_d} +\begin{alltt} +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); +int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); +int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); +int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); +\end{alltt} + +These work like the full mp\_int capable variants except the second parameter $b$ is a mp\_digit. These +functions fairly handy if you have to work with relatively small numbers since you will not have to allocate +an entire mp\_int to store a number like $1$ or $2$. + +The functions \texttt{mp\_incr} and \texttt{mp\_decr} mimic the postfix operators \texttt{++} and \texttt{--} respectively, to increment the input by one. They call the full single-digit functions if the addition would carry. Both functions need to be included in a minimized library because they call each other in case of a negative input, These functions change the inputs! +\begin{alltt} +int mp_incr(mp_int *a); +int mp_decr(mp_int *a); +\end{alltt} + + +The division by three can be made faster by replacing the division with a multiplication by the multiplicative inverse of three. + +\index{mp\_div\_3} +\begin{alltt} +int mp_div_3(const mp_int *a, mp_int *c, mp_digit *d); +\end{alltt} + +\chapter{Little Helpers} +It is never wrong to have some useful little shortcuts at hand. +\section{Function Macros} +To make this overview simpler the macros are given as function prototypes. The return of logic macros is \texttt{MP\_NO} or \texttt{MP\_YES} respectively. + +\index{mp\_iseven} +\begin{alltt} +int mp_iseven(mp_int *a) +\end{alltt} +Checks if $a = 0 mod 2$ + +\index{mp\_isodd} +\begin{alltt} +int mp_isodd(mp_int *a) +\end{alltt} +Checks if $a = 1 mod 2$ + +\index{mp\_isneg} +\begin{alltt} +int mp_isneg(mp_int *a) +\end{alltt} +Checks if $a < 0$ + + +\index{mp\_iszero} +\begin{alltt} +int mp_iszero(mp_int *a) +\end{alltt} +Checks if $a = 0$. It does not check if the amount of memory allocated for $a$ is also minimal. + + +Other macros which are either shortcuts to normal functions or just other names for them do have their place in a programmer's life, too! + +\subsection{Renamings} +\index{mp\_mag\_size} +\begin{alltt} +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +\end{alltt} + + +\index{mp\_raw\_size} +\begin{alltt} +#define mp_raw_size(mp) mp_signed_bin_size(mp) +\end{alltt} + + +\index{mp\_read\_mag} +\begin{alltt} +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +\end{alltt} + + +\index{mp\_read\_raw} +\begin{alltt} + #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +\end{alltt} + + +\index{mp\_tomag} +\begin{alltt} +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) +\end{alltt} + + +\index{mp\_toraw} +\begin{alltt} +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +\end{alltt} + + + +\subsection{Shortcuts} + +\index{mp\_to\_binary} +\begin{alltt} +#define mp_to_binary(M, S, N) mp_to_radix((M), (S), (N), 2) +\end{alltt} + + +\index{mp\_to\_octal} +\begin{alltt} +#define mp_to_octal(M, S, N) mp_to_radix((M), (S), (N), 8) +\end{alltt} + + +\index{mp\_to\_decimal} +\begin{alltt} +#define mp_to_decimal(M, S, N) mp_to_radix((M), (S), (N), 10) +\end{alltt} + + +\index{mp\_to\_hex} +\begin{alltt} +#define mp_to_hex(M, S, N) mp_to_radix((M), (S), (N), 16) +\end{alltt} + +\begin{appendices} +\appendixpage +%\noappendicestocpagenum +\addappheadtotoc +\chapter{Computing Number of Miller-Rabin Trials}\label{app:numberofmrcomp} +The number of Miller-Rabin rounds in the tables \ref{millerrabinrunsimpl}, \ref{millerrabinrunsp1}, and \ref{millerrabinrunsp2} have been calculated with the formula in FIPS 186-4 appendix F.1 (page 117) implemented as a PARI/GP script. +\begin{alltt} +log2(x) = log(x)/log(2) + +fips_f1_sums(k, M, t) = { + local(s = 0); + s = sum(m=3,M, + 2^(m-t*(m-1)) * + sum(j=2,m, + 1/ ( 2^( j + (k-1)/j ) ) + ) + ); + return(s); +} + +fips_f1_2(k, t, M) = { + local(common_factor, t1, t2, f1, f2, ds, res); + + common_factor = 2.00743 * log(2) * k * 2^(-k); + t1 = 2^(k - 2 - M*t); + f1 = (8 * ((Pi^2) - 6))/3; + f2 = 2^(k - 2); + ds = t1 + f1 * f2 * fips_f1_sums(k, M, t); + res = common_factor * ds; + return(res); +} + +fips_f1_1(prime_length, ptarget)={ + local(t, t_end, M, M_end, pkt); + + t_end = ceil(-log2(ptarget)/2); + M_end = floor(2 * sqrt(prime_length-1) - 1); + + for(t = 1, t_end, + for(M = 3, M_end, + pkt = fips_f1_2(prime_length, t, M); + if(pkt <= ptarget, + return(t); + ); + ); + ); +} +\end{alltt} + +To get the number of rounds for a $1024$ bit large prime with a probability of $2^{-160}$: +\begin{alltt} +? fips_f1_1(1024,2^(-160)) +%1 = 9 +\end{alltt} +\end{appendices} +\input{bn.ind} + +\end{document} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.1 b/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.1 new file mode 100644 index 0000000..c41ded1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.1 @@ -0,0 +1,2 @@ +256-bits (k = 36113) = 115792089237316195423570985008687907853269984665640564039457584007913129603823 +512-bits (k = 38117) = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006045979 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.c new file mode 100644 index 0000000..95ed2de --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/2kprime.c @@ -0,0 +1,81 @@ +/* Makes safe primes of a 2k nature */ +#include +#include + +static int sizes[] = {256, 512, 768, 1024, 1536, 2048, 3072, 4096}; + +int main(void) +{ + char buf[2000]; + size_t x; + mp_bool y; + mp_int q, p; + FILE *out; + clock_t t1; + mp_digit z; + + mp_init_multi(&q, &p, NULL); + + out = fopen("2kprime.1", "w"); + if (out != NULL) { + for (x = 0; x < (sizeof(sizes) / sizeof(sizes[0])); x++) { +top: + mp_2expt(&q, sizes[x]); + mp_add_d(&q, 3uL, &q); + z = -3; + + t1 = clock(); + for (;;) { + mp_sub_d(&q, 4uL, &q); + z += 4uL; + + if (z > MP_MASK) { + printf("No primes of size %d found\n", sizes[x]); + break; + } + + if ((clock() - t1) > CLOCKS_PER_SEC) { + printf("."); + fflush(stdout); + /* sleep((clock() - t1 + CLOCKS_PER_SEC/2)/CLOCKS_PER_SEC); */ + t1 = clock(); + } + + /* quick test on q */ + mp_prime_is_prime(&q, 1, &y); + if (y == MP_NO) { + continue; + } + + /* find (q-1)/2 */ + mp_sub_d(&q, 1uL, &p); + mp_div_2(&p, &p); + mp_prime_is_prime(&p, 3, &y); + if (y == MP_NO) { + continue; + } + + /* test on q */ + mp_prime_is_prime(&q, 3, &y); + if (y == MP_NO) { + continue; + } + + break; + } + + if (y == MP_NO) { + ++sizes[x]; + goto top; + } + + mp_to_decimal(&q, buf, sizeof(buf)); + printf("\n\n%d-bits (k = %lu) = %s\n", sizes[x], z, buf); + fprintf(out, "%d-bits (k = %lu) = %s\n", sizes[x], z, buf); + fflush(out); + } + fclose(out); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/drprime.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprime.c new file mode 100644 index 0000000..64e31ef --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprime.c @@ -0,0 +1,67 @@ +/* Makes safe primes of a DR nature */ +#include + +static int sizes[] = { 1+256/MP_DIGIT_BIT, 1+512/MP_DIGIT_BIT, 1+768/MP_DIGIT_BIT, 1+1024/MP_DIGIT_BIT, 1+2048/MP_DIGIT_BIT, 1+4096/MP_DIGIT_BIT }; + +int main(void) +{ + mp_bool res; + int x, y; + char buf[4096]; + FILE *out; + mp_int a, b; + + mp_init(&a); + mp_init(&b); + + out = fopen("drprimes.txt", "w"); + if (out != NULL) { + for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { +top: + printf("Seeking a %d-bit safe prime\n", sizes[x] * MP_DIGIT_BIT); + mp_grow(&a, sizes[x]); + mp_zero(&a); + for (y = 1; y < sizes[x]; y++) { + a.dp[y] = MP_MASK; + } + + /* make a DR modulus */ + a.dp[0] = -1; + a.used = sizes[x]; + + /* now loop */ + res = MP_NO; + for (;;) { + a.dp[0] += 4uL; + if (a.dp[0] >= MP_MASK) break; + mp_prime_is_prime(&a, 1, &res); + if (res == MP_NO) continue; + printf("."); + fflush(stdout); + mp_sub_d(&a, 1uL, &b); + mp_div_2(&b, &b); + mp_prime_is_prime(&b, 3, &res); + if (res == MP_NO) continue; + mp_prime_is_prime(&a, 3, &res); + if (res == MP_YES) break; + } + + if (res != MP_YES) { + printf("Error not DR modulus\n"); + sizes[x] += 1; + goto top; + } else { + mp_to_decimal(&a, buf, sizeof(buf)); + printf("\n\np == %s\n\n", buf); + fprintf(out, "%d-bit prime:\np == %s\n\n", mp_count_bits(&a), buf); + fflush(out); + } + } + fclose(out); + } + + mp_clear(&a); + mp_clear(&b); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.28 b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.28 new file mode 100644 index 0000000..9d438ad --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.28 @@ -0,0 +1,25 @@ +DR safe primes for 28-bit digits. + +224-bit prime: +p == 26959946667150639794667015087019630673637144422540572481103341844143 + +532-bit prime: +p == 14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368691747 + +784-bit prime: +p == 101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039 + +1036-bit prime: +p == 736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821798437127 + +1540-bit prime: +p == 38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783 + +2072-bit prime: +p == 542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147 + +3080-bit prime: +p == 1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503 + +4116-bit prime: +p == 1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.txt b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.txt new file mode 100644 index 0000000..7c97f67 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/drprimes.txt @@ -0,0 +1,9 @@ +300-bit prime: +p == 2037035976334486086268445688409378161051468393665936250636140449354381298610415201576637819 + +540-bit prime: +p == 3599131035634557106248430806148785487095757694641533306480604458089470064537190296255232548883112685719936728506816716098566612844395439751206810991770626477344739 + +780-bit prime: +p == 6359114106063703798370219984742410466332205126109989319225557147754704702203399726411277962562135973685197744935448875852478791860694279747355800678568677946181447581781401213133886609947027230004277244697462656003655947791725966271167 + diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile new file mode 100644 index 0000000..85bb09e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile @@ -0,0 +1,44 @@ +LTM_CFLAGS += -Wall -W -Wextra -Wshadow -O3 -I../ +LTM_CFLAGS += $(CFLAGS) + +# default lib name (requires install with root) +# LIBNAME=-ltommath + +# libname when you can't install the lib with install +LIBNAME=../libtommath.a + +#provable primes +pprime: pprime.o + $(CC) $(LTM_CFLAGS) pprime.o $(LIBNAME) -o pprime + +# portable [well requires clock()] tuning app +tune: tune.o + $(CC) $(LTM_CFLAGS) tune.o $(LIBNAME) -o tune + ./tune_it.sh + +test_standalone: tune.o + # The benchmark program works as a testtool, too + $(CC) $(LTM_CFLAGS) tune.o $(LIBNAME) -o test + +# spits out mersenne primes +mersenne: mersenne.o + $(CC) $(LTM_CFLAGS) mersenne.o $(LIBNAME) -o mersenne + +# finds DR safe primes for the given config +drprime: drprime.o + $(CC) $(LTM_CFLAGS) drprime.o $(LIBNAME) -o drprime + +# finds 2k safe primes for the given config +2kprime: 2kprime.o + $(CC) $(LTM_CFLAGS) 2kprime.o $(LIBNAME) -o 2kprime + +mont: mont.o + $(CC) $(LTM_CFLAGS) mont.o $(LIBNAME) -o mont + + +clean: + rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime mont 2kprime pprime.dat \ + tuning_list multiplying squaring test *.da *.dyn *.dpi *~ + rm -rf .libs + +.PHONY: tune diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.icc b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.icc new file mode 100644 index 0000000..9217f7b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.icc @@ -0,0 +1,67 @@ +CC = icc + +CFLAGS += -I../ + +# optimize for SPEED +# +# -mcpu= can be pentium, pentiumpro (covers PII through PIII) or pentium4 +# -ax? specifies make code specifically for ? but compatible with IA-32 +# -x? specifies compile solely for ? [not specifically IA-32 compatible] +# +# where ? is +# K - PIII +# W - first P4 [Williamette] +# N - P4 Northwood +# P - P4 Prescott +# B - Blend of P4 and PM [mobile] +# +# Default to just generic max opts +CFLAGS += -O3 -xP -ip + +# default lib name (requires install with root) +# LIBNAME=-ltommath + +# libname when you can't install the lib with install +LIBNAME=../libtommath.a + +#provable primes +pprime: pprime.o + $(CC) pprime.o $(LIBNAME) -o pprime + +tune: tune.o + $(CC) $(CFLAGS) tune.o $(LIBNAME) -o tune + ./tune_it.sh + +# same app but using RDTSC for higher precision [requires 80586+], coff based gcc installs [e.g. ming, cygwin, djgpp] +tune86: tune.c + nasm -f coff timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +# for cygwin +tune86c: tune.c + nasm -f gnuwin32 timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +#make tune86 for linux or any ELF format +tune86l: tune.c + nasm -f elf -DUSE_ELF timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86l + +# spits out mersenne primes +mersenne: mersenne.o + $(CC) mersenne.o $(LIBNAME) -o mersenne + +# fines DR safe primes for the given config +drprime: drprime.o + $(CC) drprime.o $(LIBNAME) -o drprime + +# fines 2k safe primes for the given config +2kprime: 2kprime.o + $(CC) 2kprime.o $(LIBNAME) -o 2kprime + +mont: mont.o + $(CC) mont.o $(LIBNAME) -o mont + + +clean: + rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime tune86 tune86l mont 2kprime pprime.dat *.il tuning_list diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.msvc b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.msvc new file mode 100644 index 0000000..592a437 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/makefile.msvc @@ -0,0 +1,24 @@ +#MSVC Makefile +# +#Tom St Denis + +CFLAGS = /I../ /Ox /DWIN32 /W3 + +pprime: pprime.obj + cl pprime.obj ../tommath.lib + +mersenne: mersenne.obj + cl mersenne.obj ../tommath.lib + +tune: tune.obj + cl tune.obj ../tommath.lib + + +mont: mont.obj + cl mont.obj ../tommath.lib + +drprime: drprime.obj + cl drprime.obj ../tommath.lib + +2kprime: 2kprime.obj + cl 2kprime.obj ../tommath.lib diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/mersenne.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/mersenne.c new file mode 100644 index 0000000..0c9f52f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/mersenne.c @@ -0,0 +1,138 @@ +/* Finds Mersenne primes using the Lucas-Lehmer test + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include +#include + +static mp_err is_mersenne(long s, mp_bool *pp) +{ + mp_int n, u; + mp_err res; + int k; + + *pp = MP_NO; + + if ((res = mp_init(&n)) != MP_OKAY) { + return res; + } + + if ((res = mp_init(&u)) != MP_OKAY) { + goto LBL_N; + } + + /* n = 2^s - 1 */ + if ((res = mp_2expt(&n, (int)s)) != MP_OKAY) { + goto LBL_MU; + } + if ((res = mp_sub_d(&n, 1uL, &n)) != MP_OKAY) { + goto LBL_MU; + } + + /* set u=4 */ + mp_set(&u, 4uL); + + /* for k=1 to s-2 do */ + for (k = 1; k <= (s - 2); k++) { + /* u = u^2 - 2 mod n */ + if ((res = mp_sqr(&u, &u)) != MP_OKAY) { + goto LBL_MU; + } + if ((res = mp_sub_d(&u, 2uL, &u)) != MP_OKAY) { + goto LBL_MU; + } + + /* make sure u is positive */ + while (u.sign == MP_NEG) { + if ((res = mp_add(&u, &n, &u)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* reduce */ + if ((res = mp_reduce_2k(&u, &n, 1uL)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* if u == 0 then its prime */ + if (mp_iszero(&u) == MP_YES) { + mp_prime_is_prime(&n, 8, pp); + if (*pp != MP_YES) printf("FAILURE\n"); + } + + res = MP_OKAY; +LBL_MU: + mp_clear(&u); +LBL_N: + mp_clear(&n); + return res; +} + +/* square root of a long < 65536 */ +static long i_sqrt(long x) +{ + long x1, x2; + + x2 = 16; + do { + x1 = x2; + x2 = x1 - ((x1 * x1) - x) / (2 * x1); + } while (x1 != x2); + + if ((x1 * x1) > x) { + --x1; + } + + return x1; +} + +/* is the long prime by brute force */ +static int isprime(long k) +{ + long y, z; + + y = i_sqrt(k); + for (z = 2; z <= y; z++) { + if ((k % z) == 0) + return 0; + } + return 1; +} + + +int main(void) +{ + mp_bool pp; + long k; + clock_t tt; + + k = 3; + + for (;;) { + /* start time */ + tt = clock(); + + /* test if 2^k - 1 is prime */ + if (is_mersenne(k, &pp) != MP_OKAY) { + printf("Whoa error\n"); + return -1; + } + + if (pp == MP_YES) { + /* count time */ + tt = clock() - tt; + + /* display if prime */ + printf("2^%-5ld - 1 is prime, test took %ld ticks\n", k, (long)tt); + } + + /* goto next odd exponent */ + k += 2; + + /* but make sure its prime */ + while (isprime(k) == 0) { + k += 2; + } + } +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/mont.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/mont.c new file mode 100644 index 0000000..4652410 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/mont.c @@ -0,0 +1,44 @@ +/* tests the montgomery routines */ +#include +#include +#include + +int main(void) +{ + mp_int modulus, R, p, pp; + mp_digit mp; + int x, y; + + srand(time(NULL)); + mp_init_multi(&modulus, &R, &p, &pp, NULL); + + /* loop through various sizes */ + for (x = 4; x < 256; x++) { + printf("DIGITS == %3d...", x); + fflush(stdout); + + /* make up the odd modulus */ + mp_rand(&modulus, x); + modulus.dp[0] |= 1uL; + + /* now find the R value */ + mp_montgomery_calc_normalization(&R, &modulus); + mp_montgomery_setup(&modulus, &mp); + + /* now run through a bunch tests */ + for (y = 0; y < 1000; y++) { + mp_rand(&p, x/2); /* p = random */ + mp_mul(&p, &R, &pp); /* pp = R * p */ + mp_montgomery_reduce(&pp, &modulus, mp); + + /* should be equal to p */ + if (mp_cmp(&pp, &p) != MP_EQ) { + printf("FAILURE!\n"); + exit(-1); + } + } + printf("PASSED\n"); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/pprime.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/pprime.c new file mode 100644 index 0000000..009a18c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/pprime.c @@ -0,0 +1,411 @@ +/* Generates provable primes + * + * See http://gmail.com:8080/papers/pp.pdf for more info. + * + * Tom St Denis, tomstdenis@gmail.com, http://tom.gmail.com + */ +#include +#include +#include "tommath.h" + +static int n_prime; +static FILE *primes; + +/* fast square root */ +static mp_digit i_sqrt(mp_word x) +{ + mp_word x1, x2; + + x2 = x; + do { + x1 = x2; + x2 = x1 - ((x1 * x1) - x) / (2u * x1); + } while (x1 != x2); + + if ((x1 * x1) > x) { + --x1; + } + + return x1; +} + + +/* generates a prime digit */ +static void gen_prime(void) +{ + mp_digit r, x, y, next; + FILE *out; + + out = fopen("pprime.dat", "wb"); + if (out != NULL) { + + /* write first set of primes */ + /* *INDENT-OFF* */ + r = 3uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 5uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 7uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 11uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 13uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 17uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 19uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 23uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 29uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + r = 31uL; fwrite(&r, 1uL, sizeof(mp_digit), out); + /* *INDENT-ON* */ + + /* get square root, since if 'r' is composite its factors must be < than this */ + y = i_sqrt(r); + next = (y + 1uL) * (y + 1uL); + + for (;;) { + do { + r += 2uL; /* next candidate */ + r &= MP_MASK; + if (r < 31uL) break; + + /* update sqrt ? */ + if (next <= r) { + ++y; + next = (y + 1uL) * (y + 1uL); + } + + /* loop if divisible by 3,5,7,11,13,17,19,23,29 */ + if ((r % 3uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 5uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 7uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 11uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 13uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 17uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 19uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 23uL) == 0uL) { + x = 0uL; + continue; + } + if ((r % 29uL) == 0uL) { + x = 0uL; + continue; + } + + /* now check if r is divisible by x + k={1,7,11,13,17,19,23,29} */ + for (x = 30uL; x <= y; x += 30uL) { + if ((r % (x + 1uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 7uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 11uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 13uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 17uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 19uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 23uL)) == 0uL) { + x = 0uL; + break; + } + if ((r % (x + 29uL)) == 0uL) { + x = 0uL; + break; + } + } + } while (x == 0uL); + if (r > 31uL) { + fwrite(&r, 1uL, sizeof(mp_digit), out); + printf("%9lu\r", r); + fflush(stdout); + } + if (r < 31uL) break; + } + + fclose(out); + } +} + +static void load_tab(void) +{ + primes = fopen("pprime.dat", "rb"); + if (primes == NULL) { + gen_prime(); + primes = fopen("pprime.dat", "rb"); + } + fseek(primes, 0L, SEEK_END); + n_prime = ftell(primes) / sizeof(mp_digit); +} + +static mp_digit prime_digit(void) +{ + int n; + mp_digit d; + + n = abs(rand()) % n_prime; + fseek(primes, n * sizeof(mp_digit), SEEK_SET); + fread(&d, 1uL, sizeof(mp_digit), primes); + return d; +} + + +/* makes a prime of at least k bits */ +static mp_err pprime(int k, int li, mp_int *p, mp_int *q) +{ + mp_int a, b, c, n, x, y, z, v; + mp_err res; + int ii; + static const mp_digit bases[] = { 2, 3, 5, 7, 11, 13, 17, 19 }; + + /* single digit ? */ + if (k <= (int) MP_DIGIT_BIT) { + mp_set(p, prime_digit()); + return MP_OKAY; + } + + if ((res = mp_init(&c)) != MP_OKAY) { + return res; + } + + if ((res = mp_init(&v)) != MP_OKAY) { + goto LBL_C; + } + + /* product of first 50 primes */ + if ((res = + mp_read_radix(&v, + "19078266889580195013601891820992757757219839668357012055907516904309700014933909014729740190", + 10)) != MP_OKAY) { + goto LBL_V; + } + + if ((res = mp_init(&a)) != MP_OKAY) { + goto LBL_V; + } + + /* set the prime */ + mp_set(&a, prime_digit()); + + if ((res = mp_init(&b)) != MP_OKAY) { + goto LBL_A; + } + + if ((res = mp_init(&n)) != MP_OKAY) { + goto LBL_B; + } + + if ((res = mp_init(&x)) != MP_OKAY) { + goto LBL_N; + } + + if ((res = mp_init(&y)) != MP_OKAY) { + goto LBL_X; + } + + if ((res = mp_init(&z)) != MP_OKAY) { + goto LBL_Y; + } + + /* now loop making the single digit */ + while (mp_count_bits(&a) < k) { + fprintf(stderr, "prime has %4d bits left\r", k - mp_count_bits(&a)); + fflush(stderr); +top: + mp_set(&b, prime_digit()); + + /* now compute z = a * b * 2 */ + if ((res = mp_mul(&a, &b, &z)) != MP_OKAY) { /* z = a * b */ + goto LBL_Z; + } + + if ((res = mp_copy(&z, &c)) != MP_OKAY) { /* c = a * b */ + goto LBL_Z; + } + + if ((res = mp_mul_2(&z, &z)) != MP_OKAY) { /* z = 2 * a * b */ + goto LBL_Z; + } + + /* n = z + 1 */ + if ((res = mp_add_d(&z, 1uL, &n)) != MP_OKAY) { /* n = z + 1 */ + goto LBL_Z; + } + + /* check (n, v) == 1 */ + if ((res = mp_gcd(&n, &v, &y)) != MP_OKAY) { /* y = (n, v) */ + goto LBL_Z; + } + + if (mp_cmp_d(&y, 1uL) != MP_EQ) + goto top; + + /* now try base x=bases[ii] */ + for (ii = 0; ii < li; ii++) { + mp_set(&x, bases[ii]); + + /* compute x^a mod n */ + if ((res = mp_exptmod(&x, &a, &n, &y)) != MP_OKAY) { /* y = x^a mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d(&y, 1uL) == MP_EQ) + continue; + + /* now x^2a mod n */ + if ((res = mp_sqrmod(&y, &n, &y)) != MP_OKAY) { /* y = x^2a mod n */ + goto LBL_Z; + } + + if (mp_cmp_d(&y, 1uL) == MP_EQ) + continue; + + /* compute x^b mod n */ + if ((res = mp_exptmod(&x, &b, &n, &y)) != MP_OKAY) { /* y = x^b mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d(&y, 1uL) == MP_EQ) + continue; + + /* now x^2b mod n */ + if ((res = mp_sqrmod(&y, &n, &y)) != MP_OKAY) { /* y = x^2b mod n */ + goto LBL_Z; + } + + if (mp_cmp_d(&y, 1uL) == MP_EQ) + continue; + + /* compute x^c mod n == x^ab mod n */ + if ((res = mp_exptmod(&x, &c, &n, &y)) != MP_OKAY) { /* y = x^ab mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d(&y, 1uL) == MP_EQ) + continue; + + /* now compute (x^c mod n)^2 */ + if ((res = mp_sqrmod(&y, &n, &y)) != MP_OKAY) { /* y = x^2ab mod n */ + goto LBL_Z; + } + + /* y should be 1 */ + if (mp_cmp_d(&y, 1uL) != MP_EQ) + continue; + break; + } + + /* no bases worked? */ + if (ii == li) + goto top; + + { + char buf[4096]; + + mp_to_decimal(&n, buf, sizeof(buf)); + printf("Certificate of primality for:\n%s\n\n", buf); + mp_to_decimal(&a, buf, sizeof(buf)); + printf("A == \n%s\n\n", buf); + mp_to_decimal(&b, buf, sizeof(buf)); + printf("B == \n%s\n\nG == %lu\n", buf, bases[ii]); + printf("----------------------------------------------------------------\n"); + } + + /* a = n */ + mp_copy(&n, &a); + } + + /* get q to be the order of the large prime subgroup */ + mp_sub_d(&n, 1uL, q); + mp_div_2(q, q); + mp_div(q, &b, q, NULL); + + mp_exch(&n, p); + + res = MP_OKAY; +LBL_Z: + mp_clear(&z); +LBL_Y: + mp_clear(&y); +LBL_X: + mp_clear(&x); +LBL_N: + mp_clear(&n); +LBL_B: + mp_clear(&b); +LBL_A: + mp_clear(&a); +LBL_V: + mp_clear(&v); +LBL_C: + mp_clear(&c); + return res; +} + + +int main(void) +{ + mp_int p, q; + char buf[4096]; + int k, li; + clock_t t1; + + srand(time(NULL)); + load_tab(); + + printf("Enter # of bits: \n"); + fgets(buf, sizeof(buf), stdin); + sscanf(buf, "%d", &k); + + printf("Enter number of bases to try (1 to 8):\n"); + fgets(buf, sizeof(buf), stdin); + sscanf(buf, "%d", &li); + + + mp_init(&p); + mp_init(&q); + + t1 = clock(); + pprime(k, li, &p, &q); + t1 = clock() - t1; + + printf("\n\nTook %d ticks, %d bits\n", t1, mp_count_bits(&p)); + + mp_to_decimal(&p, buf, sizeof(buf)); + printf("P == %s\n", buf); + mp_to_decimal(&q, buf, sizeof(buf)); + printf("Q == %s\n", buf); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.1024 b/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.1024 new file mode 100644 index 0000000..5636e2d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.1024 @@ -0,0 +1,414 @@ +Enter # of bits: +Enter number of bases to try (1 to 8): +Certificate of primality for: +36360080703173363 + +A == +89963569 + +B == +202082249 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +4851595597739856136987139 + +A == +36360080703173363 + +B == +66715963 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +19550639734462621430325731591027 + +A == +4851595597739856136987139 + +B == +2014867 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +10409036141344317165691858509923818734539 + +A == +19550639734462621430325731591027 + +B == +266207047 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1049829549988285012736475602118094726647504414203 + +A == +10409036141344317165691858509923818734539 + +B == +50428759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +77194737385528288387712399596835459931920358844586615003 + +A == +1049829549988285012736475602118094726647504414203 + +B == +36765367 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +35663756695365208574443215955488689578374232732893628896541201763 + +A == +77194737385528288387712399596835459931920358844586615003 + +B == +230998627 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +16711831463502165169495622246023119698415848120292671294127567620396469803 + +A == +35663756695365208574443215955488689578374232732893628896541201763 + +B == +234297127 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6163534781560285962890718925972249753147470953579266394395432475622345597103528739 + +A == +16711831463502165169495622246023119698415848120292671294127567620396469803 + +B == +184406323 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +814258256205243497704094951432575867360065658372158511036259934640748088306764553488803787 + +A == +6163534781560285962890718925972249753147470953579266394395432475622345597103528739 + +B == +66054487 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +176469695533271657902814176811660357049007467856432383037590673407330246967781451723764079581998187 + +A == +814258256205243497704094951432575867360065658372158511036259934640748088306764553488803787 + +B == +108362239 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +44924492859445516541759485198544012102424796403707253610035148063863073596051272171194806669756971406400419 + +A == +176469695533271657902814176811660357049007467856432383037590673407330246967781451723764079581998187 + +B == +127286707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +20600996927219343383225424320134474929609459588323857796871086845924186191561749519858600696159932468024710985371059 + +A == +44924492859445516541759485198544012102424796403707253610035148063863073596051272171194806669756971406400419 + +B == +229284691 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6295696427695493110141186605837397185848992307978456138112526915330347715236378041486547994708748840844217371233735072572979 + +A == +20600996927219343383225424320134474929609459588323857796871086845924186191561749519858600696159932468024710985371059 + +B == +152800771 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3104984078042317488749073016454213579257792635142218294052134804187631661145261015102617582090263808696699966840735333252107678792123 + +A == +6295696427695493110141186605837397185848992307978456138112526915330347715236378041486547994708748840844217371233735072572979 + +B == +246595759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +26405175827665701256325699315126705508919255051121452292124404943796947287968603975320562847910946802396632302209435206627913466015741799499 + +A == +3104984078042317488749073016454213579257792635142218294052134804187631661145261015102617582090263808696699966840735333252107678792123 + +B == +4252063 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +11122146237908413610034600609460545703591095894418599759742741406628055069007082998134905595800236452010905900391505454890446585211975124558601770163 + +A == +26405175827665701256325699315126705508919255051121452292124404943796947287968603975320562847910946802396632302209435206627913466015741799499 + +B == +210605419 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1649861642047798890580354082088712649911849362201343649289384923147797960364736011515757482030049342943790127685185806092659832129486307035500638595572396187 + +A == +11122146237908413610034600609460545703591095894418599759742741406628055069007082998134905595800236452010905900391505454890446585211975124558601770163 + +B == +74170111 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +857983367126266717607389719637086684134462613006415859877666235955788392464081914127715967940968197765042399904117392707518175220864852816390004264107201177394565363 + +A == +1649861642047798890580354082088712649911849362201343649289384923147797960364736011515757482030049342943790127685185806092659832129486307035500638595572396187 + +B == +260016763 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +175995909353623703257072120479340610010337144085688850745292031336724691277374210929188442230237711063783727092685448718515661641054886101716698390145283196296702450566161283 + +A == +857983367126266717607389719637086684134462613006415859877666235955788392464081914127715967940968197765042399904117392707518175220864852816390004264107201177394565363 + +B == +102563707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +48486002551155667224487059713350447239190772068092630563272168418880661006593537218144160068395218642353495339720640699721703003648144463556291315694787862009052641640656933232794283 + +A == +175995909353623703257072120479340610010337144085688850745292031336724691277374210929188442230237711063783727092685448718515661641054886101716698390145283196296702450566161283 + +B == +137747527 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +13156468011529105025061495011938518171328604045212410096476697450506055664012861932372156505805788068791146986282263016790631108386790291275939575123375304599622623328517354163964228279867403 + +A == +48486002551155667224487059713350447239190772068092630563272168418880661006593537218144160068395218642353495339720640699721703003648144463556291315694787862009052641640656933232794283 + +B == +135672847 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6355194692790533601105154341731997464407930009404822926832136060319955058388106456084549316415200519472481147942263916585428906582726749131479465958107142228236909665306781538860053107680830113869123 + +A == +13156468011529105025061495011938518171328604045212410096476697450506055664012861932372156505805788068791146986282263016790631108386790291275939575123375304599622623328517354163964228279867403 + +B == +241523587 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3157116676535430302794438027544146642863331358530722860333745617571010460905857862561870488000265751138954271040017454405707755458702044884023184574412221802502351503929935224995314581932097706874819348858083 + +A == +6355194692790533601105154341731997464407930009404822926832136060319955058388106456084549316415200519472481147942263916585428906582726749131479465958107142228236909665306781538860053107680830113869123 + +B == +248388667 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +390533129219992506725320633489467713907837370444962163378727819939092929448752905310115311180032249230394348337568973177802874166228132778126338883671958897238722734394783244237133367055422297736215754829839364158067 + +A == +3157116676535430302794438027544146642863331358530722860333745617571010460905857862561870488000265751138954271040017454405707755458702044884023184574412221802502351503929935224995314581932097706874819348858083 + +B == +61849651 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +48583654555070224891047847050732516652910250240135992225139515777200432486685999462997073444468380434359929499498804723793106565291183220444221080449740542884172281158126259373095216435009661050109711341419005972852770440739 + +A == +390533129219992506725320633489467713907837370444962163378727819939092929448752905310115311180032249230394348337568973177802874166228132778126338883671958897238722734394783244237133367055422297736215754829839364158067 + +B == +62201707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +25733035251905120039135866524384525138869748427727001128764704499071378939227862068500633813538831598776578372709963673670934388213622433800015759585470542686333039614931682098922935087822950084908715298627996115185849260703525317419 + +A == +48583654555070224891047847050732516652910250240135992225139515777200432486685999462997073444468380434359929499498804723793106565291183220444221080449740542884172281158126259373095216435009661050109711341419005972852770440739 + +B == +264832231 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +2804594464939948901906623499531073917980499195397462605359913717827014360538186518540781517129548650937632008683280555602633122170458773895504894807182664540529077836857897972175530148107545939211339044386106111633510166695386323426241809387 + +A == +25733035251905120039135866524384525138869748427727001128764704499071378939227862068500633813538831598776578372709963673670934388213622433800015759585470542686333039614931682098922935087822950084908715298627996115185849260703525317419 + +B == +54494047 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +738136612083433720096707308165797114449914259256979340471077690416567237592465306112484843530074782721390528773594351482384711900456440808251196845265132086486672447136822046628407467459921823150600138073268385534588238548865012638209515923513516547 + +A == +2804594464939948901906623499531073917980499195397462605359913717827014360538186518540781517129548650937632008683280555602633122170458773895504894807182664540529077836857897972175530148107545939211339044386106111633510166695386323426241809387 + +B == +131594179 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +392847529056126766528615419937165193421166694172790666626558750047057558168124866940509180171236517681470100877687445134633784815352076138790217228749332398026714192707447855731679485746120589851992221508292976900578299504461333767437280988393026452846013683 + +A == +738136612083433720096707308165797114449914259256979340471077690416567237592465306112484843530074782721390528773594351482384711900456440808251196845265132086486672447136822046628407467459921823150600138073268385534588238548865012638209515923513516547 + +B == +266107603 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +168459393231883505975876919268398655632763956627405508859662408056221544310200546265681845397346956580604208064328814319465940958080244889692368602591598503944015835190587740756859842792554282496742843600573336023639256008687581291233481455395123454655488735304365627 + +A == +392847529056126766528615419937165193421166694172790666626558750047057558168124866940509180171236517681470100877687445134633784815352076138790217228749332398026714192707447855731679485746120589851992221508292976900578299504461333767437280988393026452846013683 + +B == +214408111 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +14865774288636941404884923981945833072113667565310054952177860608355263252462409554658728941191929400198053290113492910272458441655458514080123870132092365833472436407455910185221474386718838138135065780840839893113912689594815485706154461164071775481134379794909690501684643 + +A == +168459393231883505975876919268398655632763956627405508859662408056221544310200546265681845397346956580604208064328814319465940958080244889692368602591598503944015835190587740756859842792554282496742843600573336023639256008687581291233481455395123454655488735304365627 + +B == +44122723 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1213301773203241614897109856134894783021668292000023984098824423682568173639394290886185366993108292039068940333907505157813934962357206131450244004178619265868614859794316361031904412926604138893775068853175215502104744339658944443630407632290152772487455298652998368296998719996019 + +A == +14865774288636941404884923981945833072113667565310054952177860608355263252462409554658728941191929400198053290113492910272458441655458514080123870132092365833472436407455910185221474386718838138135065780840839893113912689594815485706154461164071775481134379794909690501684643 + +B == +40808563 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +186935245989515158127969129347464851990429060640910951266513740972248428651109062997368144722015290092846666943896556191257222521203647606911446635194198213436423080005867489516421559330500722264446765608763224572386410155413161172707802334865729654109050873820610813855041667633843601286843 + +A == +1213301773203241614897109856134894783021668292000023984098824423682568173639394290886185366993108292039068940333907505157813934962357206131450244004178619265868614859794316361031904412926604138893775068853175215502104744339658944443630407632290152772487455298652998368296998719996019 + +B == +77035759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +83142661079751490510739960019112406284111408348732592580459037404394946037094409915127399165633756159385609671956087845517678367844901424617866988187132480585966721962585586730693443536100138246516868613250009028187662080828012497191775172228832247706080044971423654632146928165751885302331924491683 + +A == +186935245989515158127969129347464851990429060640910951266513740972248428651109062997368144722015290092846666943896556191257222521203647606911446635194198213436423080005867489516421559330500722264446765608763224572386410155413161172707802334865729654109050873820610813855041667633843601286843 + +B == +222383587 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 + +A == +83142661079751490510739960019112406284111408348732592580459037404394946037094409915127399165633756159385609671956087845517678367844901424617866988187132480585966721962585586730693443536100138246516868613250009028187662080828012497191775172228832247706080044971423654632146928165751885302331924491683 + +B == +23407687 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1663606652988091811284014366560171522582683318514519379924950390627250155440313691226744227787921928894551755219495501365555370027257568506349958010457682898612082048959464465369892842603765280317696116552850664773291371490339084156052244256635115997453399761029567033971998617303988376172539172702246575225837054723 + +A == +3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 + +B == +213701827 + +G == 2 +---------------------------------------------------------------- + + +Took 33057 ticks, 1048 bits +P == 1663606652988091811284014366560171522582683318514519379924950390627250155440313691226744227787921928894551755219495501365555370027257568506349958010457682898612082048959464465369892842603765280317696116552850664773291371490339084156052244256635115997453399761029567033971998617303988376172539172702246575225837054723 +Q == 3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.512 b/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.512 new file mode 100644 index 0000000..cb6ec30 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/prime.512 @@ -0,0 +1,205 @@ +Enter # of bits: +Enter number of bases to try (1 to 8): +Certificate of primality for: +85933926807634727 + +A == +253758023 + +B == +169322581 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +23930198825086241462113799 + +A == +85933926807634727 + +B == +139236037 + +G == 11 +---------------------------------------------------------------- +Certificate of primality for: +6401844647261612602378676572510019 + +A == +23930198825086241462113799 + +B == +133760791 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +269731366027728777712034888684015329354259 + +A == +6401844647261612602378676572510019 + +B == +21066691 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +37942338209025571690075025099189467992329684223707 + +A == +269731366027728777712034888684015329354259 + +B == +70333567 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +15306904714258982484473490774101705363308327436988160248323 + +A == +37942338209025571690075025099189467992329684223707 + +B == +201712723 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1616744757018513392810355191503853040357155275733333124624513530099 + +A == +15306904714258982484473490774101705363308327436988160248323 + +B == +52810963 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +464222094814208047161771036072622485188658077940154689939306386289983787983 + +A == +1616744757018513392810355191503853040357155275733333124624513530099 + +B == +143566909 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +187429931674053784626487560729643601208757374994177258429930699354770049369025096447 + +A == +464222094814208047161771036072622485188658077940154689939306386289983787983 + +B == +201875281 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +100579220846502621074093727119851331775052664444339632682598589456666938521976625305832917563 + +A == +187429931674053784626487560729643601208757374994177258429930699354770049369025096447 + +B == +268311523 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1173616081309758475197022137833792133815753368965945885089720153370737965497134878651384030219765163 + +A == +100579220846502621074093727119851331775052664444339632682598589456666938521976625305832917563 + +B == +5834287 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +191456913489905913185935197655672585713573070349044195411728114905691721186574907738081340754373032735283623 + +A == +1173616081309758475197022137833792133815753368965945885089720153370737965497134878651384030219765163 + +B == +81567097 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +57856530489201750164178576399448868489243874083056587683743345599898489554401618943240901541005080049321706789987519 + +A == +191456913489905913185935197655672585713573070349044195411728114905691721186574907738081340754373032735283623 + +B == +151095433 + +G == 7 +---------------------------------------------------------------- +Certificate of primality for: +13790529750452576698109671710773784949185621244122040804792403407272729038377767162233653248852099545134831722512085881814803 + +A == +57856530489201750164178576399448868489243874083056587683743345599898489554401618943240901541005080049321706789987519 + +B == +119178679 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +7075985989000817742677547821106534174334812111605018857703825637170140040509067704269696198231266351631132464035671858077052876058979 + +A == +13790529750452576698109671710773784949185621244122040804792403407272729038377767162233653248852099545134831722512085881814803 + +B == +256552363 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1227273006232588072907488910282307435921226646895131225407452056677899411162892829564455154080310937471747140942360789623819327234258162420463 + +A == +7075985989000817742677547821106534174334812111605018857703825637170140040509067704269696198231266351631132464035671858077052876058979 + +B == +86720989 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 + +A == +1227273006232588072907488910282307435921226646895131225407452056677899411162892829564455154080310937471747140942360789623819327234258162420463 + +B == +182015287 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +5290203010849586596974953717018896543907195901082056939587768479377028575911127944611236020459652034082251335583308070846379514569838984811187823420951275243 + +A == +446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 + +B == +5920567 + +G == 2 +---------------------------------------------------------------- + + +Took 3454 ticks, 521 bits +P == 5290203010849586596974953717018896543907195901082056939587768479377028575911127944611236020459652034082251335583308070846379514569838984811187823420951275243 +Q == 446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/timer.asm b/third_party/heimdal/lib/hcrypto/libtommath/etc/timer.asm new file mode 100644 index 0000000..35890d9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/timer.asm @@ -0,0 +1,37 @@ +; x86 timer in NASM +; +; Tom St Denis, tomstdenis@iahu.ca +[bits 32] +[section .data] +time dd 0, 0 + +[section .text] + +%ifdef USE_ELF +[global t_start] +t_start: +%else +[global _t_start] +_t_start: +%endif + push edx + push eax + rdtsc + mov [time+0],edx + mov [time+4],eax + pop eax + pop edx + ret + +%ifdef USE_ELF +[global t_read] +t_read: +%else +[global _t_read] +_t_read: +%endif + rdtsc + sub eax,[time+4] + sbb edx,[time+0] + ret + \ No newline at end of file diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c new file mode 100644 index 0000000..e7b99fc --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune.c @@ -0,0 +1,542 @@ +/* Tune the Karatsuba parameters + * + * Tom St Denis, tstdenis82@gmail.com + */ +#include "../tommath.h" +#include "../tommath_private.h" +#include +#include +#include + +/* + Please take in mind that both multiplicands are of the same size. The balancing + mechanism in mp_balance works well but has some overhead itself. You can test + the behaviour of it with the option "-o" followed by a (small) positive number 'x' + to generate ratios of the form 1:x. +*/ + +static uint64_t s_timer_function(void); +static void s_timer_start(void); +static uint64_t s_timer_stop(void); +static uint64_t s_time_mul(int size); +static uint64_t s_time_sqr(int size); +static void s_usage(char *s); + +static uint64_t s_timer_function(void) +{ +#if _POSIX_C_SOURCE >= 199309L +#define LTM_BILLION 1000000000 + struct timespec ts; + + /* TODO: Sets errno in case of error. Use? */ + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t)ts.tv_sec) * LTM_BILLION + (uint64_t)ts.tv_nsec); +#else + clock_t t; + t = clock(); + if (t < (clock_t)(0)) { + return (uint64_t)(0); + } + return (uint64_t)(t); +#endif +} + +/* generic ISO C timer */ +static uint64_t s_timer_tmp; +static void s_timer_start(void) +{ + s_timer_tmp = s_timer_function(); +} +static uint64_t s_timer_stop(void) +{ + return s_timer_function() - s_timer_tmp; +} + + +static int s_check_result; +static int s_number_of_test_loops; +static int s_stabilization_extra; +static int s_offset = 1; + +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static uint64_t s_time_mul(int size) +{ + int x; + mp_err e; + mp_int a, b, c, d; + uint64_t t1; + + if ((e = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + + if ((e = mp_rand(&a, size * s_offset)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + if ((e = mp_rand(&b, size)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + + s_timer_start(); + for (x = 0; x < s_number_of_test_loops; x++) { + if ((e = mp_mul(&a,&b,&c)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + if (s_check_result == 1) { + if ((e = s_mp_mul(&a,&b,&d)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + if (mp_cmp(&c, &d) != MP_EQ) { + /* Time of 0 cannot happen (famous last words?) */ + t1 = 0uLL; + goto LTM_ERR; + } + } + } + + t1 = s_timer_stop(); +LTM_ERR: + mp_clear_multi(&a, &b, &c, &d, NULL); + return t1; +} + +static uint64_t s_time_sqr(int size) +{ + int x; + mp_err e; + mp_int a, b, c; + uint64_t t1; + + if ((e = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + + if ((e = mp_rand(&a, size)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + + s_timer_start(); + for (x = 0; x < s_number_of_test_loops; x++) { + if ((e = mp_sqr(&a,&b)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + if (s_check_result == 1) { + if ((e = s_mp_sqr(&a,&c)) != MP_OKAY) { + t1 = UINT64_MAX; + goto LTM_ERR; + } + if (mp_cmp(&c, &b) != MP_EQ) { + t1 = 0uLL; + goto LTM_ERR; + } + } + } + + t1 = s_timer_stop(); +LTM_ERR: + mp_clear_multi(&a, &b, &c, NULL); + return t1; +} + +struct tune_args { + int testmode; + int verbose; + int print; + int bncore; + int terse; + int upper_limit_print; + int increment_print; +} args; + +static void s_run(const char *name, uint64_t (*op)(int), int *cutoff) +{ + int x, count = 0; + uint64_t t1, t2; + if ((args.verbose == 1) || (args.testmode == 1)) { + printf("# %s.\n", name); + } + for (x = 8; x < args.upper_limit_print; x += args.increment_print) { + *cutoff = INT_MAX; + t1 = op(x); + if ((t1 == 0uLL) || (t1 == UINT64_MAX)) { + fprintf(stderr,"%s failed at x = INT_MAX (%s)\n", name, + (t1 == 0uLL)?"wrong result":"internal error"); + exit(EXIT_FAILURE); + } + *cutoff = x; + t2 = op(x); + if ((t2 == 0uLL) || (t2 == UINT64_MAX)) { + fprintf(stderr,"%s failed (%s)\n", name, + (t2 == 0uLL)?"wrong result":"internal error"); + exit(EXIT_FAILURE); + } + if (args.verbose == 1) { + printf("%d: %9"PRIu64" %9"PRIu64", %9"PRIi64"\n", x, t1, t2, (int64_t)t2 - (int64_t)t1); + } + if (t2 < t1) { + if (count == s_stabilization_extra) { + count = 0; + break; + } else if (count < s_stabilization_extra) { + count++; + } + } else if (count > 0) { + count--; + } + } + *cutoff = x - s_stabilization_extra * args.increment_print; +} + +static long s_strtol(const char *str, char **endptr, const char *err) +{ + const int base = 10; + char *_endptr; + long val; + errno = 0; + val = strtol(str, &_endptr, base); + if ((val > INT_MAX || val < 0) || (errno != 0)) { + fprintf(stderr, "Value %s not usable\n", str); + exit(EXIT_FAILURE); + } + if (_endptr == str) { + fprintf(stderr, "%s\n", err); + exit(EXIT_FAILURE); + } + if (endptr) *endptr = _endptr; + return val; +} + +static int s_exit_code = EXIT_FAILURE; +static void s_usage(char *s) +{ + fprintf(stderr,"Usage: %s [TvcpGbtrSLFfMmosh]\n",s); + fprintf(stderr," -T testmode, for use with testme.sh\n"); + fprintf(stderr," -v verbose, print all timings\n"); + fprintf(stderr," -c check results\n"); + fprintf(stderr," -p print benchmark of final cutoffs in files \"multiplying\"\n"); + fprintf(stderr," and \"squaring\"\n"); + fprintf(stderr," -G [string] suffix for the filenames listed above\n"); + fprintf(stderr," Implies '-p'\n"); + fprintf(stderr," -b print benchmark of bncore.c\n"); + fprintf(stderr," -t prints space (0x20) separated results\n"); + fprintf(stderr," -r [64] number of rounds\n"); + fprintf(stderr," -S [0xdeadbeef] seed for PRNG\n"); + fprintf(stderr," -L [3] number of negative values accumulated until the result is accepted\n"); + fprintf(stderr," -M [3000] upper limit of T-C tests/prints\n"); + fprintf(stderr," -m [1] increment of T-C tests/prints\n"); + fprintf(stderr," -o [1] multiplier for the second multiplicand\n"); + fprintf(stderr," (Not for computing the cut-offs!)\n"); + fprintf(stderr," -s 'preset' use values in 'preset' for printing.\n"); + fprintf(stderr," 'preset' is a comma separated string with cut-offs for\n"); + fprintf(stderr," ksm, kss, tc3m, tc3s in that order\n"); + fprintf(stderr," ksm = karatsuba multiplication\n"); + fprintf(stderr," kss = karatsuba squaring\n"); + fprintf(stderr," tc3m = Toom-Cook 3-way multiplication\n"); + fprintf(stderr," tc3s = Toom-Cook 3-way squaring\n"); + fprintf(stderr," Implies '-p'\n"); + fprintf(stderr," -h this message\n"); + exit(s_exit_code); +} + +struct cutoffs { + int KARATSUBA_MUL, KARATSUBA_SQR; + int TOOM_MUL, TOOM_SQR; +}; + +const struct cutoffs max_cutoffs = +{ INT_MAX, INT_MAX, INT_MAX, INT_MAX }; + +static void set_cutoffs(const struct cutoffs *c) +{ + KARATSUBA_MUL_CUTOFF = c->KARATSUBA_MUL; + KARATSUBA_SQR_CUTOFF = c->KARATSUBA_SQR; + TOOM_MUL_CUTOFF = c->TOOM_MUL; + TOOM_SQR_CUTOFF = c->TOOM_SQR; +} + +static void get_cutoffs(struct cutoffs *c) +{ + c->KARATSUBA_MUL = KARATSUBA_MUL_CUTOFF; + c->KARATSUBA_SQR = KARATSUBA_SQR_CUTOFF; + c->TOOM_MUL = TOOM_MUL_CUTOFF; + c->TOOM_SQR = TOOM_SQR_CUTOFF; + +} + +int main(int argc, char **argv) +{ + uint64_t t1, t2; + int x, i, j; + size_t n; + + int printpreset = 0; + /*int preset[8];*/ + char *endptr, *str; + + uint64_t seed = 0xdeadbeef; + + int opt; + struct cutoffs orig, updated; + + FILE *squaring, *multiplying; + char mullog[256] = "multiplying"; + char sqrlog[256] = "squaring"; + s_number_of_test_loops = 64; + s_stabilization_extra = 3; + + MP_ZERO_BUFFER(&args, sizeof(args)); + + args.testmode = 0; + args.verbose = 0; + args.print = 0; + args.bncore = 0; + args.terse = 0; + + args.upper_limit_print = 3000; + args.increment_print = 1; + + /* Very simple option parser, please treat it nicely. */ + if (argc != 1) { + for (opt = 1; (opt < argc) && (argv[opt][0] == '-'); opt++) { + switch (argv[opt][1]) { + case 'T': + args.testmode = 1; + s_check_result = 1; + args.upper_limit_print = 1000; + args.increment_print = 11; + s_number_of_test_loops = 1; + s_stabilization_extra = 1; + s_offset = 1; + break; + case 'v': + args.verbose = 1; + break; + case 'c': + s_check_result = 1; + break; + case 'p': + args.print = 1; + break; + case 'G': + args.print = 1; + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + /* manual strcat() */ + for (i = 0; i < 255; i++) { + if (mullog[i] == '\0') { + break; + } + } + for (j = 0; i < 255; j++, i++) { + mullog[i] = argv[opt][j]; + if (argv[opt][j] == '\0') { + break; + } + } + for (i = 0; i < 255; i++) { + if (sqrlog[i] == '\0') { + break; + } + } + for (j = 0; i < 255; j++, i++) { + sqrlog[i] = argv[opt][j]; + if (argv[opt][j] == '\0') { + break; + } + } + break; + case 'b': + args.bncore = 1; + break; + case 't': + args.terse = 1; + break; + case 'S': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + str = argv[opt]; + errno = 0; + seed = (uint64_t)s_strtol(argv[opt], NULL, "No seed given?\n"); + break; + case 'L': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + s_stabilization_extra = (int)s_strtol(argv[opt], NULL, "No value for option \"-L\"given"); + break; + case 'o': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + s_offset = (int)s_strtol(argv[opt], NULL, "No value for the offset given"); + break; + case 'r': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + s_number_of_test_loops = (int)s_strtol(argv[opt], NULL, "No value for the number of rounds given"); + break; + + case 'M': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + args.upper_limit_print = (int)s_strtol(argv[opt], NULL, "No value for the upper limit of T-C tests given"); + break; + case 'm': + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + args.increment_print = (int)s_strtol(argv[opt], NULL, "No value for the increment for the T-C tests given"); + break; + case 's': + printpreset = 1; + args.print = 1; + opt++; + if (opt >= argc) { + s_usage(argv[0]); + } + str = argv[opt]; + KARATSUBA_MUL_CUTOFF = (int)s_strtol(str, &endptr, "[1/4] No value for KARATSUBA_MUL_CUTOFF given"); + str = endptr + 1; + KARATSUBA_SQR_CUTOFF = (int)s_strtol(str, &endptr, "[2/4] No value for KARATSUBA_SQR_CUTOFF given"); + str = endptr + 1; + TOOM_MUL_CUTOFF = (int)s_strtol(str, &endptr, "[3/4] No value for TOOM_MUL_CUTOFF given"); + str = endptr + 1; + TOOM_SQR_CUTOFF = (int)s_strtol(str, &endptr, "[4/4] No value for TOOM_SQR_CUTOFF given"); + break; + case 'h': + s_exit_code = EXIT_SUCCESS; + /* FALLTHROUGH */ + default: + s_usage(argv[0]); + } + } + } + + /* + mp_rand uses the cryptographically secure + source of the OS by default. That is too expensive, too slow and + most important for a benchmark: it is not repeatable. + */ + s_mp_rand_jenkins_init(seed); + mp_rand_source(s_mp_rand_jenkins); + + get_cutoffs(&orig); + + updated = max_cutoffs; + if ((args.bncore == 0) && (printpreset == 0)) { + struct { + const char *name; + int *cutoff, *update; + uint64_t (*fn)(int); + } test[] = { +#define T_MUL_SQR(n, o, f) { #n, &o##_CUTOFF, &(updated.o), MP_HAS(S_MP_##o) ? f : NULL } + /* + The influence of the Comba multiplication cannot be + eradicated programmatically. It depends on the size + of the macro MP_WPARRAY in tommath.h which needs to + be changed manually (to 0 (zero)). + */ + T_MUL_SQR("Karatsuba multiplication", KARATSUBA_MUL, s_time_mul), + T_MUL_SQR("Karatsuba squaring", KARATSUBA_SQR, s_time_sqr), + T_MUL_SQR("Toom-Cook 3-way multiplying", TOOM_MUL, s_time_mul), + T_MUL_SQR("Toom-Cook 3-way squaring", TOOM_SQR, s_time_sqr), +#undef T_MUL_SQR + }; + /* Turn all limits from bncore.c to the max */ + set_cutoffs(&max_cutoffs); + for (n = 0; n < sizeof(test)/sizeof(test[0]); ++n) { + if (test[n].fn) { + s_run(test[n].name, test[n].fn, test[n].cutoff); + *test[n].update = *test[n].cutoff; + *test[n].cutoff = INT_MAX; + } + } + } + if (args.terse == 1) { + printf("%d %d %d %d\n", + updated.KARATSUBA_MUL, + updated.KARATSUBA_SQR, + updated.TOOM_MUL, + updated.TOOM_SQR); + } else { + printf("KARATSUBA_MUL_CUTOFF = %d\n", updated.KARATSUBA_MUL); + printf("KARATSUBA_SQR_CUTOFF = %d\n", updated.KARATSUBA_SQR); + printf("TOOM_MUL_CUTOFF = %d\n", updated.TOOM_MUL); + printf("TOOM_SQR_CUTOFF = %d\n", updated.TOOM_SQR); + } + + if (args.print == 1) { + printf("Printing data for graphing to \"%s\" and \"%s\"\n",mullog, sqrlog); + + multiplying = fopen(mullog, "w+"); + if (multiplying == NULL) { + fprintf(stderr, "Opening file \"%s\" failed\n", mullog); + exit(EXIT_FAILURE); + } + + squaring = fopen(sqrlog, "w+"); + if (squaring == NULL) { + fprintf(stderr, "Opening file \"%s\" failed\n",sqrlog); + exit(EXIT_FAILURE); + } + + for (x = 8; x < args.upper_limit_print; x += args.increment_print) { + set_cutoffs(&max_cutoffs); + t1 = s_time_mul(x); + set_cutoffs(&orig); + t2 = s_time_mul(x); + fprintf(multiplying, "%d: %9"PRIu64" %9"PRIu64", %9"PRIi64"\n", x, t1, t2, (int64_t)t2 - (int64_t)t1); + fflush(multiplying); + if (args.verbose == 1) { + printf("MUL %d: %9"PRIu64" %9"PRIu64", %9"PRIi64"\n", x, t1, t2, (int64_t)t2 - (int64_t)t1); + fflush(stdout); + } + set_cutoffs(&max_cutoffs); + t1 = s_time_sqr(x); + set_cutoffs(&orig); + t2 = s_time_sqr(x); + fprintf(squaring,"%d: %9"PRIu64" %9"PRIu64", %9"PRIi64"\n", x, t1, t2, (int64_t)t2 - (int64_t)t1); + fflush(squaring); + if (args.verbose == 1) { + printf("SQR %d: %9"PRIu64" %9"PRIu64", %9"PRIi64"\n", x, t1, t2, (int64_t)t2 - (int64_t)t1); + fflush(stdout); + } + } + printf("Finished. Data for graphing in \"%s\" and \"%s\"\n",mullog, sqrlog); + if (args.verbose == 1) { + set_cutoffs(&orig); + if (args.terse == 1) { + printf("%d %d %d %d\n", + KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF, + TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF); + } else { + printf("KARATSUBA_MUL_CUTOFF = %d\n", KARATSUBA_MUL_CUTOFF); + printf("KARATSUBA_SQR_CUTOFF = %d\n", KARATSUBA_SQR_CUTOFF); + printf("TOOM_MUL_CUTOFF = %d\n", TOOM_MUL_CUTOFF); + printf("TOOM_SQR_CUTOFF = %d\n", TOOM_SQR_CUTOFF); + } + } + } + exit(EXIT_SUCCESS); +} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/etc/tune_it.sh b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune_it.sh new file mode 100755 index 0000000..5e0fe7c --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/etc/tune_it.sh @@ -0,0 +1,107 @@ +#!/bin/sh + +die() { + echo "$1 failed" + echo "Exiting" + exit $2 +} +# A linear congruential generator is sufficient for the purpose. +SEED=3735928559 +LCG() { + SEED=$(((1103515245 * $SEED + 12345) % 2147483648)) + echo $SEED +} +median() { +# read everything besides the header from file $1 +# | cut-out the required column $2 +# | sort all the entries numerically +# | show only the first $3 entries +# | show only the last entry + tail -n +2 $1 | cut -d' ' -f$2 | sort -n | head -n $3 | tail -n 1 +} + +MPWD=$(dirname $(readlink -f "$0")) +FILE_NAME="tuning_list" +TOMMATH_CUTOFFS_H="$MPWD/../tommath_cutoffs.h" +BACKUP_SUFFIX=".orig" +RNUM=0 + +############################################################################# +# It would be a good idea to isolate these processes (with e.g.: cpuset) # +# # +# It is not a good idea to e.g: watch high resolution videos while this # +# test are running if you do not have enough memory to avoid page faults. # +############################################################################# + +# Number of rounds overall. +LIMIT=100 +# Number of loops for each input. +RLOOPS=10 +# Offset ( > 0 ) . Runs tests with asymmetric input of the form 1:OFFSET +# Please use another destination for TOMMATH_CUTOFFS_H if you change OFFSET, because the numbers +# with an offset different from 1 (one) are not usable as the general cut-off values +# in "tommath_cutoffs.h". +OFFSET=1 +# Number ( >= 3 ) of positive results (TC-is-faster) accumulated until it is accepted. +# Due to the algorithm used to compute the median in this Posix compliant shell script +# the value needs to be 3 (three), not less, to keep the variation small. +LAG=3 +# Keep the temporary file $FILE_NAME. Set to 0 (zero) to remove it at the end. +# The file is in a format fit to feed into R directly. If you do it and find the median +# of this program to be off by more than a couple: please contact the authors and report +# the numbers from this program and R and the standard deviation. This program is known +# to get larger errors if the standard deviation is larger than ~50. +KEEP_TEMP=1 + +echo "You might like to watch the numbers go up to $LIMIT but it will take a long time!" + +# Might not have sufficient rights or disc full. +echo "km ks tc3m tc3s" > $FILE_NAME || die "Writing header to $FILE_NAME" $? +i=1 +while [ $i -le $LIMIT ]; do + RNUM=$(LCG) + printf "\r%d" $i + "$MPWD"/tune -t -r $RLOOPS -L $LAG -S "$RNUM" -o $OFFSET >> $FILE_NAME || die "tune" $? + i=$((i + 1)) +done + +if [ $KEEP_TEMP -eq 0 ]; then + rm -v $FILE_NAME || die "Removing $KEEP_TEMP" $? +fi + +echo "Writing cut-off values to \"$TOMMATH_CUTOFFS_H\"." +echo "In case of failure: a copy of \"$TOMMATH_CUTOFFS_H\" is in \"$TOMMATH_CUTOFFS_H$BACKUP_SUFFIX\"" + +cp -v $TOMMATH_CUTOFFS_H $TOMMATH_CUTOFFS_H$BACKUP_SUFFIX || die "Making backup copy of $TOMMATH_CUTOFFS_H" $? + +cat << END_OF_INPUT > $TOMMATH_CUTOFFS_H || die "Writing header to $TOMMATH_CUTOFFS_H" $? +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +/* + Current values evaluated on an AMD A8-6600K (64-bit). + Type "make tune" to optimize them for your machine but + be aware that it may take a long time. It took 2:30 minutes + on the aforementioned machine for example. + */ +END_OF_INPUT + +# The Posix shell does not offer an array data type so we create +# the median with 'standard tools'^TM + +# read the file (without the first line) and count the lines +i=$(tail -n +2 $FILE_NAME | wc -l) +# our median point will be at $i entries +i=$(( (i / 2) + 1 )) +TMP=$(median $FILE_NAME 1 $i) +echo "#define MP_DEFAULT_KARATSUBA_MUL_CUTOFF $TMP" +echo "#define MP_DEFAULT_KARATSUBA_MUL_CUTOFF $TMP" >> $TOMMATH_CUTOFFS_H || die "(km) Appending to $TOMMATH_CUTOFFS_H" $? +TMP=$(median $FILE_NAME 2 $i) +echo "#define MP_DEFAULT_KARATSUBA_SQR_CUTOFF $TMP" +echo "#define MP_DEFAULT_KARATSUBA_SQR_CUTOFF $TMP" >> $TOMMATH_CUTOFFS_H || die "(ks) Appending to $TOMMATH_CUTOFFS_H" $? +TMP=$(median $FILE_NAME 3 $i) +echo "#define MP_DEFAULT_TOOM_MUL_CUTOFF $TMP" +echo "#define MP_DEFAULT_TOOM_MUL_CUTOFF $TMP" >> $TOMMATH_CUTOFFS_H || die "(tc3m) Appending to $TOMMATH_CUTOFFS_H" $? +TMP=$(median $FILE_NAME 4 $i) +echo "#define MP_DEFAULT_TOOM_SQR_CUTOFF $TMP" +echo "#define MP_DEFAULT_TOOM_SQR_CUTOFF $TMP" >> $TOMMATH_CUTOFFS_H || die "(tc3s) Appending to $TOMMATH_CUTOFFS_H" $? + diff --git a/third_party/heimdal/lib/hcrypto/libtommath/gen.pl b/third_party/heimdal/lib/hcrypto/libtommath/gen.pl new file mode 100644 index 0000000..332994d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/gen.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# +# Generates a "single file" you can use to quickly +# add the whole source without any makefile troubles +# +use strict; +use warnings; + +open(my $out, '>', 'mpi.c') or die "Couldn't open mpi.c for writing: $!"; +foreach my $filename (glob 'bn*.c') { + open(my $src, '<', $filename) or die "Couldn't open $filename for reading: $!"; + print {$out} "/* Start: $filename */\n"; + print {$out} $_ while <$src>; + print {$out} "\n/* End: $filename */\n\n"; + close $src or die "Error closing $filename after reading: $!"; +} +print {$out} "\n/* EOF */\n"; +close $out or die "Error closing mpi.c after writing: $!"; + +system('perl -pli -e "s/\s*$//" mpi.c'); diff --git a/third_party/heimdal/lib/hcrypto/libtommath/helper.pl b/third_party/heimdal/lib/hcrypto/libtommath/helper.pl new file mode 100755 index 0000000..e60c1a7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/helper.pl @@ -0,0 +1,482 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Getopt::Long; +use File::Find 'find'; +use File::Basename 'basename'; +use File::Glob 'bsd_glob'; + +sub read_file { + my $f = shift; + open my $fh, "<", $f or die "FATAL: read_rawfile() cannot open file '$f': $!"; + binmode $fh; + return do { local $/; <$fh> }; +} + +sub write_file { + my ($f, $data) = @_; + die "FATAL: write_file() no data" unless defined $data; + open my $fh, ">", $f or die "FATAL: write_file() cannot open file '$f': $!"; + binmode $fh; + print $fh $data or die "FATAL: write_file() cannot write to '$f': $!"; + close $fh or die "FATAL: write_file() cannot close '$f': $!"; + return; +} + +sub sanitize_comments { + my($content) = @_; + $content =~ s{/\*(.*?)\*/}{my $x=$1; $x =~ s/\w/x/g; "/*$x*/";}egs; + return $content; +} + +sub check_source { + my @all_files = ( + bsd_glob("makefile*"), + bsd_glob("*.{h,c,sh,pl}"), + bsd_glob("*/*.{h,c,sh,pl}"), + ); + + my $fails = 0; + for my $file (sort @all_files) { + my $troubles = {}; + my $lineno = 1; + my $content = read_file($file); + $content = sanitize_comments $content; + push @{$troubles->{crlf_line_end}}, '?' if $content =~ /\r/; + for my $l (split /\n/, $content) { + push @{$troubles->{merge_conflict}}, $lineno if $l =~ /^(<<<<<<<|=======|>>>>>>>)([^<=>]|$)/; + push @{$troubles->{trailing_space}}, $lineno if $l =~ / $/; + push @{$troubles->{tab}}, $lineno if $l =~ /\t/ && basename($file) !~ /^makefile/i; + push @{$troubles->{non_ascii_char}}, $lineno if $l =~ /[^[:ascii:]]/; + push @{$troubles->{cpp_comment}}, $lineno if $file =~ /\.(c|h)$/ && ($l =~ /\s\/\// || $l =~ /\/\/\s/); + # we prefer using XMALLOC, XFREE, XREALLOC, XCALLOC ... + push @{$troubles->{unwanted_malloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmalloc\s*\(/; + push @{$troubles->{unwanted_realloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\brealloc\s*\(/; + push @{$troubles->{unwanted_calloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bcalloc\s*\(/; + push @{$troubles->{unwanted_free}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bfree\s*\(/; + # and we probably want to also avoid the following + push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/; + push @{$troubles->{unwanted_memset}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemset\s*\(/; + push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/; + push @{$troubles->{unwanted_memmove}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemmove\s*\(/; + push @{$troubles->{unwanted_memcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcmp\s*\(/; + push @{$troubles->{unwanted_strcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcmp\s*\(/; + push @{$troubles->{unwanted_strcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcpy\s*\(/; + push @{$troubles->{unwanted_strncpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrncpy\s*\(/; + push @{$troubles->{unwanted_clock}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bclock\s*\(/; + push @{$troubles->{unwanted_qsort}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bqsort\s*\(/; + push @{$troubles->{sizeof_no_brackets}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bsizeof\s*[^\(]/; + if ($file =~ m|^[^\/]+\.c$| && $l =~ /^static(\s+[a-zA-Z0-9_]+)+\s+([a-zA-Z0-9_]+)\s*\(/) { + my $funcname = $2; + # static functions should start with s_ + push @{$troubles->{staticfunc_name}}, "$lineno($funcname)" if $funcname !~ /^s_/; + } + $lineno++; + } + for my $k (sort keys %$troubles) { + warn "[$k] $file line:" . join(",", @{$troubles->{$k}}) . "\n"; + $fails++; + } + } + + warn( $fails > 0 ? "check-source: FAIL $fails\n" : "check-source: PASS\n" ); + return $fails; +} + +sub check_comments { + my $fails = 0; + my $first_comment = <<'MARKER'; +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +MARKER + #my @all_files = (bsd_glob("*.{h,c}"), bsd_glob("*/*.{h,c}")); + my @all_files = (bsd_glob("*.{h,c}")); + for my $f (@all_files) { + my $txt = read_file($f); + if ($txt !~ /\Q$first_comment\E/s) { + warn "[first_comment] $f\n"; + $fails++; + } + } + warn( $fails > 0 ? "check-comments: FAIL $fails\n" : "check-comments: PASS\n" ); + return $fails; +} + +sub check_doc { + my $fails = 0; + my $tex = read_file('doc/bn.tex'); + my $tmh = read_file('tommath.h'); + my @functions = $tmh =~ /\n\s*[a-zA-Z0-9_* ]+?(mp_[a-z0-9_]+)\s*\([^\)]+\)\s*;/sg; + my @macros = $tmh =~ /\n\s*#define\s+([a-z0-9_]+)\s*\([^\)]+\)/sg; + for my $n (sort @functions) { + (my $nn = $n) =~ s/_/\\_/g; # mp_sub_d >> mp\_sub\_d + if ($tex !~ /index\Q{$nn}\E/) { + warn "[missing_doc_for_function] $n\n"; + $fails++ + } + } + for my $n (sort @macros) { + (my $nn = $n) =~ s/_/\\_/g; # mp_iszero >> mp\_iszero + if ($tex !~ /index\Q{$nn}\E/) { + warn "[missing_doc_for_macro] $n\n"; + $fails++ + } + } + warn( $fails > 0 ? "check_doc: FAIL $fails\n" : "check-doc: PASS\n" ); + return $fails; +} + +sub prepare_variable { + my ($varname, @list) = @_; + my $output = "$varname="; + my $len = length($output); + foreach my $obj (sort @list) { + $len = $len + length $obj; + $obj =~ s/\*/\$/; + if ($len > 100) { + $output .= "\\\n"; + $len = length $obj; + } + $output .= $obj . ' '; + } + $output =~ s/ $//; + return $output; +} + +sub prepare_msvc_files_xml { + my ($all, $exclude_re, $targets) = @_; + my $last = []; + my $depth = 2; + + # sort files in the same order as visual studio (ugly, I know) + my @parts = (); + for my $orig (@$all) { + my $p = $orig; + $p =~ s|/|/~|g; + $p =~ s|/~([^/]+)$|/$1|g; + my @l = map { sprintf "% -99s", $_ } split /\//, $p; + push @parts, [ $orig, join(':', @l) ]; + } + my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } @parts; + + my $files = "\r\n"; + for my $full (@sorted) { + my @items = split /\//, $full; # split by '/' + $full =~ s|/|\\|g; # replace '/' bt '\' + shift @items; # drop first one (src) + pop @items; # drop last one (filename.ext) + my $current = \@items; + if (join(':', @$current) ne join(':', @$last)) { + my $common = 0; + $common++ while ($last->[$common] && $current->[$common] && $last->[$common] eq $current->[$common]); + my $back = @$last - $common; + if ($back > 0) { + $files .= ("\t" x --$depth) . "\r\n" for (1..$back); + } + my $fwd = [ @$current ]; splice(@$fwd, 0, $common); + for my $i (0..scalar(@$fwd) - 1) { + $files .= ("\t" x $depth) . "[$i]\"\r\n"; + $files .= ("\t" x $depth) . "\t>\r\n"; + $depth++; + } + $last = $current; + } + $files .= ("\t" x $depth) . "\r\n"; + if ($full =~ $exclude_re) { + for (@$targets) { + $files .= ("\t" x $depth) . "\t\r\n"; + $files .= ("\t" x $depth) . "\t\t\r\n"; + $files .= ("\t" x $depth) . "\t\r\n"; + } + } + $files .= ("\t" x $depth) . "\r\n"; + } + $files .= ("\t" x --$depth) . "\r\n" for (@$last); + $files .= "\t"; + return $files; +} + +sub patch_file { + my ($content, @variables) = @_; + for my $v (@variables) { + if ($v =~ /^([A-Z0-9_]+)\s*=.*$/si) { + my $name = $1; + $content =~ s/\n\Q$name\E\b.*?[^\\]\n/\n$v\n/s; + } + else { + die "patch_file failed: " . substr($v, 0, 30) . ".."; + } + } + return $content; +} + +sub process_makefiles { + my $write = shift; + my $changed_count = 0; + my @o = map { my $x = $_; $x =~ s/\.c$/.o/; $x } bsd_glob("*.c"); + my @all = bsd_glob("*.{c,h}"); + + my $var_o = prepare_variable("OBJECTS", @o); + (my $var_obj = $var_o) =~ s/\.o\b/.obj/sg; + + # update MSVC project files + my $msvc_files = prepare_msvc_files_xml(\@all, qr/NOT_USED_HERE/, ['Debug|Win32', 'Release|Win32', 'Debug|x64', 'Release|x64']); + for my $m (qw/libtommath_VS2008.vcproj/) { + my $old = read_file($m); + my $new = $old; + $new =~ s|.*|$msvc_files|s; + if ($old ne $new) { + write_file($m, $new) if $write; + warn "changed: $m\n"; + $changed_count++; + } + } + + # update OBJECTS + HEADERS in makefile* + for my $m (qw/ makefile makefile.shared makefile_include.mk makefile.msvc makefile.unix makefile.mingw /) { + my $old = read_file($m); + my $new = $m eq 'makefile.msvc' ? patch_file($old, $var_obj) + : patch_file($old, $var_o); + if ($old ne $new) { + write_file($m, $new) if $write; + warn "changed: $m\n"; + $changed_count++; + } + } + + if ($write) { + return 0; # no failures + } + else { + warn( $changed_count > 0 ? "check-makefiles: FAIL $changed_count\n" : "check-makefiles: PASS\n" ); + return $changed_count; + } +} + +sub draw_func +{ + my ($deplist, $depmap, $out, $indent, $funcslist) = @_; + my @funcs = split ',', $funcslist; + # try this if you want to have a look at a minimized version of the callgraph without all the trivial functions + #if ($deplist =~ /$funcs[0]/ || $funcs[0] =~ /BN_MP_(ADD|SUB|CLEAR|CLEAR_\S+|DIV|MUL|COPY|ZERO|GROW|CLAMP|INIT|INIT_\S+|SET|ABS|CMP|CMP_D|EXCH)_C/) { + if ($deplist =~ /$funcs[0]/) { + return $deplist; + } else { + $deplist = $deplist . $funcs[0]; + } + if ($indent == 0) { + } elsif ($indent >= 1) { + print {$out} '| ' x ($indent - 1) . '+--->'; + } + print {$out} $funcs[0] . "\n"; + shift @funcs; + my $olddeplist = $deplist; + foreach my $i (@funcs) { + $deplist = draw_func($deplist, $depmap, $out, $indent + 1, ${$depmap}{$i}) if exists ${$depmap}{$i}; + } + return $olddeplist; +} + +sub update_dep +{ + #open class file and write preamble + open(my $class, '>', 'tommath_class.h') or die "Couldn't open tommath_class.h for writing\n"; + print {$class} << 'EOS'; +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#if !(defined(LTM1) && defined(LTM2) && defined(LTM3)) +#define LTM_INSIDE +#if defined(LTM2) +# define LTM3 +#endif +#if defined(LTM1) +# define LTM2 +#endif +#define LTM1 +#if defined(LTM_ALL) +EOS + + foreach my $filename (glob 'bn*.c') { + my $define = $filename; + + print "Processing $filename\n"; + + # convert filename to upper case so we can use it as a define + $define =~ tr/[a-z]/[A-Z]/; + $define =~ tr/\./_/; + print {$class} "# define $define\n"; + + # now copy text and apply #ifdef as required + my $apply = 0; + open(my $src, '<', $filename); + open(my $out, '>', 'tmp'); + + # first line will be the #ifdef + my $line = <$src>; + if ($line =~ /include/) { + print {$out} $line; + } else { + print {$out} << "EOS"; +#include "tommath_private.h" +#ifdef $define +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +$line +EOS + $apply = 1; + } + while (<$src>) { + if ($_ !~ /tommath\.h/) { + print {$out} $_; + } + } + if ($apply == 1) { + print {$out} "#endif\n"; + } + close $src; + close $out; + + unlink $filename; + rename 'tmp', $filename; + } + print {$class} "#endif\n#endif\n"; + + # now do classes + my %depmap; + foreach my $filename (glob 'bn*.c') { + my $content; + if ($filename =~ "bn_deprecated.c") { + open(my $src, '<', $filename) or die "Can't open source file!\n"; + read $src, $content, -s $src; + close $src; + } else { + my $cc = $ENV{'CC'} || 'gcc'; + $content = `$cc -E -x c -DLTM_ALL $filename`; + $content =~ s/^# 1 "$filename".*?^# 2 "$filename"//ms; + } + + # convert filename to upper case so we can use it as a define + $filename =~ tr/[a-z]/[A-Z]/; + $filename =~ tr/\./_/; + + print {$class} "#if defined($filename)\n"; + my $list = $filename; + + # strip comments + $content =~ s{/\*.*?\*/}{}gs; + + # scan for mp_* and make classes + my @deps = (); + foreach my $line (split /\n/, $content) { + while ($line =~ /(fast_)?(s_)?mp\_[a-z_0-9]*((?=\;)|(?=\())|(?<=\()mp\_[a-z_0-9]*(?=\()/g) { + my $a = $&; + next if $a eq "mp_err"; + $a =~ tr/[a-z]/[A-Z]/; + $a = 'BN_' . $a . '_C'; + push @deps, $a; + } + } + @deps = sort(@deps); + foreach my $a (@deps) { + if ($list !~ /$a/) { + print {$class} "# define $a\n"; + } + $list = $list . ',' . $a; + } + $depmap{$filename} = $list; + + print {$class} "#endif\n\n"; + } + + print {$class} << 'EOS'; +#ifdef LTM_INSIDE +#undef LTM_INSIDE +#ifdef LTM3 +# define LTM_LAST +#endif + +#include "tommath_superclass.h" +#include "tommath_class.h" +#else +# define LTM_LAST +#endif +EOS + close $class; + + #now let's make a cool call graph... + + open(my $out, '>', 'callgraph.txt'); + foreach (sort keys %depmap) { + draw_func("", \%depmap, $out, 0, $depmap{$_}); + print {$out} "\n\n"; + } + close $out; + + return 0; +} + +sub generate_def { + my @files = split /\n/, `git ls-files`; + @files = grep(/\.c/, @files); + @files = map { my $x = $_; $x =~ s/^bn_|\.c$//g; $x; } @files; + @files = grep(!/mp_radix_smap/, @files); + + push(@files, qw(mp_set_int mp_set_long mp_set_long_long mp_get_int mp_get_long mp_get_long_long mp_init_set_int)); + + my $files = join("\n ", sort(grep(/^mp_/, @files))); + write_file "tommath.def", "; libtommath +; +; Use this command to produce a 32-bit .lib file, for use in any MSVC version +; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib +; Use this command to produce a 64-bit .lib file, for use in any MSVC version +; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib +; +EXPORTS + $files +"; + return 0; +} + +sub die_usage { + die <<"MARKER"; +usage: $0 -s OR $0 --check-source + $0 -o OR $0 --check-comments + $0 -m OR $0 --check-makefiles + $0 -a OR $0 --check-all + $0 -u OR $0 --update-files +MARKER +} + +GetOptions( "s|check-source" => \my $check_source, + "o|check-comments" => \my $check_comments, + "m|check-makefiles" => \my $check_makefiles, + "d|check-doc" => \my $check_doc, + "a|check-all" => \my $check_all, + "u|update-files" => \my $update_files, + "h|help" => \my $help + ) or die_usage; + +my $failure; +$failure ||= check_source() if $check_all || $check_source; +$failure ||= check_comments() if $check_all || $check_comments; +$failure ||= check_doc() if $check_doc; # temporarily excluded from --check-all +$failure ||= process_makefiles(0) if $check_all || $check_makefiles; +$failure ||= process_makefiles(1) if $update_files; +$failure ||= update_dep() if $update_files; +$failure ||= generate_def() if $update_files; + +die_usage unless defined $failure; +exit $failure ? 1 : 0; diff --git a/third_party/heimdal/lib/hcrypto/libtommath/libtommath.pc.in b/third_party/heimdal/lib/hcrypto/libtommath/libtommath.pc.in new file mode 100644 index 0000000..099b1cd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/libtommath.pc.in @@ -0,0 +1,10 @@ +prefix=@to-be-replaced@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: LibTomMath +Description: public domain library for manipulating large integer numbers +Version: @to-be-replaced@ +Libs: -L${libdir} -ltommath +Cflags: -I${includedir} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.sln b/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.sln new file mode 100644 index 0000000..6bfc159 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tommath", "libtommath_VS2008.vcproj", "{42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.ActiveCfg = Debug|Win32 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.Build.0 = Debug|Win32 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.ActiveCfg = Debug|x64 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.Build.0 = Debug|x64 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.ActiveCfg = Release|Win32 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.Build.0 = Release|Win32 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.ActiveCfg = Release|x64 + {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83B84178-7B4F-4B78-9C5D-17B8201D5B61} + EndGlobalSection +EndGlobal diff --git a/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.vcproj b/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.vcproj new file mode 100644 index 0000000..67cc89b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/libtommath_VS2008.vcproj @@ -0,0 +1,966 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/README b/third_party/heimdal/lib/hcrypto/libtommath/logs/README new file mode 100644 index 0000000..ea20c81 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/README @@ -0,0 +1,13 @@ +To use the pretty graphs you have to first build/run the ltmtest from the root directory of the package. +Todo this type + +make timing ; ltmtest + +in the root. It will run for a while [about ten minutes on most PCs] and produce a series of .log files in logs/. + +After doing that run "gnuplot graphs.dem" to make the PNGs. If you managed todo that all so far just open index.html to view +them all :-) + +Have fun + +Tom \ No newline at end of file diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/add.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/add.log new file mode 100644 index 0000000..0ed7b70 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/add.log @@ -0,0 +1,16 @@ + 480 48 + 960 61 + 1440 82 + 1920 97 + 2400 106 + 2880 112 + 3360 127 + 3840 130 + 4320 146 + 4800 157 + 5280 174 + 5760 185 + 6240 200 + 6720 214 + 7200 230 + 7680 244 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/addsub.png b/third_party/heimdal/lib/hcrypto/libtommath/logs/addsub.png new file mode 100644 index 0000000..b8ffef7 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/libtommath/logs/addsub.png differ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.log new file mode 100644 index 0000000..2e5ee30 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.log @@ -0,0 +1,7 @@ + 513 446633 + 769 1110301 + 1025 2414927 + 2049 14870787 + 2561 26299761 + 3073 44323310 + 4097 98934292 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.png b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.png new file mode 100644 index 0000000..27c53ee Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt.png differ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2k.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2k.log new file mode 100644 index 0000000..140b92f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2k.log @@ -0,0 +1,6 @@ + 521 533515 + 607 675230 + 1279 2560713 + 2203 7468422 + 3217 17314246 + 4253 33899969 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2kl.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2kl.log new file mode 100644 index 0000000..1dc495f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_2kl.log @@ -0,0 +1,3 @@ + 1024 2210287 + 2048 7940364 + 4096 35903891 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_dr.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_dr.log new file mode 100644 index 0000000..3752ea8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/expt_dr.log @@ -0,0 +1,7 @@ + 532 642330 + 784 1138699 + 1036 1972796 + 1540 3912241 + 2072 7075836 + 3080 16420867 + 4116 32477173 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/graphs.dem b/third_party/heimdal/lib/hcrypto/libtommath/logs/graphs.dem new file mode 100644 index 0000000..538e5c0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/graphs.dem @@ -0,0 +1,16 @@ +set terminal png +set ylabel "Cycles per Operation" +set xlabel "Operand size (bits)" + +set output "addsub.png" +plot 'add.log' smooth bezier title "Addition", 'sub.log' smooth bezier title "Subtraction" + +set output "mult.png" +plot 'sqr.log' smooth bezier title "Squaring (without Karatsuba)", 'sqr_kara.log' smooth bezier title "Squaring (Karatsuba)", 'mult.log' smooth bezier title "Multiplication (without Karatsuba)", 'mult_kara.log' smooth bezier title "Multiplication (Karatsuba)" + +set output "expt.png" +plot 'expt.log' smooth bezier title "Exptmod (Montgomery)", 'expt_dr.log' smooth bezier title "Exptmod (Dimminished Radix)", 'expt_2k.log' smooth bezier title "Exptmod (2k Reduction)" + +set output "invmod.png" +plot 'invmod.log' smooth bezier title "Modular Inverse" + diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/index.html b/third_party/heimdal/lib/hcrypto/libtommath/logs/index.html new file mode 100644 index 0000000..4b68c25 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/index.html @@ -0,0 +1,27 @@ + + +LibTomMath Log Plots + + + +

Addition and Subtraction

+
+
+ +

Multipliers

+
+
+ +

Exptmod

+
+
+ +

Modular Inverse

+
+
+ + + +/* $Source: /cvs/libtom/libtommath/logs/index.html,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.log new file mode 100644 index 0000000..7d22449 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.log @@ -0,0 +1,8 @@ + 240 58197 + 480 86617 + 720 255279 + 960 399626 + 1200 533330 + 1440 470046 + 1680 906754 + 1920 1132009 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.png b/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.png new file mode 100644 index 0000000..5c09e90 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/libtommath/logs/invmod.png differ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.log new file mode 100644 index 0000000..841b40b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.log @@ -0,0 +1,84 @@ + 240 114 + 360 182 + 480 273 + 600 364 + 717 471 + 840 597 + 960 737 + 1080 881 + 1196 1041 + 1318 1215 + 1438 1405 + 1559 1600 + 1679 1812 + 1800 2045 + 1918 2289 + 2040 2534 + 2160 2800 + 2280 3067 + 2397 3375 + 2520 3678 + 2640 4007 + 2759 4325 + 2880 4851 + 3000 5200 + 3117 5557 + 3239 5938 + 3356 6332 + 3480 6741 + 3600 7168 + 3720 7597 + 3840 8054 + 3960 8514 + 4079 8956 + 4198 9451 + 4320 9976 + 4440 10457 + 4560 10973 + 4679 11535 + 4797 12085 + 4920 12639 + 5040 13235 + 5160 13832 + 5279 14454 + 5400 15063 + 5519 15657 + 5640 16339 + 5760 16992 + 5879 17676 + 6000 18380 + 6120 18022 + 6237 18567 + 6360 19259 + 6479 19929 + 6599 20686 + 6719 21180 + 6840 22121 + 6960 22741 + 7080 23664 + 7200 24315 + 7320 25107 + 7439 25945 + 7560 26557 + 7680 27527 + 7799 28341 + 7920 30761 + 8040 31648 + 8159 32628 + 8280 33498 + 8400 34508 + 8520 33657 + 8640 34566 + 8758 35203 + 8878 36356 + 9000 37379 + 9119 38072 + 9240 39390 + 9360 48931 + 9475 66682 + 9600 72564 + 9719 51493 + 9840 52637 + 9960 48247 + 10080 49030 + 10195 50592 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.png b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.png new file mode 100644 index 0000000..9681183 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult.png differ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/mult_kara.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult_kara.log new file mode 100644 index 0000000..91b59cb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/mult_kara.log @@ -0,0 +1,84 @@ + 240 133 + 360 250 + 474 396 + 599 585 + 720 637 + 840 1045 + 960 1212 + 1080 1543 + 1196 1780 + 1320 2005 + 1436 2274 + 1560 2446 + 1680 1985 + 1800 2368 + 1920 2791 + 2038 3620 + 2160 3763 + 2278 3444 + 2400 4158 + 2516 5869 + 2640 6368 + 2753 5384 + 2876 7449 + 3000 6471 + 3114 8540 + 3240 7217 + 3360 9685 + 3476 6759 + 3599 8518 + 3714 8911 + 3840 12345 + 3960 9787 + 4079 11018 + 4196 12033 + 4319 12740 + 4440 12471 + 4558 15251 + 4678 13353 + 4798 15998 + 4920 13395 + 5040 13699 + 5160 14552 + 5280 14972 + 5400 15825 + 5520 16512 + 5639 17379 + 5757 17596 + 5879 18350 + 6000 18976 + 6115 19601 + 6240 20076 + 6354 20515 + 6480 21670 + 6600 22312 + 6716 22647 + 6839 23437 + 6960 24164 + 7080 24723 + 7199 25454 + 7320 26092 + 7440 26912 + 7557 27521 + 7677 28015 + 7800 28885 + 7919 29483 + 8040 30115 + 8160 31236 + 8280 31975 + 8400 30835 + 8520 31565 + 8639 32380 + 8760 32760 + 8879 33590 + 8996 34553 + 9119 35185 + 9239 36146 + 9358 36815 + 9480 39630 + 9596 43022 + 9720 41219 + 9840 41596 + 9960 42354 + 10080 43352 + 10200 43915 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr.log new file mode 100644 index 0000000..93234a1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr.log @@ -0,0 +1,84 @@ + 240 114 + 359 174 + 478 241 + 600 311 + 720 399 + 840 494 + 960 599 + 1080 799 + 1200 931 + 1320 911 + 1440 1016 + 1560 1143 + 1680 1281 + 1800 1459 + 1918 1617 + 2039 1763 + 2159 1913 + 2279 2071 + 2399 2240 + 2518 2412 + 2640 2600 + 2760 2792 + 2877 3008 + 2999 3220 + 3119 3405 + 3239 3637 + 3359 3859 + 3480 4094 + 3600 4328 + 3717 4571 + 3838 4840 + 3960 5098 + 4080 5349 + 4200 5617 + 4320 5891 + 4440 6147 + 4560 6444 + 4680 6745 + 4800 7057 + 4918 7317 + 5039 7637 + 5160 12833 + 5280 10098 + 5397 8666 + 5520 8999 + 5639 9376 + 5758 9727 + 5880 9996 + 6000 10427 + 6118 10868 + 6240 12218 + 6359 14010 + 6478 14838 + 6593 16135 + 6719 16503 + 6840 13267 + 6960 13648 + 7080 14118 + 7199 14525 + 7320 14803 + 7439 15378 + 7558 15871 + 7680 57530 + 7800 59550 + 7916 61091 + 8039 63004 + 8160 61136 + 8279 62803 + 8398 68671 + 8520 71001 + 8638 71537 + 8759 74757 + 8880 77164 + 9000 78963 + 9119 80982 + 9239 83142 + 9357 85292 + 9480 88190 + 9600 90343 + 9718 86710 + 9840 88818 + 9954 91034 + 10079 93350 + 10197 95592 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr_kara.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr_kara.log new file mode 100644 index 0000000..da10897 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/sqr_kara.log @@ -0,0 +1,84 @@ + 240 115 + 360 175 + 480 241 + 600 312 + 719 397 + 839 494 + 960 597 + 1080 696 + 1200 794 + 1320 908 + 1439 1022 + 1560 1141 + 1678 1284 + 1797 1461 + 1918 1590 + 2040 1764 + 2160 1911 + 2278 2072 + 2399 2263 + 2516 2425 + 2640 2627 + 2756 2809 + 2880 3017 + 3000 3220 + 3119 3413 + 3239 3627 + 3359 3864 + 3479 4087 + 3600 4327 + 3720 4603 + 3840 4867 + 3957 5095 + 4079 5079 + 4200 5623 + 4319 5878 + 4439 6177 + 4560 6467 + 4679 6749 + 4800 7056 + 4920 7384 + 5039 7681 + 5159 8004 + 5280 8332 + 5399 8664 + 5520 8929 + 5638 9340 + 5760 9631 + 5879 10109 + 5999 10458 + 6118 10816 + 6240 11215 + 6359 11550 + 6478 11958 + 6600 12390 + 6718 12801 + 6838 13197 + 6959 13609 + 7079 14033 + 7199 16182 + 7320 16539 + 7440 16952 + 7559 16255 + 7679 17593 + 7800 17107 + 7920 17362 + 8037 17723 + 8159 18072 + 8280 19804 + 8399 18966 + 8519 19510 + 8640 19958 + 8760 20364 + 8878 20674 + 9000 21682 + 9120 21665 + 9237 21945 + 9359 22394 + 9480 23105 + 9598 23334 + 9718 25301 + 9840 26053 + 9960 26565 + 10079 26812 + 10200 27300 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/logs/sub.log b/third_party/heimdal/lib/hcrypto/libtommath/logs/sub.log new file mode 100644 index 0000000..87c0160 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/logs/sub.log @@ -0,0 +1,16 @@ + 480 36 + 960 51 + 1440 64 + 1920 78 + 2400 90 + 2880 105 + 3360 118 + 3840 133 + 4320 146 + 4800 161 + 5280 182 + 5760 201 + 6240 201 + 6720 214 + 7200 228 + 7680 243 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile b/third_party/heimdal/lib/hcrypto/libtommath/makefile new file mode 100644 index 0000000..be9fac6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile @@ -0,0 +1,165 @@ +#Makefile for GCC +# +#Tom St Denis + +ifeq ($V,1) +silent= +else +silent=@ +endif + +#default files to install +ifndef LIBNAME + LIBNAME=libtommath.a +endif + +coverage: LIBNAME:=-Wl,--whole-archive $(LIBNAME) -Wl,--no-whole-archive + +include makefile_include.mk + +%.o: %.c $(HEADERS) +ifneq ($V,1) + @echo " * ${CC} $@" +endif + ${silent} ${CC} -c ${LTM_CFLAGS} $< -o $@ + +LCOV_ARGS=--directory . + +#START_INS +OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \ +bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \ +bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \ +bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \ +bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \ +bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \ +bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \ +bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \ +bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \ +bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \ +bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \ +bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ +bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \ +bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \ +bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \ +bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \ +bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \ +bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o + +#END_INS + +$(LIBNAME): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ + +#make a profiled library (takes a while!!!) +# +# This will build the library with profile generation +# then run the test demo and rebuild the library. +# +# So far I've seen improvements in the MP math +profiled: + make CFLAGS="$(CFLAGS) -fprofile-arcs -DTESTING" timing + ./timing + rm -f *.a *.o timing + make CFLAGS="$(CFLAGS) -fbranch-probabilities" + +#make a single object profiled library +profiled_single: + perl gen.pl + $(CC) $(LTM_CFLAGS) -fprofile-arcs -DTESTING -c mpi.c -o mpi.o + $(CC) $(LTM_CFLAGS) -DTESTING -DTIMER demo/timing.c mpi.o -lgcov -o timing + ./timing + rm -f *.o timing + $(CC) $(LTM_CFLAGS) -fbranch-probabilities -DTESTING -c mpi.c -o mpi.o + $(AR) $(ARFLAGS) $(LIBNAME) mpi.o + ranlib $(LIBNAME) + +install: $(LIBNAME) + install -d $(DESTDIR)$(LIBPATH) + install -d $(DESTDIR)$(INCPATH) + install -m 644 $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -m 644 $(HEADERS_PUB) $(DESTDIR)$(INCPATH) + +uninstall: + rm $(DESTDIR)$(LIBPATH)/$(LIBNAME) + rm $(HEADERS_PUB:%=$(DESTDIR)$(INCPATH)/%) + +test_standalone: test + @echo "test_standalone is deprecated, please use make-target 'test'" + +DEMOS=test mtest_opponent + +define DEMO_template +$(1): demo/$(1).o demo/shared.o $$(LIBNAME) + $$(CC) $$(LTM_CFLAGS) $$(LTM_LFLAGS) $$^ -o $$@ +endef + +$(foreach demo, $(strip $(DEMOS)), $(eval $(call DEMO_template,$(demo)))) + +.PHONY: mtest +mtest: + cd mtest ; $(CC) $(LTM_CFLAGS) -O0 mtest.c $(LTM_LFLAGS) -o mtest + +timing: $(LIBNAME) demo/timing.c + $(CC) $(LTM_CFLAGS) -DTIMER demo/timing.c $(LIBNAME) $(LTM_LFLAGS) -o timing + +tune: $(LIBNAME) + $(MAKE) -C etc tune CFLAGS="$(LTM_CFLAGS)" + $(MAKE) + +# You have to create a file .coveralls.yml with the content "repo_token: " +# in the base folder to be able to submit to coveralls +coveralls: lcov + coveralls-lcov + +docs manual: + $(MAKE) -C doc/ $@ V=$(V) + +.PHONY: pre_gen +pre_gen: + mkdir -p pre_gen + perl gen.pl + sed -e 's/[[:blank:]]*$$//' mpi.c > pre_gen/mpi.c + rm mpi.c + +zipup: clean astyle new_file docs + @# Update the index, so diff-index won't fail in case the pdf has been created. + @# As the pdf creation modifies the tex files, git sometimes detects the + @# modified files, but misses that it's put back to its original version. + @git update-index --refresh + @git diff-index --quiet HEAD -- || ( echo "FAILURE: uncommited changes or not a git" && exit 1 ) + rm -rf libtommath-$(VERSION) ltm-$(VERSION).* + @# files/dirs excluded from "git archive" are defined in .gitattributes + git archive --format=tar --prefix=libtommath-$(VERSION)/ HEAD | tar x + @echo 'fixme check' + -@(find libtommath-$(VERSION)/ -type f | xargs grep 'FIXM[E]') && echo '############## BEWARE: the "fixme" marker was found !!! ##############' || true + mkdir -p libtommath-$(VERSION)/doc + cp doc/bn.pdf libtommath-$(VERSION)/doc/ + $(MAKE) -C libtommath-$(VERSION)/ pre_gen + tar -c libtommath-$(VERSION)/ | xz -6e -c - > ltm-$(VERSION).tar.xz + zip -9rq ltm-$(VERSION).zip libtommath-$(VERSION) + cp doc/bn.pdf bn-$(VERSION).pdf + rm -rf libtommath-$(VERSION) + gpg -b -a ltm-$(VERSION).tar.xz + gpg -b -a ltm-$(VERSION).zip + +new_file: + perl helper.pl --update-files + +perlcritic: + perlcritic *.pl doc/*.pl + +astyle: + @echo " * run astyle on all sources" + @astyle --options=astylerc --formatted $(OBJECTS:.o=.c) tommath*.h demo/*.c etc/*.c mtest/mtest.c diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile.mingw b/third_party/heimdal/lib/hcrypto/libtommath/makefile.mingw new file mode 100644 index 0000000..7eee57d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile.mingw @@ -0,0 +1,109 @@ +# MAKEFILE for MS Windows (mingw + gcc + gmake) +# +# BEWARE: variable OBJECTS is updated via helper.pl + +### USAGE: +# Open a command prompt with gcc + gmake in PATH and start: +# +# gmake -f makefile.mingw all +# test.exe +# gmake -f makefile.mingw PREFIX=c:\devel\libtom install + +#The following can be overridden from command line e.g. make -f makefile.mingw CC=gcc ARFLAGS=rcs +PREFIX = c:\mingw +CC = gcc +AR = ar +ARFLAGS = r +RANLIB = ranlib +STRIP = strip +CFLAGS = -O2 +LDFLAGS = + +#Compilation flags +LTM_CFLAGS = -I. $(CFLAGS) +LTM_LDFLAGS = $(LDFLAGS) -static-libgcc + +#Libraries to be created +LIBMAIN_S =libtommath.a +LIBMAIN_I =libtommath.dll.a +LIBMAIN_D =libtommath.dll + +#List of objects to compile (all goes to libtommath.a) +OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \ +bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \ +bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \ +bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \ +bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \ +bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \ +bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \ +bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \ +bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \ +bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \ +bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \ +bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ +bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \ +bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \ +bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \ +bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \ +bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \ +bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o + +HEADERS_PUB=tommath.h +HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) + +#The default rule for make builds the libtommath.a library (static) +default: $(LIBMAIN_S) + +#Dependencies on *.h +$(OBJECTS): $(HEADERS) + +.c.o: + $(CC) $(LTM_CFLAGS) -c $< -o $@ + +#Create libtommath.a +$(LIBMAIN_S): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ + +#Create DLL + import library libtommath.dll.a +$(LIBMAIN_D) $(LIBMAIN_I): $(OBJECTS) + $(CC) -s -shared -o $(LIBMAIN_D) $^ -Wl,--enable-auto-import,--export-all -Wl,--out-implib=$(LIBMAIN_I) $(LTM_LDFLAGS) + $(STRIP) -S $(LIBMAIN_D) + +#Build test suite +test.exe: demo/shared.o demo/test.o $(LIBMAIN_S) + $(CC) $(LTM_CFLAGS) $(LTM_LDFLAGS) $^ -o $@ + @echo NOTICE: start the tests by launching test.exe + +test_standalone: test.exe + @echo test_standalone is deprecated, please use make-target 'test.exe' + +all: $(LIBMAIN_S) test.exe + +tune: $(LIBNAME_S) + $(MAKE) -C etc tune + $(MAKE) + +clean: + @-cmd /c del /Q /S *.o *.a *.exe *.dll 2>nul + +#Install the library + headers +install: $(LIBMAIN_S) $(LIBMAIN_I) $(LIBMAIN_D) + cmd /c if not exist "$(PREFIX)\bin" mkdir "$(PREFIX)\bin" + cmd /c if not exist "$(PREFIX)\lib" mkdir "$(PREFIX)\lib" + cmd /c if not exist "$(PREFIX)\include" mkdir "$(PREFIX)\include" + copy /Y $(LIBMAIN_S) "$(PREFIX)\lib" + copy /Y $(LIBMAIN_I) "$(PREFIX)\lib" + copy /Y $(LIBMAIN_D) "$(PREFIX)\bin" + copy /Y tommath*.h "$(PREFIX)\include" diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile.msvc b/third_party/heimdal/lib/hcrypto/libtommath/makefile.msvc new file mode 100644 index 0000000..aa8d8be --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile.msvc @@ -0,0 +1,93 @@ +# MAKEFILE for MS Windows (nmake + Windows SDK) +# +# BEWARE: variable OBJECTS is updated via helper.pl + +### USAGE: +# Open a command prompt with WinSDK variables set and start: +# +# nmake -f makefile.msvc all +# test.exe +# nmake -f makefile.msvc PREFIX=c:\devel\libtom install + +#The following can be overridden from command line e.g. make -f makefile.msvc CC=gcc ARFLAGS=rcs +PREFIX = c:\devel +CFLAGS = /Ox + +#Compilation flags +LTM_CFLAGS = /nologo /I./ /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D__STDC_WANT_SECURE_LIB__=1 /D_CRT_HAS_CXX17=0 /Wall /wd4146 /wd4127 /wd4668 /wd4710 /wd4711 /wd4820 /wd5045 /WX $(CFLAGS) +LTM_LDFLAGS = advapi32.lib + +#Libraries to be created (this makefile builds only static libraries) +LIBMAIN_S =tommath.lib + +#List of objects to compile (all goes to tommath.lib) +OBJECTS=bn_cutoffs.obj bn_deprecated.obj bn_mp_2expt.obj bn_mp_abs.obj bn_mp_add.obj bn_mp_add_d.obj bn_mp_addmod.obj \ +bn_mp_and.obj bn_mp_clamp.obj bn_mp_clear.obj bn_mp_clear_multi.obj bn_mp_cmp.obj bn_mp_cmp_d.obj bn_mp_cmp_mag.obj \ +bn_mp_cnt_lsb.obj bn_mp_complement.obj bn_mp_copy.obj bn_mp_count_bits.obj bn_mp_decr.obj bn_mp_div.obj bn_mp_div_2.obj \ +bn_mp_div_2d.obj bn_mp_div_3.obj bn_mp_div_d.obj bn_mp_dr_is_modulus.obj bn_mp_dr_reduce.obj bn_mp_dr_setup.obj \ +bn_mp_error_to_string.obj bn_mp_exch.obj bn_mp_expt_u32.obj bn_mp_exptmod.obj bn_mp_exteuclid.obj bn_mp_fread.obj \ +bn_mp_from_sbin.obj bn_mp_from_ubin.obj bn_mp_fwrite.obj bn_mp_gcd.obj bn_mp_get_double.obj bn_mp_get_i32.obj \ +bn_mp_get_i64.obj bn_mp_get_l.obj bn_mp_get_ll.obj bn_mp_get_mag_u32.obj bn_mp_get_mag_u64.obj bn_mp_get_mag_ul.obj \ +bn_mp_get_mag_ull.obj bn_mp_grow.obj bn_mp_incr.obj bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_i32.obj \ +bn_mp_init_i64.obj bn_mp_init_l.obj bn_mp_init_ll.obj bn_mp_init_multi.obj bn_mp_init_set.obj bn_mp_init_size.obj \ +bn_mp_init_u32.obj bn_mp_init_u64.obj bn_mp_init_ul.obj bn_mp_init_ull.obj bn_mp_invmod.obj bn_mp_is_square.obj \ +bn_mp_iseven.obj bn_mp_isodd.obj bn_mp_kronecker.obj bn_mp_lcm.obj bn_mp_log_u32.obj bn_mp_lshd.obj bn_mp_mod.obj \ +bn_mp_mod_2d.obj bn_mp_mod_d.obj bn_mp_montgomery_calc_normalization.obj bn_mp_montgomery_reduce.obj \ +bn_mp_montgomery_setup.obj bn_mp_mul.obj bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj bn_mp_mulmod.obj bn_mp_neg.obj \ +bn_mp_or.obj bn_mp_pack.obj bn_mp_pack_count.obj bn_mp_prime_fermat.obj bn_mp_prime_frobenius_underwood.obj \ +bn_mp_prime_is_prime.obj bn_mp_prime_miller_rabin.obj bn_mp_prime_next_prime.obj \ +bn_mp_prime_rabin_miller_trials.obj bn_mp_prime_rand.obj bn_mp_prime_strong_lucas_selfridge.obj \ +bn_mp_radix_size.obj bn_mp_radix_smap.obj bn_mp_rand.obj bn_mp_read_radix.obj bn_mp_reduce.obj bn_mp_reduce_2k.obj \ +bn_mp_reduce_2k_l.obj bn_mp_reduce_2k_setup.obj bn_mp_reduce_2k_setup_l.obj bn_mp_reduce_is_2k.obj \ +bn_mp_reduce_is_2k_l.obj bn_mp_reduce_setup.obj bn_mp_root_u32.obj bn_mp_rshd.obj bn_mp_sbin_size.obj bn_mp_set.obj \ +bn_mp_set_double.obj bn_mp_set_i32.obj bn_mp_set_i64.obj bn_mp_set_l.obj bn_mp_set_ll.obj bn_mp_set_u32.obj \ +bn_mp_set_u64.obj bn_mp_set_ul.obj bn_mp_set_ull.obj bn_mp_shrink.obj bn_mp_signed_rsh.obj bn_mp_sqr.obj \ +bn_mp_sqrmod.obj bn_mp_sqrt.obj bn_mp_sqrtmod_prime.obj bn_mp_sub.obj bn_mp_sub_d.obj bn_mp_submod.obj \ +bn_mp_to_radix.obj bn_mp_to_sbin.obj bn_mp_to_ubin.obj bn_mp_ubin_size.obj bn_mp_unpack.obj bn_mp_xor.obj bn_mp_zero.obj \ +bn_prime_tab.obj bn_s_mp_add.obj bn_s_mp_balance_mul.obj bn_s_mp_exptmod.obj bn_s_mp_exptmod_fast.obj \ +bn_s_mp_get_bit.obj bn_s_mp_invmod_fast.obj bn_s_mp_invmod_slow.obj bn_s_mp_karatsuba_mul.obj \ +bn_s_mp_karatsuba_sqr.obj bn_s_mp_montgomery_reduce_fast.obj bn_s_mp_mul_digs.obj bn_s_mp_mul_digs_fast.obj \ +bn_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs_fast.obj bn_s_mp_prime_is_divisible.obj \ +bn_s_mp_rand_jenkins.obj bn_s_mp_rand_platform.obj bn_s_mp_reverse.obj bn_s_mp_sqr.obj bn_s_mp_sqr_fast.obj \ +bn_s_mp_sub.obj bn_s_mp_toom_mul.obj bn_s_mp_toom_sqr.obj + +HEADERS_PUB=tommath.h +HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) + +#The default rule for make builds the tommath.lib library (static) +default: $(LIBMAIN_S) + +#Dependencies on *.h +$(OBJECTS): $(HEADERS) + +.c.obj: + $(CC) $(LTM_CFLAGS) /c $< /Fo$@ + +#Create tommath.lib +$(LIBMAIN_S): $(OBJECTS) + lib /out:$(LIBMAIN_S) $(OBJECTS) + +#Build test suite +test.exe: $(LIBMAIN_S) demo/shared.obj demo/test.obj + cl $(LTM_CFLAGS) $(TOBJECTS) $(LIBMAIN_S) $(LTM_LDFLAGS) demo/shared.c demo/test.c /Fe$@ + @echo NOTICE: start the tests by launching test.exe + +test_standalone: test.exe + @echo test_standalone is deprecated, please use make-target 'test.exe' + +all: $(LIBMAIN_S) test.exe + +tune: $(LIBMAIN_S) + $(MAKE) -C etc tune + $(MAKE) + +clean: + @-cmd /c del /Q /S *.OBJ *.LIB *.EXE *.DLL 2>nul + +#Install the library + headers +install: $(LIBMAIN_S) + cmd /c if not exist "$(PREFIX)\bin" mkdir "$(PREFIX)\bin" + cmd /c if not exist "$(PREFIX)\lib" mkdir "$(PREFIX)\lib" + cmd /c if not exist "$(PREFIX)\include" mkdir "$(PREFIX)\include" + copy /Y $(LIBMAIN_S) "$(PREFIX)\lib" + copy /Y tommath*.h "$(PREFIX)\include" diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile.shared b/third_party/heimdal/lib/hcrypto/libtommath/makefile.shared new file mode 100644 index 0000000..6802107 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile.shared @@ -0,0 +1,99 @@ +#Makefile for GCC +# +#Tom St Denis + +#default files to install +ifndef LIBNAME + LIBNAME=libtommath.la +endif + +include makefile_include.mk + + +ifndef LIBTOOL + ifeq ($(PLATFORM), Darwin) + LIBTOOL:=glibtool + else + LIBTOOL:=libtool + endif +endif +LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) +LTLINK = $(LIBTOOL) --mode=link --tag=CC $(CC) + +LCOV_ARGS=--directory .libs --directory . + +#START_INS +OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \ +bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \ +bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \ +bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \ +bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \ +bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \ +bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \ +bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \ +bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \ +bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \ +bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \ +bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ +bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \ +bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \ +bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \ +bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \ +bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \ +bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o + +#END_INS + +objs: $(OBJECTS) + +.c.o: $(HEADERS) + $(LTCOMPILE) $(LTM_CFLAGS) $(LTM_LDFLAGS) -o $@ -c $< + +LOBJECTS = $(OBJECTS:.o=.lo) + +$(LIBNAME): $(OBJECTS) + $(LTLINK) $(LTM_LDFLAGS) $(LOBJECTS) -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION_SO) $(LTM_LIBTOOLFLAGS) + +install: $(LIBNAME) + install -d $(DESTDIR)$(LIBPATH) + install -d $(DESTDIR)$(INCPATH) + $(LIBTOOL) --mode=install install -m 644 $(LIBNAME) $(DESTDIR)$(LIBPATH)/$(LIBNAME) + install -m 644 $(HEADERS_PUB) $(DESTDIR)$(INCPATH) + sed -e 's,^prefix=.*,prefix=$(PREFIX),' -e 's,^Version:.*,Version: $(VERSION_PC),' libtommath.pc.in > libtommath.pc + install -d $(DESTDIR)$(LIBPATH)/pkgconfig + install -m 644 libtommath.pc $(DESTDIR)$(LIBPATH)/pkgconfig/ + +uninstall: + $(LIBTOOL) --mode=uninstall rm $(DESTDIR)$(LIBPATH)/$(LIBNAME) + rm $(HEADERS_PUB:%=$(DESTDIR)$(INCPATH)/%) + rm $(DESTDIR)$(LIBPATH)/pkgconfig/libtommath.pc + +test_standalone: test + @echo "test_standalone is deprecated, please use make-target 'test'" + +test mtest_opponent: demo/shared.o $(LIBNAME) | demo/test.o demo/mtest_opponent.o + $(LTLINK) $(LTM_LDFLAGS) demo/$@.o $^ -o $@ + +.PHONY: mtest +mtest: + cd mtest ; $(CC) $(LTM_CFLAGS) -O0 mtest.c $(LTM_LDFLAGS) -o mtest + +timing: $(LIBNAME) demo/timing.c + $(LTLINK) $(LTM_CFLAGS) $(LTM_LDFLAGS) -DTIMER demo/timing.c $(LIBNAME) -o timing + +tune: $(LIBNAME) + $(LTCOMPILE) $(LTM_CFLAGS) -c etc/tune.c -o etc/tune.o + $(LTLINK) $(LTM_LDFLAGS) -o etc/tune etc/tune.o $(LIBNAME) + cd etc/; /bin/sh tune_it.sh; cd .. + $(MAKE) -f makefile.shared diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile.unix b/third_party/heimdal/lib/hcrypto/libtommath/makefile.unix new file mode 100644 index 0000000..4cefc7e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile.unix @@ -0,0 +1,106 @@ +# MAKEFILE that is intended to be compatible with any kind of make (GNU make, BSD make, ...) +# works on: Linux, *BSD, Cygwin, AIX, HP-UX and hopefully other UNIX systems +# +# Please do not use here neither any special make syntax nor any unusual tools/utilities! + +# using ICC compiler: +# make -f makefile.unix CC=icc CFLAGS="-O3 -xP -ip" + +# using Borland C++Builder: +# make -f makefile.unix CC=bcc32 + +#The following can be overridden from command line e.g. "make -f makefile.unix CC=gcc ARFLAGS=rcs" +DESTDIR = +PREFIX = /usr/local +LIBPATH = $(PREFIX)/lib +INCPATH = $(PREFIX)/include +CC = cc +AR = ar +ARFLAGS = r +RANLIB = ranlib +CFLAGS = -O2 +LDFLAGS = + +VERSION = 1.2.0 + +#Compilation flags +LTM_CFLAGS = -I. $(CFLAGS) +LTM_LDFLAGS = $(LDFLAGS) + +#Library to be created (this makefile builds only static library) +LIBMAIN_S = libtommath.a + +OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \ +bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \ +bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \ +bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \ +bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \ +bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \ +bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \ +bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \ +bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \ +bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \ +bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \ +bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ +bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \ +bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \ +bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \ +bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \ +bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \ +bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \ +bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \ +bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \ +bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \ +bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \ +bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \ +bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o + +HEADERS_PUB=tommath.h +HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) + +#The default rule for make builds the libtommath.a library (static) +default: $(LIBMAIN_S) + +#Dependencies on *.h +$(OBJECTS): $(HEADERS) + +#This is necessary for compatibility with BSD make (namely on OpenBSD) +.SUFFIXES: .o .c +.c.o: + $(CC) $(LTM_CFLAGS) -c $< -o $@ + +#Create libtommath.a +$(LIBMAIN_S): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ + +#Build test_standalone suite +test: demo/shared.o demo/test.o $(LIBMAIN_S) + $(CC) $(LTM_CFLAGS) $(LTM_LDFLAGS) $^ -o $@ + @echo "NOTICE: start the tests by: ./test" + +test_standalone: test + @echo "test_standalone is deprecated, please use make-target 'test'" + +all: $(LIBMAIN_S) test + +tune: $(LIBMAIN_S) + $(MAKE) -C etc tune + $(MAKE) + +#NOTE: this makefile works also on cygwin, thus we need to delete *.exe +clean: + -@rm -f $(OBJECTS) $(LIBMAIN_S) + -@rm -f demo/main.o demo/opponent.o demo/test.o test test.exe + +#Install the library + headers +install: $(LIBMAIN_S) + @mkdir -p $(DESTDIR)$(INCPATH) $(DESTDIR)$(LIBPATH)/pkgconfig + @cp $(LIBMAIN_S) $(DESTDIR)$(LIBPATH)/ + @cp $(HEADERS_PUB) $(DESTDIR)$(INCPATH)/ + @sed -e 's,^prefix=.*,prefix=$(PREFIX),' -e 's,^Version:.*,Version: $(VERSION),' libtommath.pc.in > $(DESTDIR)$(LIBPATH)/pkgconfig/libtommath.pc diff --git a/third_party/heimdal/lib/hcrypto/libtommath/makefile_include.mk b/third_party/heimdal/lib/hcrypto/libtommath/makefile_include.mk new file mode 100644 index 0000000..7b025e8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/makefile_include.mk @@ -0,0 +1,166 @@ +# +# Include makefile for libtommath +# + +#version of library +VERSION=1.2.0 +VERSION_PC=1.2.0 +VERSION_SO=3:0:2 + +PLATFORM := $(shell uname | sed -e 's/_.*//') + +# default make target +default: ${LIBNAME} + +# Compiler and Linker Names +ifndef CROSS_COMPILE + CROSS_COMPILE= +endif + +# We only need to go through this dance of determining the right compiler if we're using +# cross compilation, otherwise $(CC) is fine as-is. +ifneq (,$(CROSS_COMPILE)) +ifeq ($(origin CC),default) +CSTR := "\#ifdef __clang__\nCLANG\n\#endif\n" +ifeq ($(PLATFORM),FreeBSD) + # XXX: FreeBSD needs extra escaping for some reason + CSTR := $$$(CSTR) +endif +ifneq (,$(shell echo $(CSTR) | $(CC) -E - | grep CLANG)) + CC := $(CROSS_COMPILE)clang +else + CC := $(CROSS_COMPILE)gcc +endif # Clang +endif # cc is Make's default +endif # CROSS_COMPILE non-empty + +LD=$(CROSS_COMPILE)ld +AR=$(CROSS_COMPILE)ar +RANLIB=$(CROSS_COMPILE)ranlib + +ifndef MAKE +# BSDs refer to GNU Make as gmake +ifneq (,$(findstring $(PLATFORM),FreeBSD OpenBSD DragonFly NetBSD)) + MAKE=gmake +else + MAKE=make +endif +endif + +LTM_CFLAGS += -I./ -Wall -Wsign-compare -Wextra -Wshadow + +ifdef SANITIZER +LTM_CFLAGS += -fsanitize=undefined -fno-sanitize-recover=all -fno-sanitize=float-divide-by-zero +endif + +ifndef NO_ADDTL_WARNINGS +# additional warnings +LTM_CFLAGS += -Wdeclaration-after-statement -Wbad-function-cast -Wcast-align +LTM_CFLAGS += -Wstrict-prototypes -Wpointer-arith +endif + +ifdef CONV_WARNINGS +LTM_CFLAGS += -std=c89 -Wconversion -Wsign-conversion +ifeq ($(CONV_WARNINGS), strict) +LTM_CFLAGS += -DMP_USE_ENUMS -Wc++-compat +endif +else +LTM_CFLAGS += -Wsystem-headers +endif + +ifdef COMPILE_DEBUG +#debug +LTM_CFLAGS += -g3 +endif + +ifdef COMPILE_SIZE +#for size +LTM_CFLAGS += -Os +else + +ifndef IGNORE_SPEED +#for speed +LTM_CFLAGS += -O3 -funroll-loops + +#x86 optimizations [should be valid for any GCC install though] +LTM_CFLAGS += -fomit-frame-pointer +endif + +endif # COMPILE_SIZE + +ifneq ($(findstring clang,$(CC)),) +LTM_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header +endif +ifneq ($(findstring mingw,$(CC)),) +LTM_CFLAGS += -Wno-shadow +endif +ifeq ($(PLATFORM), Darwin) +LTM_CFLAGS += -Wno-nullability-completeness +endif +ifeq ($(PLATFORM), CYGWIN) +LIBTOOLFLAGS += -no-undefined +endif + +# add in the standard FLAGS +LTM_CFLAGS += $(CFLAGS) +LTM_LFLAGS += $(LFLAGS) +LTM_LDFLAGS += $(LDFLAGS) +LTM_LIBTOOLFLAGS += $(LIBTOOLFLAGS) + + +ifeq ($(PLATFORM),FreeBSD) + _ARCH := $(shell sysctl -b hw.machine_arch) +else + _ARCH := $(shell uname -m) +endif + +# adjust coverage set +ifneq ($(filter $(_ARCH), i386 i686 x86_64 amd64 ia64),) + COVERAGE = test_standalone timing + COVERAGE_APP = ./test && ./timing +else + COVERAGE = test_standalone + COVERAGE_APP = ./test +endif + +HEADERS_PUB=tommath.h +HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB) + +#LIBPATH The directory for libtommath to be installed to. +#INCPATH The directory to install the header files for libtommath. +#DATAPATH The directory to install the pdf docs. +DESTDIR ?= +PREFIX ?= /usr/local +LIBPATH ?= $(PREFIX)/lib +INCPATH ?= $(PREFIX)/include +DATAPATH ?= $(PREFIX)/share/doc/libtommath/pdf + +#make the code coverage of the library +# +coverage: LTM_CFLAGS += -fprofile-arcs -ftest-coverage -DTIMING_NO_LOGS +coverage: LTM_LFLAGS += -lgcov +coverage: LTM_LDFLAGS += -lgcov + +coverage: $(COVERAGE) + $(COVERAGE_APP) + +lcov: coverage + rm -f coverage.info + lcov --capture --no-external --no-recursion $(LCOV_ARGS) --output-file coverage.info -q + genhtml coverage.info --output-directory coverage -q + +# target that removes all coverage output +cleancov-clean: + rm -f `find . -type f -name "*.info" | xargs` + rm -rf coverage/ + +# cleans everything - coverage output and standard 'clean' +cleancov: cleancov-clean clean + +clean: + rm -f *.gcda *.gcno *.gcov *.bat *.o *.a *.obj *.lib *.exe *.dll etclib/*.o \ + demo/*.o test timing mtest_opponent mtest/mtest mtest/mtest.exe tuning_list \ + *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la + rm -rf .libs/ demo/.libs + ${MAKE} -C etc/ clean MAKE=${MAKE} + ${MAKE} -C doc/ clean MAKE=${MAKE} diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/logtab.h b/third_party/heimdal/lib/hcrypto/libtommath/mtest/logtab.h new file mode 100644 index 0000000..dae3344 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/logtab.h @@ -0,0 +1,24 @@ +const float s_logv_2[] = { + 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ + 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ + 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ + 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ + 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ + 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ + 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ + 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ + 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ + 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ + 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ + 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ + 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ + 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ + 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ + 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ + 0.166666667 +}; + + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-config.h b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-config.h new file mode 100644 index 0000000..ea576e5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-config.h @@ -0,0 +1,90 @@ +/* Default configuration for MPI library */ +/* $Id$ */ + +#ifndef MPI_CONFIG_H_ +#define MPI_CONFIG_H_ + +/* + For boolean options, + 0 = no + 1 = yes + + Other options are documented individually. + + */ + +#ifndef MP_IOFUNC +#define MP_IOFUNC 0 /* include mp_print() ? */ +#endif + +#ifndef MP_MODARITH +#define MP_MODARITH 1 /* include modular arithmetic ? */ +#endif + +#ifndef MP_NUMTH +#define MP_NUMTH 1 /* include number theoretic functions? */ +#endif + +#ifndef MP_LOGTAB +#define MP_LOGTAB 1 /* use table of logs instead of log()? */ +#endif + +#ifndef MP_MEMSET +#define MP_MEMSET 1 /* use memset() to zero buffers? */ +#endif + +#ifndef MP_MEMCPY +#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ +#endif + +#ifndef MP_CRYPTO +#define MP_CRYPTO 1 /* erase memory on free? */ +#endif + +#ifndef MP_ARGCHK +/* + 0 = no parameter checks + 1 = runtime checks, continue execution and return an error to caller + 2 = assertions; dump core on parameter errors + */ +#define MP_ARGCHK 2 /* how to check input arguments */ +#endif + +#ifndef MP_DEBUG +#define MP_DEBUG 0 /* print diagnostic output? */ +#endif + +#ifndef MP_DEFPREC +#define MP_DEFPREC 64 /* default precision, in digits */ +#endif + +#ifndef MP_MACRO +#define MP_MACRO 1 /* use macros for frequent calls? */ +#endif + +#ifndef MP_SQUARE +#define MP_SQUARE 1 /* use separate squaring code? */ +#endif + +#ifndef MP_PTAB_SIZE +/* + When building mpprime.c, we build in a table of small prime + values to use for primality testing. The more you include, + the more space they take up. See primes.c for the possible + values (currently 16, 32, 64, 128, 256, and 6542) + */ +#define MP_PTAB_SIZE 128 /* how many built-in primes? */ +#endif + +#ifndef MP_COMPAT_MACROS +#define MP_COMPAT_MACROS 1 /* define compatibility macros? */ +#endif + +#endif /* ifndef MPI_CONFIG_H_ */ + + +/* crc==3287762869, version==2, Sat Feb 02 06:43:53 2002 */ + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-types.h b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-types.h new file mode 100644 index 0000000..f99d7ee --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi-types.h @@ -0,0 +1,20 @@ +/* Type definitions generated by 'types.pl' */ +typedef char mp_sign; +typedef unsigned short mp_digit; /* 2 byte type */ +typedef unsigned int mp_word; /* 4 byte type */ +typedef unsigned int mp_size; +typedef int mp_err; + +#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) +#define MP_DIGIT_MAX USHRT_MAX +#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) +#define MP_WORD_MAX UINT_MAX + +#define MP_DIGIT_SIZE 2 +#define DIGIT_FMT "%04X" +#define RADIX (MP_DIGIT_MAX+1) + + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.c b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.c new file mode 100644 index 0000000..7e71ad6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.c @@ -0,0 +1,3987 @@ +/* + mpi.c + + by Michael J. Fromberger + Copyright (C) 1998 Michael J. Fromberger + + Arbitrary precision integer arithmetic library + + SPDX-License-Identifier: Unlicense + + $Id$ + */ + +#include "mpi.h" +#include +#include +#include + +#if MP_DEBUG +#include + +#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} +#else +#define DIAG(T,V) +#endif + +/* + If MP_LOGTAB is not defined, use the math library to compute the + logarithms on the fly. Otherwise, use the static table below. + Pick which works best for your system. + */ +#if MP_LOGTAB + +/* {{{ s_logv_2[] - log table for 2 in various bases */ + +/* + A table of the logs of 2 for various bases (the 0 and 1 entries of + this table are meaningless and should not be referenced). + + This table is used to compute output lengths for the mp_toradix() + function. Since a number n in radix r takes up about log_r(n) + digits, we estimate the output size by taking the least integer + greater than log_r(n), where: + + log_r(n) = log_2(n) * log_r(2) + + This table, therefore, is a table of log_r(2) for 2 <= r <= 36, + which are the output bases supported. + */ + +#include "logtab.h" + +/* }}} */ +#define LOG_V_2(R) s_logv_2[(R)] + +#else + +#include +#define LOG_V_2(R) (log(2.0)/log(R)) + +#endif + +/* Default precision for newly created mp_int's */ +static unsigned int s_mp_defprec = MP_DEFPREC; + +/* {{{ Digit arithmetic macros */ + +/* + When adding and multiplying digits, the results can be larger than + can be contained in an mp_digit. Thus, an mp_word is used. These + macros mask off the upper and lower digits of the mp_word (the + mp_word may be more than 2 mp_digits wide, but we only concern + ourselves with the low-order 2 mp_digits) + + If your mp_word DOES have more than 2 mp_digits, you need to + uncomment the first line, and comment out the second. + */ + +/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ +#define CARRYOUT(W) ((W)>>DIGIT_BIT) +#define ACCUM(W) ((W)&MP_DIGIT_MAX) + +/* }}} */ + +/* {{{ Comparison constants */ + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +/* }}} */ + +/* {{{ Constant strings */ + +/* Constant strings returned by mp_strerror() */ +static const char *mp_err_string[] = { + "unknown result code", /* say what? */ + "boolean true", /* MP_OKAY, MP_YES */ + "boolean false", /* MP_NO */ + "out of memory", /* MP_MEM */ + "argument out of range", /* MP_RANGE */ + "invalid input parameter", /* MP_BADARG */ + "result is undefined" /* MP_UNDEF */ +}; + +/* Value to digit maps for radix conversion */ + +/* s_dmap_1 - standard digits and letters */ +static const char *s_dmap_1 = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +#if 0 +/* s_dmap_2 - base64 ordering for digits */ +static const char *s_dmap_2 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#endif + +/* }}} */ + +/* {{{ Static function declarations */ + +/* + If MP_MACRO is false, these will be defined as actual functions; + otherwise, suitable macro definitions will be used. This works + around the fact that ANSI C89 doesn't support an 'inline' keyword + (although I hear C9x will ... about bloody time). At present, the + macro definitions are identical to the function bodies, but they'll + expand in place, instead of generating a function call. + + I chose these particular functions to be made into macros because + some profiling showed they are called a lot on a typical workload, + and yet they are primarily housekeeping. + */ +#if MP_MACRO == 0 + void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ + void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ + void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ + void s_mp_free(void *ptr); /* general free function */ +#else + + /* Even if these are defined as macros, we need to respect the settings + of the MP_MEMSET and MP_MEMCPY configuration options... + */ + #if MP_MEMSET == 0 + #define s_mp_setz(dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} + #else + #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) + #endif /* MP_MEMSET */ + + #if MP_MEMCPY == 0 + #define s_mp_copy(sp, dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} + #else + #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) + #endif /* MP_MEMCPY */ + + #define s_mp_alloc(nb, ni) calloc(nb, ni) + #define s_mp_free(ptr) {if(ptr) free(ptr);} +#endif /* MP_MACRO */ + +mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ +mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ + +void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ + +void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ +void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ +void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ +void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ +void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ +mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ +mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ +mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); + /* unsigned digit divide */ +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); + /* Barrett reduction */ +mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ +mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ +mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); + /* multiply buffers in place */ +#endif +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a); /* magnitude square */ +#else +#define s_mp_sqr(a) s_mp_mul(a, a) +#endif +mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ +mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ +int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ +int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ +int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ +int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ + +int s_mp_tovalue(char ch, int r); /* convert ch to value */ +char s_mp_todigit(int val, int r, int low); /* convert val to digit */ +int s_mp_outlen(int bits, int r); /* output length in bytes */ + +/* }}} */ + +/* {{{ Default precision manipulation */ + +unsigned int mp_get_prec(void) +{ + return s_mp_defprec; + +} /* end mp_get_prec() */ + +void mp_set_prec(unsigned int prec) +{ + if(prec == 0) + s_mp_defprec = MP_DEFPREC; + else + s_mp_defprec = prec; + +} /* end mp_set_prec() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_init(mp) */ + +/* + mp_init(mp) + + Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, + MP_MEM if memory could not be allocated for the structure. + */ + +mp_err mp_init(mp_int *mp) +{ + return mp_init_size(mp, s_mp_defprec); + +} /* end mp_init() */ + +/* }}} */ + +/* {{{ mp_init_array(mp[], count) */ + +mp_err mp_init_array(mp_int mp[], int count) +{ + mp_err res; + int pos; + + ARGCHK(mp !=NULL && count > 0, MP_BADARG); + + for(pos = 0; pos < count; ++pos) { + if((res = mp_init(&mp[pos])) != MP_OKAY) + goto CLEANUP; + } + + return MP_OKAY; + + CLEANUP: + while(--pos >= 0) + mp_clear(&mp[pos]); + + return res; + +} /* end mp_init_array() */ + +/* }}} */ + +/* {{{ mp_init_size(mp, prec) */ + +/* + mp_init_size(mp, prec) + + Initialize a new zero-valued mp_int with at least the given + precision; returns MP_OKAY if successful, or MP_MEM if memory could + not be allocated for the structure. + */ + +mp_err mp_init_size(mp_int *mp, mp_size prec) +{ + ARGCHK(mp != NULL && prec > 0, MP_BADARG); + + if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) + return MP_MEM; + + SIGN(mp) = MP_ZPOS; + USED(mp) = 1; + ALLOC(mp) = prec; + + return MP_OKAY; + +} /* end mp_init_size() */ + +/* }}} */ + +/* {{{ mp_init_copy(mp, from) */ + +/* + mp_init_copy(mp, from) + + Initialize mp as an exact copy of from. Returns MP_OKAY if + successful, MP_MEM if memory could not be allocated for the new + structure. + */ + +mp_err mp_init_copy(mp_int *mp, mp_int *from) +{ + ARGCHK(mp != NULL && from != NULL, MP_BADARG); + + if(mp == from) + return MP_OKAY; + + if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); + USED(mp) = USED(from); + ALLOC(mp) = USED(from); + SIGN(mp) = SIGN(from); + + return MP_OKAY; + +} /* end mp_init_copy() */ + +/* }}} */ + +/* {{{ mp_copy(from, to) */ + +/* + mp_copy(from, to) + + Copies the mp_int 'from' to the mp_int 'to'. It is presumed that + 'to' has already been initialized (if not, use mp_init_copy() + instead). If 'from' and 'to' are identical, nothing happens. + */ + +mp_err mp_copy(mp_int *from, mp_int *to) +{ + ARGCHK(from != NULL && to != NULL, MP_BADARG); + + if(from == to) + return MP_OKAY; + + { /* copy */ + mp_digit *tmp; + + /* + If the allocated buffer in 'to' already has enough space to hold + all the used digits of 'from', we'll re-use it to avoid hitting + the memory allocater more than necessary; otherwise, we'd have + to grow anyway, so we just allocate a hunk and make the copy as + usual + */ + if(ALLOC(to) >= USED(from)) { + s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); + s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); + + } else { + if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), tmp, USED(from)); + + if(DIGITS(to) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(to), ALLOC(to)); +#endif + s_mp_free(DIGITS(to)); + } + + DIGITS(to) = tmp; + ALLOC(to) = USED(from); + } + + /* Copy the precision and sign from the original */ + USED(to) = USED(from); + SIGN(to) = SIGN(from); + } /* end copy */ + + return MP_OKAY; + +} /* end mp_copy() */ + +/* }}} */ + +/* {{{ mp_exch(mp1, mp2) */ + +/* + mp_exch(mp1, mp2) + + Exchange mp1 and mp2 without allocating any intermediate memory + (well, unless you count the stack space needed for this call and the + locals it creates...). This cannot fail. + */ + +void mp_exch(mp_int *mp1, mp_int *mp2) +{ +#if MP_ARGCHK == 2 + assert(mp1 != NULL && mp2 != NULL); +#else + if(mp1 == NULL || mp2 == NULL) + return; +#endif + + s_mp_exch(mp1, mp2); + +} /* end mp_exch() */ + +/* }}} */ + +/* {{{ mp_clear(mp) */ + +/* + mp_clear(mp) + + Release the storage used by an mp_int, and void its fields so that + if someone calls mp_clear() again for the same int later, we won't + get tollchocked. + */ + +void mp_clear(mp_int *mp) +{ + if(mp == NULL) + return; + + if(DIGITS(mp) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = NULL; + } + + USED(mp) = 0; + ALLOC(mp) = 0; + +} /* end mp_clear() */ + +/* }}} */ + +/* {{{ mp_clear_array(mp[], count) */ + +void mp_clear_array(mp_int mp[], int count) +{ + ARGCHK(mp != NULL && count > 0, MP_BADARG); + + while(--count >= 0) + mp_clear(&mp[count]); + +} /* end mp_clear_array() */ + +/* }}} */ + +/* {{{ mp_zero(mp) */ + +/* + mp_zero(mp) + + Set mp to zero. Does not change the allocated size of the structure, + and therefore cannot fail (except on a bad argument, which we ignore) + */ +void mp_zero(mp_int *mp) +{ + if(mp == NULL) + return; + + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + +} /* end mp_zero() */ + +/* }}} */ + +/* {{{ mp_set(mp, d) */ + +void mp_set(mp_int *mp, mp_digit d) +{ + if(mp == NULL) + return; + + mp_zero(mp); + DIGIT(mp, 0) = d; + +} /* end mp_set() */ + +/* }}} */ + +/* {{{ mp_set_int(mp, z) */ + +mp_err mp_set_int(mp_int *mp, long z) +{ + int ix; + unsigned long v = labs(z); + mp_err res; + + ARGCHK(mp != NULL, MP_BADARG); + + mp_zero(mp); + if(z == 0) + return MP_OKAY; /* shortcut for zero */ + + for(ix = sizeof(long) - 1; ix >= 0; ix--) { + + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + res = s_mp_add_d(mp, + (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); + if(res != MP_OKAY) + return res; + + } + + if(z < 0) + SIGN(mp) = MP_NEG; + + return MP_OKAY; + +} /* end mp_set_int() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Digit arithmetic */ + +/* {{{ mp_add_d(a, d, b) */ + +/* + mp_add_d(a, d, b) + + Compute the sum b = a + d, for a single digit d. Respects the sign of + its primary addend (single digits are unsigned anyway). + */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res = MP_OKAY; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_ZPOS) { + res = s_mp_add_d(b, d); + } else if(s_mp_cmp_d(b, d) >= 0) { + res = s_mp_sub_d(b, d); + } else { + SIGN(b) = MP_ZPOS; + + DIGIT(b, 0) = d - DIGIT(b, 0); + } + + return res; + +} /* end mp_add_d() */ + +/* }}} */ + +/* {{{ mp_sub_d(a, d, b) */ + +/* + mp_sub_d(a, d, b) + + Compute the difference b = a - d, for a single digit d. Respects the + sign of its subtrahend (single digits are unsigned anyway). + */ + +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_NEG) { + if((res = s_mp_add_d(b, d)) != MP_OKAY) + return res; + + } else if(s_mp_cmp_d(b, d) >= 0) { + if((res = s_mp_sub_d(b, d)) != MP_OKAY) + return res; + + } else { + mp_neg(b, b); + + DIGIT(b, 0) = d - DIGIT(b, 0); + SIGN(b) = MP_NEG; + } + + if(s_mp_cmp_d(b, 0) == 0) + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub_d() */ + +/* }}} */ + +/* {{{ mp_mul_d(a, d, b) */ + +/* + mp_mul_d(a, d, b) + + Compute the product b = a * d, for a single digit d. Respects the sign + of its multiplicand (single digits are unsigned anyway) + */ + +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(d == 0) { + mp_zero(b); + return MP_OKAY; + } + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + res = s_mp_mul_d(b, d); + + return res; + +} /* end mp_mul_d() */ + +/* }}} */ + +/* {{{ mp_mul_2(a, c) */ + +mp_err mp_mul_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + return s_mp_mul_2(c); + +} /* end mp_mul_2() */ + +/* }}} */ + +/* {{{ mp_div_d(a, d, q, r) */ + +/* + mp_div_d(a, d, q, r) + + Compute the quotient q = a / d and remainder r = a mod d, for a + single digit d. Respects the sign of its divisor (single digits are + unsigned anyway). + */ + +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) +{ + mp_err res; + mp_digit rem; + int pow; + + ARGCHK(a != NULL, MP_BADARG); + + if(d == 0) + return MP_RANGE; + + /* Shortcut for powers of two ... */ + if((pow = s_mp_ispow2d(d)) >= 0) { + mp_digit mask; + + mask = (1 << pow) - 1; + rem = DIGIT(a, 0) & mask; + + if(q) { + mp_copy(a, q); + s_mp_div_2d(q, pow); + } + + if(r) + *r = rem; + + return MP_OKAY; + } + + /* + If the quotient is actually going to be returned, we'll try to + avoid hitting the memory allocator by copying the dividend into it + and doing the division there. This can't be any _worse_ than + always copying, and will sometimes be better (since it won't make + another copy) + + If it's not going to be returned, we need to allocate a temporary + to hold the quotient, which will just be discarded. + */ + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + res = s_mp_div_d(q, d, &rem); + if(s_mp_cmp_d(q, 0) == MP_EQ) + SIGN(q) = MP_ZPOS; + + } else { + mp_int qp; + + if((res = mp_init_copy(&qp, a)) != MP_OKAY) + return res; + + res = s_mp_div_d(&qp, d, &rem); + if(s_mp_cmp_d(&qp, 0) == 0) + SIGN(&qp) = MP_ZPOS; + + mp_clear(&qp); + } + + if(r) + *r = rem; + + return res; + +} /* end mp_div_d() */ + +/* }}} */ + +/* {{{ mp_div_2(a, c) */ + +/* + mp_div_2(a, c) + + Compute c = a / 2, disregarding the remainder. + */ + +mp_err mp_div_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + s_mp_div_2(c); + + return MP_OKAY; + +} /* end mp_div_2() */ + +/* }}} */ + +/* {{{ mp_expt_d(a, d, b) */ + +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + DIGIT(&s, 0) = 1; + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt_d() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Full arithmetic */ + +/* {{{ mp_abs(a, b) */ + +/* + mp_abs(a, b) + + Compute b = |a|. 'a' and 'b' may be identical. + */ + +mp_err mp_abs(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_abs() */ + +/* }}} */ + +/* {{{ mp_neg(a, b) */ + +/* + mp_neg(a, b) + + Compute b = -a. 'a' and 'b' may be identical. + */ + +mp_err mp_neg(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(s_mp_cmp_d(b, 0) == MP_EQ) + SIGN(b) = MP_ZPOS; + else + SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; + + return MP_OKAY; + +} /* end mp_neg() */ + +/* }}} */ + +/* {{{ mp_add(a, b, c) */ + +/* + mp_add(a, b, c) + + Compute c = a + b. All parameters may be identical. + */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ + + /* Commutativity of addition lets us do this in either order, + so we avoid having to use a temporary even if the result + is supposed to replace the output + */ + if(c == b) { + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + } else { + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ + + /* If the output is going to be clobbered, we will use a temporary + variable; otherwise, we'll do it without touching the memory + allocator at all, if possible + */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + + } + + } else if(cmp == 0) { /* different sign, a == b */ + + mp_zero(c); + return MP_OKAY; + + } else { /* different sign: a < b */ + + /* See above... */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != b && (res = mp_copy(b, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + + } + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_add() */ + +/* }}} */ + +/* {{{ mp_sub(a, b, c) */ + +/* + mp_sub(a, b, c) + + Compute c = a - b. All parameters may be identical. + */ + +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) != SIGN(b)) { + if(c == a) { + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + SIGN(c) = SIGN(a); + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + } + + } else if(cmp == 0) { /* Same sign, equal magnitude */ + mp_zero(c); + return MP_OKAY; + + } else { /* Same sign, b > a */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + } + + SIGN(c) = !SIGN(b); + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub() */ + +/* }}} */ + +/* {{{ mp_mul(a, b, c) */ + +/* + mp_mul(a, b, c) + + Compute c = a * b. All parameters may be identical. + */ + +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_sign sgn; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; + + if(c == b) { + if((res = s_mp_mul(c, a)) != MP_OKAY) + return res; + + } else { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_mul(c, b)) != MP_OKAY) + return res; + } + + if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) + SIGN(c) = MP_ZPOS; + else + SIGN(c) = sgn; + + return MP_OKAY; + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_mul_2d(a, d, c) */ + +/* + mp_mul_2d(a, d, c) + + Compute c = a * 2^d. a may be the same as c. + */ + +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(d == 0) + return MP_OKAY; + + return s_mp_mul_2d(c, d); + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_sqr(a, b) */ + +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if((res = s_mp_sqr(b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ mp_div(a, b, q, r) */ + +/* + mp_div(a, b, q, r) + + Compute q = a / b and r = a mod b. Input parameters may be re-used + as output parameters. If q or r is NULL, that portion of the + computation will be discarded (although it will still be computed) + + Pay no attention to the hacker behind the curtain. + */ + +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) +{ + mp_err res; + mp_int qtmp, rtmp; + int cmp; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + + /* If a <= b, we can compute the solution without division, and + avoid any memory allocation + */ + if((cmp = s_mp_cmp(a, b)) < 0) { + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + } + + if(q) + mp_zero(q); + + return MP_OKAY; + + } else if(cmp == 0) { + + /* Set quotient to 1, with appropriate sign */ + if(q) { + int qneg = (SIGN(a) != SIGN(b)); + + mp_set(q, 1); + if(qneg) + SIGN(q) = MP_NEG; + } + + if(r) + mp_zero(r); + + return MP_OKAY; + } + + /* If we get here, it means we actually have to do some division */ + + /* Set up some temporaries... */ + if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) + return res; + if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) + goto CLEANUP; + + /* Compute the signs for the output */ + SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ + if(SIGN(a) == SIGN(b)) + SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ + else + SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ + + if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) + SIGN(&qtmp) = MP_ZPOS; + if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) + SIGN(&rtmp) = MP_ZPOS; + + /* Copy output, if it is needed */ + if(q) + s_mp_exch(&qtmp, q); + + if(r) + s_mp_exch(&rtmp, r); + +CLEANUP: + mp_clear(&rtmp); + mp_clear(&qtmp); + + return res; + +} /* end mp_div() */ + +/* }}} */ + +/* {{{ mp_div_2d(a, d, q, r) */ + +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) +{ + mp_err res; + + ARGCHK(a != NULL, MP_BADARG); + + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + s_mp_div_2d(q, d); + } + + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + + s_mp_mod_2d(r, d); + } + + return MP_OKAY; + +} /* end mp_div_2d() */ + +/* }}} */ + +/* {{{ mp_expt(a, b, c) */ + +/* + mp_expt(a, b, c) + + Compute c = a ** b, that is, raise a to the b power. Uses a + standard iterative square-and-multiply technique. + */ + +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int s, x; + mp_err res; + mp_digit d; + unsigned int bit, dig; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + + mp_set(&s, 1); + + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + /* Loop over low-order digits in ascending order */ + for(dig = 0; dig < (USED(b) - 1); dig++) { + d = DIGIT(b, dig); + + /* Loop over bits of each non-maximal digit */ + for(bit = 0; bit < DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Consider now the last digit... */ + d = DIGIT(b, dig); + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + if(mp_iseven(b)) + SIGN(&s) = SIGN(a); + + res = mp_copy(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt() */ + +/* }}} */ + +/* {{{ mp_2expt(a, k) */ + +/* Compute a = 2^k */ + +mp_err mp_2expt(mp_int *a, mp_digit k) +{ + ARGCHK(a != NULL, MP_BADARG); + + return s_mp_2expt(a, k); + +} /* end mp_2expt() */ + +/* }}} */ + +/* {{{ mp_mod(a, m, c) */ + +/* + mp_mod(a, m, c) + + Compute c = a (mod m). Result will always be 0 <= c < m. + */ + +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + int mag; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if(SIGN(m) == MP_NEG) + return MP_RANGE; + + /* + If |a| > m, we need to divide to get the remainder and take the + absolute value. + + If |a| < m, we don't need to do any division, just copy and adjust + the sign (if a is negative). + + If |a| == m, we can simply set the result to zero. + + This order is intended to minimize the average path length of the + comparison chain on common workloads -- the most frequent cases are + that |a| != m, so we do those first. + */ + if((mag = s_mp_cmp(a, m)) > 0) { + if((res = mp_div(a, m, NULL, c)) != MP_OKAY) + return res; + + if(SIGN(c) == MP_NEG) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + } + + } else if(mag < 0) { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(mp_cmp_z(a) < 0) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + + } + + } else { + mp_zero(c); + + } + + return MP_OKAY; + +} /* end mp_mod() */ + +/* }}} */ + +/* {{{ mp_mod_d(a, d, c) */ + +/* + mp_mod_d(a, d, c) + + Compute c = a (mod d). Result will always be 0 <= c < d + */ +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) +{ + mp_err res; + mp_digit rem; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if(s_mp_cmp_d(a, d) > 0) { + if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) + return res; + + } else { + if(SIGN(a) == MP_NEG) + rem = d - DIGIT(a, 0); + else + rem = DIGIT(a, 0); + } + + if(c) + *c = rem; + + return MP_OKAY; + +} /* end mp_mod_d() */ + +/* }}} */ + +/* {{{ mp_sqrt(a, b) */ + +/* + mp_sqrt(a, b) + + Compute the integer square root of a, and store the result in b. + Uses an integer-arithmetic version of Newton's iterative linear + approximation technique to determine this value; the result has the + following two properties: + + b^2 <= a + (b+1)^2 >= a + + It is a range error to pass a negative value. + */ +mp_err mp_sqrt(mp_int *a, mp_int *b) +{ + mp_int x, t; + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + /* Cannot take square root of a negative value */ + if(SIGN(a) == MP_NEG) + return MP_RANGE; + + /* Special cases for zero and one, trivial */ + if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) + return mp_copy(a, b); + + /* Initialize the temporaries we'll use below */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + return res; + + /* Compute an initial guess for the iteration as a itself */ + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + +s_mp_rshd(&x, (USED(&x)/2)+1); +mp_add_d(&x, 1, &x); + + for(;;) { + /* t = (x * x) - a */ + mp_copy(&x, &t); /* can't fail, t is big enough for original x */ + if((res = mp_sqr(&t, &t)) != MP_OKAY || + (res = mp_sub(&t, a, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = t / 2x */ + s_mp_mul_2(&x); + if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) + goto CLEANUP; + s_mp_div_2(&x); + + /* Terminate the loop, if the quotient is zero */ + if(mp_cmp_z(&t) == MP_EQ) + break; + + /* x = x - t */ + if((res = mp_sub(&x, &t, &x)) != MP_OKAY) + goto CLEANUP; + + } + + /* Copy result to output parameter */ + mp_sub_d(&x, 1, &x); + s_mp_exch(&x, b); + + CLEANUP: + mp_clear(&x); + X: + mp_clear(&t); + + return res; + +} /* end mp_sqrt() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Modular arithmetic */ + +#if MP_MODARITH +/* {{{ mp_addmod(a, b, m, c) */ + +/* + mp_addmod(a, b, m, c) + + Compute c = (a + b) mod m + */ + +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_add(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_submod(a, b, m, c) */ + +/* + mp_submod(a, b, m, c) + + Compute c = (a - b) mod m + */ + +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sub(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_mulmod(a, b, m, c) */ + +/* + mp_mulmod(a, b, m, c) + + Compute c = (a * b) mod m + */ + +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_mul(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_sqrmod(a, m, c) */ + +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sqr(a, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} /* end mp_sqrmod() */ +#endif + +/* }}} */ + +/* {{{ mp_exptmod(a, b, m, c) */ + +/* + mp_exptmod(a, b, m, c) + + Compute c = (a ** b) mod m. Uses a standard square-and-multiply + method with modular reductions at each step. (This is basically the + same code as mp_expt(), except for the addition of the reductions) + + The modular reductions are done using Barrett's algorithm (see + s_mp_reduce() below for details) + */ + +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_int s, x, mu; + mp_err res; + mp_digit d, *db = DIGITS(b); + mp_size ub = USED(b); + unsigned int bit, dig; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + if((res = mp_mod(&x, m, &x)) != MP_OKAY || + (res = mp_init(&mu)) != MP_OKAY) + goto MU; + + mp_set(&s, 1); + + /* mu = b^2k / m */ + s_mp_add_d(&mu, 1); + s_mp_lshd(&mu, 2 * USED(m)); + if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) + goto CLEANUP; + + /* Loop over digits of b in ascending order, except highest order */ + for(dig = 0; dig < (ub - 1); dig++) { + d = *db++; + + /* Loop over the bits of the lower-order digits */ + for(bit = 0; bit < DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Now do the last digit... */ + d = *db; + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + + CLEANUP: + mp_clear(&mu); + MU: + mp_clear(&x); + X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod() */ + +/* }}} */ + +/* {{{ mp_exptmod_d(a, d, m, c) */ + +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + mp_set(&s, 1); + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY || + (res = mp_mod(&s, m, &s)) != MP_OKAY) + goto CLEANUP; + } + + d /= 2; + + if((res = s_mp_sqr(&x)) != MP_OKAY || + (res = mp_mod(&x, m, &x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod_d() */ + +/* }}} */ +#endif /* if MP_MODARITH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Comparison functions */ + +/* {{{ mp_cmp_z(a) */ + +/* + mp_cmp_z(a) + + Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. + */ + +int mp_cmp_z(mp_int *a) +{ + if(SIGN(a) == MP_NEG) + return MP_LT; + else if(USED(a) == 1 && DIGIT(a, 0) == 0) + return MP_EQ; + else + return MP_GT; + +} /* end mp_cmp_z() */ + +/* }}} */ + +/* {{{ mp_cmp_d(a, d) */ + +/* + mp_cmp_d(a, d) + + Compare a <=> d. Returns <0 if a0 if a>d + */ + +int mp_cmp_d(mp_int *a, mp_digit d) +{ + ARGCHK(a != NULL, MP_EQ); + + if(SIGN(a) == MP_NEG) + return MP_LT; + + return s_mp_cmp_d(a, d); + +} /* end mp_cmp_d() */ + +/* }}} */ + +/* {{{ mp_cmp(a, b) */ + +int mp_cmp(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + if(SIGN(a) == SIGN(b)) { + int mag; + + if((mag = s_mp_cmp(a, b)) == MP_EQ) + return MP_EQ; + + if(SIGN(a) == MP_ZPOS) + return mag; + else + return -mag; + + } else if(SIGN(a) == MP_ZPOS) { + return MP_GT; + } else { + return MP_LT; + } + +} /* end mp_cmp() */ + +/* }}} */ + +/* {{{ mp_cmp_mag(a, b) */ + +/* + mp_cmp_mag(a, b) + + Compares |a| <=> |b|, and returns an appropriate comparison result + */ + +int mp_cmp_mag(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + return s_mp_cmp(a, b); + +} /* end mp_cmp_mag() */ + +/* }}} */ + +/* {{{ mp_cmp_int(a, z) */ + +/* + This just converts z to an mp_int, and uses the existing comparison + routines. This is sort of inefficient, but it's not clear to me how + frequently this wil get used anyway. For small positive constants, + you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). + */ +int mp_cmp_int(mp_int *a, long z) +{ + mp_int tmp; + int out; + + ARGCHK(a != NULL, MP_EQ); + + mp_init(&tmp); mp_set_int(&tmp, z); + out = mp_cmp(a, &tmp); + mp_clear(&tmp); + + return out; + +} /* end mp_cmp_int() */ + +/* }}} */ + +/* {{{ mp_isodd(a) */ + +/* + mp_isodd(a) + + Returns a true (non-zero) value if a is odd, false (zero) otherwise. + */ +int mp_isodd(mp_int *a) +{ + ARGCHK(a != NULL, 0); + + return (DIGIT(a, 0) & 1); + +} /* end mp_isodd() */ + +/* }}} */ + +/* {{{ mp_iseven(a) */ + +int mp_iseven(mp_int *a) +{ + return !mp_isodd(a); + +} /* end mp_iseven() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Number theoretic functions */ + +#if MP_NUMTH +/* {{{ mp_gcd(a, b, c) */ + +/* + Like the old mp_gcd() function, except computes the GCD using the + binary algorithm due to Josef Stein in 1961 (via Knuth). + */ +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_int u, v, t; + mp_size k = 0; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + if(mp_cmp_z(a) == MP_EQ) { + return mp_copy(b, c); + } else if(mp_cmp_z(b) == MP_EQ) { + return mp_copy(a, c); + } + + if((res = mp_init(&t)) != MP_OKAY) + return res; + if((res = mp_init_copy(&u, a)) != MP_OKAY) + goto U; + if((res = mp_init_copy(&v, b)) != MP_OKAY) + goto V; + + SIGN(&u) = MP_ZPOS; + SIGN(&v) = MP_ZPOS; + + /* Divide out common factors of 2 until at least 1 of a, b is even */ + while(mp_iseven(&u) && mp_iseven(&v)) { + s_mp_div_2(&u); + s_mp_div_2(&v); + ++k; + } + + /* Initialize t */ + if(mp_isodd(&u)) { + if((res = mp_copy(&v, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = -v */ + if(SIGN(&v) == MP_ZPOS) + SIGN(&t) = MP_NEG; + else + SIGN(&t) = MP_ZPOS; + + } else { + if((res = mp_copy(&u, &t)) != MP_OKAY) + goto CLEANUP; + + } + + for(;;) { + while(mp_iseven(&t)) { + s_mp_div_2(&t); + } + + if(mp_cmp_z(&t) == MP_GT) { + if((res = mp_copy(&t, &u)) != MP_OKAY) + goto CLEANUP; + + } else { + if((res = mp_copy(&t, &v)) != MP_OKAY) + goto CLEANUP; + + /* v = -t */ + if(SIGN(&t) == MP_ZPOS) + SIGN(&v) = MP_NEG; + else + SIGN(&v) = MP_ZPOS; + } + + if((res = mp_sub(&u, &v, &t)) != MP_OKAY) + goto CLEANUP; + + if(s_mp_cmp_d(&t, 0) == MP_EQ) + break; + } + + s_mp_2expt(&v, k); /* v = 2^k */ + res = mp_mul(&u, &v, c); /* c = u * v */ + + CLEANUP: + mp_clear(&v); + V: + mp_clear(&u); + U: + mp_clear(&t); + + return res; + +} /* end mp_bgcd() */ + +/* }}} */ + +/* {{{ mp_lcm(a, b, c) */ + +/* We compute the least common multiple using the rule: + + ab = [a, b](a, b) + + ... by computing the product, and dividing out the gcd. + */ + +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int gcd, prod; + mp_err res; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + /* Set up temporaries */ + if((res = mp_init(&gcd)) != MP_OKAY) + return res; + if((res = mp_init(&prod)) != MP_OKAY) + goto GCD; + + if((res = mp_mul(a, b, &prod)) != MP_OKAY) + goto CLEANUP; + if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) + goto CLEANUP; + + res = mp_div(&prod, &gcd, c, NULL); + + CLEANUP: + mp_clear(&prod); + GCD: + mp_clear(&gcd); + + return res; + +} /* end mp_lcm() */ + +/* }}} */ + +/* {{{ mp_xgcd(a, b, g, x, y) */ + +/* + mp_xgcd(a, b, g, x, y) + + Compute g = (a, b) and values x and y satisfying Bezout's identity + (that is, ax + by = g). This uses the extended binary GCD algorithm + based on the Stein algorithm used for mp_gcd() + */ + +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) +{ + mp_int gx, xc, yc, u, v, A, B, C, D; + mp_int *clean[9]; + mp_err res; + int last = -1; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Initialize all these variables we need */ + if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; + clean[++last] = &u; + if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; + clean[++last] = &v; + if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; + clean[++last] = &gx; + if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; + clean[++last] = &A; + if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; + clean[++last] = &B; + if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; + clean[++last] = &C; + if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; + clean[++last] = &D; + if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; + clean[++last] = &xc; + mp_abs(&xc, &xc); + if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; + clean[++last] = &yc; + mp_abs(&yc, &yc); + + mp_set(&gx, 1); + + /* Divide by two until at least one of them is even */ + while(mp_iseven(&xc) && mp_iseven(&yc)) { + s_mp_div_2(&xc); + s_mp_div_2(&yc); + if((res = s_mp_mul_2(&gx)) != MP_OKAY) + goto CLEANUP; + } + + mp_copy(&xc, &u); + mp_copy(&yc, &v); + mp_set(&A, 1); mp_set(&D, 1); + + /* Loop through binary GCD algorithm */ + for(;;) { + while(mp_iseven(&u)) { + s_mp_div_2(&u); + + if(mp_iseven(&A) && mp_iseven(&B)) { + s_mp_div_2(&A); s_mp_div_2(&B); + } else { + if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&A); + if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&B); + } + } + + while(mp_iseven(&v)) { + s_mp_div_2(&v); + + if(mp_iseven(&C) && mp_iseven(&D)) { + s_mp_div_2(&C); s_mp_div_2(&D); + } else { + if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&C); + if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&D); + } + } + + if(mp_cmp(&u, &v) >= 0) { + if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; + + } else { + if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; + + } + + /* If we're done, copy results to output */ + if(mp_cmp_z(&u) == 0) { + if(x) + if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; + + if(y) + if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; + + if(g) + if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; + + break; + } + } + + CLEANUP: + while(last >= 0) + mp_clear(clean[last--]); + + return res; + +} /* end mp_xgcd() */ + +/* }}} */ + +/* {{{ mp_invmod(a, m, c) */ + +/* + mp_invmod(a, m, c) + + Compute c = a^-1 (mod m), if there is an inverse for a (mod m). + This is equivalent to the question of whether (a, m) = 1. If not, + MP_UNDEF is returned, and there is no inverse. + */ + +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_int g, x; + mp_err res; + + ARGCHK(a && m && c, MP_BADARG); + + if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) + return MP_RANGE; + + if((res = mp_init(&g)) != MP_OKAY) + return res; + if((res = mp_init(&x)) != MP_OKAY) + goto X; + + if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) + goto CLEANUP; + + if(mp_cmp_d(&g, 1) != MP_EQ) { + res = MP_UNDEF; + goto CLEANUP; + } + + res = mp_mod(&x, m, c); + SIGN(c) = SIGN(a); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&g); + + return res; + +} /* end mp_invmod() */ + +/* }}} */ +#endif /* if MP_NUMTH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_print(mp, ofp) */ + +#if MP_IOFUNC +/* + mp_print(mp, ofp) + + Print a textual representation of the given mp_int on the output + stream 'ofp'. Output is generated using the internal radix. + */ + +void mp_print(mp_int *mp, FILE *ofp) +{ + int ix; + + if(mp == NULL || ofp == NULL) + return; + + fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); + + for(ix = USED(mp) - 1; ix >= 0; ix--) { + fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); + } + +} /* end mp_print() */ + +#endif /* if MP_IOFUNC */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ More I/O Functions */ + +/* {{{ mp_read_signed_bin(mp, str, len) */ + +/* + mp_read_signed_bin(mp, str, len) + + Read in a raw value (base 256) into the given mp_int + */ + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) +{ + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { + /* Get sign from first byte */ + if(str[0]) + SIGN(mp) = MP_NEG; + else + SIGN(mp) = MP_ZPOS; + } + + return res; + +} /* end mp_read_signed_bin() */ + +/* }}} */ + +/* {{{ mp_signed_bin_size(mp) */ + +int mp_signed_bin_size(mp_int *mp) +{ + ARGCHK(mp != NULL, 0); + + return mp_unsigned_bin_size(mp) + 1; + +} /* end mp_signed_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_signed_bin(mp, str) */ + +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) +{ + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ + str[0] = (char)SIGN(mp); + + return mp_to_unsigned_bin(mp, str + 1); + +} /* end mp_to_signed_bin() */ + +/* }}} */ + +/* {{{ mp_read_unsigned_bin(mp, str, len) */ + +/* + mp_read_unsigned_bin(mp, str, len) + + Read in an unsigned value (base 256) into the given mp_int + */ + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) +{ + int ix; + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + mp_zero(mp); + + for(ix = 0; ix < len; ix++) { + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) + return res; + } + + return MP_OKAY; + +} /* end mp_read_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_unsigned_bin_size(mp) */ + +int mp_unsigned_bin_size(mp_int *mp) +{ + mp_digit topdig; + int count; + + ARGCHK(mp != NULL, 0); + + /* Special case for the value zero */ + if(USED(mp) == 1 && DIGIT(mp, 0) == 0) + return 1; + + count = (USED(mp) - 1) * sizeof(mp_digit); + topdig = DIGIT(mp, USED(mp) - 1); + + while(topdig != 0) { + ++count; + topdig >>= CHAR_BIT; + } + + return count; + +} /* end mp_unsigned_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_unsigned_bin(mp, str) */ + +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) +{ + mp_digit *dp, *end, d; + unsigned char *spos; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + dp = DIGITS(mp); + end = dp + USED(mp) - 1; + spos = str; + + /* Special case for zero, quick test */ + if(dp == end && *dp == 0) { + *str = '\0'; + return MP_OKAY; + } + + /* Generate digits in reverse order */ + while(dp < end) { + unsigned int ix; + + d = *dp; + for(ix = 0; ix < sizeof(mp_digit); ++ix) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + ++dp; + } + + /* Now handle last digit specially, high order zeroes are not written */ + d = *end; + while(d != 0) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + /* Reverse everything to get digits in the correct order */ + while(--spos > str) { + unsigned char t = *str; + *str = *spos; + *spos = t; + + ++str; + } + + return MP_OKAY; + +} /* end mp_to_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_count_bits(mp) */ + +int mp_count_bits(mp_int *mp) +{ + int len; + mp_digit d; + + ARGCHK(mp != NULL, MP_BADARG); + + len = DIGIT_BIT * (USED(mp) - 1); + d = DIGIT(mp, USED(mp) - 1); + + while(d != 0) { + ++len; + d >>= 1; + } + + return len; + +} /* end mp_count_bits() */ + +/* }}} */ + +/* {{{ mp_read_radix(mp, str, radix) */ + +/* + mp_read_radix(mp, str, radix) + + Read an integer from the given string, and set mp to the resulting + value. The input is presumed to be in base 10. Leading non-digit + characters are ignored, and the function reads until a non-digit + character or the end of the string. + */ + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) +{ + int ix = 0, val = 0; + mp_err res; + mp_sign sig = MP_ZPOS; + + ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, + MP_BADARG); + + mp_zero(mp); + + /* Skip leading non-digit characters until a digit or '-' or '+' */ + while(str[ix] && + (s_mp_tovalue(str[ix], radix) < 0) && + str[ix] != '-' && + str[ix] != '+') { + ++ix; + } + + if(str[ix] == '-') { + sig = MP_NEG; + ++ix; + } else if(str[ix] == '+') { + sig = MP_ZPOS; /* this is the default anyway... */ + ++ix; + } + + while((val = s_mp_tovalue(str[ix], radix)) >= 0) { + if((res = s_mp_mul_d(mp, radix)) != MP_OKAY) + return res; + if((res = s_mp_add_d(mp, val)) != MP_OKAY) + return res; + ++ix; + } + + if(s_mp_cmp_d(mp, 0) == MP_EQ) + SIGN(mp) = MP_ZPOS; + else + SIGN(mp) = sig; + + return MP_OKAY; + +} /* end mp_read_radix() */ + +/* }}} */ + +/* {{{ mp_radix_size(mp, radix) */ + +int mp_radix_size(mp_int *mp, int radix) +{ + int len; + ARGCHK(mp != NULL, 0); + + len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ + + if(mp_cmp_z(mp) < 0) + ++len; /* for sign */ + + return len; + +} /* end mp_radix_size() */ + +/* }}} */ + +/* {{{ mp_value_radix_size(num, qty, radix) */ + +/* num = number of digits + qty = number of bits per digit + radix = target base + + Return the number of digits in the specified radix that would be + needed to express 'num' digits of 'qty' bits each. + */ +int mp_value_radix_size(int num, int qty, int radix) +{ + ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); + + return s_mp_outlen(num * qty, radix); + +} /* end mp_value_radix_size() */ + +/* }}} */ + +/* {{{ mp_toradix(mp, str, radix) */ + +mp_err mp_toradix(mp_int *mp, char *str, int radix) +{ + int ix, pos = 0; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); + + if(mp_cmp_z(mp) == MP_EQ) { + str[0] = '0'; + str[1] = '\0'; + } else { + mp_err res; + mp_int tmp; + mp_sign sgn; + mp_digit rem, rdx = (mp_digit)radix; + char ch; + + if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) + return res; + + /* Save sign for later, and take absolute value */ + sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; + + /* Generate output digits in reverse order */ + while(mp_cmp_z(&tmp) != 0) { + if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + /* Generate digits, use capital letters */ + ch = s_mp_todigit(rem, radix, 0); + + str[pos++] = ch; + } + + /* Add - sign if original value was negative */ + if(sgn == MP_NEG) + str[pos++] = '-'; + + /* Add trailing NUL to end the string */ + str[pos--] = '\0'; + + /* Reverse the digits and sign indicator */ + ix = 0; + while(ix < pos) { + char _tmp = str[ix]; + + str[ix] = str[pos]; + str[pos] = _tmp; + ++ix; + --pos; + } + + mp_clear(&tmp); + } + + return MP_OKAY; + +} /* end mp_toradix() */ + +/* }}} */ + +/* {{{ mp_char2value(ch, r) */ + +int mp_char2value(char ch, int r) +{ + return s_mp_tovalue(ch, r); + +} /* end mp_tovalue() */ + +/* }}} */ + +/* }}} */ + +/* {{{ mp_strerror(ec) */ + +/* + mp_strerror(ec) + + Return a string describing the meaning of error code 'ec'. The + string returned is allocated in static memory, so the caller should + not attempt to modify or free the memory associated with this + string. + */ +const char *mp_strerror(mp_err ec) +{ + int aec = (ec < 0) ? -ec : ec; + + /* Code values are negative, so the senses of these comparisons + are accurate */ + if(ec < MP_LAST_CODE || ec > MP_OKAY) { + return mp_err_string[0]; /* unknown error code */ + } else { + return mp_err_string[aec + 1]; + } + +} /* end mp_strerror() */ + +/* }}} */ + +/*========================================================================*/ +/*------------------------------------------------------------------------*/ +/* Static function definitions (internal use only) */ + +/* {{{ Memory management */ + +/* {{{ s_mp_grow(mp, min) */ + +/* Make sure there are at least 'min' digits allocated to mp */ +mp_err s_mp_grow(mp_int *mp, mp_size min) +{ + if(min > ALLOC(mp)) { + mp_digit *tmp; + + /* Set min to next nearest default precision block size */ + min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; + + if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(mp), tmp, USED(mp)); + +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = tmp; + ALLOC(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_grow() */ + +/* }}} */ + +/* {{{ s_mp_pad(mp, min) */ + +/* Make sure the used size of mp is at least 'min', growing if needed */ +mp_err s_mp_pad(mp_int *mp, mp_size min) +{ + if(min > USED(mp)) { + mp_err res; + + /* Make sure there is room to increase precision */ + if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) + return res; + + /* Increase precision; should already be 0-filled */ + USED(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_pad() */ + +/* }}} */ + +/* {{{ s_mp_setz(dp, count) */ + +#if MP_MACRO == 0 +/* Set 'count' digits pointed to by dp to be zeroes */ +void s_mp_setz(mp_digit *dp, mp_size count) +{ +#if MP_MEMSET == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = 0; +#else + memset(dp, 0, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_setz() */ +#endif + +/* }}} */ + +/* {{{ s_mp_copy(sp, dp, count) */ + +#if MP_MACRO == 0 +/* Copy 'count' digits from sp to dp */ +void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) +{ +#if MP_MEMCPY == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = sp[ix]; +#else + memcpy(dp, sp, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_copy() */ +#endif + +/* }}} */ + +/* {{{ s_mp_alloc(nb, ni) */ + +#if MP_MACRO == 0 +/* Allocate ni records of nb bytes each, and return a pointer to that */ +void *s_mp_alloc(size_t nb, size_t ni) +{ + return calloc(nb, ni); + +} /* end s_mp_alloc() */ +#endif + +/* }}} */ + +/* {{{ s_mp_free(ptr) */ + +#if MP_MACRO == 0 +/* Free the memory pointed to by ptr */ +void s_mp_free(void *ptr) +{ + if(ptr) + free(ptr); + +} /* end s_mp_free() */ +#endif + +/* }}} */ + +/* {{{ s_mp_clamp(mp) */ + +/* Remove leading zeroes from the given value */ +void s_mp_clamp(mp_int *mp) +{ + mp_size du = USED(mp); + mp_digit *zp = DIGITS(mp) + du - 1; + + while(du > 1 && !*zp--) + --du; + + USED(mp) = du; + +} /* end s_mp_clamp() */ + + +/* }}} */ + +/* {{{ s_mp_exch(a, b) */ + +/* Exchange the data for a and b; (b, a) = (a, b) */ +void s_mp_exch(mp_int *a, mp_int *b) +{ + mp_int tmp; + + tmp = *a; + *a = *b; + *b = tmp; + +} /* end s_mp_exch() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Arithmetic helpers */ + +/* {{{ s_mp_lshd(mp, p) */ + +/* + Shift mp leftward by p digits, growing if needed, and zero-filling + the in-shifted digits at the right end. This is a convenient + alternative to multiplication by powers of the radix + */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p) +{ + mp_err res; + mp_size pos; + mp_digit *dp; + int ix; + + if(p == 0) + return MP_OKAY; + + if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) + return res; + + pos = USED(mp) - 1; + dp = DIGITS(mp); + + /* Shift all the significant figures over as needed */ + for(ix = pos - p; ix >= 0; ix--) + dp[ix + p] = dp[ix]; + + /* Fill the bottom digits with zeroes */ + for(ix = 0; (unsigned)ix < p; ix++) + dp[ix] = 0; + + return MP_OKAY; + +} /* end s_mp_lshd() */ + +/* }}} */ + +/* {{{ s_mp_rshd(mp, p) */ + +/* + Shift mp rightward by p digits. Maintains the invariant that + digits above the precision are all zero. Digits shifted off the + end are lost. Cannot fail. + */ + +void s_mp_rshd(mp_int *mp, mp_size p) +{ + mp_size ix; + mp_digit *dp; + + if(p == 0) + return; + + /* Shortcut when all digits are to be shifted off */ + if(p >= USED(mp)) { + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + return; + } + + /* Shift all the significant figures over as needed */ + dp = DIGITS(mp); + for(ix = p; ix < USED(mp); ix++) + dp[ix - p] = dp[ix]; + + /* Fill the top digits with zeroes */ + ix -= p; + while(ix < USED(mp)) + dp[ix++] = 0; + + /* Strip off any leading zeroes */ + s_mp_clamp(mp); + +} /* end s_mp_rshd() */ + +/* }}} */ + +/* {{{ s_mp_div_2(mp) */ + +/* Divide by two -- take advantage of radix properties to do it fast */ +void s_mp_div_2(mp_int *mp) +{ + s_mp_div_2d(mp, 1); + +} /* end s_mp_div_2() */ + +/* }}} */ + +/* {{{ s_mp_mul_2(mp) */ + +mp_err s_mp_mul_2(mp_int *mp) +{ + unsigned int ix; + mp_digit kin = 0, kout, *dp = DIGITS(mp); + mp_err res; + + /* Shift digits leftward by 1 bit */ + for(ix = 0; ix < USED(mp); ix++) { + kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; + dp[ix] = (dp[ix] << 1) | kin; + + kin = kout; + } + + /* Deal with rollover from last digit */ + if(kin) { + if(ix >= ALLOC(mp)) { + if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + dp[ix] = kin; + USED(mp) += 1; + } + + return MP_OKAY; + +} /* end s_mp_mul_2() */ + +/* }}} */ + +/* {{{ s_mp_mod_2d(mp, d) */ + +/* + Remainder the integer by 2^d, where d is a number of bits. This + amounts to a bitwise AND of the value, and does not require the full + division code + */ +void s_mp_mod_2d(mp_int *mp, mp_digit d) +{ + unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); + unsigned int ix; + mp_digit dmask, *dp = DIGITS(mp); + + if(ndig >= USED(mp)) + return; + + /* Flush all the bits above 2^d in its digit */ + dmask = (1 << nbit) - 1; + dp[ndig] &= dmask; + + /* Flush all digits above the one with 2^d in it */ + for(ix = ndig + 1; ix < USED(mp); ix++) + dp[ix] = 0; + + s_mp_clamp(mp); + +} /* end s_mp_mod_2d() */ + +/* }}} */ + +/* {{{ s_mp_mul_2d(mp, d) */ + +/* + Multiply by the integer 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full multiplication code. + */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) +{ + mp_err res; + mp_digit save, next, mask, *dp; + mp_size used; + unsigned int ix; + + if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) + return res; + + dp = DIGITS(mp); used = USED(mp); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + /* If the shift requires another digit, make sure we've got one to + work with */ + if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { + if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + /* Do the shifting... */ + save = 0; + for(ix = 0; ix < used; ix++) { + next = (dp[ix] >> (DIGIT_BIT - d)) & mask; + dp[ix] = (dp[ix] << d) | save; + save = next; + } + + /* If, at this point, we have a nonzero carryout into the next + digit, we'll increase the size by one digit, and store it... + */ + if(save) { + dp[used] = save; + USED(mp) += 1; + } + + s_mp_clamp(mp); + return MP_OKAY; + +} /* end s_mp_mul_2d() */ + +/* }}} */ + +/* {{{ s_mp_div_2d(mp, d) */ + +/* + Divide the integer by 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full division code (used in Barrett reduction, see below) + */ +void s_mp_div_2d(mp_int *mp, mp_digit d) +{ + int ix; + mp_digit save, next, mask, *dp = DIGITS(mp); + + s_mp_rshd(mp, d / DIGIT_BIT); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + save = 0; + for(ix = USED(mp) - 1; ix >= 0; ix--) { + next = dp[ix] & mask; + dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); + save = next; + } + + s_mp_clamp(mp); + +} /* end s_mp_div_2d() */ + +/* }}} */ + +/* {{{ s_mp_norm(a, b) */ + +/* + s_mp_norm(a, b) + + Normalize a and b for division, where b is the divisor. In order + that we might make good guesses for quotient digits, we want the + leading digit of b to be at least half the radix, which we + accomplish by multiplying a and b by a constant. This constant is + returned (so that it can be divided back out of the remainder at the + end of the division process). + + We multiply by the smallest power of 2 that gives us a leading digit + at least half the radix. By choosing a power of 2, we simplify the + multiplication and division steps to simple shifts. + */ +mp_digit s_mp_norm(mp_int *a, mp_int *b) +{ + mp_digit t, d = 0; + + t = DIGIT(b, USED(b) - 1); + while(t < (RADIX / 2)) { + t <<= 1; + ++d; + } + + if(d != 0) { + s_mp_mul_2d(a, d); + s_mp_mul_2d(b, d); + } + + return d; + +} /* end s_mp_norm() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive digit arithmetic */ + +/* {{{ s_mp_add_d(mp, d) */ + +/* Add d to |mp| in place */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ +{ + mp_word w, k = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + w = dp[0] + d; + dp[0] = ACCUM(w); + k = CARRYOUT(w); + + while(ix < used && k) { + w = dp[ix] + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + ++ix; + } + + if(k != 0) { + mp_err res; + + if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) + return res; + + DIGIT(mp, ix) = k; + } + + return MP_OKAY; + +} /* end s_mp_add_d() */ + +/* }}} */ + +/* {{{ s_mp_sub_d(mp, d) */ + +/* Subtract d from |mp| in place, assumes |mp| > d */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ +{ + mp_word w, b = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + /* Compute initial subtraction */ + w = (RADIX + dp[0]) - d; + b = CARRYOUT(w) ? 0 : 1; + dp[0] = ACCUM(w); + + /* Propagate borrows leftward */ + while(b && ix < used) { + w = (RADIX + dp[ix]) - b; + b = CARRYOUT(w) ? 0 : 1; + dp[ix] = ACCUM(w); + ++ix; + } + + /* Remove leading zeroes */ + s_mp_clamp(mp); + + /* If we have a borrow out, it's a violation of the input invariant */ + if(b) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub_d() */ + +/* }}} */ + +/* {{{ s_mp_mul_d(a, d) */ + +/* Compute a = a * d, single digit multiplication */ +mp_err s_mp_mul_d(mp_int *a, mp_digit d) +{ + mp_word w, k = 0; + mp_size ix, max; + mp_err res; + mp_digit *dp = DIGITS(a); + + /* + Single-digit multiplication will increase the precision of the + output by at most one digit. However, we can detect when this + will happen -- if the high-order digit of a, times d, gives a + two-digit result, then the precision of the result will increase; + otherwise it won't. We use this fact to avoid calling s_mp_pad() + unless absolutely necessary. + */ + max = USED(a); + w = dp[max - 1] * d; + if(CARRYOUT(w) != 0) { + if((res = s_mp_pad(a, max + 1)) != MP_OKAY) + return res; + dp = DIGITS(a); + } + + for(ix = 0; ix < max; ix++) { + w = (dp[ix] * d) + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + } + + /* If there is a precision increase, take care of it here; the above + test guarantees we have enough storage to do this safely. + */ + if(k) { + dp[max] = k; + USED(a) = max + 1; + } + + s_mp_clamp(a); + + return MP_OKAY; + +} /* end s_mp_mul_d() */ + +/* }}} */ + +/* {{{ s_mp_div_d(mp, d, r) */ + +/* + s_mp_div_d(mp, d, r) + + Compute the quotient mp = mp / d and remainder r = mp mod d, for a + single digit d. If r is null, the remainder will be discarded. + */ + +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) +{ + mp_word w = 0, t; + mp_int quot; + mp_err res; + mp_digit *dp = DIGITS(mp), *qp; + int ix; + + if(d == 0) + return MP_RANGE; + + /* Make room for the quotient */ + if((res = mp_init_size(", USED(mp))) != MP_OKAY) + return res; + + USED(") = USED(mp); /* so clamping will work below */ + qp = DIGITS("); + + /* Divide without subtraction */ + for(ix = USED(mp) - 1; ix >= 0; ix--) { + w = (w << DIGIT_BIT) | dp[ix]; + + if(w >= d) { + t = w / d; + w = w % d; + } else { + t = 0; + } + + qp[ix] = t; + } + + /* Deliver the remainder, if desired */ + if(r) + *r = w; + + s_mp_clamp("); + mp_exch(", mp); + mp_clear("); + + return MP_OKAY; + +} /* end s_mp_div_d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive full arithmetic */ + +/* {{{ s_mp_add(a, b) */ + +/* Compute a = |a| + |b| */ +mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + mp_err res; + + /* Make sure a has enough precision for the output value */ + if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) + return res; + + /* + Add up all digits up to the precision of b. If b had initially + the same precision as a, or greater, we took care of it by the + padding step above, so there is no problem. If b had initially + less precision, we'll have to make sure the carry out is duly + propagated upward among the higher-order digits of the sum. + */ + pa = DIGITS(a); + pb = DIGITS(b); + for(ix = 0; ix < used; ++ix) { + w += *pa + *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + } + + /* If we run out of 'b' digits before we're actually done, make + sure the carries get propagated upward... + */ + used = USED(a); + while(w && ix < used) { + w += *pa; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + ++ix; + } + + /* If there's an overall carry out, increase precision and include + it. We could have done this initially, but why touch the memory + allocator unless we're sure we have to? + */ + if(w) { + if((res = s_mp_pad(a, used + 1)) != MP_OKAY) + return res; + + DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ + } + + return MP_OKAY; + +} /* end s_mp_add() */ + +/* }}} */ + +/* {{{ s_mp_sub(a, b) */ + +/* Compute a = |a| - |b|, assumes |a| >= |b| */ +mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + + /* + Subtract and propagate borrow. Up to the precision of b, this + accounts for the digits of b; after that, we just make sure the + carries get to the right place. This saves having to pad b out to + the precision of a just to make the loops work right... + */ + pa = DIGITS(a); + pb = DIGITS(b); + + for(ix = 0; ix < used; ++ix) { + w = (RADIX + *pa) - w - *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + } + + used = USED(a); + while(ix < used) { + w = RADIX + *pa - w; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + ++ix; + } + + /* Clobber any leading zeroes we created */ + s_mp_clamp(a); + + /* + If there was a borrow out, then |b| > |a| in violation + of our input invariant. We've already done the work, + but we'll at least complain about it... + */ + if(w) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub() */ + +/* }}} */ + +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) +{ + mp_int q; + mp_err res; + mp_size um = USED(m); + + if((res = mp_init_copy(&q, x)) != MP_OKAY) + return res; + + s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ + s_mp_mul(&q, mu); /* q2 = q1 * mu */ + s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ + + /* x = x mod b^(k+1), quick (no division) */ + s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1))); + + /* q = q * m mod b^(k+1), quick (no division), uses the short multiplier */ +#ifndef SHRT_MUL + s_mp_mul(&q, m); + s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1))); +#else + s_mp_mul_dig(&q, m, um + 1); +#endif + + /* x = x - q */ + if((res = mp_sub(x, &q, x)) != MP_OKAY) + goto CLEANUP; + + /* If x < 0, add b^(k+1) to it */ + if(mp_cmp_z(x) < 0) { + mp_set(&q, 1); + if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if((res = mp_add(x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while(mp_cmp(x, m) >= 0) { + if((res = s_mp_sub(x, m)) != MP_OKAY) + break; + } + + CLEANUP: + mp_clear(&q); + + return res; + +} /* end s_mp_reduce() */ + + + +/* {{{ s_mp_mul(a, b) */ + +/* Compute a = |a| * |b| */ +mp_err s_mp_mul(mp_int *a, mp_int *b) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, ua = USED(a), ub = USED(b); + mp_digit *pa, *pb, *pt, *pbt; + + if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) + return res; + + /* This has the effect of left-padding with zeroes... */ + USED(&tmp) = ua + ub; + + /* We're going to need the base value each iteration */ + pbt = DIGITS(&tmp); + + /* Outer loop: Digits of b */ + + pb = DIGITS(b); + for(ix = 0; ix < ub; ++ix, ++pb) { + if(*pb == 0) + continue; + + /* Inner product: Digits of a */ + pa = DIGITS(a); + for(jx = 0; jx < ua; ++jx, ++pa) { + pt = pbt + ix + jx; + w = *pb * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + pbt[ix + jx] = k; + k = 0; + } + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_mul() */ + +/* }}} */ + +/* {{{ s_mp_kmul(a, b, out, len) */ + +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) +{ + mp_word w, k = 0; + mp_size ix, jx; + mp_digit *pa, *pt; + + for(ix = 0; ix < len; ++ix, ++b) { + if(*b == 0) + continue; + + pa = a; + for(jx = 0; jx < len; ++jx, ++pa) { + pt = out + ix + jx; + w = *b * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + out[ix + jx] = k; + k = 0; + } + +} /* end s_mp_kmul() */ +#endif + +/* }}} */ + +/* {{{ s_mp_sqr(a) */ + +/* + Computes the square of a, in place. This can be done more + efficiently than a general multiplication, because many of the + computation steps are redundant when squaring. The inner product + step is a bit more complicated, but we save a fair number of + iterations of the multiplication loop. + */ +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, kx, used = USED(a); + mp_digit *pa1, *pa2, *pt, *pbt; + + if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) + return res; + + /* Left-pad with zeroes */ + USED(&tmp) = 2 * used; + + /* We need the base value each time through the loop */ + pbt = DIGITS(&tmp); + + pa1 = DIGITS(a); + for(ix = 0; ix < used; ++ix, ++pa1) { + if(*pa1 == 0) + continue; + + w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); + + pbt[ix + ix] = ACCUM(w); + k = CARRYOUT(w); + + /* + The inner product is computed as: + + (C, S) = t[i,j] + 2 a[i] a[j] + C + + This can overflow what can be represented in an mp_word, and + since C arithmetic does not provide any way to check for + overflow, we have to check explicitly for overflow conditions + before they happen. + */ + for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { + mp_word u = 0, v; + + /* Store this in a temporary to avoid indirections later */ + pt = pbt + ix + jx; + + /* Compute the multiplicative step */ + w = *pa1 * *pa2; + + /* If w is more than half MP_WORD_MAX, the doubling will + overflow, and we need to record a carry out into the next + word */ + u = (w >> (MP_WORD_BIT - 1)) & 1; + + /* Double what we've got, overflow will be ignored as defined + for C arithmetic (we've already noted if it is to occur) + */ + w *= 2; + + /* Compute the additive step */ + v = *pt + k; + + /* If we do not already have an overflow carry, check to see + if the addition will cause one, and set the carry out if so + */ + u |= ((MP_WORD_MAX - v) < w); + + /* Add in the rest, again ignoring overflow */ + w += v; + + /* Set the i,j digit of the output */ + *pt = ACCUM(w); + + /* Save carry information for the next iteration of the loop. + This is why k must be an mp_word, instead of an mp_digit */ + k = CARRYOUT(w) | (u << DIGIT_BIT); + + } /* for(jx ...) */ + + /* Set the last digit in the cycle and reset the carry */ + k = DIGIT(&tmp, ix + jx) + k; + pbt[ix + jx] = ACCUM(k); + k = CARRYOUT(k); + + /* If we are carrying out, propagate the carry to the next digit + in the output. This may cascade, so we have to be somewhat + circumspect -- but we will have enough precision in the output + that we won't overflow + */ + kx = 1; + while(k) { + k = pbt[ix + jx + kx] + 1; + pbt[ix + jx + kx] = ACCUM(k); + k = CARRYOUT(k); + ++kx; + } + } /* for(ix ...) */ + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ s_mp_div(a, b) */ + +/* + s_mp_div(a, b) + + Compute a = a / b and b = a mod b. Assumes b > a. + */ + +mp_err s_mp_div(mp_int *a, mp_int *b) +{ + mp_int quot, rem, t; + mp_word q; + mp_err res; + mp_digit d; + int ix; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Shortcut if b is power of two */ + if((ix = s_mp_ispow2(b)) >= 0) { + mp_copy(a, b); /* need this for remainder */ + s_mp_div_2d(a, (mp_digit)ix); + s_mp_mod_2d(b, (mp_digit)ix); + + return MP_OKAY; + } + + /* Allocate space to store the quotient */ + if((res = mp_init_size(", USED(a))) != MP_OKAY) + return res; + + /* A working temporary for division */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + goto T; + + /* Allocate space for the remainder */ + if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) + goto REM; + + /* Normalize to optimize guessing */ + d = s_mp_norm(a, b); + + /* Perform the division itself...woo! */ + ix = USED(a) - 1; + + while(ix >= 0) { + /* Find a partial substring of a which is at least b */ + while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { + if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_lshd(", 1)) != MP_OKAY) + goto CLEANUP; + + DIGIT(&rem, 0) = DIGIT(a, ix); + s_mp_clamp(&rem); + --ix; + } + + /* If we didn't find one, we're finished dividing */ + if(s_mp_cmp(&rem, b) < 0) + break; + + /* Compute a guess for the next quotient digit */ + q = DIGIT(&rem, USED(&rem) - 1); + if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) + q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); + + q /= DIGIT(b, USED(b) - 1); + + /* The guess can be as much as RADIX + 1 */ + if(q >= RADIX) + q = RADIX - 1; + + /* See what that multiplies out to */ + mp_copy(b, &t); + if((res = s_mp_mul_d(&t, q)) != MP_OKAY) + goto CLEANUP; + + /* + If it's too big, back it off. We should not have to do this + more than once, or, in rare cases, twice. Knuth describes a + method by which this could be reduced to a maximum of once, but + I didn't implement that here. + */ + while(s_mp_cmp(&t, &rem) > 0) { + --q; + s_mp_sub(&t, b); + } + + /* At this point, q should be the right next digit */ + if((res = s_mp_sub(&rem, &t)) != MP_OKAY) + goto CLEANUP; + + /* + Include the digit in the quotient. We allocated enough memory + for any quotient we could ever possibly get, so we should not + have to check for failures here + */ + DIGIT(", 0) = q; + } + + /* Denormalize remainder */ + if(d != 0) + s_mp_div_2d(&rem, d); + + s_mp_clamp("); + s_mp_clamp(&rem); + + /* Copy quotient back to output */ + s_mp_exch(", a); + + /* Copy remainder back to output */ + s_mp_exch(&rem, b); + +CLEANUP: + mp_clear(&rem); +REM: + mp_clear(&t); +T: + mp_clear("); + + return res; + +} /* end s_mp_div() */ + +/* }}} */ + +/* {{{ s_mp_2expt(a, k) */ + +mp_err s_mp_2expt(mp_int *a, mp_digit k) +{ + mp_err res; + mp_size dig, bit; + + dig = k / DIGIT_BIT; + bit = k % DIGIT_BIT; + + mp_zero(a); + if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) + return res; + + DIGIT(a, dig) |= (1 << bit); + + return MP_OKAY; + +} /* end s_mp_2expt() */ + +/* }}} */ + + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive comparisons */ + +/* {{{ s_mp_cmp(a, b) */ + +/* Compare |a| <=> |b|, return 0 if equal, <0 if a0 if a>b */ +int s_mp_cmp(mp_int *a, mp_int *b) +{ + mp_size ua = USED(a), ub = USED(b); + + if(ua > ub) + return MP_GT; + else if(ua < ub) + return MP_LT; + else { + int ix = ua - 1; + mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; + + while(ix >= 0) { + if(*ap > *bp) + return MP_GT; + else if(*ap < *bp) + return MP_LT; + + --ap; --bp; --ix; + } + + return MP_EQ; + } + +} /* end s_mp_cmp() */ + +/* }}} */ + +/* {{{ s_mp_cmp_d(a, d) */ + +/* Compare |a| <=> d, return 0 if equal, <0 if a0 if a>d */ +int s_mp_cmp_d(mp_int *a, mp_digit d) +{ + mp_size ua = USED(a); + mp_digit *ap = DIGITS(a); + + if(ua > 1) + return MP_GT; + + if(*ap < d) + return MP_LT; + else if(*ap > d) + return MP_GT; + else + return MP_EQ; + +} /* end s_mp_cmp_d() */ + +/* }}} */ + +/* {{{ s_mp_ispow2(v) */ + +/* + Returns -1 if the value is not a power of two; otherwise, it returns + k such that v = 2^k, i.e. lg(v). + */ +int s_mp_ispow2(mp_int *v) +{ + mp_digit d, *dp; + mp_size uv = USED(v); + int extra = 0, ix; + + d = DIGIT(v, uv - 1); /* most significant digit of v */ + + while(d && ((d & 1) == 0)) { + d >>= 1; + ++extra; + } + + if(d == 1) { + ix = uv - 2; + dp = DIGITS(v) + ix; + + while(ix >= 0) { + if(*dp) + return -1; /* not a power of two */ + + --dp; --ix; + } + + return ((uv - 1) * DIGIT_BIT) + extra; + } + + return -1; + +} /* end s_mp_ispow2() */ + +/* }}} */ + +/* {{{ s_mp_ispow2d(d) */ + +int s_mp_ispow2d(mp_digit d) +{ + int pow = 0; + + while((d & 1) == 0) { + ++pow; d >>= 1; + } + + if(d == 1) + return pow; + + return -1; + +} /* end s_mp_ispow2d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive I/O helpers */ + +/* {{{ s_mp_tovalue(ch, r) */ + +/* + Convert the given character to its digit value, in the given radix. + If the given character is not understood in the given radix, -1 is + returned. Otherwise the digit's numeric value is returned. + + The results will be odd if you use a radix < 2 or > 62, you are + expected to know what you're up to. + */ +int s_mp_tovalue(char ch, int r) +{ + int val, xch; + + if(r > 36) + xch = ch; + else + xch = toupper(ch); + + if(isdigit(xch)) + val = xch - '0'; + else if(isupper(xch)) + val = xch - 'A' + 10; + else if(islower(xch)) + val = xch - 'a' + 36; + else if(xch == '+') + val = 62; + else if(xch == '/') + val = 63; + else + return -1; + + if(val < 0 || val >= r) + return -1; + + return val; + +} /* end s_mp_tovalue() */ + +/* }}} */ + +/* {{{ s_mp_todigit(val, r, low) */ + +/* + Convert val to a radix-r digit, if possible. If val is out of range + for r, returns zero. Otherwise, returns an ASCII character denoting + the value in the given radix. + + The results may be odd if you use a radix < 2 or > 64, you are + expected to know what you're doing. + */ + +char s_mp_todigit(int val, int r, int low) +{ + char ch; + + if(val < 0 || val >= r) + return 0; + + ch = s_dmap_1[val]; + + if(r <= 36 && low) + ch = tolower(ch); + + return ch; + +} /* end s_mp_todigit() */ + +/* }}} */ + +/* {{{ s_mp_outlen(bits, radix) */ + +/* + Return an estimate for how long a string is needed to hold a radix + r representation of a number with 'bits' significant bits. + + Does not include space for a sign or a NUL terminator. + */ +int s_mp_outlen(int bits, int r) +{ + return (int)((double)bits * LOG_V_2(r)); + +} /* end s_mp_outlen() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* HERE THERE BE DRAGONS */ +/* crc==4242132123, version==2, Sat Feb 02 06:43:52 2002 */ + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.h b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.h new file mode 100644 index 0000000..9a9cc41 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mpi.h @@ -0,0 +1,233 @@ +/* + mpi.h + + by Michael J. Fromberger + Copyright (C) 1998 Michael J. Fromberger + + Arbitrary precision integer arithmetic library + + SPDX-License-Identifier: Unlicense + + $Id$ + */ + +#ifndef _H_MPI_ +#define _H_MPI_ + +#include "mpi-config.h" + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +#if MP_DEBUG +#undef MP_IOFUNC +#define MP_IOFUNC 1 +#endif + +#if MP_IOFUNC +#include +#include +#endif + +#include + +#define MP_NEG 1 +#define MP_ZPOS 0 + +/* Included for compatibility... */ +#define NEG MP_NEG +#define ZPOS MP_ZPOS + +#define MP_OKAY 0 /* no error, all is well */ +#define MP_YES 0 /* yes (boolean result) */ +#define MP_NO -1 /* no (boolean result) */ +#define MP_MEM -2 /* out of memory */ +#define MP_RANGE -3 /* argument out of range */ +#define MP_BADARG -4 /* invalid parameter */ +#define MP_UNDEF -5 /* answer is undefined */ +#define MP_LAST_CODE MP_UNDEF + +#include "mpi-types.h" + +/* Included for compatibility... */ +#define DIGIT_BIT MP_DIGIT_BIT +#define DIGIT_MAX MP_DIGIT_MAX + +/* Macros for accessing the mp_int internals */ +#define SIGN(MP) ((MP)->sign) +#define USED(MP) ((MP)->used) +#define ALLOC(MP) ((MP)->alloc) +#define DIGITS(MP) ((MP)->dp) +#define DIGIT(MP,N) (MP)->dp[(N)] + +#if MP_ARGCHK == 1 +#define ARGCHK(X,Y) {if(!(X)){return (Y);}} +#elif MP_ARGCHK == 2 +#include +#define ARGCHK(X,Y) assert(X) +#else +#define ARGCHK(X,Y) /* */ +#endif + +/* This defines the maximum I/O base (minimum is 2) */ +#define MAX_RADIX 64 + +typedef struct { + mp_sign sign; /* sign of this quantity */ + mp_size alloc; /* how many digits allocated */ + mp_size used; /* how many digits used */ + mp_digit *dp; /* the digits themselves */ +} mp_int; + +/*------------------------------------------------------------------------*/ +/* Default precision */ + +unsigned int mp_get_prec(void); +void mp_set_prec(unsigned int prec); + +/*------------------------------------------------------------------------*/ +/* Memory management */ + +mp_err mp_init(mp_int *mp); +mp_err mp_init_array(mp_int mp[], int count); +mp_err mp_init_size(mp_int *mp, mp_size prec); +mp_err mp_init_copy(mp_int *mp, mp_int *from); +mp_err mp_copy(mp_int *from, mp_int *to); +void mp_exch(mp_int *mp1, mp_int *mp2); +void mp_clear(mp_int *mp); +void mp_clear_array(mp_int mp[], int count); +void mp_zero(mp_int *mp); +void mp_set(mp_int *mp, mp_digit d); +mp_err mp_set_int(mp_int *mp, long z); +mp_err mp_shrink(mp_int *a); + + +/*------------------------------------------------------------------------*/ +/* Single digit arithmetic */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_2(mp_int *a, mp_int *c); +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r); +mp_err mp_div_2(mp_int *a, mp_int *c); +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c); + +/*------------------------------------------------------------------------*/ +/* Sign manipulations */ + +mp_err mp_abs(mp_int *a, mp_int *b); +mp_err mp_neg(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Full arithmetic */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c); +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b); +#else +#define mp_sqr(a, b) mp_mul(a, a, b) +#endif +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r); +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r); +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_2expt(mp_int *a, mp_digit k); +mp_err mp_sqrt(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Modular arithmetic */ + +#if MP_MODARITH +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c); +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c); +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c); +#else +#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c) +#endif +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c); +#endif /* MP_MODARITH */ + +/*------------------------------------------------------------------------*/ +/* Comparisons */ + +int mp_cmp_z(mp_int *a); +int mp_cmp_d(mp_int *a, mp_digit d); +int mp_cmp(mp_int *a, mp_int *b); +int mp_cmp_mag(mp_int *a, mp_int *b); +int mp_cmp_int(mp_int *a, long z); +int mp_isodd(mp_int *a); +int mp_iseven(mp_int *a); + +/*------------------------------------------------------------------------*/ +/* Number theoretic */ + +#if MP_NUMTH +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y); +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c); +#endif /* end MP_NUMTH */ + +/*------------------------------------------------------------------------*/ +/* Input and output */ + +#if MP_IOFUNC +void mp_print(mp_int *mp, FILE *ofp); +#endif /* end MP_IOFUNC */ + +/*------------------------------------------------------------------------*/ +/* Base conversion */ + +#define BITS 1 +#define BYTES CHAR_BIT + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len); +int mp_signed_bin_size(mp_int *mp); +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str); + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len); +int mp_unsigned_bin_size(mp_int *mp); +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); + +int mp_count_bits(mp_int *mp); + +#if MP_COMPAT_MACROS +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) +#endif + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix); +int mp_radix_size(mp_int *mp, int radix); +int mp_value_radix_size(int num, int qty, int radix); +mp_err mp_toradix(mp_int *mp, char *str, int radix); + +int mp_char2value(char ch, int r); + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/*------------------------------------------------------------------------*/ +/* Error strings */ + +const char *mp_strerror(mp_err ec); + +#endif /* end _H_MPI_ */ + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/mtest/mtest.c b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mtest.c new file mode 100644 index 0000000..06c9afb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/mtest/mtest.c @@ -0,0 +1,374 @@ +/* makes a bignum test harness with NUM tests per operation + * + * the output is made in the following format [one parameter per line] + +operation +operand1 +operand2 +[... operandN] +result1 +result2 +[... resultN] + +So for example "a * b mod n" would be + +mulmod +a +b +n +a*b mod n + +e.g. if a=3, b=4 n=11 then + +mulmod +3 +4 +11 +1 + + */ + +#ifdef MP_8BIT +#define THE_MASK 127 +#else +#define THE_MASK 32767 +#endif + +#include +#include +#include +#include "mpi.c" + +#ifdef LTM_MTEST_REAL_RAND +#define getRandChar() fgetc(rng) +FILE *rng; +#else +#define getRandChar() (rand()&0xFF) +#endif + +void rand_num(mp_int *a) +{ + int size; + unsigned char buf[2048]; + size_t sz; + + size = 1 + ((getRandChar()<<8) + getRandChar()) % 101; + buf[0] = (getRandChar()&1)?1:0; +#ifdef LTM_MTEST_REAL_RAND + sz = fread(buf+1, 1, size, rng); +#else + sz = 1; + while (sz < (unsigned)size) { + buf[sz] = getRandChar(); + ++sz; + } +#endif + if (sz != (unsigned)size) { + fprintf(stderr, "\nWarning: fread failed\n\n"); + } + while (buf[1] == 0) buf[1] = getRandChar(); + mp_read_raw(a, buf, 1+size); +} + +void rand_num2(mp_int *a) +{ + int size; + unsigned char buf[2048]; + size_t sz; + + size = 10 + ((getRandChar()<<8) + getRandChar()) % 101; + buf[0] = (getRandChar()&1)?1:0; +#ifdef LTM_MTEST_REAL_RAND + sz = fread(buf+1, 1, size, rng); +#else + sz = 1; + while (sz < (unsigned)size) { + buf[sz] = getRandChar(); + ++sz; + } +#endif + if (sz != (unsigned)size) { + fprintf(stderr, "\nWarning: fread failed\n\n"); + } + while (buf[1] == 0) buf[1] = getRandChar(); + mp_read_raw(a, buf, 1+size); +} + +#define mp_to64(a, b) mp_toradix(a, b, 64) + +int main(int argc, char *argv[]) +{ + int n, tmp; + long long max; + mp_int a, b, c, d, e; +#ifdef MTEST_NO_FULLSPEED + clock_t t1; +#endif + char buf[4096]; + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + + if (argc > 1) { + max = strtol(argv[1], NULL, 0); + if (max < 0) { + if (max > -64) { + max = (1 << -(max)) + 1; + } else { + max = 1; + } + } else if (max == 0) { + max = 1; + } + } else { + max = 0; + } + + + /* initial (2^n - 1)^2 testing, makes sure the comba multiplier works [it has the new carry code] */ + /* + mp_set(&a, 1); + for (n = 1; n < 8192; n++) { + mp_mul(&a, &a, &c); + printf("mul\n"); + mp_to64(&a, buf); + printf("%s\n%s\n", buf, buf); + mp_to64(&c, buf); + printf("%s\n", buf); + + mp_add_d(&a, 1, &a); + mp_mul_2(&a, &a); + mp_sub_d(&a, 1, &a); + } + */ + +#ifdef LTM_MTEST_REAL_RAND + rng = fopen("/dev/urandom", "rb"); + if (rng == NULL) { + rng = fopen("/dev/random", "rb"); + if (rng == NULL) { + fprintf(stderr, "\nWarning: no /dev/[u]random available\n\n"); + printf("exit\n"); + return 1; + } + } +#else + srand(23); +#endif + +#ifdef MTEST_NO_FULLSPEED + t1 = clock(); +#endif + for (;;) { +#ifdef MTEST_NO_FULLSPEED + if (clock() - t1 > CLOCKS_PER_SEC) { + sleep(2); + t1 = clock(); + } +#endif + n = getRandChar() % 15; + + if (max != 0) { + --max; + if (max == 0) + n = 255; + } + + if (n == 0) { + /* add tests */ + rand_num(&a); + rand_num(&b); + mp_add(&a, &b, &c); + printf("add\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 1) { + /* sub tests */ + rand_num(&a); + rand_num(&b); + mp_sub(&a, &b, &c); + printf("sub\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 2) { + /* mul tests */ + rand_num(&a); + rand_num(&b); + mp_mul(&a, &b, &c); + printf("mul\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 3) { + /* div tests */ + rand_num(&a); + rand_num(&b); + mp_div(&a, &b, &c, &d); + printf("div\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + mp_to64(&d, buf); + printf("%s\n", buf); + } else if (n == 4) { + /* sqr tests */ + rand_num(&a); + mp_sqr(&a, &b); + printf("sqr\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 5) { + /* mul_2d test */ + rand_num(&a); + mp_copy(&a, &b); + n = getRandChar() & 63; + mp_mul_2d(&b, n, &b); + mp_to64(&a, buf); + printf("mul2d\n"); + printf("%s\n", buf); + printf("%d\n", n); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 6) { + /* div_2d test */ + rand_num(&a); + mp_copy(&a, &b); + n = getRandChar() & 63; + mp_div_2d(&b, n, &b, NULL); + mp_to64(&a, buf); + printf("div2d\n"); + printf("%s\n", buf); + printf("%d\n", n); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 7) { + /* gcd test */ + rand_num(&a); + rand_num(&b); + a.sign = MP_ZPOS; + b.sign = MP_ZPOS; + mp_gcd(&a, &b, &c); + printf("gcd\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 8) { + /* lcm test */ + rand_num(&a); + rand_num(&b); + a.sign = MP_ZPOS; + b.sign = MP_ZPOS; + mp_lcm(&a, &b, &c); + printf("lcm\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 9) { + /* exptmod test */ + rand_num2(&a); + rand_num2(&b); + rand_num2(&c); + /* if (c.dp[0]&1) mp_add_d(&c, 1, &c); */ + a.sign = b.sign = c.sign = 0; + mp_exptmod(&a, &b, &c, &d); + printf("expt\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + mp_to64(&d, buf); + printf("%s\n", buf); + } else if (n == 10) { + /* invmod test */ + do { + rand_num2(&a); + rand_num2(&b); + b.sign = MP_ZPOS; + a.sign = MP_ZPOS; + mp_gcd(&a, &b, &c); + } while (mp_cmp_d(&c, 1) != 0 || mp_cmp_d(&b, 1) == 0); + mp_invmod(&a, &b, &c); + printf("invmod\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 11) { + rand_num(&a); + mp_mul_2(&a, &a); + mp_div_2(&a, &b); + printf("div2\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 12) { + rand_num2(&a); + mp_mul_2(&a, &b); + printf("mul2\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 13) { + rand_num2(&a); + tmp = abs(rand()) & THE_MASK; + mp_add_d(&a, tmp, &b); + printf("add_d\n"); + mp_to64(&a, buf); + printf("%s\n%d\n", buf, tmp); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 14) { + rand_num2(&a); + tmp = abs(rand()) & THE_MASK; + mp_sub_d(&a, tmp, &b); + printf("sub_d\n"); + mp_to64(&a, buf); + printf("%s\n%d\n", buf, tmp); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 255) { + printf("exit\n"); + break; + } + + } +#ifdef LTM_MTEST_REAL_RAND + fclose(rng); +#endif + return 0; +} + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/pre_gen/mpi.c b/third_party/heimdal/lib/hcrypto/libtommath/pre_gen/mpi.c new file mode 100644 index 0000000..96f001d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/pre_gen/mpi.c @@ -0,0 +1,9541 @@ +/* Start: bn_cutoffs.c */ +#include "tommath_private.h" +#ifdef BN_CUTOFFS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_FIXED_CUTOFFS +#include "tommath_cutoffs.h" +int KARATSUBA_MUL_CUTOFF = MP_DEFAULT_KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF = MP_DEFAULT_KARATSUBA_SQR_CUTOFF, + TOOM_MUL_CUTOFF = MP_DEFAULT_TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF = MP_DEFAULT_TOOM_SQR_CUTOFF; +#endif + +#endif + +/* End: bn_cutoffs.c */ + +/* Start: bn_deprecated.c */ +#include "tommath_private.h" +#ifdef BN_DEPRECATED_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef BN_MP_GET_BIT_C +int mp_get_bit(const mp_int *a, int b) +{ + if (b < 0) { + return MP_VAL; + } + return (s_mp_get_bit(a, (unsigned int)b) == MP_YES) ? MP_YES : MP_NO; +} +#endif +#ifdef BN_MP_JACOBI_C +mp_err mp_jacobi(const mp_int *a, const mp_int *n, int *c) +{ + if (a->sign == MP_NEG) { + return MP_VAL; + } + if (mp_cmp_d(n, 0uL) != MP_GT) { + return MP_VAL; + } + return mp_kronecker(a, n, c); +} +#endif +#ifdef BN_MP_PRIME_RANDOM_EX_C +mp_err mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat) +{ + return s_mp_prime_random_ex(a, t, size, flags, cb, dat); +} +#endif +#ifdef BN_MP_RAND_DIGIT_C +mp_err mp_rand_digit(mp_digit *r) +{ + mp_err err = s_mp_rand_source(r, sizeof(mp_digit)); + *r &= MP_MASK; + return err; +} +#endif +#ifdef BN_FAST_MP_INVMOD_C +mp_err fast_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_invmod_fast(a, b, c); +} +#endif +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +mp_err fast_mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) +{ + return s_mp_montgomery_reduce_fast(x, n, rho); +} +#endif +#ifdef BN_FAST_S_MP_MUL_DIGS_C +mp_err fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + return s_mp_mul_digs_fast(a, b, c, digs); +} +#endif +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C +mp_err fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + return s_mp_mul_high_digs_fast(a, b, c, digs); +} +#endif +#ifdef BN_FAST_S_MP_SQR_C +mp_err fast_s_mp_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_sqr_fast(a, b); +} +#endif +#ifdef BN_MP_BALANCE_MUL_C +mp_err mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_balance_mul(a, b, c); +} +#endif +#ifdef BN_MP_EXPTMOD_FAST_C +mp_err mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + return s_mp_exptmod_fast(G, X, P, Y, redmode); +} +#endif +#ifdef BN_MP_INVMOD_SLOW_C +mp_err mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_invmod_slow(a, b, c); +} +#endif +#ifdef BN_MP_KARATSUBA_MUL_C +mp_err mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_karatsuba_mul(a, b, c); +} +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +mp_err mp_karatsuba_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_karatsuba_sqr(a, b); +} +#endif +#ifdef BN_MP_TOOM_MUL_C +mp_err mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + return s_mp_toom_mul(a, b, c); +} +#endif +#ifdef BN_MP_TOOM_SQR_C +mp_err mp_toom_sqr(const mp_int *a, mp_int *b) +{ + return s_mp_toom_sqr(a, b); +} +#endif +#ifdef S_MP_REVERSE_C +void bn_reverse(unsigned char *s, int len) +{ + if (len > 0) { + s_mp_reverse(s, (size_t)len); + } +} +#endif +#ifdef BN_MP_TC_AND_C +mp_err mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_and(a, b, c); +} +#endif +#ifdef BN_MP_TC_OR_C +mp_err mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_or(a, b, c); +} +#endif +#ifdef BN_MP_TC_XOR_C +mp_err mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c) +{ + return mp_xor(a, b, c); +} +#endif +#ifdef BN_MP_TC_DIV_2D_C +mp_err mp_tc_div_2d(const mp_int *a, int b, mp_int *c) +{ + return mp_signed_rsh(a, b, c); +} +#endif +#ifdef BN_MP_INIT_SET_INT_C +mp_err mp_init_set_int(mp_int *a, unsigned long b) +{ + return mp_init_u32(a, (uint32_t)b); +} +#endif +#ifdef BN_MP_SET_INT_C +mp_err mp_set_int(mp_int *a, unsigned long b) +{ + mp_set_u32(a, (uint32_t)b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_SET_LONG_C +mp_err mp_set_long(mp_int *a, unsigned long b) +{ + mp_set_u64(a, b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_SET_LONG_LONG_C +mp_err mp_set_long_long(mp_int *a, unsigned long long b) +{ + mp_set_u64(a, b); + return MP_OKAY; +} +#endif +#ifdef BN_MP_GET_INT_C +unsigned long mp_get_int(const mp_int *a) +{ + return (unsigned long)mp_get_mag_u32(a); +} +#endif +#ifdef BN_MP_GET_LONG_C +unsigned long mp_get_long(const mp_int *a) +{ + return (unsigned long)mp_get_mag_ul(a); +} +#endif +#ifdef BN_MP_GET_LONG_LONG_C +unsigned long long mp_get_long_long(const mp_int *a) +{ + return mp_get_mag_ull(a); +} +#endif +#ifdef BN_MP_PRIME_IS_DIVISIBLE_C +mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result) +{ + return s_mp_prime_is_divisible(a, result); +} +#endif +#ifdef BN_MP_EXPT_D_EX_C +mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) +{ + (void)fast; + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_expt_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_EXPT_D_C +mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c) +{ + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_expt_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_N_ROOT_EX_C +mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) +{ + (void)fast; + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_root_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_N_ROOT_C +mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c) +{ + if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) { + return MP_VAL; + } + return mp_root_u32(a, (uint32_t)b, c); +} +#endif +#ifdef BN_MP_UNSIGNED_BIN_SIZE_C +int mp_unsigned_bin_size(const mp_int *a) +{ + return (int)mp_ubin_size(a); +} +#endif +#ifdef BN_MP_READ_UNSIGNED_BIN_C +mp_err mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c) +{ + return mp_from_ubin(a, b, (size_t) c); +} +#endif +#ifdef BN_MP_TO_UNSIGNED_BIN_C +mp_err mp_to_unsigned_bin(const mp_int *a, unsigned char *b) +{ + return mp_to_ubin(a, b, SIZE_MAX, NULL); +} +#endif +#ifdef BN_MP_TO_UNSIGNED_BIN_N_C +mp_err mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) +{ + size_t n = mp_ubin_size(a); + if (*outlen < (unsigned long)n) { + return MP_VAL; + } + *outlen = (unsigned long)n; + return mp_to_ubin(a, b, n, NULL); +} +#endif +#ifdef BN_MP_SIGNED_BIN_SIZE_C +int mp_signed_bin_size(const mp_int *a) +{ + return (int)mp_sbin_size(a); +} +#endif +#ifdef BN_MP_READ_SIGNED_BIN_C +mp_err mp_read_signed_bin(mp_int *a, const unsigned char *b, int c) +{ + return mp_from_sbin(a, b, (size_t) c); +} +#endif +#ifdef BN_MP_TO_SIGNED_BIN_C +mp_err mp_to_signed_bin(const mp_int *a, unsigned char *b) +{ + return mp_to_sbin(a, b, SIZE_MAX, NULL); +} +#endif +#ifdef BN_MP_TO_SIGNED_BIN_N_C +mp_err mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) +{ + size_t n = mp_sbin_size(a); + if (*outlen < (unsigned long)n) { + return MP_VAL; + } + *outlen = (unsigned long)n; + return mp_to_sbin(a, b, n, NULL); +} +#endif +#ifdef BN_MP_TORADIX_N_C +mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen) +{ + if (maxlen < 0) { + return MP_VAL; + } + return mp_to_radix(a, str, (size_t)maxlen, NULL, radix); +} +#endif +#ifdef BN_MP_TORADIX_C +mp_err mp_toradix(const mp_int *a, char *str, int radix) +{ + return mp_to_radix(a, str, SIZE_MAX, NULL, radix); +} +#endif +#ifdef BN_MP_IMPORT_C +mp_err mp_import(mp_int *rop, size_t count, int order, size_t size, int endian, size_t nails, + const void *op) +{ + return mp_unpack(rop, count, order, size, endian, nails, op); +} +#endif +#ifdef BN_MP_EXPORT_C +mp_err mp_export(void *rop, size_t *countp, int order, size_t size, + int endian, size_t nails, const mp_int *op) +{ + return mp_pack(rop, SIZE_MAX, countp, order, size, endian, nails, op); +} +#endif +#endif + +/* End: bn_deprecated.c */ + +/* Start: bn_mp_2expt.c */ +#include "tommath_private.h" +#ifdef BN_MP_2EXPT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +mp_err mp_2expt(mp_int *a, int b) +{ + mp_err err; + + /* zero a as per default */ + mp_zero(a); + + /* grow a to accomodate the single bit */ + if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { + return err; + } + + /* set the used count of where the bit will go */ + a->used = (b / MP_DIGIT_BIT) + 1; + + /* put the single bit in its place */ + a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT); + + return MP_OKAY; +} +#endif + +/* End: bn_mp_2expt.c */ + +/* Start: bn_mp_abs.c */ +#include "tommath_private.h" +#ifdef BN_MP_ABS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +mp_err mp_abs(const mp_int *a, mp_int *b) +{ + mp_err err; + + /* copy a to b */ + if (a != b) { + if ((err = mp_copy(a, b)) != MP_OKAY) { + return err; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + +/* End: bn_mp_abs.c */ + +/* Start: bn_mp_add.c */ +#include "tommath_private.h" +#ifdef BN_MP_ADD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level addition (handles signs) */ +mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_sign sa, sb; + mp_err err; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + err = s_mp_add(a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag(a, b) == MP_LT) { + c->sign = sb; + err = s_mp_sub(b, a, c); + } else { + c->sign = sa; + err = s_mp_sub(a, b, c); + } + } + return err; +} + +#endif + +/* End: bn_mp_add.c */ + +/* Start: bn_mp_add_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_ADD_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit addition */ +mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_err err; + int ix, oldused; + mp_digit *tmpa, *tmpc; + + /* grow c as required */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if ((a->sign == MP_NEG) && ((a->used > 1) || (a->dp[0] >= b))) { + mp_int a_ = *a; + /* temporarily fix sign of a */ + a_.sign = MP_ZPOS; + + /* c = |a| - b */ + err = mp_sub_d(&a_, b, c); + + /* fix sign */ + c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return err; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digits, mu is carry */ + mp_digit mu = b; + for (ix = 0; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> MP_DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* now zero to oldused */ + MP_ZERO_DIGITS(tmpc, oldused - ix); + mp_clamp(c); + + return MP_OKAY; +} + +#endif + +/* End: bn_mp_add_d.c */ + +/* Start: bn_mp_addmod.c */ +#include "tommath_private.h" +#ifdef BN_MP_ADDMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a + b (mod c) */ +mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_add(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_addmod.c */ + +/* Start: bn_mp_and.c */ +#include "tommath_private.h" +#ifdef BN_MP_AND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement and */ +mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = ((a->sign == MP_NEG) && (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x & y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_and.c */ + +/* Start: bn_mp_clamp.c */ +#include "tommath_private.h" +#ifdef BN_MP_CLAMP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void mp_clamp(mp_int *a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} +#endif + +/* End: bn_mp_clamp.c */ + +/* Start: bn_mp_clear.c */ +#include "tommath_private.h" +#ifdef BN_MP_CLEAR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* clear one (frees) */ +void mp_clear(mp_int *a) +{ + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* free ram */ + MP_FREE_DIGITS(a->dp, a->alloc); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} +#endif + +/* End: bn_mp_clear.c */ + +/* Start: bn_mp_clear_multi.c */ +#include "tommath_private.h" +#ifdef BN_MP_CLEAR_MULTI_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int *next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int *); + } + va_end(args); +} +#endif + +/* End: bn_mp_clear_multi.c */ + +/* Start: bn_mp_cmp.c */ +#include "tommath_private.h" +#ifdef BN_MP_CMP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare two ints (signed)*/ +mp_ord mp_cmp(const mp_int *a, const mp_int *b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} +#endif + +/* End: bn_mp_cmp.c */ + +/* Start: bn_mp_cmp_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_CMP_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare a digit */ +mp_ord mp_cmp_d(const mp_int *a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} +#endif + +/* End: bn_mp_cmp_d.c */ + +/* Start: bn_mp_cmp_mag.c */ +#include "tommath_private.h" +#ifdef BN_MP_CMP_MAG_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* compare maginitude of two ints (unsigned) */ +mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) +{ + int n; + const mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} +#endif + +/* End: bn_mp_cmp_mag.c */ + +/* Start: bn_mp_cnt_lsb.c */ +#include "tommath_private.h" +#ifdef BN_MP_CNT_LSB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(const mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (MP_IS_ZERO(a)) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {} + q = a->dp[x]; + x *= MP_DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1u) == 0u) { + do { + qq = q & 15u; + x += lnz[qq]; + q >>= 4; + } while (qq == 0u); + } + return x; +} + +#endif + +/* End: bn_mp_cnt_lsb.c */ + +/* Start: bn_mp_complement.c */ +#include "tommath_private.h" +#ifdef BN_MP_COMPLEMENT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = ~a */ +mp_err mp_complement(const mp_int *a, mp_int *b) +{ + mp_err err = mp_neg(a, b); + return (err == MP_OKAY) ? mp_sub_d(b, 1uL, b) : err; +} +#endif + +/* End: bn_mp_complement.c */ + +/* Start: bn_mp_copy.c */ +#include "tommath_private.h" +#ifdef BN_MP_COPY_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* copy, b = a */ +mp_err mp_copy(const mp_int *a, mp_int *b) +{ + int n; + mp_digit *tmpa, *tmpb; + mp_err err; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((err = mp_grow(b, a->used)) != MP_OKAY) { + return err; + } + } + + /* zero b and copy the parameters over */ + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + MP_ZERO_DIGITS(tmpb, b->used - n); + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* End: bn_mp_copy.c */ + +/* Start: bn_mp_count_bits.c */ +#include "tommath_private.h" +#ifdef BN_MP_COUNT_BITS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* returns the number of bits in an int */ +int mp_count_bits(const mp_int *a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (MP_IS_ZERO(a)) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * MP_DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > 0u) { + ++r; + q >>= 1u; + } + return r; +} +#endif + +/* End: bn_mp_count_bits.c */ + +/* Start: bn_mp_decr.c */ +#include "tommath_private.h" +#ifdef BN_MP_DECR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Decrement "a" by one like "a--". Changes input! */ +mp_err mp_decr(mp_int *a) +{ + if (MP_IS_ZERO(a)) { + mp_set(a,1uL); + a->sign = MP_NEG; + return MP_OKAY; + } else if (a->sign == MP_NEG) { + mp_err err; + a->sign = MP_ZPOS; + if ((err = mp_incr(a)) != MP_OKAY) { + return err; + } + /* There is no -0 in LTM */ + if (!MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + return MP_OKAY; + } else if (a->dp[0] > 1uL) { + a->dp[0]--; + if (a->dp[0] == 0u) { + mp_zero(a); + } + return MP_OKAY; + } else { + return mp_sub_d(a, 1uL,a); + } +} +#endif + +/* End: bn_mp_decr.c */ + +/* Start: bn_mp_div.c */ +#include "tommath_private.h" +#ifdef BN_MP_DIV_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) +{ + mp_int ta, tb, tq, q; + int n, n2; + mp_err err; + + /* is divisor zero ? */ + if (MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag(a, b) == MP_LT) { + if (d != NULL) { + err = mp_copy(a, d); + } else { + err = MP_OKAY; + } + if (c != NULL) { + mp_zero(c); + } + return err; + } + + /* init our temps */ + if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) { + return err; + } + + + mp_set(&tq, 1uL); + n = mp_count_bits(a) - mp_count_bits(b); + if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR; + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR; + } + if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR; + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + if (c != NULL) { + mp_exch(c, &q); + c->sign = MP_IS_ZERO(c) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = MP_IS_ZERO(d) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return err; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) +{ + mp_int q, x, y, t1, t2; + int n, t, i, norm; + mp_sign neg; + mp_err err; + + /* is divisor zero ? */ + if (MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag(a, b) == MP_LT) { + if (d != NULL) { + err = mp_copy(a, d); + } else { + err = MP_OKAY; + } + if (c != NULL) { + mp_zero(c); + } + return err; + } + + if ((err = mp_init_size(&q, a->used + 2)) != MP_OKAY) { + return err; + } + q.used = a->used + 2; + + if ((err = mp_init(&t1)) != MP_OKAY) goto LBL_Q; + + if ((err = mp_init(&t2)) != MP_OKAY) goto LBL_T1; + + if ((err = mp_init_copy(&x, a)) != MP_OKAY) goto LBL_T2; + + if ((err = mp_init_copy(&y, b)) != MP_OKAY) goto LBL_X; + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**MP_DIGIT_BIT] */ + norm = mp_count_bits(&y) % MP_DIGIT_BIT; + if (norm < (MP_DIGIT_BIT - 1)) { + norm = (MP_DIGIT_BIT - 1) - norm; + if ((err = mp_mul_2d(&x, norm, &x)) != MP_OKAY) goto LBL_Y; + if ((err = mp_mul_2d(&y, norm, &y)) != MP_OKAY) goto LBL_Y; + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + /* y = y*b**{n-t} */ + if ((err = mp_lshd(&y, n - t)) != MP_OKAY) goto LBL_Y; + + while (mp_cmp(&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((err = mp_sub(&x, &y, &x)) != MP_OKAY) goto LBL_Y; + } + + /* reset y by shifting it back down */ + mp_rshd(&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)MP_DIGIT_BIT) - (mp_digit)1; + } else { + mp_word tmp; + tmp = (mp_word)x.dp[i] << (mp_word)MP_DIGIT_BIT; + tmp |= (mp_word)x.dp[i - 1]; + tmp /= (mp_word)y.dp[t]; + if (tmp > (mp_word)MP_MASK) { + tmp = MP_MASK; + } + q.dp[(i - t) - 1] = (mp_digit)(tmp & (mp_word)MP_MASK); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] + 1uL) & (mp_digit)MP_MASK; + do { + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & (mp_digit)MP_MASK; + + /* find left hand */ + mp_zero(&t1); + t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((err = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y; + + /* find right hand */ + t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2]; + t2.dp[1] = x.dp[i - 1]; /* i >= 1 always holds */ + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((err = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y; + + if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y; + + if ((err = mp_sub(&x, &t1, &x)) != MP_OKAY) goto LBL_Y; + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((err = mp_copy(&y, &t1)) != MP_OKAY) goto LBL_Y; + if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y; + if ((err = mp_add(&x, &t1, &x)) != MP_OKAY) goto LBL_Y; + + q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = (x.used == 0) ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + c->sign = neg; + } + + if (d != NULL) { + if ((err = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) goto LBL_Y; + mp_exch(&x, d); + } + + err = MP_OKAY; + +LBL_Y: + mp_clear(&y); +LBL_X: + mp_clear(&x); +LBL_T2: + mp_clear(&t2); +LBL_T1: + mp_clear(&t1); +LBL_Q: + mp_clear(&q); + return err; +} + +#endif + +#endif + +/* End: bn_mp_div.c */ + +/* Start: bn_mp_div_2.c */ +#include "tommath_private.h" +#ifdef BN_MP_DIV_2_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = a/2 */ +mp_err mp_div_2(const mp_int *a, mp_int *b) +{ + int x, oldused; + mp_digit r, rr, *tmpa, *tmpb; + mp_err err; + + /* copy */ + if (b->alloc < a->used) { + if ((err = mp_grow(b, a->used)) != MP_OKAY) { + return err; + } + } + + oldused = b->used; + b->used = a->used; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1u; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (MP_DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used); + + b->sign = a->sign; + mp_clamp(b); + return MP_OKAY; +} +#endif + +/* End: bn_mp_div_2.c */ + +/* Start: bn_mp_div_2d.c */ +#include "tommath_private.h" +#ifdef BN_MP_DIV_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) +{ + mp_digit D, r, rr; + int x; + mp_err err; + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + err = mp_copy(a, c); + if (d != NULL) { + mp_zero(d); + } + return err; + } + + /* copy */ + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + /* 'a' should not be used after here - it might be the same as d */ + + /* get the remainder */ + if (d != NULL) { + if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) { + return err; + } + } + + /* shift by as many digits in the bit count */ + if (b >= MP_DIGIT_BIT) { + mp_rshd(c, b / MP_DIGIT_BIT); + } + + /* shift any bit count < MP_DIGIT_BIT */ + D = (mp_digit)(b % MP_DIGIT_BIT); + if (D != 0u) { + mp_digit *tmpc, mask, shift; + + /* mask */ + mask = ((mp_digit)1 << D) - 1uL; + + /* shift for lsb */ + shift = (mp_digit)MP_DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_div_2d.c */ + +/* Start: bn_mp_div_3.c */ +#include "tommath_private.h" +#ifdef BN_MP_DIV_3_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* divide by three (based on routine from MPI and the GMP manual) */ +mp_err mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + mp_err err; + int ix; + + /* b = 2**MP_DIGIT_BIT / 3 */ + b = ((mp_word)1 << (mp_word)MP_DIGIT_BIT) / (mp_word)3; + + if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { + return err; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; + + if (w >= 3u) { + /* multiply w by [1/3] */ + t = (w * (mp_word)b) >> (mp_word)MP_DIGIT_BIT; + + /* now subtract 3 * [w/3] from w, to get the remainder */ + w -= t+t+t; + + /* fixup the remainder as required since + * the optimization is not exact. + */ + while (w >= 3u) { + t += 1u; + w -= 3u; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + /* [optional] store the remainder */ + if (d != NULL) { + *d = (mp_digit)w; + } + + /* [optional] store the quotient */ + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return err; +} + +#endif + +/* End: bn_mp_div_3.c */ + +/* Start: bn_mp_div_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_DIV_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit division (based on routine from MPI) */ +mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) +{ + mp_int q; + mp_word w; + mp_digit t; + mp_err err; + int ix; + + /* cannot divide by zero */ + if (b == 0u) { + return MP_VAL; + } + + /* quick outs */ + if ((b == 1u) || MP_IS_ZERO(a)) { + if (d != NULL) { + *d = 0; + } + if (c != NULL) { + return mp_copy(a, c); + } + return MP_OKAY; + } + + /* power of two ? */ + if ((b & (b - 1u)) == 0u) { + ix = 1; + while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL); + } + if (c != NULL) { + return mp_div_2d(a, ix, c, NULL); + } + return MP_OKAY; + } + + /* three? */ + if (MP_HAS(MP_DIV_3) && (b == 3u)) { + return mp_div_3(a, c, d); + } + + /* no easy answer [c'est la vie]. Just division */ + if ((err = mp_init_size(&q, a->used)) != MP_OKAY) { + return err; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix]; + + if (w >= b) { + t = (mp_digit)(w / b); + w -= (mp_word)t * (mp_word)b; + } else { + t = 0; + } + q.dp[ix] = t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return err; +} + +#endif + +/* End: bn_mp_div_d.c */ + +/* Start: bn_mp_dr_is_modulus.c */ +#include "tommath_private.h" +#ifdef BN_MP_DR_IS_MODULUS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if a number is a valid DR modulus */ +mp_bool mp_dr_is_modulus(const mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return MP_NO; + } + + /* must be of the form b**k - a [a <= b] so all + * but the first digit must be equal to -1 (mod b). + */ + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return MP_NO; + } + } + return MP_YES; +} + +#endif + +/* End: bn_mp_dr_is_modulus.c */ + +/* Start: bn_mp_dr_reduce.c */ +#include "tommath_private.h" +#ifdef BN_MP_DR_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Joong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) +{ + mp_err err; + int i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < (m + m)) { + if ((err = mp_grow(x, m + m)) != MP_OKAY) { + return err; + } + } + + /* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++ * (mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + MP_ZERO_DIGITS(tmpx1, (x->used - m) - 1); + + /* clamp, sub and return */ + mp_clamp(x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag(x, n) != MP_LT) { + if ((err = s_mp_sub(x, n, x)) != MP_OKAY) { + return err; + } + goto top; + } + return MP_OKAY; +} +#endif + +/* End: bn_mp_dr_reduce.c */ + +/* Start: bn_mp_dr_setup.c */ +#include "tommath_private.h" +#ifdef BN_MP_DR_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +void mp_dr_setup(const mp_int *a, mp_digit *d) +{ + /* the casts are required if MP_DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31] + */ + *d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]); +} + +#endif + +/* End: bn_mp_dr_setup.c */ + +/* Start: bn_mp_error_to_string.c */ +#include "tommath_private.h" +#ifdef BN_MP_ERROR_TO_STRING_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* return a char * string for a given code */ +const char *mp_error_to_string(mp_err code) +{ + switch (code) { + case MP_OKAY: + return "Successful"; + case MP_ERR: + return "Unknown error"; + case MP_MEM: + return "Out of heap"; + case MP_VAL: + return "Value out of range"; + case MP_ITER: + return "Max. iterations reached"; + case MP_BUF: + return "Buffer overflow"; + default: + return "Invalid error code"; + } +} + +#endif + +/* End: bn_mp_error_to_string.c */ + +/* Start: bn_mp_exch.c */ +#include "tommath_private.h" +#ifdef BN_MP_EXCH_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void mp_exch(mp_int *a, mp_int *b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} +#endif + +/* End: bn_mp_exch.c */ + +/* Start: bn_mp_expt_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_EXPT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* calculate c = a**b using a square-multiply algorithm */ +mp_err mp_expt_u32(const mp_int *a, uint32_t b, mp_int *c) +{ + mp_err err; + + mp_int g; + + if ((err = mp_init_copy(&g, a)) != MP_OKAY) { + return err; + } + + /* set initial result */ + mp_set(c, 1uL); + + while (b > 0u) { + /* if the bit is set multiply */ + if ((b & 1u) != 0u) { + if ((err = mp_mul(c, &g, c)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* square */ + if (b > 1u) { + if ((err = mp_sqr(&g, &g)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* shift to next bit */ + b >>= 1; + } + + err = MP_OKAY; + +LBL_ERR: + mp_clear(&g); + return err; +} + +#endif + +/* End: bn_mp_expt_u32.c */ + +/* Start: bn_mp_exptmod.c */ +#include "tommath_private.h" +#ifdef BN_MP_EXPTMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + mp_err err; + + if (!MP_HAS(MP_INVMOD)) { + return MP_VAL; + } + + if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) { + return err; + } + + /* first compute 1/G mod P */ + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + goto LBL_ERR; + } + + /* now get |X| */ + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + goto LBL_ERR; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); +LBL_ERR: + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* modified diminished radix reduction */ + if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) && + (mp_reduce_is_2k_l(P) == MP_YES)) { + return s_mp_exptmod(G, X, P, Y, 1); + } + + /* is it a DR modulus? default to no */ + dr = (MP_HAS(MP_DR_IS_MODULUS) && (mp_dr_is_modulus(P) == MP_YES)) ? 1 : 0; + + /* if not, is it a unrestricted DR modulus? */ + if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) { + dr = (mp_reduce_is_2k(P) == MP_YES) ? 2 : 0; + } + + /* if the modulus is odd or dr != 0 use the montgomery method */ + if (MP_HAS(S_MP_EXPTMOD_FAST) && (MP_IS_ODD(P) || (dr != 0))) { + return s_mp_exptmod_fast(G, X, P, Y, dr); + } else if (MP_HAS(S_MP_EXPTMOD)) { + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod(G, X, P, Y, 0); + } else { + /* no exptmod for evens */ + return MP_VAL; + } +} + +#endif + +/* End: bn_mp_exptmod.c */ + +/* Start: bn_mp_exteuclid.c */ +#include "tommath_private.h" +#ifdef BN_MP_EXTEUCLID_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Extended euclidean algorithm of (a, b) produces + a*u1 + b*u2 = u3 + */ +mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) +{ + mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp; + mp_err err; + + if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) { + return err; + } + + /* initialize, (u1,u2,u3) = (1,0,a) */ + mp_set(&u1, 1uL); + if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR; + + /* initialize, (v1,v2,v3) = (0,1,b) */ + mp_set(&v2, 1uL); + if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR; + + /* loop while v3 != 0 */ + while (!MP_IS_ZERO(&v3)) { + /* q = u3/v3 */ + if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR; + + /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ + if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR; + + /* (u1,u2,u3) = (v1,v2,v3) */ + if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR; + + /* (v1,v2,v3) = (t1,t2,t3) */ + if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR; + } + + /* make sure U3 >= 0 */ + if (u3.sign == MP_NEG) { + if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR; + } + + /* copy result out */ + if (U1 != NULL) { + mp_exch(U1, &u1); + } + if (U2 != NULL) { + mp_exch(U2, &u2); + } + if (U3 != NULL) { + mp_exch(U3, &u3); + } + + err = MP_OKAY; +LBL_ERR: + mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); + return err; +} +#endif + +/* End: bn_mp_exteuclid.c */ + +/* Start: bn_mp_fread.c */ +#include "tommath_private.h" +#ifdef BN_MP_FREAD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +/* read a bigint from a file stream in ASCII */ +mp_err mp_fread(mp_int *a, int radix, FILE *stream) +{ + mp_err err; + mp_sign neg; + + /* if first digit is - then set negative */ + int ch = fgetc(stream); + if (ch == (int)'-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + /* no digits, return error */ + if (ch == EOF) { + return MP_ERR; + } + + /* clear a */ + mp_zero(a); + + do { + int y; + unsigned pos = (unsigned)(ch - (int)'('); + if (mp_s_rmap_reverse_sz < pos) { + break; + } + + y = (int)mp_s_rmap_reverse[pos]; + + if ((y == 0xff) || (y >= radix)) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) { + return err; + } + } while ((ch = fgetc(stream)) != EOF); + + if (a->used != 0) { + a->sign = neg; + } + + return MP_OKAY; +} +#endif + +#endif + +/* End: bn_mp_fread.c */ + +/* Start: bn_mp_from_sbin.c */ +#include "tommath_private.h" +#ifdef BN_MP_FROM_SBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +mp_err mp_from_sbin(mp_int *a, const unsigned char *buf, size_t size) +{ + mp_err err; + + /* read magnitude */ + if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) { + return err; + } + + /* first byte is 0 for positive, non-zero for negative */ + if (buf[0] == (unsigned char)0) { + a->sign = MP_ZPOS; + } else { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#endif + +/* End: bn_mp_from_sbin.c */ + +/* Start: bn_mp_from_ubin.c */ +#include "tommath_private.h" +#ifdef BN_MP_FROM_UBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +mp_err mp_from_ubin(mp_int *a, const unsigned char *buf, size_t size) +{ + mp_err err; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((err = mp_grow(a, 2)) != MP_OKAY) { + return err; + } + } + + /* zero the int */ + mp_zero(a); + + /* read the bytes in */ + while (size-- > 0u) { + if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) { + return err; + } + +#ifndef MP_8BIT + a->dp[0] |= *buf++; + a->used += 1; +#else + a->dp[0] = (*buf & MP_MASK); + a->dp[1] |= ((*buf++ >> 7) & 1u); + a->used += 2; +#endif + } + mp_clamp(a); + return MP_OKAY; +} +#endif + +/* End: bn_mp_from_ubin.c */ + +/* Start: bn_mp_fwrite.c */ +#include "tommath_private.h" +#ifdef BN_MP_FWRITE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef MP_NO_FILE +mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) +{ + char *buf; + mp_err err; + int len; + size_t written; + + /* TODO: this function is not in this PR */ + if (MP_HAS(MP_RADIX_SIZE_OVERESTIMATE)) { + /* if ((err = mp_radix_size_overestimate(&t, base, &len)) != MP_OKAY) goto LBL_ERR; */ + } else { + if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) { + return err; + } + } + + buf = (char *) MP_MALLOC((size_t)len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_to_radix(a, buf, (size_t)len, &written, radix)) != MP_OKAY) { + goto LBL_ERR; + } + + if (fwrite(buf, written, 1uL, stream) != 1uL) { + err = MP_ERR; + goto LBL_ERR; + } + err = MP_OKAY; + + +LBL_ERR: + MP_FREE_BUFFER(buf, (size_t)len); + return err; +} +#endif + +#endif + +/* End: bn_mp_fwrite.c */ + +/* Start: bn_mp_gcd.c */ +#include "tommath_private.h" +#ifdef BN_MP_GCD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Greatest Common Divisor using the binary method */ +mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int u, v; + int k, u_lsb, v_lsb; + mp_err err; + + /* either zero than gcd is the largest */ + if (MP_IS_ZERO(a)) { + return mp_abs(b, c); + } + if (MP_IS_ZERO(b)) { + return mp_abs(a, c); + } + + /* get copies of a and b we can modify */ + if ((err = mp_init_copy(&u, a)) != MP_OKAY) { + return err; + } + + if ((err = mp_init_copy(&v, b)) != MP_OKAY) { + goto LBL_U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MP_MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + + if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + if (v_lsb != k) { + if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + while (!MP_IS_ZERO(&v)) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + /* swap u and v to make sure v is >= u */ + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto LBL_V; + } + + /* Divide out all factors of two */ + if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) { + goto LBL_V; + } + c->sign = MP_ZPOS; + err = MP_OKAY; +LBL_V: + mp_clear(&u); +LBL_U: + mp_clear(&v); + return err; +} +#endif + +/* End: bn_mp_gcd.c */ + +/* Start: bn_mp_get_double.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_DOUBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +double mp_get_double(const mp_int *a) +{ + int i; + double d = 0.0, fac = 1.0; + for (i = 0; i < MP_DIGIT_BIT; ++i) { + fac *= 2.0; + } + for (i = a->used; i --> 0;) { + d = (d * fac) + (double)a->dp[i]; + } + return (a->sign == MP_NEG) ? -d : d; +} +#endif + +/* End: bn_mp_get_double.c */ + +/* Start: bn_mp_get_i32.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t) +#endif + +/* End: bn_mp_get_i32.c */ + +/* Start: bn_mp_get_i64.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t) +#endif + +/* End: bn_mp_get_i64.c */ + +/* Start: bn_mp_get_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long) +#endif + +/* End: bn_mp_get_l.c */ + +/* Start: bn_mp_get_ll.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_SIGNED(mp_get_ll, mp_get_mag_ull, long long, unsigned long long) +#endif + +/* End: bn_mp_get_ll.c */ + +/* Start: bn_mp_get_mag_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_u32, uint32_t) +#endif + +/* End: bn_mp_get_mag_u32.c */ + +/* Start: bn_mp_get_mag_u64.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_u64, uint64_t) +#endif + +/* End: bn_mp_get_mag_u64.c */ + +/* Start: bn_mp_get_mag_ul.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_ul, unsigned long) +#endif + +/* End: bn_mp_get_mag_ul.c */ + +/* Start: bn_mp_get_mag_ull.c */ +#include "tommath_private.h" +#ifdef BN_MP_GET_MAG_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_GET_MAG(mp_get_mag_ull, unsigned long long) +#endif + +/* End: bn_mp_get_mag_ull.c */ + +/* Start: bn_mp_grow.c */ +#include "tommath_private.h" +#ifdef BN_MP_GROW_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* grow as required */ +mp_err mp_grow(mp_int *a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = (mp_digit *) MP_REALLOC(a->dp, + (size_t)a->alloc * sizeof(mp_digit), + (size_t)size * sizeof(mp_digit)); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + MP_ZERO_DIGITS(a->dp + i, a->alloc - i); + } + return MP_OKAY; +} +#endif + +/* End: bn_mp_grow.c */ + +/* Start: bn_mp_incr.c */ +#include "tommath_private.h" +#ifdef BN_MP_INCR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Increment "a" by one like "a++". Changes input! */ +mp_err mp_incr(mp_int *a) +{ + if (MP_IS_ZERO(a)) { + mp_set(a,1uL); + return MP_OKAY; + } else if (a->sign == MP_NEG) { + mp_err err; + a->sign = MP_ZPOS; + if ((err = mp_decr(a)) != MP_OKAY) { + return err; + } + /* There is no -0 in LTM */ + if (!MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + return MP_OKAY; + } else if (a->dp[0] < MP_DIGIT_MAX) { + a->dp[0]++; + return MP_OKAY; + } else { + return mp_add_d(a, 1uL,a); + } +} +#endif + +/* End: bn_mp_incr.c */ + +/* Start: bn_mp_init.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* init a new mp_int */ +mp_err mp_init(mp_int *a) +{ + /* allocate memory required and clear it */ + a->dp = (mp_digit *) MP_CALLOC((size_t)MP_PREC, sizeof(mp_digit)); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + +/* End: bn_mp_init.c */ + +/* Start: bn_mp_init_copy.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_COPY_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* creates "a" then copies b into it */ +mp_err mp_init_copy(mp_int *a, const mp_int *b) +{ + mp_err err; + + if ((err = mp_init_size(a, b->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_copy(b, a)) != MP_OKAY) { + mp_clear(a); + } + + return err; +} +#endif + +/* End: bn_mp_init_copy.c */ + +/* Start: bn_mp_init_i32.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t) +#endif + +/* End: bn_mp_init_i32.c */ + +/* Start: bn_mp_init_i64.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t) +#endif + +/* End: bn_mp_init_i64.c */ + +/* Start: bn_mp_init_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_l, mp_set_l, long) +#endif + +/* End: bn_mp_init_l.c */ + +/* Start: bn_mp_init_ll.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ll, mp_set_ll, long long) +#endif + +/* End: bn_mp_init_ll.c */ + +/* Start: bn_mp_init_multi.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_MULTI_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#include + +mp_err mp_init_multi(mp_int *mp, ...) +{ + mp_err err = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int *cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n-- != 0) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int *); + } + va_end(clean_args); + err = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int *); + } + va_end(args); + return err; /* Assumed ok, if error flagged above. */ +} + +#endif + +/* End: bn_mp_init_multi.c */ + +/* Start: bn_mp_init_set.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_SET_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* initialize and set a digit */ +mp_err mp_init_set(mp_int *a, mp_digit b) +{ + mp_err err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + mp_set(a, b); + return err; +} +#endif + +/* End: bn_mp_init_set.c */ + +/* Start: bn_mp_init_size.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* init an mp_init for a given size */ +mp_err mp_init_size(mp_int *a, int size) +{ + size = MP_MAX(MP_MIN_PREC, size); + + /* alloc mem */ + a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit)); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + +/* End: bn_mp_init_size.c */ + +/* Start: bn_mp_init_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t) +#endif + +/* End: bn_mp_init_u32.c */ + +/* Start: bn_mp_init_u64.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t) +#endif + +/* End: bn_mp_init_u64.c */ + +/* Start: bn_mp_init_ul.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long) +#endif + +/* End: bn_mp_init_ul.c */ + +/* Start: bn_mp_init_ull.c */ +#include "tommath_private.h" +#ifdef BN_MP_INIT_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_INIT_INT(mp_init_ull, mp_set_ull, unsigned long long) +#endif + +/* End: bn_mp_init_ull.c */ + +/* Start: bn_mp_invmod.c */ +#include "tommath_private.h" +#ifdef BN_MP_INVMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* hac 14.61, pp608 */ +mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + /* b cannot be negative and has to be >1 */ + if ((b->sign == MP_NEG) || (mp_cmp_d(b, 1uL) != MP_GT)) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (MP_HAS(S_MP_INVMOD_FAST) && MP_IS_ODD(b)) { + return s_mp_invmod_fast(a, b, c); + } + + return MP_HAS(S_MP_INVMOD_SLOW) + ? s_mp_invmod_slow(a, b, c) + : MP_VAL; +} +#endif + +/* End: bn_mp_invmod.c */ + +/* Start: bn_mp_is_square.c */ +#include "tommath_private.h" +#ifdef BN_MP_IS_SQUARE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Check if remainders are possible squares - fast exclude non-squares */ +static const char rem_128[128] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 +}; + +static const char rem_105[105] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 +}; + +/* Store non-zero to ret if arg is square, and zero if not */ +mp_err mp_is_square(const mp_int *arg, mp_bool *ret) +{ + mp_err err; + mp_digit c; + mp_int t; + unsigned long r; + + /* Default to Non-square :) */ + *ret = MP_NO; + + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + if (MP_IS_ZERO(arg)) { + return MP_OKAY; + } + + /* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */ + if (rem_128[127u & arg->dp[0]] == (char)1) { + return MP_OKAY; + } + + /* Next check mod 105 (3*5*7) */ + if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) { + return err; + } + if (rem_105[c] == (char)1) { + return MP_OKAY; + } + + + if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) { + return err; + } + if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) { + goto LBL_ERR; + } + r = mp_get_u32(&t); + /* Check for other prime modules, note it's not an ERROR but we must + * free "t" so the easiest way is to goto LBL_ERR. We know that err + * is already equal to MP_OKAY from the mp_mod call + */ + if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR; + if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR; + + /* Final check - is sqr(sqrt(arg)) == arg ? */ + if ((err = mp_sqrt(arg, &t)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_sqr(&t, &t)) != MP_OKAY) { + goto LBL_ERR; + } + + *ret = (mp_cmp_mag(&t, arg) == MP_EQ) ? MP_YES : MP_NO; +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_is_square.c */ + +/* Start: bn_mp_iseven.c */ +#include "tommath_private.h" +#ifdef BN_MP_ISEVEN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_bool mp_iseven(const mp_int *a) +{ + return MP_IS_EVEN(a) ? MP_YES : MP_NO; +} +#endif + +/* End: bn_mp_iseven.c */ + +/* Start: bn_mp_isodd.c */ +#include "tommath_private.h" +#ifdef BN_MP_ISODD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_bool mp_isodd(const mp_int *a) +{ + return MP_IS_ODD(a) ? MP_YES : MP_NO; +} +#endif + +/* End: bn_mp_isodd.c */ + +/* Start: bn_mp_kronecker.c */ +#include "tommath_private.h" +#ifdef BN_MP_KRONECKER_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + Kronecker symbol (a|p) + Straightforward implementation of algorithm 1.4.10 in + Henri Cohen: "A Course in Computational Algebraic Number Theory" + + @book{cohen2013course, + title={A course in computational algebraic number theory}, + author={Cohen, Henri}, + volume={138}, + year={2013}, + publisher={Springer Science \& Business Media} + } + */ +mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) +{ + mp_int a1, p1, r; + mp_err err; + int v, k; + + static const int table[8] = {0, 1, 0, -1, 0, -1, 0, 1}; + + if (MP_IS_ZERO(p)) { + if ((a->used == 1) && (a->dp[0] == 1u)) { + *c = 1; + } else { + *c = 0; + } + return MP_OKAY; + } + + if (MP_IS_EVEN(a) && MP_IS_EVEN(p)) { + *c = 0; + return MP_OKAY; + } + + if ((err = mp_init_copy(&a1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_init_copy(&p1, p)) != MP_OKAY) { + goto LBL_KRON_0; + } + + v = mp_cnt_lsb(&p1); + if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) { + goto LBL_KRON_1; + } + + if ((v & 1) == 0) { + k = 1; + } else { + k = table[a->dp[0] & 7u]; + } + + if (p1.sign == MP_NEG) { + p1.sign = MP_ZPOS; + if (a1.sign == MP_NEG) { + k = -k; + } + } + + if ((err = mp_init(&r)) != MP_OKAY) { + goto LBL_KRON_1; + } + + for (;;) { + if (MP_IS_ZERO(&a1)) { + if (mp_cmp_d(&p1, 1uL) == MP_EQ) { + *c = k; + goto LBL_KRON; + } else { + *c = 0; + goto LBL_KRON; + } + } + + v = mp_cnt_lsb(&a1); + if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) { + goto LBL_KRON; + } + + if ((v & 1) == 1) { + k = k * table[p1.dp[0] & 7u]; + } + + if (a1.sign == MP_NEG) { + /* + * Compute k = (-1)^((a1)*(p1-1)/4) * k + * a1.dp[0] + 1 cannot overflow because the MSB + * of the type mp_digit is not set by definition + */ + if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) { + k = -k; + } + } else { + /* compute k = (-1)^((a1-1)*(p1-1)/4) * k */ + if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) { + k = -k; + } + } + + if ((err = mp_copy(&a1, &r)) != MP_OKAY) { + goto LBL_KRON; + } + r.sign = MP_ZPOS; + if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) { + goto LBL_KRON; + } + if ((err = mp_copy(&r, &p1)) != MP_OKAY) { + goto LBL_KRON; + } + } + +LBL_KRON: + mp_clear(&r); +LBL_KRON_1: + mp_clear(&p1); +LBL_KRON_0: + mp_clear(&a1); + + return err; +} + +#endif + +/* End: bn_mp_kronecker.c */ + +/* Start: bn_mp_lcm.c */ +#include "tommath_private.h" +#ifdef BN_MP_LCM_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes least common multiple as |a*b|/(a, b) */ +mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + mp_int t1, t2; + + + if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) { + return err; + } + + /* t1 = get the GCD of the two inputs */ + if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) { + goto LBL_T; + } + + /* divide the smallest by the GCD */ + if (mp_cmp_mag(a, b) == MP_LT) { + /* store quotient in t2 such that t2 * b is the LCM */ + if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + err = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + err = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +LBL_T: + mp_clear_multi(&t1, &t2, NULL); + return err; +} +#endif + +/* End: bn_mp_lcm.c */ + +/* Start: bn_mp_log_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_LOG_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Compute log_{base}(a) */ +static mp_word s_pow(mp_word base, mp_word exponent) +{ + mp_word result = 1uLL; + while (exponent != 0u) { + if ((exponent & 1u) == 1u) { + result *= base; + } + exponent >>= 1; + base *= base; + } + + return result; +} + +static mp_digit s_digit_ilogb(mp_digit base, mp_digit n) +{ + mp_word bracket_low = 1uLL, bracket_mid, bracket_high, N; + mp_digit ret, high = 1uL, low = 0uL, mid; + + if (n < base) { + return 0uL; + } + if (n == base) { + return 1uL; + } + + bracket_high = (mp_word) base ; + N = (mp_word) n; + + while (bracket_high < N) { + low = high; + bracket_low = bracket_high; + high <<= 1; + bracket_high *= bracket_high; + } + + while (((mp_digit)(high - low)) > 1uL) { + mid = (low + high) >> 1; + bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low)); + + if (N < bracket_mid) { + high = mid ; + bracket_high = bracket_mid ; + } + if (N > bracket_mid) { + low = mid ; + bracket_low = bracket_mid ; + } + if (N == bracket_mid) { + return (mp_digit) mid; + } + } + + if (bracket_high == N) { + ret = high; + } else { + ret = low; + } + + return ret; +} + +/* TODO: output could be "int" because the output of mp_radix_size is int, too, + as is the output of mp_bitcount. + With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only! +*/ +mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c) +{ + mp_err err; + mp_ord cmp; + uint32_t high, low, mid; + mp_int bracket_low, bracket_high, bracket_mid, t, bi_base; + + err = MP_OKAY; + + if (a->sign == MP_NEG) { + return MP_VAL; + } + + if (MP_IS_ZERO(a)) { + return MP_VAL; + } + + if (base < 2u) { + return MP_VAL; + } + + /* A small shortcut for bases that are powers of two. */ + if ((base & (base - 1u)) == 0u) { + int y, bit_count; + for (y=0; (y < 7) && ((base & 1u) == 0u); y++) { + base >>= 1; + } + bit_count = mp_count_bits(a) - 1; + *c = (uint32_t)(bit_count/y); + return MP_OKAY; + } + + if (a->used == 1) { + *c = (uint32_t)s_digit_ilogb(base, a->dp[0]); + return err; + } + + cmp = mp_cmp_d(a, base); + if ((cmp == MP_LT) || (cmp == MP_EQ)) { + *c = cmp == MP_EQ; + return err; + } + + if ((err = + mp_init_multi(&bracket_low, &bracket_high, + &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) { + return err; + } + + low = 0u; + mp_set(&bracket_low, 1uL); + high = 1u; + + mp_set(&bracket_high, base); + + /* + A kind of Giant-step/baby-step algorithm. + Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/ + The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped + for small n. + */ + while (mp_cmp(&bracket_high, a) == MP_LT) { + low = high; + if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) { + goto LBL_ERR; + } + high <<= 1; + if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_set(&bi_base, base); + + while ((high - low) > 1u) { + mid = (high + low) >> 1; + + if ((err = mp_expt_u32(&bi_base, (uint32_t)(mid - low), &t)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) { + goto LBL_ERR; + } + cmp = mp_cmp(a, &bracket_mid); + if (cmp == MP_LT) { + high = mid; + mp_exch(&bracket_mid, &bracket_high); + } + if (cmp == MP_GT) { + low = mid; + mp_exch(&bracket_mid, &bracket_low); + } + if (cmp == MP_EQ) { + *c = mid; + goto LBL_END; + } + } + + *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low; + +LBL_END: +LBL_ERR: + mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid, + &t, &bi_base, NULL); + return err; +} + + +#endif + +/* End: bn_mp_log_u32.c */ + +/* Start: bn_mp_lshd.c */ +#include "tommath_private.h" +#ifdef BN_MP_LSHD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift left a certain amount of digits */ +mp_err mp_lshd(mp_int *a, int b) +{ + int x; + mp_err err; + mp_digit *top, *bottom; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + /* no need to shift 0 around */ + if (MP_IS_ZERO(a)) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < (a->used + b)) { + if ((err = mp_grow(a, a->used + b)) != MP_OKAY) { + return err; + } + } + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = (a->dp + a->used - 1) - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + MP_ZERO_DIGITS(a->dp, b); + + return MP_OKAY; +} +#endif + +/* End: bn_mp_lshd.c */ + +/* Start: bn_mp_mod.c */ +#include "tommath_private.h" +#ifdef BN_MP_MOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */ +mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int t; + mp_err err; + + if ((err = mp_init_size(&t, b->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_div(a, b, NULL, &t)) != MP_OKAY) { + goto LBL_ERR; + } + + if (MP_IS_ZERO(&t) || (t.sign == b->sign)) { + err = MP_OKAY; + mp_exch(&t, c); + } else { + err = mp_add(b, &t, c); + } + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_mod.c */ + +/* Start: bn_mp_mod_2d.c */ +#include "tommath_private.h" +#ifdef BN_MP_MOD_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* calc a value mod 2**b */ +mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) +{ + int x; + mp_err err; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero(c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (a->used * MP_DIGIT_BIT)) { + return mp_copy(a, c); + } + + /* copy */ + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + + /* zero digits above the last digit of the modulus */ + x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1); + MP_ZERO_DIGITS(c->dp + x, c->used - x); + + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / MP_DIGIT_BIT] &= + ((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1; + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_mod_2d.c */ + +/* Start: bn_mp_mod_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_MOD_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_err mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c) +{ + return mp_div_d(a, b, NULL, c); +} +#endif + +/* End: bn_mp_mod_d.c */ + +/* Start: bn_mp_montgomery_calc_normalization.c */ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) +{ + int x, bits; + mp_err err; + + /* how many bits of last digit does b use */ + bits = mp_count_bits(b) % MP_DIGIT_BIT; + + if (b->used > 1) { + if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) { + return err; + } + } else { + mp_set(a, 1uL); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) { + if ((err = mp_mul_2(a, a)) != MP_OKAY) { + return err; + } + if (mp_cmp_mag(a, b) != MP_LT) { + if ((err = s_mp_sub(a, b, a)) != MP_OKAY) { + return err; + } + } + } + + return MP_OKAY; +} +#endif + +/* End: bn_mp_montgomery_calc_normalization.c */ + +/* Start: bn_mp_montgomery_reduce.c */ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) +{ + int ix, digs; + mp_err err; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = (n->used * 2) + 1; + if ((digs < MP_WARRAY) && + (x->used <= MP_WARRAY) && + (n->used < MP_MAXFAST)) { + return s_mp_montgomery_reduce_fast(x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((err = mp_grow(x, digs)) != MP_OKAY) { + return err; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + int iy; + mp_digit *tmpn, *tmpx, u; + mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu * (mp_word)*tmpn++) + + (mp_word)u + (mp_word)*tmpx; + + /* get carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & (mp_word)MP_MASK); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u != 0u) { + *tmpx += u; + u = *tmpx >> MP_DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd(x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag(x, n) != MP_LT) { + return s_mp_sub(x, n, x); + } + + return MP_OKAY; +} +#endif + +/* End: bn_mp_montgomery_reduce.c */ + +/* Start: bn_mp_montgomery_setup.c */ +#include "tommath_private.h" +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* setups the montgomery reduction stuff */ +mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) +{ + mp_digit x, b; + + /* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1u) == 0u) { + return MP_VAL; + } + + x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2u - (b * x); /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2u - (b * x); /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2u - (b * x); /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2u - (b * x); /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + +/* End: bn_mp_montgomery_setup.c */ + +/* Start: bn_mp_mul.c */ +#include "tommath_private.h" +#ifdef BN_MP_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level multiplication (handles sign) */ +mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + int min_len = MP_MIN(a->used, b->used), + max_len = MP_MAX(a->used, b->used), + digs = a->used + b->used + 1; + mp_sign neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + if (MP_HAS(S_MP_BALANCE_MUL) && + /* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off. + * The bigger one needs to be at least about one MP_KARATSUBA_MUL_CUTOFF bigger + * to make some sense, but it depends on architecture, OS, position of the + * stars... so YMMV. + * Using it to cut the input into slices small enough for fast_s_mp_mul_digs + * was actually slower on the author's machine, but YMMV. + */ + (min_len >= MP_KARATSUBA_MUL_CUTOFF) && + ((max_len / 2) >= MP_KARATSUBA_MUL_CUTOFF) && + /* Not much effect was observed below a ratio of 1:2, but again: YMMV. */ + (max_len >= (2 * min_len))) { + err = s_mp_balance_mul(a,b,c); + } else if (MP_HAS(S_MP_TOOM_MUL) && + (min_len >= MP_TOOM_MUL_CUTOFF)) { + err = s_mp_toom_mul(a, b, c); + } else if (MP_HAS(S_MP_KARATSUBA_MUL) && + (min_len >= MP_KARATSUBA_MUL_CUTOFF)) { + err = s_mp_karatsuba_mul(a, b, c); + } else if (MP_HAS(S_MP_MUL_DIGS_FAST) && + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + (digs < MP_WARRAY) && + (min_len <= MP_MAXFAST)) { + err = s_mp_mul_digs_fast(a, b, c, digs); + } else if (MP_HAS(S_MP_MUL_DIGS)) { + err = s_mp_mul_digs(a, b, c, digs); + } else { + err = MP_VAL; + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return err; +} +#endif + +/* End: bn_mp_mul.c */ + +/* Start: bn_mp_mul_2.c */ +#include "tommath_private.h" +#ifdef BN_MP_MUL_2_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = a*2 */ +mp_err mp_mul_2(const mp_int *a, mp_int *b) +{ + int x, oldused; + mp_err err; + + /* grow to accomodate result */ + if (b->alloc < (a->used + 1)) { + if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) { + return err; + } + } + + oldused = b->used; + b->used = a->used; + + { + mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> (mp_digit)(MP_DIGIT_BIT - 1); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << 1uL) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0u) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used); + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* End: bn_mp_mul_2.c */ + +/* Start: bn_mp_mul_2d.c */ +#include "tommath_private.h" +#ifdef BN_MP_MUL_2D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift left by a certain bit count */ +mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) +{ + mp_digit d; + mp_err err; + + /* copy */ + if (a != c) { + if ((err = mp_copy(a, c)) != MP_OKAY) { + return err; + } + } + + if (c->alloc < (c->used + (b / MP_DIGIT_BIT) + 1)) { + if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) { + return err; + } + } + + /* shift by as many digits in the bit count */ + if (b >= MP_DIGIT_BIT) { + if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) { + return err; + } + } + + /* shift any bit count < MP_DIGIT_BIT */ + d = (mp_digit)(b % MP_DIGIT_BIT); + if (d != 0u) { + mp_digit *tmpc, shift, mask, r, rr; + int x; + + /* bitmask for carries */ + mask = ((mp_digit)1 << d) - (mp_digit)1; + + /* shift for msbs */ + shift = (mp_digit)MP_DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0u) { + c->dp[(c->used)++] = r; + } + } + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_mul_2d.c */ + +/* Start: bn_mp_mul_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_MUL_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiply by a digit */ +mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + mp_err err; + int ix, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = (mp_word)u + ((mp_word)*tmpa++ * (mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* send carry into next iteration */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif + +/* End: bn_mp_mul_d.c */ + +/* Start: bn_mp_mulmod.c */ +#include "tommath_private.h" +#ifdef BN_MP_MULMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a * b (mod c) */ +mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init_size(&t, c->used)) != MP_OKAY) { + return err; + } + + if ((err = mp_mul(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_mulmod.c */ + +/* Start: bn_mp_neg.c */ +#include "tommath_private.h" +#ifdef BN_MP_NEG_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* b = -a */ +mp_err mp_neg(const mp_int *a, mp_int *b) +{ + mp_err err; + if (a != b) { + if ((err = mp_copy(a, b)) != MP_OKAY) { + return err; + } + } + + if (!MP_IS_ZERO(b)) { + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } else { + b->sign = MP_ZPOS; + } + + return MP_OKAY; +} +#endif + +/* End: bn_mp_neg.c */ + +/* Start: bn_mp_or.c */ +#include "tommath_private.h" +#ifdef BN_MP_OR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement or */ +mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = ((a->sign == MP_NEG) || (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x | y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_or.c */ + +/* Start: bn_mp_pack.c */ +#include "tommath_private.h" +#ifdef BN_MP_PACK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* based on gmp's mpz_export. + * see http://gmplib.org/manual/Integer-Import-and-Export.html + */ +mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size, + mp_endian endian, size_t nails, const mp_int *op) +{ + mp_err err; + size_t odd_nails, nail_bytes, i, j, count; + unsigned char odd_nail_mask; + + mp_int t; + + count = mp_pack_count(op, nails, size); + + if (count > maxcount) { + return MP_BUF; + } + + if ((err = mp_init_copy(&t, op)) != MP_OKAY) { + return err; + } + + if (endian == MP_NATIVE_ENDIAN) { + MP_GET_ENDIANNESS(endian); + } + + odd_nails = (nails % 8u); + odd_nail_mask = 0xff; + for (i = 0u; i < odd_nails; ++i) { + odd_nail_mask ^= (unsigned char)(1u << (7u - i)); + } + nail_bytes = nails / 8u; + + for (i = 0u; i < count; ++i) { + for (j = 0u; j < size; ++j) { + unsigned char *byte = (unsigned char *)rop + + (((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) + + ((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j)); + + if (j >= (size - nail_bytes)) { + *byte = 0; + continue; + } + + *byte = (unsigned char)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL)); + + if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + + } + } + + if (written != NULL) { + *written = count; + } + err = MP_OKAY; + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif + +/* End: bn_mp_pack.c */ + +/* Start: bn_mp_pack_count.c */ +#include "tommath_private.h" +#ifdef BN_MP_PACK_COUNT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) +{ + size_t bits = (size_t)mp_count_bits(a); + return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u)); +} + +#endif + +/* End: bn_mp_pack_count.c */ + +/* Start: bn_mp_prime_fermat.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_FERMAT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* performs one Fermat test. + * + * If "a" were prime then b**a == b (mod a) since the order of + * the multiplicative sub-group would be phi(a) = a-1. That means + * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a). + * + * Sets result to 1 if the congruence holds, or zero otherwise. + */ +mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, mp_bool *result) +{ + mp_int t; + mp_err err; + + /* default to composite */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1uL) != MP_GT) { + return MP_VAL; + } + + /* init t */ + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + /* compute t = b**a mod a */ + if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) { + goto LBL_T; + } + + /* is it equal to b? */ + if (mp_cmp(&t, b) == MP_EQ) { + *result = MP_YES; + } + + err = MP_OKAY; +LBL_T: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_prime_fermat.c */ + +/* Start: bn_mp_prime_frobenius_underwood.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_FROBENIUS_UNDERWOOD_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details + */ +#ifndef LTM_USE_ONLY_MR + +#ifdef MP_8BIT +/* + * floor of positive solution of + * (2^16)-1 = (a+4)*(2*a+5) + * TODO: Both values are smaller than N^(1/4), would have to use a bigint + * for a instead but any a biger than about 120 are already so rare that + * it is possible to ignore them and still get enough pseudoprimes. + * But it is still a restriction of the set of available pseudoprimes + * which makes this implementation less secure if used stand-alone. + */ +#define LTM_FROBENIUS_UNDERWOOD_A 177 +#else +#define LTM_FROBENIUS_UNDERWOOD_A 32764 +#endif +mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result) +{ + mp_int T1z, T2z, Np1z, sz, tz; + + int a, ap2, length, i, j; + mp_err err; + + *result = MP_NO; + + if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) { + return err; + } + + for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) { + /* TODO: That's ugly! No, really, it is! */ + if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) || + (a==14) || (a==18) || (a==23) || (a==26) || (a==28)) { + continue; + } + /* (32764^2 - 4) < 2^31, no bigint for >MP_8BIT needed) */ + mp_set_u32(&T1z, (uint32_t)a); + + if ((err = mp_sqr(&T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if ((err = mp_sub_d(&T1z, 4uL, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_FU_ERR; + + if (j == -1) { + break; + } + + if (j == 0) { + /* composite */ + goto LBL_FU_ERR; + } + } + /* Tell it a composite and set return value accordingly */ + if (a >= LTM_FROBENIUS_UNDERWOOD_A) { + err = MP_ITER; + goto LBL_FU_ERR; + } + /* Composite if N and (a+4)*(2*a+5) are not coprime */ + mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5))); + + if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + + if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) goto LBL_FU_ERR; + + ap2 = a + 2; + if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_FU_ERR; + + mp_set(&sz, 1uL); + mp_set(&tz, 2uL); + length = mp_count_bits(&Np1z); + + for (i = length - 2; i >= 0; i--) { + /* + * temp = (sz*(a*sz+2*tz))%N; + * tz = ((tz-sz)*(tz+sz))%N; + * sz = temp; + */ + if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + + /* a = 0 at about 50% of the cases (non-square and odd input) */ + if (a != 0) { + if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + } + + if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_FU_ERR; + if (s_mp_get_bit(&Np1z, (unsigned int)i) == MP_YES) { + /* + * temp = (a+2) * sz + tz + * tz = 2 * tz - sz + * sz = temp + */ + if (a == 0) { + if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + } else { + if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + } + if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR; + if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_FU_ERR; + mp_exch(&sz, &T1z); + } + } + + mp_set_u32(&T1z, (uint32_t)((2 * a) + 5)); + if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_FU_ERR; + if (MP_IS_ZERO(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ)) { + *result = MP_YES; + } + +LBL_FU_ERR: + mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL); + return err; +} + +#endif +#endif + +/* End: bn_mp_prime_frobenius_underwood.c */ + +/* Start: bn_mp_prime_is_prime.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_IS_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* portable integer log of two with small footprint */ +static unsigned int s_floor_ilog2(int value) +{ + unsigned int r = 0; + while ((value >>= 1) != 0) { + r++; + } + return r; +} + + +mp_err mp_prime_is_prime(const mp_int *a, int t, mp_bool *result) +{ + mp_int b; + int ix, p_max = 0, size_a, len; + mp_bool res; + mp_err err; + unsigned int fips_rand, mask; + + /* default to no */ + *result = MP_NO; + + /* Some shortcuts */ + /* N > 3 */ + if (a->used == 1) { + if ((a->dp[0] == 0u) || (a->dp[0] == 1u)) { + *result = MP_NO; + return MP_OKAY; + } + if (a->dp[0] == 2u) { + *result = MP_YES; + return MP_OKAY; + } + } + + /* N must be odd */ + if (MP_IS_EVEN(a)) { + return MP_OKAY; + } + /* N is not a perfect square: floor(sqrt(N))^2 != N */ + if ((err = mp_is_square(a, &res)) != MP_OKAY) { + return err; + } + if (res != MP_NO) { + return MP_OKAY; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) { + if (mp_cmp_d(a, s_mp_prime_tab[ix]) == MP_EQ) { + *result = MP_YES; + return MP_OKAY; + } + } +#ifdef MP_8BIT + /* The search in the loop above was exhaustive in this case */ + if ((a->used == 1) && (PRIVATE_MP_PRIME_TAB_SIZE >= 31)) { + return MP_OKAY; + } +#endif + + /* first perform trial division */ + if ((err = s_mp_prime_is_divisible(a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* + Run the Miller-Rabin test with base 2 for the BPSW test. + */ + if ((err = mp_init_set(&b, 2uL)) != MP_OKAY) { + return err; + } + + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + /* + Rumours have it that Mathematica does a second M-R test with base 3. + Other rumours have it that their strong L-S test is slightly different. + It does not hurt, though, beside a bit of extra runtime. + */ + b.dp[0]++; + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + + /* + * Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite + * slow so if speed is an issue, define LTM_USE_ONLY_MR to use M-R tests with + * bases 2, 3 and t random bases. + */ +#ifndef LTM_USE_ONLY_MR + if (t >= 0) { + /* + * Use a Frobenius-Underwood test instead of the Lucas-Selfridge test for + * MP_8BIT (It is unknown if the Lucas-Selfridge test works with 16-bit + * integers but the necesssary analysis is on the todo-list). + */ +#if defined (MP_8BIT) || defined (LTM_USE_FROBENIUS_TEST) + err = mp_prime_frobenius_underwood(a, &res); + if ((err != MP_OKAY) && (err != MP_ITER)) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } +#else + if ((err = mp_prime_strong_lucas_selfridge(a, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } +#endif + } +#endif + + /* run at least one Miller-Rabin test with a random base */ + if (t == 0) { + t = 1; + } + + /* + Only recommended if the input range is known to be < 3317044064679887385961981 + + It uses the bases necessary for a deterministic M-R test if the input is + smaller than 3317044064679887385961981 + The caller has to check the size. + TODO: can be made a bit finer grained but comparing is not free. + */ + if (t < 0) { + /* + Sorenson, Jonathan; Webster, Jonathan (2015). + "Strong Pseudoprimes to Twelve Prime Bases". + */ + /* 0x437ae92817f9fc85b7e5 = 318665857834031151167461 */ + if ((err = mp_read_radix(&b, "437ae92817f9fc85b7e5", 16)) != MP_OKAY) { + goto LBL_B; + } + + if (mp_cmp(a, &b) == MP_LT) { + p_max = 12; + } else { + /* 0x2be6951adc5b22410a5fd = 3317044064679887385961981 */ + if ((err = mp_read_radix(&b, "2be6951adc5b22410a5fd", 16)) != MP_OKAY) { + goto LBL_B; + } + + if (mp_cmp(a, &b) == MP_LT) { + p_max = 13; + } else { + err = MP_VAL; + goto LBL_B; + } + } + + /* we did bases 2 and 3 already, skip them */ + for (ix = 2; ix < p_max; ix++) { + mp_set(&b, s_mp_prime_tab[ix]); + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + } + } + /* + Do "t" M-R tests with random bases between 3 and "a". + See Fips 186.4 p. 126ff + */ + else if (t > 0) { + /* + * The mp_digit's have a defined bit-size but the size of the + * array a.dp is a simple 'int' and this library can not assume full + * compliance to the current C-standard (ISO/IEC 9899:2011) because + * it gets used for small embeded processors, too. Some of those MCUs + * have compilers that one cannot call standard compliant by any means. + * Hence the ugly type-fiddling in the following code. + */ + size_a = mp_count_bits(a); + mask = (1u << s_floor_ilog2(size_a)) - 1u; + /* + Assuming the General Rieman hypothesis (never thought to write that in a + comment) the upper bound can be lowered to 2*(log a)^2. + E. Bach, "Explicit bounds for primality testing and related problems," + Math. Comp. 55 (1990), 355-380. + + size_a = (size_a/10) * 7; + len = 2 * (size_a * size_a); + + E.g.: a number of size 2^2048 would be reduced to the upper limit + + floor(2048/10)*7 = 1428 + 2 * 1428^2 = 4078368 + + (would have been ~4030331.9962 with floats and natural log instead) + That number is smaller than 2^28, the default bit-size of mp_digit. + */ + + /* + How many tests, you might ask? Dana Jacobsen of Math::Prime::Util fame + does exactly 1. In words: one. Look at the end of _GMP_is_prime() in + Math-Prime-Util-GMP-0.50/primality.c if you do not believe it. + + The function mp_rand() goes to some length to use a cryptographically + good PRNG. That also means that the chance to always get the same base + in the loop is non-zero, although very low. + If the BPSW test and/or the addtional Frobenious test have been + performed instead of just the Miller-Rabin test with the bases 2 and 3, + a single extra test should suffice, so such a very unlikely event + will not do much harm. + + To preemptivly answer the dangling question: no, a witness does not + need to be prime. + */ + for (ix = 0; ix < t; ix++) { + /* mp_rand() guarantees the first digit to be non-zero */ + if ((err = mp_rand(&b, 1)) != MP_OKAY) { + goto LBL_B; + } + /* + * Reduce digit before casting because mp_digit might be bigger than + * an unsigned int and "mask" on the other side is most probably not. + */ + fips_rand = (unsigned int)(b.dp[0] & (mp_digit) mask); +#ifdef MP_8BIT + /* + * One 8-bit digit is too small, so concatenate two if the size of + * unsigned int allows for it. + */ + if ((MP_SIZEOF_BITS(unsigned int)/2) >= MP_SIZEOF_BITS(mp_digit)) { + if ((err = mp_rand(&b, 1)) != MP_OKAY) { + goto LBL_B; + } + fips_rand <<= MP_SIZEOF_BITS(mp_digit); + fips_rand |= (unsigned int) b.dp[0]; + fips_rand &= mask; + } +#endif + if (fips_rand > (unsigned int)(INT_MAX - MP_DIGIT_BIT)) { + len = INT_MAX / MP_DIGIT_BIT; + } else { + len = (((int)fips_rand + MP_DIGIT_BIT) / MP_DIGIT_BIT); + } + /* Unlikely. */ + if (len < 0) { + ix--; + continue; + } + /* + * As mentioned above, one 8-bit digit is too small and + * although it can only happen in the unlikely case that + * an "unsigned int" is smaller than 16 bit a simple test + * is cheap and the correction even cheaper. + */ +#ifdef MP_8BIT + /* All "a" < 2^8 have been caught before */ + if (len == 1) { + len++; + } +#endif + if ((err = mp_rand(&b, len)) != MP_OKAY) { + goto LBL_B; + } + /* + * That number might got too big and the witness has to be + * smaller than "a" + */ + len = mp_count_bits(&b); + if (len >= size_a) { + len = (len - size_a) + 1; + if ((err = mp_div_2d(&b, len, &b, NULL)) != MP_OKAY) { + goto LBL_B; + } + } + /* Although the chance for b <= 3 is miniscule, try again. */ + if (mp_cmp_d(&b, 3uL) != MP_GT) { + ix--; + continue; + } + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + if (res == MP_NO) { + goto LBL_B; + } + } + } + + /* passed the test */ + *result = MP_YES; +LBL_B: + mp_clear(&b); + return err; +} + +#endif + +/* End: bn_mp_prime_is_prime.c */ + +/* Start: bn_mp_prime_miller_rabin.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_MILLER_RABIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, mp_bool *result) +{ + mp_int n1, y, r; + mp_err err; + int s, j; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1uL) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy(&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) { + goto LBL_R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init(&y)) != MP_OKAY) { + goto LBL_R; + } + if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y != 1 and y != n1 do */ + if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) { + if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d(&y, 1uL) == MP_EQ) { + goto LBL_Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp(&y, &n1) != MP_EQ) { + goto LBL_Y; + } + } + + /* probably prime now */ + *result = MP_YES; +LBL_Y: + mp_clear(&y); +LBL_R: + mp_clear(&r); +LBL_N1: + mp_clear(&n1); + return err; +} +#endif + +/* End: bn_mp_prime_miller_rabin.c */ + +/* Start: bn_mp_prime_next_prime.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_NEXT_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +mp_err mp_prime_next_prime(mp_int *a, int t, int bbs_style) +{ + int x, y; + mp_ord cmp; + mp_err err; + mp_bool res = MP_NO; + mp_digit res_tab[PRIVATE_MP_PRIME_TAB_SIZE], step, kstep; + mp_int b; + + /* force positive */ + a->sign = MP_ZPOS; + + /* simple algo if a is less than the largest prime in the table */ + if (mp_cmp_d(a, s_mp_prime_tab[PRIVATE_MP_PRIME_TAB_SIZE-1]) == MP_LT) { + /* find which prime it is bigger than "a" */ + for (x = 0; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + cmp = mp_cmp_d(a, s_mp_prime_tab[x]); + if (cmp == MP_EQ) { + continue; + } + if (cmp != MP_GT) { + if ((bbs_style == 1) && ((s_mp_prime_tab[x] & 3u) != 3u)) { + /* try again until we get a prime congruent to 3 mod 4 */ + continue; + } else { + mp_set(a, s_mp_prime_tab[x]); + return MP_OKAY; + } + } + } + /* fall through to the sieve */ + } + + /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */ + if (bbs_style == 1) { + kstep = 4; + } else { + kstep = 2; + } + + /* at this point we will use a combination of a sieve and Miller-Rabin */ + + if (bbs_style == 1) { + /* if a mod 4 != 3 subtract the correct value to make it so */ + if ((a->dp[0] & 3u) != 3u) { + if ((err = mp_sub_d(a, (a->dp[0] & 3u) + 1u, a)) != MP_OKAY) { + return err; + } + } + } else { + if (MP_IS_EVEN(a)) { + /* force odd */ + if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) { + return err; + } + } + } + + /* generate the restable */ + for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + if ((err = mp_mod_d(a, s_mp_prime_tab[x], res_tab + x)) != MP_OKAY) { + return err; + } + } + + /* init temp used for Miller-Rabin Testing */ + if ((err = mp_init(&b)) != MP_OKAY) { + return err; + } + + for (;;) { + /* skip to the next non-trivially divisible candidate */ + step = 0; + do { + /* y == 1 if any residue was zero [e.g. cannot be prime] */ + y = 0; + + /* increase step to next candidate */ + step += kstep; + + /* compute the new residue without using division */ + for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) { + /* add the step to each residue */ + res_tab[x] += kstep; + + /* subtract the modulus [instead of using division] */ + if (res_tab[x] >= s_mp_prime_tab[x]) { + res_tab[x] -= s_mp_prime_tab[x]; + } + + /* set flag if zero */ + if (res_tab[x] == 0u) { + y = 1; + } + } + } while ((y == 1) && (step < (((mp_digit)1 << MP_DIGIT_BIT) - kstep))); + + /* add the step */ + if ((err = mp_add_d(a, step, a)) != MP_OKAY) { + goto LBL_ERR; + } + + /* if didn't pass sieve and step == MP_MAX then skip test */ + if ((y == 1) && (step >= (((mp_digit)1 << MP_DIGIT_BIT) - kstep))) { + continue; + } + + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto LBL_ERR; + } + if (res == MP_YES) { + break; + } + } + + err = MP_OKAY; +LBL_ERR: + mp_clear(&b); + return err; +} + +#endif + +/* End: bn_mp_prime_next_prime.c */ + +/* Start: bn_mp_prime_rabin_miller_trials.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +static const struct { + int k, t; +} sizes[] = { + { 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */ + { 81, 37 }, /* max. error = 2^(-96)*/ + { 96, 32 }, /* max. error = 2^(-96)*/ + { 128, 40 }, /* max. error = 2^(-112)*/ + { 160, 35 }, /* max. error = 2^(-112)*/ + { 256, 27 }, /* max. error = 2^(-128)*/ + { 384, 16 }, /* max. error = 2^(-128)*/ + { 512, 18 }, /* max. error = 2^(-160)*/ + { 768, 11 }, /* max. error = 2^(-160)*/ + { 896, 10 }, /* max. error = 2^(-160)*/ + { 1024, 12 }, /* max. error = 2^(-192)*/ + { 1536, 8 }, /* max. error = 2^(-192)*/ + { 2048, 6 }, /* max. error = 2^(-192)*/ + { 3072, 4 }, /* max. error = 2^(-192)*/ + { 4096, 5 }, /* max. error = 2^(-256)*/ + { 5120, 4 }, /* max. error = 2^(-256)*/ + { 6144, 4 }, /* max. error = 2^(-256)*/ + { 8192, 3 }, /* max. error = 2^(-256)*/ + { 9216, 3 }, /* max. error = 2^(-256)*/ + { 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */ +}; + +/* returns # of RM trials required for a given bit size */ +int mp_prime_rabin_miller_trials(int size) +{ + int x; + + for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) { + if (sizes[x].k == size) { + return sizes[x].t; + } else if (sizes[x].k > size) { + return (x == 0) ? sizes[0].t : sizes[x - 1].t; + } + } + return sizes[x-1].t; +} + + +#endif + +/* End: bn_mp_prime_rabin_miller_trials.c */ + +/* Start: bn_mp_prime_rand.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_RAND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * MP_PRIME_BBS - make prime congruent to 3 mod 4 + * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS) + * MP_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ + +/* This is possibly the mother of all prime generation functions, muahahahahaha! */ +mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int bsize, maskOR_msb_offset; + mp_bool res; + mp_err err; + + /* sanity check the input */ + if ((size <= 1) || (t <= 0)) { + return MP_VAL; + } + + /* MP_PRIME_SAFE implies MP_PRIME_BBS */ + if ((flags & MP_PRIME_SAFE) != 0) { + flags |= MP_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3) + ((size&7)?1:0); + + /* we need a buffer of bsize bytes */ + tmp = (unsigned char *) MP_MALLOC((size_t)bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = ((size&7) == 0) ? 0xFFu : (unsigned char)(0xFFu >> (8 - (size & 7))); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0; + if ((flags & MP_PRIME_2MSB_ON) != 0) { + maskOR_msb |= (unsigned char)(0x80 >> ((9 - size) & 7)); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 1u; + if ((flags & MP_PRIME_BBS) != 0) { + maskOR_lsb |= 3u; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= (unsigned char)(1 << ((size - 1) & 7)); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + /* TODO: casting only for now until all lengths have been changed to the type "size_t"*/ + if ((err = mp_from_ubin(a, tmp, (size_t)bsize)) != MP_OKAY) { + goto error; + } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto error; + } + if (res == MP_NO) { + continue; + } + + if ((flags & MP_PRIME_SAFE) != 0) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) { + goto error; + } + if ((err = mp_div_2(a, a)) != MP_OKAY) { + goto error; + } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + goto error; + } + } + } while (res == MP_NO); + + if ((flags & MP_PRIME_SAFE) != 0) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { + goto error; + } + if ((err = mp_add_d(a, 1uL, a)) != MP_OKAY) { + goto error; + } + } + + err = MP_OKAY; +error: + MP_FREE_BUFFER(tmp, (size_t)bsize); + return err; +} + +static int s_mp_rand_cb(unsigned char *dst, int len, void *dat) +{ + (void)dat; + if (len <= 0) { + return len; + } + if (s_mp_rand_source(dst, (size_t)len) != MP_OKAY) { + return 0; + } + return len; +} + +mp_err mp_prime_rand(mp_int *a, int t, int size, int flags) +{ + return s_mp_prime_random_ex(a, t, size, flags, s_mp_rand_cb, NULL); +} + +#endif + +/* End: bn_mp_prime_rand.c */ + +/* Start: bn_mp_prime_strong_lucas_selfridge.c */ +#include "tommath_private.h" +#ifdef BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* + * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details + */ +#ifndef LTM_USE_ONLY_MR + +/* + * 8-bit is just too small. You can try the Frobenius test + * but that frobenius test can fail, too, for the same reason. + */ +#ifndef MP_8BIT + +/* + * multiply bigint a with int d and put the result in c + * Like mp_mul_d() but with a signed long as the small input + */ +static mp_err s_mp_mul_si(const mp_int *a, int32_t d, mp_int *c) +{ + mp_int t; + mp_err err; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + /* + * mp_digit might be smaller than a long, which excludes + * the use of mp_mul_d() here. + */ + mp_set_i32(&t, d); + err = mp_mul(a, &t, c); + mp_clear(&t); + return err; +} +/* + Strong Lucas-Selfridge test. + returns MP_YES if it is a strong L-S prime, MP_NO if it is composite + + Code ported from Thomas Ray Nicely's implementation of the BPSW test + at http://www.trnicely.net/misc/bpsw.html + + Freeware copyright (C) 2016 Thomas R. Nicely . + Released into the public domain by the author, who disclaims any legal + liability arising from its use + + The multi-line comments are made by Thomas R. Nicely and are copied verbatim. + Additional comments marked "CZ" (without the quotes) are by the code-portist. + + (If that name sounds familiar, he is the guy who found the fdiv bug in the + Pentium (P5x, I think) Intel processor) +*/ +mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, mp_bool *result) +{ + /* CZ TODO: choose better variable names! */ + mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz; + /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */ + int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits; + mp_err err; + mp_bool oddness; + + *result = MP_NO; + /* + Find the first element D in the sequence {5, -7, 9, -11, 13, ...} + such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory + indicates that, if N is not a perfect square, D will "nearly + always" be "small." Just in case, an overflow trap for D is + included. + */ + + if ((err = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz, + NULL)) != MP_OKAY) { + return err; + } + + D = 5; + sign = 1; + + for (;;) { + Ds = sign * D; + sign = -sign; + mp_set_u32(&Dz, (uint32_t)D); + if ((err = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) goto LBL_LS_ERR; + + /* if 1 < GCD < N then N is composite with factor "D", and + Jacobi(D,N) is technically undefined (but often returned + as zero). */ + if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) { + goto LBL_LS_ERR; + } + if (Ds < 0) { + Dz.sign = MP_NEG; + } + if ((err = mp_kronecker(&Dz, a, &J)) != MP_OKAY) goto LBL_LS_ERR; + + if (J == -1) { + break; + } + D += 2; + + if (D > (INT_MAX - 2)) { + err = MP_VAL; + goto LBL_LS_ERR; + } + } + + + + P = 1; /* Selfridge's choice */ + Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */ + + /* NOTE: The conditions (a) N does not divide Q, and + (b) D is square-free or not a perfect square, are included by + some authors; e.g., "Prime numbers and computer methods for + factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston), + p. 130. For this particular application of Lucas sequences, + these conditions were found to be immaterial. */ + + /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the + odd positive integer d and positive integer s for which + N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test). + The strong Lucas-Selfridge test then returns N as a strong + Lucas probable prime (slprp) if any of the following + conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0, + V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0 + (all equalities mod N). Thus d is the highest index of U that + must be computed (since V_2m is independent of U), compared + to U_{N+1} for the standard Lucas-Selfridge test; and no + index of V beyond (N+1)/2 is required, just as in the + standard Lucas-Selfridge test. However, the quantity Q^d must + be computed for use (if necessary) in the latter stages of + the test. The result is that the strong Lucas-Selfridge test + has a running time only slightly greater (order of 10 %) than + that of the standard Lucas-Selfridge test, while producing + only (roughly) 30 % as many pseudoprimes (and every strong + Lucas pseudoprime is also a standard Lucas pseudoprime). Thus + the evidence indicates that the strong Lucas-Selfridge test is + more effective than the standard Lucas-Selfridge test, and a + Baillie-PSW test based on the strong Lucas-Selfridge test + should be more reliable. */ + + if ((err = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) goto LBL_LS_ERR; + s = mp_cnt_lsb(&Np1); + + /* CZ + * This should round towards zero because + * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp() + * and mp_div_2d() is equivalent. Additionally: + * dividing an even number by two does not produce + * any leftovers. + */ + if ((err = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) goto LBL_LS_ERR; + /* We must now compute U_d and V_d. Since d is odd, the accumulated + values U and V are initialized to U_1 and V_1 (if the target + index were even, U and V would be initialized instead to U_0=0 + and V_0=2). The values of U_2m and V_2m are also initialized to + U_1 and V_1; the FOR loop calculates in succession U_2 and V_2, + U_4 and V_4, U_8 and V_8, etc. If the corresponding bits + (1, 2, 3, ...) of t are on (the zero bit having been accounted + for in the initialization of U and V), these values are then + combined with the previous totals for U and V, using the + composition formulas for addition of indices. */ + + mp_set(&Uz, 1uL); /* U=U_1 */ + mp_set(&Vz, (mp_digit)P); /* V=V_1 */ + mp_set(&U2mz, 1uL); /* U_1 */ + mp_set(&V2mz, (mp_digit)P); /* V_1 */ + + mp_set_i32(&Qmz, Q); + if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR; + /* Initializes calculation of Q^d */ + mp_set_i32(&Qkdz, Q); + + Nbits = mp_count_bits(&Dz); + + for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */ + /* Formulas for doubling of indices (carried out mod N). Note that + * the indices denoted as "2m" are actually powers of 2, specifically + * 2^(ul-1) beginning each loop and 2^ul ending each loop. + * + * U_2m = U_m*V_m + * V_2m = V_m*V_m - 2*Q^m + */ + + if ((err = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) goto LBL_LS_ERR; + + /* Must calculate powers of Q for use in V_2m, also for Q^d later */ + if ((err = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) goto LBL_LS_ERR; + + /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */ + if ((err = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR; + + if (s_mp_get_bit(&Dz, (unsigned int)u) == MP_YES) { + /* Formulas for addition of indices (carried out mod N); + * + * U_(m+n) = (U_m*V_n + U_n*V_m)/2 + * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2 + * + * Be careful with division by 2 (mod N)! + */ + if ((err = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = s_mp_mul_si(&T4z, Ds, &T4z)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ODD(&Uz)) { + if ((err = mp_add(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + } + /* CZ + * This should round towards negative infinity because + * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp(). + * But mp_div_2() does not do so, it is truncating instead. + */ + oddness = MP_IS_ODD(&Uz) ? MP_YES : MP_NO; + if ((err = mp_div_2(&Uz, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if ((Uz.sign == MP_NEG) && (oddness != MP_NO)) { + if ((err = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + } + if ((err = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ODD(&Vz)) { + if ((err = mp_add(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + } + oddness = MP_IS_ODD(&Vz) ? MP_YES : MP_NO; + if ((err = mp_div_2(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((Vz.sign == MP_NEG) && (oddness != MP_NO)) { + if ((err = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + } + if ((err = mp_mod(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + + /* Calculating Q^d for later use */ + if ((err = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + } + } + + /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a + strong Lucas pseudoprime. */ + if (MP_IS_ZERO(&Uz) || MP_IS_ZERO(&Vz)) { + *result = MP_YES; + goto LBL_LS_ERR; + } + + /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed., + 1995/6) omits the condition V0 on p.142, but includes it on + p. 130. The condition is NECESSARY; otherwise the test will + return false negatives---e.g., the primes 29 and 2000029 will be + returned as composite. */ + + /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d} + by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of + these are congruent to 0 mod N, then N is a prime or a strong + Lucas pseudoprime. */ + + /* Initialize 2*Q^(d*2^r) for V_2m */ + if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR; + + for (r = 1; r < s; r++) { + if ((err = mp_sqr(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR; + if (MP_IS_ZERO(&Vz)) { + *result = MP_YES; + goto LBL_LS_ERR; + } + /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */ + if (r < (s - 1)) { + if ((err = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR; + if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR; + } + } +LBL_LS_ERR: + mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL); + return err; +} +#endif +#endif +#endif + +/* End: bn_mp_prime_strong_lucas_selfridge.c */ + +/* Start: bn_mp_radix_size.c */ +#include "tommath_private.h" +#ifdef BN_MP_RADIX_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* returns size of ASCII representation */ +mp_err mp_radix_size(const mp_int *a, int radix, int *size) +{ + mp_err err; + int digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* make sure the radix is in range */ + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + if (MP_IS_ZERO(a)) { + *size = 2; + return MP_OKAY; + } + + /* special case for binary */ + if (radix == 2) { + *size = (mp_count_bits(a) + ((a->sign == MP_NEG) ? 1 : 0) + 1); + return MP_OKAY; + } + + /* digs is the digit count */ + digs = 0; + + /* if it's negative add one for the sign */ + if (a->sign == MP_NEG) { + ++digs; + } + + /* init a copy of the input */ + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + /* force temp to positive */ + t.sign = MP_ZPOS; + + /* fetch out all of the digits */ + while (!MP_IS_ZERO(&t)) { + if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { + goto LBL_ERR; + } + ++digs; + } + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + err = MP_OKAY; + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif + +/* End: bn_mp_radix_size.c */ + +/* Start: bn_mp_radix_smap.c */ +#include "tommath_private.h" +#ifdef BN_MP_RADIX_SMAP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* chars used in radix conversions */ +const char *const mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; +const uint8_t mp_s_rmap_reverse[] = { + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* ()*+,-./ */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */ + 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 89:;<=>? */ + 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* @ABCDEFG */ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* HIJKLMNO */ + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* PQRSTUVW */ + 0x21, 0x22, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, /* XYZ[\]^_ */ + 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, /* `abcdefg */ + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, /* hijklmno */ + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, /* pqrstuvw */ + 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, /* xyz{|}~. */ +}; +const size_t mp_s_rmap_reverse_sz = sizeof(mp_s_rmap_reverse); +#endif + +/* End: bn_mp_radix_smap.c */ + +/* Start: bn_mp_rand.c */ +#include "tommath_private.h" +#ifdef BN_MP_RAND_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform; + +void mp_rand_source(mp_err(*source)(void *out, size_t size)) +{ + s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source; +} + +mp_err mp_rand(mp_int *a, int digits) +{ + int i; + mp_err err; + + mp_zero(a); + + if (digits <= 0) { + return MP_OKAY; + } + + if ((err = mp_grow(a, digits)) != MP_OKAY) { + return err; + } + + if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) { + return err; + } + + /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */ + while ((a->dp[digits - 1] & MP_MASK) == 0u) { + if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) { + return err; + } + } + + a->used = digits; + for (i = 0; i < digits; ++i) { + a->dp[i] &= MP_MASK; + } + + return MP_OKAY; +} +#endif + +/* End: bn_mp_rand.c */ + +/* Start: bn_mp_read_radix.c */ +#include "tommath_private.h" +#ifdef BN_MP_READ_RADIX_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#define MP_TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (((c) + 'A') - 'a') : (c)) + +/* read a string [ASCII] in a given radix */ +mp_err mp_read_radix(mp_int *a, const char *str, int radix) +{ + mp_err err; + int y; + mp_sign neg; + unsigned pos; + char ch; + + /* zero the digit bignum */ + mp_zero(a); + + /* make sure the radix is ok */ + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + /* set the integer to the default of zero */ + mp_zero(a); + + /* process each digit of the string */ + while (*str != '\0') { + /* if the radix <= 36 the conversion is case insensitive + * this allows numbers like 1AB and 1ab to represent the same value + * [e.g. in hex] + */ + ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str; + pos = (unsigned)(ch - '('); + if (mp_s_rmap_reverse_sz < pos) { + break; + } + y = (int)mp_s_rmap_reverse[pos]; + + /* if the char was found in the map + * and is less than the given radix add it + * to the number, otherwise exit the loop. + */ + if ((y == 0xff) || (y >= radix)) { + break; + } + if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) { + return err; + } + ++str; + } + + /* if an illegal character was found, fail. */ + if (!((*str == '\0') || (*str == '\r') || (*str == '\n'))) { + mp_zero(a); + return MP_VAL; + } + + /* set the sign only if a != 0 */ + if (!MP_IS_ZERO(a)) { + a->sign = neg; + } + return MP_OKAY; +} +#endif + +/* End: bn_mp_read_radix.c */ + +/* Start: bn_mp_reduce.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) +{ + mp_int q; + mp_err err; + int um = m->used; + + /* q = x */ + if ((err = mp_init_copy(&q, x)) != MP_OKAY) { + return err; + } + + /* q1 = x / b**(k-1) */ + mp_rshd(&q, um - 1); + + /* according to HAC this optimization is ok */ + if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) { + if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else if (MP_HAS(S_MP_MUL_HIGH_DIGS)) { + if ((err = s_mp_mul_high_digs(&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } + } else if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)) { + if ((err = s_mp_mul_high_digs_fast(&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } + } else { + err = MP_VAL; + goto CLEANUP; + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd(&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((err = s_mp_mul_digs(&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((err = mp_sub(x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d(x, 0uL) == MP_LT) { + mp_set(&q, 1uL); + if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((err = mp_add(x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp(x, m) != MP_LT) { + if ((err = s_mp_sub(x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear(&q); + + return err; +} +#endif + +/* End: bn_mp_reduce.c */ + +/* Start: bn_mp_reduce_2k.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces a modulo n where n is of the form 2**p - d */ +mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) +{ + mp_int q; + mp_err err; + int p; + + if ((err = mp_init(&q)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (d != 1u) { + /* q = q * d */ + if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* a = a + q */ + if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { + goto LBL_ERR; + } + goto top; + } + +LBL_ERR: + mp_clear(&q); + return err; +} + +#endif + +/* End: bn_mp_reduce_2k.c */ + +/* Start: bn_mp_reduce_2k_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) +{ + mp_int q; + mp_err err; + int p; + + if ((err = mp_init(&q)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + /* q = q * d */ + if ((err = mp_mul(&q, d, &q)) != MP_OKAY) { + goto LBL_ERR; + } + + /* a = a + q */ + if ((err = s_mp_add(a, &q, a)) != MP_OKAY) { + goto LBL_ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + if ((err = s_mp_sub(a, n, a)) != MP_OKAY) { + goto LBL_ERR; + } + goto top; + } + +LBL_ERR: + mp_clear(&q); + return err; +} + +#endif + +/* End: bn_mp_reduce_2k_l.c */ + +/* Start: bn_mp_reduce_2k_setup.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) +{ + mp_err err; + mp_int tmp; + int p; + + if ((err = mp_init(&tmp)) != MP_OKAY) { + return err; + } + + p = mp_count_bits(a); + if ((err = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return err; + } + + if ((err = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return err; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} +#endif + +/* End: bn_mp_reduce_2k_setup.c */ + +/* Start: bn_mp_reduce_2k_setup_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_2K_SETUP_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines the setup value */ +mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) +{ + mp_err err; + mp_int tmp; + + if ((err = mp_init(&tmp)) != MP_OKAY) { + return err; + } + + if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto LBL_ERR; + } + + if ((err = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto LBL_ERR; + } + +LBL_ERR: + mp_clear(&tmp); + return err; +} +#endif + +/* End: bn_mp_reduce_2k_setup_l.c */ + +/* Start: bn_mp_reduce_is_2k.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_IS_2K_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if mp_reduce_2k can be used */ +mp_bool mp_reduce_is_2k(const mp_int *a) +{ + int ix, iy, iw; + mp_digit iz; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + iy = mp_count_bits(a); + iz = 1; + iw = 1; + + /* Test every bit from the second digit up, must be 1 */ + for (ix = MP_DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0u) { + return MP_NO; + } + iz <<= 1; + if (iz > MP_DIGIT_MAX) { + ++iw; + iz = 1; + } + } + return MP_YES; + } else { + return MP_YES; + } +} + +#endif + +/* End: bn_mp_reduce_is_2k.c */ + +/* Start: bn_mp_reduce_is_2k_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_IS_2K_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if reduce_2k_l can be used */ +mp_bool mp_reduce_is_2k_l(const mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + /* if more than half of the digits are -1 we're sold */ + for (iy = ix = 0; ix < a->used; ix++) { + if (a->dp[ix] == MP_DIGIT_MAX) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + } else { + return MP_NO; + } +} + +#endif + +/* End: bn_mp_reduce_is_2k_l.c */ + +/* Start: bn_mp_reduce_setup.c */ +#include "tommath_private.h" +#ifdef BN_MP_REDUCE_SETUP_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +mp_err mp_reduce_setup(mp_int *a, const mp_int *b) +{ + mp_err err; + if ((err = mp_2expt(a, b->used * 2 * MP_DIGIT_BIT)) != MP_OKAY) { + return err; + } + return mp_div(a, b, a, NULL); +} +#endif + +/* End: bn_mp_reduce_setup.c */ + +/* Start: bn_mp_root_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_ROOT_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* find the n'th root of an integer + * + * Result found such that (c)**b <= a and (c+1)**b > a + * + * This algorithm uses Newton's approximation + * x[i+1] = x[i] - f(x[i])/f'(x[i]) + * which will find the root in log(N) time where + * each step involves a fair bit. + */ +mp_err mp_root_u32(const mp_int *a, uint32_t b, mp_int *c) +{ + mp_int t1, t2, t3, a_; + mp_ord cmp; + int ilog2; + mp_err err; + + /* input must be positive if b is even */ + if (((b & 1u) == 0u) && (a->sign == MP_NEG)) { + return MP_VAL; + } + + if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) { + return err; + } + + /* if a is negative fudge the sign but keep track */ + a_ = *a; + a_.sign = MP_ZPOS; + + /* Compute seed: 2^(log_2(n)/b + 2)*/ + ilog2 = mp_count_bits(a); + + /* + If "b" is larger than INT_MAX it is also larger than + log_2(n) because the bit-length of the "n" is measured + with an int and hence the root is always < 2 (two). + */ + if (b > (uint32_t)(INT_MAX/2)) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + + /* "b" is smaller than INT_MAX, we can cast safely */ + if (ilog2 < (int)b) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + ilog2 = ilog2 / ((int)b); + if (ilog2 == 0) { + mp_set(c, 1uL); + c->sign = a->sign; + err = MP_OKAY; + goto LBL_ERR; + } + /* Start value must be larger than root */ + ilog2 += 2; + if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) goto LBL_ERR; + do { + /* t1 = t2 */ + if ((err = mp_copy(&t2, &t1)) != MP_OKAY) goto LBL_ERR; + + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((err = mp_expt_u32(&t1, b - 1u, &t3)) != MP_OKAY) goto LBL_ERR; + + /* numerator */ + /* t2 = t1**b */ + if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) goto LBL_ERR; + + /* t2 = t1**b - a */ + if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) goto LBL_ERR; + + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((err = mp_mul_d(&t3, b, &t3)) != MP_OKAY) goto LBL_ERR; + + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) goto LBL_ERR; + + /* + Number of rounds is at most log_2(root). If it is more it + got stuck, so break out of the loop and do the rest manually. + */ + if (ilog2-- == 0) { + break; + } + } while (mp_cmp(&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + /* Loop beneath can overshoot by one if found root is smaller than actual root */ + for (;;) { + if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; + cmp = mp_cmp(&t2, &a_); + if (cmp == MP_EQ) { + err = MP_OKAY; + goto LBL_ERR; + } + if (cmp == MP_LT) { + if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; + } else { + break; + } + } + /* correct overshoot from above or from recurrence */ + for (;;) { + if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; + if (mp_cmp(&t2, &a_) == MP_GT) { + if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; + } else { + break; + } + } + + /* set the result */ + mp_exch(&t1, c); + + /* set the sign of the result */ + c->sign = a->sign; + + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&t1, &t2, &t3, NULL); + return err; +} + +#endif + +/* End: bn_mp_root_u32.c */ + +/* Start: bn_mp_rshd.c */ +#include "tommath_private.h" +#ifdef BN_MP_RSHD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right a certain amount of digits */ +void mp_rshd(mp_int *a, int b) +{ + int x; + mp_digit *bottom, *top; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero(a); + return; + } + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + MP_ZERO_DIGITS(bottom, a->used - x); + + /* remove excess digits */ + a->used -= b; +} +#endif + +/* End: bn_mp_rshd.c */ + +/* Start: bn_mp_sbin_size.c */ +#include "tommath_private.h" +#ifdef BN_MP_SBIN_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* get the size for an signed equivalent */ +size_t mp_sbin_size(const mp_int *a) +{ + return 1u + mp_ubin_size(a); +} +#endif + +/* End: bn_mp_sbin_size.c */ + +/* Start: bn_mp_set.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b) +{ + a->dp[0] = b & MP_MASK; + a->sign = MP_ZPOS; + a->used = (a->dp[0] != 0u) ? 1 : 0; + MP_ZERO_DIGITS(a->dp + a->used, a->alloc - a->used); +} +#endif + +/* End: bn_mp_set.c */ + +/* Start: bn_mp_set_double.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_DOUBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) +mp_err mp_set_double(mp_int *a, double b) +{ + uint64_t frac; + int exp; + mp_err err; + union { + double dbl; + uint64_t bits; + } cast; + cast.dbl = b; + + exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFu); + frac = (cast.bits & ((1uLL << 52) - 1uLL)) | (1uLL << 52); + + if (exp == 0x7FF) { /* +-inf, NaN */ + return MP_VAL; + } + exp -= 1023 + 52; + + mp_set_u64(a, frac); + + err = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); + if (err != MP_OKAY) { + return err; + } + + if (((cast.bits >> 63) != 0uLL) && !MP_IS_ZERO(a)) { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format") +# else +# warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" +# endif +#endif +#endif + +/* End: bn_mp_set_double.c */ + +/* Start: bn_mp_set_i32.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_I32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_i32, mp_set_u32, int32_t, uint32_t) +#endif + +/* End: bn_mp_set_i32.c */ + +/* Start: bn_mp_set_i64.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_I64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_i64, mp_set_u64, int64_t, uint64_t) +#endif + +/* End: bn_mp_set_i64.c */ + +/* Start: bn_mp_set_l.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_L_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_l, mp_set_ul, long, unsigned long) +#endif + +/* End: bn_mp_set_l.c */ + +/* Start: bn_mp_set_ll.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_LL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_SIGNED(mp_set_ll, mp_set_ull, long long, unsigned long long) +#endif + +/* End: bn_mp_set_ll.c */ + +/* Start: bn_mp_set_u32.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_U32_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_u32, uint32_t) +#endif + +/* End: bn_mp_set_u32.c */ + +/* Start: bn_mp_set_u64.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_U64_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_u64, uint64_t) +#endif + +/* End: bn_mp_set_u64.c */ + +/* Start: bn_mp_set_ul.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_UL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_ul, unsigned long) +#endif + +/* End: bn_mp_set_ul.c */ + +/* Start: bn_mp_set_ull.c */ +#include "tommath_private.h" +#ifdef BN_MP_SET_ULL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +MP_SET_UNSIGNED(mp_set_ull, unsigned long long) +#endif + +/* End: bn_mp_set_ull.c */ + +/* Start: bn_mp_shrink.c */ +#include "tommath_private.h" +#ifdef BN_MP_SHRINK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shrink a bignum */ +mp_err mp_shrink(mp_int *a) +{ + mp_digit *tmp; + int alloc = MP_MAX(MP_MIN_PREC, a->used); + if (a->alloc != alloc) { + if ((tmp = (mp_digit *) MP_REALLOC(a->dp, + (size_t)a->alloc * sizeof(mp_digit), + (size_t)alloc * sizeof(mp_digit))) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = alloc; + } + return MP_OKAY; +} +#endif + +/* End: bn_mp_shrink.c */ + +/* Start: bn_mp_signed_rsh.c */ +#include "tommath_private.h" +#ifdef BN_MP_SIGNED_RSH_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* shift right by a certain bit count with sign extension */ +mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) +{ + mp_err res; + if (a->sign == MP_ZPOS) { + return mp_div_2d(a, b, c, NULL); + } + + res = mp_add_d(a, 1uL, c); + if (res != MP_OKAY) { + return res; + } + + res = mp_div_2d(c, b, c, NULL); + return (res == MP_OKAY) ? mp_sub_d(c, 1uL, c) : res; +} +#endif + +/* End: bn_mp_signed_rsh.c */ + +/* Start: bn_mp_sqr.c */ +#include "tommath_private.h" +#ifdef BN_MP_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes b = a*a */ +mp_err mp_sqr(const mp_int *a, mp_int *b) +{ + mp_err err; + if (MP_HAS(S_MP_TOOM_SQR) && /* use Toom-Cook? */ + (a->used >= MP_TOOM_SQR_CUTOFF)) { + err = s_mp_toom_sqr(a, b); + } else if (MP_HAS(S_MP_KARATSUBA_SQR) && /* Karatsuba? */ + (a->used >= MP_KARATSUBA_SQR_CUTOFF)) { + err = s_mp_karatsuba_sqr(a, b); + } else if (MP_HAS(S_MP_SQR_FAST) && /* can we use the fast comba multiplier? */ + (((a->used * 2) + 1) < MP_WARRAY) && + (a->used < (MP_MAXFAST / 2))) { + err = s_mp_sqr_fast(a, b); + } else if (MP_HAS(S_MP_SQR)) { + err = s_mp_sqr(a, b); + } else { + err = MP_VAL; + } + b->sign = MP_ZPOS; + return err; +} +#endif + +/* End: bn_mp_sqr.c */ + +/* Start: bn_mp_sqrmod.c */ +#include "tommath_private.h" +#ifdef BN_MP_SQRMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = a * a (mod b) */ +mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_sqr(a, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, b, c); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_sqrmod.c */ + +/* Start: bn_mp_sqrt.c */ +#include "tommath_private.h" +#ifdef BN_MP_SQRT_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this function is less generic than mp_n_root, simpler and faster */ +mp_err mp_sqrt(const mp_int *arg, mp_int *ret) +{ + mp_err err; + mp_int t1, t2; + + /* must be positive */ + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* easy out */ + if (MP_IS_ZERO(arg)) { + mp_zero(ret); + return MP_OKAY; + } + + if ((err = mp_init_copy(&t1, arg)) != MP_OKAY) { + return err; + } + + if ((err = mp_init(&t2)) != MP_OKAY) { + goto E2; + } + + /* First approx. (not very bad for large arg) */ + mp_rshd(&t1, t1.used/2); + + /* t1 > 0 */ + if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { + goto E1; + } + if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { + goto E1; + } + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { + goto E1; + } + /* And now t1 > sqrt(arg) */ + do { + if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) { + goto E1; + } + if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) { + goto E1; + } + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) { + goto E1; + } + /* t1 >= sqrt(arg) >= t2 at this point */ + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + mp_exch(&t1, ret); + +E1: + mp_clear(&t2); +E2: + mp_clear(&t1); + return err; +} + +#endif + +/* End: bn_mp_sqrt.c */ + +/* Start: bn_mp_sqrtmod_prime.c */ +#include "tommath_private.h" +#ifdef BN_MP_SQRTMOD_PRIME_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Tonelli-Shanks algorithm + * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm + * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html + * + */ + +mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret) +{ + mp_err err; + int legendre; + mp_int t1, C, Q, S, Z, M, T, R, two; + mp_digit i; + + /* first handle the simple cases */ + if (mp_cmp_d(n, 0uL) == MP_EQ) { + mp_zero(ret); + return MP_OKAY; + } + if (mp_cmp_d(prime, 2uL) == MP_EQ) return MP_VAL; /* prime must be odd */ + if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err; + if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */ + + if ((err = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) { + return err; + } + + /* SPECIAL CASE: if prime mod 4 == 3 + * compute directly: err = n^(prime+1)/4 mod prime + * Handbook of Applied Cryptography algorithm 3.36 + */ + if ((err = mp_mod_d(prime, 4uL, &i)) != MP_OKAY) goto cleanup; + if (i == 3u) { + if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup; + err = MP_OKAY; + goto cleanup; + } + + /* NOW: Tonelli-Shanks algorithm */ + + /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */ + if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup; + if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto cleanup; + /* Q = prime - 1 */ + mp_zero(&S); + /* S = 0 */ + while (MP_IS_EVEN(&Q)) { + if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup; + /* Q = Q / 2 */ + if ((err = mp_add_d(&S, 1uL, &S)) != MP_OKAY) goto cleanup; + /* S = S + 1 */ + } + + /* find a Z such that the Legendre symbol (Z|prime) == -1 */ + mp_set_u32(&Z, 2u); + /* Z = 2 */ + for (;;) { + if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto cleanup; + if (legendre == -1) break; + if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto cleanup; + /* Z = Z + 1 */ + } + + if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup; + /* C = Z ^ Q mod prime */ + if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup; + /* t1 = (Q + 1) / 2 */ + if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup; + /* R = n ^ ((Q + 1) / 2) mod prime */ + if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup; + /* T = n ^ Q mod prime */ + if ((err = mp_copy(&S, &M)) != MP_OKAY) goto cleanup; + /* M = S */ + mp_set_u32(&two, 2u); + + for (;;) { + if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup; + i = 0; + for (;;) { + if (mp_cmp_d(&t1, 1uL) == MP_EQ) break; + if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup; + i++; + } + if (i == 0u) { + if ((err = mp_copy(&R, ret)) != MP_OKAY) goto cleanup; + err = MP_OKAY; + goto cleanup; + } + if ((err = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto cleanup; + if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup; + /* t1 = 2 ^ (M - i - 1) */ + if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup; + /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ + if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup; + /* C = (t1 * t1) mod prime */ + if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup; + /* R = (R * t1) mod prime */ + if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup; + /* T = (T * C) mod prime */ + mp_set(&M, i); + /* M = i */ + } + +cleanup: + mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL); + return err; +} + +#endif + +/* End: bn_mp_sqrtmod_prime.c */ + +/* Start: bn_mp_sub.c */ +#include "tommath_private.h" +#ifdef BN_MP_SUB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* high level subtraction (handles signs) */ +mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_sign sa = a->sign, sb = b->sign; + mp_err err; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + err = s_mp_add(a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag(a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + err = s_mp_sub(a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + err = s_mp_sub(b, a, c); + } + } + return err; +} + +#endif + +/* End: bn_mp_sub.c */ + +/* Start: bn_mp_sub_d.c */ +#include "tommath_private.h" +#ifdef BN_MP_SUB_D_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single digit subtraction */ +mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) +{ + mp_digit *tmpa, *tmpc; + mp_err err; + int ix, oldused; + + /* grow c as required */ + if (c->alloc < (a->used + 1)) { + if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) { + return err; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + mp_int a_ = *a; + a_.sign = MP_ZPOS; + err = mp_add_d(&a_, b, c); + c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return err; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if (((a->used == 1) && (a->dp[0] <= b)) || (a->used == 0)) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + mp_digit mu = b; + + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract digits, mu is carry */ + for (ix = 0; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + MP_ZERO_DIGITS(tmpc, oldused - ix); + + mp_clamp(c); + return MP_OKAY; +} + +#endif + +/* End: bn_mp_sub_d.c */ + +/* Start: bn_mp_submod.c */ +#include "tommath_private.h" +#ifdef BN_MP_SUBMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* d = a - b (mod c) */ +mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) +{ + mp_err err; + mp_int t; + + if ((err = mp_init(&t)) != MP_OKAY) { + return err; + } + + if ((err = mp_sub(a, b, &t)) != MP_OKAY) { + goto LBL_ERR; + } + err = mp_mod(&t, c, d); + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_submod.c */ + +/* Start: bn_mp_to_radix.c */ +#include "tommath_private.h" +#ifdef BN_MP_TO_RADIX_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto "size - 1" chars and always a NULL byte, puts the number of characters + * written, including the '\0', in "written". + */ +mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) +{ + size_t digs; + mp_err err; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of radix and size*/ + if (maxlen < 2u) { + return MP_BUF; + } + if ((radix < 2) || (radix > 64)) { + return MP_VAL; + } + + /* quick out if its zero */ + if (MP_IS_ZERO(a)) { + *str++ = '0'; + *str = '\0'; + if (written != NULL) { + *written = 2u; + } + return MP_OKAY; + } + + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + /* we have to reverse our digits later... but not the - sign!! */ + ++_s; + + /* store the flag and mark the number as positive */ + *str++ = '-'; + t.sign = MP_ZPOS; + + /* subtract a char */ + --maxlen; + } + digs = 0u; + while (!MP_IS_ZERO(&t)) { + if (--maxlen < 1u) { + /* no more room */ + err = MP_BUF; + goto LBL_ERR; + } + if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) { + goto LBL_ERR; + } + *str++ = mp_s_rmap[d]; + ++digs; + } + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number + */ + s_mp_reverse((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + digs++; + + if (written != NULL) { + *written = (a->sign == MP_NEG) ? (digs + 1u): digs; + } + +LBL_ERR: + mp_clear(&t); + return err; +} + +#endif + +/* End: bn_mp_to_radix.c */ + +/* Start: bn_mp_to_sbin.c */ +#include "tommath_private.h" +#ifdef BN_MP_TO_SBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* store in signed [big endian] format */ +mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) +{ + mp_err err; + if (maxlen == 0u) { + return MP_BUF; + } + if ((err = mp_to_ubin(a, buf + 1, maxlen - 1u, written)) != MP_OKAY) { + return err; + } + if (written != NULL) { + (*written)++; + } + buf[0] = (a->sign == MP_ZPOS) ? (unsigned char)0 : (unsigned char)1; + return MP_OKAY; +} +#endif + +/* End: bn_mp_to_sbin.c */ + +/* Start: bn_mp_to_ubin.c */ +#include "tommath_private.h" +#ifdef BN_MP_TO_UBIN_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* store in unsigned [big endian] format */ +mp_err mp_to_ubin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) +{ + size_t x, count; + mp_err err; + mp_int t; + + count = mp_ubin_size(a); + if (count > maxlen) { + return MP_BUF; + } + + if ((err = mp_init_copy(&t, a)) != MP_OKAY) { + return err; + } + + for (x = count; x --> 0u;) { +#ifndef MP_8BIT + buf[x] = (unsigned char)(t.dp[0] & 255u); +#else + buf[x] = (unsigned char)(t.dp[0] | ((t.dp[1] & 1u) << 7)); +#endif + if ((err = mp_div_2d(&t, 8, &t, NULL)) != MP_OKAY) { + goto LBL_ERR; + } + } + + if (written != NULL) { + *written = count; + } + +LBL_ERR: + mp_clear(&t); + return err; +} +#endif + +/* End: bn_mp_to_ubin.c */ + +/* Start: bn_mp_ubin_size.c */ +#include "tommath_private.h" +#ifdef BN_MP_UBIN_SIZE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* get the size for an unsigned equivalent */ +size_t mp_ubin_size(const mp_int *a) +{ + size_t size = (size_t)mp_count_bits(a); + return (size / 8u) + (((size & 7u) != 0u) ? 1u : 0u); +} +#endif + +/* End: bn_mp_ubin_size.c */ + +/* Start: bn_mp_unpack.c */ +#include "tommath_private.h" +#ifdef BN_MP_UNPACK_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* based on gmp's mpz_import. + * see http://gmplib.org/manual/Integer-Import-and-Export.html + */ +mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, + mp_endian endian, size_t nails, const void *op) +{ + mp_err err; + size_t odd_nails, nail_bytes, i, j; + unsigned char odd_nail_mask; + + mp_zero(rop); + + if (endian == MP_NATIVE_ENDIAN) { + MP_GET_ENDIANNESS(endian); + } + + odd_nails = (nails % 8u); + odd_nail_mask = 0xff; + for (i = 0; i < odd_nails; ++i) { + odd_nail_mask ^= (unsigned char)(1u << (7u - i)); + } + nail_bytes = nails / 8u; + + for (i = 0; i < count; ++i) { + for (j = 0; j < (size - nail_bytes); ++j) { + unsigned char byte = *((const unsigned char *)op + + (((order == MP_MSB_FIRST) ? i : ((count - 1u) - i)) * size) + + ((endian == MP_BIG_ENDIAN) ? (j + nail_bytes) : (((size - 1u) - j) - nail_bytes))); + + if ((err = mp_mul_2d(rop, (j == 0u) ? (int)(8u - odd_nails) : 8, rop)) != MP_OKAY) { + return err; + } + + rop->dp[0] |= (j == 0u) ? (mp_digit)(byte & odd_nail_mask) : (mp_digit)byte; + rop->used += 1; + } + } + + mp_clamp(rop); + + return MP_OKAY; +} + +#endif + +/* End: bn_mp_unpack.c */ + +/* Start: bn_mp_xor.c */ +#include "tommath_private.h" +#ifdef BN_MP_XOR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* two complement xor */ +mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) +{ + int used = MP_MAX(a->used, b->used) + 1, i; + mp_err err; + mp_digit ac = 1, bc = 1, cc = 1; + mp_sign csign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS; + + if (c->alloc < used) { + if ((err = mp_grow(c, used)) != MP_OKAY) { + return err; + } + } + + for (i = 0; i < used; i++) { + mp_digit x, y; + + /* convert to two complement if negative */ + if (a->sign == MP_NEG) { + ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK); + x = ac & MP_MASK; + ac >>= MP_DIGIT_BIT; + } else { + x = (i >= a->used) ? 0uL : a->dp[i]; + } + + /* convert to two complement if negative */ + if (b->sign == MP_NEG) { + bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK); + y = bc & MP_MASK; + bc >>= MP_DIGIT_BIT; + } else { + y = (i >= b->used) ? 0uL : b->dp[i]; + } + + c->dp[i] = x ^ y; + + /* convert to to sign-magnitude if negative */ + if (csign == MP_NEG) { + cc += ~c->dp[i] & MP_MASK; + c->dp[i] = cc & MP_MASK; + cc >>= MP_DIGIT_BIT; + } + } + + c->used = used; + c->sign = csign; + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_mp_xor.c */ + +/* Start: bn_mp_zero.c */ +#include "tommath_private.h" +#ifdef BN_MP_ZERO_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* set to zero */ +void mp_zero(mp_int *a) +{ + a->sign = MP_ZPOS; + a->used = 0; + MP_ZERO_DIGITS(a->dp, a->alloc); +} +#endif + +/* End: bn_mp_zero.c */ + +/* Start: bn_prime_tab.c */ +#include "tommath_private.h" +#ifdef BN_PRIME_TAB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +const mp_digit ltm_prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif +}; + +#if defined(__GNUC__) && __GNUC__ >= 4 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) && _MSC_VER >= 1500 +#pragma warning(push) +#pragma warning(disable: 4996) +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#pragma warning(pop) +#else +const mp_digit *s_mp_prime_tab = ltm_prime_tab; +#endif + +#endif + +/* End: bn_prime_tab.c */ + +/* Start: bn_s_mp_add.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_ADD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) +{ + const mp_int *x; + mp_err err; + int olduse, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < (max + 1)) { + if ((err = mp_grow(c, max + 1)) != MP_OKAY) { + return err; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (mp_digit)MP_DIGIT_BIT; + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (mp_digit)MP_DIGIT_BIT; + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + MP_ZERO_DIGITS(tmpc, olduse - c->used); + } + + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_add.c */ + +/* Start: bn_s_mp_balance_mul.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_BALANCE_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* single-digit multiplication with the smaller number as the single-digit */ +mp_err s_mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + int count, len_a, len_b, nblocks, i, j, bsize; + mp_int a0, tmp, A, B, r; + mp_err err; + + len_a = a->used; + len_b = b->used; + + nblocks = MP_MAX(a->used, b->used) / MP_MIN(a->used, b->used); + bsize = MP_MIN(a->used, b->used) ; + + if ((err = mp_init_size(&a0, bsize + 2)) != MP_OKAY) { + return err; + } + if ((err = mp_init_multi(&tmp, &r, NULL)) != MP_OKAY) { + mp_clear(&a0); + return err; + } + + /* Make sure that A is the larger one*/ + if (len_a < len_b) { + B = *a; + A = *b; + } else { + A = *a; + B = *b; + } + + for (i = 0, j=0; i < nblocks; i++) { + /* Cut a slice off of a */ + a0.used = 0; + for (count = 0; count < bsize; count++) { + a0.dp[count] = A.dp[ j++ ]; + a0.used++; + } + mp_clamp(&a0); + /* Multiply with b */ + if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) { + goto LBL_ERR; + } + /* Shift tmp to the correct position */ + if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { + goto LBL_ERR; + } + /* Add to output. No carry needed */ + if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* The left-overs; there are always left-overs */ + if (j < A.used) { + a0.used = 0; + for (count = 0; j < A.used; count++) { + a0.dp[count] = A.dp[ j++ ]; + a0.used++; + } + mp_clamp(&a0); + if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) { + goto LBL_ERR; + } + if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) { + goto LBL_ERR; + } + } + + mp_exch(&r,c); +LBL_ERR: + mp_clear_multi(&a0, &tmp, &r,NULL); + return err; +} +#endif + +/* End: bn_s_mp_balance_mul.c */ + +/* Start: bn_s_mp_exptmod.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_EXPTMOD_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifdef MP_LOW_MEM +# define TAB_SIZE 32 +# define MAX_WINSIZE 5 +#else +# define TAB_SIZE 256 +# define MAX_WINSIZE 0 +#endif + +mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + mp_err err; + int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + mp_err(*redux)(mp_int *x, const mp_int *m, const mp_int *mu); + + /* find window size */ + x = mp_count_bits(X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize; + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear(&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init(&mu)) != MP_OKAY) goto LBL_M; + + if (redmode == 0) { + if ((err = mp_reduce_setup(&mu, P)) != MP_OKAY) goto LBL_MU; + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l(P, &mu)) != MP_OKAY) goto LBL_MU; + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_MU; + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU; + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], + &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU; + + /* reduce modulo P */ + if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, &mu)) != MP_OKAY) goto LBL_MU; + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_MU; + if ((err = redux(&M[x], P, &mu)) != MP_OKAY) goto LBL_MU; + } + + /* setup result */ + if ((err = mp_init(&res)) != MP_OKAY) goto LBL_MU; + mp_set(&res, 1uL); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)MP_DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(MP_DIGIT_BIT - 1)) & 1uL; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if ((mode == 0) && (y == 0)) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if ((mode == 1) && (y == 0)) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + } + + /* then multiply */ + if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if ((mode == 2) && (bitcpy > 0)) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES; + } + } + } + + mp_exch(&res, Y); + err = MP_OKAY; +LBL_RES: + mp_clear(&res); +LBL_MU: + mp_clear(&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear(&M[x]); + } + return err; +} +#endif + +/* End: bn_s_mp_exptmod.c */ + +/* Start: bn_s_mp_exptmod_fast.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_EXPTMOD_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +#ifdef MP_LOW_MEM +# define TAB_SIZE 32 +# define MAX_WINSIZE 5 +#else +# define TAB_SIZE 256 +# define MAX_WINSIZE 0 +#endif + +mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + mp_err err; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + mp_err(*redux)(mp_int *x, const mp_int *n, mp_digit rho); + + /* find window size */ + x = mp_count_bits(X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize; + + /* init M array */ + /* init first cell */ + if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear(&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + if (MP_HAS(MP_MONTGOMERY_SETUP)) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) goto LBL_M; + } else { + err = MP_VAL; + goto LBL_M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (MP_HAS(S_MP_MONTGOMERY_REDUCE_FAST) && + (((P->used * 2) + 1) < MP_WARRAY) && + (P->used < MP_MAXFAST)) { + redux = s_mp_montgomery_reduce_fast; + } else if (MP_HAS(MP_MONTGOMERY_REDUCE)) { + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; + } else { + err = MP_VAL; + goto LBL_M; + } + } else if (redmode == 1) { + if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) { + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + err = MP_VAL; + goto LBL_M; + } + } else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) { + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) goto LBL_M; + redux = mp_reduce_2k; + } else { + err = MP_VAL; + goto LBL_M; + } + + /* setup result */ + if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) goto LBL_M; + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) goto LBL_RES; + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) goto LBL_RES; + } else { + err = MP_VAL; + goto LBL_RES; + } + } else { + mp_set(&res, 1uL); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_RES; + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES; + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES; + if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_RES; + if ((err = redux(&M[x], P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)MP_DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (MP_DIGIT_BIT - 1)) & 1uL; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if ((mode == 0) && (y == 0)) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if ((mode == 1) && (y == 0)) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* then multiply */ + if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if ((mode == 2) && (bitcpy > 0)) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES; + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES; + } + + /* swap res with Y */ + mp_exch(&res, Y); + err = MP_OKAY; +LBL_RES: + mp_clear(&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear(&M[x]); + } + return err; +} +#endif + +/* End: bn_s_mp_exptmod_fast.c */ + +/* Start: bn_s_mp_get_bit.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_GET_BIT_C + +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Get bit at position b and return MP_YES if the bit is 1, MP_NO if it is 0 */ +mp_bool s_mp_get_bit(const mp_int *a, unsigned int b) +{ + mp_digit bit; + int limb = (int)(b / MP_DIGIT_BIT); + + if (limb >= a->used) { + return MP_NO; + } + + bit = (mp_digit)1 << (b % MP_DIGIT_BIT); + return ((a->dp[limb] & bit) != 0u) ? MP_YES : MP_NO; +} + +#endif + +/* End: bn_s_mp_get_bit.c */ + +/* Start: bn_s_mp_invmod_fast.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_INVMOD_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on slow invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x, y, u, v, B, D; + mp_sign neg; + mp_err err; + + /* 2. [modified] b must be odd */ + if (MP_IS_EVEN(b)) { + return MP_VAL; + } + + /* init all our temps */ + if ((err = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return err; + } + + /* x == modulus, y == value to invert */ + if ((err = mp_copy(b, &x)) != MP_OKAY) goto LBL_ERR; + + /* we need y = |a| */ + if ((err = mp_mod(a, b, &y)) != MP_OKAY) goto LBL_ERR; + + /* if one of x,y is zero return an error! */ + if (MP_IS_ZERO(&x) || MP_IS_ZERO(&y)) { + err = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR; + mp_set(&D, 1uL); + +top: + /* 4. while u is even do */ + while (MP_IS_EVEN(&u)) { + /* 4.1 u = u/2 */ + if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR; + + /* 4.2 if B is odd then */ + if (MP_IS_ODD(&B)) { + if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR; + } + /* B = B/2 */ + if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR; + } + + /* 5. while v is even do */ + while (MP_IS_EVEN(&v)) { + /* 5.1 v = v/2 */ + if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR; + + /* 5.2 if D is odd then */ + if (MP_IS_ODD(&D)) { + /* D = (D-x)/2 */ + if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR; + } + /* D = D/2 */ + if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* 6. if u >= v then */ + if (mp_cmp(&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR; + } else { + /* v - v - u, D = D - B */ + if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* if not zero goto step 4 */ + if (!MP_IS_ZERO(&u)) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d(&v, 1uL) != MP_EQ) { + err = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((err = mp_add(&D, b, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* too big */ + while (mp_cmp_mag(&D, b) != MP_LT) { + if ((err = mp_sub(&D, b, &D)) != MP_OKAY) goto LBL_ERR; + } + + mp_exch(&D, c); + c->sign = neg; + err = MP_OKAY; + +LBL_ERR: + mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL); + return err; +} +#endif + +/* End: bn_s_mp_invmod_fast.c */ + +/* Start: bn_s_mp_invmod_slow.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_INVMOD_SLOW_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* hac 14.61, pp608 */ +mp_err s_mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x, y, u, v, A, B, C, D; + mp_err err; + + /* b cannot be negative */ + if ((b->sign == MP_NEG) || MP_IS_ZERO(b)) { + return MP_VAL; + } + + /* init temps */ + if ((err = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return err; + } + + /* x = a, y = b */ + if ((err = mp_mod(a, b, &x)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(b, &y)) != MP_OKAY) goto LBL_ERR; + + /* 2. [modified] if x,y are both even then return an error! */ + if (MP_IS_EVEN(&x) && MP_IS_EVEN(&y)) { + err = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR; + mp_set(&A, 1uL); + mp_set(&D, 1uL); + +top: + /* 4. while u is even do */ + while (MP_IS_EVEN(&u)) { + /* 4.1 u = u/2 */ + if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR; + + /* 4.2 if A or B is odd then */ + if (MP_IS_ODD(&A) || MP_IS_ODD(&B)) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((err = mp_add(&A, &y, &A)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR; + } + /* A = A/2, B = B/2 */ + if ((err = mp_div_2(&A, &A)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR; + } + + /* 5. while v is even do */ + while (MP_IS_EVEN(&v)) { + /* 5.1 v = v/2 */ + if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR; + + /* 5.2 if C or D is odd then */ + if (MP_IS_ODD(&C) || MP_IS_ODD(&D)) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((err = mp_add(&C, &y, &C)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR; + } + /* C = C/2, D = D/2 */ + if ((err = mp_div_2(&C, &C)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* 6. if u >= v then */ + if (mp_cmp(&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&A, &C, &A)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR; + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&C, &A, &C)) != MP_OKAY) goto LBL_ERR; + + if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR; + } + + /* if not zero goto step 4 */ + if (!MP_IS_ZERO(&u)) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d(&v, 1uL) != MP_EQ) { + err = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0uL) == MP_LT) { + if ((err = mp_add(&C, b, &C)) != MP_OKAY) goto LBL_ERR; + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((err = mp_sub(&C, b, &C)) != MP_OKAY) goto LBL_ERR; + } + + /* C is now the inverse */ + mp_exch(&C, c); + err = MP_OKAY; +LBL_ERR: + mp_clear_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return err; +} +#endif + +/* End: bn_s_mp_invmod_slow.c */ + +/* Start: bn_s_mp_karatsuba_mul.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_KARATSUBA_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**MP_DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1+b1)(a0+b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +mp_err s_mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B; + mp_err err = MP_MEM; /* default the return code to an error */ + + /* min # of digits */ + B = MP_MIN(a->used, b->used); + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size(&x0, B) != MP_OKAY) { + goto LBL_ERR; + } + if (mp_init_size(&x1, a->used - B) != MP_OKAY) { + goto X0; + } + if (mp_init_size(&y0, B) != MP_OKAY) { + goto X1; + } + if (mp_init_size(&y1, b->used - B) != MP_OKAY) { + goto Y0; + } + + /* init temps */ + if (mp_init_size(&t1, B * 2) != MP_OKAY) { + goto Y1; + } + if (mp_init_size(&x0y0, B * 2) != MP_OKAY) { + goto T1; + } + if (mp_init_size(&x1y1, B * 2) != MP_OKAY) { + goto X0Y0; + } + + /* now shift the digits */ + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + int x; + mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp(&x0); + mp_clamp(&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul(&x0, &y0, &x0y0) != MP_OKAY) { + goto X1Y1; /* x0y0 = x0*y0 */ + } + if (mp_mul(&x1, &y1, &x1y1) != MP_OKAY) { + goto X1Y1; /* x1y1 = x1*y1 */ + } + + /* now calc x1+x0 and y1+y0 */ + if (s_mp_add(&x1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = x1 - x0 */ + } + if (s_mp_add(&y1, &y0, &x0) != MP_OKAY) { + goto X1Y1; /* t2 = y1 - y0 */ + } + if (mp_mul(&t1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */ + } + + /* add x0y0 */ + if (mp_add(&x0y0, &x1y1, &x0) != MP_OKAY) { + goto X1Y1; /* t2 = x0y0 + x1y1 */ + } + if (s_mp_sub(&t1, &x0, &t1) != MP_OKAY) { + goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */ + } + + /* shift by B */ + if (mp_lshd(&t1, B) != MP_OKAY) { + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size(&x0, B) != MP_OKAY) + goto LBL_ERR; + if (mp_init_size(&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size(&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size(&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size(&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size(&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + int x; + mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp(&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr(&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr(&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1+x0)**2 */ + if (s_mp_add(&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr(&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add(&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (s_mp_sub(&t1, &t2, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */ + + /* shift by B */ + if (mp_lshd(&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<used > MP_WARRAY) { + return MP_VAL; + } + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < (n->used + 1)) { + if ((err = mp_grow(x, n->used + 1)) != MP_OKAY) { + return err; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + mp_word *_W; + mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + if (ix < ((n->used * 2) + 1)) { + MP_ZERO_BUFFER(_W, sizeof(mp_word) * (size_t)(((n->used * 2) + 1) - ix)); + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + mp_digit mu; + mu = ((W[ix] & MP_MASK) * rho) & MP_MASK; + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + int iy; + mp_digit *tmpn; + mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += (mp_word)mu * (mp_word)*tmpn++; + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> (mp_word)MP_DIGIT_BIT; + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + mp_digit *tmpx; + mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix < ((n->used * 2) + 1); ix++) { + *_W++ += *_W1++ >> (mp_word)MP_DIGIT_BIT; + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < (n->used + 1); ix++) { + *tmpx++ = *_W++ & (mp_word)MP_MASK; + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + MP_ZERO_DIGITS(tmpx, olduse - ix); + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp(x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag(x, n) != MP_LT) { + return s_mp_sub(x, n, x); + } + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_montgomery_reduce_fast.c */ + +/* Start: bn_s_mp_mul_digs.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_DIGS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +mp_err s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + mp_int t; + mp_err err; + int pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if ((digs < MP_WARRAY) && + (MP_MIN(a->used, b->used) < MP_MAXFAST)) { + return s_mp_mul_digs_fast(a, b, c, digs); + } + + if ((err = mp_init_size(&t, digs)) != MP_OKAY) { + return err; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MP_MIN(b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = (mp_word)*tmpt + + ((mp_word)tmpx * (mp_word)*tmpy++) + + (mp_word)u; + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* get the carry word from the result */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + /* set carry if it is placed below digs */ + if ((ix + iy) < digs) { + *tmpt = u; + } + } + + mp_clamp(&t); + mp_exch(&t, c); + + mp_clear(&t); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_mul_digs.c */ + +/* Start: bn_s_mp_mul_digs_fast.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_DIGS_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +mp_err s_mp_mul_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + int olduse, pa, ix, iz; + mp_err err; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((err = mp_grow(c, digs)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + pa = MP_MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MP_MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + + } + + /* store term */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + _W = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + } + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_mul_digs_fast.c */ + +/* Start: bn_s_mp_mul_high_digs.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_HIGH_DIGS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + mp_int t; + int pa, pb, ix, iy; + mp_err err; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST) + && ((a->used + b->used + 1) < MP_WARRAY) + && (MP_MIN(a->used, b->used) < MP_MAXFAST)) { + return s_mp_mul_high_digs_fast(a, b, c, digs); + } + + if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) { + return err; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = (mp_word)*tmpt + + ((mp_word)tmpx * (mp_word)*tmpy++) + + (mp_word)u; + + /* get the lower part */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* carry the carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + *tmpt = u; + } + mp_clamp(&t); + mp_exch(&t, c); + mp_clear(&t); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_mul_high_digs.c */ + +/* Start: bn_s_mp_mul_high_digs_fast.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_MUL_HIGH_DIGS_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +mp_err s_mp_mul_high_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) +{ + int olduse, pa, ix, iz; + mp_err err; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((err = mp_grow(c, pa)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + pa = a->used + b->used; + _W = 0; + for (ix = digs; ix < pa; ix++) { + int tx, ty, iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MP_MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + } + + /* store term */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + _W = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + + tmpc = c->dp + digs; + for (ix = digs; ix < pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpc, olduse - ix); + } + mp_clamp(c); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_mul_high_digs_fast.c */ + +/* Start: bn_s_mp_prime_is_divisible.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_PRIME_IS_DIVISIBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not + * + * sets result to 0 if not, 1 if yes + */ +mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result) +{ + int ix; + mp_err err; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d(a, s_mp_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0u) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_prime_is_divisible.c */ + +/* Start: bn_s_mp_rand_jenkins.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_RAND_JENKINS_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* Bob Jenkins' http://burtleburtle.net/bob/rand/smallprng.html */ +/* Chosen for speed and a good "mix" */ +typedef struct { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +} ranctx; + +static ranctx jenkins_x; + +#define rot(x,k) (((x)<<(k))|((x)>>(64-(k)))) +static uint64_t s_rand_jenkins_val(void) +{ + uint64_t e = jenkins_x.a - rot(jenkins_x.b, 7); + jenkins_x.a = jenkins_x.b ^ rot(jenkins_x.c, 13); + jenkins_x.b = jenkins_x.c + rot(jenkins_x.d, 37); + jenkins_x.c = jenkins_x.d + e; + jenkins_x.d = e + jenkins_x.a; + return jenkins_x.d; +} + +void s_mp_rand_jenkins_init(uint64_t seed) +{ + uint64_t i; + jenkins_x.a = 0xf1ea5eedULL; + jenkins_x.b = jenkins_x.c = jenkins_x.d = seed; + for (i = 0uLL; i < 20uLL; ++i) { + (void)s_rand_jenkins_val(); + } +} + +mp_err s_mp_rand_jenkins(void *p, size_t n) +{ + char *q = (char *)p; + while (n > 0u) { + int i; + uint64_t x = s_rand_jenkins_val(); + for (i = 0; (i < 8) && (n > 0u); ++i, --n) { + *q++ = (char)(x & 0xFFuLL); + x >>= 8; + } + } + return MP_OKAY; +} + +#endif + +/* End: bn_s_mp_rand_jenkins.c */ + +/* Start: bn_s_mp_rand_platform.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_RAND_PLATFORM_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* First the OS-specific special cases + * - *BSD + * - Windows + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#define BN_S_READ_ARC4RANDOM_C +static mp_err s_read_arc4random(void *p, size_t n) +{ + arc4random_buf(p, n); + return MP_OKAY; +} +#endif + +#if defined(_WIN32) || defined(_WIN32_WCE) +#define BN_S_READ_WINCSP_C + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#ifdef _WIN32_WCE +#define UNDER_CE +#define ARM +#endif + +#define WIN32_LEAN_AND_MEAN +#include +#include + +static mp_err s_read_wincsp(void *p, size_t n) +{ + static HCRYPTPROV hProv = 0; + if (hProv == 0) { + HCRYPTPROV h = 0; + if (!CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && + !CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) { + return MP_ERR; + } + hProv = h; + } + return CryptGenRandom(hProv, (DWORD)n, (BYTE *)p) == TRUE ? MP_OKAY : MP_ERR; +} +#endif /* WIN32 */ + +#if !defined(BN_S_READ_WINCSP_C) && defined(__linux__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2, 25) +#define BN_S_READ_GETRANDOM_C +#include +#include + +static mp_err s_read_getrandom(void *p, size_t n) +{ + char *q = (char *)p; + while (n > 0u) { + ssize_t ret = getrandom(q, n, 0); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + return MP_ERR; + } + q += ret; + n -= (size_t)ret; + } + return MP_OKAY; +} +#endif +#endif + +/* We assume all platforms besides windows provide "/dev/urandom". + * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time. + */ +#if !defined(BN_S_READ_WINCSP_C) && !defined(MP_NO_DEV_URANDOM) +#define BN_S_READ_URANDOM_C +#ifndef MP_DEV_URANDOM +#define MP_DEV_URANDOM "/dev/urandom" +#endif +#include +#include +#include + +static mp_err s_read_urandom(void *p, size_t n) +{ + int fd; + char *q = (char *)p; + + do { + fd = open(MP_DEV_URANDOM, O_RDONLY); + } while ((fd == -1) && (errno == EINTR)); + if (fd == -1) return MP_ERR; + + while (n > 0u) { + ssize_t ret = read(fd, p, n); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + close(fd); + return MP_ERR; + } + q += ret; + n -= (size_t)ret; + } + + close(fd); + return MP_OKAY; +} +#endif + +#if defined(MP_PRNG_ENABLE_LTM_RNG) +#define BN_S_READ_LTM_RNG +unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void)); +void (*ltm_rng_callback)(void); + +static mp_err s_read_ltm_rng(void *p, size_t n) +{ + unsigned long res; + if (ltm_rng == NULL) return MP_ERR; + res = ltm_rng(p, n, ltm_rng_callback); + if (res != n) return MP_ERR; + return MP_OKAY; +} +#endif + +mp_err s_read_arc4random(void *p, size_t n); +mp_err s_read_wincsp(void *p, size_t n); +mp_err s_read_getrandom(void *p, size_t n); +mp_err s_read_urandom(void *p, size_t n); +mp_err s_read_ltm_rng(void *p, size_t n); + +mp_err s_mp_rand_platform(void *p, size_t n) +{ + mp_err err = MP_ERR; + if ((err != MP_OKAY) && MP_HAS(S_READ_ARC4RANDOM)) err = s_read_arc4random(p, n); + if ((err != MP_OKAY) && MP_HAS(S_READ_WINCSP)) err = s_read_wincsp(p, n); + if ((err != MP_OKAY) && MP_HAS(S_READ_GETRANDOM)) err = s_read_getrandom(p, n); + if ((err != MP_OKAY) && MP_HAS(S_READ_URANDOM)) err = s_read_urandom(p, n); + if ((err != MP_OKAY) && MP_HAS(S_READ_LTM_RNG)) err = s_read_ltm_rng(p, n); + return err; +} + +#endif + +/* End: bn_s_mp_rand_platform.c */ + +/* Start: bn_s_mp_reverse.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_REVERSE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* reverse an array, used for radix code */ +void s_mp_reverse(unsigned char *s, size_t len) +{ + size_t ix, iy; + unsigned char t; + + ix = 0u; + iy = len - 1u; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} +#endif + +/* End: bn_s_mp_reverse.c */ + +/* Start: bn_s_mp_sqr.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +mp_err s_mp_sqr(const mp_int *a, mp_int *b) +{ + mp_int t; + int ix, iy, pa; + mp_err err; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((err = mp_init_size(&t, (2 * pa) + 1)) != MP_OKAY) { + return err; + } + + /* default used is maximum possible size */ + t.used = (2 * pa) + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = (mp_word)t.dp[2*ix] + + ((mp_word)a->dp[ix] * (mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit)(r & (mp_word)MP_MASK); + + /* get the carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + ((2 * ix) + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = (mp_word)tmpx * (mp_word)a->dp[iy]; + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = (mp_word)*tmpt + r + r + (mp_word)u; + + /* store lower part */ + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + + /* get carry */ + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + /* propagate upwards */ + while (u != 0uL) { + r = (mp_word)*tmpt + (mp_word)u; + *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK); + u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT); + } + } + + mp_clamp(&t); + mp_exch(&t, b); + mp_clear(&t); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_sqr.c */ + +/* Start: bn_s_mp_sqr_fast.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_SQR_FAST_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +mp_err s_mp_sqr_fast(const mp_int *a, mp_int *b) +{ + int olduse, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + mp_err err; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((err = mp_grow(b, pa)) != MP_OKAY) { + return err; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MP_MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MP_MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MP_MIN(iy, ((ty-tx)+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += (mp_word)*tmpx++ * (mp_word)*tmpy--; + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if (((unsigned)ix & 1u) == 0u) { + _W += (mp_word)a->dp[ix>>1] * (mp_word)a->dp[ix>>1]; + } + + /* store it */ + W[ix] = (mp_digit)_W & MP_MASK; + + /* make next carry */ + W1 = _W >> (mp_word)MP_DIGIT_BIT; + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + MP_ZERO_DIGITS(tmpb, olduse - ix); + } + mp_clamp(b); + return MP_OKAY; +} +#endif + +/* End: bn_s_mp_sqr_fast.c */ + +/* Start: bn_s_mp_sub.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_SUB_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) +{ + int olduse, min, max; + mp_err err; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((err = mp_grow(c, max)) != MP_OKAY) { + return err; + } + } + olduse = c->used; + c->used = max; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = (*tmpa++ - *tmpb++) - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + MP_ZERO_DIGITS(tmpc, olduse - c->used); + } + + mp_clamp(c); + return MP_OKAY; +} + +#endif + +/* End: bn_s_mp_sub.c */ + +/* Start: bn_s_mp_toom_mul.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_TOOM_MUL_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* multiplication using the Toom-Cook 3-way algorithm + * + * Much more complicated than Karatsuba but has a lower + * asymptotic running time of O(N**1.464). This algorithm is + * only particularly useful on VERY large inputs + * (we're talking 1000s of digits here...). +*/ + +/* + This file contains code from J. Arndt's book "Matters Computational" + and the accompanying FXT-library with permission of the author. +*/ + +/* + Setup from + + Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae." + 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007. + + The interpolation from above needed one temporary variable more + than the interpolation here: + + Bodrato, Marco, and Alberto Zanoni. "What about Toom-Cook matrices optimality." + Centro Vito Volterra Universita di Roma Tor Vergata (2006) +*/ + +mp_err s_mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) +{ + mp_int S1, S2, T1, a0, a1, a2, b0, b1, b2; + int B, count; + mp_err err; + + /* init temps */ + if ((err = mp_init_multi(&S1, &S2, &T1, NULL)) != MP_OKAY) { + return err; + } + + /* B */ + B = MP_MIN(a->used, b->used) / 3; + + /** a = a2 * x^2 + a1 * x + a0; */ + if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0; + + for (count = 0; count < B; count++) { + a0.dp[count] = a->dp[count]; + a0.used++; + } + mp_clamp(&a0); + if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1; + for (; count < (2 * B); count++) { + a1.dp[count - B] = a->dp[count]; + a1.used++; + } + mp_clamp(&a1); + if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2; + for (; count < a->used; count++) { + a2.dp[count - (2 * B)] = a->dp[count]; + a2.used++; + } + mp_clamp(&a2); + + /** b = b2 * x^2 + b1 * x + b0; */ + if ((err = mp_init_size(&b0, B)) != MP_OKAY) goto LBL_ERRb0; + for (count = 0; count < B; count++) { + b0.dp[count] = b->dp[count]; + b0.used++; + } + mp_clamp(&b0); + if ((err = mp_init_size(&b1, B)) != MP_OKAY) goto LBL_ERRb1; + for (; count < (2 * B); count++) { + b1.dp[count - B] = b->dp[count]; + b1.used++; + } + mp_clamp(&b1); + if ((err = mp_init_size(&b2, B + (b->used - (3 * B)))) != MP_OKAY) goto LBL_ERRb2; + for (; count < b->used; count++) { + b2.dp[count - (2 * B)] = b->dp[count]; + b2.used++; + } + mp_clamp(&b2); + + /** \\ S1 = (a2+a1+a0) * (b2+b1+b0); */ + /** T1 = a2 + a1; */ + if ((err = mp_add(&a2, &a1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = T1 + a0; */ + if ((err = mp_add(&T1, &a0, &S2)) != MP_OKAY) goto LBL_ERR; + + /** c = b2 + b1; */ + if ((err = mp_add(&b2, &b1, c)) != MP_OKAY) goto LBL_ERR; + + /** S1 = c + b0; */ + if ((err = mp_add(c, &b0, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 * S2; */ + if ((err = mp_mul(&S1, &S2, &S1)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = (4*a2+2*a1+a0) * (4*b2+2*b1+b0); */ + /** T1 = T1 + a2; */ + if ((err = mp_add(&T1, &a2, &T1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = T1 << 1; */ + if ((err = mp_mul_2(&T1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = T1 + a0; */ + if ((err = mp_add(&T1, &a0, &T1)) != MP_OKAY) goto LBL_ERR; + + /** c = c + b2; */ + if ((err = mp_add(c, &b2, c)) != MP_OKAY) goto LBL_ERR; + + /** c = c << 1; */ + if ((err = mp_mul_2(c, c)) != MP_OKAY) goto LBL_ERR; + + /** c = c + b0; */ + if ((err = mp_add(c, &b0, c)) != MP_OKAY) goto LBL_ERR; + + /** S2 = T1 * c; */ + if ((err = mp_mul(&T1, c, &S2)) != MP_OKAY) goto LBL_ERR; + + /** \\S3 = (a2-a1+a0) * (b2-b1+b0); */ + /** a1 = a2 - a1; */ + if ((err = mp_sub(&a2, &a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 + a0; */ + if ((err = mp_add(&a1, &a0, &a1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = b2 - b1; */ + if ((err = mp_sub(&b2, &b1, &b1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = b1 + b0; */ + if ((err = mp_add(&b1, &b0, &b1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 * b1; */ + if ((err = mp_mul(&a1, &b1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** b1 = a2 * b2; */ + if ((err = mp_mul(&a2, &b2, &b1)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = (S2 - S3)/3; */ + /** S2 = S2 - a1; */ + if ((err = mp_sub(&S2, &a1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 / 3; \\ this is an exact division */ + if ((err = mp_div_3(&S2, &S2, NULL)) != MP_OKAY) goto LBL_ERR; + + /** a1 = S1 - a1; */ + if ((err = mp_sub(&S1, &a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 >> 1; */ + if ((err = mp_div_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** a0 = a0 * b0; */ + if ((err = mp_mul(&a0, &b0, &a0)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - a0; */ + if ((err = mp_sub(&S1, &a0, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 - S1; */ + if ((err = mp_sub(&S2, &S1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 >> 1; */ + if ((err = mp_div_2(&S2, &S2)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - a1; */ + if ((err = mp_sub(&S1, &a1, &S1)) != MP_OKAY) goto LBL_ERR; + + /** S1 = S1 - b1; */ + if ((err = mp_sub(&S1, &b1, &S1)) != MP_OKAY) goto LBL_ERR; + + /** T1 = b1 << 1; */ + if ((err = mp_mul_2(&b1, &T1)) != MP_OKAY) goto LBL_ERR; + + /** S2 = S2 - T1; */ + if ((err = mp_sub(&S2, &T1, &S2)) != MP_OKAY) goto LBL_ERR; + + /** a1 = a1 - S2; */ + if ((err = mp_sub(&a1, &S2, &a1)) != MP_OKAY) goto LBL_ERR; + + + /** P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0; */ + if ((err = mp_lshd(&b1, 4 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&S2, 3 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &S2, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&S1, 2 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &S1, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a1, 1 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &a1, &b1)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&b1, &a0, c)) != MP_OKAY) goto LBL_ERR; + + /** a * b - P */ + + +LBL_ERR: + mp_clear(&b2); +LBL_ERRb2: + mp_clear(&b1); +LBL_ERRb1: + mp_clear(&b0); +LBL_ERRb0: + mp_clear(&a2); +LBL_ERRa2: + mp_clear(&a1); +LBL_ERRa1: + mp_clear(&a0); +LBL_ERRa0: + mp_clear_multi(&S1, &S2, &T1, NULL); + return err; +} + +#endif + +/* End: bn_s_mp_toom_mul.c */ + +/* Start: bn_s_mp_toom_sqr.c */ +#include "tommath_private.h" +#ifdef BN_S_MP_TOOM_SQR_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* squaring using Toom-Cook 3-way algorithm */ + +/* + This file contains code from J. Arndt's book "Matters Computational" + and the accompanying FXT-library with permission of the author. +*/ + +/* squaring using Toom-Cook 3-way algorithm */ +/* + Setup and interpolation from algorithm SQR_3 in + + Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae." + 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007. + +*/ +mp_err s_mp_toom_sqr(const mp_int *a, mp_int *b) +{ + mp_int S0, a0, a1, a2; + mp_digit *tmpa, *tmpc; + int B, count; + mp_err err; + + + /* init temps */ + if ((err = mp_init(&S0)) != MP_OKAY) { + return err; + } + + /* B */ + B = a->used / 3; + + /** a = a2 * x^2 + a1 * x + a0; */ + if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0; + + a0.used = B; + if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1; + a1.used = B; + if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2; + + tmpa = a->dp; + tmpc = a0.dp; + for (count = 0; count < B; count++) { + *tmpc++ = *tmpa++; + } + tmpc = a1.dp; + for (; count < (2 * B); count++) { + *tmpc++ = *tmpa++; + } + tmpc = a2.dp; + for (; count < a->used; count++) { + *tmpc++ = *tmpa++; + a2.used++; + } + mp_clamp(&a0); + mp_clamp(&a1); + mp_clamp(&a2); + + /** S0 = a0^2; */ + if ((err = mp_sqr(&a0, &S0)) != MP_OKAY) goto LBL_ERR; + + /** \\S1 = (a2 + a1 + a0)^2 */ + /** \\S2 = (a2 - a1 + a0)^2 */ + /** \\S1 = a0 + a2; */ + /** a0 = a0 + a2; */ + if ((err = mp_add(&a0, &a2, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S1 - a1; */ + /** b = a0 - a1; */ + if ((err = mp_sub(&a0, &a1, b)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1 + a1; */ + /** a0 = a0 + a1; */ + if ((err = mp_add(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1^2; */ + /** a0 = a0^2; */ + if ((err = mp_sqr(&a0, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S2^2; */ + /** b = b^2; */ + if ((err = mp_sqr(b, b)) != MP_OKAY) goto LBL_ERR; + + /** \\ S3 = 2 * a1 * a2 */ + /** \\S3 = a1 * a2; */ + /** a1 = a1 * a2; */ + if ((err = mp_mul(&a1, &a2, &a1)) != MP_OKAY) goto LBL_ERR; + /** \\S3 = S3 << 1; */ + /** a1 = a1 << 1; */ + if ((err = mp_mul_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR; + + /** \\S4 = a2^2; */ + /** a2 = a2^2; */ + if ((err = mp_sqr(&a2, &a2)) != MP_OKAY) goto LBL_ERR; + + /** \\ tmp = (S1 + S2)/2 */ + /** \\tmp = S1 + S2; */ + /** b = a0 + b; */ + if ((err = mp_add(&a0, b, b)) != MP_OKAY) goto LBL_ERR; + /** \\tmp = tmp >> 1; */ + /** b = b >> 1; */ + if ((err = mp_div_2(b, b)) != MP_OKAY) goto LBL_ERR; + + /** \\ S1 = S1 - tmp - S3 */ + /** \\S1 = S1 - tmp; */ + /** a0 = a0 - b; */ + if ((err = mp_sub(&a0, b, &a0)) != MP_OKAY) goto LBL_ERR; + /** \\S1 = S1 - S3; */ + /** a0 = a0 - a1; */ + if ((err = mp_sub(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR; + + /** \\S2 = tmp - S4 -S0 */ + /** \\S2 = tmp - S4; */ + /** b = b - a2; */ + if ((err = mp_sub(b, &a2, b)) != MP_OKAY) goto LBL_ERR; + /** \\S2 = S2 - S0; */ + /** b = b - S0; */ + if ((err = mp_sub(b, &S0, b)) != MP_OKAY) goto LBL_ERR; + + + /** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */ + /** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */ + + if ((err = mp_lshd(&a2, 4 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a1, 3 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(b, 2 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_lshd(&a0, 1 * B)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&a2, &a1, &a2)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(&a2, b, b)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(b, &a0, b)) != MP_OKAY) goto LBL_ERR; + if ((err = mp_add(b, &S0, b)) != MP_OKAY) goto LBL_ERR; + /** a^2 - P */ + + +LBL_ERR: + mp_clear(&a2); +LBL_ERRa2: + mp_clear(&a1); +LBL_ERRa1: + mp_clear(&a0); +LBL_ERRa0: + mp_clear(&S0); + + return err; +} + +#endif + +/* End: bn_s_mp_toom_sqr.c */ + + +/* EOF */ diff --git a/third_party/heimdal/lib/hcrypto/libtommath/testme.sh b/third_party/heimdal/lib/hcrypto/libtommath/testme.sh new file mode 100755 index 0000000..40fa32d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/testme.sh @@ -0,0 +1,394 @@ +#!/bin/bash +# +# return values of this script are: +# 0 success +# 128 a test failed +# >0 the number of timed-out tests +# 255 parsing of parameters failed + +set -e + +if [ -f /proc/cpuinfo ] +then + MAKE_JOBS=$(( ($(cat /proc/cpuinfo | grep -E '^processor[[:space:]]*:' | tail -n -1 | cut -d':' -f2) + 1) * 2 + 1 )) +else + MAKE_JOBS=8 +fi + +ret=0 +TEST_CFLAGS="" + +_help() +{ + echo "Usage options for $(basename $0) [--with-cc=arg [other options]]" + echo + echo "Executing this script without any parameter will only run the default" + echo "configuration that has automatically been determined for the" + echo "architecture you're running." + echo + echo " --with-cc=* The compiler(s) to use for the tests" + echo " This is an option that will be iterated." + echo + echo " --test-vs-mtest=* Run test vs. mtest for '*' operations." + echo " Only the first of each options will be" + echo " taken into account." + echo + echo "To be able to specify options a compiler has to be given with" + echo "the option --with-cc=compilername" + echo "All other options will be tested with all MP_xBIT configurations." + echo + echo " --with-{m64,m32,mx32} The architecture(s) to build and test" + echo " for, e.g. --with-mx32." + echo " This is an option that will be iterated," + echo " multiple selections are possible." + echo " The mx32 architecture is not supported" + echo " by clang and will not be executed." + echo + echo " --cflags=* Give an option to the compiler," + echo " e.g. --cflags=-g" + echo " This is an option that will always be" + echo " passed as parameter to CC." + echo + echo " --make-option=* Give an option to make," + echo " e.g. --make-option=\"-f makefile.shared\"" + echo " This is an option that will always be" + echo " passed as parameter to make." + echo + echo " --with-low-mp Also build&run tests with -DMP_{8,16,32}BIT." + echo + echo " --mtest-real-rand Use real random data when running mtest." + echo + echo " --with-valgrind" + echo " --with-valgrind=* Run in valgrind (slow!)." + echo + echo " --with-travis-valgrind Run with valgrind on Travis on specific branches." + echo + echo " --valgrind-options Additional Valgrind options" + echo " Some of the options like e.g.:" + echo " --track-origins=yes add a lot of extra" + echo " runtime and may trigger the 30 minutes" + echo " timeout." + echo + echo "Godmode:" + echo + echo " --all Choose all architectures and gcc and clang" + echo " as compilers but does not run valgrind." + echo + echo " --format Runs the various source-code formatters" + echo " and generators and checks if the sources" + echo " are clean." + echo + echo " -h" + echo " --help This message" + echo + echo " -v" + echo " --version Prints the version. It is just the number" + echo " of git commits to this file, no deeper" + echo " meaning attached" + exit 0 +} + +_die() +{ + echo "error $2 while $1" + if [ "$2" != "124" ] + then + exit 128 + else + echo "assuming timeout while running test - continue" + local _tail="" + which tail >/dev/null && _tail="tail -n 1 test_${suffix}.log" && \ + echo "last line of test_"${suffix}".log was:" && $_tail && echo "" + ret=$(( $ret + 1 )) + fi +} + +_make() +{ + echo -ne " Compile $1 $2" + suffix=$(echo ${1}${2} | tr ' ' '_') + CC="$1" CFLAGS="$2 $TEST_CFLAGS" make -j$MAKE_JOBS $3 $MAKE_OPTIONS > /dev/null 2>gcc_errors_${suffix}.log + errcnt=$(wc -l < gcc_errors_${suffix}.log) + if [[ ${errcnt} -gt 1 ]]; then + echo " failed" + cat gcc_errors_${suffix}.log + exit 128 + fi +} + + +_runtest() +{ + make clean > /dev/null + local _timeout="" + which timeout >/dev/null && _timeout="timeout --foreground 90" + if [[ "$MAKE_OPTIONS" =~ "tune" ]] + then + # "make tune" will run "tune_it.sh" automatically, hence "autotune", but it cannot + # get switched off without some effort, so we just let it run twice for testing purposes + echo -e "\rRun autotune $1 $2" + _make "$1" "$2" "" + $_timeout $TUNE_CMD > test_${suffix}.log || _die "running autotune" $? + else + _make "$1" "$2" "test" + echo -e "\rRun test $1 $2" + $_timeout ./test > test_${suffix}.log || _die "running tests" $? + fi +} + +# This is not much more of a C&P of _runtest with a different timeout +# and the additional valgrind call. +# TODO: merge +_runvalgrind() +{ + make clean > /dev/null + local _timeout="" + # 30 minutes? Yes. Had it at 20 minutes and the Valgrind run needed over 25 minutes. + # A bit too close for comfort. + which timeout >/dev/null && _timeout="timeout --foreground 1800" +echo "MAKE_OPTIONS = \"$MAKE_OPTIONS\"" + if [[ "$MAKE_OPTIONS" =~ "tune" ]] + then +echo "autotune branch" + _make "$1" "$2" "" + # The shell used for /bin/sh is DASH 0.5.7-4ubuntu1 on the author's machine which fails valgrind, so + # we just run on instance of etc/tune with the same options as in etc/tune_it.sh + echo -e "\rRun etc/tune $1 $2 once inside valgrind" + $_timeout $VALGRIND_BIN $VALGRIND_OPTS $TUNE_CMD > test_${suffix}.log || _die "running etc/tune" $? + else + _make "$1" "$2" "test" + echo -e "\rRun test $1 $2 inside valgrind" + $_timeout $VALGRIND_BIN $VALGRIND_OPTS ./test > test_${suffix}.log || _die "running tests" $? + fi +} + + +_banner() +{ + echo "uname="$(uname -a) + [[ "$#" != "0" ]] && (echo $1=$($1 -dumpversion)) || true +} + +_exit() +{ + if [ "$ret" == "0" ] + then + echo "Tests successful" + else + echo "$ret tests timed out" + fi + + exit $ret +} + +ARCHFLAGS="" +COMPILERS="" +CFLAGS="" +WITH_LOW_MP="" +TEST_VS_MTEST="" +MTEST_RAND="" +# timed with an AMD A8-6600K +# 25 minutes +#VALGRIND_OPTS=" --track-origins=yes --leak-check=full --show-leak-kinds=all --error-exitcode=1 " +# 9 minutes (14 minutes with --test-vs-mtest=333333 --mtest-real-rand) +VALGRIND_OPTS=" --leak-check=full --show-leak-kinds=all --error-exitcode=1 " +#VALGRIND_OPTS="" +VALGRIND_BIN="" +CHECK_FORMAT="" +TUNE_CMD="./etc/tune -t -r 10 -L 3" + +alive_pid=0 + +function kill_alive() { + disown $alive_pid || true + kill $alive_pid 2>/dev/null +} + +function start_alive_printing() { + [ "$alive_pid" == "0" ] || return 0; + for i in `seq 1 10` ; do sleep 300 && echo "Tests still in Progress..."; done & + alive_pid=$! + trap kill_alive EXIT +} + +while [ $# -gt 0 ]; +do + case $1 in + "--with-m64" | "--with-m32" | "--with-mx32") + ARCHFLAGS="$ARCHFLAGS ${1:6}" + ;; + --with-cc=*) + COMPILERS="$COMPILERS ${1#*=}" + ;; + --cflags=*) + CFLAGS="$CFLAGS ${1#*=}" + ;; + --valgrind-options=*) + VALGRIND_OPTS="$VALGRIND_OPTS ${1#*=}" + ;; + --with-valgrind*) + if [[ ${1#*d} != "" ]] + then + VALGRIND_BIN="${1#*=}" + else + VALGRIND_BIN="valgrind" + fi + start_alive_printing + ;; + --with-travis-valgrind*) + if [[ ("$TRAVIS_BRANCH" == "develop" && "$TRAVIS_PULL_REQUEST" == "false") || "$TRAVIS_BRANCH" == *"valgrind"* || "$TRAVIS_COMMIT_MESSAGE" == *"valgrind"* ]] + then + if [[ ${1#*d} != "" ]] + then + VALGRIND_BIN="${1#*=}" + else + VALGRIND_BIN="valgrind" + fi + start_alive_printing + fi + ;; + --make-option=*) + MAKE_OPTIONS="$MAKE_OPTIONS ${1#*=}" + ;; + --with-low-mp) + WITH_LOW_MP="1" + ;; + --test-vs-mtest=*) + TEST_VS_MTEST="${1#*=}" + if ! [ "$TEST_VS_MTEST" -eq "$TEST_VS_MTEST" ] 2> /dev/null + then + echo "--test-vs-mtest Parameter has to be int" + exit 255 + fi + start_alive_printing + ;; + --mtest-real-rand) + MTEST_RAND="-DLTM_MTEST_REAL_RAND" + ;; + --format) + CHECK_FORMAT="1" + ;; + --all) + COMPILERS="gcc clang" + ARCHFLAGS="-m64 -m32 -mx32" + ;; + --help | -h) + _help + ;; + --version | -v) + echo $(git rev-list HEAD --count -- testme.sh) || echo "Unknown. Please run in original libtommath git repository." + exit 0 + ;; + *) + echo "Ignoring option ${1}" + ;; + esac + shift +done + +function _check_git() { + git update-index --refresh >/dev/null || true + git diff-index --quiet HEAD -- . || ( echo "FAILURE: $*" && exit 1 ) +} + +if [[ "$CHECK_FORMAT" == "1" ]] +then + make astyle + _check_git "make astyle" + perl helper.pl --update-files + _check_git "helper.pl --update-files" + perl helper.pl --check-all + _check_git "helper.pl --check-all" + exit $? +fi + +[[ "$VALGRIND_BIN" == "" ]] && VALGRIND_OPTS="" + +# default to CC environment variable if no compiler is defined but some other options +if [[ "$COMPILERS" == "" ]] && [[ "$ARCHFLAGS$MAKE_OPTIONS$CFLAGS" != "" ]] +then + COMPILERS="$CC" +# default to CC environment variable and run only default config if no option is given +elif [[ "$COMPILERS" == "" ]] +then + _banner "$CC" + if [[ "$VALGRIND_BIN" != "" ]] + then + _runvalgrind "$CC" "" + else + _runtest "$CC" "" + fi + _exit +fi + + +archflags=( $ARCHFLAGS ) +compilers=( $COMPILERS ) + +# choosing a compiler without specifying an architecture will use the default architecture +if [ "${#archflags[@]}" == "0" ] +then + archflags[0]=" " +fi + +_banner + +if [[ "$TEST_VS_MTEST" != "" ]] +then + make clean > /dev/null + _make "${compilers[0]} ${archflags[0]}" "$CFLAGS" "mtest_opponent" + echo + _make "gcc" "$MTEST_RAND" "mtest" + echo + echo "Run test vs. mtest for $TEST_VS_MTEST iterations" + _timeout="" + which timeout >/dev/null && _timeout="timeout --foreground 1800" + $_timeout ./mtest/mtest $TEST_VS_MTEST | $VALGRIND_BIN $VALGRIND_OPTS ./mtest_opponent > valgrind_test.log 2> test_vs_mtest_err.log + retval=$? + head -n 5 valgrind_test.log + tail -n 2 valgrind_test.log + exit $retval +fi + +for i in "${compilers[@]}" +do + if [ -z "$(which $i)" ] + then + echo "Skipped compiler $i, file not found" + continue + fi + compiler_version=$(echo "$i="$($i -dumpversion)) + if [ "$compiler_version" == "clang=4.2.1" ] + then + # one of my versions of clang complains about some stuff in stdio.h and stdarg.h ... + TEST_CFLAGS="-Wno-typedef-redefinition" + else + TEST_CFLAGS="" + fi + echo $compiler_version + + for a in "${archflags[@]}" + do + if [[ $(expr "$i" : "clang") -ne 0 && "$a" == "-mx32" ]] + then + echo "clang -mx32 tests skipped" + continue + fi + if [[ "$VALGRIND_BIN" != "" ]] + then + _runvalgrind "$i $a" "$CFLAGS" + [ "$WITH_LOW_MP" != "1" ] && continue + _runvalgrind "$i $a" "-DMP_8BIT $CFLAGS" + _runvalgrind "$i $a" "-DMP_16BIT $CFLAGS" + _runvalgrind "$i $a" "-DMP_32BIT $CFLAGS" + else + _runtest "$i $a" "$CFLAGS" + [ "$WITH_LOW_MP" != "1" ] && continue + _runtest "$i $a" "-DMP_8BIT $CFLAGS" + _runtest "$i $a" "-DMP_16BIT $CFLAGS" + _runtest "$i $a" "-DMP_32BIT $CFLAGS" + fi + done +done + +_exit diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath.def b/third_party/heimdal/lib/hcrypto/libtommath/tommath.def new file mode 100644 index 0000000..229fae4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath.def @@ -0,0 +1,145 @@ +; libtommath +; +; Use this command to produce a 32-bit .lib file, for use in any MSVC version +; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib +; Use this command to produce a 64-bit .lib file, for use in any MSVC version +; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib +; +EXPORTS + mp_2expt + mp_abs + mp_add + mp_add_d + mp_addmod + mp_and + mp_clamp + mp_clear + mp_clear_multi + mp_cmp + mp_cmp_d + mp_cmp_mag + mp_cnt_lsb + mp_complement + mp_copy + mp_count_bits + mp_decr + mp_div + mp_div_2 + mp_div_2d + mp_div_3 + mp_div_d + mp_dr_is_modulus + mp_dr_reduce + mp_dr_setup + mp_error_to_string + mp_exch + mp_expt_u32 + mp_exptmod + mp_exteuclid + mp_fread + mp_from_sbin + mp_from_ubin + mp_fwrite + mp_gcd + mp_get_double + mp_get_i32 + mp_get_i64 + mp_get_int + mp_get_l + mp_get_ll + mp_get_long + mp_get_long_long + mp_get_mag_u32 + mp_get_mag_u64 + mp_get_mag_ul + mp_get_mag_ull + mp_grow + mp_incr + mp_init + mp_init_copy + mp_init_i32 + mp_init_i64 + mp_init_l + mp_init_ll + mp_init_multi + mp_init_set + mp_init_set_int + mp_init_size + mp_init_u32 + mp_init_u64 + mp_init_ul + mp_init_ull + mp_invmod + mp_is_square + mp_iseven + mp_isodd + mp_kronecker + mp_lcm + mp_log_u32 + mp_lshd + mp_mod + mp_mod_2d + mp_mod_d + mp_montgomery_calc_normalization + mp_montgomery_reduce + mp_montgomery_setup + mp_mul + mp_mul_2 + mp_mul_2d + mp_mul_d + mp_mulmod + mp_neg + mp_or + mp_pack + mp_pack_count + mp_prime_fermat + mp_prime_frobenius_underwood + mp_prime_is_prime + mp_prime_miller_rabin + mp_prime_next_prime + mp_prime_rabin_miller_trials + mp_prime_rand + mp_prime_strong_lucas_selfridge + mp_radix_size + mp_rand + mp_read_radix + mp_reduce + mp_reduce_2k + mp_reduce_2k_l + mp_reduce_2k_setup + mp_reduce_2k_setup_l + mp_reduce_is_2k + mp_reduce_is_2k_l + mp_reduce_setup + mp_root_u32 + mp_rshd + mp_sbin_size + mp_set + mp_set_double + mp_set_i32 + mp_set_i64 + mp_set_int + mp_set_l + mp_set_ll + mp_set_long + mp_set_long_long + mp_set_u32 + mp_set_u64 + mp_set_ul + mp_set_ull + mp_shrink + mp_signed_rsh + mp_sqr + mp_sqrmod + mp_sqrt + mp_sqrtmod_prime + mp_sub + mp_sub_d + mp_submod + mp_to_radix + mp_to_sbin + mp_to_ubin + mp_ubin_size + mp_unpack + mp_xor + mp_zero diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath.h b/third_party/heimdal/lib/hcrypto/libtommath/tommath.h new file mode 100644 index 0000000..e87bb08 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath.h @@ -0,0 +1,781 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef BN_H_ +#define BN_H_ + +#include +#include +#include + +#ifdef LTM_NO_FILE +# warning LTM_NO_FILE has been deprecated, use MP_NO_FILE. +# define MP_NO_FILE +#endif + +#ifndef MP_NO_FILE +# include +#endif + +#ifdef MP_8BIT +# ifdef _MSC_VER +# pragma message("8-bit (MP_8BIT) support is deprecated and will be dropped completely in the next version.") +# else +# warning "8-bit (MP_8BIT) support is deprecated and will be dropped completely in the next version." +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */ +#if (defined(_MSC_VER) || defined(__LLP64__) || defined(__e2k__) || defined(__LCC__)) && !defined(MP_64BIT) +# define MP_32BIT +#endif + +/* detect 64-bit mode if possible */ +#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \ + defined(__s390x__) || defined(__arch64__) || defined(__aarch64__) || \ + defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) || \ + defined(__ia64) || defined(__ia64__) || defined(__itanium__) || defined(_M_IA64) || \ + defined(__LP64__) || defined(_LP64) || defined(__64BIT__) +# if !(defined(MP_64BIT) || defined(MP_32BIT) || defined(MP_16BIT) || defined(MP_8BIT)) +# if defined(__GNUC__) && !defined(__hppa) +/* we support 128bit integers only via: __attribute__((mode(TI))) */ +# define MP_64BIT +# else +/* otherwise we fall back to MP_32BIT even on 64bit platforms */ +# define MP_32BIT +# endif +# endif +#endif + +#ifdef MP_DIGIT_BIT +# error Defining MP_DIGIT_BIT is disallowed, use MP_8/16/31/32/64BIT +#endif + +/* some default configurations. + * + * A "mp_digit" must be able to hold MP_DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*MP_DIGIT_BIT + 1 bits + * + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] + */ + +#ifdef MP_8BIT +typedef uint8_t mp_digit; +typedef uint16_t private_mp_word; +# define MP_DIGIT_BIT 7 +#elif defined(MP_16BIT) +typedef uint16_t mp_digit; +typedef uint32_t private_mp_word; +# define MP_DIGIT_BIT 15 +#elif defined(MP_64BIT) +/* for GCC only on supported platforms */ +typedef uint64_t mp_digit; +#if defined(__GNUC__) +typedef unsigned long private_mp_word __attribute__((mode(TI))); +#endif +# define MP_DIGIT_BIT 60 +#else +typedef uint32_t mp_digit; +typedef uint64_t private_mp_word; +# ifdef MP_31BIT +/* + * This is an extension that uses 31-bit digits. + * Please be aware that not all functions support this size, especially s_mp_mul_digs_fast + * will be reduced to work on small numbers only: + * Up to 8 limbs, 248 bits instead of up to 512 limbs, 15872 bits with MP_28BIT. + */ +# define MP_DIGIT_BIT 31 +# else +/* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */ +# define MP_DIGIT_BIT 28 +# define MP_28BIT +# endif +#endif + +/* mp_word is a private type */ +#define mp_word MP_DEPRECATED_PRAGMA("mp_word has been made private") private_mp_word + +#define MP_SIZEOF_MP_DIGIT (MP_DEPRECATED_PRAGMA("MP_SIZEOF_MP_DIGIT has been deprecated, use sizeof (mp_digit)") sizeof (mp_digit)) + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)MP_DIGIT_BIT))-((mp_digit)1)) +#define MP_DIGIT_MAX MP_MASK + +/* Primality generation flags */ +#define MP_PRIME_BBS 0x0001 /* BBS style prime */ +#define MP_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */ +#define MP_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */ + +#define LTM_PRIME_BBS (MP_DEPRECATED_PRAGMA("LTM_PRIME_BBS has been deprecated, use MP_PRIME_BBS") MP_PRIME_BBS) +#define LTM_PRIME_SAFE (MP_DEPRECATED_PRAGMA("LTM_PRIME_SAFE has been deprecated, use MP_PRIME_SAFE") MP_PRIME_SAFE) +#define LTM_PRIME_2MSB_ON (MP_DEPRECATED_PRAGMA("LTM_PRIME_2MSB_ON has been deprecated, use MP_PRIME_2MSB_ON") MP_PRIME_2MSB_ON) + +#ifdef MP_USE_ENUMS +typedef enum { + MP_ZPOS = 0, /* positive */ + MP_NEG = 1 /* negative */ +} mp_sign; +typedef enum { + MP_LT = -1, /* less than */ + MP_EQ = 0, /* equal */ + MP_GT = 1 /* greater than */ +} mp_ord; +typedef enum { + MP_NO = 0, + MP_YES = 1 +} mp_bool; +typedef enum { + MP_OKAY = 0, /* no error */ + MP_ERR = -1, /* unknown error */ + MP_MEM = -2, /* out of mem */ + MP_VAL = -3, /* invalid input */ + MP_ITER = -4, /* maximum iterations reached */ + MP_BUF = -5 /* buffer overflow, supplied buffer too small */ +} mp_err; +typedef enum { + MP_LSB_FIRST = -1, + MP_MSB_FIRST = 1 +} mp_order; +typedef enum { + MP_LITTLE_ENDIAN = -1, + MP_NATIVE_ENDIAN = 0, + MP_BIG_ENDIAN = 1 +} mp_endian; +#else +typedef int mp_sign; +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ +typedef int mp_ord; +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ +typedef int mp_bool; +#define MP_YES 1 +#define MP_NO 0 +typedef int mp_err; +#define MP_OKAY 0 /* no error */ +#define MP_ERR -1 /* unknown error */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE (MP_DEPRECATED_PRAGMA("MP_RANGE has been deprecated in favor of MP_VAL") MP_VAL) +#define MP_ITER -4 /* maximum iterations reached */ +#define MP_BUF -5 /* buffer overflow, supplied buffer too small */ +typedef int mp_order; +#define MP_LSB_FIRST -1 +#define MP_MSB_FIRST 1 +typedef int mp_endian; +#define MP_LITTLE_ENDIAN -1 +#define MP_NATIVE_ENDIAN 0 +#define MP_BIG_ENDIAN 1 +#endif + +/* tunable cutoffs */ + +#ifndef MP_FIXED_CUTOFFS +extern int +KARATSUBA_MUL_CUTOFF, +KARATSUBA_SQR_CUTOFF, +TOOM_MUL_CUTOFF, +TOOM_SQR_CUTOFF; +#endif + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +/* default precision */ +#ifndef MP_PREC +# ifndef MP_LOW_MEM +# define PRIVATE_MP_PREC 32 /* default digits of precision */ +# elif defined(MP_8BIT) +# define PRIVATE_MP_PREC 16 /* default digits of precision */ +# else +# define PRIVATE_MP_PREC 8 /* default digits of precision */ +# endif +# define MP_PREC (MP_DEPRECATED_PRAGMA("MP_PREC is an internal macro") PRIVATE_MP_PREC) +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define PRIVATE_MP_WARRAY (int)(1uLL << (((CHAR_BIT * sizeof(private_mp_word)) - (2 * MP_DIGIT_BIT)) + 1)) +#define MP_WARRAY (MP_DEPRECATED_PRAGMA("MP_WARRAY is an internal macro") PRIVATE_MP_WARRAY) + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define MP_NULL_TERMINATED __attribute__((sentinel)) +#else +# define MP_NULL_TERMINATED +#endif + +/* + * MP_WUR - warn unused result + * --------------------------- + * + * The result of functions annotated with MP_WUR must be + * checked and cannot be ignored. + * + * Most functions in libtommath return an error code. + * This error code must be checked in order to prevent crashes or invalid + * results. + * + * If you still want to avoid the error checks for quick and dirty programs + * without robustness guarantees, you can `#define MP_WUR` before including + * tommath.h, disabling the warnings. + */ +#ifndef MP_WUR +# if defined(__GNUC__) && __GNUC__ >= 4 +# define MP_WUR __attribute__((warn_unused_result)) +# else +# define MP_WUR +# endif +#endif + +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 405) +# define MP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x))) +# define PRIVATE_MP_DEPRECATED_PRAGMA(s) _Pragma(#s) +# define MP_DEPRECATED_PRAGMA(s) PRIVATE_MP_DEPRECATED_PRAGMA(GCC warning s) +#elif defined(_MSC_VER) && _MSC_VER >= 1500 +# define MP_DEPRECATED(x) __declspec(deprecated("replaced by " #x)) +# define MP_DEPRECATED_PRAGMA(s) __pragma(message(s)) +#else +# define MP_DEPRECATED(s) +# define MP_DEPRECATED_PRAGMA(s) +#endif + +#define DIGIT_BIT (MP_DEPRECATED_PRAGMA("DIGIT_BIT macro is deprecated, MP_DIGIT_BIT instead") MP_DIGIT_BIT) +#define USED(m) (MP_DEPRECATED_PRAGMA("USED macro is deprecated, use z->used instead") (m)->used) +#define DIGIT(m, k) (MP_DEPRECATED_PRAGMA("DIGIT macro is deprecated, use z->dp instead") (m)->dp[(k)]) +#define SIGN(m) (MP_DEPRECATED_PRAGMA("SIGN macro is deprecated, use z->sign instead") (m)->sign) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc; + mp_sign sign; + mp_digit *dp; +} mp_int; + +/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */ +typedef int private_mp_prime_callback(unsigned char *dst, int len, void *dat); +typedef private_mp_prime_callback MP_DEPRECATED(mp_rand_source) ltm_prime_callback; + +/* error code to char* string */ +const char *mp_error_to_string(mp_err code) MP_WUR; + +/* ---> init and deinit bignum functions <--- */ +/* init a bignum */ +mp_err mp_init(mp_int *a) MP_WUR; + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* init a null terminated series of arguments */ +mp_err mp_init_multi(mp_int *mp, ...) MP_NULL_TERMINATED MP_WUR; + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...) MP_NULL_TERMINATED; + +/* exchange two ints */ +void mp_exch(mp_int *a, mp_int *b); + +/* shrink ram required for a bignum */ +mp_err mp_shrink(mp_int *a) MP_WUR; + +/* grow an int to a given size */ +mp_err mp_grow(mp_int *a, int size) MP_WUR; + +/* init to a given number of digits */ +mp_err mp_init_size(mp_int *a, int size) MP_WUR; + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +mp_bool mp_iseven(const mp_int *a) MP_WUR; +mp_bool mp_isodd(const mp_int *a) MP_WUR; +#define mp_isneg(a) (((a)->sign != MP_ZPOS) ? MP_YES : MP_NO) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* get and set doubles */ +double mp_get_double(const mp_int *a) MP_WUR; +mp_err mp_set_double(mp_int *a, double b) MP_WUR; + +/* get integer, set integer and init with integer (int32_t) */ +int32_t mp_get_i32(const mp_int *a) MP_WUR; +void mp_set_i32(mp_int *a, int32_t b); +mp_err mp_init_i32(mp_int *a, int32_t b) MP_WUR; + +/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint32_t) */ +#define mp_get_u32(a) ((uint32_t)mp_get_i32(a)) +void mp_set_u32(mp_int *a, uint32_t b); +mp_err mp_init_u32(mp_int *a, uint32_t b) MP_WUR; + +/* get integer, set integer and init with integer (int64_t) */ +int64_t mp_get_i64(const mp_int *a) MP_WUR; +void mp_set_i64(mp_int *a, int64_t b); +mp_err mp_init_i64(mp_int *a, int64_t b) MP_WUR; + +/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint64_t) */ +#define mp_get_u64(a) ((uint64_t)mp_get_i64(a)) +void mp_set_u64(mp_int *a, uint64_t b); +mp_err mp_init_u64(mp_int *a, uint64_t b) MP_WUR; + +/* get magnitude */ +uint32_t mp_get_mag_u32(const mp_int *a) MP_WUR; +uint64_t mp_get_mag_u64(const mp_int *a) MP_WUR; +unsigned long mp_get_mag_ul(const mp_int *a) MP_WUR; +unsigned long long mp_get_mag_ull(const mp_int *a) MP_WUR; + +/* get integer, set integer (long) */ +long mp_get_l(const mp_int *a) MP_WUR; +void mp_set_l(mp_int *a, long b); +mp_err mp_init_l(mp_int *a, long b) MP_WUR; + +/* get integer, set integer (unsigned long) */ +#define mp_get_ul(a) ((unsigned long)mp_get_l(a)) +void mp_set_ul(mp_int *a, unsigned long b); +mp_err mp_init_ul(mp_int *a, unsigned long b) MP_WUR; + +/* get integer, set integer (long long) */ +long long mp_get_ll(const mp_int *a) MP_WUR; +void mp_set_ll(mp_int *a, long long b); +mp_err mp_init_ll(mp_int *a, long long b) MP_WUR; + +/* get integer, set integer (unsigned long long) */ +#define mp_get_ull(a) ((unsigned long long)mp_get_ll(a)) +void mp_set_ull(mp_int *a, unsigned long long b); +mp_err mp_init_ull(mp_int *a, unsigned long long b) MP_WUR; + +/* set to single unsigned digit, up to MP_DIGIT_MAX */ +void mp_set(mp_int *a, mp_digit b); +mp_err mp_init_set(mp_int *a, mp_digit b) MP_WUR; + +/* get integer, set integer and init with integer (deprecated) */ +MP_DEPRECATED(mp_get_mag_u32/mp_get_u32) unsigned long mp_get_int(const mp_int *a) MP_WUR; +MP_DEPRECATED(mp_get_mag_ul/mp_get_ul) unsigned long mp_get_long(const mp_int *a) MP_WUR; +MP_DEPRECATED(mp_get_mag_ull/mp_get_ull) unsigned long long mp_get_long_long(const mp_int *a) MP_WUR; +MP_DEPRECATED(mp_set_ul) mp_err mp_set_int(mp_int *a, unsigned long b); +MP_DEPRECATED(mp_set_ul) mp_err mp_set_long(mp_int *a, unsigned long b); +MP_DEPRECATED(mp_set_ull) mp_err mp_set_long_long(mp_int *a, unsigned long long b); +MP_DEPRECATED(mp_init_ul) mp_err mp_init_set_int(mp_int *a, unsigned long b) MP_WUR; + +/* copy, b = a */ +mp_err mp_copy(const mp_int *a, mp_int *b) MP_WUR; + +/* inits and copies, a = b */ +mp_err mp_init_copy(mp_int *a, const mp_int *b) MP_WUR; + +/* trim unused digits */ +void mp_clamp(mp_int *a); + + +/* export binary data */ +MP_DEPRECATED(mp_pack) mp_err mp_export(void *rop, size_t *countp, int order, size_t size, + int endian, size_t nails, const mp_int *op) MP_WUR; + +/* import binary data */ +MP_DEPRECATED(mp_unpack) mp_err mp_import(mp_int *rop, size_t count, int order, + size_t size, int endian, size_t nails, + const void *op) MP_WUR; + +/* unpack binary data */ +mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, mp_endian endian, + size_t nails, const void *op) MP_WUR; + +/* pack binary data */ +size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) MP_WUR; +mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size, + mp_endian endian, size_t nails, const mp_int *op) MP_WUR; + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +void mp_rshd(mp_int *a, int b); + +/* left shift by "b" digits */ +mp_err mp_lshd(mp_int *a, int b) MP_WUR; + +/* c = a / 2**b, implemented as c = a >> b */ +mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) MP_WUR; + +/* b = a/2 */ +mp_err mp_div_2(const mp_int *a, mp_int *b) MP_WUR; + +/* a/3 => 3c + d == a */ +mp_err mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) MP_WUR; + +/* c = a * 2**b, implemented as c = a << b */ +mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) MP_WUR; + +/* b = a*2 */ +mp_err mp_mul_2(const mp_int *a, mp_int *b) MP_WUR; + +/* c = a mod 2**b */ +mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) MP_WUR; + +/* computes a = 2**b */ +mp_err mp_2expt(mp_int *a, int b) MP_WUR; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(const mp_int *a) MP_WUR; + +/* I Love Earth! */ + +/* makes a pseudo-random mp_int of a given size */ +mp_err mp_rand(mp_int *a, int digits) MP_WUR; +/* makes a pseudo-random small int of a given size */ +MP_DEPRECATED(mp_rand) mp_err mp_rand_digit(mp_digit *r) MP_WUR; +/* use custom random data source instead of source provided the platform */ +void mp_rand_source(mp_err(*source)(void *out, size_t size)); + +#ifdef MP_PRNG_ENABLE_LTM_RNG +# warning MP_PRNG_ENABLE_LTM_RNG has been deprecated, use mp_rand_source instead. +/* A last resort to provide random data on systems without any of the other + * implemented ways to gather entropy. + * It is compatible with `rng_get_bytes()` from libtomcrypt so you could + * provide that one and then set `ltm_rng = rng_get_bytes;` */ +extern unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void)); +extern void (*ltm_rng_callback)(void); +#endif + +/* ---> binary operations <--- */ + +/* Checks the bit at position b and returns MP_YES + * if the bit is 1, MP_NO if it is 0 and MP_VAL + * in case of error + */ +MP_DEPRECATED(s_mp_get_bit) int mp_get_bit(const mp_int *a, int b) MP_WUR; + +/* c = a XOR b (two complement) */ +MP_DEPRECATED(mp_xor) mp_err mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = a OR b (two complement) */ +MP_DEPRECATED(mp_or) mp_err mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = a AND b (two complement) */ +MP_DEPRECATED(mp_and) mp_err mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* b = ~a (bitwise not, two complement) */ +mp_err mp_complement(const mp_int *a, mp_int *b) MP_WUR; + +/* right shift with sign extension */ +MP_DEPRECATED(mp_signed_rsh) mp_err mp_tc_div_2d(const mp_int *a, int b, mp_int *c) MP_WUR; +mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) MP_WUR; + +/* ---> Basic arithmetic <--- */ + +/* b = -a */ +mp_err mp_neg(const mp_int *a, mp_int *b) MP_WUR; + +/* b = |a| */ +mp_err mp_abs(const mp_int *a, mp_int *b) MP_WUR; + +/* compare a to b */ +mp_ord mp_cmp(const mp_int *a, const mp_int *b) MP_WUR; + +/* compare |a| to |b| */ +mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) MP_WUR; + +/* c = a + b */ +mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = a - b */ +mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = a * b */ +mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* b = a*a */ +mp_err mp_sqr(const mp_int *a, mp_int *b) MP_WUR; + +/* a/b => cb + d == a */ +mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) MP_WUR; + +/* c = a mod b, 0 <= c < b */ +mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* Increment "a" by one like "a++". Changes input! */ +mp_err mp_incr(mp_int *a) MP_WUR; + +/* Decrement "a" by one like "a--". Changes input! */ +mp_err mp_decr(mp_int *a) MP_WUR; + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +mp_ord mp_cmp_d(const mp_int *a, mp_digit b) MP_WUR; + +/* c = a + b */ +mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR; + +/* c = a - b */ +mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR; + +/* c = a * b */ +mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR; + +/* a/b => cb + d == a */ +mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) MP_WUR; + +/* c = a mod b, 0 <= c < b */ +mp_err mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c) MP_WUR; + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR; + +/* d = a - b (mod c) */ +mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR; + +/* d = a * b (mod c) */ +mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR; + +/* c = a * a (mod b) */ +mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = 1/a (mod b) */ +mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* c = (a, b) */ +mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* produces value such that U1*a + U2*b = U3 */ +mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) MP_WUR; + +/* c = [a, b] or (a*b)/(a, b) */ +mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; + +/* finds one of the b'th root of a, such that |c|**b <= |a| + * + * returns error if a < 0 and b is even + */ +mp_err mp_root_u32(const mp_int *a, uint32_t b, mp_int *c) MP_WUR; +MP_DEPRECATED(mp_root_u32) mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c) MP_WUR; +MP_DEPRECATED(mp_root_u32) mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) MP_WUR; + +/* special sqrt algo */ +mp_err mp_sqrt(const mp_int *arg, mp_int *ret) MP_WUR; + +/* special sqrt (mod prime) */ +mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret) MP_WUR; + +/* is number a square? */ +mp_err mp_is_square(const mp_int *arg, mp_bool *ret) MP_WUR; + +/* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +MP_DEPRECATED(mp_kronecker) mp_err mp_jacobi(const mp_int *a, const mp_int *n, int *c) MP_WUR; + +/* computes the Kronecker symbol c = (a | p) (like jacobi() but with {a,p} in Z */ +mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) MP_WUR; + +/* used to setup the Barrett reduction for a given modulus b */ +mp_err mp_reduce_setup(mp_int *a, const mp_int *b) MP_WUR; + +/* Barrett Reduction, computes a (mod b) with a precomputed value c + * + * Assumes that 0 < x <= m*m, note if 0 > x > -(m*m) then you can merely + * compute the reduction as -1 * mp_reduce(mp_abs(x)) [pseudo code]. + */ +mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) MP_WUR; + +/* setups the montgomery reduction */ +mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) MP_WUR; + +/* computes a = B**n mod b without division or multiplication useful for + * normalizing numbers in a Montgomery system. + */ +mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) MP_WUR; + +/* computes x/R == x (mod N) via Montgomery Reduction */ +mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR; + +/* returns 1 if a is a valid DR modulus */ +mp_bool mp_dr_is_modulus(const mp_int *a) MP_WUR; + +/* sets the value of "d" required for mp_dr_reduce */ +void mp_dr_setup(const mp_int *a, mp_digit *d); + +/* reduces a modulo n using the Diminished Radix method */ +mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) MP_WUR; + +/* returns true if a can be reduced with mp_reduce_2k */ +mp_bool mp_reduce_is_2k(const mp_int *a) MP_WUR; + +/* determines k value for 2k reduction */ +mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) MP_WUR; + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) MP_WUR; + +/* returns true if a can be reduced with mp_reduce_2k_l */ +mp_bool mp_reduce_is_2k_l(const mp_int *a) MP_WUR; + +/* determines k value for 2k reduction */ +mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) MP_WUR; + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) MP_WUR; + +/* Y = G**X (mod P) */ +mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) MP_WUR; + +/* ---> Primes <--- */ + +/* number of primes */ +#ifdef MP_8BIT +# define PRIVATE_MP_PRIME_TAB_SIZE 31 +#else +# define PRIVATE_MP_PRIME_TAB_SIZE 256 +#endif +#define PRIME_SIZE (MP_DEPRECATED_PRAGMA("PRIME_SIZE has been made internal") PRIVATE_MP_PRIME_TAB_SIZE) + +/* table of first PRIME_SIZE primes */ +MP_DEPRECATED(internal) extern const mp_digit ltm_prime_tab[PRIVATE_MP_PRIME_TAB_SIZE]; + +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ +MP_DEPRECATED(mp_prime_is_prime) mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result) MP_WUR; + +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, mp_bool *result) MP_WUR; + +/* performs one Miller-Rabin test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, mp_bool *result) MP_WUR; + +/* This gives [for a given bit size] the number of trials required + * such that Miller-Rabin gives a prob of failure lower than 2^-96 + */ +int mp_prime_rabin_miller_trials(int size) MP_WUR; + +/* performs one strong Lucas-Selfridge test of "a". + * Sets result to 0 if composite or 1 if probable prime + */ +mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, mp_bool *result) MP_WUR; + +/* performs one Frobenius test of "a" as described by Paul Underwood. + * Sets result to 0 if composite or 1 if probable prime + */ +mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result) MP_WUR; + +/* performs t random rounds of Miller-Rabin on "a" additional to + * bases 2 and 3. Also performs an initial sieve of trial + * division. Determines if "a" is prime with probability + * of error no more than (1/4)**t. + * Both a strong Lucas-Selfridge to complete the BPSW test + * and a separate Frobenius test are available at compile time. + * With t<0 a deterministic test is run for primes up to + * 318665857834031151167461. With t<13 (abs(t)-13) additional + * tests with sequential small primes are run starting at 43. + * Is Fips 186.4 compliant if called with t as computed by + * mp_prime_rabin_miller_trials(); + * + * Sets result to 1 if probably prime, 0 otherwise + */ +mp_err mp_prime_is_prime(const mp_int *a, int t, mp_bool *result) MP_WUR; + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +mp_err mp_prime_next_prime(mp_int *a, int t, int bbs_style) MP_WUR; + +/* makes a truly random prime of a given size (bytes), + * call with bbs = 1 if you want it to be congruent to 3 mod 4 + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + * The prime generated will be larger than 2^(8*size). + */ +#define mp_prime_random(a, t, size, bbs, cb, dat) (MP_DEPRECATED_PRAGMA("mp_prime_random has been deprecated, use mp_prime_rand instead") mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?MP_PRIME_BBS:0, cb, dat)) + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * MP_PRIME_BBS - make prime congruent to 3 mod 4 + * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS) + * MP_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ +MP_DEPRECATED(mp_prime_rand) mp_err mp_prime_random_ex(mp_int *a, int t, int size, int flags, + private_mp_prime_callback cb, void *dat) MP_WUR; +mp_err mp_prime_rand(mp_int *a, int t, int size, int flags) MP_WUR; + +/* Integer logarithm to integer base */ +mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c) MP_WUR; + +/* c = a**b */ +mp_err mp_expt_u32(const mp_int *a, uint32_t b, mp_int *c) MP_WUR; +MP_DEPRECATED(mp_expt_u32) mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR; +MP_DEPRECATED(mp_expt_u32) mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) MP_WUR; + +/* ---> radix conversion <--- */ +int mp_count_bits(const mp_int *a) MP_WUR; + + +MP_DEPRECATED(mp_ubin_size) int mp_unsigned_bin_size(const mp_int *a) MP_WUR; +MP_DEPRECATED(mp_from_ubin) mp_err mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c) MP_WUR; +MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin(const mp_int *a, unsigned char *b) MP_WUR; +MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) MP_WUR; + +MP_DEPRECATED(mp_sbin_size) int mp_signed_bin_size(const mp_int *a) MP_WUR; +MP_DEPRECATED(mp_from_sbin) mp_err mp_read_signed_bin(mp_int *a, const unsigned char *b, int c) MP_WUR; +MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin(const mp_int *a, unsigned char *b) MP_WUR; +MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) MP_WUR; + +size_t mp_ubin_size(const mp_int *a) MP_WUR; +mp_err mp_from_ubin(mp_int *a, const unsigned char *buf, size_t size) MP_WUR; +mp_err mp_to_ubin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) MP_WUR; + +size_t mp_sbin_size(const mp_int *a) MP_WUR; +mp_err mp_from_sbin(mp_int *a, const unsigned char *buf, size_t size) MP_WUR; +mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) MP_WUR; + +mp_err mp_read_radix(mp_int *a, const char *str, int radix) MP_WUR; +MP_DEPRECATED(mp_to_radix) mp_err mp_toradix(const mp_int *a, char *str, int radix) MP_WUR; +MP_DEPRECATED(mp_to_radix) mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen) MP_WUR; +mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) MP_WUR; +mp_err mp_radix_size(const mp_int *a, int radix, int *size) MP_WUR; + +#ifndef MP_NO_FILE +mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR; +mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) MP_WUR; +#endif + +#define mp_read_raw(mp, str, len) (MP_DEPRECATED_PRAGMA("replaced by mp_read_signed_bin") mp_read_signed_bin((mp), (str), (len))) +#define mp_raw_size(mp) (MP_DEPRECATED_PRAGMA("replaced by mp_signed_bin_size") mp_signed_bin_size(mp)) +#define mp_toraw(mp, str) (MP_DEPRECATED_PRAGMA("replaced by mp_to_signed_bin") mp_to_signed_bin((mp), (str))) +#define mp_read_mag(mp, str, len) (MP_DEPRECATED_PRAGMA("replaced by mp_read_unsigned_bin") mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) (MP_DEPRECATED_PRAGMA("replaced by mp_unsigned_bin_size") mp_unsigned_bin_size(mp)) +#define mp_tomag(mp, str) (MP_DEPRECATED_PRAGMA("replaced by mp_to_unsigned_bin") mp_to_unsigned_bin((mp), (str))) + +#define mp_tobinary(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_binary") mp_toradix((M), (S), 2)) +#define mp_tooctal(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_octal") mp_toradix((M), (S), 8)) +#define mp_todecimal(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_decimal") mp_toradix((M), (S), 10)) +#define mp_tohex(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_hex") mp_toradix((M), (S), 16)) + +#define mp_to_binary(M, S, N) mp_to_radix((M), (S), (N), NULL, 2) +#define mp_to_octal(M, S, N) mp_to_radix((M), (S), (N), NULL, 8) +#define mp_to_decimal(M, S, N) mp_to_radix((M), (S), (N), NULL, 10) +#define mp_to_hex(M, S, N) mp_to_radix((M), (S), (N), NULL, 16) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath_class.h b/third_party/heimdal/lib/hcrypto/libtommath/tommath_class.h new file mode 100644 index 0000000..52ba585 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath_class.h @@ -0,0 +1,1319 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#if !(defined(LTM1) && defined(LTM2) && defined(LTM3)) +#define LTM_INSIDE +#if defined(LTM2) +# define LTM3 +#endif +#if defined(LTM1) +# define LTM2 +#endif +#define LTM1 +#if defined(LTM_ALL) +# define BN_CUTOFFS_C +# define BN_DEPRECATED_C +# define BN_MP_2EXPT_C +# define BN_MP_ABS_C +# define BN_MP_ADD_C +# define BN_MP_ADD_D_C +# define BN_MP_ADDMOD_C +# define BN_MP_AND_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_CMP_MAG_C +# define BN_MP_CNT_LSB_C +# define BN_MP_COMPLEMENT_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DECR_C +# define BN_MP_DIV_C +# define BN_MP_DIV_2_C +# define BN_MP_DIV_2D_C +# define BN_MP_DIV_3_C +# define BN_MP_DIV_D_C +# define BN_MP_DR_IS_MODULUS_C +# define BN_MP_DR_REDUCE_C +# define BN_MP_DR_SETUP_C +# define BN_MP_ERROR_TO_STRING_C +# define BN_MP_EXCH_C +# define BN_MP_EXPT_U32_C +# define BN_MP_EXPTMOD_C +# define BN_MP_EXTEUCLID_C +# define BN_MP_FREAD_C +# define BN_MP_FROM_SBIN_C +# define BN_MP_FROM_UBIN_C +# define BN_MP_FWRITE_C +# define BN_MP_GCD_C +# define BN_MP_GET_DOUBLE_C +# define BN_MP_GET_I32_C +# define BN_MP_GET_I64_C +# define BN_MP_GET_L_C +# define BN_MP_GET_LL_C +# define BN_MP_GET_MAG_U32_C +# define BN_MP_GET_MAG_U64_C +# define BN_MP_GET_MAG_UL_C +# define BN_MP_GET_MAG_ULL_C +# define BN_MP_GROW_C +# define BN_MP_INCR_C +# define BN_MP_INIT_C +# define BN_MP_INIT_COPY_C +# define BN_MP_INIT_I32_C +# define BN_MP_INIT_I64_C +# define BN_MP_INIT_L_C +# define BN_MP_INIT_LL_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INIT_SET_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_INIT_U32_C +# define BN_MP_INIT_U64_C +# define BN_MP_INIT_UL_C +# define BN_MP_INIT_ULL_C +# define BN_MP_INVMOD_C +# define BN_MP_IS_SQUARE_C +# define BN_MP_ISEVEN_C +# define BN_MP_ISODD_C +# define BN_MP_KRONECKER_C +# define BN_MP_LCM_C +# define BN_MP_LOG_U32_C +# define BN_MP_LSHD_C +# define BN_MP_MOD_C +# define BN_MP_MOD_2D_C +# define BN_MP_MOD_D_C +# define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +# define BN_MP_MONTGOMERY_REDUCE_C +# define BN_MP_MONTGOMERY_SETUP_C +# define BN_MP_MUL_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_2D_C +# define BN_MP_MUL_D_C +# define BN_MP_MULMOD_C +# define BN_MP_NEG_C +# define BN_MP_OR_C +# define BN_MP_PACK_C +# define BN_MP_PACK_COUNT_C +# define BN_MP_PRIME_FERMAT_C +# define BN_MP_PRIME_FROBENIUS_UNDERWOOD_C +# define BN_MP_PRIME_IS_PRIME_C +# define BN_MP_PRIME_MILLER_RABIN_C +# define BN_MP_PRIME_NEXT_PRIME_C +# define BN_MP_PRIME_RABIN_MILLER_TRIALS_C +# define BN_MP_PRIME_RAND_C +# define BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C +# define BN_MP_RADIX_SIZE_C +# define BN_MP_RADIX_SMAP_C +# define BN_MP_RAND_C +# define BN_MP_READ_RADIX_C +# define BN_MP_REDUCE_C +# define BN_MP_REDUCE_2K_C +# define BN_MP_REDUCE_2K_L_C +# define BN_MP_REDUCE_2K_SETUP_C +# define BN_MP_REDUCE_2K_SETUP_L_C +# define BN_MP_REDUCE_IS_2K_C +# define BN_MP_REDUCE_IS_2K_L_C +# define BN_MP_REDUCE_SETUP_C +# define BN_MP_ROOT_U32_C +# define BN_MP_RSHD_C +# define BN_MP_SBIN_SIZE_C +# define BN_MP_SET_C +# define BN_MP_SET_DOUBLE_C +# define BN_MP_SET_I32_C +# define BN_MP_SET_I64_C +# define BN_MP_SET_L_C +# define BN_MP_SET_LL_C +# define BN_MP_SET_U32_C +# define BN_MP_SET_U64_C +# define BN_MP_SET_UL_C +# define BN_MP_SET_ULL_C +# define BN_MP_SHRINK_C +# define BN_MP_SIGNED_RSH_C +# define BN_MP_SQR_C +# define BN_MP_SQRMOD_C +# define BN_MP_SQRT_C +# define BN_MP_SQRTMOD_PRIME_C +# define BN_MP_SUB_C +# define BN_MP_SUB_D_C +# define BN_MP_SUBMOD_C +# define BN_MP_TO_RADIX_C +# define BN_MP_TO_SBIN_C +# define BN_MP_TO_UBIN_C +# define BN_MP_UBIN_SIZE_C +# define BN_MP_UNPACK_C +# define BN_MP_XOR_C +# define BN_MP_ZERO_C +# define BN_PRIME_TAB_C +# define BN_S_MP_ADD_C +# define BN_S_MP_BALANCE_MUL_C +# define BN_S_MP_EXPTMOD_C +# define BN_S_MP_EXPTMOD_FAST_C +# define BN_S_MP_GET_BIT_C +# define BN_S_MP_INVMOD_FAST_C +# define BN_S_MP_INVMOD_SLOW_C +# define BN_S_MP_KARATSUBA_MUL_C +# define BN_S_MP_KARATSUBA_SQR_C +# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C +# define BN_S_MP_MUL_DIGS_C +# define BN_S_MP_MUL_DIGS_FAST_C +# define BN_S_MP_MUL_HIGH_DIGS_C +# define BN_S_MP_MUL_HIGH_DIGS_FAST_C +# define BN_S_MP_PRIME_IS_DIVISIBLE_C +# define BN_S_MP_RAND_JENKINS_C +# define BN_S_MP_RAND_PLATFORM_C +# define BN_S_MP_REVERSE_C +# define BN_S_MP_SQR_C +# define BN_S_MP_SQR_FAST_C +# define BN_S_MP_SUB_C +# define BN_S_MP_TOOM_MUL_C +# define BN_S_MP_TOOM_SQR_C +#endif +#endif +#if defined(BN_CUTOFFS_C) +#endif + +#if defined(BN_DEPRECATED_C) +# define BN_FAST_MP_INVMOD_C +# define BN_FAST_MP_MONTGOMERY_REDUCE_C +# define BN_FAST_S_MP_MUL_DIGS_C +# define BN_FAST_S_MP_MUL_HIGH_DIGS_C +# define BN_FAST_S_MP_SQR_C +# define BN_MP_AND_C +# define BN_MP_BALANCE_MUL_C +# define BN_MP_CMP_D_C +# define BN_MP_EXPORT_C +# define BN_MP_EXPTMOD_FAST_C +# define BN_MP_EXPT_D_C +# define BN_MP_EXPT_D_EX_C +# define BN_MP_EXPT_U32_C +# define BN_MP_FROM_SBIN_C +# define BN_MP_FROM_UBIN_C +# define BN_MP_GET_BIT_C +# define BN_MP_GET_INT_C +# define BN_MP_GET_LONG_C +# define BN_MP_GET_LONG_LONG_C +# define BN_MP_GET_MAG_U32_C +# define BN_MP_GET_MAG_ULL_C +# define BN_MP_GET_MAG_UL_C +# define BN_MP_IMPORT_C +# define BN_MP_INIT_SET_INT_C +# define BN_MP_INIT_U32_C +# define BN_MP_INVMOD_SLOW_C +# define BN_MP_JACOBI_C +# define BN_MP_KARATSUBA_MUL_C +# define BN_MP_KARATSUBA_SQR_C +# define BN_MP_KRONECKER_C +# define BN_MP_N_ROOT_C +# define BN_MP_N_ROOT_EX_C +# define BN_MP_OR_C +# define BN_MP_PACK_C +# define BN_MP_PRIME_IS_DIVISIBLE_C +# define BN_MP_PRIME_RANDOM_EX_C +# define BN_MP_RAND_DIGIT_C +# define BN_MP_READ_SIGNED_BIN_C +# define BN_MP_READ_UNSIGNED_BIN_C +# define BN_MP_ROOT_U32_C +# define BN_MP_SBIN_SIZE_C +# define BN_MP_SET_INT_C +# define BN_MP_SET_LONG_C +# define BN_MP_SET_LONG_LONG_C +# define BN_MP_SET_U32_C +# define BN_MP_SET_U64_C +# define BN_MP_SIGNED_BIN_SIZE_C +# define BN_MP_SIGNED_RSH_C +# define BN_MP_TC_AND_C +# define BN_MP_TC_DIV_2D_C +# define BN_MP_TC_OR_C +# define BN_MP_TC_XOR_C +# define BN_MP_TOOM_MUL_C +# define BN_MP_TOOM_SQR_C +# define BN_MP_TORADIX_C +# define BN_MP_TORADIX_N_C +# define BN_MP_TO_RADIX_C +# define BN_MP_TO_SBIN_C +# define BN_MP_TO_SIGNED_BIN_C +# define BN_MP_TO_SIGNED_BIN_N_C +# define BN_MP_TO_UBIN_C +# define BN_MP_TO_UNSIGNED_BIN_C +# define BN_MP_TO_UNSIGNED_BIN_N_C +# define BN_MP_UBIN_SIZE_C +# define BN_MP_UNPACK_C +# define BN_MP_UNSIGNED_BIN_SIZE_C +# define BN_MP_XOR_C +# define BN_S_MP_BALANCE_MUL_C +# define BN_S_MP_EXPTMOD_FAST_C +# define BN_S_MP_GET_BIT_C +# define BN_S_MP_INVMOD_FAST_C +# define BN_S_MP_INVMOD_SLOW_C +# define BN_S_MP_KARATSUBA_MUL_C +# define BN_S_MP_KARATSUBA_SQR_C +# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C +# define BN_S_MP_MUL_DIGS_FAST_C +# define BN_S_MP_MUL_HIGH_DIGS_FAST_C +# define BN_S_MP_PRIME_IS_DIVISIBLE_C +# define BN_S_MP_PRIME_RANDOM_EX_C +# define BN_S_MP_RAND_SOURCE_C +# define BN_S_MP_REVERSE_C +# define BN_S_MP_SQR_FAST_C +# define BN_S_MP_TOOM_MUL_C +# define BN_S_MP_TOOM_SQR_C +#endif + +#if defined(BN_MP_2EXPT_C) +# define BN_MP_GROW_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_ABS_C) +# define BN_MP_COPY_C +#endif + +#if defined(BN_MP_ADD_C) +# define BN_MP_CMP_MAG_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_ADD_D_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_ADDMOD_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_C +# define BN_MP_INIT_C +# define BN_MP_MOD_C +#endif + +#if defined(BN_MP_AND_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_CLAMP_C) +#endif + +#if defined(BN_MP_CLEAR_C) +#endif + +#if defined(BN_MP_CLEAR_MULTI_C) +# define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_CMP_C) +# define BN_MP_CMP_MAG_C +#endif + +#if defined(BN_MP_CMP_D_C) +#endif + +#if defined(BN_MP_CMP_MAG_C) +#endif + +#if defined(BN_MP_CNT_LSB_C) +#endif + +#if defined(BN_MP_COMPLEMENT_C) +# define BN_MP_NEG_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_COPY_C) +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_COUNT_BITS_C) +#endif + +#if defined(BN_MP_DECR_C) +# define BN_MP_INCR_C +# define BN_MP_SET_C +# define BN_MP_SUB_D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_DIV_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_CMP_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_2D_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_C +# define BN_MP_INIT_COPY_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_MUL_2D_C +# define BN_MP_MUL_D_C +# define BN_MP_RSHD_C +# define BN_MP_SUB_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_DIV_2_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_DIV_2D_C) +# define BN_MP_CLAMP_C +# define BN_MP_COPY_C +# define BN_MP_MOD_2D_C +# define BN_MP_RSHD_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_DIV_3_C) +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +#endif + +#if defined(BN_MP_DIV_D_C) +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_COPY_C +# define BN_MP_DIV_2D_C +# define BN_MP_DIV_3_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +#endif + +#if defined(BN_MP_DR_IS_MODULUS_C) +#endif + +#if defined(BN_MP_DR_REDUCE_C) +# define BN_MP_CLAMP_C +# define BN_MP_CMP_MAG_C +# define BN_MP_GROW_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_DR_SETUP_C) +#endif + +#if defined(BN_MP_ERROR_TO_STRING_C) +#endif + +#if defined(BN_MP_EXCH_C) +#endif + +#if defined(BN_MP_EXPT_U32_C) +# define BN_MP_CLEAR_C +# define BN_MP_INIT_COPY_C +# define BN_MP_MUL_C +# define BN_MP_SET_C +# define BN_MP_SQR_C +#endif + +#if defined(BN_MP_EXPTMOD_C) +# define BN_MP_ABS_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_DR_IS_MODULUS_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INVMOD_C +# define BN_MP_REDUCE_IS_2K_C +# define BN_MP_REDUCE_IS_2K_L_C +# define BN_S_MP_EXPTMOD_C +# define BN_S_MP_EXPTMOD_FAST_C +#endif + +#if defined(BN_MP_EXTEUCLID_C) +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_COPY_C +# define BN_MP_DIV_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MUL_C +# define BN_MP_NEG_C +# define BN_MP_SET_C +# define BN_MP_SUB_C +#endif + +#if defined(BN_MP_FREAD_C) +# define BN_MP_ADD_D_C +# define BN_MP_MUL_D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_FROM_SBIN_C) +# define BN_MP_FROM_UBIN_C +#endif + +#if defined(BN_MP_FROM_UBIN_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +# define BN_MP_MUL_2D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_FWRITE_C) +# define BN_MP_RADIX_SIZE_C +# define BN_MP_TO_RADIX_C +#endif + +#if defined(BN_MP_GCD_C) +# define BN_MP_ABS_C +# define BN_MP_CLEAR_C +# define BN_MP_CMP_MAG_C +# define BN_MP_CNT_LSB_C +# define BN_MP_DIV_2D_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_COPY_C +# define BN_MP_MUL_2D_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_GET_DOUBLE_C) +#endif + +#if defined(BN_MP_GET_I32_C) +# define BN_MP_GET_MAG_U32_C +#endif + +#if defined(BN_MP_GET_I64_C) +# define BN_MP_GET_MAG_U64_C +#endif + +#if defined(BN_MP_GET_L_C) +# define BN_MP_GET_MAG_UL_C +#endif + +#if defined(BN_MP_GET_LL_C) +# define BN_MP_GET_MAG_ULL_C +#endif + +#if defined(BN_MP_GET_MAG_U32_C) +#endif + +#if defined(BN_MP_GET_MAG_U64_C) +#endif + +#if defined(BN_MP_GET_MAG_UL_C) +#endif + +#if defined(BN_MP_GET_MAG_ULL_C) +#endif + +#if defined(BN_MP_GROW_C) +#endif + +#if defined(BN_MP_INCR_C) +# define BN_MP_ADD_D_C +# define BN_MP_DECR_C +# define BN_MP_SET_C +#endif + +#if defined(BN_MP_INIT_C) +#endif + +#if defined(BN_MP_INIT_COPY_C) +# define BN_MP_CLEAR_C +# define BN_MP_COPY_C +# define BN_MP_INIT_SIZE_C +#endif + +#if defined(BN_MP_INIT_I32_C) +# define BN_MP_INIT_C +# define BN_MP_SET_I32_C +#endif + +#if defined(BN_MP_INIT_I64_C) +# define BN_MP_INIT_C +# define BN_MP_SET_I64_C +#endif + +#if defined(BN_MP_INIT_L_C) +# define BN_MP_INIT_C +# define BN_MP_SET_L_C +#endif + +#if defined(BN_MP_INIT_LL_C) +# define BN_MP_INIT_C +# define BN_MP_SET_LL_C +#endif + +#if defined(BN_MP_INIT_MULTI_C) +# define BN_MP_CLEAR_C +# define BN_MP_INIT_C +#endif + +#if defined(BN_MP_INIT_SET_C) +# define BN_MP_INIT_C +# define BN_MP_SET_C +#endif + +#if defined(BN_MP_INIT_SIZE_C) +#endif + +#if defined(BN_MP_INIT_U32_C) +# define BN_MP_INIT_C +# define BN_MP_SET_U32_C +#endif + +#if defined(BN_MP_INIT_U64_C) +# define BN_MP_INIT_C +# define BN_MP_SET_U64_C +#endif + +#if defined(BN_MP_INIT_UL_C) +# define BN_MP_INIT_C +# define BN_MP_SET_UL_C +#endif + +#if defined(BN_MP_INIT_ULL_C) +# define BN_MP_INIT_C +# define BN_MP_SET_ULL_C +#endif + +#if defined(BN_MP_INVMOD_C) +# define BN_MP_CMP_D_C +# define BN_S_MP_INVMOD_FAST_C +# define BN_S_MP_INVMOD_SLOW_C +#endif + +#if defined(BN_MP_IS_SQUARE_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_MAG_C +# define BN_MP_GET_I32_C +# define BN_MP_INIT_U32_C +# define BN_MP_MOD_C +# define BN_MP_MOD_D_C +# define BN_MP_SQRT_C +# define BN_MP_SQR_C +#endif + +#if defined(BN_MP_ISEVEN_C) +#endif + +#if defined(BN_MP_ISODD_C) +#endif + +#if defined(BN_MP_KRONECKER_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_D_C +# define BN_MP_CNT_LSB_C +# define BN_MP_COPY_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_C +# define BN_MP_INIT_COPY_C +# define BN_MP_MOD_C +#endif + +#if defined(BN_MP_LCM_C) +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_MAG_C +# define BN_MP_DIV_C +# define BN_MP_GCD_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MUL_C +#endif + +#if defined(BN_MP_LOG_U32_C) +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_EXCH_C +# define BN_MP_EXPT_U32_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MUL_C +# define BN_MP_SET_C +# define BN_MP_SQR_C +#endif + +#if defined(BN_MP_LSHD_C) +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_MOD_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_C +# define BN_MP_DIV_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +#endif + +#if defined(BN_MP_MOD_2D_C) +# define BN_MP_CLAMP_C +# define BN_MP_COPY_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_MOD_D_C) +# define BN_MP_DIV_D_C +#endif + +#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C) +# define BN_MP_2EXPT_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_MUL_2_C +# define BN_MP_SET_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_REDUCE_C) +# define BN_MP_CLAMP_C +# define BN_MP_CMP_MAG_C +# define BN_MP_GROW_C +# define BN_MP_RSHD_C +# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_SETUP_C) +#endif + +#if defined(BN_MP_MUL_C) +# define BN_S_MP_BALANCE_MUL_C +# define BN_S_MP_KARATSUBA_MUL_C +# define BN_S_MP_MUL_DIGS_C +# define BN_S_MP_MUL_DIGS_FAST_C +# define BN_S_MP_TOOM_MUL_C +#endif + +#if defined(BN_MP_MUL_2_C) +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_MUL_2D_C) +# define BN_MP_CLAMP_C +# define BN_MP_COPY_C +# define BN_MP_GROW_C +# define BN_MP_LSHD_C +#endif + +#if defined(BN_MP_MUL_D_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_MULMOD_C) +# define BN_MP_CLEAR_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_MOD_C +# define BN_MP_MUL_C +#endif + +#if defined(BN_MP_NEG_C) +# define BN_MP_COPY_C +#endif + +#if defined(BN_MP_OR_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_PACK_C) +# define BN_MP_CLEAR_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_COPY_C +# define BN_MP_PACK_COUNT_C +#endif + +#if defined(BN_MP_PACK_COUNT_C) +# define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_PRIME_FERMAT_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_EXPTMOD_C +# define BN_MP_INIT_C +#endif + +#if defined(BN_MP_PRIME_FROBENIUS_UNDERWOOD_C) +# define BN_MP_ADD_C +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_EXCH_C +# define BN_MP_GCD_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_KRONECKER_C +# define BN_MP_MOD_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_C +# define BN_MP_MUL_D_C +# define BN_MP_SET_C +# define BN_MP_SET_U32_C +# define BN_MP_SQR_C +# define BN_MP_SUB_C +# define BN_MP_SUB_D_C +# define BN_S_MP_GET_BIT_C +#endif + +#if defined(BN_MP_PRIME_IS_PRIME_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_SET_C +# define BN_MP_IS_SQUARE_C +# define BN_MP_PRIME_MILLER_RABIN_C +# define BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C +# define BN_MP_RAND_C +# define BN_MP_READ_RADIX_C +# define BN_MP_SET_C +# define BN_S_MP_PRIME_IS_DIVISIBLE_C +#endif + +#if defined(BN_MP_PRIME_MILLER_RABIN_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_CNT_LSB_C +# define BN_MP_DIV_2D_C +# define BN_MP_EXPTMOD_C +# define BN_MP_INIT_C +# define BN_MP_INIT_COPY_C +# define BN_MP_SQRMOD_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_PRIME_NEXT_PRIME_C) +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_C +# define BN_MP_CMP_D_C +# define BN_MP_INIT_C +# define BN_MP_MOD_D_C +# define BN_MP_PRIME_IS_PRIME_C +# define BN_MP_SET_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C) +#endif + +#if defined(BN_MP_PRIME_RAND_C) +# define BN_MP_ADD_D_C +# define BN_MP_DIV_2_C +# define BN_MP_FROM_UBIN_C +# define BN_MP_MUL_2_C +# define BN_MP_PRIME_IS_PRIME_C +# define BN_MP_SUB_D_C +# define BN_S_MP_PRIME_RANDOM_EX_C +# define BN_S_MP_RAND_CB_C +# define BN_S_MP_RAND_SOURCE_C +#endif + +#if defined(BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C) +# define BN_MP_ADD_C +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_CNT_LSB_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_2D_C +# define BN_MP_DIV_2_C +# define BN_MP_GCD_C +# define BN_MP_INIT_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_KRONECKER_C +# define BN_MP_MOD_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_C +# define BN_MP_SET_C +# define BN_MP_SET_I32_C +# define BN_MP_SET_U32_C +# define BN_MP_SQR_C +# define BN_MP_SUB_C +# define BN_MP_SUB_D_C +# define BN_S_MP_GET_BIT_C +# define BN_S_MP_MUL_SI_C +#endif + +#if defined(BN_MP_RADIX_SIZE_C) +# define BN_MP_CLEAR_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_D_C +# define BN_MP_INIT_COPY_C +#endif + +#if defined(BN_MP_RADIX_SMAP_C) +#endif + +#if defined(BN_MP_RAND_C) +# define BN_MP_GROW_C +# define BN_MP_RAND_SOURCE_C +# define BN_MP_ZERO_C +# define BN_S_MP_RAND_PLATFORM_C +# define BN_S_MP_RAND_SOURCE_C +#endif + +#if defined(BN_MP_READ_RADIX_C) +# define BN_MP_ADD_D_C +# define BN_MP_MUL_D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_REDUCE_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_INIT_COPY_C +# define BN_MP_LSHD_C +# define BN_MP_MOD_2D_C +# define BN_MP_MUL_C +# define BN_MP_RSHD_C +# define BN_MP_SET_C +# define BN_MP_SUB_C +# define BN_S_MP_MUL_DIGS_C +# define BN_S_MP_MUL_HIGH_DIGS_C +# define BN_S_MP_MUL_HIGH_DIGS_FAST_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_C +# define BN_MP_MUL_D_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_L_C) +# define BN_MP_CLEAR_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_C +# define BN_MP_MUL_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_C) +# define BN_MP_2EXPT_C +# define BN_MP_CLEAR_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_INIT_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_L_C) +# define BN_MP_2EXPT_C +# define BN_MP_CLEAR_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_INIT_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_IS_2K_C) +# define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_REDUCE_IS_2K_L_C) +#endif + +#if defined(BN_MP_REDUCE_SETUP_C) +# define BN_MP_2EXPT_C +# define BN_MP_DIV_C +#endif + +#if defined(BN_MP_ROOT_U32_C) +# define BN_MP_2EXPT_C +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DIV_C +# define BN_MP_EXCH_C +# define BN_MP_EXPT_U32_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MUL_C +# define BN_MP_MUL_D_C +# define BN_MP_SET_C +# define BN_MP_SUB_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_RSHD_C) +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SBIN_SIZE_C) +# define BN_MP_UBIN_SIZE_C +#endif + +#if defined(BN_MP_SET_C) +#endif + +#if defined(BN_MP_SET_DOUBLE_C) +# define BN_MP_DIV_2D_C +# define BN_MP_MUL_2D_C +# define BN_MP_SET_U64_C +#endif + +#if defined(BN_MP_SET_I32_C) +# define BN_MP_SET_U32_C +#endif + +#if defined(BN_MP_SET_I64_C) +# define BN_MP_SET_U64_C +#endif + +#if defined(BN_MP_SET_L_C) +# define BN_MP_SET_UL_C +#endif + +#if defined(BN_MP_SET_LL_C) +# define BN_MP_SET_ULL_C +#endif + +#if defined(BN_MP_SET_U32_C) +#endif + +#if defined(BN_MP_SET_U64_C) +#endif + +#if defined(BN_MP_SET_UL_C) +#endif + +#if defined(BN_MP_SET_ULL_C) +#endif + +#if defined(BN_MP_SHRINK_C) +#endif + +#if defined(BN_MP_SIGNED_RSH_C) +# define BN_MP_ADD_D_C +# define BN_MP_DIV_2D_C +# define BN_MP_SUB_D_C +#endif + +#if defined(BN_MP_SQR_C) +# define BN_S_MP_KARATSUBA_SQR_C +# define BN_S_MP_SQR_C +# define BN_S_MP_SQR_FAST_C +# define BN_S_MP_TOOM_SQR_C +#endif + +#if defined(BN_MP_SQRMOD_C) +# define BN_MP_CLEAR_C +# define BN_MP_INIT_C +# define BN_MP_MOD_C +# define BN_MP_SQR_C +#endif + +#if defined(BN_MP_SQRT_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_C +# define BN_MP_CMP_MAG_C +# define BN_MP_DIV_2_C +# define BN_MP_DIV_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_C +# define BN_MP_INIT_COPY_C +# define BN_MP_RSHD_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SQRTMOD_PRIME_C) +# define BN_MP_ADD_D_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_D_C +# define BN_MP_COPY_C +# define BN_MP_DIV_2_C +# define BN_MP_EXPTMOD_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_KRONECKER_C +# define BN_MP_MOD_D_C +# define BN_MP_MULMOD_C +# define BN_MP_SET_C +# define BN_MP_SET_U32_C +# define BN_MP_SQRMOD_C +# define BN_MP_SUB_D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SUB_C) +# define BN_MP_CMP_MAG_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_SUB_D_C) +# define BN_MP_ADD_D_C +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_SUBMOD_C) +# define BN_MP_CLEAR_C +# define BN_MP_INIT_C +# define BN_MP_MOD_C +# define BN_MP_SUB_C +#endif + +#if defined(BN_MP_TO_RADIX_C) +# define BN_MP_CLEAR_C +# define BN_MP_DIV_D_C +# define BN_MP_INIT_COPY_C +# define BN_S_MP_REVERSE_C +#endif + +#if defined(BN_MP_TO_SBIN_C) +# define BN_MP_TO_UBIN_C +#endif + +#if defined(BN_MP_TO_UBIN_C) +# define BN_MP_CLEAR_C +# define BN_MP_DIV_2D_C +# define BN_MP_INIT_COPY_C +# define BN_MP_UBIN_SIZE_C +#endif + +#if defined(BN_MP_UBIN_SIZE_C) +# define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_UNPACK_C) +# define BN_MP_CLAMP_C +# define BN_MP_MUL_2D_C +# define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_XOR_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_MP_ZERO_C) +#endif + +#if defined(BN_PRIME_TAB_C) +#endif + +#if defined(BN_S_MP_ADD_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_S_MP_BALANCE_MUL_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_MUL_C +#endif + +#if defined(BN_S_MP_EXPTMOD_C) +# define BN_MP_CLEAR_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_C +# define BN_MP_MOD_C +# define BN_MP_MUL_C +# define BN_MP_REDUCE_2K_L_C +# define BN_MP_REDUCE_2K_SETUP_L_C +# define BN_MP_REDUCE_C +# define BN_MP_REDUCE_SETUP_C +# define BN_MP_SET_C +# define BN_MP_SQR_C +#endif + +#if defined(BN_S_MP_EXPTMOD_FAST_C) +# define BN_MP_CLEAR_C +# define BN_MP_COPY_C +# define BN_MP_COUNT_BITS_C +# define BN_MP_DR_REDUCE_C +# define BN_MP_DR_SETUP_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_MOD_C +# define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +# define BN_MP_MONTGOMERY_REDUCE_C +# define BN_MP_MONTGOMERY_SETUP_C +# define BN_MP_MULMOD_C +# define BN_MP_MUL_C +# define BN_MP_REDUCE_2K_C +# define BN_MP_REDUCE_2K_SETUP_C +# define BN_MP_SET_C +# define BN_MP_SQR_C +# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C +#endif + +#if defined(BN_S_MP_GET_BIT_C) +#endif + +#if defined(BN_S_MP_INVMOD_FAST_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COPY_C +# define BN_MP_DIV_2_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MOD_C +# define BN_MP_SET_C +# define BN_MP_SUB_C +#endif + +#if defined(BN_S_MP_INVMOD_SLOW_C) +# define BN_MP_ADD_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_CMP_C +# define BN_MP_CMP_D_C +# define BN_MP_CMP_MAG_C +# define BN_MP_COPY_C +# define BN_MP_DIV_2_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_MOD_C +# define BN_MP_SET_C +# define BN_MP_SUB_C +#endif + +#if defined(BN_S_MP_KARATSUBA_MUL_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_MUL_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_S_MP_KARATSUBA_SQR_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_SQR_C +# define BN_S_MP_ADD_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_S_MP_MONTGOMERY_REDUCE_FAST_C) +# define BN_MP_CLAMP_C +# define BN_MP_CMP_MAG_C +# define BN_MP_GROW_C +# define BN_S_MP_SUB_C +#endif + +#if defined(BN_S_MP_MUL_DIGS_C) +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +# define BN_S_MP_MUL_DIGS_FAST_C +#endif + +#if defined(BN_S_MP_MUL_DIGS_FAST_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_S_MP_MUL_HIGH_DIGS_C) +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +# define BN_S_MP_MUL_HIGH_DIGS_FAST_C +#endif + +#if defined(BN_S_MP_MUL_HIGH_DIGS_FAST_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_S_MP_PRIME_IS_DIVISIBLE_C) +# define BN_MP_MOD_D_C +#endif + +#if defined(BN_S_MP_RAND_JENKINS_C) +# define BN_S_MP_RAND_JENKINS_INIT_C +#endif + +#if defined(BN_S_MP_RAND_PLATFORM_C) +#endif + +#if defined(BN_S_MP_REVERSE_C) +#endif + +#if defined(BN_S_MP_SQR_C) +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_EXCH_C +# define BN_MP_INIT_SIZE_C +#endif + +#if defined(BN_S_MP_SQR_FAST_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_S_MP_SUB_C) +# define BN_MP_CLAMP_C +# define BN_MP_GROW_C +#endif + +#if defined(BN_S_MP_TOOM_MUL_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_DIV_2_C +# define BN_MP_DIV_3_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_C +# define BN_MP_SUB_C +#endif + +#if defined(BN_S_MP_TOOM_SQR_C) +# define BN_MP_ADD_C +# define BN_MP_CLAMP_C +# define BN_MP_CLEAR_C +# define BN_MP_DIV_2_C +# define BN_MP_INIT_C +# define BN_MP_INIT_SIZE_C +# define BN_MP_LSHD_C +# define BN_MP_MUL_2_C +# define BN_MP_MUL_C +# define BN_MP_SQR_C +# define BN_MP_SUB_C +#endif + +#ifdef LTM_INSIDE +#undef LTM_INSIDE +#ifdef LTM3 +# define LTM_LAST +#endif + +#include "tommath_superclass.h" +#include "tommath_class.h" +#else +# define LTM_LAST +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath_cutoffs.h b/third_party/heimdal/lib/hcrypto/libtommath/tommath_cutoffs.h new file mode 100644 index 0000000..a65a9b3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath_cutoffs.h @@ -0,0 +1,13 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +/* + Current values evaluated on an AMD A8-6600K (64-bit). + Type "make tune" to optimize them for your machine but + be aware that it may take a long time. It took 2:30 minutes + on the aforementioned machine for example. + */ + +#define MP_DEFAULT_KARATSUBA_MUL_CUTOFF 80 +#define MP_DEFAULT_KARATSUBA_SQR_CUTOFF 120 +#define MP_DEFAULT_TOOM_MUL_CUTOFF 350 +#define MP_DEFAULT_TOOM_SQR_CUTOFF 400 diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath_private.h b/third_party/heimdal/lib/hcrypto/libtommath/tommath_private.h new file mode 100644 index 0000000..1a0096f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath_private.h @@ -0,0 +1,303 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +#ifndef TOMMATH_PRIV_H_ +#define TOMMATH_PRIV_H_ + +#include "tommath.h" +#include "tommath_class.h" + +/* + * Private symbols + * --------------- + * + * On Unix symbols can be marked as hidden if libtommath is compiled + * as a shared object. By default, symbols are visible. + * As of now, this feature is opt-in via the MP_PRIVATE_SYMBOLS define. + * + * On Win32 a .def file must be used to specify the exported symbols. + */ +#if defined (MP_PRIVATE_SYMBOLS) && defined(__GNUC__) && __GNUC__ >= 4 +# define MP_PRIVATE __attribute__ ((visibility ("hidden"))) +#else +# define MP_PRIVATE +#endif + +/* Hardening libtommath + * -------------------- + * + * By default memory is zeroed before calling + * MP_FREE to avoid leaking data. This is good + * practice in cryptographical applications. + * + * Note however that memory allocators used + * in cryptographical applications can often + * be configured by itself to clear memory, + * rendering the clearing in tommath unnecessary. + * See for example https://github.com/GrapheneOS/hardened_malloc + * and the option CONFIG_ZERO_ON_FREE. + * + * Furthermore there are applications which + * value performance more and want this + * feature to be disabled. For such applications + * define MP_NO_ZERO_ON_FREE during compilation. + */ +#ifdef MP_NO_ZERO_ON_FREE +# define MP_FREE_BUFFER(mem, size) MP_FREE((mem), (size)) +# define MP_FREE_DIGITS(mem, digits) MP_FREE((mem), sizeof (mp_digit) * (size_t)(digits)) +#else +# define MP_FREE_BUFFER(mem, size) \ +do { \ + size_t fs_ = (size); \ + void* fm_ = (mem); \ + if (fm_ != NULL) { \ + MP_ZERO_BUFFER(fm_, fs_); \ + MP_FREE(fm_, fs_); \ + } \ +} while (0) +# define MP_FREE_DIGITS(mem, digits) \ +do { \ + int fd_ = (digits); \ + void* fm_ = (mem); \ + if (fm_ != NULL) { \ + size_t fs_ = sizeof (mp_digit) * (size_t)fd_; \ + MP_ZERO_BUFFER(fm_, fs_); \ + MP_FREE(fm_, fs_); \ + } \ +} while (0) +#endif + +#ifdef MP_USE_MEMSET +# include +# define MP_ZERO_BUFFER(mem, size) memset((mem), 0, (size)) +# define MP_ZERO_DIGITS(mem, digits) \ +do { \ + int zd_ = (digits); \ + if (zd_ > 0) { \ + memset((mem), 0, sizeof(mp_digit) * (size_t)zd_); \ + } \ +} while (0) +#else +# define MP_ZERO_BUFFER(mem, size) \ +do { \ + size_t zs_ = (size); \ + char* zm_ = (char*)(mem); \ + while (zs_-- > 0u) { \ + *zm_++ = '\0'; \ + } \ +} while (0) +# define MP_ZERO_DIGITS(mem, digits) \ +do { \ + int zd_ = (digits); \ + mp_digit* zm_ = (mem); \ + while (zd_-- > 0) { \ + *zm_++ = 0; \ + } \ +} while (0) +#endif + +/* Tunable cutoffs + * --------------- + * + * - In the default settings, a cutoff X can be modified at runtime + * by adjusting the corresponding X_CUTOFF variable. + * + * - Tunability of the library can be disabled at compile time + * by defining the MP_FIXED_CUTOFFS macro. + * + * - There is an additional file tommath_cutoffs.h, which defines + * the default cutoffs. These can be adjusted manually or by the + * autotuner. + * + */ + +#ifdef MP_FIXED_CUTOFFS +# include "tommath_cutoffs.h" +# define MP_KARATSUBA_MUL_CUTOFF MP_DEFAULT_KARATSUBA_MUL_CUTOFF +# define MP_KARATSUBA_SQR_CUTOFF MP_DEFAULT_KARATSUBA_SQR_CUTOFF +# define MP_TOOM_MUL_CUTOFF MP_DEFAULT_TOOM_MUL_CUTOFF +# define MP_TOOM_SQR_CUTOFF MP_DEFAULT_TOOM_SQR_CUTOFF +#else +# define MP_KARATSUBA_MUL_CUTOFF KARATSUBA_MUL_CUTOFF +# define MP_KARATSUBA_SQR_CUTOFF KARATSUBA_SQR_CUTOFF +# define MP_TOOM_MUL_CUTOFF TOOM_MUL_CUTOFF +# define MP_TOOM_SQR_CUTOFF TOOM_SQR_CUTOFF +#endif + +/* define heap macros */ +#ifndef MP_MALLOC +/* default to libc stuff */ +# include +# define MP_MALLOC(size) malloc(size) +# define MP_REALLOC(mem, oldsize, newsize) realloc((mem), (newsize)) +# define MP_CALLOC(nmemb, size) calloc((nmemb), (size)) +# define MP_FREE(mem, size) free(mem) +#else +/* prototypes for our heap functions */ +extern void *MP_MALLOC(size_t size); +extern void *MP_REALLOC(void *mem, size_t oldsize, size_t newsize); +extern void *MP_CALLOC(size_t nmemb, size_t size); +extern void MP_FREE(void *mem, size_t size); +#endif + +/* feature detection macro */ +#ifdef _MSC_VER +/* Prevent false positive: not enough arguments for function-like macro invocation */ +#pragma warning(disable: 4003) +#endif +#define MP_STRINGIZE(x) MP__STRINGIZE(x) +#define MP__STRINGIZE(x) ""#x"" +#define MP_HAS(x) (sizeof(MP_STRINGIZE(BN_##x##_C)) == 1u) + +/* TODO: Remove private_mp_word as soon as deprecated mp_word is removed from tommath. */ +#undef mp_word +typedef private_mp_word mp_word; + +#define MP_MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MP_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/* Static assertion */ +#define MP_STATIC_ASSERT(msg, cond) typedef char mp_static_assert_##msg[(cond) ? 1 : -1]; + +/* ---> Basic Manipulations <--- */ +#define MP_IS_ZERO(a) ((a)->used == 0) +#define MP_IS_EVEN(a) (((a)->used == 0) || (((a)->dp[0] & 1u) == 0u)) +#define MP_IS_ODD(a) (((a)->used > 0) && (((a)->dp[0] & 1u) == 1u)) + +#define MP_SIZEOF_BITS(type) ((size_t)CHAR_BIT * sizeof(type)) +#define MP_MAXFAST (int)(1uL << (MP_SIZEOF_BITS(mp_word) - (2u * (size_t)MP_DIGIT_BIT))) + +/* TODO: Remove PRIVATE_MP_WARRAY as soon as deprecated MP_WARRAY is removed from tommath.h */ +#undef MP_WARRAY +#define MP_WARRAY PRIVATE_MP_WARRAY + +/* TODO: Remove PRIVATE_MP_PREC as soon as deprecated MP_PREC is removed from tommath.h */ +#ifdef PRIVATE_MP_PREC +# undef MP_PREC +# define MP_PREC PRIVATE_MP_PREC +#endif + +/* Minimum number of available digits in mp_int, MP_PREC >= MP_MIN_PREC */ +#define MP_MIN_PREC ((((int)MP_SIZEOF_BITS(long long) + MP_DIGIT_BIT) - 1) / MP_DIGIT_BIT) + +MP_STATIC_ASSERT(prec_geq_min_prec, MP_PREC >= MP_MIN_PREC) + +/* random number source */ +extern MP_PRIVATE mp_err(*s_mp_rand_source)(void *out, size_t size); + +/* lowlevel functions, do not call! */ +MP_PRIVATE mp_bool s_mp_get_bit(const mp_int *a, unsigned int b); +MP_PRIVATE mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_mul_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR; +MP_PRIVATE mp_err s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR; +MP_PRIVATE mp_err s_mp_mul_high_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR; +MP_PRIVATE mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR; +MP_PRIVATE mp_err s_mp_sqr_fast(const mp_int *a, mp_int *b) MP_WUR; +MP_PRIVATE mp_err s_mp_sqr(const mp_int *a, mp_int *b) MP_WUR; +MP_PRIVATE mp_err s_mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_karatsuba_sqr(const mp_int *a, mp_int *b) MP_WUR; +MP_PRIVATE mp_err s_mp_toom_sqr(const mp_int *a, mp_int *b) MP_WUR; +MP_PRIVATE mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR; +MP_PRIVATE mp_err s_mp_montgomery_reduce_fast(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR; +MP_PRIVATE mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR; +MP_PRIVATE mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR; +MP_PRIVATE mp_err s_mp_rand_platform(void *p, size_t n) MP_WUR; +MP_PRIVATE mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat); +MP_PRIVATE void s_mp_reverse(unsigned char *s, size_t len); +MP_PRIVATE mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result); + +/* TODO: jenkins prng is not thread safe as of now */ +MP_PRIVATE mp_err s_mp_rand_jenkins(void *p, size_t n) MP_WUR; +MP_PRIVATE void s_mp_rand_jenkins_init(uint64_t seed); + +extern MP_PRIVATE const char *const mp_s_rmap; +extern MP_PRIVATE const uint8_t mp_s_rmap_reverse[]; +extern MP_PRIVATE const size_t mp_s_rmap_reverse_sz; +extern MP_PRIVATE const mp_digit *s_mp_prime_tab; + +/* deprecated functions */ +MP_DEPRECATED(s_mp_invmod_fast) mp_err fast_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c); +MP_DEPRECATED(s_mp_montgomery_reduce_fast) mp_err fast_mp_montgomery_reduce(mp_int *x, const mp_int *n, + mp_digit rho); +MP_DEPRECATED(s_mp_mul_digs_fast) mp_err fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, + int digs); +MP_DEPRECATED(s_mp_mul_high_digs_fast) mp_err fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b, + mp_int *c, + int digs); +MP_DEPRECATED(s_mp_sqr_fast) mp_err fast_s_mp_sqr(const mp_int *a, mp_int *b); +MP_DEPRECATED(s_mp_balance_mul) mp_err mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c); +MP_DEPRECATED(s_mp_exptmod_fast) mp_err mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, + mp_int *Y, + int redmode); +MP_DEPRECATED(s_mp_invmod_slow) mp_err mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c); +MP_DEPRECATED(s_mp_karatsuba_mul) mp_err mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c); +MP_DEPRECATED(s_mp_karatsuba_sqr) mp_err mp_karatsuba_sqr(const mp_int *a, mp_int *b); +MP_DEPRECATED(s_mp_toom_mul) mp_err mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c); +MP_DEPRECATED(s_mp_toom_sqr) mp_err mp_toom_sqr(const mp_int *a, mp_int *b); +MP_DEPRECATED(s_mp_reverse) void bn_reverse(unsigned char *s, int len); + +#define MP_GET_ENDIANNESS(x) \ + do{\ + int16_t n = 0x1; \ + char *p = (char *)&n; \ + x = (p[0] == '\x01') ? MP_LITTLE_ENDIAN : MP_BIG_ENDIAN; \ + } while (0) + +/* code-generating macros */ +#define MP_SET_UNSIGNED(name, type) \ + void name(mp_int * a, type b) \ + { \ + int i = 0; \ + while (b != 0u) { \ + a->dp[i++] = ((mp_digit)b & MP_MASK); \ + if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \ + b >>= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \ + } \ + a->used = i; \ + a->sign = MP_ZPOS; \ + MP_ZERO_DIGITS(a->dp + a->used, a->alloc - a->used); \ + } + +#define MP_SET_SIGNED(name, uname, type, utype) \ + void name(mp_int * a, type b) \ + { \ + uname(a, (b < 0) ? -(utype)b : (utype)b); \ + if (b < 0) { a->sign = MP_NEG; } \ + } + +#define MP_INIT_INT(name , set, type) \ + mp_err name(mp_int * a, type b) \ + { \ + mp_err err; \ + if ((err = mp_init(a)) != MP_OKAY) { \ + return err; \ + } \ + set(a, b); \ + return MP_OKAY; \ + } + +#define MP_GET_MAG(name, type) \ + type name(const mp_int* a) \ + { \ + unsigned i = MP_MIN((unsigned)a->used, (unsigned)((MP_SIZEOF_BITS(type) + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT)); \ + type res = 0u; \ + while (i --> 0u) { \ + res <<= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \ + res |= (type)a->dp[i]; \ + if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \ + } \ + return res; \ + } + +#define MP_GET_SIGNED(name, mag, type, utype) \ + type name(const mp_int* a) \ + { \ + utype res = mag(a); \ + return (a->sign == MP_NEG) ? (type)-res : (type)res; \ + } + +#endif diff --git a/third_party/heimdal/lib/hcrypto/libtommath/tommath_superclass.h b/third_party/heimdal/lib/hcrypto/libtommath/tommath_superclass.h new file mode 100644 index 0000000..d88bce9 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/libtommath/tommath_superclass.h @@ -0,0 +1,110 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ + +/* super class file for PK algos */ + +/* default ... include all MPI */ +#ifndef LTM_NOTHING +#define LTM_ALL +#endif + +/* RSA only (does not support DH/DSA/ECC) */ +/* #define SC_RSA_1 */ +/* #define SC_RSA_1_WITH_TESTS */ + +/* For reference.... On an Athlon64 optimizing for speed... + + LTM's mpi.o with all functions [striped] is 142KiB in size. + +*/ + +#ifdef SC_RSA_1_WITH_TESTS +# define BN_MP_ERROR_TO_STRING_C +# define BN_MP_FREAD_C +# define BN_MP_FWRITE_C +# define BN_MP_INCR_C +# define BN_MP_ISEVEN_C +# define BN_MP_ISODD_C +# define BN_MP_NEG_C +# define BN_MP_PRIME_FROBENIUS_UNDERWOOD_C +# define BN_MP_RADIX_SIZE_C +# define BN_MP_RAND_C +# define BN_MP_REDUCE_C +# define BN_MP_REDUCE_2K_L_C +# define BN_MP_FROM_SBIN_C +# define BN_MP_ROOT_U32_C +# define BN_MP_SET_L_C +# define BN_MP_SET_UL_C +# define BN_MP_SBIN_SIZE_C +# define BN_MP_TO_RADIX_C +# define BN_MP_TO_SBIN_C +# define BN_S_MP_RAND_JENKINS_C +# define BN_S_MP_RAND_PLATFORM_C +#endif + +/* Works for RSA only, mpi.o is 68KiB */ +#if defined(SC_RSA_1) || defined (SC_RSA_1_WITH_TESTS) +# define BN_CUTOFFS_C +# define BN_MP_ADDMOD_C +# define BN_MP_CLEAR_MULTI_C +# define BN_MP_EXPTMOD_C +# define BN_MP_GCD_C +# define BN_MP_INIT_MULTI_C +# define BN_MP_INVMOD_C +# define BN_MP_LCM_C +# define BN_MP_MOD_C +# define BN_MP_MOD_D_C +# define BN_MP_MULMOD_C +# define BN_MP_PRIME_IS_PRIME_C +# define BN_MP_PRIME_RABIN_MILLER_TRIALS_C +# define BN_MP_PRIME_RAND_C +# define BN_MP_RADIX_SMAP_C +# define BN_MP_SET_INT_C +# define BN_MP_SHRINK_C +# define BN_MP_TO_UNSIGNED_BIN_C +# define BN_MP_UNSIGNED_BIN_SIZE_C +# define BN_PRIME_TAB_C +# define BN_S_MP_REVERSE_C + +/* other modifiers */ +# define BN_MP_DIV_SMALL /* Slower division, not critical */ + + +/* here we are on the last pass so we turn things off. The functions classes are still there + * but we remove them specifically from the build. This also invokes tweaks in functions + * like removing support for even moduli, etc... + */ +# ifdef LTM_LAST +# undef BN_MP_DR_IS_MODULUS_C +# undef BN_MP_DR_SETUP_C +# undef BN_MP_DR_REDUCE_C +# undef BN_MP_DIV_3_C +# undef BN_MP_REDUCE_2K_SETUP_C +# undef BN_MP_REDUCE_2K_C +# undef BN_MP_REDUCE_IS_2K_C +# undef BN_MP_REDUCE_SETUP_C +# undef BN_S_MP_BALANCE_MUL_C +# undef BN_S_MP_EXPTMOD_C +# undef BN_S_MP_INVMOD_FAST_C +# undef BN_S_MP_KARATSUBA_MUL_C +# undef BN_S_MP_KARATSUBA_SQR_C +# undef BN_S_MP_MUL_HIGH_DIGS_C +# undef BN_S_MP_MUL_HIGH_DIGS_FAST_C +# undef BN_S_MP_TOOM_MUL_C +# undef BN_S_MP_TOOM_SQR_C + +# ifndef SC_RSA_1_WITH_TESTS +# undef BN_MP_REDUCE_C +# endif + +/* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold + * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines] + * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without + * trouble. + */ +# undef BN_MP_MONTGOMERY_REDUCE_C +# undef BN_S_MP_MUL_DIGS_C +# undef BN_S_MP_SQR_C +# endif + +#endif diff --git a/third_party/heimdal/lib/hcrypto/md4.c b/third_party/heimdal/lib/hcrypto/md4.c new file mode 100644 index 0000000..2a803ce --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/md4.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hash.h" +#include "md4.h" + +#define A m->counter[0] +#define B m->counter[1] +#define C m->counter[2] +#define D m->counter[3] +#define X data + +int +MD4_Init (struct md4 *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + D = 0x10325476; + C = 0x98badcfe; + B = 0xefcdab89; + A = 0x67452301; + return 1; +} + +#define F(x,y,z) CRAYFIX((x & y) | (~x & z)) +#define G(x,y,z) ((x & y) | (x & z) | (y & z)) +#define H(x,y,z) (x ^ y ^ z) + +#define DOIT(a,b,c,d,k,s,i,OP) \ +a = cshift(a + OP(b,c,d) + X[k] + i, s) + +#define DO1(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,F) +#define DO2(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,G) +#define DO3(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,H) + +static inline void +calc (struct md4 *m, uint32_t *data) +{ + uint32_t AA, BB, CC, DD; + + AA = A; + BB = B; + CC = C; + DD = D; + + /* Round 1 */ + + DO1(A,B,C,D,0,3,0); + DO1(D,A,B,C,1,7,0); + DO1(C,D,A,B,2,11,0); + DO1(B,C,D,A,3,19,0); + + DO1(A,B,C,D,4,3,0); + DO1(D,A,B,C,5,7,0); + DO1(C,D,A,B,6,11,0); + DO1(B,C,D,A,7,19,0); + + DO1(A,B,C,D,8,3,0); + DO1(D,A,B,C,9,7,0); + DO1(C,D,A,B,10,11,0); + DO1(B,C,D,A,11,19,0); + + DO1(A,B,C,D,12,3,0); + DO1(D,A,B,C,13,7,0); + DO1(C,D,A,B,14,11,0); + DO1(B,C,D,A,15,19,0); + + /* Round 2 */ + + DO2(A,B,C,D,0,3,0x5A827999); + DO2(D,A,B,C,4,5,0x5A827999); + DO2(C,D,A,B,8,9,0x5A827999); + DO2(B,C,D,A,12,13,0x5A827999); + + DO2(A,B,C,D,1,3,0x5A827999); + DO2(D,A,B,C,5,5,0x5A827999); + DO2(C,D,A,B,9,9,0x5A827999); + DO2(B,C,D,A,13,13,0x5A827999); + + DO2(A,B,C,D,2,3,0x5A827999); + DO2(D,A,B,C,6,5,0x5A827999); + DO2(C,D,A,B,10,9,0x5A827999); + DO2(B,C,D,A,14,13,0x5A827999); + + DO2(A,B,C,D,3,3,0x5A827999); + DO2(D,A,B,C,7,5,0x5A827999); + DO2(C,D,A,B,11,9,0x5A827999); + DO2(B,C,D,A,15,13,0x5A827999); + + /* Round 3 */ + + DO3(A,B,C,D,0,3,0x6ED9EBA1); + DO3(D,A,B,C,8,9,0x6ED9EBA1); + DO3(C,D,A,B,4,11,0x6ED9EBA1); + DO3(B,C,D,A,12,15,0x6ED9EBA1); + + DO3(A,B,C,D,2,3,0x6ED9EBA1); + DO3(D,A,B,C,10,9,0x6ED9EBA1); + DO3(C,D,A,B,6,11,0x6ED9EBA1); + DO3(B,C,D,A,14,15,0x6ED9EBA1); + + DO3(A,B,C,D,1,3,0x6ED9EBA1); + DO3(D,A,B,C,9,9,0x6ED9EBA1); + DO3(C,D,A,B,5,11,0x6ED9EBA1); + DO3(B,C,D,A,13,15,0x6ED9EBA1); + + DO3(A,B,C,D,3,3,0x6ED9EBA1); + DO3(D,A,B,C,11,9,0x6ED9EBA1); + DO3(C,D,A,B,7,11,0x6ED9EBA1); + DO3(B,C,D,A,15,15,0x6ED9EBA1); + + A += AA; + B += BB; + C += CC; + D += DD; +} + +/* + * From `Performance analysis of MD5' by Joseph D. Touch + */ + +#if defined(WORDS_BIGENDIAN) +static inline uint32_t +swap_uint32_t (uint32_t t) +{ + uint32_t temp1, temp2; + + temp1 = cshift(t, 16); + temp2 = temp1 >> 8; + temp1 &= 0x00ff00ff; + temp2 &= 0x00ff00ff; + temp1 <<= 8; + return temp1 | temp2; +} +#endif + +struct x32{ + unsigned int a:32; + unsigned int b:32; +}; + +int +MD4_Update (struct md4 *m, const void *v, size_t len) +{ + const unsigned char *p = v; + size_t old_sz = m->sz[0]; + size_t offset; + + m->sz[0] += len * 8; + if (m->sz[0] < old_sz) + ++m->sz[1]; + offset = (old_sz / 8) % 64; + while(len > 0) { + size_t l = min(len, 64 - offset); + memcpy(m->save + offset, p, l); + offset += l; + p += l; + len -= l; + if(offset == 64) { +#if defined(WORDS_BIGENDIAN) + int i; + uint32_t current[16]; + struct x32 *us = (struct x32*)m->save; + for(i = 0; i < 8; i++){ + current[2*i+0] = swap_uint32_t(us[i].a); + current[2*i+1] = swap_uint32_t(us[i].b); + } + calc(m, current); +#else + calc(m, (uint32_t*)m->save); +#endif + offset = 0; + } + } + return 1; +} + +int +MD4_Final (void *res, struct md4 *m) +{ + unsigned char zeros[72]; + unsigned offset = (m->sz[0] / 8) % 64; + unsigned int dstart = (120 - offset - 1) % 64 + 1; + + *zeros = 0x80; + memset (zeros + 1, 0, sizeof(zeros) - 1); + zeros[dstart+0] = (m->sz[0] >> 0) & 0xff; + zeros[dstart+1] = (m->sz[0] >> 8) & 0xff; + zeros[dstart+2] = (m->sz[0] >> 16) & 0xff; + zeros[dstart+3] = (m->sz[0] >> 24) & 0xff; + zeros[dstart+4] = (m->sz[1] >> 0) & 0xff; + zeros[dstart+5] = (m->sz[1] >> 8) & 0xff; + zeros[dstart+6] = (m->sz[1] >> 16) & 0xff; + zeros[dstart+7] = (m->sz[1] >> 24) & 0xff; + MD4_Update (m, zeros, dstart + 8); + { + int i; + unsigned char *r = (unsigned char *)res; + + for (i = 0; i < 4; ++i) { + r[4*i] = m->counter[i] & 0xFF; + r[4*i+1] = (m->counter[i] >> 8) & 0xFF; + r[4*i+2] = (m->counter[i] >> 16) & 0xFF; + r[4*i+3] = (m->counter[i] >> 24) & 0xFF; + } + } +#if 0 + { + int i; + uint32_t *r = (uint32_t *)res; + + for (i = 0; i < 4; ++i) + r[i] = swap_uint32_t (m->counter[i]); + } +#endif + return 1; +} diff --git a/third_party/heimdal/lib/hcrypto/md4.h b/third_party/heimdal/lib/hcrypto/md4.h new file mode 100644 index 0000000..06575c5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/md4.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_MD4_H +#define HEIM_MD4_H 1 + +/* symbol renaming */ +#define MD4_Init hc_MD4_Init +#define MD4_Update hc_MD4_Update +#define MD4_Final hc_MD4_Final + +/* + * + */ + +#define MD4_DIGEST_LENGTH 16 + +struct md4 { + unsigned int sz[2]; + uint32_t counter[4]; + unsigned char save[64]; +}; + +typedef struct md4 MD4_CTX; + +int MD4_Init (struct md4 *m); +int MD4_Update (struct md4 *m, const void *p, size_t len); +int MD4_Final (void *res, struct md4 *m); + +#endif /* HEIM_MD4_H */ diff --git a/third_party/heimdal/lib/hcrypto/md5.c b/third_party/heimdal/lib/hcrypto/md5.c new file mode 100644 index 0000000..ca5d160 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/md5.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hash.h" +#include "md5.h" + +#define A m->counter[0] +#define B m->counter[1] +#define C m->counter[2] +#define D m->counter[3] +#define X data + +int +MD5_Init (struct md5 *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + D = 0x10325476; + C = 0x98badcfe; + B = 0xefcdab89; + A = 0x67452301; + return 1; +} + +#define F(x,y,z) CRAYFIX((x & y) | (~x & z)) +#define G(x,y,z) CRAYFIX((x & z) | (y & ~z)) +#define H(x,y,z) (x ^ y ^ z) +#define I(x,y,z) CRAYFIX(y ^ (x | ~z)) + +#define DOIT(a,b,c,d,k,s,i,OP) \ +a = b + cshift(a + OP(b,c,d) + X[k] + (i), s) + +#define DO1(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,F) +#define DO2(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,G) +#define DO3(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,H) +#define DO4(a,b,c,d,k,s,i) DOIT(a,b,c,d,k,s,i,I) + +static inline void +calc (struct md5 *m, uint32_t *data) +{ + uint32_t AA, BB, CC, DD; + + AA = A; + BB = B; + CC = C; + DD = D; + + /* Round 1 */ + + DO1(A,B,C,D,0,7,0xd76aa478); + DO1(D,A,B,C,1,12,0xe8c7b756); + DO1(C,D,A,B,2,17,0x242070db); + DO1(B,C,D,A,3,22,0xc1bdceee); + + DO1(A,B,C,D,4,7,0xf57c0faf); + DO1(D,A,B,C,5,12,0x4787c62a); + DO1(C,D,A,B,6,17,0xa8304613); + DO1(B,C,D,A,7,22,0xfd469501); + + DO1(A,B,C,D,8,7,0x698098d8); + DO1(D,A,B,C,9,12,0x8b44f7af); + DO1(C,D,A,B,10,17,0xffff5bb1); + DO1(B,C,D,A,11,22,0x895cd7be); + + DO1(A,B,C,D,12,7,0x6b901122); + DO1(D,A,B,C,13,12,0xfd987193); + DO1(C,D,A,B,14,17,0xa679438e); + DO1(B,C,D,A,15,22,0x49b40821); + + /* Round 2 */ + + DO2(A,B,C,D,1,5,0xf61e2562); + DO2(D,A,B,C,6,9,0xc040b340); + DO2(C,D,A,B,11,14,0x265e5a51); + DO2(B,C,D,A,0,20,0xe9b6c7aa); + + DO2(A,B,C,D,5,5,0xd62f105d); + DO2(D,A,B,C,10,9,0x2441453); + DO2(C,D,A,B,15,14,0xd8a1e681); + DO2(B,C,D,A,4,20,0xe7d3fbc8); + + DO2(A,B,C,D,9,5,0x21e1cde6); + DO2(D,A,B,C,14,9,0xc33707d6); + DO2(C,D,A,B,3,14,0xf4d50d87); + DO2(B,C,D,A,8,20,0x455a14ed); + + DO2(A,B,C,D,13,5,0xa9e3e905); + DO2(D,A,B,C,2,9,0xfcefa3f8); + DO2(C,D,A,B,7,14,0x676f02d9); + DO2(B,C,D,A,12,20,0x8d2a4c8a); + + /* Round 3 */ + + DO3(A,B,C,D,5,4,0xfffa3942); + DO3(D,A,B,C,8,11,0x8771f681); + DO3(C,D,A,B,11,16,0x6d9d6122); + DO3(B,C,D,A,14,23,0xfde5380c); + + DO3(A,B,C,D,1,4,0xa4beea44); + DO3(D,A,B,C,4,11,0x4bdecfa9); + DO3(C,D,A,B,7,16,0xf6bb4b60); + DO3(B,C,D,A,10,23,0xbebfbc70); + + DO3(A,B,C,D,13,4,0x289b7ec6); + DO3(D,A,B,C,0,11,0xeaa127fa); + DO3(C,D,A,B,3,16,0xd4ef3085); + DO3(B,C,D,A,6,23,0x4881d05); + + DO3(A,B,C,D,9,4,0xd9d4d039); + DO3(D,A,B,C,12,11,0xe6db99e5); + DO3(C,D,A,B,15,16,0x1fa27cf8); + DO3(B,C,D,A,2,23,0xc4ac5665); + + /* Round 4 */ + + DO4(A,B,C,D,0,6,0xf4292244); + DO4(D,A,B,C,7,10,0x432aff97); + DO4(C,D,A,B,14,15,0xab9423a7); + DO4(B,C,D,A,5,21,0xfc93a039); + + DO4(A,B,C,D,12,6,0x655b59c3); + DO4(D,A,B,C,3,10,0x8f0ccc92); + DO4(C,D,A,B,10,15,0xffeff47d); + DO4(B,C,D,A,1,21,0x85845dd1); + + DO4(A,B,C,D,8,6,0x6fa87e4f); + DO4(D,A,B,C,15,10,0xfe2ce6e0); + DO4(C,D,A,B,6,15,0xa3014314); + DO4(B,C,D,A,13,21,0x4e0811a1); + + DO4(A,B,C,D,4,6,0xf7537e82); + DO4(D,A,B,C,11,10,0xbd3af235); + DO4(C,D,A,B,2,15,0x2ad7d2bb); + DO4(B,C,D,A,9,21,0xeb86d391); + + A += AA; + B += BB; + C += CC; + D += DD; +} + +/* + * From `Performance analysis of MD5' by Joseph D. Touch + */ + +#if defined(WORDS_BIGENDIAN) +static inline uint32_t +swap_uint32_t (uint32_t t) +{ + uint32_t temp1, temp2; + + temp1 = cshift(t, 16); + temp2 = temp1 >> 8; + temp1 &= 0x00ff00ff; + temp2 &= 0x00ff00ff; + temp1 <<= 8; + return temp1 | temp2; +} +#endif + +struct x32{ + unsigned int a:32; + unsigned int b:32; +}; + +int +MD5_Update (struct md5 *m, const void *v, size_t len) +{ + const unsigned char *p = v; + size_t old_sz = m->sz[0]; + size_t offset; + + m->sz[0] += len * 8; + if (m->sz[0] < old_sz) + ++m->sz[1]; + offset = (old_sz / 8) % 64; + while(len > 0){ + size_t l = min(len, 64 - offset); + memcpy(m->save + offset, p, l); + offset += l; + p += l; + len -= l; + if(offset == 64){ +#if defined(WORDS_BIGENDIAN) + int i; + uint32_t swapped[16]; + struct x32 *us = (struct x32*)m->save; + for(i = 0; i < 8; i++){ + swapped[2*i+0] = swap_uint32_t(us[i].a); + swapped[2*i+1] = swap_uint32_t(us[i].b); + } + calc(m, swapped); +#else + calc(m, (uint32_t*)m->save); +#endif + offset = 0; + } + } + return 1; +} + +int +MD5_Final (void *res, struct md5 *m) +{ + unsigned char zeros[72]; + unsigned offset = (m->sz[0] / 8) % 64; + unsigned int dstart = (120 - offset - 1) % 64 + 1; + + *zeros = 0x80; + memset (zeros + 1, 0, sizeof(zeros) - 1); + zeros[dstart+0] = (m->sz[0] >> 0) & 0xff; + zeros[dstart+1] = (m->sz[0] >> 8) & 0xff; + zeros[dstart+2] = (m->sz[0] >> 16) & 0xff; + zeros[dstart+3] = (m->sz[0] >> 24) & 0xff; + zeros[dstart+4] = (m->sz[1] >> 0) & 0xff; + zeros[dstart+5] = (m->sz[1] >> 8) & 0xff; + zeros[dstart+6] = (m->sz[1] >> 16) & 0xff; + zeros[dstart+7] = (m->sz[1] >> 24) & 0xff; + MD5_Update (m, zeros, dstart + 8); + { + int i; + unsigned char *r = (unsigned char *)res; + + for (i = 0; i < 4; ++i) { + r[4*i] = m->counter[i] & 0xFF; + r[4*i+1] = (m->counter[i] >> 8) & 0xFF; + r[4*i+2] = (m->counter[i] >> 16) & 0xFF; + r[4*i+3] = (m->counter[i] >> 24) & 0xFF; + } + } +#if 0 + { + int i; + uint32_t *r = (uint32_t *)res; + + for (i = 0; i < 4; ++i) + r[i] = swap_uint32_t (m->counter[i]); + } +#endif + return 1; +} diff --git a/third_party/heimdal/lib/hcrypto/md5.h b/third_party/heimdal/lib/hcrypto/md5.h new file mode 100644 index 0000000..ab1ac35 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/md5.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_MD5_H +#define HEIM_MD5_H 1 + +/* symbol renaming */ +#define MD5_Init hc_MD5_Init +#define MD5_Update hc_MD5_Update +#define MD5_Final hc_MD5_Final + +/* + * + */ + +#define MD5_DIGEST_LENGTH 16 + +struct md5 { + unsigned int sz[2]; + uint32_t counter[4]; + unsigned char save[64]; +}; + +typedef struct md5 MD5_CTX; + +int MD5_Init (struct md5 *m); +int MD5_Update (struct md5 *m, const void *p, size_t len); +int MD5_Final (void *res, struct md5 *m); /* uint32_t res[4] */ + +#endif /* HEIM_MD5_H */ diff --git a/third_party/heimdal/lib/hcrypto/md5crypt_test.c b/third_party/heimdal/lib/hcrypto/md5crypt_test.c new file mode 100644 index 0000000..f57c3ed --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/md5crypt_test.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +struct test { + const char *str; + const char *salt; + const char *result; +} tests[] = { + {"Hello world!", "$1$saltstring", "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"}, + {NULL, NULL, NULL} +}; + +static int +do_test (void) +{ + struct test *t; + int res = 0; + + for (t = tests; t->str != NULL; ++t) { + const char *c; + + c = crypt (t->str, t->salt); + + if (strcmp (c, t->result) != 0) { + res = 1; + printf ("should have been: \"%s\"\n", t->result); + printf ("result was: \"%s\"\n", c); + } + } + if (res) + printf ("failed\n"); + else + printf ("success\n"); + return res; +} + +int +main (void) +{ + return do_test (); +} diff --git a/third_party/heimdal/lib/hcrypto/mdtest.c b/third_party/heimdal/lib/hcrypto/mdtest.c new file mode 100644 index 0000000..7ad93e3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/mdtest.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 1995 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#define HC_DEPRECATED_CRYPTO + +#ifdef KRB5 +#include +#endif +#include +#include +#include +#include + +#define ONE_MILLION_A "one million a's" + +struct hash_foo { + const char *name; + size_t psize; + size_t hsize; + int (*init)(void*); + int (*update)(void*, const void*, size_t); + int (*final)(void*, void*); + const EVP_MD * (*evp)(void); +} md4 = { + "MD4", + sizeof(MD4_CTX), + 16, + (int (*)(void*))MD4_Init, + (int (*)(void*,const void*, size_t))MD4_Update, + (int (*)(void*, void*))MD4_Final, + EVP_md4 +}, md5 = { + "MD5", + sizeof(MD5_CTX), + 16, + (int (*)(void*))MD5_Init, + (int (*)(void*,const void*, size_t))MD5_Update, + (int (*)(void*, void*))MD5_Final, + EVP_md5 +}, sha1 = { + "SHA-1", + sizeof(struct sha), + 20, + (int (*)(void*))SHA1_Init, + (int (*)(void*,const void*, size_t))SHA1_Update, + (int (*)(void*, void*))SHA1_Final, + EVP_sha1 +}; +struct hash_foo sha256 = { + "SHA-256", + sizeof(SHA256_CTX), + 32, + (int (*)(void*))SHA256_Init, + (int (*)(void*,const void*, size_t))SHA256_Update, + (int (*)(void*, void*))SHA256_Final, + EVP_sha256 +}; +struct hash_foo sha384 = { + "SHA-384", + sizeof(SHA384_CTX), + 48, + (int (*)(void*))SHA384_Init, + (int (*)(void*,const void*, size_t))SHA384_Update, + (int (*)(void*, void*))SHA384_Final, + EVP_sha384 +}; +struct hash_foo sha512 = { + "SHA-512", + sizeof(SHA512_CTX), + 64, + (int (*)(void*))SHA512_Init, + (int (*)(void*,const void*, size_t))SHA512_Update, + (int (*)(void*, void*))SHA512_Final, + EVP_sha512 +}; + +struct test { + char *str; + unsigned char hash[64]; +}; + +struct test md4_tests[] = { + {"", + {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, 0xb7, 0x3c, 0x59, + 0xd7, 0xe0, 0xc0, 0x89, 0xc0}}, + {"a", + {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, + 0xfb, 0xdb, 0xd6, 0xfb, 0x24}}, + {"abc", + {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d}}, + {"message digest", + {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b}}, + {"abcdefghijklmnopqrstuvwxyz", {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9, }}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4}}, + {"12345678901234567890123456789012345678901234567890123456789012345678901234567890", + {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36, }}, + {NULL, { 0x0 }}}; + +struct test md5_tests[] = { + {"", {0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e}}, + {"a", {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61}}, + {"abc", {0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72}}, + {"message digest", {0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0}}, + {"abcdefghijklmnopqrstuvwxyz", {0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b}}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", {0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f}}, + {"12345678901234567890123456789012345678901234567890123456789012345678901234567890", {0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a}}, + {NULL, { 0x0 }}}; + +struct test sha1_tests[] = { + { "abc", + {0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, + 0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, + 0x9C, 0xD0, 0xD8, 0x9D}}, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + {0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, + 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, + 0xE5, 0x46, 0x70, 0xF1}}, + { ONE_MILLION_A, + {0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, + 0xf6, 0x1e, 0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, + 0x65, 0x34, 0x01, 0x6f}}, + { NULL, { 0 } } +}; + +struct test sha256_tests[] = { + { "abc", + { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }}, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }}, + { ONE_MILLION_A, + {0xcd,0xc7,0x6e,0x5c, 0x99,0x14,0xfb,0x92, + 0x81,0xa1,0xc7,0xe2, 0x84,0xd7,0x3e,0x67, + 0xf1,0x80,0x9a,0x48, 0xa4,0x97,0x20,0x0e, + 0x04,0x6d,0x39,0xcc, 0xc7,0x11,0x2c,0xd0 }}, + { NULL, { 0 } } +}; + +struct test sha384_tests[] = { + { "abc", + { 0xcb,0x00,0x75,0x3f,0x45,0xa3,0x5e,0x8b, + 0xb5,0xa0,0x3d,0x69,0x9a,0xc6,0x50,0x07, + 0x27,0x2c,0x32,0xab,0x0e,0xde,0xd1,0x63, + 0x1a,0x8b,0x60,0x5a,0x43,0xff,0x5b,0xed, + 0x80,0x86,0x07,0x2b,0xa1,0xe7,0xcc,0x23, + 0x58,0xba,0xec,0xa1,0x34,0xc8,0x25,0xa7}}, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + "ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x09,0x33,0x0c,0x33,0xf7,0x11,0x47,0xe8, + 0x3d,0x19,0x2f,0xc7,0x82,0xcd,0x1b,0x47, + 0x53,0x11,0x1b,0x17,0x3b,0x3b,0x05,0xd2, + 0x2f,0xa0,0x80,0x86,0xe3,0xb0,0xf7,0x12, + 0xfc,0xc7,0xc7,0x1a,0x55,0x7e,0x2d,0xb9, + 0x66,0xc3,0xe9,0xfa,0x91,0x74,0x60,0x39}}, + { ONE_MILLION_A, + { 0x9d,0x0e,0x18,0x09,0x71,0x64,0x74,0xcb, + 0x08,0x6e,0x83,0x4e,0x31,0x0a,0x4a,0x1c, + 0xed,0x14,0x9e,0x9c,0x00,0xf2,0x48,0x52, + 0x79,0x72,0xce,0xc5,0x70,0x4c,0x2a,0x5b, + 0x07,0xb8,0xb3,0xdc,0x38,0xec,0xc4,0xeb, + 0xae,0x97,0xdd,0xd8,0x7f,0x3d,0x89,0x85}}, + {NULL, { 0 }} +}; + +struct test sha512_tests[] = { + { "abc", + { 0xdd,0xaf,0x35,0xa1,0x93,0x61,0x7a,0xba, + 0xcc,0x41,0x73,0x49,0xae,0x20,0x41,0x31, + 0x12,0xe6,0xfa,0x4e,0x89,0xa9,0x7e,0xa2, + 0x0a,0x9e,0xee,0xe6,0x4b,0x55,0xd3,0x9a, + 0x21,0x92,0x99,0x2a,0x27,0x4f,0xc1,0xa8, + 0x36,0xba,0x3c,0x23,0xa3,0xfe,0xeb,0xbd, + 0x45,0x4d,0x44,0x23,0x64,0x3c,0xe8,0x0e, + 0x2a,0x9a,0xc9,0x4f,0xa5,0x4c,0xa4,0x9f }}, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + "ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x8e,0x95,0x9b,0x75,0xda,0xe3,0x13,0xda, + 0x8c,0xf4,0xf7,0x28,0x14,0xfc,0x14,0x3f, + 0x8f,0x77,0x79,0xc6,0xeb,0x9f,0x7f,0xa1, + 0x72,0x99,0xae,0xad,0xb6,0x88,0x90,0x18, + 0x50,0x1d,0x28,0x9e,0x49,0x00,0xf7,0xe4, + 0x33,0x1b,0x99,0xde,0xc4,0xb5,0x43,0x3a, + 0xc7,0xd3,0x29,0xee,0xb6,0xdd,0x26,0x54, + 0x5e,0x96,0xe5,0x5b,0x87,0x4b,0xe9,0x09 }}, + { ONE_MILLION_A, + { 0xe7,0x18,0x48,0x3d,0x0c,0xe7,0x69,0x64, + 0x4e,0x2e,0x42,0xc7,0xbc,0x15,0xb4,0x63, + 0x8e,0x1f,0x98,0xb1,0x3b,0x20,0x44,0x28, + 0x56,0x32,0xa8,0x03,0xaf,0xa9,0x73,0xeb, + 0xde,0x0f,0xf2,0x44,0x87,0x7e,0xa6,0x0a, + 0x4c,0xb0,0x43,0x2c,0xe5,0x77,0xc3,0x1b, + 0xeb,0x00,0x9c,0x5c,0x2c,0x49,0xaa,0x2e, + 0x4e,0xad,0xb2,0x17,0xad,0x8c,0xc0,0x9b }}, + { NULL, { 0 } } +}; + +static int +hash_test (struct hash_foo *hash, struct test *tests) +{ + struct test *t; + EVP_MD_CTX *ectx; + unsigned int esize; + void *ctx = malloc(hash->psize); + unsigned char *res = malloc(hash->hsize); + + printf ("%s... ", hash->name); + for (t = tests; t->str; ++t) { + char buf[1000]; + + ectx = EVP_MD_CTX_create(); + if (hash->evp() == NULL) { + printf("unavailable\n"); + continue; + } + EVP_DigestInit_ex(ectx, hash->evp(), NULL); + + (*hash->init)(ctx); + if(strcmp(t->str, ONE_MILLION_A) == 0) { + int i; + memset(buf, 'a', sizeof(buf)); + for(i = 0; i < 1000; i++) { + (*hash->update)(ctx, buf, sizeof(buf)); + EVP_DigestUpdate(ectx, buf, sizeof(buf)); + } + } else { + (*hash->update)(ctx, (unsigned char *)t->str, strlen(t->str)); + EVP_DigestUpdate(ectx, t->str, strlen(t->str)); + } + + (*hash->final) (res, ctx); + if (memcmp (res, t->hash, hash->hsize) != 0) { + int i; + + printf ("%s(\"%s\") failed\n", hash->name, t->str); + printf("should be: "); + for(i = 0; i < hash->hsize; ++i) { + if(i > 0 && (i % 16) == 0) + printf("\n "); + printf("%02x ", t->hash[i]); + } + printf("\nresult was: "); + for(i = 0; i < hash->hsize; ++i) { + if(i > 0 && (i % 16) == 0) + printf("\n "); + printf("%02x ", res[i]); + } + printf("\n"); + return 1; + } + + EVP_DigestFinal_ex(ectx, res, &esize); + EVP_MD_CTX_destroy(ectx); + + if (hash->hsize != esize) { + printf("EVP %s returned wrong hash size\n", hash->name); + return 1; + } + + if (memcmp (res, t->hash, hash->hsize) != 0) { + printf("EVP %s failed here old function where successful!\n", + hash->name); + return 1; + } + } + free(ctx); + free(res); + printf ("success\n"); + return 0; +} + +int +main (void) +{ + return + hash_test(&md4, md4_tests) + + hash_test(&md5, md5_tests) + + hash_test(&sha1, sha1_tests) + + hash_test(&sha256, sha256_tests) + + hash_test(&sha384, sha384_tests) + + hash_test(&sha512, sha512_tests); +} diff --git a/third_party/heimdal/lib/hcrypto/passwd_dialog.aps b/third_party/heimdal/lib/hcrypto/passwd_dialog.aps new file mode 100644 index 0000000..c90d030 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/passwd_dialog.aps differ diff --git a/third_party/heimdal/lib/hcrypto/passwd_dialog.clw b/third_party/heimdal/lib/hcrypto/passwd_dialog.clw new file mode 100644 index 0000000..f3451af --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/passwd_dialog.clw @@ -0,0 +1,34 @@ +; CLW file contains information for the MFC ClassWizard + +[General Info] +Version=1 +LastClass= +LastTemplate=CDialog +NewFileInclude1=#include "stdafx.h" +NewFileInclude2=#include "passwd_dialog.h" +LastPage=0 + +ClassCount=0 + +ResourceCount=2 +Resource1=IDD_DIALOG1 +Resource2=IDD_PASSWD_DIALOG + +[DLG:IDD_DIALOG1] +Type=1 +ControlCount=6 +Control1=IDOK,button,1342242817 +Control2=IDCANCEL,button,1342242816 +Control3=IDC_STATIC,static,1342308352 +Control4=IDC_STATIC,static,1342308352 +Control5=IDC_EDIT1,edit,1350631552 +Control6=IDC_EDIT2,edit,1350631584 + +[DLG:IDD_PASSWD_DIALOG] +Type=1 +ControlCount=4 +Control1=IDC_PASSWD_EDIT,edit,1350631456 +Control2=IDOK,button,1342242817 +Control3=IDCANCEL,button,1342242816 +Control4=IDC_STATIC,static,1342177280 + diff --git a/third_party/heimdal/lib/hcrypto/passwd_dialog.rc b/third_party/heimdal/lib/hcrypto/passwd_dialog.rc new file mode 100644 index 0000000..62079f2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/passwd_dialog.rc @@ -0,0 +1,143 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Swedish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) +#ifdef _WIN32 +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PASSWD_DIALOG DIALOG DISCARDABLE 0, 0, 186, 66 +STYLE DS_ABSALIGN | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | + WS_VISIBLE | WS_CAPTION +CAPTION "Password query" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_PASSWD_EDIT,30,22,125,14,ES_PASSWORD + DEFPUSHBUTTON "OK",IDOK,30,45,50,14 + PUSHBUTTON "Cancel",IDCANCEL,105,45,50,14 + LTEXT "Please insert password:",IDC_STATIC,30,13,87,8,NOT + WS_GROUP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_PASSWD_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 59 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Royal Institute of Technology (KTH)\0" + VALUE "FileDescription", "des\0" + VALUE "FileVersion", "4, 0, 9, 9\0" + VALUE "InternalName", "des\0" + VALUE "LegalCopyright", "Copyright 1996 - 1998 Royal Institute of Technology (KTH)\0" + VALUE "OriginalFilename", "des.dll\0" + VALUE "ProductName", "KTH Kerberos\0" + VALUE "ProductVersion", "4,0,9,9\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // Swedish resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/third_party/heimdal/lib/hcrypto/passwd_dialog.res b/third_party/heimdal/lib/hcrypto/passwd_dialog.res new file mode 100644 index 0000000..bdb2868 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/passwd_dialog.res differ diff --git a/third_party/heimdal/lib/hcrypto/passwd_dlg.c b/third_party/heimdal/lib/hcrypto/passwd_dlg.c new file mode 100644 index 0000000..3072116 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/passwd_dlg.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* passwd_dlg.c - Dialog boxes for Windows95/NT + * Author: Jörgen Karlsson - d93-jka@nada.kth.se + * Date: June 1996 + */ + +#include +#include + +#ifdef WIN32 /* Visual C++ 4.0 (Windows95/NT) */ +#include "passwd_dlg.h" +#include "Resource.h" +#define passwdBufSZ 64 + +char passwd[passwdBufSZ]; + +BOOL CALLBACK +pwd_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_COMMAND: + switch(wParam) + { + case IDOK: + if(!GetDlgItemText(hwndDlg,IDC_PASSWD_EDIT, passwd, passwdBufSZ)) + EndDialog(hwndDlg, IDCANCEL); + case IDCANCEL: + EndDialog(hwndDlg, wParam); + return TRUE; + } + } + return FALSE; +} + + +/* return 0 if ok, 1 otherwise */ +int +pwd_dialog(char *buf, int size) +{ + int i; + HWND wnd = GetActiveWindow(); + HANDLE hInst = GetModuleHandle("des"); + switch(DialogBox(hInst,MAKEINTRESOURCE(IDD_PASSWD_DIALOG),wnd,pwd_dialog_proc)) + { + case IDOK: + strlcpy(buf, passwd, size); + memset_s (passwd, sizeof(passwd), 0, sizeof(passwd)); + return 0; + case IDCANCEL: + default: + memset_s (passwd, sizeof(passwd), 0, sizeof(passwd)); + return 1; + } +} + +#endif /* WIN32 */ diff --git a/third_party/heimdal/lib/hcrypto/passwd_dlg.h b/third_party/heimdal/lib/hcrypto/passwd_dlg.h new file mode 100644 index 0000000..222417d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/passwd_dlg.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* passwd_dlg.h - Dialog boxes for Windows95/NT + * Author: Jörgen Karlsson - d93-jka@nada.kth.se + * Date: June 1996 + */ + +/* $Id$ */ + +#ifndef PASSWD_DLG_H +#define PASSWD_DLG_H + +int pwd_dialog(char *buf, int size); + + +#endif /* PASSWD_DLG_H */ diff --git a/third_party/heimdal/lib/hcrypto/pkcs12.c b/third_party/heimdal/lib/hcrypto/pkcs12.c new file mode 100644 index 0000000..29fc524 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/pkcs12.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +int +PKCS12_key_gen(const void *key, size_t keylen, + const void *salt, size_t saltlen, + int id, int iteration, size_t outkeysize, + void *out, const EVP_MD *md) +{ + unsigned char *v, *I, hash[EVP_MAX_MD_SIZE]; + unsigned int size, size_I = 0; + unsigned char idc = id; + EVP_MD_CTX *ctx; + unsigned char *outp = out; + int i, vlen; + + /** + * The argument key is pointing to an utf16 string, and thus + * keylen that is no a multiple of 2 is invalid. + */ + if (keylen & 1) + return 0; + + ctx = EVP_MD_CTX_create(); + if (ctx == NULL) + return 0; + + vlen = EVP_MD_block_size(md); + v = malloc(vlen + 1); + if (v == NULL) { + EVP_MD_CTX_destroy(ctx); + return 0; + } + + I = calloc(1, vlen * 2); + if (I == NULL) { + EVP_MD_CTX_destroy(ctx); + free(v); + return 0; + } + + if (salt && saltlen > 0) { + for (i = 0; i < vlen; i++) + I[i] = ((const unsigned char*)salt)[i % saltlen]; + size_I += vlen; + } + /* + * There is a diffrence between the no password string and the + * empty string, in the empty string the UTF16 NUL terminator is + * included into the string. + */ + if (key) { + for (i = 0; i < vlen / 2; i++) { + I[(i * 2) + size_I] = 0; + I[(i * 2) + size_I + 1] = ((const unsigned char*)key)[i % (keylen + 1)]; + } + size_I += vlen; + } + + while (1) { + BIGNUM *bnB, *bnOne; + + if (!EVP_DigestInit_ex(ctx, md, NULL)) { + EVP_MD_CTX_destroy(ctx); + free(I); + free(v); + return 0; + } + for (i = 0; i < vlen; i++) + EVP_DigestUpdate(ctx, &idc, 1); + EVP_DigestUpdate(ctx, I, size_I); + EVP_DigestFinal_ex(ctx, hash, &size); + + for (i = 1; i < iteration; i++) + EVP_Digest(hash, size, hash, &size, md, NULL); + + memcpy(outp, hash, min(outkeysize, size)); + if (outkeysize < size) + break; + outkeysize -= size; + outp += size; + + for (i = 0; i < vlen; i++) + v[i] = hash[i % size]; + + bnB = BN_bin2bn(v, vlen, NULL); + bnOne = BN_new(); + BN_set_word(bnOne, 1); + + BN_uadd(bnB, bnB, bnOne); + + for (i = 0; i < vlen * 2; i += vlen) { + BIGNUM *bnI; + int j; + + bnI = BN_bin2bn(I + i, vlen, NULL); + + BN_uadd(bnI, bnI, bnB); + + j = BN_num_bytes(bnI); + if (j > vlen) { + assert(j == vlen + 1); + BN_bn2bin(bnI, v); + memcpy(I + i, v + 1, vlen); + } else { + memset(I + i, 0, vlen - j); + BN_bn2bin(bnI, I + i + vlen - j); + } + BN_free(bnI); + } + BN_free(bnB); + BN_free(bnOne); + size_I = vlen * 2; + } + + EVP_MD_CTX_destroy(ctx); + free(I); + free(v); + + return 1; +} diff --git a/third_party/heimdal/lib/hcrypto/pkcs12.h b/third_party/heimdal/lib/hcrypto/pkcs12.h new file mode 100644 index 0000000..7e8214e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/pkcs12.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_PKCS12_H +#define _HEIM_PKCS12_H 1 + +/* symbol renaming */ +#define PKCS12_key_gen hc_PKCS12_key_gen + +/* + * + */ + +#include + +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 + +int PKCS12_key_gen(const void *, size_t, const void *, + size_t, int, int, size_t, void *, const EVP_MD *); + + +#endif /* _HEIM_PKCS12_H */ diff --git a/third_party/heimdal/lib/hcrypto/pkcs5.c b/third_party/heimdal/lib/hcrypto/pkcs5.c new file mode 100644 index 0000000..88e71c4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/pkcs5.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#ifdef KRB5 +#include +#endif + +#include +#include + +/** + * As descriped in PKCS5, convert a password, salt, and iteration counter into a crypto key. + * + * @param password Password. + * @param password_len Length of password. + * @param salt Salt + * @param salt_len Length of salt. + * @param iter iteration counter. + * @param md the digest function. + * @param keylen the output key length. + * @param key the output key. + * + * @return 1 on success, non 1 on failure. + * + * @ingroup hcrypto_misc + */ + +int +PKCS5_PBKDF2_HMAC(const void * password, size_t password_len, + const void * salt, size_t salt_len, + unsigned long iter, + const EVP_MD *md, + size_t keylen, void *key) +{ + size_t datalen, leftofkey, checksumsize; + char *data, *tmpcksum; + uint32_t keypart; + unsigned long i; + int j; + char *p; + unsigned int hmacsize; + + if (md == NULL) + return 0; + + checksumsize = EVP_MD_size(md); + datalen = salt_len + 4; + + tmpcksum = malloc(checksumsize + datalen); + if (tmpcksum == NULL) + return 0; + + data = &tmpcksum[checksumsize]; + + if (salt_len) + memcpy(data, salt, salt_len); + + keypart = 1; + leftofkey = keylen; + p = key; + + while (leftofkey) { + int len; + + if (leftofkey > checksumsize) + len = checksumsize; + else + len = leftofkey; + + data[datalen - 4] = (keypart >> 24) & 0xff; + data[datalen - 3] = (keypart >> 16) & 0xff; + data[datalen - 2] = (keypart >> 8) & 0xff; + data[datalen - 1] = (keypart) & 0xff; + + HMAC(md, password, password_len, data, datalen, + tmpcksum, &hmacsize); + + memcpy(p, tmpcksum, len); + for (i = 1; i < iter; i++) { + HMAC(md, password, password_len, tmpcksum, checksumsize, + tmpcksum, &hmacsize); + + for (j = 0; j < len; j++) + p[j] ^= tmpcksum[j]; + } + + p += len; + leftofkey -= len; + keypart++; + } + + free(tmpcksum); + + return 1; +} + +/** + * As descriped in PKCS5, convert a password, salt, and iteration counter into a crypto key. + * + * @param password Password. + * @param password_len Length of password. + * @param salt Salt + * @param salt_len Length of salt. + * @param iter iteration counter. + * @param keylen the output key length. + * @param key the output key. + * + * @return 1 on success, non 1 on failure. + * + * @ingroup hcrypto_misc + */ +int +PKCS5_PBKDF2_HMAC_SHA1(const void * password, size_t password_len, + const void * salt, size_t salt_len, + unsigned long iter, + size_t keylen, void *key) +{ + return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iter, + EVP_sha1(), keylen, key); +} diff --git a/third_party/heimdal/lib/hcrypto/rand-fortuna.c b/third_party/heimdal/lib/hcrypto/rand-fortuna.c new file mode 100644 index 0000000..31f7233 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand-fortuna.c @@ -0,0 +1,648 @@ +/* + * fortuna.c + * Fortuna-like PRNG. + * + * Copyright (c) 2005 Marko Kreen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.8 2006/10/04 00:29:46 momjian Exp $ + */ + +#include +#include +#include +#include + +#ifdef KRB5 +#include +#endif + +#include "randi.h" +#include "aes.h" +#include "sha.h" + +/* + * Why Fortuna-like: There does not seem to be any definitive reference + * on Fortuna in the net. Instead this implementation is based on + * following references: + * + * http://en.wikipedia.org/wiki/Fortuna_(PRNG) + * - Wikipedia article + * http://jlcooke.ca/random/ + * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux. + */ + +/* + * There is some confusion about whether and how to carry forward + * the state of the pools. Seems like original Fortuna does not + * do it, resetting hash after each request. I guess expecting + * feeding to happen more often that requesting. This is absolutely + * unsuitable for pgcrypto, as nothing asynchronous happens here. + * + * J.L. Cooke fixed this by feeding previous hash to new re-initialized + * hash context. + * + * Fortuna predecessor Yarrow requires ability to query intermediate + * 'final result' from hash, without affecting it. + * + * This implementation uses the Yarrow method - asking intermediate + * results, but continuing with old state. + */ + + +/* + * Algorithm parameters + */ + +#define NUM_POOLS 32 + +/* in microseconds */ +#define RESEED_INTERVAL 100000 /* 0.1 sec */ + +/* for one big request, reseed after this many bytes */ +#define RESEED_BYTES (1024*1024) + +/* + * Skip reseed if pool 0 has less than this many + * bytes added since last reseed. + */ +#define POOL0_FILL (256/8) + +/* + * Algorithm constants + */ + +/* Both cipher key size and hash result size */ +#define BLOCK 32 + +/* cipher block size */ +#define CIPH_BLOCK 16 + +/* for internal wrappers */ +#define MD_CTX SHA256_CTX +#define CIPH_CTX AES_KEY + +struct fortuna_state +{ + unsigned char counter[CIPH_BLOCK]; + unsigned char result[CIPH_BLOCK]; + unsigned char key[BLOCK]; + MD_CTX pool[NUM_POOLS]; + CIPH_CTX ciph; + unsigned reseed_count; + struct timeval last_reseed_time; + unsigned pool0_bytes; + unsigned rnd_pos; + int tricks_done; + pid_t pid; +}; +typedef struct fortuna_state FState; + + +/* + * Use our own wrappers here. + * - Need to get intermediate result from digest, without affecting it. + * - Need re-set key on a cipher context. + * - Algorithms are guaranteed to exist. + * - No memory allocations. + */ + +static void +ciph_init(CIPH_CTX * ctx, const unsigned char *key, int klen) +{ + AES_set_encrypt_key(key, klen * 8, ctx); +} + +static void +ciph_encrypt(CIPH_CTX * ctx, const unsigned char *in, unsigned char *out) +{ + AES_encrypt(in, out, ctx); +} + +static void +md_init(MD_CTX * ctx) +{ + SHA256_Init(ctx); +} + +static void +md_update(MD_CTX * ctx, const unsigned char *data, int len) +{ + SHA256_Update(ctx, data, len); +} + +static void +md_result(MD_CTX * ctx, unsigned char *dst) +{ + SHA256_CTX tmp; + + memcpy(&tmp, ctx, sizeof(*ctx)); + SHA256_Final(dst, &tmp); + memset_s(&tmp, sizeof(tmp), 0, sizeof(tmp)); +} + +/* + * initialize state + */ +static void +init_state(FState * st) +{ + int i; + + memset(st, 0, sizeof(*st)); + for (i = 0; i < NUM_POOLS; i++) + md_init(&st->pool[i]); + st->pid = getpid(); +} + +/* + * Endianess does not matter. + * It just needs to change without repeating. + */ +static void +inc_counter(FState * st) +{ + uint32_t *val = (uint32_t *) st->counter; + + if (++val[0]) + return; + if (++val[1]) + return; + if (++val[2]) + return; + ++val[3]; +} + +/* + * This is called 'cipher in counter mode'. + */ +static void +encrypt_counter(FState * st, unsigned char *dst) +{ + ciph_encrypt(&st->ciph, st->counter, dst); + inc_counter(st); +} + + +/* + * The time between reseed must be at least RESEED_INTERVAL + * microseconds. + */ +static int +enough_time_passed(FState * st) +{ + int ok; + struct timeval tv; + struct timeval *last = &st->last_reseed_time; + + gettimeofday(&tv, NULL); + + /* check how much time has passed */ + ok = 0; + if (tv.tv_sec > last->tv_sec + 1) + ok = 1; + else if (tv.tv_sec == last->tv_sec + 1) + { + if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + ok = 1; + } + else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + ok = 1; + + /* reseed will happen, update last_reseed_time */ + if (ok) + memcpy(last, &tv, sizeof(tv)); + + memset_s(&tv, sizeof(tv), 0, sizeof(tv)); + + return ok; +} + +/* + * generate new key from all the pools + */ +static void +reseed(FState * st) +{ + unsigned k; + unsigned n; + MD_CTX key_md; + unsigned char buf[BLOCK]; + + /* set pool as empty */ + st->pool0_bytes = 0; + + /* + * Both #0 and #1 reseed would use only pool 0. Just skip #0 then. + */ + n = ++st->reseed_count; + + /* + * The goal: use k-th pool only 1/(2^k) of the time. + */ + md_init(&key_md); + for (k = 0; k < NUM_POOLS; k++) + { + md_result(&st->pool[k], buf); + md_update(&key_md, buf, BLOCK); + + if (n & 1 || !n) + break; + n >>= 1; + } + + /* add old key into mix too */ + md_update(&key_md, st->key, BLOCK); + + /* add pid to make output diverse after fork() */ + md_update(&key_md, (const unsigned char *)&st->pid, sizeof(st->pid)); + + /* now we have new key */ + md_result(&key_md, st->key); + + /* use new key */ + ciph_init(&st->ciph, st->key, BLOCK); + + memset_s(&key_md, sizeof(key_md), 0, sizeof(key_md)); + memset_s(buf, sizeof(buf), 0, sizeof(buf)); +} + +/* + * Pick a random pool. This uses key bytes as random source. + */ +static unsigned +get_rand_pool(FState * st) +{ + unsigned rnd; + + /* + * This slightly prefers lower pools - thats OK. + */ + rnd = st->key[st->rnd_pos] % NUM_POOLS; + + st->rnd_pos++; + if (st->rnd_pos >= BLOCK) + st->rnd_pos = 0; + + return rnd; +} + +/* + * update pools + */ +static void +add_entropy(FState * st, const unsigned char *data, unsigned len) +{ + unsigned pos; + unsigned char hash[BLOCK]; + MD_CTX md; + + /* hash given data */ + md_init(&md); + md_update(&md, data, len); + md_result(&md, hash); + + /* + * Make sure the pool 0 is initialized, then update randomly. + */ + if (st->reseed_count == 0) + pos = 0; + else + pos = get_rand_pool(st); + md_update(&st->pool[pos], hash, BLOCK); + + if (pos == 0) + st->pool0_bytes += len; + + memset_s(hash, sizeof(hash), 0, sizeof(hash)); + memset_s(&md, sizeof(md), 0, sizeof(md)); +} + +/* + * Just take 2 next blocks as new key + */ +static void +rekey(FState * st) +{ + encrypt_counter(st, st->key); + encrypt_counter(st, st->key + CIPH_BLOCK); + ciph_init(&st->ciph, st->key, BLOCK); +} + +/* + * Hide public constants. (counter, pools > 0) + * + * This can also be viewed as spreading the startup + * entropy over all of the components. + */ +static void +startup_tricks(FState * st) +{ + int i; + unsigned char buf[BLOCK]; + + /* Use next block as counter. */ + encrypt_counter(st, st->counter); + + /* Now shuffle pools, excluding #0 */ + for (i = 1; i < NUM_POOLS; i++) + { + encrypt_counter(st, buf); + encrypt_counter(st, buf + CIPH_BLOCK); + md_update(&st->pool[i], buf, BLOCK); + } + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + + /* Hide the key. */ + rekey(st); + + /* This can be done only once. */ + st->tricks_done = 1; +} + +static void +extract_data(FState * st, unsigned count, unsigned char *dst) +{ + unsigned n; + unsigned block_nr = 0; + pid_t pid = getpid(); + + /* Should we reseed? */ + if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0) + if (enough_time_passed(st)) + reseed(st); + + /* Do some randomization on first call */ + if (!st->tricks_done) + startup_tricks(st); + + /* If we forked, force a reseed again */ + if (pid != st->pid) { + st->pid = pid; + reseed(st); + } + + while (count > 0) + { + /* produce bytes */ + encrypt_counter(st, st->result); + + /* copy result */ + if (count > CIPH_BLOCK) + n = CIPH_BLOCK; + else + n = count; + memcpy(dst, st->result, n); + dst += n; + count -= n; + + /* must not give out too many bytes with one key */ + block_nr++; + if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) + { + rekey(st); + block_nr = 0; + } + } + /* Set new key for next request. */ + rekey(st); +} + +/* + * public interface + */ + +static FState main_state; +static int init_done; +static int have_entropy; +#define FORTUNA_RESEED_BYTE 10000 +static unsigned resend_bytes; + +/* + * This mutex protects all of the above static elements from concurrent + * access by multiple threads + */ +static HEIMDAL_MUTEX fortuna_mutex = HEIMDAL_MUTEX_INITIALIZER; + +/* + * Try our best to do an initial seed + */ +#define INIT_BYTES 128 + +/* + * fortuna_mutex must be held across calls to this function + */ + +static int +fortuna_reseed(void) +{ + int entropy_p = 0; + + if (!init_done) + abort(); + +#ifndef NO_RAND_UNIX_METHOD + { + unsigned char buf[INIT_BYTES]; + if ((*hc_rand_unix_method.bytes)(buf, sizeof(buf)) == 1) { + add_entropy(&main_state, buf, sizeof(buf)); + entropy_p = 1; + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + } + } +#endif +#ifdef HAVE_ARC4RANDOM + { + uint32_t buf[INIT_BYTES / sizeof(uint32_t)]; + int i; + + for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) + buf[i] = arc4random(); + add_entropy(&main_state, (void *)buf, sizeof(buf)); + entropy_p = 1; + } +#endif + /* + * Fall back to gattering data from timer and secret files, this + * is really the last resort. + */ + if (!entropy_p) { + /* to save stackspace */ + union { + unsigned char buf[INIT_BYTES]; + unsigned char shad[1001]; + } u; + int fd; + + /* add timer info */ + if ((*hc_rand_timer_method.bytes)(u.buf, sizeof(u.buf)) == 1) + add_entropy(&main_state, u.buf, sizeof(u.buf)); + /* add /etc/shadow */ + fd = open("/etc/shadow", O_RDONLY, 0); + if (fd >= 0) { + rk_cloexec(fd); + /* add_entropy will hash the buf */ + while (read(fd, (char *)u.shad, sizeof(u.shad)) > 0) + add_entropy(&main_state, u.shad, sizeof(u.shad)); + close(fd); + } + + memset_s(&u, sizeof(u), 0, sizeof(u)); + + entropy_p = 1; /* sure about this ? */ + } + { + pid_t pid = getpid(); + add_entropy(&main_state, (void *)&pid, sizeof(pid)); + } + { + struct timeval tv; + gettimeofday(&tv, NULL); + add_entropy(&main_state, (void *)&tv, sizeof(tv)); + } +#ifdef HAVE_GETUID + { + uid_t u = getuid(); + add_entropy(&main_state, (void *)&u, sizeof(u)); + } +#endif + return entropy_p; +} + +/* + * fortuna_mutex must be held by callers of this function + */ +static int +fortuna_init(void) +{ + if (!init_done) + { + init_state(&main_state); + init_done = 1; + } + if (!have_entropy) + have_entropy = fortuna_reseed(); + return (init_done && have_entropy); +} + + + +static void +fortuna_seed(const void *indata, int size) +{ + HEIMDAL_MUTEX_lock(&fortuna_mutex); + + fortuna_init(); + add_entropy(&main_state, indata, size); + if (size >= INIT_BYTES) + have_entropy = 1; + + HEIMDAL_MUTEX_unlock(&fortuna_mutex); +} + +static int +fortuna_bytes(unsigned char *outdata, int size) +{ + int ret = 0; + + HEIMDAL_MUTEX_lock(&fortuna_mutex); + + if (!fortuna_init()) + goto out; + + resend_bytes += size; + if (resend_bytes > FORTUNA_RESEED_BYTE || resend_bytes < size) { + resend_bytes = 0; + fortuna_reseed(); + } + extract_data(&main_state, size, outdata); + ret = 1; + +out: + HEIMDAL_MUTEX_unlock(&fortuna_mutex); + + return ret; +} + +static void +fortuna_cleanup(void) +{ + HEIMDAL_MUTEX_lock(&fortuna_mutex); + + init_done = 0; + have_entropy = 0; + memset_s(&main_state, sizeof(main_state), 0, sizeof(main_state)); + + HEIMDAL_MUTEX_unlock(&fortuna_mutex); +} + +static void +fortuna_add(const void *indata, int size, double entropi) +{ + fortuna_seed(indata, size); +} + +static int +fortuna_pseudorand(unsigned char *outdata, int size) +{ + return fortuna_bytes(outdata, size); +} + +static int +fortuna_status(void) +{ + int result; + + HEIMDAL_MUTEX_lock(&fortuna_mutex); + result = fortuna_init(); + HEIMDAL_MUTEX_unlock(&fortuna_mutex); + + return result ? 1 : 0; +} + +#if defined(__GNUC__) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +const RAND_METHOD hc_rand_fortuna_method = { + .seed = fortuna_seed, + .bytes = fortuna_bytes, + .cleanup = fortuna_cleanup, + .add = fortuna_add, + .pseudorand = fortuna_pseudorand, + .status = fortuna_status +}; +#else +const RAND_METHOD hc_rand_fortuna_method = { + fortuna_seed, + fortuna_bytes, + fortuna_cleanup, + fortuna_add, + fortuna_pseudorand, + fortuna_status +}; +#endif + +const RAND_METHOD * +RAND_fortuna_method(void) +{ + return &hc_rand_fortuna_method; +} diff --git a/third_party/heimdal/lib/hcrypto/rand-timer.c b/third_party/heimdal/lib/hcrypto/rand-timer.c new file mode 100644 index 0000000..935a3a7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand-timer.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 1995, 1996, 1997, 1999, 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +#include "randi.h" + +#ifndef WIN32 /* don't bother with this on windows */ + +static volatile int counter; +static volatile unsigned char *gdata; /* Global data */ +static volatile int igdata; /* Index into global data */ +static int gsize; + +static +RETSIGTYPE +sigALRM(int sig) +{ + if (igdata < gsize) + gdata[igdata++] ^= counter & 0xff; + +#ifndef HAVE_SIGACTION + signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */ +#endif + SIGRETURN(0); +} + +#ifndef HAVE_SETITIMER +static void +pacemaker(struct timeval *tv) +{ + fd_set fds; + pid_t pid; + pid = getppid(); + while(1){ + FD_ZERO(&fds); + FD_SET(0, &fds); + select(1, &fds, NULL, NULL, tv); + kill(pid, SIGALRM); + } +} +#endif + +#ifdef HAVE_SIGACTION +/* XXX ugly hack, should perhaps use function from roken */ +static RETSIGTYPE +(*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int) +{ + struct sigaction sa, osa; + sa.sa_handler = f; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sig, &sa, &osa); + return osa.sa_handler; +} +#define signal(S, F) fake_signal((S), (F)) +#endif + +#endif /* WIN32*/ + +/* + * + */ + +static void +timer_seed(const void *indata, int size) +{ +} + +static int +timer_bytes(unsigned char *outdata, int size) +{ +#ifdef WIN32 + return 0; +#else /* WIN32 */ + struct itimerval tv, otv; + RETSIGTYPE (*osa)(int); + int i, j; +#ifndef HAVE_SETITIMER + RETSIGTYPE (*ochld)(int); + pid_t pid; +#endif + + gdata = outdata; + gsize = size; + igdata = 0; + + osa = signal(SIGALRM, sigALRM); + + /* Start timer */ + tv.it_value.tv_sec = 0; + tv.it_value.tv_usec = 10 * 1000; /* 10 ms */ + tv.it_interval = tv.it_value; +#ifdef HAVE_SETITIMER + setitimer(ITIMER_REAL, &tv, &otv); +#else + ochld = signal(SIGCHLD, SIG_IGN); + pid = fork(); + if(pid == -1){ + signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL); + des_not_rand_data(data, size); + return; + } + if(pid == 0) + pacemaker(&tv.it_interval); +#endif + + for(i = 0; i < 4; i++) { + for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */ + counter++; + for (j = 0; j < size; j++) /* Only use 2 bits each lap */ + gdata[j] = (gdata[j]>>2) | (gdata[j]<<6); + } +#ifdef HAVE_SETITIMER + setitimer(ITIMER_REAL, &otv, 0); +#else + kill(pid, SIGKILL); + while(waitpid(pid, NULL, 0) != pid); + signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL); +#endif + signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL); + + return 1; +#endif +} + +static void +timer_cleanup(void) +{ +} + +static void +timer_add(const void *indata, int size, double entropi) +{ +} + +static int +timer_pseudorand(unsigned char *outdata, int size) +{ + return timer_bytes(outdata, size); +} + +static int +timer_status(void) +{ +#ifdef WIN32 + return 0; +#else + return 1; +#endif +} + +#if defined(__GNUC__) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +const RAND_METHOD hc_rand_timer_method = { + .seed = timer_seed, + .bytes = timer_bytes, + .cleanup = timer_cleanup, + .add = timer_add, + .pseudorand = timer_pseudorand, + .status = timer_status +}; +#else +const RAND_METHOD hc_rand_timer_method = { + timer_seed, + timer_bytes, + timer_cleanup, + timer_add, + timer_pseudorand, + timer_status +}; +#endif + +const RAND_METHOD * +RAND_timer_method(void) +{ + return &hc_rand_timer_method; +} diff --git a/third_party/heimdal/lib/hcrypto/rand-unix.c b/third_party/heimdal/lib/hcrypto/rand-unix.c new file mode 100644 index 0000000..2d6013e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand-unix.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include "randi.h" + +/* + * Unix /dev/random + */ + +int +_hc_unix_device_fd(int flags, const char **fn) +{ + static const char *rnd_devices[] = { + "/dev/urandom", + "/dev/random", + "/dev/srandom", + "/dev/arandom", + NULL + }; + const char **p; + + for(p = rnd_devices; *p; p++) { + int fd = open(*p, flags | O_NDELAY); + if(fd >= 0) { + if (fn) + *fn = *p; + rk_cloexec(fd); + return fd; + } + } + return -1; +} + +static void +unix_seed(const void *p, int size) +{ + const unsigned char *indata = p; + ssize_t count; + int fd; + + if (size < 0) + return; + else if (size == 0) + return; + + fd = _hc_unix_device_fd(O_RDONLY, NULL); + if (fd < 0) + return; + + while (size > 0) { + count = write(fd, indata, size); + if (count < 0 && errno == EINTR) + continue; + else if (count <= 0) { + close(fd); + return; + } + indata += count; + size -= count; + } + close(fd); +} + + +static int +unix_bytes(unsigned char *outdata, int size) +{ + ssize_t count; + int fd; + + if (size < 0) + return 0; + else if (size == 0) + return 1; + + fd = _hc_unix_device_fd(O_RDONLY, NULL); + if (fd < 0) + return 0; + + while (size > 0) { + count = read(fd, outdata, size); + if (count < 0 && errno == EINTR) + continue; + else if (count <= 0) { + close(fd); + return 0; + } + outdata += count; + size -= count; + } + close(fd); + + return 1; +} + +static void +unix_cleanup(void) +{ +} + +static void +unix_add(const void *indata, int size, double entropi) +{ + unix_seed(indata, size); +} + +static int +unix_pseudorand(unsigned char *outdata, int size) +{ + return unix_bytes(outdata, size); +} + +static int +unix_status(void) +{ + int fd; + + fd = _hc_unix_device_fd(O_RDONLY, NULL); + if (fd < 0) + return 0; + close(fd); + + return 1; +} + +const RAND_METHOD hc_rand_unix_method = { + unix_seed, + unix_bytes, + unix_cleanup, + unix_add, + unix_pseudorand, + unix_status +}; + +const RAND_METHOD * +RAND_unix_method(void) +{ + return &hc_rand_unix_method; +} diff --git a/third_party/heimdal/lib/hcrypto/rand-w32.c b/third_party/heimdal/lib/hcrypto/rand-w32.c new file mode 100644 index 0000000..d7d91a3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand-w32.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +#include +#include + +#include "randi.h" + +volatile static HCRYPTPROV g_cryptprovider; + +static HCRYPTPROV +_hc_CryptProvider(void) +{ + BOOL rv; + HCRYPTPROV cryptprovider = (HCRYPTPROV)0; + + if (g_cryptprovider) + goto out; + + rv = CryptAcquireContext(&cryptprovider, NULL, + MS_ENHANCED_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + + if (GetLastError() == NTE_BAD_KEYSET) { + rv = CryptAcquireContext(&cryptprovider, NULL, + MS_ENHANCED_PROV, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + } + + if (rv) { + /* try the default provider */ + rv = CryptAcquireContext(&cryptprovider, NULL, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + + if (GetLastError() == NTE_BAD_KEYSET) { + rv = CryptAcquireContext(&cryptprovider, NULL, + MS_ENHANCED_PROV, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + } + } + + if (rv) { + /* try just a default random number generator */ + rv = CryptAcquireContext(&cryptprovider, NULL, 0, PROV_RNG, + CRYPT_VERIFYCONTEXT); + } + + if (rv == 0 && + InterlockedCompareExchangePointer((PVOID *) &g_cryptprovider, + (PVOID) cryptprovider, NULL) != 0) { + + CryptReleaseContext(cryptprovider, 0); + } + +out: + return g_cryptprovider; +} + +/* + * + */ + + +static void +w32crypto_seed(const void *indata, int size) +{ +} + + +static int +w32crypto_bytes(unsigned char *outdata, int size) +{ + if (CryptGenRandom(_hc_CryptProvider(), size, outdata)) + return 1; + return 0; +} + +static void +w32crypto_cleanup(void) +{ + HCRYPTPROV cryptprovider; + + if (InterlockedCompareExchangePointer((PVOID *) &cryptprovider, + 0, (PVOID) g_cryptprovider) == 0) { + CryptReleaseContext(cryptprovider, 0); + } +} + +static void +w32crypto_add(const void *indata, int size, double entropi) +{ +} + +static int +w32crypto_status(void) +{ + if (_hc_CryptProvider() == 0) + return 0; + return 1; +} + +const RAND_METHOD hc_rand_w32crypto_method = { + w32crypto_seed, + w32crypto_bytes, + w32crypto_cleanup, + w32crypto_add, + w32crypto_bytes, + w32crypto_status +}; + +const RAND_METHOD * +RAND_w32crypto_method(void) +{ + return &hc_rand_w32crypto_method; +} diff --git a/third_party/heimdal/lib/hcrypto/rand.c b/third_party/heimdal/lib/hcrypto/rand.c new file mode 100644 index 0000000..893d5c6 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef _WIN32 +#include +#endif + +/** + * @page page_rand RAND - random number + * + * See the library functions here: @ref hcrypto_rand + */ + +static const RAND_METHOD *selected_meth = NULL; +static ENGINE *selected_engine = NULL; + +static void +init_method(void) +{ + if (selected_meth != NULL) + return; +#if defined(_WIN32) + selected_meth = &hc_rand_w32crypto_method; +#elif defined(__APPLE__) + selected_meth = &hc_rand_unix_method; +#else + selected_meth = &hc_rand_fortuna_method; +#endif +} + +/** + * Seed that random number generator. Secret material can securely be + * feed into the function, they will never be returned. + * + * @param indata seed data + * @param size length seed data + * + * @ingroup hcrypto_rand + */ + +void +RAND_seed(const void *indata, size_t size) +{ + init_method(); + (*selected_meth->seed)(indata, size); +} + +/** + * Get a random block from the random generator, can be used for key material. + * + * @param outdata random data + * @param size length random data + * + * @return 1 on success, 0 on failure. + * + * @ingroup hcrypto_rand + */ +int +RAND_bytes(void *outdata, size_t size) +{ + if (size == 0) + return 1; + init_method(); + return (*selected_meth->bytes)(outdata, size); +} + +/** + * Reset and free memory used by the random generator. + * + * @ingroup hcrypto_rand + */ + +void +RAND_cleanup(void) +{ + const RAND_METHOD *meth = selected_meth; + ENGINE *engine = selected_engine; + + selected_meth = NULL; + selected_engine = NULL; + + if (meth) + (*meth->cleanup)(); + if (engine) + ENGINE_finish(engine); +} + +/** + * Seed that random number generator. Secret material can securely be + * feed into the function, they will never be returned. + * + * @param indata the input data. + * @param size size of in data. + * @param entropi entropi in data. + * + * + * @ingroup hcrypto_rand + */ + +void +RAND_add(const void *indata, size_t size, double entropi) +{ + init_method(); + (*selected_meth->add)(indata, size, entropi); +} + +/** + * Get a random block from the random generator, should NOT be used for key material. + * + * @param outdata random data + * @param size length random data + * + * @return 1 on success, 0 on failure. + * + * @ingroup hcrypto_rand + */ + +int +RAND_pseudo_bytes(void *outdata, size_t size) +{ + init_method(); + return (*selected_meth->pseudorand)(outdata, size); +} + +/** + * Return status of the random generator + * + * @return 1 if the random generator can deliver random data. + * + * @ingroup hcrypto_rand + */ + +int +RAND_status(void) +{ + init_method(); + return (*selected_meth->status)(); +} + +/** + * Set the default random method. + * + * @param meth set the new default method. + * + * @return 1 on success. + * + * @ingroup hcrypto_rand + */ + +int +RAND_set_rand_method(const RAND_METHOD *meth) +{ + const RAND_METHOD *old = selected_meth; + selected_meth = meth; + if (old) + (*old->cleanup)(); + if (selected_engine) { + ENGINE_finish(selected_engine); + selected_engine = NULL; + } + return 1; +} + +/** + * Get the default random method. + * + * @return Returns a RAND_METHOD + * + * @ingroup hcrypto_rand + */ + +const RAND_METHOD * +RAND_get_rand_method(void) +{ + init_method(); + return selected_meth; +} + +/** + * Set the default random method from engine. + * + * @param engine use engine, if NULL is passed it, old method and engine is cleared. + * + * @return 1 on success, 0 on failure. + * + * @ingroup hcrypto_rand + */ + +int +RAND_set_rand_engine(ENGINE *engine) +{ + const RAND_METHOD *meth, *old = selected_meth; + + if (engine) { + ENGINE_up_ref(engine); + meth = ENGINE_get_RAND(engine); + if (meth == NULL) { + ENGINE_finish(engine); + return 0; + } + } else { + meth = NULL; + } + + if (old) + (*old->cleanup)(); + + if (selected_engine) + ENGINE_finish(selected_engine); + + selected_engine = engine; + selected_meth = meth; + + return 1; +} + +#define RAND_FILE_SIZE 1024 + +/** + * Load a a file and feed it into RAND_seed(). + * + * @param filename name of file to read. + * @param size minimum size to read. + * + * @return Returns the number of seed bytes loaded (0 indicates failure) + * + * @ingroup hcrypto_rand + */ + +int +RAND_load_file(const char *filename, size_t size) +{ + unsigned char buf[128]; + size_t len; + ssize_t slen; + int fd; + + fd = open(filename, O_RDONLY | O_BINARY, 0600); + if (fd < 0) + return 0; + rk_cloexec(fd); + len = 0; + while(len < size) { + slen = read(fd, buf, sizeof(buf)); + if (slen <= 0) + break; + RAND_seed(buf, slen); + len += slen; + } + close(fd); + + return len ? 1 : 0; +} + +/** + * Write of random numbers to a file to store for later initiation with RAND_load_file(). + * + * @param filename name of file to write. + * + * @return 1 on success and non-one on failure. + * @ingroup hcrypto_rand + */ + +int +RAND_write_file(const char *filename) +{ + unsigned char buf[128]; + size_t len; + int res = 0, fd; + + fd = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0600); + if (fd < 0) + return 0; + rk_cloexec(fd); + + len = 0; + while(len < RAND_FILE_SIZE) { + res = RAND_bytes(buf, sizeof(buf)); + if (res != 1) + break; + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + res = 0; + break; + } + len += sizeof(buf); + } + + close(fd); + + return res; +} + +/** + * Return the default random state filename for a user to use for + * RAND_load_file(), and RAND_write_file(). + * + * @param filename buffer to hold file name. + * @param size size of buffer filename. + * + * @return the buffer filename or NULL on failure. + * + * @ingroup hcrypto_rand + */ + +const char * +RAND_file_name(char *filename, size_t size) +{ + const char *e = NULL; + int pathp = 0, ret; + + e = secure_getenv("RANDFILE"); + if (e == NULL) + e = secure_getenv("HOME"); + if (e) + pathp = 1; + +#ifndef _WIN32 + /* + * Here we really want to call getpwuid(getuid()) but this will + * cause recursive lookups if the nss library uses + * gssapi/krb5/hcrypto to authenticate to the ldap servers. + * + * So at least return the unix /dev/random if we have one + */ + if (e == NULL) { + int fd; + + fd = _hc_unix_device_fd(O_RDONLY, &e); + if (fd >= 0) + close(fd); + } +#else /* Win32 */ + + if (e == NULL) { + char profile[MAX_PATH]; + + if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, + SHGFP_TYPE_CURRENT, profile) == S_OK) { + ret = snprintf(filename, size, "%s\\.rnd", profile); + + if (ret > 0 && ret < size) + return filename; + } + } + +#endif + + if (e == NULL) + return NULL; + + if (pathp) + ret = snprintf(filename, size, "%s/.rnd", e); + else + ret = snprintf(filename, size, "%s", e); + + if (ret <= 0 || ret >= size) + return NULL; + + return filename; +} diff --git a/third_party/heimdal/lib/hcrypto/rand.h b/third_party/heimdal/lib/hcrypto/rand.h new file mode 100644 index 0000000..1955c44 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rand.h @@ -0,0 +1,106 @@ + +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_RAND_H +#define _HEIM_RAND_H 1 + +#define RAND_METHOD hc_RAND_METHOD + +typedef struct RAND_METHOD RAND_METHOD; + +#include + +/* symbol renaming */ +#define RAND_bytes hc_RAND_bytes +#define RAND_pseudo_bytes hc_RAND_pseudo_bytes +#define RAND_seed hc_RAND_seed +#define RAND_cleanup hc_RAND_cleanup +#define RAND_add hc_RAND_add +#define RAND_set_rand_method hc_RAND_set_rand_method +#define RAND_get_rand_method hc_RAND_get_rand_method +#define RAND_set_rand_engine hc_RAND_set_rand_engine +#define RAND_file_name hc_RAND_file_name +#define RAND_load_file hc_RAND_load_file +#define RAND_write_file hc_RAND_write_file +#define RAND_status hc_RAND_status +#define RAND_fortuna_method hc_RAND_fortuna_method +#define RAND_timer_method hc_RAND_timer_method +#define RAND_unix_method hc_RAND_unix_method +#define RAND_w32crypto_method hc_RAND_w32crypto_method + +/* + * + */ + +struct RAND_METHOD +{ + void (*seed)(const void *, int); + int (*bytes)(unsigned char *, int); + void (*cleanup)(void); + void (*add)(const void *, int, double); + int (*pseudorand)(unsigned char *, int); + int (*status)(void); +}; + +/* + * + */ + +int RAND_bytes(void *, size_t num); +int RAND_pseudo_bytes(void *, size_t); +void RAND_seed(const void *, size_t); +void RAND_cleanup(void); +void RAND_add(const void *, size_t, double); + +int RAND_set_rand_method(const RAND_METHOD *); +const RAND_METHOD * + RAND_get_rand_method(void); +int RAND_set_rand_engine(ENGINE *); + +const char * + RAND_file_name(char *, size_t); +int RAND_load_file(const char *, size_t); +int RAND_write_file(const char *); +int RAND_status(void); + + +const RAND_METHOD * RAND_fortuna_method(void); +const RAND_METHOD * RAND_unix_method(void); +const RAND_METHOD * RAND_w32crypto_method(void); + +#endif /* _HEIM_RAND_H */ diff --git a/third_party/heimdal/lib/hcrypto/randi.h b/third_party/heimdal/lib/hcrypto/randi.h new file mode 100644 index 0000000..85d5d66 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/randi.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_RANDI_H +#define _HEIM_RANDI_H 1 + +extern const RAND_METHOD hc_rand_fortuna_method; +extern const RAND_METHOD hc_rand_unix_method; +extern const RAND_METHOD hc_rand_timer_method; +extern const RAND_METHOD hc_rand_w32crypto_method; + +const RAND_METHOD * RAND_timer_method(void); +int _hc_unix_device_fd(int, const char **); + +#endif /* _HEIM_RANDI_H */ diff --git a/third_party/heimdal/lib/hcrypto/rc2.c b/third_party/heimdal/lib/hcrypto/rc2.c new file mode 100644 index 0000000..53d32cf --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rc2.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "rc2.h" + +/* + * Implemented from Peter Gutmann's "Specification for Ron Rivests Cipher No.2" + * rfc2268 and "On the Design and Security of RC2" was also useful. + */ + +static unsigned int Sbox[256] = { + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, + 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, + 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, + 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, + 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, + 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, + 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, + 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, + 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, + 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, + 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, + 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, + 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, + 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, + 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, + 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, + 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, + 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, + 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, + 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, + 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, + 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, + 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, + 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, + 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, + 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, + 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad +}; + +void +RC2_set_key(RC2_KEY *key, int len, const unsigned char *data, int bits) +{ + unsigned char k[128]; + int j, T8, TM; + + if (len <= 0) + abort(); + if (len > 128) + len = 128; + if (bits <= 0 || bits > 1024) + bits = 1024; + + for (j = 0; j < len; j++) + k[j] = data[j]; + for (; j < 128; j++) + k[j] = Sbox[(k[j - len] + k[j - 1]) & 0xff]; + + T8 = (bits + 7) / 8; + j = (8*T8 - bits); + TM = 0xff >> j; + + k[128 - T8] = Sbox[k[128 - T8] & TM]; + + for (j = 127 - T8; j >= 0; j--) + k[j] = Sbox[k[j + 1] ^ k[j + T8]]; + + for (j = 0; j < 64; j++) + key->data[j] = k[(j * 2) + 0] | (k[(j * 2) + 1] << 8); + memset_s(k, sizeof(k), 0, sizeof(k)); +} + +#define ROT16L(w,n) ((w<>(16-n))) +#define ROT16R(w,n) ((w>>n)|(w<<(16-n))) + +void +RC2_encryptc(unsigned char *in, unsigned char *out, const RC2_KEY *key) +{ + int i, j; + int w0, w1, w2, w3; + int t0, t1, t2, t3; + + w0 = in[0] | (in[1] << 8); + w1 = in[2] | (in[3] << 8); + w2 = in[4] | (in[5] << 8); + w3 = in[6] | (in[7] << 8); + + for (i = 0; i < 16; i++) { + j = i * 4; + t0 = (w0 + (w1 & ~w3) + (w2 & w3) + key->data[j + 0]) & 0xffff; + w0 = ROT16L(t0, 1); + t1 = (w1 + (w2 & ~w0) + (w3 & w0) + key->data[j + 1]) & 0xffff; + w1 = ROT16L(t1, 2); + t2 = (w2 + (w3 & ~w1) + (w0 & w1) + key->data[j + 2]) & 0xffff; + w2 = ROT16L(t2, 3); + t3 = (w3 + (w0 & ~w2) + (w1 & w2) + key->data[j + 3]) & 0xffff; + w3 = ROT16L(t3, 5); + if(i == 4 || i == 10) { + w0 += key->data[w3 & 63]; + w1 += key->data[w0 & 63]; + w2 += key->data[w1 & 63]; + w3 += key->data[w2 & 63]; + } + } + + out[0] = w0 & 0xff; + out[1] = (w0 >> 8) & 0xff; + out[2] = w1 & 0xff; + out[3] = (w1 >> 8) & 0xff; + out[4] = w2 & 0xff; + out[5] = (w2 >> 8) & 0xff; + out[6] = w3 & 0xff; + out[7] = (w3 >> 8) & 0xff; +} + +void +RC2_decryptc(unsigned char *in, unsigned char *out, const RC2_KEY *key) +{ + int i, j; + int w0, w1, w2, w3; + int t0, t1, t2, t3; + + w0 = in[0] | (in[1] << 8); + w1 = in[2] | (in[3] << 8); + w2 = in[4] | (in[5] << 8); + w3 = in[6] | (in[7] << 8); + + for (i = 15; i >= 0; i--) { + j = i * 4; + + if(i == 4 || i == 10) { + w3 = (w3 - key->data[w2 & 63]) & 0xffff; + w2 = (w2 - key->data[w1 & 63]) & 0xffff; + w1 = (w1 - key->data[w0 & 63]) & 0xffff; + w0 = (w0 - key->data[w3 & 63]) & 0xffff; + } + + t3 = ROT16R(w3, 5); + w3 = (t3 - (w0 & ~w2) - (w1 & w2) - key->data[j + 3]) & 0xffff; + t2 = ROT16R(w2, 3); + w2 = (t2 - (w3 & ~w1) - (w0 & w1) - key->data[j + 2]) & 0xffff; + t1 = ROT16R(w1, 2); + w1 = (t1 - (w2 & ~w0) - (w3 & w0) - key->data[j + 1]) & 0xffff; + t0 = ROT16R(w0, 1); + w0 = (t0 - (w1 & ~w3) - (w2 & w3) - key->data[j + 0]) & 0xffff; + + } + out[0] = w0 & 0xff; + out[1] = (w0 >> 8) & 0xff; + out[2] = w1 & 0xff; + out[3] = (w1 >> 8) & 0xff; + out[4] = w2 & 0xff; + out[5] = (w2 >> 8) & 0xff; + out[6] = w3 & 0xff; + out[7] = (w3 >> 8) & 0xff; +} + +void +RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long size, + RC2_KEY *key, unsigned char *iv, int forward_encrypt) +{ + unsigned char tmp[RC2_BLOCK_SIZE]; + int i; + + if (forward_encrypt) { + while (size >= RC2_BLOCK_SIZE) { + for (i = 0; i < RC2_BLOCK_SIZE; i++) + tmp[i] = in[i] ^ iv[i]; + RC2_encryptc(tmp, out, key); + memcpy(iv, out, RC2_BLOCK_SIZE); + size -= RC2_BLOCK_SIZE; + in += RC2_BLOCK_SIZE; + out += RC2_BLOCK_SIZE; + } + if (size) { + for (i = 0; i < size; i++) + tmp[i] = in[i] ^ iv[i]; + for (i = size; i < RC2_BLOCK_SIZE; i++) + tmp[i] = iv[i]; + RC2_encryptc(tmp, out, key); + memcpy(iv, out, RC2_BLOCK_SIZE); + } + } else { + while (size >= RC2_BLOCK_SIZE) { + memcpy(tmp, in, RC2_BLOCK_SIZE); + RC2_decryptc(tmp, out, key); + for (i = 0; i < RC2_BLOCK_SIZE; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, RC2_BLOCK_SIZE); + size -= RC2_BLOCK_SIZE; + in += RC2_BLOCK_SIZE; + out += RC2_BLOCK_SIZE; + } + if (size) { + memcpy(tmp, in, RC2_BLOCK_SIZE); + RC2_decryptc(tmp, out, key); + for (i = 0; i < size; i++) + out[i] ^= iv[i]; + memcpy(iv, tmp, RC2_BLOCK_SIZE); + } + } +} diff --git a/third_party/heimdal/lib/hcrypto/rc2.h b/third_party/heimdal/lib/hcrypto/rc2.h new file mode 100644 index 0000000..5e479fb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rc2.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +/* symbol renaming */ +#define RC2_set_key hc_RC2_set_key +#define RC2_encryptc hc_RC2_encryptc +#define RC2_decryptc hc_RC2_decryptc +#define RC2_cbc_encrypt hc_RC2_cbc_encrypt + +/* + * + */ + +#define RC2_ENCRYPT 1 +#define RC2_DECRYPT 0 + +#define RC2_BLOCK_SIZE 8 +#define RC2_BLOCK RC2_BLOCK_SIZE +#define RC2_KEY_LENGTH 16 + +typedef struct rc2_key { + unsigned int data[64]; +} RC2_KEY; + +#ifdef __cplusplus +extern "C" { +#endif + +void RC2_set_key(RC2_KEY *, int, const unsigned char *,int); + +void RC2_encryptc(unsigned char *, unsigned char *, const RC2_KEY *); +void RC2_decryptc(unsigned char *, unsigned char *, const RC2_KEY *); + +void RC2_cbc_encrypt(const unsigned char *, unsigned char *, long, + RC2_KEY *, unsigned char *, int); + +#ifdef __cplusplus +} +#endif diff --git a/third_party/heimdal/lib/hcrypto/rc2test.c b/third_party/heimdal/lib/hcrypto/rc2test.c new file mode 100644 index 0000000..553bed3 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rc2test.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +struct { + const void *key; + const int keylen; + const int bitsize; + const void *plain; + const void *cipher; +} tests[] = { + { + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 0, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x1C\x19\x8A\x83\x8D\xF0\x28\xB7" + }, + { + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + 16, + 0, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x21\x82\x9C\x78\xA9\xF9\xC0\x74" + }, + { + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 0, + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", + "\x13\xDB\x35\x17\xD3\x21\x86\x9E" + }, + { + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + 16, + 0, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x50\xDC\x01\x62\xBD\x75\x7F\x31" + }, + { + "\x00\x00\x00\x00\x00\x00\x00\x00", + 8, + 63, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\xeb\xb7\x73\xf9\x93\x27\x8e\xff" + }, + { + "\xff\xff\xff\xff\xff\xff\xff\xff", + 8, + 64, + "\xff\xff\xff\xff\xff\xff\xff\xff", + "\x27\x8b\x27\xe4\x2e\x2f\x0d\x49" + }, + { + "\x88", + 1, + 64, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x61\xa8\xa2\x44\xad\xac\xcc\xf0" + } +}; + +const unsigned char cbc_key[16] = +"\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00"; +const char cbc_iv[8] = +"\x01\x01\x01\x01\x01\x01\x01\x01"; +const unsigned char cbc_in_data[32] = +"\x20\x20\x20\x20\x20\x20\x20\x20" +"\x20\x20\x20\x20\x20\x20\x20\x20" +"\x20\x20\x20\x20\x20\x20\x20\x20" +"\x20\x20\x20\x20\x20\x20\x20\x20"; + +const char out_iv[8] = "\x00\x78\x1b\x6\xff\xb9\xfa\xe"; + +const char cbc_out_data[32] = +"\xb4\x3f\x89\x15\x69\x68\xda\x79" +"\x29\xab\x5f\x78\xc5\xba\x15\x82" +"\x80\x89\x57\x1b\xbe\x57\x2f\xdc" +"\x00\x78\x1b\x06\xff\xb9\xfa\x0e"; + +int +main(int argc, char **argv) +{ + RC2_KEY key; + unsigned char t[8]; + unsigned char out[40]; + int i; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + RC2_set_key(&key, tests[i].keylen, tests[i].key, tests[i].bitsize); + + memcpy(t, tests[i].plain, 8); + RC2_encryptc(t, t, &key); + if (memcmp(t, tests[i].cipher, 8) != 0) { + printf("encrypt %d\n", i); + exit(1); + } + RC2_decryptc(t, t, &key); + if (memcmp(t, tests[i].plain, 8) != 0) { + printf("decrypt: %d\n", i); + exit(1); + } + } + + /* cbc test */ + + RC2_set_key(&key, 16, cbc_key, 0); + memcpy(t, cbc_iv, 8); + RC2_cbc_encrypt(cbc_in_data, out, 32, &key, t, 1); + + if (memcmp(out_iv, t, 8) != 0) + abort(); + + if (memcmp(out, cbc_out_data, 32) != 0) { + printf("cbc test encrypt\n"); + exit(1); + } + + memcpy(t, cbc_iv, 8); + RC2_cbc_encrypt(out, out, 32, &key, t, 0); + + if (memcmp(cbc_in_data, out, 32) != 0) { + printf("cbc test decrypt \n"); + exit(1); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/rc4.c b/third_party/heimdal/lib/hcrypto/rc4.c new file mode 100644 index 0000000..cc7882d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rc4.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* implemented from description in draft-kaukonen-cipher-arcfour-03.txt */ + +#include +#include + +#include + +#define SWAP(k,x,y) \ +{ unsigned int _t; \ + _t = k->state[x]; \ + k->state[x] = k->state[y]; \ + k->state[y] = _t; \ +} + +void +RC4_set_key(RC4_KEY *key, const int len, const unsigned char *data) +{ + int i, j; + + for (i = 0; i < 256; i++) + key->state[i] = i; + for (i = 0, j = 0; i < 256; i++) { + j = (j + key->state[i] + data[i % len]) % 256; + SWAP(key, i, j); + } + key->x = key->y = 0; +} + +void +RC4(RC4_KEY *key, const int len, const unsigned char *in, unsigned char *out) +{ + int i, t; + unsigned x, y; + + x = key->x; + y = key->y; + for (i = 0; i < len; i++) { + x = (x + 1) % 256; + y = (y + key->state[x]) % 256; + SWAP(key, x, y); + t = (key->state[x] + key->state[y]) % 256; + *out++ = key->state[t] ^ *in++; + } + key->x = x; + key->y = y; +} diff --git a/third_party/heimdal/lib/hcrypto/rc4.h b/third_party/heimdal/lib/hcrypto/rc4.h new file mode 100644 index 0000000..f93482f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rc4.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +/* symbol renaming */ +#define RC4_set_key hc_RC4_set_key +#define RC4 hc_RC4 + +typedef struct rc4_key { + unsigned int x, y; + unsigned int state[256]; +} RC4_KEY; + +void RC4_set_key(RC4_KEY *, const int, const unsigned char *); +void RC4(RC4_KEY *, const int, const unsigned char *, unsigned char *); diff --git a/third_party/heimdal/lib/hcrypto/rctest.c b/third_party/heimdal/lib/hcrypto/rctest.c new file mode 100644 index 0000000..031d8cd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rctest.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +static unsigned char plain1[8] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static unsigned char key1[8] = + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; +static unsigned char cipher1[8] = + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }; + +static unsigned char plain2[5] = + { 0xdc, 0xee, 0x4c, 0xf9, 0x2c }; +static unsigned char key2[5] = + { 0x61, 0x8a, 0x63, 0xd2, 0xfb }; +static unsigned char cipher2[5] = + { 0xf1, 0x38, 0x29, 0xc9, 0xde }; + +static unsigned char plain3[] = + { + 0x52, 0x75, 0x69, 0x73, 0x6c, 0x69, 0x6e, 0x6e, + 0x75, 0x6e, 0x20, 0x6c, 0x61, 0x75, 0x6c, 0x75, + 0x20, 0x6b, 0x6f, 0x72, 0x76, 0x69, 0x73, 0x73, + 0x73, 0x61, 0x6e, 0x69, 0x2c, 0x20, 0x74, 0xe4, + 0x68, 0x6b, 0xe4, 0x70, 0xe4, 0x69, 0x64, 0x65, + 0x6e, 0x20, 0x70, 0xe4, 0xe4, 0x6c, 0x6c, 0xe4, + 0x20, 0x74, 0xe4, 0x79, 0x73, 0x69, 0x6b, 0x75, + 0x75, 0x2e, 0x20, 0x4b, 0x65, 0x73, 0xe4, 0x79, + 0xf6, 0x6e, 0x20, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, + 0x6e, 0x69, 0x20, 0x6f, 0x6d, 0x61, 0x6e, 0x61, + 0x6e, 0x69, 0x2c, 0x20, 0x6b, 0x61, 0x73, 0x6b, + 0x69, 0x73, 0x61, 0x76, 0x75, 0x75, 0x6e, 0x20, + 0x6c, 0x61, 0x61, 0x6b, 0x73, 0x6f, 0x74, 0x20, + 0x76, 0x65, 0x72, 0x68, 0x6f, 0x75, 0x75, 0x2e, + 0x20, 0x45, 0x6e, 0x20, 0x6d, 0x61, 0x20, 0x69, + 0x6c, 0x6f, 0x69, 0x74, 0x73, 0x65, 0x2c, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6f, + 0x6b, 0x61, 0x61, 0x2c, 0x20, 0x6d, 0x75, 0x74, + 0x74, 0x61, 0x20, 0x6d, 0x65, 0x74, 0x73, 0xe4, + 0x6e, 0x20, 0x74, 0x75, 0x6d, 0x6d, 0x75, 0x75, + 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x6c, 0x65, 0x20, + 0x74, 0x75, 0x6f, 0x6b, 0x61, 0x61, 0x2e, 0x20, + 0x50, 0x75, 0x75, 0x6e, 0x74, 0x6f, 0x20, 0x70, + 0x69, 0x6c, 0x76, 0x65, 0x6e, 0x2c, 0x20, 0x6d, + 0x69, 0x20, 0x68, 0x75, 0x6b, 0x6b, 0x75, 0x75, + 0x2c, 0x20, 0x73, 0x69, 0x69, 0x6e, 0x74, 0x6f, + 0x20, 0x76, 0x61, 0x72, 0x61, 0x6e, 0x20, 0x74, + 0x75, 0x75, 0x6c, 0x69, 0x73, 0x65, 0x6e, 0x2c, + 0x20, 0x6d, 0x69, 0x20, 0x6e, 0x75, 0x6b, 0x6b, + 0x75, 0x75, 0x2e, 0x20, 0x54, 0x75, 0x6f, 0x6b, + 0x73, 0x75, 0x74, 0x20, 0x76, 0x61, 0x6e, 0x61, + 0x6d, 0x6f, 0x6e, 0x20, 0x6a, 0x61, 0x20, 0x76, + 0x61, 0x72, 0x6a, 0x6f, 0x74, 0x20, 0x76, 0x65, + 0x65, 0x6e, 0x2c, 0x20, 0x6e, 0x69, 0x69, 0x73, + 0x74, 0xe4, 0x20, 0x73, 0x79, 0x64, 0xe4, 0x6d, + 0x65, 0x6e, 0x69, 0x20, 0x6c, 0x61, 0x75, 0x6c, + 0x75, 0x6e, 0x20, 0x74, 0x65, 0x65, 0x6e, 0x2e, + 0x20, 0x2d, 0x20, 0x45, 0x69, 0x6e, 0x6f, 0x20, + 0x4c, 0x65, 0x69, 0x6e, 0x6f }; + +static unsigned char key3[16] = + { 0x29, 0x04, 0x19, 0x72, 0xfb, 0x42, 0xba, 0x5f, + 0xc7, 0x12, 0x77, 0x12, 0xf1, 0x38, 0x29, 0xc9 }; + +const unsigned char cipher3[] = + { 0x35, 0x81, 0x86, 0x99, 0x90, 0x01, 0xe6, 0xb5, + 0xda, 0xf0, 0x5e, 0xce, 0xeb, 0x7e, 0xee, 0x21, + 0xe0, 0x68, 0x9c, 0x1f, 0x00, 0xee, 0xa8, 0x1f, + 0x7d, 0xd2, 0xca, 0xae, 0xe1, 0xd2, 0x76, 0x3e, + 0x68, 0xaf, 0x0e, 0xad, 0x33, 0xd6, 0x6c, 0x26, + 0x8b, 0xc9, 0x46, 0xc4, 0x84, 0xfb, 0xe9, 0x4c, + 0x5f, 0x5e, 0x0b, 0x86, 0xa5, 0x92, 0x79, 0xe4, + 0xf8, 0x24, 0xe7, 0xa6, 0x40, 0xbd, 0x22, 0x32, + 0x10, 0xb0, 0xa6, 0x11, 0x60, 0xb7, 0xbc, 0xe9, + 0x86, 0xea, 0x65, 0x68, 0x80, 0x03, 0x59, 0x6b, + 0x63, 0x0a, 0x6b, 0x90, 0xf8, 0xe0, 0xca, 0xf6, + 0x91, 0x2a, 0x98, 0xeb, 0x87, 0x21, 0x76, 0xe8, + 0x3c, 0x20, 0x2c, 0xaa, 0x64, 0x16, 0x6d, 0x2c, + 0xce, 0x57, 0xff, 0x1b, 0xca, 0x57, 0xb2, 0x13, + 0xf0, 0xed, 0x1a, 0xa7, 0x2f, 0xb8, 0xea, 0x52, + 0xb0, 0xbe, 0x01, 0xcd, 0x1e, 0x41, 0x28, 0x67, + 0x72, 0x0b, 0x32, 0x6e, 0xb3, 0x89, 0xd0, 0x11, + 0xbd, 0x70, 0xd8, 0xaf, 0x03, 0x5f, 0xb0, 0xd8, + 0x58, 0x9d, 0xbc, 0xe3, 0xc6, 0x66, 0xf5, 0xea, + 0x8d, 0x4c, 0x79, 0x54, 0xc5, 0x0c, 0x3f, 0x34, + 0x0b, 0x04, 0x67, 0xf8, 0x1b, 0x42, 0x59, 0x61, + 0xc1, 0x18, 0x43, 0x07, 0x4d, 0xf6, 0x20, 0xf2, + 0x08, 0x40, 0x4b, 0x39, 0x4c, 0xf9, 0xd3, 0x7f, + 0xf5, 0x4b, 0x5f, 0x1a, 0xd8, 0xf6, 0xea, 0x7d, + 0xa3, 0xc5, 0x61, 0xdf, 0xa7, 0x28, 0x1f, 0x96, + 0x44, 0x63, 0xd2, 0xcc, 0x35, 0xa4, 0xd1, 0xb0, + 0x34, 0x90, 0xde, 0xc5, 0x1b, 0x07, 0x11, 0xfb, + 0xd6, 0xf5, 0x5f, 0x79, 0x23, 0x4d, 0x5b, 0x7c, + 0x76, 0x66, 0x22, 0xa6, 0x6d, 0xe9, 0x2b, 0xe9, + 0x96, 0x46, 0x1d, 0x5e, 0x4d, 0xc8, 0x78, 0xef, + 0x9b, 0xca, 0x03, 0x05, 0x21, 0xe8, 0x35, 0x1e, + 0x4b, 0xae, 0xd2, 0xfd, 0x04, 0xf9, 0x46, 0x73, + 0x68, 0xc4, 0xad, 0x6a, 0xc1, 0x86, 0xd0, 0x82, + 0x45, 0xb2, 0x63, 0xa2, 0x66, 0x6d, 0x1f, 0x6c, + 0x54, 0x20, 0xf1, 0x59, 0x9d, 0xfd, 0x9f, 0x43, + 0x89, 0x21, 0xc2, 0xf5, 0xa4, 0x63, 0x93, 0x8c, + 0xe0, 0x98, 0x22, 0x65, 0xee, 0xf7, 0x01, 0x79, + 0xbc, 0x55, 0x3f, 0x33, 0x9e, 0xb1, 0xa4, 0xc1, + 0xaf, 0x5f, 0x6a, 0x54, 0x7f }; + +int +main (void) +{ + unsigned char buf[1024]; + RC4_KEY key; + + RC4_set_key(&key, 8, key1); + RC4(&key, 8, plain1, buf); + if (memcmp(buf, cipher1, 8) != 0) + return 1; + + RC4_set_key(&key, 5, key2); + RC4(&key, 5, plain2, buf); + if (memcmp(buf, cipher2, 5) != 0) + return 1; + + RC4_set_key(&key, 16, key3); + RC4(&key, 309, plain3, buf); + if (memcmp(buf, cipher3, 309) != 0) + return 1; + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/resource.h b/third_party/heimdal/lib/hcrypto/resource.h new file mode 100644 index 0000000..9074dc1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by passwd_dialog.rc +// +#define IDD_PASSWD_DIALOG 101 +#define IDC_EDIT1 1000 +#define IDC_PASSWD_EDIT 1001 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.c b/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.c new file mode 100644 index 0000000..be05cdd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.c @@ -0,0 +1,1223 @@ +/* $NetBSD: rijndael-alg-fst.c,v 1.5 2001/11/13 01:40:10 lukem Exp $ */ +/* $KAME: rijndael-alg-fst.c,v 1.10 2003/07/15 10:47:16 itojun Exp $ */ +/** + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* "$NetBSD: rijndael-alg-fst.c,v 1.5 2001/11/13 01:40:10 lukem Exp $" */ + +#include +#include + +#ifdef KRB5 +#include +#endif + +#include "rijndael-alg-fst.h" + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const uint32_t Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const uint32_t Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const uint32_t Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const uint32_t Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const uint32_t Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const uint32_t Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const uint32_t Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const uint32_t Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const uint32_t Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const uint32_t Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const uint32_t rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) + +#ifdef _MSC_VER +#define GETU32(p) SWAP(*((uint32_t *)(p))) +#define PUTU32(ct, st) { *((uint32_t *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3])) +#define PUTU32(ct, st) { (ct)[0] = (uint8_t)((st) >> 24); (ct)[1] = (uint8_t)((st) >> 16); (ct)[2] = (uint8_t)((st) >> 8); (ct)[3] = (uint8_t)(st); } +#endif + +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int rijndaelKeySetupEnc(uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits) { + int i = 0; + uint32_t temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + if (keyBits == 128) { + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 10; + } + rk += 4; + } + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + if (keyBits == 192) { + for (;;) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 12; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + if (keyBits == 256) { + for (;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 14; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int rijndaelKeySetupDec(uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits) { + int Nr, i, j; + uint32_t temp; + + /* expand the cipher key: */ + Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); + /* invert the order of the round keys: */ + for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < Nr; i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return Nr; +} + +void rijndaelEncrypt(const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t pt[16], uint8_t ct[16]) { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (Nr > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (Nr > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += Nr << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ct , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ct + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ct + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ct + 12, s3); +} + +void rijndaelDecrypt(const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t ct[16], uint8_t pt[16]) { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (Nr > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (Nr > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += Nr << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(pt , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(pt + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(pt + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(pt + 12, s3); +} diff --git a/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.h b/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.h new file mode 100644 index 0000000..7e2e193 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rijndael-alg-fst.h @@ -0,0 +1,46 @@ +/* $NetBSD: rijndael-alg-fst.h,v 1.2 2000/10/02 17:19:15 itojun Exp $ */ +/* $KAME: rijndael-alg-fst.h,v 1.5 2003/07/15 10:47:16 itojun Exp $ */ +/** + * rijndael-alg-fst.h + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __RIJNDAEL_ALG_FST_H +#define __RIJNDAEL_ALG_FST_H + +/* symbol renaming */ +#define rijndaelKeySetupEnc _hc_rijndaelKeySetupEnc +#define rijndaelKeySetupDec _hc_rijndaelKeySetupDec +#define rijndaelEncrypt _hc_rijndaelEncrypt +#define rijndaelDecrypt _hc_rijndaelDecrypt + +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXKB (256/8) +#define RIJNDAEL_MAXNR 14 + +int rijndaelKeySetupEnc(uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits); +int rijndaelKeySetupDec(uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits); +void rijndaelEncrypt(const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t pt[16], uint8_t ct[16]); +void rijndaelDecrypt(const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t ct[16], uint8_t pt[16]); + +#endif /* __RIJNDAEL_ALG_FST_H */ diff --git a/third_party/heimdal/lib/hcrypto/rnd_keys.c b/third_party/heimdal/lib/hcrypto/rnd_keys.c new file mode 100644 index 0000000..ec35021 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rnd_keys.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1995, 1996, 1997, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#define HC_DEPRECATED + +#ifdef KRB5 +#include +#endif + +#include +#include + +#undef __attribute__ +#define __attribute__(X) + +void HC_DEPRECATED +DES_rand_data(void *outdata, int size) +{ + RAND_bytes(outdata, size); +} + +void HC_DEPRECATED +DES_generate_random_block(DES_cblock *block) +{ + RAND_bytes(block, sizeof(*block)); +} + +#define DES_rand_data_key hc_DES_rand_data_key + +void HC_DEPRECATED +DES_rand_data_key(DES_cblock *key); + +/* + * Generate a random DES key. + */ + +void HC_DEPRECATED +DES_rand_data_key(DES_cblock *key) +{ + DES_new_random_key(key); +} + +void HC_DEPRECATED +DES_set_sequence_number(void *ll) +{ +} + +void HC_DEPRECATED +DES_set_random_generator_seed(DES_cblock *seed) +{ + RAND_seed(seed, sizeof(*seed)); +} + +/** + * Generate a random des key using a random block, fixup parity and + * skip weak keys. + * + * @param key is set to a random key. + * + * @return 0 on success, non zero on random number generator failure. + * + * @ingroup hcrypto_des + */ + +int HC_DEPRECATED +DES_new_random_key(DES_cblock *key) +{ + do { + if (RAND_bytes(key, sizeof(*key)) != 1) + return 1; + DES_set_odd_parity(key); + } while(DES_is_weak_key(key)); + + return(0); +} + +/** + * Seed the random number generator. Deprecated, use @ref page_rand + * + * @param seed a seed to seed that random number generate with. + * + * @ingroup hcrypto_des + */ + +void HC_DEPRECATED +DES_init_random_number_generator(DES_cblock *seed) +{ + RAND_seed(seed, sizeof(*seed)); +} + +/** + * Generate a random key, deprecated since it doesn't return an error + * code, use DES_new_random_key(). + * + * @param key is set to a random key. + * + * @ingroup hcrypto_des + */ + +void HC_DEPRECATED +DES_random_key(DES_cblock *key) +{ + if (DES_new_random_key(key)) + abort(); +} diff --git a/third_party/heimdal/lib/hcrypto/rsa-gmp.c b/third_party/heimdal/lib/hcrypto/rsa-gmp.c new file mode 100644 index 0000000..8fb28ed --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rsa-gmp.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#ifdef HAVE_GMP + +#include + +static void +BN2mpz(mpz_t s, const BIGNUM *bn) +{ + size_t len; + void *p; + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + mpz_init(s); + mpz_import(s, len, 1, 1, 1, 0, p); + + free(p); +} + + +static BIGNUM * +mpz2BN(mpz_t s) +{ + size_t size; + BIGNUM *bn; + void *p; + + mpz_export(NULL, &size, 1, 1, 1, 0, s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + mpz_export(p, &size, 1, 1, 1, 0, s); + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +static int +rsa_private_calculate(mpz_t in, mpz_t p, mpz_t q, + mpz_t dmp1, mpz_t dmq1, mpz_t iqmp, + mpz_t out) +{ + mpz_t vp, vq, u; + mpz_init(vp); mpz_init(vq); mpz_init(u); + + /* vq = c ^ (d mod (q - 1)) mod q */ + /* vp = c ^ (d mod (p - 1)) mod p */ + mpz_fdiv_r(vp, in, p); + mpz_powm(vp, vp, dmp1, p); + mpz_fdiv_r(vq, in, q); + mpz_powm(vq, vq, dmq1, q); + + /* C2 = 1/q mod p (iqmp) */ + /* u = (vp - vq)C2 mod p. */ + mpz_sub(u, vp, vq); +#if 0 + if (mp_int_compare_zero(&u) < 0) + mp_int_add(&u, p, &u); +#endif + mpz_mul(u, iqmp, u); + mpz_fdiv_r(u, u, p); + + /* c ^ d mod n = vq + u q */ + mpz_mul(u, q, u); + mpz_add(out, u, vq); + + mpz_clear(vp); + mpz_clear(vq); + mpz_clear(u); + + return 0; +} + +/* + * + */ + +static int +gmp_rsa_public_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + size_t size, padlen; + mpz_t enc, dec, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + BN2mpz(n, rsa->n); + BN2mpz(e, rsa->e); + + p = p0 = malloc(size - 1); + if (p0 == NULL) { + mpz_clear(e); + mpz_clear(n); + return -3; + } + + padlen = size - flen - 3; + assert(padlen >= 8); + + *p++ = 2; + if (RAND_bytes(p, padlen) != 1) { + mpz_clear(e); + mpz_clear(n); + free(p0); + return -4; + } + while(padlen) { + if (*p == 0) + *p = 1; + padlen--; + p++; + } + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size - 1); + + mpz_init(enc); + mpz_init(dec); + mpz_import(dec, size - 1, 1, 1, 1, 0, p0); + free(p0); + + mpz_powm(enc, dec, e, n); + + mpz_clear(dec); + mpz_clear(e); + mpz_clear(n); + { + size_t ssize; + mpz_export(to, &ssize, 1, 1, 1, 0, enc); + assert(size >= ssize); + size = ssize; + } + mpz_clear(enc); + + return size; +} + +static int +gmp_rsa_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p; + size_t size; + mpz_t s, us, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + if (flen > RSA_size(rsa)) + return -2; + + BN2mpz(n, rsa->n); + BN2mpz(e, rsa->e); + +#if 0 + /* Check that the exponent is larger then 3 */ + if (mp_int_compare_value(&e, 3) <= 0) { + mp_int_clear(&n); + mp_int_clear(&e); + return -3; + } +#endif + + mpz_init(s); + mpz_init(us); + mpz_import(s, flen, 1, 1, 1, 0, rk_UNCONST(from)); + + if (mpz_cmp(s, n) >= 0) { + mpz_clear(n); + mpz_clear(e); + return -4; + } + + mpz_powm(us, s, e, n); + + mpz_clear(s); + mpz_clear(n); + mpz_clear(e); + + p = to; + + mpz_export(p, &size, 1, 1, 1, 0, us); + assert(size <= RSA_size(rsa)); + + mpz_clear(us); + + /* head zero was skipped by mp_int_to_unsigned */ + if (*p == 0) + return -6; + if (*p != 1) + return -7; + size--; p++; + while (size && *p == 0xff) { + size--; p++; + } + if (size == 0 || *p != 0) + return -8; + size--; p++; + + memmove(to, p, size); + + return size; +} + +static int +gmp_rsa_private_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + size_t size; + mpz_t in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + p0 = p = malloc(size); + *p++ = 0; + *p++ = 1; + memset(p, 0xff, size - flen - 3); + p += size - flen - 3; + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size); + + BN2mpz(n, rsa->n); + BN2mpz(e, rsa->e); + + mpz_init(in); + mpz_init(out); + mpz_import(in, size, 1, 1, 1, 0, p0); + free(p0); + +#if 0 + if(mp_int_compare_zero(&in) < 0 || + mp_int_compare(&in, &n) >= 0) { + size = 0; + goto out; + } +#endif + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mpz_t p, q, dmp1, dmq1, iqmp; + + BN2mpz(p, rsa->p); + BN2mpz(q, rsa->q); + BN2mpz(dmp1, rsa->dmp1); + BN2mpz(dmq1, rsa->dmq1); + BN2mpz(iqmp, rsa->iqmp); + + rsa_private_calculate(in, p, q, dmp1, dmq1, iqmp, out); + + mpz_clear(p); + mpz_clear(q); + mpz_clear(dmp1); + mpz_clear(dmq1); + mpz_clear(iqmp); + } else { + mpz_t d; + + BN2mpz(d, rsa->d); + mpz_powm(out, in, d, n); + mpz_clear(d); + } + + { + size_t ssize; + mpz_export(to, &ssize, 1, 1, 1, 0, out); + assert(size >= ssize); + size = ssize; + } + + mpz_clear(e); + mpz_clear(n); + mpz_clear(in); + mpz_clear(out); + + return size; +} + +static int +gmp_rsa_private_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr; + size_t size; + mpz_t in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + if (flen > size) + return -2; + + mpz_init(in); + mpz_init(out); + + BN2mpz(n, rsa->n); + BN2mpz(e, rsa->e); + + mpz_import(in, flen, 1, 1, 1, 0, from); + + if(mpz_cmp_ui(in, 0) < 0 || + mpz_cmp(in, n) >= 0) { + size = 0; + goto out; + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mpz_t p, q, dmp1, dmq1, iqmp; + + BN2mpz(p, rsa->p); + BN2mpz(q, rsa->q); + BN2mpz(dmp1, rsa->dmp1); + BN2mpz(dmq1, rsa->dmq1); + BN2mpz(iqmp, rsa->iqmp); + + rsa_private_calculate(in, p, q, dmp1, dmq1, iqmp, out); + + mpz_clear(p); + mpz_clear(q); + mpz_clear(dmp1); + mpz_clear(dmq1); + mpz_clear(iqmp); + } else { + mpz_t d; + +#if 0 + if(mp_int_compare_zero(&in) < 0 || + mp_int_compare(&in, &n) >= 0) + return MP_RANGE; +#endif + + BN2mpz(d, rsa->d); + mpz_powm(out, in, d, n); + mpz_clear(d); + } + + ptr = to; + { + size_t ssize; + mpz_export(ptr, &ssize, 1, 1, 1, 0, out); + assert(size >= ssize); + size = ssize; + } + + /* head zero was skipped by mp_int_to_unsigned */ + if (*ptr != 2) + return -3; + size--; ptr++; + while (size && *ptr != 0) { + size--; ptr++; + } + if (size == 0) + return -4; + size--; ptr++; + + memmove(to, ptr, size); + +out: + mpz_clear(e); + mpz_clear(n); + mpz_clear(in); + mpz_clear(out); + + return size; +} + +static int +random_num(mpz_t num, size_t len) +{ + unsigned char *p; + + len = (len + 7) / 8; + p = malloc(len); + if (p == NULL) + return 1; + if (RAND_bytes(p, len) != 1) { + free(p); + return 1; + } + mpz_import(num, len, 1, 1, 1, 0, p); + free(p); + return 0; +} + + +static int +gmp_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + mpz_t el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; + int counter, ret; + + if (bits < 789) + return -1; + + ret = -1; + + mpz_init(el); + mpz_init(p); + mpz_init(q); + mpz_init(n); + mpz_init(d); + mpz_init(dmp1); + mpz_init(dmq1); + mpz_init(iqmp); + mpz_init(t1); + mpz_init(t2); + mpz_init(t3); + + BN2mpz(el, e); + + /* generate p and q so that p != q and bits(pq) ~ bits */ + + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + random_num(p, bits / 2 + 1); + mpz_nextprime(p, p); + + mpz_sub_ui(t1, p, 1); + mpz_gcd(t2, t1, el); + } while(mpz_cmp_ui(t2, 1) != 0); + + BN_GENCB_call(cb, 3, 0); + + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + random_num(q, bits / 2 + 1); + mpz_nextprime(q, q); + + mpz_sub_ui(t1, q, 1); + mpz_gcd(t2, t1, el); + } while(mpz_cmp_ui(t2, 1) != 0); + + /* make p > q */ + if (mpz_cmp(p, q) < 0) + mpz_swap(p, q); + + BN_GENCB_call(cb, 3, 1); + + /* calculate n, n = p * q */ + mpz_mul(n, p, q); + + /* calculate d, d = 1/e mod (p - 1)(q - 1) */ + mpz_sub_ui(t1, p, 1); + mpz_sub_ui(t2, q, 1); + mpz_mul(t3, t1, t2); + mpz_invert(d, el, t3); + + /* calculate dmp1 dmp1 = d mod (p-1) */ + mpz_mod(dmp1, d, t1); + /* calculate dmq1 dmq1 = d mod (q-1) */ + mpz_mod(dmq1, d, t2); + /* calculate iqmp iqmp = 1/q mod p */ + mpz_invert(iqmp, q, p); + + /* fill in RSA key */ + + rsa->e = mpz2BN(el); + rsa->p = mpz2BN(p); + rsa->q = mpz2BN(q); + rsa->n = mpz2BN(n); + rsa->d = mpz2BN(d); + rsa->dmp1 = mpz2BN(dmp1); + rsa->dmq1 = mpz2BN(dmq1); + rsa->iqmp = mpz2BN(iqmp); + + ret = 1; + + mpz_clear(el); + mpz_clear(p); + mpz_clear(q); + mpz_clear(n); + mpz_clear(d); + mpz_clear(dmp1); + mpz_clear(dmq1); + mpz_clear(iqmp); + mpz_clear(t1); + mpz_clear(t2); + mpz_clear(t3); + + return ret; +} + +static int +gmp_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +gmp_rsa_finish(RSA *rsa) +{ + return 1; +} + +const RSA_METHOD hc_rsa_gmp_method = { + "hcrypto GMP RSA", + gmp_rsa_public_encrypt, + gmp_rsa_public_decrypt, + gmp_rsa_private_encrypt, + gmp_rsa_private_decrypt, + NULL, + NULL, + gmp_rsa_init, + gmp_rsa_finish, + 0, + NULL, + NULL, + NULL, + gmp_rsa_generate_key +}; + +#endif /* HAVE_GMP */ + +/** + * RSA implementation using Gnu Multipresistion Library. + */ + +const RSA_METHOD * +RSA_gmp_method(void) +{ +#ifdef HAVE_GMP + return &hc_rsa_gmp_method; +#else + return NULL; +#endif +} diff --git a/third_party/heimdal/lib/hcrypto/rsa-ltm.c b/third_party/heimdal/lib/hcrypto/rsa-ltm.c new file mode 100644 index 0000000..aec51da --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rsa-ltm.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2006 - 2007, 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include "tommath.h" + +#define CHECK(f) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY && ((ret = f)) != MP_OKAY) { goto out; } } while (0) +#define FIRST(e) do { ret = (e); } while (0) +#define FIRST_ALLOC(e) \ + do { where = __LINE__; ret = ((e)) ? MP_OKAY : MP_MEM; } while (0) +#define THEN_MP(e) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY) ret = (e); } while (0) +#define THEN_IF_MP(cond, e) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY && (cond)) ret = (e); } while (0) +#define THEN_IF_VOID(cond, e) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY && (cond)) e; } while (0) +#define THEN_VOID(e) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY) e; } while (0) +#define THEN_ALLOC(e) \ + do { where = __LINE__ + 1; if (ret == MP_OKAY) ret = ((e)) ? MP_OKAY : MP_MEM; } while (0) + +static mp_err +random_num(mp_int *num, size_t len) +{ + unsigned char *p; + mp_err ret = MP_MEM; + + len = (len + 7) / 8; /* bits to bytes */ + if ((p = malloc(len)) && RAND_bytes(p, len) != 1) + ret = MP_ERR; + if (p) + ret = mp_from_ubin(num, p, len); + free(p); + return ret; +} + +static mp_err +BN2mpz(mp_int *s, const BIGNUM *bn) +{ + size_t len; + mp_err ret = MP_MEM; + void *p; + + len = BN_num_bytes(bn); + p = malloc(len); + if (p) { + BN_bn2bin(bn, p); + ret = mp_from_ubin(s, p, len); + } + free(p); + return ret; +} + +static mp_err +setup_blind(mp_int *n, mp_int *b, mp_int *bi) +{ + mp_err ret; + + ret = random_num(b, mp_count_bits(n)); + if (ret == MP_OKAY) ret = mp_mod(b, n, b); + if (ret == MP_OKAY) ret = mp_invmod(b, n, bi); + return ret; +} + +static mp_err +blind(mp_int *in, mp_int *b, mp_int *e, mp_int *n) +{ + mp_err ret; + mp_int t1; + + ret = mp_init(&t1); + /* in' = (in * b^e) mod n */ + if (ret == MP_OKAY) ret = mp_exptmod(b, e, n, &t1); + if (ret == MP_OKAY) ret = mp_mul(&t1, in, in); + if (ret == MP_OKAY) ret = mp_mod(in, n, in); + mp_clear(&t1); + return ret; +} + +static mp_err +unblind(mp_int *out, mp_int *bi, mp_int *n) +{ + mp_err ret; + + /* out' = (out * 1/b) mod n */ + ret = mp_mul(out, bi, out); + if (ret == MP_OKAY) ret = mp_mod(out, n, out); + return ret; +} + +static mp_err +ltm_rsa_private_calculate(mp_int * in, mp_int * p, mp_int * q, + mp_int * dmp1, mp_int * dmq1, mp_int * iqmp, + mp_int * out) +{ + mp_err ret; + mp_int vp, vq, u; + int where HEIMDAL_UNUSED_ATTRIBUTE = 0; + + FIRST(mp_init_multi(&vp, &vq, &u, NULL)); + + /* vq = c ^ (d mod (q - 1)) mod q */ + /* vp = c ^ (d mod (p - 1)) mod p */ + THEN_MP(mp_mod(in, p, &u)); + THEN_MP(mp_exptmod(&u, dmp1, p, &vp)); + THEN_MP(mp_mod(in, q, &u)); + THEN_MP(mp_exptmod(&u, dmq1, q, &vq)); + + /* C2 = 1/q mod p (iqmp) */ + /* u = (vp - vq)C2 mod p. */ + THEN_MP(mp_sub(&vp, &vq, &u)); + THEN_IF_MP(mp_isneg(&u), mp_add(&u, p, &u)); + THEN_MP(mp_mul(&u, iqmp, &u)); + THEN_MP(mp_mod(&u, p, &u)); + + /* c ^ d mod n = vq + u q */ + THEN_MP(mp_mul(&u, q, &u)); + THEN_MP(mp_add(&u, &vq, out)); + + mp_clear_multi(&vp, &vq, &u, NULL); + return ret; +} + +/* + * + */ + +static int +ltm_rsa_public_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p = NULL, *p0 = NULL; + size_t size, ssize = 0, padlen; + mp_int enc, dec, n, e; + mp_err ret; + int where = __LINE__; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + FIRST(mp_init_multi(&n, &e, &enc, &dec, NULL)); + + size = RSA_size(rsa); + THEN_IF_MP((size < RSA_PKCS1_PADDING_SIZE || + size - RSA_PKCS1_PADDING_SIZE < flen), + MP_ERR); + THEN_MP(BN2mpz(&n, rsa->n)); + THEN_MP(BN2mpz(&e, rsa->e)); + THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); + THEN_ALLOC((p = p0 = malloc(size - 1))); + + if (ret == MP_OKAY) { + padlen = size - flen - 3; + *p++ = 2; + } + THEN_IF_MP((RAND_bytes(p, padlen) != 1), MP_ERR); + + if (ret == MP_OKAY) { + while (padlen) { + if (*p == 0) + *p = 1; + padlen--; + p++; + } + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size - 1); + } + + THEN_MP(mp_from_ubin(&dec, p0, size - 1)); + THEN_MP(mp_exptmod(&dec, &e, &n, &enc)); + THEN_VOID(ssize = mp_ubin_size(&enc)); + THEN_VOID(assert(size >= ssize)); + THEN_MP(mp_to_ubin(&enc, to, SIZE_MAX, NULL)); + THEN_VOID(size = ssize); + + mp_clear_multi(&dec, &e, &n, NULL); + mp_clear(&enc); + free(p0); + return ret == MP_OKAY ? size : -where; +} + +static int +ltm_rsa_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p = NULL; + mp_err ret; + size_t size = 0; + mp_int s, us, n, e; + int where = __LINE__; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + if (flen > RSA_size(rsa)) + return -2; + + FIRST(mp_init_multi(&e, &n, &s, &us, NULL)); + THEN_MP(BN2mpz(&n, rsa->n)); + THEN_MP(BN2mpz(&e, rsa->e)); + THEN_MP((mp_cmp_d(&e, 3) == MP_LT) ? MP_ERR : MP_OKAY); + THEN_MP(mp_from_ubin(&s, rk_UNCONST(from), (size_t)flen)); + THEN_MP((mp_cmp(&s, &n) >= 0) ? MP_ERR : MP_OKAY); + THEN_MP(mp_exptmod(&s, &e, &n, &us)); + + THEN_VOID(p = to); + THEN_VOID(size = mp_ubin_size(&us)); + THEN_VOID(assert(size <= RSA_size(rsa))); + THEN_MP(mp_to_ubin(&us, p, SIZE_MAX, NULL)); + + mp_clear_multi(&e, &n, &s, NULL); + mp_clear(&us); + + if (ret != MP_OKAY || size == 0) + return -where; + + /* head zero was skipped by mp_to_unsigned_bin */ + if (*p == 0) + return -where; + if (*p != 1) + return -(where + 1); + size--; p++; + while (size && *p == 0xff) { + size--; p++; + } + if (size == 0 || *p != 0) + return -(where + 2); + size--; p++; + memmove(to, p, size); + return size; +} + +static int +ltm_rsa_private_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr = NULL, *ptr0 = NULL; + mp_err ret; + mp_int in, out, n, e; + mp_int bi, b; + size_t size; + int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; + int do_unblind = 0; + int where = __LINE__; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + FIRST(mp_init_multi(&e, &n, &in, &out, &b, &bi, NULL)); + + size = RSA_size(rsa); + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + THEN_ALLOC((ptr0 = ptr = malloc(size))); + if (ret == MP_OKAY) { + *ptr++ = 0; + *ptr++ = 1; + memset(ptr, 0xff, size - flen - 3); + ptr += size - flen - 3; + *ptr++ = 0; + memcpy(ptr, from, flen); + ptr += flen; + assert((ptr - ptr0) == size); + } + + THEN_MP(BN2mpz(&n, rsa->n)); + THEN_MP(BN2mpz(&e, rsa->e)); + THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); + THEN_MP(mp_from_ubin(&in, ptr0, size)); + free(ptr0); + + THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); + + if (blinding) { + THEN_MP(setup_blind(&n, &b, &bi)); + THEN_MP(blind(&in, &b, &e, &n)); + do_unblind = 1; + } + + if (ret == MP_OKAY && rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && + rsa->iqmp) { + mp_int p, q, dmp1, dmq1, iqmp; + + FIRST(mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL)); + THEN_MP(BN2mpz(&p, rsa->p)); + THEN_MP(BN2mpz(&q, rsa->q)); + THEN_MP(BN2mpz(&dmp1, rsa->dmp1)); + THEN_MP(BN2mpz(&dmq1, rsa->dmq1)); + THEN_MP(BN2mpz(&iqmp, rsa->iqmp)); + THEN_MP(ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, + &out)); + mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + if (ret != MP_OKAY) goto out; + } else if (ret == MP_OKAY) { + mp_int d; + + THEN_MP(BN2mpz(&d, rsa->d)); + THEN_MP(mp_exptmod(&in, &d, &n, &out)); + mp_clear(&d); + if (ret != MP_OKAY) goto out; + } + + if (do_unblind) + THEN_MP(unblind(&out, &bi, &n)); + + if (ret == MP_OKAY && size > 0) { + size_t ssize; + + ssize = mp_ubin_size(&out); + assert(size >= ssize); + THEN_MP(mp_to_ubin(&out, to, SIZE_MAX, NULL)); + size = ssize; + } + + out: + mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); + return ret == MP_OKAY ? size : -where; +} + +static int +ltm_rsa_private_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr; + size_t size; + mp_err ret; + mp_int in, out, n, e, b, bi; + int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; + int do_unblind = 0; + int where = __LINE__; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + if (flen > size) + return -2; + + FIRST(mp_init_multi(&in, &n, &e, &out, &b, &bi, NULL)); + THEN_MP(BN2mpz(&n, rsa->n)); + THEN_MP(BN2mpz(&e, rsa->e)); + THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); + THEN_MP(mp_from_ubin(&in, rk_UNCONST(from), flen)); + THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); + + if (blinding) { + THEN_MP(setup_blind(&n, &b, &bi)); + THEN_MP(blind(&in, &b, &e, &n)); + do_unblind = 1; + } + + if (ret == MP_OKAY && rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && + rsa->iqmp) { + mp_int p, q, dmp1, dmq1, iqmp; + + THEN_MP(mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL)); + THEN_MP(BN2mpz(&p, rsa->p)); + THEN_MP(BN2mpz(&q, rsa->q)); + THEN_MP(BN2mpz(&dmp1, rsa->dmp1)); + THEN_MP(BN2mpz(&dmq1, rsa->dmq1)); + THEN_MP(BN2mpz(&iqmp, rsa->iqmp)); + THEN_MP(ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out)); + mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + if (ret != MP_OKAY) goto out; + } else if (ret == MP_OKAY) { + mp_int d; + + THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); + THEN_MP(BN2mpz(&d, rsa->d)); + THEN_MP(mp_exptmod(&in, &d, &n, &out)); + mp_clear(&d); + if (ret != MP_OKAY) goto out; + } + + if (do_unblind) + THEN_MP(unblind(&out, &bi, &n)); + + if (ret == MP_OKAY) { + size_t ssize; + + ptr = to; + ssize = mp_ubin_size(&out); + assert(size >= ssize); + ret = mp_to_ubin(&out, ptr, SIZE_MAX, NULL); + if (ret != MP_OKAY) goto out; + size = ssize; + + /* head zero was skipped by mp_int_to_unsigned */ + if (*ptr != 2) { + where = __LINE__; + goto out; + } + size--; ptr++; + while (size && *ptr != 0) { + size--; ptr++; + } + if (size == 0) { + where = __LINE__; + goto out; + } + size--; ptr++; + memmove(to, ptr, size); + } + + out: + mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); + return (ret == MP_OKAY) ? size : -where; +} + +static BIGNUM * +mpz2BN(mp_int *s) +{ + size_t size; + BIGNUM *bn; + mp_err ret; + void *p; + + size = mp_ubin_size(s); + if (size == 0) + return NULL; + + p = malloc(size); + if (p == NULL) + return NULL; + + ret = mp_to_ubin(s, p, SIZE_MAX, NULL); + if (ret == MP_OKAY) + bn = BN_bin2bn(p, size, NULL); + free(p); + return (ret == MP_OKAY) ? bn : NULL; +} + +enum gen_pq_type { GEN_P, GEN_Q }; + +static int +gen_p(int bits, enum gen_pq_type pq_type, uint8_t nibble_pair, mp_int *p, mp_int *e, BN_GENCB *cb) +{ + unsigned char *buf = NULL; + mp_bool res; + mp_err ret = MP_MEM; + mp_int t1, t2; + size_t len = (bits + 7) / 8; + int trials = mp_prime_rabin_miller_trials(bits); + int counter = 0; + int where HEIMDAL_UNUSED_ATTRIBUTE = 0; + + + FIRST(mp_init_multi(&t1, &t2, NULL)); + if (ret == MP_OKAY && (buf = malloc(len))) do { + BN_GENCB_call(cb, 2, counter++); + /* random bytes */ + ret = (RAND_bytes(buf, len) == 1) ? MP_OKAY : MP_ERR; + + /* make it odd */ + buf[len - 1] |= 1; + + /* ensure the high nibble of the product is at least 128 */ + if (pq_type == GEN_P) + buf[0] = (nibble_pair & 0xf0) | (buf[0] & 0x0f); + else + buf[0] = ((nibble_pair & 0x0f) << 4) | (buf[0] & 0x0f); + + /* load number */ + THEN_MP(mp_from_ubin(p, buf, len)); + + /* test primality; repeat if not */ + THEN_MP(mp_prime_is_prime(p, trials, &res)); + if (ret == MP_OKAY && res == MP_NO) continue; + + /* check gcd(p - 1, e) == 1 */ + THEN_MP(mp_sub_d(p, 1, &t1)); + THEN_MP(mp_gcd(&t1, e, &t2)); + } while (ret == MP_OKAY && mp_cmp_d(&t2, 1) != MP_EQ); + + mp_clear_multi(&t1, &t2, NULL); + free(buf); + return ret; +} + +static uint8_t pq_high_nibble_pairs[] = { +0x9f, 0xad, 0xae, 0xaf, 0xbc, 0xbd, 0xbe, 0xbf, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, +0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf9, +0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static int +ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + mp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; + mp_err ret; + uint8_t high_nibbles = 0; + int bitsp; + int where = __LINE__; + + if (bits < 789) + return -1; + + bitsp = (bits + 1) / 2; + + FIRST(mp_init_multi(&el, &p, &q, &n, &d, + &dmp1, &dmq1, &iqmp, + &t1, &t2, &t3, NULL)); + THEN_MP(BN2mpz(&el, e)); + + /* + * randomly pick a pair of high nibbles for p and q to ensure the product's + * high nibble is at least 128 + */ + if (ret == MP_OKAY) + ret = (RAND_bytes(&high_nibbles, 1) == 1) ? MP_OKAY : MP_ERR; + high_nibbles %= sizeof(pq_high_nibble_pairs); + high_nibbles = pq_high_nibble_pairs[high_nibbles]; + + /* generate p and q so that p != q and bits(pq) ~ bits */ + THEN_MP(gen_p(bitsp, GEN_P, high_nibbles, &p, &el, cb)); + BN_GENCB_call(cb, 3, 0); + THEN_MP(gen_p(bitsp, GEN_Q, high_nibbles, &q, &el, cb)); + + /* make p > q */ + if (mp_cmp(&p, &q) < 0) { + mp_int c; + c = p; + p = q; + q = c; + } + + BN_GENCB_call(cb, 3, 1); + + /* calculate n, n = p * q */ + THEN_MP(mp_mul(&p, &q, &n)); + + /* calculate d, d = 1/e mod (p - 1)(q - 1) */ + THEN_MP(mp_sub_d(&p, 1, &t1)); + THEN_MP(mp_sub_d(&q, 1, &t2)); + THEN_MP(mp_mul(&t1, &t2, &t3)); + THEN_MP(mp_invmod(&el, &t3, &d)); + + /* calculate dmp1 dmp1 = d mod (p-1) */ + THEN_MP(mp_mod(&d, &t1, &dmp1)); + /* calculate dmq1 dmq1 = d mod (q-1) */ + THEN_MP(mp_mod(&d, &t2, &dmq1)); + /* calculate iqmp iqmp = 1/q mod p */ + THEN_MP(mp_invmod(&q, &p, &iqmp)); + + /* fill in RSA key */ + + if (ret == MP_OKAY) { + rsa->e = mpz2BN(&el); + rsa->p = mpz2BN(&p); + rsa->q = mpz2BN(&q); + rsa->n = mpz2BN(&n); + rsa->d = mpz2BN(&d); + rsa->dmp1 = mpz2BN(&dmp1); + rsa->dmq1 = mpz2BN(&dmq1); + rsa->iqmp = mpz2BN(&iqmp); + } + + mp_clear_multi(&el, &p, &q, &n, &d, + &dmp1, &dmq1, &iqmp, + &t1, &t2, &t3, NULL); + return (ret == MP_OKAY) ? 1 : -where; +} + +static int +ltm_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +ltm_rsa_finish(RSA *rsa) +{ + return 1; +} + +const RSA_METHOD hc_rsa_ltm_method = { + "hcrypto ltm RSA", + ltm_rsa_public_encrypt, + ltm_rsa_public_decrypt, + ltm_rsa_private_encrypt, + ltm_rsa_private_decrypt, + NULL, + NULL, + ltm_rsa_init, + ltm_rsa_finish, + 0, + NULL, + NULL, + NULL, + ltm_rsa_generate_key +}; + +const RSA_METHOD * +RSA_ltm_method(void) +{ + return &hc_rsa_ltm_method; +} diff --git a/third_party/heimdal/lib/hcrypto/rsa-tfm.c b/third_party/heimdal/lib/hcrypto/rsa-tfm.c new file mode 100644 index 0000000..41b0fc1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rsa-tfm.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2006 - 2007, 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#ifdef USE_HCRYPTO_TFM + +#include "tfm.h" + +static void +BN2mpz(fp_int *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + fp_init(s); + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + fp_read_unsigned_bin(s, p, len); + free(p); +} + +static int +tfm_rsa_private_calculate(fp_int * in, fp_int * p, fp_int * q, + fp_int * dmp1, fp_int * dmq1, fp_int * iqmp, + fp_int * out) +{ + fp_int vp, vq, u; + + fp_init_multi(&vp, &vq, &u, NULL); + + /* vq = c ^ (d mod (q - 1)) mod q */ + /* vp = c ^ (d mod (p - 1)) mod p */ + fp_mod(in, p, &u); + fp_exptmod(&u, dmp1, p, &vp); + fp_mod(in, q, &u); + fp_exptmod(&u, dmq1, q, &vq); + + /* C2 = 1/q mod p (iqmp) */ + /* u = (vp - vq)C2 mod p. */ + fp_sub(&vp, &vq, &u); + if (fp_isneg(&u)) + fp_add(&u, p, &u); + fp_mul(&u, iqmp, &u); + fp_mod(&u, p, &u); + + /* c ^ d mod n = vq + u q */ + fp_mul(&u, q, &u); + fp_add(&u, &vq, out); + + fp_zero_multi(&vp, &vq, &u, NULL); + + return 0; +} + +/* + * + */ + +static int +tfm_rsa_public_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + int res; + size_t size, padlen; + fp_int enc, dec, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + p = p0 = malloc(size - 1); + if (p0 == NULL) { + fp_zero_multi(&e, &n, NULL); + return -3; + } + + padlen = size - flen - 3; + + *p++ = 2; + if (RAND_bytes(p, padlen) != 1) { + fp_zero_multi(&e, &n, NULL); + free(p0); + return -4; + } + while(padlen) { + if (*p == 0) + *p = 1; + padlen--; + p++; + } + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size - 1); + + fp_init_multi(&enc, &dec, NULL); + fp_read_unsigned_bin(&dec, p0, size - 1); + free(p0); + + res = fp_exptmod(&dec, &e, &n, &enc); + + fp_zero_multi(&dec, &e, &n, NULL); + + if (res != 0) + return -4; + + { + size_t ssize; + ssize = fp_unsigned_bin_size(&enc); + assert(size >= ssize); + fp_to_unsigned_bin(&enc, to); + size = ssize; + } + fp_zero(&enc); + + return size; +} + +static int +tfm_rsa_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p; + int res; + size_t size; + fp_int s, us, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + if (flen > RSA_size(rsa)) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + +#if 0 + /* Check that the exponent is larger then 3 */ + if (mp_int_compare_value(&e, 3) <= 0) { + fp_zero_multi(&e, &n, NULL); + return -3; + } +#endif + + fp_init_multi(&s, &us, NULL); + fp_read_unsigned_bin(&s, rk_UNCONST(from), flen); + + if (fp_cmp(&s, &n) >= 0) { + fp_zero_multi(&e, &n, NULL); + return -4; + } + + res = fp_exptmod(&s, &e, &n, &us); + + fp_zero_multi(&s, &e, &n, NULL); + + if (res != 0) + return -5; + p = to; + + + size = fp_unsigned_bin_size(&us); + assert(size <= RSA_size(rsa)); + fp_to_unsigned_bin(&us, p); + + fp_zero(&us); + + /* head zero was skipped by fp_to_unsigned_bin */ + if (*p == 0) + return -6; + if (*p != 1) + return -7; + size--; p++; + while (size && *p == 0xff) { + size--; p++; + } + if (size == 0 || *p != 0) + return -8; + size--; p++; + + memmove(to, p, size); + + return size; +} + +static int +tfm_rsa_private_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + int res; + int size; + fp_int in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + p0 = p = malloc(size); + *p++ = 0; + *p++ = 1; + memset(p, 0xff, size - flen - 3); + p += size - flen - 3; + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + fp_init_multi(&in, &out, NULL); + fp_read_unsigned_bin(&in, p0, size); + free(p0); + + if(fp_isneg(&in) || fp_cmp(&in, &n) >= 0) { + size = -3; + goto out; + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + fp_int p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = tfm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + fp_zero_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + + if (res != 0) { + size = -4; + goto out; + } + } else { + fp_int d; + + BN2mpz(&d, rsa->d); + res = fp_exptmod(&in, &d, &n, &out); + fp_zero(&d); + if (res != 0) { + size = -5; + goto out; + } + } + + if (size > 0) { + size_t ssize; + ssize = fp_unsigned_bin_size(&out); + assert(size >= ssize); + fp_to_unsigned_bin(&out, to); + size = ssize; + } + + out: + fp_zero_multi(&e, &n, &in, &out, NULL); + + return size; +} + +static int +tfm_rsa_private_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr; + int res; + int size; + fp_int in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + if (flen > size) + return -2; + + fp_init_multi(&in, &out, NULL); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + fp_read_unsigned_bin(&in, rk_UNCONST(from), flen); + + if(fp_isneg(&in) || fp_cmp(&in, &n) >= 0) { + size = -2; + goto out; + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + fp_int p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = tfm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + fp_zero_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + + if (res != 0) { + size = -3; + goto out; + } + + } else { + fp_int d; + + if(fp_isneg(&in) || fp_cmp(&in, &n) >= 0) + return -4; + + BN2mpz(&d, rsa->d); + res = fp_exptmod(&in, &d, &n, &out); + fp_zero(&d); + if (res != 0) { + size = -5; + goto out; + } + } + + ptr = to; + { + size_t ssize; + ssize = fp_unsigned_bin_size(&out); + assert(size >= ssize); + fp_to_unsigned_bin(&out, ptr); + size = ssize; + } + + /* head zero was skipped by mp_int_to_unsigned */ + if (*ptr != 2) { + size = -6; + goto out; + } + size--; ptr++; + while (size && *ptr != 0) { + size--; ptr++; + } + if (size == 0) + return -7; + size--; ptr++; + + memmove(to, ptr, size); + + out: + fp_zero_multi(&e, &n, &in, &out, NULL); + + return size; +} + +static BIGNUM * +mpz2BN(fp_int *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = fp_unsigned_bin_size(s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + + fp_to_unsigned_bin(s, p); + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +static int +random_num(fp_int *num, size_t len) +{ + unsigned char *p; + + len = (len + 7) / 8; + p = malloc(len); + if (p == NULL) + return 1; + if (RAND_bytes(p, len) != 1) { + free(p); + return 1; + } + fp_read_unsigned_bin(num, p, len); + free(p); + return 0; +} + +#define CHECK(f, v) if ((f) != (v)) { goto out; } + +static int +tfm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + fp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; + int counter, ret, bitsp; + + if (bits < 789) + return -1; + + bitsp = (bits + 1) / 2; + + ret = -1; + + fp_init_multi(&el, &p, &q, &n, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); + + BN2mpz(&el, e); + + /* generate p and q so that p != q and bits(pq) ~ bits */ + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&p, bitsp), 0); + CHECK(fp_find_prime(&p), FP_YES); + + fp_sub_d(&p, 1, &t1); + fp_gcd(&t1, &el, &t2); + } while(fp_cmp_d(&t2, 1) != 0); + + BN_GENCB_call(cb, 3, 0); + + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&q, bits - bitsp), 0); + CHECK(fp_find_prime(&q), FP_YES); + + if (fp_cmp(&p, &q) == 0) /* don't let p and q be the same */ + continue; + + fp_sub_d(&q, 1, &t1); + fp_gcd(&t1, &el, &t2); + } while(fp_cmp_d(&t2, 1) != 0); + + /* make p > q */ + if (fp_cmp(&p, &q) < 0) { + fp_int c; + fp_copy(&p, &c); + fp_copy(&q, &p); + fp_copy(&c, &q); + } + + BN_GENCB_call(cb, 3, 1); + + /* calculate n, n = p * q */ + fp_mul(&p, &q, &n); + + /* calculate d, d = 1/e mod (p - 1)(q - 1) */ + fp_sub_d(&p, 1, &t1); + fp_sub_d(&q, 1, &t2); + fp_mul(&t1, &t2, &t3); + fp_invmod(&el, &t3, &d); + + /* calculate dmp1 dmp1 = d mod (p-1) */ + fp_mod(&d, &t1, &dmp1); + /* calculate dmq1 dmq1 = d mod (q-1) */ + fp_mod(&d, &t2, &dmq1); + /* calculate iqmp iqmp = 1/q mod p */ + fp_invmod(&q, &p, &iqmp); + + /* fill in RSA key */ + + rsa->e = mpz2BN(&el); + rsa->p = mpz2BN(&p); + rsa->q = mpz2BN(&q); + rsa->n = mpz2BN(&n); + rsa->d = mpz2BN(&d); + rsa->dmp1 = mpz2BN(&dmp1); + rsa->dmq1 = mpz2BN(&dmq1); + rsa->iqmp = mpz2BN(&iqmp); + + ret = 1; + +out: + fp_zero_multi(&el, &p, &q, &n, &d, &dmp1, + &dmq1, &iqmp, &t1, &t2, &t3, NULL); + + return ret; +} + +static int +tfm_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +tfm_rsa_finish(RSA *rsa) +{ + return 1; +} + +const RSA_METHOD hc_rsa_tfm_method = { + "hcrypto tfm RSA", + tfm_rsa_public_encrypt, + tfm_rsa_public_decrypt, + tfm_rsa_private_encrypt, + tfm_rsa_private_decrypt, + NULL, + NULL, + tfm_rsa_init, + tfm_rsa_finish, + 0, + NULL, + NULL, + NULL, + tfm_rsa_generate_key +}; + +#endif + +const RSA_METHOD * +RSA_tfm_method(void) +{ +#ifdef USE_HCRYPTO_TFM + return &hc_rsa_tfm_method; +#else + return NULL; +#endif +} + diff --git a/third_party/heimdal/lib/hcrypto/rsa.c b/third_party/heimdal/lib/hcrypto/rsa.c new file mode 100644 index 0000000..31470d0 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rsa.c @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include + +#include "common.h" + +/** + * @page page_rsa RSA - public-key cryptography + * + * RSA is named by its inventors (Ron Rivest, Adi Shamir, and Leonard + * Adleman) (published in 1977), patented expired in 21 September 2000. + * + * + * Speed for RSA in seconds + * no key blinding + * 1000 iteration, + * same rsa keys (1024 and 2048) + * operation performed each eteration sign, verify, encrypt, decrypt on a random bit pattern + * + * name 1024 2048 4098 + * ================================= + * gmp: 0.73 6.60 44.80 + * tfm: 2.45 -- -- + * ltm: 3.79 20.74 105.41 (default in hcrypto) + * openssl: 4.04 11.90 82.59 + * cdsa: 15.89 102.89 721.40 + * imath: 40.62 -- -- + * + * See the library functions here: @ref hcrypto_rsa + */ + +/** + * Same as RSA_new_method() using NULL as engine. + * + * @return a newly allocated RSA object. Free with RSA_free(). + * + * @ingroup hcrypto_rsa + */ + +RSA * +RSA_new(void) +{ + return RSA_new_method(NULL); +} + +/** + * Allocate a new RSA object using the engine, if NULL is specified as + * the engine, use the default RSA engine as returned by + * ENGINE_get_default_RSA(). + * + * @param engine Specific what ENGINE RSA provider should be used. + * + * @return a newly allocated RSA object. Free with RSA_free(). + * + * @ingroup hcrypto_rsa + */ + +RSA * +RSA_new_method(ENGINE *engine) +{ + RSA *rsa; + + rsa = calloc(1, sizeof(*rsa)); + if (rsa == NULL) + return NULL; + + rsa->references = 1; + + if (engine) { + ENGINE_up_ref(engine); + rsa->engine = engine; + } else { + rsa->engine = ENGINE_get_default_RSA(); + } + + if (rsa->engine) { + rsa->meth = ENGINE_get_RSA(rsa->engine); + if (rsa->meth == NULL) { + ENGINE_finish(rsa->engine); + free(rsa); + return 0; + } + } + + if (rsa->meth == NULL) + rsa->meth = rk_UNCONST(RSA_get_default_method()); + + (*rsa->meth->init)(rsa); + + return rsa; +} + +/** + * Free an allocation RSA object. + * + * @param rsa the RSA object to free. + * @ingroup hcrypto_rsa + */ + +void +RSA_free(RSA *rsa) +{ + if (rsa->references <= 0) + abort(); + + if (--rsa->references > 0) + return; + + (*rsa->meth->finish)(rsa); + + if (rsa->engine) + ENGINE_finish(rsa->engine); + +#define free_if(f) if (f) { BN_free(f); } + free_if(rsa->n); + free_if(rsa->e); + free_if(rsa->d); + free_if(rsa->p); + free_if(rsa->q); + free_if(rsa->dmp1); + free_if(rsa->dmq1); + free_if(rsa->iqmp); +#undef free_if + + memset_s(rsa, sizeof(*rsa), 0, sizeof(*rsa)); + free(rsa); +} + +/** + * Add an extra reference to the RSA object. The object should be free + * with RSA_free() to drop the reference. + * + * @param rsa the object to add reference counting too. + * + * @return the current reference count, can't safely be used except + * for debug printing. + * + * @ingroup hcrypto_rsa + */ + +int +RSA_up_ref(RSA *rsa) +{ + return ++rsa->references; +} + +/** + * Return the RSA_METHOD used for this RSA object. + * + * @param rsa the object to get the method from. + * + * @return the method used for this RSA object. + * + * @ingroup hcrypto_rsa + */ + +const RSA_METHOD * +RSA_get_method(const RSA *rsa) +{ + return rsa->meth; +} + +/** + * Set a new method for the RSA keypair. + * + * @param rsa rsa parameter. + * @param method the new method for the RSA parameter. + * + * @return 1 on success. + * + * @ingroup hcrypto_rsa + */ + +int +RSA_set_method(RSA *rsa, const RSA_METHOD *method) +{ + (*rsa->meth->finish)(rsa); + + if (rsa->engine) { + ENGINE_finish(rsa->engine); + rsa->engine = NULL; + } + + rsa->meth = method; + (*rsa->meth->init)(rsa); + return 1; +} + +/** + * Set the application data for the RSA object. + * + * @param rsa the rsa object to set the parameter for + * @param arg the data object to store + * + * @return 1 on success. + * + * @ingroup hcrypto_rsa + */ + +int +RSA_set_app_data(RSA *rsa, void *arg) +{ + rsa->ex_data.sk = arg; + return 1; +} + +/** + * Get the application data for the RSA object. + * + * @param rsa the rsa object to get the parameter for + * + * @return the data object + * + * @ingroup hcrypto_rsa + */ + +void * +RSA_get_app_data(const RSA *rsa) +{ + return rsa->ex_data.sk; +} + +int +RSA_check_key(const RSA *key) +{ + static const unsigned char inbuf[] = "hello, world!"; + RSA *rsa = rk_UNCONST(key); + void *buffer; + int ret; + + /* + * XXX I have no clue how to implement this w/o a bignum library. + * Well, when we have a RSA key pair, we can try to encrypt/sign + * and then decrypt/verify. + */ + + if (rsa->n == NULL) + return 0; + + if (rsa->d == NULL && + (rsa->p == NULL || rsa->q || rsa->dmp1 == NULL || rsa->dmq1 == NULL || rsa->iqmp == NULL)) + return 0; + + buffer = malloc(RSA_size(rsa)); + if (buffer == NULL) + return 0; + + ret = RSA_private_encrypt(sizeof(inbuf), inbuf, buffer, + rsa, RSA_PKCS1_PADDING); + if (ret == -1) { + free(buffer); + return 0; + } + + ret = RSA_public_decrypt(ret, buffer, buffer, + rsa, RSA_PKCS1_PADDING); + if (ret == -1) { + free(buffer); + return 0; + } + + if (ret == sizeof(inbuf) && ct_memcmp(buffer, inbuf, sizeof(inbuf)) == 0) { + free(buffer); + return 1; + } + free(buffer); + return 0; +} + +int +RSA_size(const RSA *rsa) +{ + return BN_num_bytes(rsa->n); +} + +#define RSAFUNC(name, body) \ +int \ +name(int flen,const unsigned char* f, unsigned char* t, RSA* r, int p){\ + return body; \ +} + +RSAFUNC(RSA_public_encrypt, (r)->meth->rsa_pub_enc(flen, f, t, r, p)) +RSAFUNC(RSA_public_decrypt, (r)->meth->rsa_pub_dec(flen, f, t, r, p)) +RSAFUNC(RSA_private_encrypt, (r)->meth->rsa_priv_enc(flen, f, t, r, p)) +RSAFUNC(RSA_private_decrypt, (r)->meth->rsa_priv_dec(flen, f, t, r, p)) + +static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +static const AlgorithmIdentifier _signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; +static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; +static const AlgorithmIdentifier _signature_sha256_data = { + { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +static const AlgorithmIdentifier _signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + + +int +RSA_sign(int type, const unsigned char *from, unsigned int flen, + unsigned char *to, unsigned int *tlen, RSA *rsa) +{ + if (rsa->meth->rsa_sign) + return rsa->meth->rsa_sign(type, from, flen, to, tlen, rsa); + + if (rsa->meth->rsa_priv_enc) { + heim_octet_string indata; + DigestInfo di; + size_t size; + int ret; + + memset(&di, 0, sizeof(di)); + + if (type == NID_sha1) { + di.digestAlgorithm = _signature_sha1_data; + } else if (type == NID_md5) { + di.digestAlgorithm = _signature_md5_data; + } else if (type == NID_sha256) { + di.digestAlgorithm = _signature_sha256_data; + } else + return -1; + + di.digest.data = rk_UNCONST(from); + di.digest.length = flen; + + ASN1_MALLOC_ENCODE(DigestInfo, + indata.data, + indata.length, + &di, + &size, + ret); + if (ret) + return ret; + if (indata.length != size) + abort(); + + ret = rsa->meth->rsa_priv_enc(indata.length, indata.data, to, + rsa, RSA_PKCS1_PADDING); + free(indata.data); + if (ret > 0) { + *tlen = ret; + ret = 1; + } else + ret = 0; + + return ret; + } + + return 0; +} + +int +RSA_verify(int type, const unsigned char *from, unsigned int flen, + unsigned char *sigbuf, unsigned int siglen, RSA *rsa) +{ + if (rsa->meth->rsa_verify) + return rsa->meth->rsa_verify(type, from, flen, sigbuf, siglen, rsa); + + if (rsa->meth->rsa_pub_dec) { + const AlgorithmIdentifier *digest_alg; + void *data; + DigestInfo di; + size_t size; + int ret, ret2; + + data = malloc(RSA_size(rsa)); + if (data == NULL) + return -1; + + memset(&di, 0, sizeof(di)); + + ret = rsa->meth->rsa_pub_dec(siglen, sigbuf, data, rsa, RSA_PKCS1_PADDING); + if (ret <= 0) { + free(data); + return -2; + } + + ret2 = decode_DigestInfo(data, ret, &di, &size); + free(data); + if (ret2 != 0) + return -3; + if (ret != size) { + free_DigestInfo(&di); + return -4; + } + + if (flen != di.digest.length || ct_memcmp(di.digest.data, from, flen) != 0) { + free_DigestInfo(&di); + return -5; + } + + if (type == NID_sha1) { + digest_alg = &_signature_sha1_data; + } else if (type == NID_md5) { + digest_alg = &_signature_md5_data; + } else if (type == NID_sha256) { + digest_alg = &_signature_sha256_data; + } else { + free_DigestInfo(&di); + return -1; + } + + ret = der_heim_oid_cmp(&digest_alg->algorithm, + &di.digestAlgorithm.algorithm); + free_DigestInfo(&di); + + if (ret != 0) + return 0; + return 1; + } + + return 0; +} + +/* + * A NULL RSA_METHOD that returns failure for all operations. This is + * used as the default RSA method if we don't have any native + * support. + */ + +static RSAFUNC(null_rsa_public_encrypt, -1) +static RSAFUNC(null_rsa_public_decrypt, -1) +static RSAFUNC(null_rsa_private_encrypt, -1) +static RSAFUNC(null_rsa_private_decrypt, -1) + +/* + * + */ + +int +RSA_generate_key_ex(RSA *r, int bits, BIGNUM *e, BN_GENCB *cb) +{ + if (r->meth->rsa_keygen) + return (*r->meth->rsa_keygen)(r, bits, e, cb); + return 0; +} + + +/* + * + */ + +static int +null_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +null_rsa_finish(RSA *rsa) +{ + return 1; +} + +static const RSA_METHOD rsa_null_method = { + "hcrypto null RSA", + null_rsa_public_encrypt, + null_rsa_public_decrypt, + null_rsa_private_encrypt, + null_rsa_private_decrypt, + NULL, + NULL, + null_rsa_init, + null_rsa_finish, + 0, + NULL, + NULL, + NULL, + NULL +}; + +const RSA_METHOD * +RSA_null_method(void) +{ + return &rsa_null_method; +} + +extern const RSA_METHOD hc_rsa_gmp_method; +extern const RSA_METHOD hc_rsa_tfm_method; +extern const RSA_METHOD hc_rsa_ltm_method; +static const RSA_METHOD *default_rsa_method = &hc_rsa_ltm_method; + + +const RSA_METHOD * +RSA_get_default_method(void) +{ + return default_rsa_method; +} + +void +RSA_set_default_method(const RSA_METHOD *meth) +{ + default_rsa_method = meth; +} + +/* + * + */ + +RSA * +d2i_RSAPrivateKey(RSA *rsa, const unsigned char **pp, size_t len) +{ + RSAPrivateKey data; + RSA *k = rsa; + size_t size; + int ret; + + ret = decode_RSAPrivateKey(*pp, len, &data, &size); + if (ret) + return NULL; + + *pp += size; + + if (k == NULL) { + k = RSA_new(); + if (k == NULL) { + free_RSAPrivateKey(&data); + return NULL; + } + } + + k->n = _hc_integer_to_BN(&data.modulus, NULL); + k->e = _hc_integer_to_BN(&data.publicExponent, NULL); + k->d = _hc_integer_to_BN(&data.privateExponent, NULL); + k->p = _hc_integer_to_BN(&data.prime1, NULL); + k->q = _hc_integer_to_BN(&data.prime2, NULL); + k->dmp1 = _hc_integer_to_BN(&data.exponent1, NULL); + k->dmq1 = _hc_integer_to_BN(&data.exponent2, NULL); + k->iqmp = _hc_integer_to_BN(&data.coefficient, NULL); + free_RSAPrivateKey(&data); + + if (k->n == NULL || k->e == NULL || k->d == NULL || k->p == NULL || + k->q == NULL || k->dmp1 == NULL || k->dmq1 == NULL || k->iqmp == NULL) + { + RSA_free(k); + return NULL; + } + + return k; +} + +int +i2d_RSAPrivateKey(RSA *rsa, unsigned char **pp) +{ + RSAPrivateKey data; + size_t size; + int ret; + + if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL || rsa->p == NULL || + rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == NULL || + rsa->iqmp == NULL) + return -1; + + memset(&data, 0, sizeof(data)); + + ret = _hc_BN_to_integer(rsa->n, &data.modulus); + ret |= _hc_BN_to_integer(rsa->e, &data.publicExponent); + ret |= _hc_BN_to_integer(rsa->d, &data.privateExponent); + ret |= _hc_BN_to_integer(rsa->p, &data.prime1); + ret |= _hc_BN_to_integer(rsa->q, &data.prime2); + ret |= _hc_BN_to_integer(rsa->dmp1, &data.exponent1); + ret |= _hc_BN_to_integer(rsa->dmq1, &data.exponent2); + ret |= _hc_BN_to_integer(rsa->iqmp, &data.coefficient); + if (ret) { + free_RSAPrivateKey(&data); + return -1; + } + + if (pp == NULL) { + size = length_RSAPrivateKey(&data); + free_RSAPrivateKey(&data); + } else { + void *p; + size_t len; + + ASN1_MALLOC_ENCODE(RSAPrivateKey, p, len, &data, &size, ret); + free_RSAPrivateKey(&data); + if (ret) + return -1; + if (len != size) + abort(); + + memcpy(*pp, p, size); + free(p); + + *pp += size; + + } + return size; +} + +int +i2d_RSAPublicKey(RSA *rsa, unsigned char **pp) +{ + RSAPublicKey data; + size_t size; + int ret; + + memset(&data, 0, sizeof(data)); + + if (_hc_BN_to_integer(rsa->n, &data.modulus) || + _hc_BN_to_integer(rsa->e, &data.publicExponent)) + { + free_RSAPublicKey(&data); + return -1; + } + + if (pp == NULL) { + size = length_RSAPublicKey(&data); + free_RSAPublicKey(&data); + } else { + void *p; + size_t len; + + ASN1_MALLOC_ENCODE(RSAPublicKey, p, len, &data, &size, ret); + free_RSAPublicKey(&data); + if (ret) + return -1; + if (len != size) + abort(); + + memcpy(*pp, p, size); + free(p); + + *pp += size; + } + + return size; +} + +RSA * +d2i_RSAPublicKey(RSA *rsa, const unsigned char **pp, size_t len) +{ + RSAPublicKey data; + RSA *k = rsa; + size_t size; + int ret; + + ret = decode_RSAPublicKey(*pp, len, &data, &size); + if (ret) + return NULL; + + *pp += size; + + if (k == NULL) { + k = RSA_new(); + if (k == NULL) { + free_RSAPublicKey(&data); + return NULL; + } + } + + k->n = _hc_integer_to_BN(&data.modulus, NULL); + k->e = _hc_integer_to_BN(&data.publicExponent, NULL); + + free_RSAPublicKey(&data); + + if (k->n == NULL || k->e == NULL) { + RSA_free(k); + return NULL; + } + + return k; +} diff --git a/third_party/heimdal/lib/hcrypto/rsa.h b/third_party/heimdal/lib/hcrypto/rsa.h new file mode 100644 index 0000000..d59213b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/rsa.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef _HEIM_RSA_H +#define _HEIM_RSA_H 1 + +/* symbol renaming */ +#define RSA_null_method hc_RSA_null_method +#define RSA_ltm_method hc_RSA_ltm_method +#define RSA_gmp_method hc_RSA_gmp_method +#define RSA_tfm_method hc_RSA_tfm_method +#define RSA_new hc_RSA_new +#define RSA_new_method hc_RSA_new_method +#define RSA_free hc_RSA_free +#define RSA_up_ref hc_RSA_up_ref +#define RSA_set_default_method hc_RSA_set_default_method +#define RSA_get_default_method hc_RSA_get_default_method +#define RSA_set_method hc_RSA_set_method +#define RSA_get_method hc_RSA_get_method +#define RSA_set_app_data hc_RSA_set_app_data +#define RSA_get_app_data hc_RSA_get_app_data +#define RSA_check_key hc_RSA_check_key +#define RSA_size hc_RSA_size +#define RSA_public_encrypt hc_RSA_public_encrypt +#define RSA_public_decrypt hc_RSA_public_decrypt +#define RSA_private_encrypt hc_RSA_private_encrypt +#define RSA_private_decrypt hc_RSA_private_decrypt +#define RSA_sign hc_RSA_sign +#define RSA_verify hc_RSA_verify +#define RSA_generate_key_ex hc_RSA_generate_key_ex +#define d2i_RSAPrivateKey hc_d2i_RSAPrivateKey +#define i2d_RSAPrivateKey hc_i2d_RSAPrivateKey +#define i2d_RSAPublicKey hc_i2d_RSAPublicKey +#define d2i_RSAPublicKey hc_d2i_RSAPublicKey + +#define RSA hc_RSA +#define RSA_METHOD hc_RSA_METHOD + +/* + * + */ + +typedef struct RSA RSA; +typedef struct RSA_METHOD RSA_METHOD; + +#include +#include + +struct RSA_METHOD { + const char *name; + int (*rsa_pub_enc)(int,const unsigned char *, unsigned char *, RSA *,int); + int (*rsa_pub_dec)(int,const unsigned char *, unsigned char *, RSA *,int); + int (*rsa_priv_enc)(int,const unsigned char *, unsigned char *, RSA *,int); + int (*rsa_priv_dec)(int,const unsigned char *, unsigned char *, RSA *,int); + void *rsa_mod_exp; + void *bn_mod_exp; + int (*init)(RSA *rsa); + int (*finish)(RSA *rsa); + int flags; + char *app_data; + int (*rsa_sign)(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int *, const RSA *); + int (*rsa_verify)(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int, const RSA *); + int (*rsa_keygen)(RSA *, int, BIGNUM *, BN_GENCB *); +}; + +struct RSA { + int pad; + long version; + const RSA_METHOD *meth; + void *engine; + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + struct rsa_CRYPTO_EX_DATA { + void *sk; + int dummy; + } ex_data; + int references; + int flags; + void *_method_mod_n; + void *_method_mod_p; + void *_method_mod_q; + + char *bignum_data; + void *blinding; + void *mt_blinding; +}; + +#define RSA_FLAG_NO_BLINDING 0x0080 + +#define RSA_PKCS1_PADDING 1 +#define RSA_PKCS1_OAEP_PADDING 4 +#define RSA_PKCS1_PADDING_SIZE 11 + +/* + * + */ + +const RSA_METHOD *RSA_null_method(void); +const RSA_METHOD *RSA_gmp_method(void); +const RSA_METHOD *RSA_tfm_method(void); +const RSA_METHOD *RSA_ltm_method(void); + +/* + * + */ + +RSA * RSA_new(void); +RSA * RSA_new_method(ENGINE *); +void RSA_free(RSA *); +int RSA_up_ref(RSA *); + +void RSA_set_default_method(const RSA_METHOD *); +const RSA_METHOD * RSA_get_default_method(void); + +const RSA_METHOD * RSA_get_method(const RSA *); +int RSA_set_method(RSA *, const RSA_METHOD *); + +int RSA_set_app_data(RSA *, void *arg); +void * RSA_get_app_data(const RSA *); + +int RSA_check_key(const RSA *); +int RSA_size(const RSA *); + +int RSA_public_encrypt(int,const unsigned char*,unsigned char*,RSA *,int); +int RSA_private_encrypt(int,const unsigned char*,unsigned char*,RSA *,int); +int RSA_public_decrypt(int,const unsigned char*,unsigned char*,RSA *,int); +int RSA_private_decrypt(int,const unsigned char*,unsigned char*,RSA *,int); + +int RSA_sign(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int *, RSA *); +int RSA_verify(int, const unsigned char *, unsigned int, + unsigned char *, unsigned int, RSA *); + +int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); + +RSA * d2i_RSAPrivateKey(RSA *, const unsigned char **, size_t); +int i2d_RSAPrivateKey(RSA *, unsigned char **); + +int i2d_RSAPublicKey(RSA *, unsigned char **); +RSA * d2i_RSAPublicKey(RSA *, const unsigned char **, size_t); + +#endif /* _HEIM_RSA_H */ diff --git a/third_party/heimdal/lib/hcrypto/rsakey.der b/third_party/heimdal/lib/hcrypto/rsakey.der new file mode 100644 index 0000000..e7c665e Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/rsakey.der differ diff --git a/third_party/heimdal/lib/hcrypto/rsakey2048.der b/third_party/heimdal/lib/hcrypto/rsakey2048.der new file mode 100644 index 0000000..c802d3b Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/rsakey2048.der differ diff --git a/third_party/heimdal/lib/hcrypto/rsakey4096.der b/third_party/heimdal/lib/hcrypto/rsakey4096.der new file mode 100644 index 0000000..1b763b8 Binary files /dev/null and b/third_party/heimdal/lib/hcrypto/rsakey4096.der differ diff --git a/third_party/heimdal/lib/hcrypto/sha.c b/third_party/heimdal/lib/hcrypto/sha.c new file mode 100644 index 0000000..8eae9b4 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/sha.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hash.h" +#include "sha.h" + +#define A m->counter[0] +#define B m->counter[1] +#define C m->counter[2] +#define D m->counter[3] +#define E m->counter[4] +#define X data + +int +SHA1_Init (struct sha *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + A = 0x67452301; + B = 0xefcdab89; + C = 0x98badcfe; + D = 0x10325476; + E = 0xc3d2e1f0; + return 1; +} + + +#define F0(x,y,z) CRAYFIX((x & y) | (~x & z)) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (x & z) | (y & z)) +#define F3(x,y,z) F1(x,y,z) + +#define K0 0x5a827999 +#define K1 0x6ed9eba1 +#define K2 0x8f1bbcdc +#define K3 0xca62c1d6 + +#define DO(t,f,k) \ +do { \ + uint32_t temp; \ + \ + temp = cshift(AA, 5) + f(BB,CC,DD) + EE + data[t] + k; \ + EE = DD; \ + DD = CC; \ + CC = cshift(BB, 30); \ + BB = AA; \ + AA = temp; \ +} while(0) + +static inline void +calc (struct sha *m, uint32_t *in) +{ + uint32_t AA, BB, CC, DD, EE; + uint32_t data[80]; + int i; + + AA = A; + BB = B; + CC = C; + DD = D; + EE = E; + + for (i = 0; i < 16; ++i) + data[i] = in[i]; + for (i = 16; i < 80; ++i) + data[i] = cshift(data[i-3] ^ data[i-8] ^ data[i-14] ^ data[i-16], 1); + + /* t=[0,19] */ + + DO(0,F0,K0); + DO(1,F0,K0); + DO(2,F0,K0); + DO(3,F0,K0); + DO(4,F0,K0); + DO(5,F0,K0); + DO(6,F0,K0); + DO(7,F0,K0); + DO(8,F0,K0); + DO(9,F0,K0); + DO(10,F0,K0); + DO(11,F0,K0); + DO(12,F0,K0); + DO(13,F0,K0); + DO(14,F0,K0); + DO(15,F0,K0); + DO(16,F0,K0); + DO(17,F0,K0); + DO(18,F0,K0); + DO(19,F0,K0); + + /* t=[20,39] */ + + DO(20,F1,K1); + DO(21,F1,K1); + DO(22,F1,K1); + DO(23,F1,K1); + DO(24,F1,K1); + DO(25,F1,K1); + DO(26,F1,K1); + DO(27,F1,K1); + DO(28,F1,K1); + DO(29,F1,K1); + DO(30,F1,K1); + DO(31,F1,K1); + DO(32,F1,K1); + DO(33,F1,K1); + DO(34,F1,K1); + DO(35,F1,K1); + DO(36,F1,K1); + DO(37,F1,K1); + DO(38,F1,K1); + DO(39,F1,K1); + + /* t=[40,59] */ + + DO(40,F2,K2); + DO(41,F2,K2); + DO(42,F2,K2); + DO(43,F2,K2); + DO(44,F2,K2); + DO(45,F2,K2); + DO(46,F2,K2); + DO(47,F2,K2); + DO(48,F2,K2); + DO(49,F2,K2); + DO(50,F2,K2); + DO(51,F2,K2); + DO(52,F2,K2); + DO(53,F2,K2); + DO(54,F2,K2); + DO(55,F2,K2); + DO(56,F2,K2); + DO(57,F2,K2); + DO(58,F2,K2); + DO(59,F2,K2); + + /* t=[60,79] */ + + DO(60,F3,K3); + DO(61,F3,K3); + DO(62,F3,K3); + DO(63,F3,K3); + DO(64,F3,K3); + DO(65,F3,K3); + DO(66,F3,K3); + DO(67,F3,K3); + DO(68,F3,K3); + DO(69,F3,K3); + DO(70,F3,K3); + DO(71,F3,K3); + DO(72,F3,K3); + DO(73,F3,K3); + DO(74,F3,K3); + DO(75,F3,K3); + DO(76,F3,K3); + DO(77,F3,K3); + DO(78,F3,K3); + DO(79,F3,K3); + + A += AA; + B += BB; + C += CC; + D += DD; + E += EE; +} + +/* + * From `Performance analysis of MD5' by Joseph D. Touch + */ + +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) +static inline uint32_t +swap_uint32_t (uint32_t t) +{ +#define ROL(x,n) ((x)<<(n))|((x)>>(32-(n))) + uint32_t temp1, temp2; + + temp1 = cshift(t, 16); + temp2 = temp1 >> 8; + temp1 &= 0x00ff00ff; + temp2 &= 0x00ff00ff; + temp1 <<= 8; + return temp1 | temp2; +} +#endif + +struct x32{ + unsigned int a:32; + unsigned int b:32; +}; + +int +SHA1_Update (struct sha *m, const void *v, size_t len) +{ + const unsigned char *p = v; + size_t old_sz = m->sz[0]; + size_t offset; + + m->sz[0] += len * 8; + if (m->sz[0] < old_sz) + ++m->sz[1]; + offset = (old_sz / 8) % 64; + while(len > 0){ + size_t l = min(len, 64 - offset); + memcpy(m->save + offset, p, l); + offset += l; + p += l; + len -= l; + if(offset == 64){ +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) + int i; + uint32_t SHA1current[16]; + struct x32 *us = (struct x32*)m->save; + for(i = 0; i < 8; i++){ + SHA1current[2*i+0] = swap_uint32_t(us[i].a); + SHA1current[2*i+1] = swap_uint32_t(us[i].b); + } + calc(m, SHA1current); +#else + calc(m, (uint32_t*)m->save); +#endif + offset = 0; + } + } + return 1; +} + +int +SHA1_Final (void *res, struct sha *m) +{ + unsigned char zeros[72]; + unsigned offset = (m->sz[0] / 8) % 64; + unsigned int dstart = (120 - offset - 1) % 64 + 1; + + *zeros = 0x80; + memset (zeros + 1, 0, sizeof(zeros) - 1); + zeros[dstart+7] = (m->sz[0] >> 0) & 0xff; + zeros[dstart+6] = (m->sz[0] >> 8) & 0xff; + zeros[dstart+5] = (m->sz[0] >> 16) & 0xff; + zeros[dstart+4] = (m->sz[0] >> 24) & 0xff; + zeros[dstart+3] = (m->sz[1] >> 0) & 0xff; + zeros[dstart+2] = (m->sz[1] >> 8) & 0xff; + zeros[dstart+1] = (m->sz[1] >> 16) & 0xff; + zeros[dstart+0] = (m->sz[1] >> 24) & 0xff; + SHA1_Update (m, zeros, dstart + 8); + { + int i; + unsigned char *r = (unsigned char*)res; + + for (i = 0; i < 5; ++i) { + r[4*i+3] = m->counter[i] & 0xFF; + r[4*i+2] = (m->counter[i] >> 8) & 0xFF; + r[4*i+1] = (m->counter[i] >> 16) & 0xFF; + r[4*i] = (m->counter[i] >> 24) & 0xFF; + } + } +#if 0 + { + int i; + uint32_t *r = (uint32_t *)res; + + for (i = 0; i < 5; ++i) + r[i] = swap_uint32_t (m->counter[i]); + } +#endif + return 1; +} diff --git a/third_party/heimdal/lib/hcrypto/sha.h b/third_party/heimdal/lib/hcrypto/sha.h new file mode 100644 index 0000000..59d7240 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/sha.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_SHA_H +#define HEIM_SHA_H 1 + +/* symbol renaming */ +#define SHA1_Init hc_SHA1_Init +#define SHA1_Update hc_SHA1_Update +#define SHA1_Final hc_SHA1_Final +#define SHA256_Init hc_SHA256_Init +#define SHA256_Update hc_SHA256_Update +#define SHA256_Final hc_SHA256_Final +#define SHA384_Init hc_SHA384_Init +#define SHA384_Update hc_SHA384_Update +#define SHA384_Final hc_SHA384_Final +#define SHA512_Init hc_SHA512_Init +#define SHA512_Update hc_SHA512_Update +#define SHA512_Final hc_SHA512_Final + +/* + * SHA-1 + */ + +#define SHA_DIGEST_LENGTH 20 + +struct sha { + unsigned int sz[2]; + uint32_t counter[5]; + unsigned char save[64]; +}; + +typedef struct sha SHA_CTX; + +int SHA1_Init (struct sha *m); +int SHA1_Update (struct sha *m, const void *v, size_t len); +int SHA1_Final (void *res, struct sha *m); + +/* + * SHA-2 256 + */ + +#define SHA256_DIGEST_LENGTH 32 + +struct hc_sha256state { + unsigned int sz[2]; + uint32_t counter[8]; + unsigned char save[64]; +}; + +typedef struct hc_sha256state SHA256_CTX; + +int SHA256_Init (SHA256_CTX *); +int SHA256_Update (SHA256_CTX *, const void *, size_t); +int SHA256_Final (void *, SHA256_CTX *); + +/* + * SHA-2 512 + */ + +#define SHA512_DIGEST_LENGTH 64 + +struct hc_sha512state { + uint64_t sz[2]; + uint64_t counter[8]; + unsigned char save[128]; +}; + +typedef struct hc_sha512state SHA512_CTX; + +int SHA512_Init (SHA512_CTX *); +int SHA512_Update (SHA512_CTX *, const void *, size_t); +int SHA512_Final (void *, SHA512_CTX *); + +#define SHA384_DIGEST_LENGTH 48 + +typedef struct hc_sha512state SHA384_CTX; + +int SHA384_Init (SHA384_CTX *); +int SHA384_Update (SHA384_CTX *, const void *, size_t); +int SHA384_Final (void *, SHA384_CTX *); + +#endif /* HEIM_SHA_H */ diff --git a/third_party/heimdal/lib/hcrypto/sha256.c b/third_party/heimdal/lib/hcrypto/sha256.c new file mode 100644 index 0000000..1b62ba2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/sha256.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hash.h" +#include "sha.h" + +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#define ROTR(x,n) (((x)>>(n)) | ((x) << (32 - (n)))) + +#define Sigma0(x) (ROTR(x,2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define Sigma1(x) (ROTR(x,6) ^ ROTR(x,11) ^ ROTR(x,25)) +#define sigma0(x) (ROTR(x,7) ^ ROTR(x,18) ^ ((x)>>3)) +#define sigma1(x) (ROTR(x,17) ^ ROTR(x,19) ^ ((x)>>10)) + +#define A m->counter[0] +#define B m->counter[1] +#define C m->counter[2] +#define D m->counter[3] +#define E m->counter[4] +#define F m->counter[5] +#define G m->counter[6] +#define H m->counter[7] + +static const uint32_t constant_256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +int +SHA256_Init (SHA256_CTX *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + A = 0x6a09e667; + B = 0xbb67ae85; + C = 0x3c6ef372; + D = 0xa54ff53a; + E = 0x510e527f; + F = 0x9b05688c; + G = 0x1f83d9ab; + H = 0x5be0cd19; + return 1; +} + +static void +calc (SHA256_CTX *m, uint32_t *in) +{ + uint32_t AA, BB, CC, DD, EE, FF, GG, HH; + uint32_t data[64]; + int i; + + AA = A; + BB = B; + CC = C; + DD = D; + EE = E; + FF = F; + GG = G; + HH = H; + + for (i = 0; i < 16; ++i) + data[i] = in[i]; + for (i = 16; i < 64; ++i) + data[i] = sigma1(data[i-2]) + data[i-7] + + sigma0(data[i-15]) + data[i - 16]; + + for (i = 0; i < 64; i++) { + uint32_t T1, T2; + + T1 = HH + Sigma1(EE) + Ch(EE, FF, GG) + constant_256[i] + data[i]; + T2 = Sigma0(AA) + Maj(AA,BB,CC); + + HH = GG; + GG = FF; + FF = EE; + EE = DD + T1; + DD = CC; + CC = BB; + BB = AA; + AA = T1 + T2; + } + + A += AA; + B += BB; + C += CC; + D += DD; + E += EE; + F += FF; + G += GG; + H += HH; +} + +/* + * From `Performance analysis of MD5' by Joseph D. Touch + */ + +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) +static inline uint32_t +swap_uint32_t (uint32_t t) +{ +#define ROL(x,n) ((x)<<(n))|((x)>>(32-(n))) + uint32_t temp1, temp2; + + temp1 = cshift(t, 16); + temp2 = temp1 >> 8; + temp1 &= 0x00ff00ff; + temp2 &= 0x00ff00ff; + temp1 <<= 8; + return temp1 | temp2; +} +#endif + +struct x32{ + unsigned int a:32; + unsigned int b:32; +}; + +int +SHA256_Update (SHA256_CTX *m, const void *v, size_t len) +{ + const unsigned char *p = v; + size_t old_sz = m->sz[0]; + size_t offset; + + m->sz[0] += len * 8; + if (m->sz[0] < old_sz) + ++m->sz[1]; + offset = (old_sz / 8) % 64; + while(len > 0){ + size_t l = min(len, 64 - offset); + memcpy(m->save + offset, p, l); + offset += l; + p += l; + len -= l; + if(offset == 64){ +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) + int i; + uint32_t current[16]; + struct x32 *us = (struct x32*)m->save; + for(i = 0; i < 8; i++){ + current[2*i+0] = swap_uint32_t(us[i].a); + current[2*i+1] = swap_uint32_t(us[i].b); + } + calc(m, current); +#else + calc(m, (uint32_t*)m->save); +#endif + offset = 0; + } + } + return 1; +} + +int +SHA256_Final (void *res, SHA256_CTX *m) +{ + unsigned char zeros[72]; + unsigned offset = (m->sz[0] / 8) % 64; + unsigned int dstart = (120 - offset - 1) % 64 + 1; + + *zeros = 0x80; + memset (zeros + 1, 0, sizeof(zeros) - 1); + zeros[dstart+7] = (m->sz[0] >> 0) & 0xff; + zeros[dstart+6] = (m->sz[0] >> 8) & 0xff; + zeros[dstart+5] = (m->sz[0] >> 16) & 0xff; + zeros[dstart+4] = (m->sz[0] >> 24) & 0xff; + zeros[dstart+3] = (m->sz[1] >> 0) & 0xff; + zeros[dstart+2] = (m->sz[1] >> 8) & 0xff; + zeros[dstart+1] = (m->sz[1] >> 16) & 0xff; + zeros[dstart+0] = (m->sz[1] >> 24) & 0xff; + SHA256_Update (m, zeros, dstart + 8); + { + int i; + unsigned char *r = (unsigned char*)res; + + for (i = 0; i < 8; ++i) { + r[4*i+3] = m->counter[i] & 0xFF; + r[4*i+2] = (m->counter[i] >> 8) & 0xFF; + r[4*i+1] = (m->counter[i] >> 16) & 0xFF; + r[4*i] = (m->counter[i] >> 24) & 0xFF; + } + } + return 1; +} diff --git a/third_party/heimdal/lib/hcrypto/sha512.c b/third_party/heimdal/lib/hcrypto/sha512.c new file mode 100644 index 0000000..98c418e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/sha512.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2006, 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hash.h" +#include "sha.h" + +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#define ROTR(x,n) (((x)>>(n)) | ((x) << (64 - (n)))) + +#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) +#define sigma0(x) (ROTR(x,1) ^ ROTR(x,8) ^ ((x)>>7)) +#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ ((x)>>6)) + +#define A m->counter[0] +#define B m->counter[1] +#define C m->counter[2] +#define D m->counter[3] +#define E m->counter[4] +#define F m->counter[5] +#define G m->counter[6] +#define H m->counter[7] + +static const uint64_t constant_512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +int +SHA512_Init (SHA512_CTX *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + A = 0x6a09e667f3bcc908ULL; + B = 0xbb67ae8584caa73bULL; + C = 0x3c6ef372fe94f82bULL; + D = 0xa54ff53a5f1d36f1ULL; + E = 0x510e527fade682d1ULL; + F = 0x9b05688c2b3e6c1fULL; + G = 0x1f83d9abfb41bd6bULL; + H = 0x5be0cd19137e2179ULL; + return 1; +} + +static void +calc (SHA512_CTX *m, uint64_t *in) +{ + uint64_t AA, BB, CC, DD, EE, FF, GG, HH; + uint64_t data[80]; + int i; + + AA = A; + BB = B; + CC = C; + DD = D; + EE = E; + FF = F; + GG = G; + HH = H; + + for (i = 0; i < 16; ++i) + data[i] = in[i]; + for (i = 16; i < 80; ++i) + data[i] = sigma1(data[i-2]) + data[i-7] + + sigma0(data[i-15]) + data[i - 16]; + + for (i = 0; i < 80; i++) { + uint64_t T1, T2; + + T1 = HH + Sigma1(EE) + Ch(EE, FF, GG) + constant_512[i] + data[i]; + T2 = Sigma0(AA) + Maj(AA,BB,CC); + + HH = GG; + GG = FF; + FF = EE; + EE = DD + T1; + DD = CC; + CC = BB; + BB = AA; + AA = T1 + T2; + } + + A += AA; + B += BB; + C += CC; + D += DD; + E += EE; + F += FF; + G += GG; + H += HH; +} + +/* + * From `Performance analysis of MD5' by Joseph D. Touch + */ + +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) +static inline uint64_t +swap_uint64_t (uint64_t t) +{ + uint64_t temp; + + temp = cshift64(t, 32); + temp = ((temp & 0xff00ff00ff00ff00ULL) >> 8) | + ((temp & 0x00ff00ff00ff00ffULL) << 8); + return ((temp & 0xffff0000ffff0000ULL) >> 16) | + ((temp & 0x0000ffff0000ffffULL) << 16); +} + +struct x64{ + uint64_t a; + uint64_t b; +}; +#endif + +int +SHA512_Update (SHA512_CTX *m, const void *v, size_t len) +{ + const unsigned char *p = v; + size_t old_sz = m->sz[0]; + size_t offset; + + m->sz[0] += len * 8; + if (m->sz[0] < old_sz) + ++m->sz[1]; + offset = (old_sz / 8) % 128; + while(len > 0){ + size_t l = min(len, 128 - offset); + memcpy(m->save + offset, p, l); + offset += l; + p += l; + len -= l; + if(offset == 128){ +#if !defined(WORDS_BIGENDIAN) || defined(_CRAY) + int i; + uint64_t current[16]; + struct x64 *us = (struct x64*)m->save; + for(i = 0; i < 8; i++){ + current[2*i+0] = swap_uint64_t(us[i].a); + current[2*i+1] = swap_uint64_t(us[i].b); + } + calc(m, current); +#else + calc(m, (uint64_t*)m->save); +#endif + offset = 0; + } + } + return 1; +} + +int +SHA512_Final (void *res, SHA512_CTX *m) +{ + unsigned char zeros[128 + 16]; + unsigned offset = (m->sz[0] / 8) % 128; + unsigned int dstart = (240 - offset - 1) % 128 + 1; + + *zeros = 0x80; + memset (zeros + 1, 0, sizeof(zeros) - 1); + zeros[dstart+15] = (m->sz[0] >> 0) & 0xff; + zeros[dstart+14] = (m->sz[0] >> 8) & 0xff; + zeros[dstart+13] = (m->sz[0] >> 16) & 0xff; + zeros[dstart+12] = (m->sz[0] >> 24) & 0xff; + zeros[dstart+11] = (m->sz[0] >> 32) & 0xff; + zeros[dstart+10] = (m->sz[0] >> 40) & 0xff; + zeros[dstart+9] = (m->sz[0] >> 48) & 0xff; + zeros[dstart+8] = (m->sz[0] >> 56) & 0xff; + + zeros[dstart+7] = (m->sz[1] >> 0) & 0xff; + zeros[dstart+6] = (m->sz[1] >> 8) & 0xff; + zeros[dstart+5] = (m->sz[1] >> 16) & 0xff; + zeros[dstart+4] = (m->sz[1] >> 24) & 0xff; + zeros[dstart+3] = (m->sz[1] >> 32) & 0xff; + zeros[dstart+2] = (m->sz[1] >> 40) & 0xff; + zeros[dstart+1] = (m->sz[1] >> 48) & 0xff; + zeros[dstart+0] = (m->sz[1] >> 56) & 0xff; + SHA512_Update (m, zeros, dstart + 16); + { + int i; + unsigned char *r = (unsigned char*)res; + + for (i = 0; i < 8; ++i) { + r[8*i+7] = m->counter[i] & 0xFF; + r[8*i+6] = (m->counter[i] >> 8) & 0xFF; + r[8*i+5] = (m->counter[i] >> 16) & 0xFF; + r[8*i+4] = (m->counter[i] >> 24) & 0xFF; + r[8*i+3] = (m->counter[i] >> 32) & 0XFF; + r[8*i+2] = (m->counter[i] >> 40) & 0xFF; + r[8*i+1] = (m->counter[i] >> 48) & 0xFF; + r[8*i] = (m->counter[i] >> 56) & 0xFF; + } + } + return 1; +} + +int +SHA384_Init(SHA384_CTX *m) +{ + m->sz[0] = 0; + m->sz[1] = 0; + A = 0xcbbb9d5dc1059ed8ULL; + B = 0x629a292a367cd507ULL; + C = 0x9159015a3070dd17ULL; + D = 0x152fecd8f70e5939ULL; + E = 0x67332667ffc00b31ULL; + F = 0x8eb44a8768581511ULL; + G = 0xdb0c2e0d64f98fa7ULL; + H = 0x47b5481dbefa4fa4ULL; + return 1; +} + +int +SHA384_Update (SHA384_CTX *m, const void *v, size_t len) +{ + SHA512_Update(m, v, len); + return 1; +} + +int +SHA384_Final (void *res, SHA384_CTX *m) +{ + unsigned char data[SHA512_DIGEST_LENGTH]; + SHA512_Final(data, m); + memcpy(res, data, SHA384_DIGEST_LENGTH); + return 1; +} + diff --git a/third_party/heimdal/lib/hcrypto/test_bn.c b/third_party/heimdal/lib/hcrypto/test_bn.c new file mode 100644 index 0000000..74709fe --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_bn.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +static int +set_get(unsigned long num) +{ + BIGNUM *bn; + + bn = BN_new(); + if (!BN_set_word(bn, num)) + return 1; + + if (BN_get_word(bn) != num) + return 1; + + BN_free(bn); + return 0; +} + +#define CHECK(x) do { ret += x; } while(0) + +static int +test_BN_set_get(void) +{ + int ret = 0; + CHECK(set_get(0)); + CHECK(set_get(1)); + CHECK(set_get(0xff)); + CHECK(set_get(0x1ff)); + CHECK(set_get(0xffff)); + CHECK(set_get(0xf000)); + CHECK(set_get(ULONG_MAX / 2)); + CHECK(set_get(ULONG_MAX - 1)); + + return ret; +} + +static int +test_BN_bit(void) +{ + BIGNUM *bn; + int ret = 0; + + bn = BN_new(); + + /* test setting and getting of "word" */ + if (!BN_set_word(bn, 1)) + return 1; + if (!BN_is_bit_set(bn, 0)) + ret += 1; + if (!BN_is_bit_set(bn, 0)) + ret += 1; + + if (!BN_set_word(bn, 2)) + return 1; + if (!BN_is_bit_set(bn, 1)) + ret += 1; + + if (!BN_set_word(bn, 3)) + return 1; + if (!BN_is_bit_set(bn, 0)) + ret += 1; + if (!BN_is_bit_set(bn, 1)) + ret += 1; + + if (!BN_set_word(bn, 0x100)) + return 1; + if (!BN_is_bit_set(bn, 8)) + ret += 1; + + if (!BN_set_word(bn, 0x1000)) + return 1; + if (!BN_is_bit_set(bn, 12)) + ret += 1; + + /* test bitsetting */ + if (!BN_set_word(bn, 1)) + return 1; + if (!BN_set_bit(bn, 1)) + return 1; + if (BN_get_word(bn) != 3) + return 1; + if (!BN_clear_bit(bn, 0)) + return 1; + if (BN_get_word(bn) != 2) + return 1; + + /* test bitsetting past end of current end */ + BN_clear(bn); + if (!BN_set_bit(bn, 12)) + return 1; + if (BN_get_word(bn) != 0x1000) + return 1; + + /* test bit and byte counting functions */ + if (BN_num_bits(bn) != 13) + return 1; + if (BN_num_bytes(bn) != 2) + return 1; + + BN_free(bn); + return ret; +} + +struct ietest { + char *data; + size_t len; + unsigned long num; +} ietests[] = { + { "", 0, 0 }, + { "\x01", 1, 1 }, + { "\x02", 1, 2 }, + { "\xf2", 1, 0xf2 }, + { "\x01\x00", 2, 256 } +}; + +static int +test_BN_import_export(void) +{ + BIGNUM *bn; + int ret = 0; + int i; + + bn = BN_new(); + + for (i = 0; i < sizeof(ietests)/sizeof(ietests[0]); i++) { + size_t len; + unsigned char *p; + if (!BN_bin2bn((unsigned char*)ietests[i].data, ietests[i].len, bn)) + return 1; + if (BN_get_word(bn) != ietests[i].num) + return 1; + len = BN_num_bytes(bn); + if (len != ietests[i].len) + return 1; + p = malloc(len + 1); + p[len] = 0xf4; + BN_bn2bin(bn, p); + if (p[len] != 0xf4) + return 1; + if (memcmp(p, ietests[i].data, ietests[i].len) != 0) + return 1; + free(p); + } + + BN_free(bn); + return ret; +} + +static int +test_BN_uadd(void) +{ + BIGNUM *a, *b, *c; + char *p; + + a = BN_new(); + b = BN_new(); + c = BN_new(); + + BN_set_word(a, 1); + BN_set_word(b, 2); + + BN_uadd(c, a, b); + + if (BN_get_word(c) != 3) + return 1; + + BN_uadd(c, b, a); + + if (BN_get_word(c) != 3) + return 1; + + BN_set_word(b, 0xff); + + BN_uadd(c, a, b); + if (BN_get_word(c) != 0x100) + return 1; + + BN_uadd(c, b, a); + if (BN_get_word(c) != 0x100) + return 1; + + BN_set_word(a, 0xff); + + BN_uadd(c, a, b); + if (BN_get_word(c) != 0x1fe) + return 1; + + BN_uadd(c, b, a); + if (BN_get_word(c) != 0x1fe) + return 1; + + + BN_free(a); + BN_free(b); + + BN_hex2bn(&a, "50212A3B611D46642C825A16A354CE0FD4D85DD2"); + BN_hex2bn(&b, "84B6C7E8D28ACA1614954DA"); + + BN_uadd(c, b, a); + p = BN_bn2hex(c); + if (strcmp(p, "50212A3B611D466434CDC695307D7AB13621B2AC") != 0) { + free(p); + return 1; + } + free(p); + + BN_uadd(c, a, b); + p = BN_bn2hex(c); + if (strcmp(p, "50212A3B611D466434CDC695307D7AB13621B2AC") != 0) { + free(p); + return 1; + } + free(p); + + BN_free(a); + BN_free(b); + BN_free(c); + + return 0; +} + +static int +test_BN_cmp(void) +{ + BIGNUM *a, *b; + + a = BN_new(); + b = BN_new(); + + if (!BN_set_word(a, 1)) + return 1; + if (!BN_set_word(b, 1)) + return 1; + + if (BN_cmp(a, b) != 0) + return 1; + if (BN_cmp(b, a) != 0) + return 1; + + if (!BN_set_word(b, 2)) + return 1; + + if (BN_cmp(a, b) >= 0) + return 1; + if (BN_cmp(b, a) <= 0) + return 1; + + BN_set_negative(b, 1); + + if (BN_cmp(a, b) <= 0) + return 1; + if (BN_cmp(b, a) >= 0) + return 1; + + BN_free(a); + BN_free(b); + + BN_hex2bn(&a, "50212A3B611D46642C825A16A354CE0FD4D85DD1"); + BN_hex2bn(&b, "50212A3B611D46642C825A16A354CE0FD4D85DD2"); + + if (BN_cmp(a, b) >= 0) + return 1; + if (BN_cmp(b, a) <= 0) + return 1; + + BN_set_negative(b, 1); + + if (BN_cmp(a, b) <= 0) + return 1; + if (BN_cmp(b, a) >= 0) + return 1; + + BN_free(a); + BN_free(b); + return 0; +} + +static int +test_BN_rand(void) +{ + BIGNUM *bn; + + if (RAND_status() != 1) + return 0; + + bn = BN_new(); + if (bn == NULL) + return 1; + + if (!BN_rand(bn, 1024, 0, 0)) + return 1; + + BN_free(bn); + return 0; +} + +#define testnum 100 +#define testnum2 10 + +static int +test_BN_CTX(void) +{ + unsigned int i, j; + BIGNUM *bn; + BN_CTX *c; + + if ((c = BN_CTX_new()) == NULL) + return 1; + + for (i = 0; i < testnum; i++) { + BN_CTX_start(c); + BN_CTX_end(c); + } + + for (i = 0; i < testnum; i++) + BN_CTX_start(c); + for (i = 0; i < testnum; i++) + BN_CTX_end(c); + + for (i = 0; i < testnum; i++) { + BN_CTX_start(c); + if ((bn = BN_CTX_get(c)) == NULL) + return 1; + BN_CTX_end(c); + } + + for (i = 0; i < testnum; i++) { + BN_CTX_start(c); + for (j = 0; j < testnum2; j++) + if ((bn = BN_CTX_get(c)) == NULL) + return 1; + } + for (i = 0; i < testnum; i++) + BN_CTX_end(c); + + BN_CTX_free(c); + return 0; +} + + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_BN_set_get(); + ret += test_BN_bit(); + ret += test_BN_import_export(); + ret += test_BN_uadd(); + ret += test_BN_cmp(); + ret += test_BN_rand(); + ret += test_BN_CTX(); + + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/test_bulk.c b/third_party/heimdal/lib/hcrypto/test_bulk.c new file mode 100644 index 0000000..db5aeae --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_bulk.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#if defined(_WIN32) +#include +#endif +#include +#include +#include + +#ifdef WIN32 +#define STATS_START(M) \ + LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds; \ + LARGE_INTEGER Frequency; \ + \ + QueryPerformanceFrequency(&Frequency); \ + QueryPerformanceCounter(&StartingTime); + +#define STATS_END(M) \ + QueryPerformanceCounter(&EndingTime); \ + ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; \ + ElapsedMicroseconds.QuadPart *= 1000000; \ + ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; \ + \ + M += (ElapsedMicroseconds.QuadPart - M) / (i + 1); +#else +#define STATS_START(M) \ + struct timeval StartingTime, EndingTime; \ + \ + gettimeofday(&StartingTime, NULL); + +#define STATS_END(M) \ + gettimeofday(&EndingTime, NULL); \ + timevalsub(&EndingTime, &StartingTime); \ + M += (EndingTime.tv_sec * 1000000 + EndingTime.tv_usec - M) / (i + 1); +#endif + +static int version_flag; +static int help_flag; +static int len = 1; +static int loops = 20; +static char *provider = "hcrypto"; +static unsigned char *d; + +#ifdef __APPLE__ +#define PROVIDER_USAGE "hcrypto|cc" +#elif defined(WIN32) +#define PROVIDER_USAGE "hcrypto|w32crypto" +#elif __sun || defined(PKCS11_MODULE_PATH) +#define PROVIDER_USAGE "hcrypto|pkcs11" +#else +#define PROVIDER_USAGE "hcrypto" +#endif + +static struct getargs args[] = { + { "provider", 0, arg_string, &provider, + "crypto provider", PROVIDER_USAGE }, + { "loops", 0, arg_integer, &loops, + "number of loops", "loops" }, + { "size", 0, arg_integer, &len, + "size (KB)", NULL }, + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(*args), + NULL, + ""); + exit (ret); +} + +static int +test_bulk_cipher(const char *cname, const EVP_CIPHER *c) +{ + static unsigned char key[16]; + static unsigned char iv[16]; + int i; + int64_t M = 0; + + if (c == NULL) { + printf("%s not supported\n", cname); + return 0; + } + + for (i = 0; i < loops; i++) { + EVP_CIPHER_CTX ectx; + EVP_CIPHER_CTX dctx; + + STATS_START(M) + + EVP_CIPHER_CTX_init(&ectx); + EVP_CIPHER_CTX_init(&dctx); + + if (EVP_CipherInit_ex(&ectx, c, NULL, NULL, NULL, 1) != 1) + errx(1, "can't init encrypt"); + if (EVP_CipherInit_ex(&dctx, c, NULL, NULL, NULL, 0) != 1) + errx(1, "can't init decrypt"); + + EVP_CIPHER_CTX_set_key_length(&ectx, sizeof(key)); + EVP_CIPHER_CTX_set_key_length(&dctx, sizeof(key)); + + if (EVP_CipherInit_ex(&ectx, NULL, NULL, key, iv, 1) != 1) + errx(1, "can't init encrypt"); + if (EVP_CipherInit_ex(&dctx, NULL, NULL, key, iv, 0) != 1) + errx(1, "can't init decrypt"); + + if (!EVP_Cipher(&ectx, d, d, len)) + errx(1, "can't encrypt"); + if (!EVP_Cipher(&dctx, d, d, len)) + errx(1, "can't decrypt"); + + EVP_CIPHER_CTX_cleanup(&ectx); + EVP_CIPHER_CTX_cleanup(&dctx); + + STATS_END(M); + + if (d[0] != 0x00 || d[len - 1] != ((len - 1) & 0xff)) + errx(1, "encrypt/decrypt inconsistent"); + } + + printf("%s: mean time %llu usec%s\n", cname, (unsigned long long)M, + (M == 1) ? "" : "s"); + + return 0; +} + +static int +test_bulk_digest(const char *cname, const EVP_MD *md) +{ + char digest[EVP_MAX_MD_SIZE]; + int i; + unsigned int tmp = sizeof(digest); + int64_t M = 0; + + if (md == NULL) { + printf("%s not supported\n", cname); + return 0; + } + + for (i = 0; i < loops; i++) { + STATS_START(M); + EVP_Digest(d, len, digest, &tmp, md, NULL); + STATS_END(M); + } + + printf("%s: mean time %llu usec%s\n", cname, (unsigned long long)M, + (M == 1) ? "" : "s"); + + return 0; +} + +static void +test_bulk_provider_hcrypto(void) +{ + test_bulk_cipher("hcrypto_aes_256_cbc", EVP_hcrypto_aes_256_cbc()); +#if 0 + test_bulk_cipher("hcrypto_aes_256_cfb8", EVP_hcrypto_aes_256_cfb8()); +#endif + test_bulk_cipher("hcrypto_rc4", EVP_hcrypto_rc4()); + test_bulk_digest("hcrypto_md4", EVP_hcrypto_md4()); + test_bulk_digest("hcrypto_md5", EVP_hcrypto_md5()); + test_bulk_digest("hcrypto_sha1", EVP_hcrypto_sha1()); + test_bulk_digest("hcrypto_sha256", EVP_hcrypto_sha256()); + test_bulk_digest("hcrypto_sha384", EVP_hcrypto_sha384()); + test_bulk_digest("hcrypto_sha512", EVP_hcrypto_sha512()); +} + +#ifdef __APPLE__ +static void +test_bulk_provider_cc(void) +{ + test_bulk_cipher("cc_aes_256_cbc", EVP_cc_aes_256_cbc()); +#if 0 + test_bulk_cipher("cc_aes_256_cfb8", EVP_cc_aes_256_cfb8()); +#endif + test_bulk_cipher("cc_rc4", EVP_cc_rc4()); + test_bulk_digest("cc_md4", EVP_cc_md4()); + test_bulk_digest("cc_md5", EVP_cc_md5()); + test_bulk_digest("cc_sha1", EVP_cc_sha1()); + test_bulk_digest("cc_sha256", EVP_cc_sha256()); + test_bulk_digest("cc_sha384", EVP_cc_sha384()); + test_bulk_digest("cc_sha512", EVP_cc_sha512()); +} +#endif /* __APPLE__ */ + +#ifdef WIN32 +static void +test_bulk_provider_w32crypto(void) +{ + test_bulk_cipher("w32crypto_aes_256_cbc", EVP_w32crypto_aes_256_cbc()); +#if 0 + test_bulk_cipher("w32crypto_aes_256_cfb8", EVP_w32crypto_aes_256_cfb8()); +#endif + test_bulk_cipher("w32crypto_rc4", EVP_w32crypto_rc4()); + test_bulk_digest("w32crypto_md4", EVP_w32crypto_md4()); + test_bulk_digest("w32crypto_md5", EVP_w32crypto_md5()); + test_bulk_digest("w32crypto_sha1", EVP_w32crypto_sha1()); + test_bulk_digest("w32crypto_sha256", EVP_w32crypto_sha256()); + test_bulk_digest("w32crypto_sha384", EVP_w32crypto_sha384()); + test_bulk_digest("w32crypto_sha512", EVP_w32crypto_sha512()); +} +#endif /* WIN32 */ + +#if __sun || defined(PKCS11_MODULE_PATH) +static void +test_bulk_provider_pkcs11(void) +{ + test_bulk_cipher("pkcs11_aes_256_cbc", EVP_pkcs11_aes_256_cbc()); + test_bulk_cipher("pkcs11_rc4", EVP_pkcs11_rc4()); + test_bulk_digest("pkcs11_md5", EVP_pkcs11_md5()); + test_bulk_digest("pkcs11_sha1", EVP_pkcs11_sha1()); + test_bulk_digest("pkcs11_sha256", EVP_pkcs11_sha256()); + test_bulk_digest("pkcs11_sha384", EVP_pkcs11_sha384()); + test_bulk_digest("pkcs11_sha512", EVP_pkcs11_sha512()); +} +#endif /* __sun || PKCS11_MODULE_PATH */ + +int +main(int argc, char **argv) +{ + int ret = 0; + int idx = 0; + int i; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag) { + print_version(NULL); + exit(0); + } + + argc -= idx; + argv += idx; + + len *= 1024; + + d = emalloc(len); + for (i = 0; i < len; i++) + d[i] = i & 0xff; + + if (strcmp(provider, "hcrypto") == 0) + test_bulk_provider_hcrypto(); +#ifdef __APPLE__ + else if (strcmp(provider, "cc") == 0) + test_bulk_provider_cc(); +#endif +#ifdef WIN32 + else if (strcmp(provider, "w32crypto") == 0) + test_bulk_provider_w32crypto(); +#endif +#if __sun || defined(PKCS11_MODULE_PATH) + else if (strcmp(provider, "pkcs11") == 0) + test_bulk_provider_pkcs11(); +#endif + else + usage(1); + + free(d); + + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/test_cipher.c b/third_party/heimdal/lib/hcrypto/test_cipher.c new file mode 100644 index 0000000..9be65dd --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_cipher.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#define HC_DEPRECATED_CRYPTO + +#include + +#include +#include +#include +#if defined(_WIN32) +#include +#endif +#include +#include +#include +#include + +struct tests { + const char *name; + void *key; + size_t keysize; + void *iv; + size_t datasize; + void *indata; + void *outdata; + void *outiv; +}; + +struct tests aes_tests[] = { + { "aes-256", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 32, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xdc\x95\xc0\x78\xa2\x40\x89\x89\xad\x48\xa2\x14\x92\x84\x20\x87", + NULL + } +}; + +struct tests aes_cfb_tests[] = { + { "aes-cfb8-128", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x66\x16\xf9\x2e\x42\xa8\xf1\x1a\x91\x16\x68\x57\x8e\xc3\xaa\x0f", + NULL + } +}; + + +struct tests rc2_tests[] = { + { "rc2", + "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00", + 8, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x22\x69\x55\x2a\xb0\xf8\x5c\xa6", + NULL + } +}; + + +struct tests rc2_40_tests[] = { + { "rc2-40", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xc0\xb8\xff\xa5\xd6\xeb\xc9\x62\xcc\x52\x5f\xfe\x9a\x3c\x97\xe6", + NULL + } +}; + +struct tests des_ede3_tests[] = { + { "des-ede3", + "\x19\x17\xff\xe6\xbb\x77\x2e\xfc" + "\x29\x76\x43\xbc\x63\x56\x7e\x9a" + "\x00\x2e\x4d\x43\x1d\x5f\xfd\x58", + 24, + "\xbf\x9a\x12\xb7\x26\x69\xfd\x05", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x55\x95\x97\x76\xa9\x6c\x66\x40\x64\xc7\xf4\x1c\x21\xb7\x14\x1b", + NULL + } +}; + +struct tests camellia128_tests[] = { + { "camellia128", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x07\x92\x3A\x39\xEB\x0A\x81\x7D\x1C\x4D\x87\xBD\xB8\x2D\x1F\x1C", + NULL + } +}; + +struct tests rc4_tests[] = { + { + "rc4 8", + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + 8, + NULL, + 8, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x74\x94\xC2\xE7\x10\x4B\x08\x79", + NULL + }, + { + "rc4 5", + "\x61\x8a\x63\xd2\xfb", + 5, + NULL, + 5, + "\xdc\xee\x4c\xf9\x2c", + "\xf1\x38\x29\xc9\xde", + NULL + }, + { + "rc4 309", + "\x29\x04\x19\x72\xfb\x42\xba\x5f\xc7\x12\x77\x12\xf1\x38\x29\xc9", + 16, + NULL, + 309, + "\x52\x75\x69\x73\x6c\x69\x6e\x6e" + "\x75\x6e\x20\x6c\x61\x75\x6c\x75" + "\x20\x6b\x6f\x72\x76\x69\x73\x73" + "\x73\x61\x6e\x69\x2c\x20\x74\xe4" + "\x68\x6b\xe4\x70\xe4\x69\x64\x65" + "\x6e\x20\x70\xe4\xe4\x6c\x6c\xe4" + "\x20\x74\xe4\x79\x73\x69\x6b\x75" + "\x75\x2e\x20\x4b\x65\x73\xe4\x79" + "\xf6\x6e\x20\x6f\x6e\x20\x6f\x6e" + "\x6e\x69\x20\x6f\x6d\x61\x6e\x61" + "\x6e\x69\x2c\x20\x6b\x61\x73\x6b" + "\x69\x73\x61\x76\x75\x75\x6e\x20" + "\x6c\x61\x61\x6b\x73\x6f\x74\x20" + "\x76\x65\x72\x68\x6f\x75\x75\x2e" + "\x20\x45\x6e\x20\x6d\x61\x20\x69" + "\x6c\x6f\x69\x74\x73\x65\x2c\x20" + "\x73\x75\x72\x65\x20\x68\x75\x6f" + "\x6b\x61\x61\x2c\x20\x6d\x75\x74" + "\x74\x61\x20\x6d\x65\x74\x73\xe4" + "\x6e\x20\x74\x75\x6d\x6d\x75\x75" + "\x73\x20\x6d\x75\x6c\x6c\x65\x20" + "\x74\x75\x6f\x6b\x61\x61\x2e\x20" + "\x50\x75\x75\x6e\x74\x6f\x20\x70" + "\x69\x6c\x76\x65\x6e\x2c\x20\x6d" + "\x69\x20\x68\x75\x6b\x6b\x75\x75" + "\x2c\x20\x73\x69\x69\x6e\x74\x6f" + "\x20\x76\x61\x72\x61\x6e\x20\x74" + "\x75\x75\x6c\x69\x73\x65\x6e\x2c" + "\x20\x6d\x69\x20\x6e\x75\x6b\x6b" + "\x75\x75\x2e\x20\x54\x75\x6f\x6b" + "\x73\x75\x74\x20\x76\x61\x6e\x61" + "\x6d\x6f\x6e\x20\x6a\x61\x20\x76" + "\x61\x72\x6a\x6f\x74\x20\x76\x65" + "\x65\x6e\x2c\x20\x6e\x69\x69\x73" + "\x74\xe4\x20\x73\x79\x64\xe4\x6d" + "\x65\x6e\x69\x20\x6c\x61\x75\x6c" + "\x75\x6e\x20\x74\x65\x65\x6e\x2e" + "\x20\x2d\x20\x45\x69\x6e\x6f\x20" + "\x4c\x65\x69\x6e\x6f", + "\x35\x81\x86\x99\x90\x01\xe6\xb5" + "\xda\xf0\x5e\xce\xeb\x7e\xee\x21" + "\xe0\x68\x9c\x1f\x00\xee\xa8\x1f" + "\x7d\xd2\xca\xae\xe1\xd2\x76\x3e" + "\x68\xaf\x0e\xad\x33\xd6\x6c\x26" + "\x8b\xc9\x46\xc4\x84\xfb\xe9\x4c" + "\x5f\x5e\x0b\x86\xa5\x92\x79\xe4" + "\xf8\x24\xe7\xa6\x40\xbd\x22\x32" + "\x10\xb0\xa6\x11\x60\xb7\xbc\xe9" + "\x86\xea\x65\x68\x80\x03\x59\x6b" + "\x63\x0a\x6b\x90\xf8\xe0\xca\xf6" + "\x91\x2a\x98\xeb\x87\x21\x76\xe8" + "\x3c\x20\x2c\xaa\x64\x16\x6d\x2c" + "\xce\x57\xff\x1b\xca\x57\xb2\x13" + "\xf0\xed\x1a\xa7\x2f\xb8\xea\x52" + "\xb0\xbe\x01\xcd\x1e\x41\x28\x67" + "\x72\x0b\x32\x6e\xb3\x89\xd0\x11" + "\xbd\x70\xd8\xaf\x03\x5f\xb0\xd8" + "\x58\x9d\xbc\xe3\xc6\x66\xf5\xea" + "\x8d\x4c\x79\x54\xc5\x0c\x3f\x34" + "\x0b\x04\x67\xf8\x1b\x42\x59\x61" + "\xc1\x18\x43\x07\x4d\xf6\x20\xf2" + "\x08\x40\x4b\x39\x4c\xf9\xd3\x7f" + "\xf5\x4b\x5f\x1a\xd8\xf6\xea\x7d" + "\xa3\xc5\x61\xdf\xa7\x28\x1f\x96" + "\x44\x63\xd2\xcc\x35\xa4\xd1\xb0" + "\x34\x90\xde\xc5\x1b\x07\x11\xfb" + "\xd6\xf5\x5f\x79\x23\x4d\x5b\x7c" + "\x76\x66\x22\xa6\x6d\xe9\x2b\xe9" + "\x96\x46\x1d\x5e\x4d\xc8\x78\xef" + "\x9b\xca\x03\x05\x21\xe8\x35\x1e" + "\x4b\xae\xd2\xfd\x04\xf9\x46\x73" + "\x68\xc4\xad\x6a\xc1\x86\xd0\x82" + "\x45\xb2\x63\xa2\x66\x6d\x1f\x6c" + "\x54\x20\xf1\x59\x9d\xfd\x9f\x43" + "\x89\x21\xc2\xf5\xa4\x63\x93\x8c" + "\xe0\x98\x22\x65\xee\xf7\x01\x79" + "\xbc\x55\x3f\x33\x9e\xb1\xa4\xc1" + "\xaf\x5f\x6a\x54\x7f", + NULL + } +}; + + +static int +test_cipher(int i, const EVP_CIPHER *c, struct tests *t) +{ + EVP_CIPHER_CTX ectx; + EVP_CIPHER_CTX dctx; + void *d; + + if (c == NULL) { + printf("%s not supported\n", t->name); + return 0; + } + + EVP_CIPHER_CTX_init(&ectx); + EVP_CIPHER_CTX_init(&dctx); + + if (EVP_CipherInit_ex(&ectx, c, NULL, NULL, NULL, 1) != 1) + errx(1, "%s: %d EVP_CipherInit_ex einit", t->name, i); + if (EVP_CipherInit_ex(&dctx, c, NULL, NULL, NULL, 0) != 1) + errx(1, "%s: %d EVP_CipherInit_ex dinit", t->name, i); + + EVP_CIPHER_CTX_set_key_length(&ectx, t->keysize); + EVP_CIPHER_CTX_set_key_length(&dctx, t->keysize); + + if (EVP_CipherInit_ex(&ectx, NULL, NULL, t->key, t->iv, 1) != 1) + errx(1, "%s: %d EVP_CipherInit_ex encrypt", t->name, i); + if (EVP_CipherInit_ex(&dctx, NULL, NULL, t->key, t->iv, 0) != 1) + errx(1, "%s: %d EVP_CipherInit_ex decrypt", t->name, i); + + d = emalloc(t->datasize); + + if (!EVP_Cipher(&ectx, d, t->indata, t->datasize)) + errx(1, "%s: %d EVP_Cipher encrypt failed", t->name, i); + + if (memcmp(d, t->outdata, t->datasize) != 0) { + char *s, *s2; + hex_encode(d, t->datasize, &s); + hex_encode(t->outdata, t->datasize, &s2); + errx(1, "%s: %d encrypt not the same: %s != %s", t->name, i, s, s2); + } + + if (!EVP_Cipher(&dctx, d, d, t->datasize)) + errx(1, "%s: %d EVP_Cipher decrypt failed", t->name, i); + + if (memcmp(d, t->indata, t->datasize) != 0) { + char *s; + hex_encode(d, t->datasize, &s); + errx(1, "%s: %d decrypt not the same: %s", t->name, i, s); + } + +#if 0 /* TODO */ + if (t->outiv) + /* XXXX check */; +#endif + + EVP_CIPHER_CTX_cleanup(&ectx); + EVP_CIPHER_CTX_cleanup(&dctx); + free(d); + + return 0; +} + +static int version_flag; +static int help_flag; + +static struct getargs args[] = { + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(*args), + NULL, + ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int ret = 0; + int i, idx = 0; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= idx; + argv += idx; + + /* hcrypto */ + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_rc2_cbc(), &rc2_tests[i]); + for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_rc2_40_cbc(), &rc2_40_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_des_ede3_cbc(), &des_ede3_tests[i]); + for (i = 0; i < sizeof(camellia128_tests)/sizeof(camellia128_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_camellia_128_cbc(), + &camellia128_tests[i]); + for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++) + ret += test_cipher(i, EVP_hcrypto_rc4(), &rc4_tests[i]); + + /* Common Crypto */ +#ifdef __APPLE__ + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_cc_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_cc_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++) + ret += test_cipher(i, EVP_cc_rc2_40_cbc(), &rc2_40_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_cc_des_ede3_cbc(), &des_ede3_tests[i]); + for (i = 0; i < sizeof(camellia128_tests)/sizeof(camellia128_tests[0]); i++) + ret += test_cipher(i, EVP_cc_camellia_128_cbc(), + &camellia128_tests[i]); + for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++) + ret += test_cipher(i, EVP_cc_rc4(), &rc4_tests[i]); +#endif /* __APPLE__ */ + + /* Windows CNG (if available) */ +#ifdef WIN32 + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_rc2_cbc(), &rc2_tests[i]); + for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_rc2_40_cbc(), &rc2_40_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_des_ede3_cbc(), &des_ede3_tests[i]); + for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++) + ret += test_cipher(i, EVP_w32crypto_rc4(), &rc4_tests[i]); +#endif /* WIN32 */ + + /* PKCS#11 */ +#if __sun || defined(PKCS11_MODULE_PATH) + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_rc2_cbc(), &rc2_tests[i]); + for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_rc2_40_cbc(), &rc2_40_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_des_ede3_cbc(), &des_ede3_tests[i]); + for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++) + ret += test_cipher(i, EVP_pkcs11_rc4(), &rc4_tests[i]); +#endif /* PKCS11_MODULE_PATH */ + + /* OpenSSL */ +#ifdef HAVE_HCRYPTO_W_OPENSSL + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_des_ede3_cbc(), &des_ede3_tests[i]); +#endif /* PKCS11_MODULE_PATH */ + + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/test_crypto.in b/third_party/heimdal/lib/hcrypto/test_crypto.in new file mode 100644 index 0000000..91c4d8f --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_crypto.in @@ -0,0 +1,120 @@ +#!/bin/sh +# +# Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" + +rsa="${TESTS_ENVIRONMENT} ./test_rsa@exeext@" +engine="${TESTS_ENVIRONMENT} ./test_engine_dso@exeext@" +rand="${TESTS_ENVIRONMENT} ./test_rand@exeext@" + +${engine} --test-random > /dev/null || { echo "missing random"; exit 77; } + +${rsa} --key=${srcdir}/rsakey.der || \ + { echo "rsa test failed" ; exit 1; } + +${rsa} --time-key=${srcdir}/rsakey.der || \ + { echo "rsa test failed" ; exit 1; } + +${rsa} --time-key=${srcdir}/rsakey2048.der || \ + { echo "rsa test failed" ; exit 1; } + +${rsa} --time-key=generate || \ + { echo "rsa test failed" ; exit 1; } + +${engine} --rsa=${srcdir}/rsakey.der || \ + { echo "engine test failed" ; exit 1; } + +${rsa} --loops=4 || { echo "rsa test for 4 loops failed" ; exit 1; } + +for a in unix fortuna egd w32crypto ;do + ${rand} --method=${a} --file=crypto-test 2>error + res=$? + if test "X$res" != X0 ; then + grep "unknown method" error && \ + { echo "random $a is not available" ; continue; } + grep "random not ready yet" error || \ + { echo "random $a ready failing" ; cat error; exit 1; } + echo "random method $a out for lunch" + continue + fi + ${rand} --method=${a} --file=crypto-test2 2>error + res=$? + if test "X$res" != X0 ; then + grep "random not ready yet" error || \ + { echo "random $a ready failing" ; cat error; exit 1; } + echo "random metod $a out for dinner" + continue + fi + cmp crypto-test crypto-test2 >/dev/null 2>/dev/null && \ + { echo "rand output same!" ; exit 1; } +done + +for a in 1 7 15 16 17 31 32 33 ; do + ./example_evp_cipher $a ${srcdir}/test_crypto.in test-out-$a || + { echo "$s failed" ; exit 1; } +done +for a in 7 15 16 17 31 32 33 ; do + cmp test-out-1 test-out-$a || { echo "cmp $a failed" ; exit 1; } +done + +# +# Last time we run is w/o HOME and RANDFILE to make sure we can do +# RAND_file_name() when the environment is lacking those. +# + +if [ -r /dev/random -o -r /dev/urandom -o -r /dev/srandom -o -r /dev/arandom ] ; then + + # try hard to unset HOME and RANDFILE + HOME= + RANDFILE= + + unset HOME + unset RANDFILE + + ${rand} --method=unix --file=unix 2>error + res=$? + if test "X$res" != X0 ; then + grep "unknown method" error && \ + { echo "random unix is not available"; exit 0; } + grep "random not ready yet" error || \ + { echo "random unix ready failing" ; cat error; exit 1; } + echo "random method unix out for lunch" + continue + fi + +fi + +exit 0 diff --git a/third_party/heimdal/lib/hcrypto/test_dh.c b/third_party/heimdal/lib/hcrypto/test_dh.c new file mode 100644 index 0000000..2ee9477 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_dh.c @@ -0,0 +1,472 @@ +/* +* Copyright (c) 2007, Novell, Inc. +* Author: Matthias Koenig +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* * Neither the name of the Novell nor the names of its contributors may be used +* to endorse or promote products derived from this software without specific +* prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +/* openssl diffie-hellman test code + * works with openssl-0.9.8e + * primes with 3072 and 6144 bits as specified in RFC3526 + * fail since openssl-0.9.8f + */ + +#include +#include + +#include +#include + +#include +#include + +/* + * + */ + +static char *id_string; +static int verbose; +static int version_flag; +static int help_flag; + +static struct getargs args[] = { + { "id", 0, arg_string, &id_string, + "type of ENGINE", NULL }, + { "verbose", 0, arg_flag, &verbose, + "verbose output from tests", NULL }, + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +/* + * + */ + +#define OAKLEY_PRIME_MODP768 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP1024 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" \ + "FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP1536 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF" + +/* RFC 3526 */ +#define OAKLEY_PRIME_MODP2048 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP3072 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP4096 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \ + "FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP6144 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ + "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \ + "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \ + "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \ + "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \ + "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \ + "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \ + "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ + "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \ + "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \ + "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \ + "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF" + +#define OAKLEY_PRIME_MODP8192 \ + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ + "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \ + "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \ + "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \ + "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \ + "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \ + "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \ + "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ + "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \ + "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \ + "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \ + "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \ + "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \ + "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \ + "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \ + "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \ + "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \ + "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \ + "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \ + "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \ + "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \ + "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \ + "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF" + +struct prime { + char *name; + char *value; +} primes[] = { + { "modp768", OAKLEY_PRIME_MODP768 }, + { "modp1024", OAKLEY_PRIME_MODP1024 }, + { "modp1536", OAKLEY_PRIME_MODP1536 }, + { "modp2048", OAKLEY_PRIME_MODP2048 }, + { "modp3072", OAKLEY_PRIME_MODP3072 }, + { "modp4096", OAKLEY_PRIME_MODP4096 }, + { "modp6144", OAKLEY_PRIME_MODP6144 }, + { "modp8192", OAKLEY_PRIME_MODP8192 }, + { NULL, NULL } +}; + +/* + * exchange a string based "base" to a value. + * + */ +static char * +str2val(const char *str, int base, size_t *len) +{ + int f; + size_t i; + char *dst; + char *rp; + const char *p; + char b[3]; + + i = 0; + for (p = str; *p != '\0'; p++) { + if (isxdigit((unsigned char)*p)) + i++; + else if (isspace((unsigned char)*p)) + ; + else + return NULL; + } + if (i == 0 || (i % 2) != 0) + return NULL; + i /= 2; + + if ((dst = malloc(i)) == NULL) + return NULL; + + i = 0; + f = 0; + for (rp = dst, p = str; *p != '\0'; p++) { + if (isxdigit((unsigned char)*p)) { + if (!f) { + b[0] = *p; + f = 1; + } else { + b[1] = *p; + b[2] = '\0'; + *rp++ = (char)strtol(b, NULL, base); + i++; + f = 0; + } + } + } + + *len = i; + + return(dst); +} + +static void set_prime(BIGNUM *p, char *str) +{ + size_t len = 0; + unsigned char *prime; + + prime = (unsigned char *)str2val(str, 16, &len); + if (prime == NULL) + errx(1, "failed to parse %s", str); + BN_bin2bn(prime, len, p); +} + +static void set_generator(BIGNUM *g) +{ + BN_set_word(g, 2); +} + +static void print_secret(unsigned char *sec, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + printf("%x", sec[i]); + + printf("\n"); +} + +static int check_prime(ENGINE *engine, struct prime *pr) +{ + DH *dh1, *dh2; + BIGNUM *p, *g; + unsigned char *sec1, *sec2; + size_t size; + int ret; + + if (verbose) + printf("Testing %s\n", pr->name); + + p = BN_new(); + g = BN_new(); + dh1 = DH_new_method(engine); + dh2 = DH_new_method(engine); + + /* 1. set shared parameter */ + set_prime(p, pr->value); + set_generator(g); + dh1->p = BN_dup(p); + dh1->g = BN_dup(g); + dh2->p = BN_dup(p); + dh2->g = BN_dup(g); + + /* 2. set keys */ + ret = DH_generate_key(dh1); + if (ret == 0) { + fprintf(stderr, "DH_generate_key\n"); + exit(EXIT_FAILURE); + } + ret = DH_generate_key(dh2); + if (ret == 0) { + fprintf(stderr, "DH_generate_key\n"); + exit(EXIT_FAILURE); + } + + /* 3. compute shared secret */ + size = DH_size(dh1); + if (size != DH_size(dh2)) { + fprintf(stderr, "size does not match!\n"); + exit(EXIT_FAILURE); + } + sec1 = malloc(size); + sec2 = malloc(size); + if (!sec1 || !sec2) { + perror("malloc"); + exit(EXIT_FAILURE); + } + ret = DH_compute_key(sec1, dh2->pub_key, dh1); + if (ret == -1) { + fprintf(stderr, "DH_compute_key"); + exit(EXIT_FAILURE); + } + ret = DH_compute_key(sec2, dh1->pub_key, dh2); + if (ret == -1) { + fprintf(stderr, "DH_compute_key"); + exit(EXIT_FAILURE); + } + + /* 4. compare shared secret */ + if (verbose) { + printf("shared secret 1\n"); + print_secret(sec1, size); + printf("shared secret 2\n"); + print_secret(sec2, size); + } + + if (memcmp(sec1, sec2, size) == 0) + ret = 1; + else + ret = 0; + + free(sec2); + free(sec1); + DH_free(dh2); + DH_free(dh1); + BN_free(g); + BN_free(p); + + return ret; +} + +/* + * + */ + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(*args), + NULL, + ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + ENGINE *engine = NULL; + int idx = 0; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= idx; + argv += idx; + + OpenSSL_add_all_algorithms(); +#ifdef OPENSSL + ENGINE_load_openssl(); +#endif + ENGINE_load_builtin_engines(); + + if (id_string) { + engine = ENGINE_by_id(id_string); + if (engine == NULL) + engine = ENGINE_by_dso(id_string, id_string); + } else { + engine = ENGINE_by_id("builtin"); + } + if (engine == NULL) + errx(1, "ENGINE_by_dso failed"); + + printf("dh %s\n", ENGINE_get_DH(engine)->name); + + { + struct prime *p = primes; + + for (; p->name; ++p) + if (check_prime(engine, p)) + printf("%s: shared secret OK\n", p->name); + else + printf("%s: shared secret FAILURE\n", p->name); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/test_engine_dso.c b/third_party/heimdal/lib/hcrypto/test_engine_dso.c new file mode 100644 index 0000000..00a672e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_engine_dso.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +struct { + const char *cpriv; + const char *cpub; + const char *spriv; + const char *spub; +} dhtests[] = { + { + "5C0946275D07223AEAF04301D964498F3285946057B4C50D13B4FE12C88DFD8D499DD3CC00C1BC17C0D343F2FE053C9F53389110551715B1EDF261A0314485C4835D01F7B8894027D534A2D81D63619D2F58C9864AC9816086B3FF75C01B3FAFF355425AB7369A6ABDC8B633F0A0DC4D29B50F364E7594B297183D14E5CDC05D", + "2D66DC5998B7AEE3332DC1061C6E6F6CF0FCCD74534187E2CDC9ACBCADF0FC9D5900451F44832A762F01E9CEEF1CBD7D69D020AC524D09FAD087DFADEAC36C845157B83937B51C8DB7F500C3C54FB2A05E074E40BA982186E7FEB2534EDDB387D5480AAA355B398CCAD0886F3952C3718490B7884FA67BD8B6943CDDA20134C6", + "42644BA7CF74689E18BA72BF80FCA674D1A2ADF81795EB3828E67C30E42ABD07A8E90E27F046189FAC122D915276870B72427388EAAB5D06994FC38885BBACCEA1CFC45951B730D73C1A8F83208CD1351746601648C11D70BC95B817C86E4A5C40D633654615041C7934BB3CAF4E02754D542033DB024E94C7E561A29ED0C6EC", + "C233633AB116E2DB20B4E08DA42DE8766293E6D9042F7A2C2A2F34F18FE66010B074CCF3C9B03EF27B14F0746B738AF22776224161D767D96AEC230A1DFA6DECFFCE9FED23B96F50CCB0093E59817AD0CEAEB7993AB5764679948BFB1293C9560B07AA3DFA229E341EB17C9FAE0B1D483082461D2DDBCEEE6FE7C0A34D96F66D" + }, + { + "76295C1280B890970F0F7EB01BBD9C5DF9BB8F590EB384A39EBF85CD141451407F955FD1D39012AA1F8BA53FD6A5A37CB2835CEDB27D1EBF1FE8AC9F2FFD628BD9BF7B8DD77CB80C8DC0A75F4567C7700442B26972833EB9738A8728A1FC274C59CED5E3ADA224B46711112AAA1CB831D2D6125E183ADA4F805A05024C9C6DDB", + "1E0AB5EBAAC7985FE67A574447FAE58AE4CB95416278D4C239A789D4532FA8E6F82BA10BE411D8A0A06B9E1DECE704466B3523496A8A4165B97FBCFB9CE9C4FF2DEEE786BA046E8C270FA8A9055D2F6E42EDDB32C73CF7875551A56EB69C0F14A3745745845B81C347401B27D074C60C5177BA9C14BBB1C8C219B78E15126EF8", + "68D84A8F92082F113542CFD990DEEFAD9C7EFA545268F8B3EBDF4CCBAF2865CF03EF60044EB4AF4154E6804CC2BDD673B801507446CEFC692DA577B6DC6E0272B7B081A1BEFDC2A4FAC83DB8845E3DA0D1B64DB33AA2164FEDB08A01E815336BD58F4E6DE6A265468E61C8C988B8AEC0D52DB714448DDC007E7C3382C07357DB", + "393815D507A2EF80DE2D0F2A55AAB1C25B870ACA3FC97438B4336CBF979BF9A4F8DA1B61C667129F9123045E07E24976040EC5E2368DD4EF70690102D74E900B260D3826256FD473733A7569BF514652AB78C48C334FDCA26C44ABF322643AF15BFF693A37BB2C19CA9FE5F1537FCFE2B24CF74D4E57060D35ABF115B4B6CD21" + }, + { + "7307D6C3CB874327A95F7A6A91C336CEAA086736525DF3F8EC49497CF444C68D264EB70CD6904FE56E240EEF34E6C5177911C478A7F250A0F54183BCBE64B42BAB5D019E73E2F17C095C211E4815E6BA5FDD72786AF987ABBC9109ECEEF439AF9E2141D5222CE7DC0152D8E9A6CCCE301D21A7D1D6ACB9B91B5E28379C91890D", + "83FBD7BFFDF415BBB7E21D399CB2F36A61AFDBAFC542E428E444C66AA03617C0C55C639FE2428905B57035892AE1BD2C4060E807D9E003B0C204FFC8FDD69CC8ADE7A8E18DCBFFF64E3EF9DA2C117390374241466E48A020A1B2F575AE42C233F8BD357B8331CC203E0345DFC19C73E6F1F70B6C2786E681D73BF48B15FE9992", + "61BCF748BB05A48861578B8CB1855200B2E62A40E126BD7323E5B714645A54A2C8761EE39EE39BA6D2FE19B688168EDEA6DC5056400B5315ED299E7926176B887012E58634D78F05D7BCF0E1B81B1B41F5F8EF0B0711D3A64F9A317DD183AE039A4D3BE02A515892362F8C7BB6EB6434BB25418A438ED33D50C475122CBBE862", + "7DB8D69D1605D9812B7F2F3E92BCEEB3426FEEE3265A174D71B2B6E16B332B43DF0B3C2FA152E48DE2FAC110D8CECE122C3398558E7987B27CACE12722C0032AC7E7766A9BCC881BA35B9DB9E751BD4E51F7683DE092F6C1D4DD937CDCE9C16E6F7D77CC6AAD806E4082E8E22E28592C4D78256354393FE831E811E03ED0A81A" + }, + { + "60C18B62F786DE6A4A8B13EB6DA2380B4C6731F861C715D9496DCF4A9F01CD33DDB52F1AB4D1F820FAF7AD4EFEB66586F7F08135714B13D77FE652B9EEAB2C543596A9ED307C1629CF535DD14AB22F081AE4ADF7A3E0BC7B33E0EC7A7306F9A737F55807974B5E1B7B6394BD0373917128B43A17757B34BAE1B600763E957F75", + "0DEDA337C38EA005D5B8567EAB681CE91892C2C62C9D42BF748FBFE681E11F25D98280E42E1539A10EEE9177EF2F40216987936AF19D9B5EBE22EEAC27242D77CE3A5061F2E5CFACF15CD0F80E736AE8642252FE91E129DE3C78CFB85A0B1BB87B059CBB24483444F8A07244F4E89370BA78D58BD409DFBB3D41921B8879B9C7", + "462C0707CF3366C2242A808CFDB79B77E8B3AF9D796583EB9CCD7BF4E8792AB0A818E49FFE53CA241F56988F825B366BF1E78481F8086A123259B9D83AC643E85845BF6B2C5412FFDDFAA8C9ED203CA4B3C1BFD777286099976472FA15B3CCC8418CF162F03C0C3E85D7EFC5CF5ACB9B2C039CCF3A1A9C6BB6B9C09C18D86CBD", + "56DB382EDB8C2D95934D20261CE1A37090B0802D451E647DB1DA3B73CDB5A878EAD598A8817302449370F9D45E34F5C45F73D02BF4EB2B3712A8665F446F5D2B774039E5444AB74807859FA58DF9EBA4B12BA4545ACED827E4ED64CC71F937D64A1033BC43403F2490C1B715A74822B8D50A72A102213F0CF7A1B98B771B34C4" + }, + { + "61B7321207F4A73646E43E99221F902D2F38095E84CE7346A1510FE71BA7B9B34DCB6609E4DDDA8C82426E82D1C23F1E761130ECE4638D77554A7618E1608625049328FCC1F8845CA9A88E847106B01BD31EF6500E3C7EE81A048924BEAA3EDF367E5F4575341206C7A76427571898294B07BD918D4C2642854CC89D439042E5", + "29AA38E63E4DD7C651E25DEC7A5A53E48114F52813793D36A9DBDD4F7C06FC38406E330764E0B2AFD811C39D857EA5F904105360E06856DC0780C7D61C53165833F0AEA15CB54732DE113F44C8FCFB86F4A876DD42D7A55356D91C0173F2B012680FB54C13EF54B65DF4AEDE2E13419B1316435187CEF07D44DB3DF57C4703FD", + "5ED5AFB04CBFEE43EF3D9B60A57080831563648A2380D98F1EA4A96CF153903A40A2E564DED87E7254DF3270568AB952BF6F400681DD6AD919C9B06AC0F45F0646BCF37B217191AA0B7B7BED226B61F48B46DEA2E5A09E41F316583823A38A60FFD79085F43F60D98871ECA1A0F667701425094E88885A81DE9DA6C293E95060", + "4DE4F24EAA3E2790FBCB1B13C2ED0EFD846EC33154DBEBBEFD895E1399B3617D55EC2CE8D71CF380B55D93636FEF741328D6B1E224D46F8A8B60A41D08DD86E88DE806AA781791364E6D88BF68571BF5D8C35CB04BA302227B7E4CB6A67AB7510ACBCDBF2F8A95EB5DEE693CCA5CC425A0F1CA2D18C369A767906A2477E32704" + } +}; + +static void +dh_test(DH *server, DH *client) +{ + void *skey, *ckey; + int ssize, csize; + + skey = emalloc(DH_size(server)); + ckey = emalloc(DH_size(client)); + + ssize = DH_compute_key(skey, client->pub_key, server); + if (ssize == -1) + errx(1, "DH_compute_key failed for server"); + csize = DH_compute_key(ckey, server->pub_key, client); + if (csize == -1) + errx(1, "DH_compute_key failed for client"); + + if (ssize != csize) + errx(1, "DH_compute_key size mismatch"); + + if (memcmp(skey, ckey, csize) != 0) + errx(1, "DH_compute_key key mismatch"); + + free(skey); + free(ckey); +} + + +static int version_flag; +static int help_flag; +static char *id_flag; +static char *rsa_flag; +static int dh_flag = 1; +static int test_random_flag; + +static struct getargs args[] = { + { "id", 0, arg_string, &id_flag, + "selects the engine id", "engine-id" }, + { "rsa", 0, arg_string, &rsa_flag, + "tests RSA modes", "private-rsa-der-file" }, + { "dh", 0, arg_negative_flag, &dh_flag, + "test dh", NULL }, + { "test-random", 0, arg_flag, &test_random_flag, + "test if there is a random device", NULL }, + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(*args), + NULL, + "filename.so"); + exit (ret); +} + +int +main(int argc, char **argv) +{ + ENGINE *engine = NULL; + int idx = 0; + int have_rsa, have_dh; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= idx; + argv += idx; + + OpenSSL_add_all_algorithms(); + + if (argc == 0) { + OpenSSL_add_all_algorithms(); + ENGINE_load_builtin_engines(); + engine = ENGINE_by_id("builtin"); + } else { + engine = ENGINE_by_dso(argv[0], id_flag); + } + if (engine == NULL) + errx(1, "ENGINE_by_dso failed"); + + printf("name: %s\n", ENGINE_get_name(engine)); + printf("id: %s\n", ENGINE_get_id(engine)); + have_rsa = ENGINE_get_RSA(engine) != NULL; + have_dh = ENGINE_get_DH(engine) != NULL; + printf("RSA: %s", have_rsa ? "yes," : "no"); + if (have_rsa) + printf(" %s", ENGINE_get_RSA(engine)->name); + printf("\n"); + printf("DH: %s", have_dh ? "yes," : "no"); + if (have_dh) + printf(" %s", ENGINE_get_DH(engine)->name); + printf("\n"); + + if (RAND_status() != 1) + errx(77, "no functional random device, can't execute tests"); + if (test_random_flag) + exit(0); + + if (rsa_flag && have_rsa) { + unsigned char buf[1024 * 4]; + const unsigned char *p; + size_t size; + int keylen; + RSA *rsa; + FILE *f; + + f = fopen(rsa_flag, "rb"); + if (f == NULL) + err(1, "could not open file %s", rsa_flag); + + size = fread(buf, 1, sizeof(buf), f); + if (size == 0) + err(1, "failed to read file %s", rsa_flag); + if (size == sizeof(buf)) + err(1, "key too long in file %s!", rsa_flag); + fclose(f); + + p = buf; + rsa = d2i_RSAPrivateKey(NULL, &p, size); + if (rsa == NULL) + err(1, "failed to parse key in file %s", rsa_flag); + + RSA_set_method(rsa, ENGINE_get_RSA(engine)); + + /* + * try rsa signing + */ + + memcpy(buf, "hejsan", 7); + keylen = RSA_private_encrypt(7, buf, buf, rsa, RSA_PKCS1_PADDING); + if (keylen <= 0) + errx(1, "failed to private encrypt"); + + keylen = RSA_public_decrypt(keylen, buf, buf, rsa, RSA_PKCS1_PADDING); + if (keylen <= 0) + errx(1, "failed to public decrypt"); + + if (keylen != 7) + errx(1, "output buffer not same length: %d", (int)keylen); + + if (memcmp(buf, "hejsan", 7) != 0) + errx(1, "string not the same after decryption"); + + /* + * try rsa encryption + */ + + memcpy(buf, "hejsan", 7); + keylen = RSA_public_encrypt(7, buf, buf, rsa, RSA_PKCS1_PADDING); + if (keylen <= 0) + errx(1, "failed to public encrypt"); + + keylen = RSA_private_decrypt(keylen, buf, buf, rsa, RSA_PKCS1_PADDING); + if (keylen <= 0) + errx(1, "failed to private decrypt"); + + if (keylen != 7) + errx(1, "output buffer not same length: %d", (int)keylen); + + if (memcmp(buf, "hejsan", 7) != 0) + errx(1, "string not the same after decryption"); + + RSA_free(rsa); + + printf("rsa test passed\n"); + + } + + if (dh_flag) { + DH *server, *client; + int i; + + /* RFC2412-MODP-group2 */ + const char *p = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + const char *g = "02"; + + /* + * Try generated keys + */ + + for (i = 0; i < 10; i++) { + server = DH_new_method(engine); + client = DH_new_method(engine); + + BN_hex2bn(&server->p, p); + BN_hex2bn(&client->p, p); + BN_hex2bn(&server->g, g); + BN_hex2bn(&client->g, g); + + if (!DH_generate_key(server)) + errx(1, "DH_generate_key failed for server"); + if (!DH_generate_key(client)) + errx(1, "DH_generate_key failed for client"); + + dh_test(server, client); + + DH_free(server); + DH_free(client); + } + /* + * Try known result + */ + + for (i = 0; i < sizeof(dhtests)/sizeof(dhtests[0]); i++) { + + server = DH_new_method(engine); + client = DH_new_method(engine); + + BN_hex2bn(&server->p, p); + BN_hex2bn(&client->p, p); + BN_hex2bn(&server->g, g); + BN_hex2bn(&client->g, g); + + BN_hex2bn(&client->priv_key, dhtests[i].cpriv); + BN_hex2bn(&client->pub_key, dhtests[i].cpub); + BN_hex2bn(&server->priv_key, dhtests[i].spriv); + BN_hex2bn(&server->pub_key, dhtests[i].spub); + + dh_test(server, client); + + DH_free(server); + DH_free(client); + } + + printf("DH test passed\n"); + } + + ENGINE_finish(engine); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/test_hmac.c b/third_party/heimdal/lib/hcrypto/test_hmac.c new file mode 100644 index 0000000..36a5626 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_hmac.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +int +main(int argc, char **argv) +{ + unsigned char buf[4] = { 0, 0, 0, 0 }; + char hmackey[] = "hello-world"; + size_t hmackey_size = sizeof(hmackey); + unsigned int hmaclen; + unsigned char hmac[EVP_MAX_MD_SIZE]; + HMAC_CTX c; + + char answer[20] = "\x2c\xfa\x32\xb7\x2b\x8a\xf6\xdf\xcf\xda" + "\x6f\xd1\x52\x4d\x54\x58\x73\x0f\xf3\x24"; + + HMAC_CTX_init(&c); + if (HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL) == 0) { + HMAC_CTX_cleanup(&c); + printf("out of memory\n"); + return 1; + } + HMAC_Update(&c, buf, sizeof(buf)); + HMAC_Final(&c, hmac, &hmaclen); + HMAC_CTX_cleanup(&c); + + if (hmaclen != 20) { + printf("hmaclen = %d\n", (int)hmaclen); + return 1; + } + + if (ct_memcmp(hmac, answer, hmaclen) != 0) { + printf("wrong answer\n"); + return 1; + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/test_pkcs12.c b/third_party/heimdal/lib/hcrypto/test_pkcs12.c new file mode 100644 index 0000000..3c7f5da --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_pkcs12.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +struct tests { + int id; + const char *password; + void *salt; + size_t saltsize; + int iterations; + size_t keylen; + const EVP_MD * (*md)(void); + void *key; +}; + +struct tests p12_pbe_tests[] = { + { PKCS12_KEY_ID, + NULL, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 100, + 16, + EVP_sha1, + "\xd7\x2d\xd4\xcf\x7e\xe1\x89\xc5\xb5\xe5\x31\xa7\x63\x2c\xf0\x4b" + }, + { PKCS12_KEY_ID, + "", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 100, + 16, + EVP_sha1, + "\x00\x54\x91\xaf\xc0\x6a\x76\xc3\xf9\xb6\xf2\x28\x1a\x15\xd9\xfe" + }, + { PKCS12_KEY_ID, + "foobar", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 100, + 16, + EVP_sha1, + "\x79\x95\xbf\x3f\x1c\x6d\xe\xe8\xd3\x71\xc4\x94\xd\xb\x18\xb5" + }, + { PKCS12_KEY_ID, + "foobar", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + 2048, + 24, + EVP_sha1, + "\x0b\xb5\xe\xa6\x71\x0d\x0c\xf7\x44\xe\xe1\x9b\xb5\xdf\xf1\xdc\x4f\xb0\xca\xe\xee\x4f\xb9\xfd" + }, + { PKCS12_IV_ID, + "foobar", + "\x3c\xdf\x84\x32\x59\xd3\xda\x69", + 8, + 2048, + 8, + EVP_sha1, + "\xbf\x9a\x12\xb7\x26\x69\xfd\x05" + } + +}; + +static int +test_pkcs12_pbe(struct tests *t) +{ + void *key; + size_t pwlen = 0; + + key = malloc(t->keylen); + if (t->password) + pwlen = strlen(t->password); + + if (!PKCS12_key_gen(t->password, pwlen, + t->salt, t->saltsize, + t->id, t->iterations, t->keylen, + key, t->md())) + { + printf("key_gen failed\n"); + return 1; + } + + if (memcmp(t->key, key, t->keylen) != 0) { + printf("incorrect key\n"); + free(key); + return 1; + } + free(key); + return 0; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + int i; + + for (i = 0; i < sizeof(p12_pbe_tests)/sizeof(p12_pbe_tests[0]); i++) + ret += test_pkcs12_pbe(&p12_pbe_tests[i]); + + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/test_pkcs5.c b/third_party/heimdal/lib/hcrypto/test_pkcs5.c new file mode 100644 index 0000000..3641a6e --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_pkcs5.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +struct tests { + const char *password; + const char *salt; + int iterations; + const void *pbkdf2_128; + const void *pbkdf2_256; +}; + + +const struct tests pkcs5_tests[] = { + { "password", + "ATHENA.MIT.EDUraeburn", + 1, + "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15", + "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15" + "\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3\x33\xec\xc0\xe2\xe1\xf7\x08\x37" + }, + { "password", + "ATHENA.MIT.EDUraeburn", + 2, + "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d", + "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d" + "\xa0\x53\x78\xb9\x32\x44\xec\x8f\x48\xa9\x9e\x61\xad\x79\x9d\x86" + }, + { "password", + "ATHENA.MIT.EDUraeburn", + 1200, + "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b", + "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b" + "\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f\x70\x8a\x31\xe2\xe6\x2b\x1e\x13" + }, + { + "password", "\x12\x34\x56\x78\x78\x56\x34\x12", + 5, + "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49", + "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49" + "\x3f\x98\xd2\x03\xe6\xbe\x49\xa6\xad\xf4\xfa\x57\x4b\x6e\x64\xee" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", + 1200, + "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9", + "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9" + "\xc5\xec\x59\xf1\xa4\x52\xf5\xcc\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", + 1200, + "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61", + "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61" + "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a" + }, + { + "\xf0\x9d\x84\x9e" /* g-clef */, + "EXAMPLE.COMpianist", + 50, + "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39", + "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39" + "\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2\x81\xff\x30\x69\xe1\xe9\x4f\x52" + } +}; + +static int +test_pkcs5_pbe2(const struct tests *t) +{ + unsigned char key[32]; + int ret, error = 0; + + ret = PKCS5_PBKDF2_HMAC(t->password, strlen(t->password), + t->salt, strlen(t->salt), + t->iterations, EVP_sha1(), + 16, key); + if (ret != 1) + errx(1, "PKCS5_PBKDF2_HMAC: %d", ret); + + if (memcmp(t->pbkdf2_128, key, 16) != 0) { + printf("incorrect 128 key\n"); + error++; + } + + ret = PKCS5_PBKDF2_HMAC(t->password, strlen(t->password), + t->salt, strlen(t->salt), + t->iterations, EVP_sha1(), + 32, key); + if (ret != 1) + errx(1, "PKCS5_PBKDF2_HMAC: %d", ret); + + if (memcmp(t->pbkdf2_256, key, 32) != 0) { + printf("incorrect 256 key\n"); + error++; + } + + return error; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + int i; + + for (i = 0; i < sizeof(pkcs5_tests)/sizeof(pkcs5_tests[0]); i++) + ret += test_pkcs5_pbe2(&pkcs5_tests[i]); + + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/test_rand.c b/third_party/heimdal/lib/hcrypto/test_rand.c new file mode 100644 index 0000000..b3ee2b1 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_rand.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include "rand.h" + + +/* + * + */ + +static int version_flag; +static int help_flag; +static int len = 1024 * 1024; +static char *rand_method; +static char *filename; + +static struct getargs args[] = { + { "length", 0, arg_integer, &len, + "length", NULL }, + { "file", 0, arg_string, &filename, + "file name", NULL }, + { "method", 0, arg_string, &rand_method, + "method", NULL }, + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +/* + * + */ + +/* + * + */ + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(args[0]), + NULL, + ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int idx = 0; + char *buffer; + char path[MAXPATHLEN]; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + if (argc != idx) + usage(1); + + buffer = emalloc(len); + + if (rand_method) { + if (0) { + } +#ifndef NO_RAND_FORTUNA_METHOD + else if (strcasecmp(rand_method, "fortuna") == 0) + RAND_set_rand_method(RAND_fortuna_method()); +#endif +#ifndef NO_RAND_UNIX_METHOD + else if (strcasecmp(rand_method, "unix") == 0) + RAND_set_rand_method(RAND_unix_method()); +#endif +#ifdef WIN32 + else if (strcasecmp(rand_method, "w32crypto") == 0) + RAND_set_rand_method(RAND_w32crypto_method()); +#endif + else + errx(1, "unknown method %s", rand_method); + } + + if (RAND_file_name(path, sizeof(path)) == NULL) + errx(1, "RAND_file_name failed"); + + if (RAND_status() != 1) + errx(1, "random not ready yet"); + + if (RAND_bytes(buffer, len) != 1) + errx(1, "RAND_bytes"); + + if (filename) + rk_dumpdata(filename, buffer, len); + + /* head vs tail */ + if (len >= 100000) { + unsigned bytes[256]; + unsigned bits[8]; + size_t bit, i; + double res; + double slen = sqrt((double)len); + + memset(bits, 0, sizeof(bits)); + memset(bytes, 0, sizeof(bytes)); + + for (i = 0; i < len; i++) { + unsigned char c = ((unsigned char *)buffer)[i]; + + bytes[c]++; + + for (bit = 0; bit < 8 && c; bit++) { + if (c & 1) + bits[bit]++; + c = c >> 1; + } + } + + /* + * The count for each bit value has a mean of n*p = len/2, + * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/4). + * Normalizing by dividing by "n*p", we get a mean of 1 and + * a standard deviation of sqrt(q/n*p) = 1/sqrt(len). + * + * A 5.33-sigma event happens 1 time in 10 million. + * A 5.73-sigma event happens 1 time in 100 million. + * A 6.11-sigma event happens 1 time in 1000 million. + * + * We tolerate 5.33-sigma events (we have 8 not entirely + * independent chances of skewed results) and want to fail + * with a good RNG less often than 1 time in million. + */ + for (bit = 0; bit < 8; bit++) { + res = slen * fabs(1.0 - 2 * (double)bits[bit] / len); + if (res > 5.33) + errx(1, "head%d vs tail%d: %.1f-sigma (%d of %d)", + (int)bit, (int)bit, res, bits[bit], len); + printf("head vs tails bit%d: %f-sigma\n", (int)bit, res); + } + + /* + * The count of each byte value has a mean of n*p = len/256, + * and a standard deviation of sqrt(n*p*q) ~ sqrt(len/256). + * Normalizing by dividing by "n*p", we get a mean of 1 and + * a standard deviation of sqrt(q/n*p) ~ 16/sqrt(len). + * + * We tolerate 5.73-sigma events (we have 256 not entirely + * independent chances of skewed results). Note, for example, + * a 5.2-sigma event was observed in ~5,000 runs. + */ + for (i = 0; i < 256; i++) { + res = (slen / 16) * fabs(1.0 - 256 * (double)bytes[i] / len); + if (res > 5.73) + errx(1, "byte %d: %.1f-sigma (%d of %d)", + (int) i, res, bytes[i], len); + printf("byte %d: %f-sigma\n", (int)i, res); + } + } + + free(buffer); + + /* test write random file */ + { + static const char *file = "test.file"; + if (RAND_write_file(file) != 1) + errx(1, "RAND_write_file"); + if (RAND_load_file(file, 1024) != 1) + errx(1, "RAND_load_file"); + unlink(file); + } + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/test_rsa.c b/third_party/heimdal/lib/hcrypto/test_rsa.c new file mode 100644 index 0000000..c9766b8 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/test_rsa.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +/* + * + */ + +static int version_flag; +static int help_flag; +static int time_keygen; +static char *time_key; +static int key_blinding = 1; +static char *rsa_key; +static char *id_flag; +static int loops = 1; + +static struct getargs args[] = { + { "loops", 0, arg_integer, &loops, + "number of loops", "loops" }, + { "id", 0, arg_string, &id_flag, + "selects the engine id", "engine-id" }, + { "time-keygen", 0, arg_flag, &time_keygen, + "time rsa generation", NULL }, + { "time-key", 0, arg_string, &time_key, + "rsa key file", NULL }, + { "key-blinding", 0, arg_negative_flag, &key_blinding, + "key blinding", NULL }, + { "key", 0, arg_string, &rsa_key, + "rsa key file", NULL }, + { "version", 0, arg_flag, &version_flag, + "print version", NULL }, + { "help", 0, arg_flag, &help_flag, + NULL, NULL } +}; + +/* + * + */ + +static void +check_rsa(const unsigned char *in, size_t len, RSA *rsa, int padding) +{ + unsigned char *res, *res2; + unsigned int len2; + int keylen; + + res = malloc(RSA_size(rsa)); + if (res == NULL) + errx(1, "res: ENOMEM"); + + res2 = malloc(RSA_size(rsa)); + if (res2 == NULL) + errx(1, "res2: ENOMEM"); + + /* signing */ + + keylen = RSA_private_encrypt(len, in, res, rsa, padding); + if (keylen <= 0) + errx(1, "failed to private encrypt: %d %d", (int)len, (int)keylen); + + if (keylen > RSA_size(rsa)) + errx(1, "keylen > RSA_size(rsa)"); + + keylen = RSA_public_decrypt(keylen, res, res2, rsa, padding); + if (keylen <= 0) + errx(1, "failed to public decrypt: %d", (int)keylen); + + if (keylen != len) + errx(1, "output buffer not same length: %d", (int)keylen); + + if (memcmp(res2, in, len) != 0) + errx(1, "string not the same after decryption"); + + /* encryption */ + + keylen = RSA_public_encrypt(len, in, res, rsa, padding); + if (keylen <= 0) + errx(1, "failed to public encrypt: %d", (int)keylen); + + if (keylen > RSA_size(rsa)) + errx(1, "keylen > RSA_size(rsa)"); + + keylen = RSA_private_decrypt(keylen, res, res2, rsa, padding); + if (keylen <= 0) + errx(1, "failed to private decrypt: %d", (int)keylen); + + if (keylen != len) + errx(1, "output buffer not same length: %d", (int)keylen); + + if (memcmp(res2, in, len) != 0) + errx(1, "string not the same after decryption"); + + len2 = keylen; + + if (RSA_sign(NID_sha1, in, len, res, &len2, rsa) != 1) + errx(1, "RSA_sign failed"); + + if (RSA_verify(NID_sha1, in, len, res, len2, rsa) != 1) + errx(1, "RSA_verify failed"); + + free(res); + free(res2); +} + +static int +cb_func(int a, int b, BN_GENCB *c) +{ + return 1; +} + +static RSA * +read_key(ENGINE *engine, const char *keyfile) +{ + unsigned char buf[1024 * 4]; + const unsigned char *p; + size_t size; + RSA *rsa; + FILE *f; + + f = fopen(keyfile, "rb"); + if (f == NULL) + err(1, "could not open file %s", keyfile); + rk_cloexec_file(f); + + size = fread(buf, 1, sizeof(buf), f); + fclose(f); + if (size == 0) + err(1, "failed to read file %s", keyfile); + if (size == sizeof(buf)) + err(1, "key too long in file %s!", keyfile); + + p = buf; + rsa = d2i_RSAPrivateKey(NULL, &p, size); + if (rsa == NULL) + err(1, "failed to parse key in file %s", keyfile); + + RSA_set_method(rsa, ENGINE_get_RSA(engine)); + + if (!key_blinding) + rsa->flags |= RSA_FLAG_NO_BLINDING; + + return rsa; +} + +/* + * + */ + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args)/sizeof(*args), + NULL, + "filename.so"); + exit (ret); +} + +int +main(int argc, char **argv) +{ + ENGINE *engine = NULL; + int i, j, idx = 0; + RSA *rsa; + + setprogname(argv[0]); + + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx)) + usage(1); + + if (help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= idx; + argv += idx; + + OpenSSL_add_all_algorithms(); +#ifdef OPENSSL + ENGINE_load_openssl(); +#endif + ENGINE_load_builtin_engines(); + + if (argc == 0) { + engine = ENGINE_by_id("builtin"); + } else { + engine = ENGINE_by_id(argv[0]); + if (engine == NULL) + engine = ENGINE_by_dso(argv[0], id_flag); + } + if (engine == NULL) + errx(1, "ENGINE_by_dso failed"); + + if (ENGINE_get_RSA(engine) == NULL) + return 77; + + printf("rsa %s\n", ENGINE_get_RSA(engine)->name); + + if (RAND_status() != 1) + errx(77, "no functional random device, refusing to run tests"); + + if (time_keygen) { + struct timeval tv1, tv2; + BIGNUM *e; + + rsa = RSA_new_method(engine); + if (!key_blinding) + rsa->flags |= RSA_FLAG_NO_BLINDING; + + e = BN_new(); + BN_set_word(e, 0x10001); + + printf("running keygen with %d loops\n", loops); + + gettimeofday(&tv1, NULL); + + for (i = 0; i < loops; i++) { + rsa = RSA_new_method(engine); + if (RSA_generate_key_ex(rsa, 1024, e, NULL) != 1) + errx(1, "RSA_generate_key_ex"); + RSA_free(rsa); + } + + gettimeofday(&tv2, NULL); + timevalsub(&tv2, &tv1); + + printf("time %lu.%06lu\n", + (unsigned long)tv2.tv_sec, + (unsigned long)tv2.tv_usec); + + BN_free(e); + ENGINE_finish(engine); + + return 0; + } + + if (time_key) { + const int size = 20; + struct timeval tv1, tv2; + unsigned char *p; + + if (strcmp(time_key, "generate") == 0) { + BIGNUM *e; + + rsa = RSA_new_method(engine); + if (!key_blinding) + rsa->flags |= RSA_FLAG_NO_BLINDING; + + e = BN_new(); + BN_set_word(e, 0x10001); + + if (RSA_generate_key_ex(rsa, 1024, e, NULL) != 1) + errx(1, "RSA_generate_key_ex"); + BN_free(e); + } else { + rsa = read_key(engine, time_key); + } + + p = emalloc(loops * size); + + RAND_bytes(p, loops * size); + + gettimeofday(&tv1, NULL); + for (i = 0; i < loops; i++) + check_rsa(p + (i * size), size, rsa, RSA_PKCS1_PADDING); + gettimeofday(&tv2, NULL); + + timevalsub(&tv2, &tv1); + + printf("time %lu.%06lu\n", + (unsigned long)tv2.tv_sec, + (unsigned long)tv2.tv_usec); + + RSA_free(rsa); + ENGINE_finish(engine); + + free(p); + return 0; + } + + if (rsa_key) { + rsa = read_key(engine, rsa_key); + + /* + * Assuming that you use the RSA key in the distribution, this + * test will generate a signature have a starting zero and thus + * will generate a checksum that is 127 byte instead of the + * checksum that is 128 byte (like the key). + */ + { + const unsigned char sha1[20] = { + 0x6d, 0x33, 0xf9, 0x40, 0x75, 0x5b, 0x4e, 0xc5, 0x90, 0x35, + 0x48, 0xab, 0x75, 0x02, 0x09, 0x76, 0x9a, 0xb4, 0x7d, 0x6b + }; + + check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING); + } + + for (i = 0; i < 128; i++) { + unsigned char sha1[20]; + + RAND_bytes(sha1, sizeof(sha1)); + check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING); + } + for (i = 0; i < 128; i++) { + unsigned char des3[21]; + + RAND_bytes(des3, sizeof(des3)); + check_rsa(des3, sizeof(des3), rsa, RSA_PKCS1_PADDING); + } + for (i = 0; i < 128; i++) { + unsigned char aes[32]; + + RAND_bytes(aes, sizeof(aes)); + check_rsa(aes, sizeof(aes), rsa, RSA_PKCS1_PADDING); + } + + RSA_free(rsa); + } + + for (i = 0; i < loops; i++) { + BN_GENCB cb; + BIGNUM *e; + unsigned int n; + + rsa = RSA_new_method(engine); + if (!key_blinding) + rsa->flags |= RSA_FLAG_NO_BLINDING; + + e = BN_new(); + BN_set_word(e, 0x10001); + + BN_GENCB_set(&cb, cb_func, NULL); + + RAND_bytes(&n, sizeof(n)); + n &= 0x1ff; + n += 1024; + + if (RSA_generate_key_ex(rsa, n, e, &cb) != 1) + errx(1, "RSA_generate_key_ex"); + + BN_free(e); + + for (j = 0; j < 8; j++) { + unsigned char sha1[20]; + RAND_bytes(sha1, sizeof(sha1)); + check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING); + } + + RSA_free(rsa); + } + + ENGINE_finish(engine); + + return 0; +} diff --git a/third_party/heimdal/lib/hcrypto/ui.c b/third_party/heimdal/lib/hcrypto/ui.c new file mode 100644 index 0000000..0eb09e7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ui.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 1997 - 2000, 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#ifdef HAVE_TERMIOS_H +#include +#endif + +#include +#ifdef HAVE_CONIO_H +#include +#endif + +static sig_atomic_t intr_flag; + +static void +intr(int sig) +{ + intr_flag++; +} + +#ifdef HAVE_CONIO_H + +/* + * Windows does console slightly different then then unix case. + */ + +static int +read_string(const char *preprompt, const char *prompt, + char *buf, size_t len, int echo) +{ + int of = 0; + int c; + char *p; + void (*oldsigintr)(int); + + _cprintf("%s%s", preprompt, prompt); + + oldsigintr = signal(SIGINT, intr); + + p = buf; + while(intr_flag == 0){ + c = ((echo)? _getche(): _getch()); + if(c == '\n' || c == '\r') + break; + if(of == 0) + *p++ = c; + of = (p == buf + len); + } + if(of) + p--; + *p = 0; + + if(echo == 0){ + printf("\n"); + } + + signal(SIGINT, oldsigintr); + + if(intr_flag) + return -2; + if(of) + return -1; + return 0; +} + +#else /* !HAVE_CONIO_H */ + +#ifndef NSIG +#define NSIG 47 +#endif + +static int +read_string(const char *preprompt, const char *prompt, + char *buf, size_t len, int echo) +{ + struct sigaction sigs[NSIG]; + int oksigs[NSIG]; + struct sigaction sa; + FILE *tty; + int ret = 0; + int of = 0; + int i; + int c; + char *p; + + struct termios t_new, t_old; + + memset(&oksigs, 0, sizeof(oksigs)); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = intr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + for(i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) + if (i != SIGALRM) + if (sigaction(i, &sa, &sigs[i]) == 0) + oksigs[i] = 1; + + if((tty = fopen("/dev/tty", "r")) != NULL) + rk_cloexec_file(tty); + else + tty = stdin; + + fprintf(stderr, "%s%s", preprompt, prompt); + fflush(stderr); + + if(echo == 0){ + tcgetattr(fileno(tty), &t_old); + memcpy(&t_new, &t_old, sizeof(t_new)); + t_new.c_lflag &= ~ECHO; + tcsetattr(fileno(tty), TCSANOW, &t_new); + } + intr_flag = 0; + p = buf; + while(intr_flag == 0){ + c = getc(tty); + if(c == EOF){ + if(!ferror(tty)) + ret = 1; + break; + } + if(c == '\n') + break; + if(of == 0) + *p++ = c; + of = (p == buf + len); + } + if(of) + p--; + *p = 0; + + if(echo == 0){ + fprintf(stderr, "\n"); + tcsetattr(fileno(tty), TCSANOW, &t_old); + } + + if(tty != stdin) + fclose(tty); + + for(i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) + if (oksigs[i]) + sigaction(i, &sigs[i], NULL); + + if(ret) + return -3; + if(intr_flag) + return -2; + if(of) + return -1; + return 0; +} + +#endif /* HAVE_CONIO_H */ + +int +UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, int verify) +{ + int ret; + + ret = read_string("", prompt, buf, length, 0); + if (ret) + return ret; + + if (verify & UI_UTIL_FLAG_VERIFY) { + char *buf2; + buf2 = malloc(length); + if (buf2 == NULL) + return 1; + + ret = read_string("Verify password - ", prompt, buf2, length, 0); + if (ret) { + free(buf2); + return ret; + } + if (strcmp(buf2, buf) != 0) { + if (!(verify & UI_UTIL_FLAG_VERIFY_SILENT)) { + fprintf(stderr, "Verify failure\n"); + fflush(stderr); + } + ret = 1; + } + free(buf2); + } + return ret; +} diff --git a/third_party/heimdal/lib/hcrypto/ui.h b/third_party/heimdal/lib/hcrypto/ui.h new file mode 100644 index 0000000..4f56da7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/ui.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef _HEIM_UI_H +#define _HEIM_UI_H 1 + +/* symbol renaming */ +#define UI_UTIL_read_pw_string hc_UI_UTIL_read_pw_string + +/* OpenSSL API extensions */ +#define UI_UTIL_FLAG_VERIFY 0x1 /* ask to verify password */ +#define UI_UTIL_FLAG_VERIFY_SILENT 0x2 /* silence on verify failure */ + +int UI_UTIL_read_pw_string(char *, int, const char *, int); /* XXX */ + +#endif /* _HEIM_UI_H */ + diff --git a/third_party/heimdal/lib/hcrypto/undef.h b/third_party/heimdal/lib/hcrypto/undef.h new file mode 100644 index 0000000..6de5734 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/undef.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIM_UNDEF_H +#define HEIM_UNDEF_H 1 + +#undef BIGNUM +#undef BN_CTX +#undef BN_BLINDING +#undef BN_MONT_CTX +#undef BN_GENCB +#undef DH +#undef DH_METHOD +#undef DSA +#undef DSA_METHOD +#undef RSA +#undef RSA_METHOD +#undef RAND_METHOD +#undef ENGINE +#undef BN_GENCB_call +#undef BN_GENCB_set +#undef BN_CTX_new +#undef BN_CTX_free +#undef BN_CTX_start +#undef BN_CTX_get +#undef BN_CTX_end +#undef BN_is_negative +#undef BN_rand +#undef BN_num_bits +#undef BN_num_bytes +#undef BN_new +#undef BN_clear_free +#undef BN_bin2bn +#undef BN_bn2bin +#undef BN_uadd +#undef BN_set_negative +#undef BN_set_word +#undef BN_get_word +#undef BN_cmp +#undef BN_free +#undef BN_is_bit_set +#undef BN_clear +#undef BN_dup +#undef BN_set_bit +#undef BN_clear_bit +#undef BN_bn2hex +#undef BN_hex2bn +#undef EVP_CIPHER_CTX_block_size +#undef EVP_CIPHER_CTX_cipher +#undef EVP_CIPHER_CTX_cleanup +#undef EVP_CIPHER_CTX_flags +#undef EVP_CIPHER_CTX_get_app_data +#undef EVP_CIPHER_CTX_init +#undef EVP_CIPHER_CTX_iv_length +#undef EVP_CIPHER_CTX_key_length +#undef EVP_CIPHER_CTX_mode +#undef EVP_CIPHER_CTX_set_app_data +#undef EVP_CIPHER_CTX_set_key_length +#undef EVP_CIPHER_CTX_set_padding +#undef EVP_CIPHER_block_size +#undef EVP_CIPHER_iv_length +#undef EVP_CIPHER_key_length +#undef EVP_Cipher +#undef EVP_CipherInit_ex +#undef EVP_CipherUpdate +#undef EVP_CipherFinal_ex +#undef EVP_Digest +#undef EVP_DigestFinal_ex +#undef EVP_DigestInit_ex +#undef EVP_DigestUpdate +#undef EVP_MD_CTX_block_size +#undef EVP_MD_CTX_cleanup +#undef EVP_MD_CTX_create +#undef EVP_MD_CTX_init +#undef EVP_MD_CTX_destroy +#undef EVP_MD_CTX_md +#undef EVP_MD_CTX_size +#undef EVP_MD_block_size +#undef EVP_MD_size +#undef EVP_aes_128_cbc +#undef EVP_aes_192_cbc +#undef EVP_aes_256_cbc +#undef EVP_aes_128_cfb8 +#undef EVP_aes_192_cfb8 +#undef EVP_aes_256_cfb8 +#undef EVP_des_cbc +#undef EVP_des_ede3_cbc +#undef EVP_enc_null +#undef EVP_md4 +#undef EVP_md5 +#undef EVP_md_null +#undef EVP_rc2_40_cbc +#undef EVP_rc2_64_cbc +#undef EVP_rc2_cbc +#undef EVP_rc4 +#undef EVP_rc4_40 +#undef EVP_camellia_128_cbc +#undef EVP_camellia_192_cbc +#undef EVP_camellia_256_cbc +#undef EVP_sha +#undef EVP_sha1 +#undef EVP_sha256 +#undef EVP_sha384 +#undef EVP_sha512 +#undef PKCS5_PBKDF2_HMAC +#undef PKCS5_PBKDF2_HMAC_SHA1 +#undef EVP_BytesToKey +#undef EVP_get_cipherbyname +#undef OpenSSL_add_all_algorithms +#undef OpenSSL_add_all_algorithms_conf +#undef OpenSSL_add_all_algorithms_noconf +#undef EVP_CIPHER_CTX_ctrl +#undef EVP_CIPHER_CTX_rand_key +#undef hcrypto_validate +#undef EVP_MD_CTX +#undef EVP_PKEY +#undef EVP_MD +#undef EVP_CIPHER +#undef EVP_CIPHER_CTX +#undef EVP_CIPH_STREAM_CIPHER +#undef EVP_CIPH_CBC_MODE +#undef EVP_CIPH_CFB8_MODE +#undef EVP_CIPH_MODE +#undef EVP_CIPH_CTRL_INIT +#undef EVP_CTRL_INIT +#undef EVP_CIPH_VARIABLE_LENGTH +#undef EVP_CIPH_ALWAYS_CALL_INIT +#undef EVP_CIPH_RAND_KEY +#undef EVP_CTRL_RAND_KEY +#undef NID_md4 +#undef NID_md5 +#undef NID_sha1 +#undef NID_sha256 +#undef NID_sha384 +#undef NID_sha512 + +#endif /* HEIM_UNDEF_H */ diff --git a/third_party/heimdal/lib/hcrypto/validate.c b/third_party/heimdal/lib/hcrypto/validate.c new file mode 100644 index 0000000..4b655f2 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/validate.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include + +struct tests { + const EVP_CIPHER *(*cipher)(void); + const char *name; + void *key; + size_t keysize; + void *iv; + size_t datasize; + void *indata; + void *outdata; + void *outiv; +}; + +static struct tests hc_tests[] = { + { + EVP_aes_256_cbc, + "aes-256", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 32, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xdc\x95\xc0\x78\xa2\x40\x89\x89\xad\x48\xa2\x14\x92\x84\x20\x87", + NULL + }, +#if 0 + { + EVP_aes_128_cfb8, + "aes-cfb8-128", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e" + }, +#endif + { + EVP_des_ede3_cbc, + "des-ede3", + "\x19\x17\xff\xe6\xbb\x77\x2e\xfc" + "\x29\x76\x43\xbc\x63\x56\x7e\x9a" + "\x00\x2e\x4d\x43\x1d\x5f\xfd\x58", + 24, + "\xbf\x9a\x12\xb7\x26\x69\xfd\x05", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x55\x95\x97\x76\xa9\x6c\x66\x40\x64\xc7\xf4\x1c\x21\xb7\x14\x1b", + NULL + }, +#if 0 + { + EVP_camellia_128_cbc, + "camellia128", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16, + "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x07\x92\x3A\x39\xEB\x0A\x81\x7D\x1C\x4D\x87\xBD\xB8\x2D\x1F\x1C", + NULL + }, +#endif + { + EVP_rc4, + "rc4 8", + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + 8, + NULL, + 8, + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x74\x94\xC2\xE7\x10\x4B\x08\x79", + NULL + }, + { + EVP_rc4, + "rc4 5", + "\x61\x8a\x63\xd2\xfb", + 5, + NULL, + 5, + "\xdc\xee\x4c\xf9\x2c", + "\xf1\x38\x29\xc9\xde", + NULL + }, + { + EVP_rc4, + "rc4 309", + "\x29\x04\x19\x72\xfb\x42\xba\x5f\xc7\x12\x77\x12\xf1\x38\x29\xc9", + 16, + NULL, + 309, + "\x52\x75\x69\x73\x6c\x69\x6e\x6e" + "\x75\x6e\x20\x6c\x61\x75\x6c\x75" + "\x20\x6b\x6f\x72\x76\x69\x73\x73" + "\x73\x61\x6e\x69\x2c\x20\x74\xe4" + "\x68\x6b\xe4\x70\xe4\x69\x64\x65" + "\x6e\x20\x70\xe4\xe4\x6c\x6c\xe4" + "\x20\x74\xe4\x79\x73\x69\x6b\x75" + "\x75\x2e\x20\x4b\x65\x73\xe4\x79" + "\xf6\x6e\x20\x6f\x6e\x20\x6f\x6e" + "\x6e\x69\x20\x6f\x6d\x61\x6e\x61" + "\x6e\x69\x2c\x20\x6b\x61\x73\x6b" + "\x69\x73\x61\x76\x75\x75\x6e\x20" + "\x6c\x61\x61\x6b\x73\x6f\x74\x20" + "\x76\x65\x72\x68\x6f\x75\x75\x2e" + "\x20\x45\x6e\x20\x6d\x61\x20\x69" + "\x6c\x6f\x69\x74\x73\x65\x2c\x20" + "\x73\x75\x72\x65\x20\x68\x75\x6f" + "\x6b\x61\x61\x2c\x20\x6d\x75\x74" + "\x74\x61\x20\x6d\x65\x74\x73\xe4" + "\x6e\x20\x74\x75\x6d\x6d\x75\x75" + "\x73\x20\x6d\x75\x6c\x6c\x65\x20" + "\x74\x75\x6f\x6b\x61\x61\x2e\x20" + "\x50\x75\x75\x6e\x74\x6f\x20\x70" + "\x69\x6c\x76\x65\x6e\x2c\x20\x6d" + "\x69\x20\x68\x75\x6b\x6b\x75\x75" + "\x2c\x20\x73\x69\x69\x6e\x74\x6f" + "\x20\x76\x61\x72\x61\x6e\x20\x74" + "\x75\x75\x6c\x69\x73\x65\x6e\x2c" + "\x20\x6d\x69\x20\x6e\x75\x6b\x6b" + "\x75\x75\x2e\x20\x54\x75\x6f\x6b" + "\x73\x75\x74\x20\x76\x61\x6e\x61" + "\x6d\x6f\x6e\x20\x6a\x61\x20\x76" + "\x61\x72\x6a\x6f\x74\x20\x76\x65" + "\x65\x6e\x2c\x20\x6e\x69\x69\x73" + "\x74\xe4\x20\x73\x79\x64\xe4\x6d" + "\x65\x6e\x69\x20\x6c\x61\x75\x6c" + "\x75\x6e\x20\x74\x65\x65\x6e\x2e" + "\x20\x2d\x20\x45\x69\x6e\x6f\x20" + "\x4c\x65\x69\x6e\x6f", + "\x35\x81\x86\x99\x90\x01\xe6\xb5" + "\xda\xf0\x5e\xce\xeb\x7e\xee\x21" + "\xe0\x68\x9c\x1f\x00\xee\xa8\x1f" + "\x7d\xd2\xca\xae\xe1\xd2\x76\x3e" + "\x68\xaf\x0e\xad\x33\xd6\x6c\x26" + "\x8b\xc9\x46\xc4\x84\xfb\xe9\x4c" + "\x5f\x5e\x0b\x86\xa5\x92\x79\xe4" + "\xf8\x24\xe7\xa6\x40\xbd\x22\x32" + "\x10\xb0\xa6\x11\x60\xb7\xbc\xe9" + "\x86\xea\x65\x68\x80\x03\x59\x6b" + "\x63\x0a\x6b\x90\xf8\xe0\xca\xf6" + "\x91\x2a\x98\xeb\x87\x21\x76\xe8" + "\x3c\x20\x2c\xaa\x64\x16\x6d\x2c" + "\xce\x57\xff\x1b\xca\x57\xb2\x13" + "\xf0\xed\x1a\xa7\x2f\xb8\xea\x52" + "\xb0\xbe\x01\xcd\x1e\x41\x28\x67" + "\x72\x0b\x32\x6e\xb3\x89\xd0\x11" + "\xbd\x70\xd8\xaf\x03\x5f\xb0\xd8" + "\x58\x9d\xbc\xe3\xc6\x66\xf5\xea" + "\x8d\x4c\x79\x54\xc5\x0c\x3f\x34" + "\x0b\x04\x67\xf8\x1b\x42\x59\x61" + "\xc1\x18\x43\x07\x4d\xf6\x20\xf2" + "\x08\x40\x4b\x39\x4c\xf9\xd3\x7f" + "\xf5\x4b\x5f\x1a\xd8\xf6\xea\x7d" + "\xa3\xc5\x61\xdf\xa7\x28\x1f\x96" + "\x44\x63\xd2\xcc\x35\xa4\xd1\xb0" + "\x34\x90\xde\xc5\x1b\x07\x11\xfb" + "\xd6\xf5\x5f\x79\x23\x4d\x5b\x7c" + "\x76\x66\x22\xa6\x6d\xe9\x2b\xe9" + "\x96\x46\x1d\x5e\x4d\xc8\x78\xef" + "\x9b\xca\x03\x05\x21\xe8\x35\x1e" + "\x4b\xae\xd2\xfd\x04\xf9\x46\x73" + "\x68\xc4\xad\x6a\xc1\x86\xd0\x82" + "\x45\xb2\x63\xa2\x66\x6d\x1f\x6c" + "\x54\x20\xf1\x59\x9d\xfd\x9f\x43" + "\x89\x21\xc2\xf5\xa4\x63\x93\x8c" + "\xe0\x98\x22\x65\xee\xf7\x01\x79" + "\xbc\x55\x3f\x33\x9e\xb1\xa4\xc1" + "\xaf\x5f\x6a\x54\x7f", + NULL + } +}; + +static int +test_cipher(struct tests *t) +{ + const EVP_CIPHER *c = t->cipher(); + EVP_CIPHER_CTX ectx; + EVP_CIPHER_CTX dctx; + void *d; + + EVP_CIPHER_CTX_init(&ectx); + EVP_CIPHER_CTX_init(&dctx); + + if (EVP_CipherInit_ex(&ectx, c, NULL, NULL, NULL, 1) != 1) + errx(1, "%s: EVP_CipherInit_ex einit", t->name); + if (EVP_CipherInit_ex(&dctx, c, NULL, NULL, NULL, 0) != 1) + errx(1, "%s: EVP_CipherInit_ex dinit", t->name); + + EVP_CIPHER_CTX_set_key_length(&ectx, t->keysize); + EVP_CIPHER_CTX_set_key_length(&dctx, t->keysize); + + if (EVP_CipherInit_ex(&ectx, NULL, NULL, t->key, t->iv, 1) != 1) + errx(1, "%s: EVP_CipherInit_ex encrypt", t->name); + if (EVP_CipherInit_ex(&dctx, NULL, NULL, t->key, t->iv, 0) != 1) + errx(1, "%s: EVP_CipherInit_ex decrypt", t->name); + + d = emalloc(t->datasize); + + if (!EVP_Cipher(&ectx, d, t->indata, t->datasize)) + return 1; + + if (memcmp(d, t->outdata, t->datasize) != 0) + errx(1, "%s: encrypt not the same", t->name); + + if (!EVP_Cipher(&dctx, d, d, t->datasize)) + return 1; + + if (memcmp(d, t->indata, t->datasize) != 0) + errx(1, "%s: decrypt not the same", t->name); + +#if 0 + if (t->outiv) + /* XXXX check */; +#endif + + EVP_CIPHER_CTX_cleanup(&ectx); + EVP_CIPHER_CTX_cleanup(&dctx); + free(d); + + return 0; +} + +static void +check_hmac(void) +{ + unsigned char buf[4] = { 0, 0, 0, 0 }; + char hmackey[] = "hello-world"; + size_t hmackey_size = sizeof(hmackey); + unsigned int hmaclen; + unsigned char hmac[EVP_MAX_MD_SIZE]; + HMAC_CTX c; + + char answer[20] = "\x2c\xfa\x32\xb7\x2b\x8a\xf6\xdf\xcf\xda" + "\x6f\xd1\x52\x4d\x54\x58\x73\x0f\xf3\x24"; + + HMAC_CTX_init(&c); + if (HMAC_Init_ex(&c, hmackey, hmackey_size, EVP_sha1(), NULL) == 0) + errx(1, "HMAC_Init_ex() out of memory"); + HMAC_Update(&c, buf, sizeof(buf)); + HMAC_Final(&c, hmac, &hmaclen); + HMAC_CTX_cleanup(&c); + + if (hmaclen != 20) + errx(1, "hmaclen = %d\n", (int)hmaclen); + + if (ct_memcmp(hmac, answer, hmaclen) != 0) + errx(1, "wrong answer\n"); +} + +void +hcrypto_validate(void) +{ + static int validated = 0; + unsigned int i; + + /* its ok to run this twice, do don't check for races */ + if (validated) + return; + validated++; + + for (i = 0; i < sizeof(hc_tests) / sizeof(hc_tests[0]); i++) + test_cipher(&hc_tests[i]); + + check_hmac(); +} diff --git a/third_party/heimdal/lib/hcrypto/version-script.map b/third_party/heimdal/lib/hcrypto/version-script.map new file mode 100644 index 0000000..b51d4bb --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/version-script.map @@ -0,0 +1,333 @@ +# $Id$ + +HEIMDAL_CRYPTO_1.0 { + global: + hc_AES_cbc_encrypt; + hc_AES_cfb8_encrypt; + hc_AES_decrypt; + hc_AES_decrypt_key; + hc_BN_CTX_end; + hc_BN_CTX_free; + hc_BN_CTX_get; + hc_BN_CTX_new; + hc_BN_CTX_start; + hc_AES_encrypt; + hc_AES_set_encrypt_key; + hc_BN_GENCB_call; + hc_BN_GENCB_set; + hc_BN_bin2bn; + hc_BN_bn2bin; + hc_BN_bn2hex; + hc_BN_clear; + hc_BN_clear_bit; + hc_BN_clear_free; + hc_BN_cmp; + hc_BN_dup; + hc_BN_free; + hc_BN_get_word; + hc_BN_hex2bn; + hc_BN_is_bit_set; + hc_BN_is_negative; + hc_BN_new; + hc_BN_num_bits; + hc_BN_num_bytes; + hc_BN_rand; + hc_BN_set_bit; + hc_BN_set_negative; + hc_BN_set_word; + hc_BN_uadd; + hc_DES_cbc_cksum; + hc_DES_cbc_encrypt; + hc_DES_cfb64_encrypt; + hc_DES_check_key_parity; + hc_DES_ecb3_encrypt; + hc_DES_ecb_encrypt; + hc_DES_ede3_cbc_encrypt; + hc_DES_encrypt; + hc_DES_generate_random_block; + hc_DES_init_random_number_generator; + hc_DES_is_weak_key; + hc_DES_key_sched; + hc_DES_mem_rand8; + hc_DES_new_random_key; + hc_DES_pcbc_encrypt; + hc_DES_rand_data; + hc_DES_rand_data_key; + hc_DES_random_key; + hc_DES_read_password; + hc_DES_set_key; + hc_DES_set_key_checked; + hc_DES_set_key_unchecked; + hc_DES_set_odd_parity; + hc_DES_set_random_generator_seed; + hc_DES_set_sequence_number; + hc_DES_string_to_key; + hc_DH_check_pubkey; + hc_DH_compute_key; + hc_DH_free; + hc_DH_generate_key; + hc_DH_generate_parameters_ex; + hc_DH_get_default_method; + hc_DH_get_ex_data; + hc_DH_ltm_method; + hc_DH_gmp_method; + hc_DH_new; + hc_DH_new_method; + hc_DH_null_method; + hc_DH_set_default_method; + hc_DH_set_ex_data; + hc_DH_set_method; + hc_DH_size; + hc_DH_up_ref; + hc_DSA_free; + hc_DSA_get_default_method; + hc_DSA_new; + hc_DSA_null_method; + hc_DSA_set_default_method; + hc_DSA_up_ref; + hc_DSA_verify; + hc_ENGINE_new; + hc_ENGINE_free; + hc_ENGINE_add_conf_module; + hc_ENGINE_by_dso; + hc_ENGINE_by_id; + hc_ENGINE_finish; + hc_ENGINE_get_DH; + hc_ENGINE_get_RAND; + hc_ENGINE_get_RSA; + hc_ENGINE_get_default_DH; + hc_ENGINE_get_default_RSA; + hc_ENGINE_get_id; + hc_ENGINE_get_name; + hc_ENGINE_load_builtin_engines; + hc_ENGINE_set_DH; + hc_ENGINE_set_RSA; + hc_ENGINE_set_default_DH; + hc_ENGINE_set_default_RSA; + hc_ENGINE_set_destroy_function; + hc_ENGINE_set_id; + hc_ENGINE_set_name; + hc_ENGINE_up_ref; + hc_EVP_BytesToKey; + hc_EVP_CIPHER_CTX_block_size; + hc_EVP_CIPHER_CTX_cipher; + hc_EVP_CIPHER_CTX_cleanup; + hc_EVP_CIPHER_CTX_flags; + hc_EVP_CIPHER_CTX_get_app_data; + hc_EVP_CIPHER_CTX_init; + hc_EVP_CIPHER_CTX_iv_length; + hc_EVP_CIPHER_CTX_key_length; + hc_EVP_CIPHER_CTX_mode; + hc_EVP_CIPHER_CTX_set_app_data; + hc_EVP_CIPHER_block_size; + hc_EVP_CIPHER_iv_length; + hc_EVP_CIPHER_key_length; + hc_EVP_Cipher; + hc_EVP_CipherInit_ex; + hc_EVP_Digest; + hc_EVP_DigestFinal_ex; + hc_EVP_DigestInit_ex; + hc_EVP_DigestUpdate; + hc_EVP_MD_CTX_block_size; + hc_EVP_MD_CTX_cleanup; + hc_EVP_MD_CTX_cleanup; + hc_EVP_MD_CTX_create; + hc_EVP_MD_CTX_create; + hc_EVP_MD_CTX_destroy; + hc_EVP_MD_CTX_destroy; + hc_EVP_MD_CTX_init; + hc_EVP_MD_CTX_init; + hc_EVP_MD_CTX_md; + hc_EVP_MD_CTX_size; + hc_EVP_MD_block_size; + hc_EVP_MD_size; + hc_EVP_aes_128_cbc; + hc_EVP_aes_192_cbc; + hc_EVP_aes_256_cbc; + hc_EVP_aes_128_cfb8; + hc_EVP_aes_192_cfb8; + hc_EVP_aes_256_cfb8; + hc_EVP_des_cbc; + hc_EVP_des_ede3_cbc; + hc_EVP_camellia_128_cbc; + hc_EVP_camellia_192_cbc; + hc_EVP_camellia_256_cbc; + hc_EVP_enc_null; + hc_EVP_get_cipherbyname; + hc_EVP_md4; + hc_EVP_md5; + hc_EVP_md_null; + hc_EVP_rc2_40_cbc; + hc_EVP_rc2_64_cbc; + hc_EVP_rc2_cbc; + hc_EVP_rc4; + hc_EVP_rc4_40; + hc_EVP_sha; + hc_EVP_sha1; + hc_EVP_sha256; + hc_EVP_sha384; + hc_EVP_sha512; + + hc_EVP_cc_md4; + hc_EVP_cc_md5; + hc_EVP_cc_sha1; + hc_EVP_cc_sha256; + hc_EVP_cc_sha384; + hc_EVP_cc_sha512; + hc_EVP_cc_des_ede3_cbc; + hc_EVP_cc_aes_128_cbc; + hc_EVP_cc_aes_192_cbc; + hc_EVP_cc_aes_256_cbc; + hc_EVP_cc_aes_128_cfb8; + hc_EVP_cc_aes_192_cfb8; + hc_EVP_cc_aes_256_cfb8; + + hc_EVP_hcrypto_md4; + hc_EVP_hcrypto_md5; + hc_EVP_hcrypto_sha1; + hc_EVP_hcrypto_sha256; + hc_EVP_hcrypto_sha384; + hc_EVP_hcrypto_sha512; + hc_EVP_hcrypto_des_ede3_cbc; + hc_EVP_hcrypto_aes_128_cbc; + hc_EVP_hcrypto_aes_192_cbc; + hc_EVP_hcrypto_aes_256_cbc; + hc_EVP_hcrypto_aes_128_cfb8; + hc_EVP_hcrypto_aes_192_cfb8; + hc_EVP_hcrypto_aes_256_cfb8; + hc_EVP_hcrypto_rc4; + hc_EVP_hcrypto_rc4_40; + + hc_EVP_ossl_md4; + hc_EVP_ossl_md5; + hc_EVP_ossl_sha1; + hc_EVP_ossl_sha256; + hc_EVP_ossl_sha384; + hc_EVP_ossl_sha512; + hc_EVP_ossl_des_ede3_cbc; + hc_EVP_ossl_aes_128_cbc; + hc_EVP_ossl_aes_192_cbc; + hc_EVP_ossl_aes_256_cbc; + hc_EVP_ossl_aes_128_cfb8; + hc_EVP_ossl_aes_192_cfb8; + hc_EVP_ossl_aes_256_cfb8; + hc_EVP_ossl_rc2_cbc; + hc_EVP_ossl_rc2_40_cbc; + hc_EVP_ossl_rc4; + hc_EVP_ossl_rc4_40; + + hc_EVP_pkcs11_md4; + hc_EVP_pkcs11_md5; + hc_EVP_pkcs11_sha1; + hc_EVP_pkcs11_sha256; + hc_EVP_pkcs11_des_ede3_cbc; + hc_EVP_pkcs11_aes_128_cbc; + hc_EVP_pkcs11_aes_192_cbc; + hc_EVP_pkcs11_aes_256_cbc; + hc_EVP_pkcs11_aes_128_cfb8; + hc_EVP_pkcs11_aes_192_cfb8; + hc_EVP_pkcs11_aes_256_cfb8; + hc_EVP_pkcs11_rc2_40_cbc; + hc_EVP_pkcs11_rc2_64_cbc; + hc_EVP_pkcs11_rc2_cbc; + hc_EVP_pkcs11_rc4; + hc_EVP_pkcs11_rc4_40; + + hc_EVP_hcrypto_aes_128_cts; + hc_EVP_hcrypto_aes_192_cts; + hc_EVP_hcrypto_aes_256_cts; + hc_HMAC; + hc_HMAC_CTX_cleanup; + hc_HMAC_CTX_free; + hc_HMAC_CTX_init; + hc_HMAC_CTX_new; + hc_HMAC_Final; + hc_HMAC_Init_ex; + hc_HMAC_Update; + hc_HMAC_size; + hc_MD4_Final; + hc_MD4_Init; + hc_MD4_Update; + hc_MD5_Final; + hc_MD5_Init; + hc_MD5_Update; + hc_OpenSSL_add_all_algorithms; + hc_OpenSSL_add_all_algorithms_conf; + hc_OpenSSL_add_all_algorithms_noconf; + hc_PKCS12_key_gen; + hc_PKCS5_PBKDF2_HMAC; + hc_PKCS5_PBKDF2_HMAC_SHA1; + hc_RAND_add; + hc_RAND_bytes; + hc_RAND_cleanup; + hc_RAND_file_name; + hc_RAND_fortuna_method; + hc_RAND_get_rand_method; + hc_RAND_load_file; + hc_RAND_pseudo_bytes; + hc_RAND_seed; + hc_RAND_set_rand_engine; + hc_RAND_set_rand_method; + hc_RAND_status; + hc_RAND_unix_method; + hc_RAND_timer_method; + hc_RAND_write_file; + hc_RC2_cbc_encrypt; + hc_RC2_decryptc; + hc_RC2_encryptc; + hc_RC2_set_key; + hc_RC4; + hc_RC4_set_key; + hc_RSA_check_key; + hc_RSA_free; + hc_RSA_generate_key_ex; + hc_RSA_get_app_data; + hc_RSA_get_default_method; + hc_RSA_get_method; + hc_RSA_new; + hc_RSA_new_method; + hc_RSA_null_method; + hc_RSA_private_decrypt; + hc_RSA_private_encrypt; + hc_RSA_public_decrypt; + hc_RSA_public_encrypt; + hc_RSA_set_app_data; + hc_RSA_set_default_method; + hc_RSA_set_method; + hc_RSA_sign; + hc_RSA_size; + hc_RSA_up_ref; + hc_RSA_verify; + hc_SHA1_Final; + hc_SHA1_Init; + hc_SHA1_Update; + hc_SHA256_Final; + hc_SHA256_Init; + hc_SHA256_Update; + hc_SHA384_Final; + hc_SHA384_Init; + hc_SHA384_Update; + hc_SHA512_Final; + hc_SHA512_Init; + hc_SHA512_Update; + hc_UI_UTIL_read_pw_string; + hc_UI_UTIL_read_pw_string; + hc_i2d_DHparams; + hc_d2i_RSAPrivateKey; + hc_i2d_RSAPrivateKey; + hc_i2d_RSAPublicKey; + hc_d2i_RSAPublicKey; + hc_EVP_CIPHER_CTX_ctrl; + hc_EVP_CIPHER_CTX_rand_key; + hc_EVP_CIPHER_CTX_set_key_length; + hc_EVP_hcrypto_rc2_cbc; + hc_EVP_hcrypto_rc2_40_cbc; + hc_EVP_hcrypto_camellia_128_cbc; + hc_EVP_CipherUpdate; + hc_EVP_CipherFinal_ex; + hc_hcrypto_validate; + hc_hcrypto_scalarmult_curve25519; + hc_hcrypto_scalarmult_curve25519_base; + local: + *; +}; diff --git a/third_party/heimdal/lib/hcrypto/x25519/NTMakefile b/third_party/heimdal/lib/hcrypto/x25519/NTMakefile new file mode 100644 index 0000000..408f240 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/NTMakefile @@ -0,0 +1,46 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\hcrypto\x25519 + +!include ../../../windows/NTMakefile.w32 + +intcflags=-I$(SRC)\lib\hcrypto + +LIBX25519_OBJS= \ + $(OBJ)\ed25519_ref10.obj \ + $(OBJ)\x25519_ref10.obj + +$(LIBX25519): $(LIBX25519_OBJS) + $(LIBCON) + +all:: $(LIBX25519) + diff --git a/third_party/heimdal/lib/hcrypto/x25519/align.h b/third_party/heimdal/lib/hcrypto/x25519/align.h new file mode 100644 index 0000000..57c90ec --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/align.h @@ -0,0 +1,7 @@ +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif diff --git a/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.c b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.c new file mode 100644 index 0000000..6533404 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.c @@ -0,0 +1,2886 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "ed25519_ref10.h" +#include "align.h" + +static inline uint64_t +load_3(const unsigned char *in) +{ + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + + return result; +} + +static inline uint64_t +load_4(const unsigned char *in) +{ + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + + return result; +} + +/* + * Field arithmetic: + * Use 5*51 bit limbs on 64-bit systems with support for 128 bit arithmetic, + * and 10*25.5 bit limbs elsewhere. + * + * Functions used elsewhere that are candidates for inlining are defined + * via "private/curve25519_ref10.h". + */ + +#ifdef HAVE_TI_MODE +# include "fe_51/constants.h" +# include "fe_51/fe.h" +#else +# include "fe_25_5/constants.h" +# include "fe_25_5/fe.h" +#endif + +void +fe25519_invert(fe25519 out, const fe25519 z) +{ + fe25519 t0; + fe25519 t1; + fe25519 t2; + fe25519 t3; + int i; + + fe25519_sq(t0, z); + fe25519_sq(t1, t0); + fe25519_sq(t1, t1); + fe25519_mul(t1, z, t1); + fe25519_mul(t0, t0, t1); + fe25519_sq(t2, t0); + fe25519_mul(t1, t1, t2); + fe25519_sq(t2, t1); + for (i = 1; i < 5; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 10; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 20; ++i) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 10; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 50; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 100; ++i) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 50; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 5; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(out, t1, t0); +} + +static void +fe25519_pow22523(fe25519 out, const fe25519 z) +{ + fe25519 t0; + fe25519 t1; + fe25519 t2; + int i; + + fe25519_sq(t0, z); + fe25519_sq(t1, t0); + fe25519_sq(t1, t1); + fe25519_mul(t1, z, t1); + fe25519_mul(t0, t0, t1); + fe25519_sq(t0, t0); + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 5; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 10; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t1, t1, t0); + fe25519_sq(t2, t1); + for (i = 1; i < 20; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 10; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 50; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t1, t1, t0); + fe25519_sq(t2, t1); + for (i = 1; i < 100; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 50; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t0, t0); + fe25519_sq(t0, t0); + fe25519_mul(out, t0, z); +} + +static inline void +fe25519_cneg(fe25519 h, const fe25519 f, unsigned int b) +{ + fe25519 negf; + + fe25519_neg(negf, f); + fe25519_copy(h, f); + fe25519_cmov(h, negf, b); +} + +static inline void +fe25519_abs(fe25519 h, const fe25519 f) +{ + fe25519_cneg(h, f, fe25519_isnegative(f)); +} + +/* + r = p + q + */ + +void +ge25519_add(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->YplusX); + fe25519_mul(r->Y, r->Y, q->YminusX); + fe25519_mul(r->T, q->T2d, p->T); + fe25519_mul(r->X, p->Z, q->Z); + fe25519_add(t0, r->X, r->X); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_add(r->Z, t0, r->T); + fe25519_sub(r->T, t0, r->T); +} + +static void +slide_vartime(signed char *r, const unsigned char *a) +{ + int i; + int b; + int k; + int ribs; + int cmp; + + for (i = 0; i < 256; ++i) { + r[i] = 1 & (a[i >> 3] >> (i & 7)); + } + for (i = 0; i < 256; ++i) { + if (! r[i]) { + continue; + } + for (b = 1; b <= 6 && i + b < 256; ++b) { + if (! r[i + b]) { + continue; + } + ribs = r[i + b] << b; + cmp = r[i] + ribs; + if (cmp <= 15) { + r[i] = cmp; + r[i + b] = 0; + } else { + cmp = r[i] - ribs; + if (cmp < -15) { + break; + } + r[i] = cmp; + for (k = i + b; k < 256; ++k) { + if (! r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } + } + } +} + +int +ge25519_frombytes(ge25519_p3 *h, const unsigned char *s) +{ + fe25519 u; + fe25519 v; + fe25519 v3; + fe25519 vxx; + fe25519 m_root_check, p_root_check; + fe25519 negx; + fe25519 x_sqrtm1; + int has_m_root, has_p_root; + + fe25519_frombytes(h->Y, s); + fe25519_1(h->Z); + fe25519_sq(u, h->Y); + fe25519_mul(v, u, d); + fe25519_sub(u, u, h->Z); /* u = y^2-1 */ + fe25519_add(v, v, h->Z); /* v = dy^2+1 */ + + fe25519_sq(v3, v); + fe25519_mul(v3, v3, v); /* v3 = v^3 */ + fe25519_sq(h->X, v3); + fe25519_mul(h->X, h->X, v); + fe25519_mul(h->X, h->X, u); /* x = uv^7 */ + + fe25519_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe25519_mul(h->X, h->X, v3); + fe25519_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe25519_sq(vxx, h->X); + fe25519_mul(vxx, vxx, v); + fe25519_sub(m_root_check, vxx, u); /* vx^2-u */ + fe25519_add(p_root_check, vxx, u); /* vx^2+u */ + has_m_root = fe25519_iszero(m_root_check); + has_p_root = fe25519_iszero(p_root_check); + fe25519_mul(x_sqrtm1, h->X, sqrtm1); /* x*sqrt(-1) */ + fe25519_cmov(h->X, x_sqrtm1, 1 - has_m_root); + + fe25519_neg(negx, h->X); + fe25519_cmov(h->X, negx, fe25519_isnegative(h->X) ^ (s[31] >> 7)); + fe25519_mul(h->T, h->X, h->Y); + + return (has_m_root | has_p_root) - 1; +} + +int +ge25519_frombytes_negate_vartime(ge25519_p3 *h, const unsigned char *s) +{ + fe25519 u; + fe25519 v; + fe25519 v3; + fe25519 vxx; + fe25519 m_root_check, p_root_check; + + fe25519_frombytes(h->Y, s); + fe25519_1(h->Z); + fe25519_sq(u, h->Y); + fe25519_mul(v, u, d); + fe25519_sub(u, u, h->Z); /* u = y^2-1 */ + fe25519_add(v, v, h->Z); /* v = dy^2+1 */ + + fe25519_sq(v3, v); + fe25519_mul(v3, v3, v); /* v3 = v^3 */ + fe25519_sq(h->X, v3); + fe25519_mul(h->X, h->X, v); + fe25519_mul(h->X, h->X, u); /* x = uv^7 */ + + fe25519_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe25519_mul(h->X, h->X, v3); + fe25519_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe25519_sq(vxx, h->X); + fe25519_mul(vxx, vxx, v); + fe25519_sub(m_root_check, vxx, u); /* vx^2-u */ + if (fe25519_iszero(m_root_check) == 0) { + fe25519_add(p_root_check, vxx, u); /* vx^2+u */ + if (fe25519_iszero(p_root_check) == 0) { + return -1; + } + fe25519_mul(h->X, h->X, sqrtm1); + } + + if (fe25519_isnegative(h->X) == (s[31] >> 7)) { + fe25519_neg(h->X, h->X); + } + fe25519_mul(h->T, h->X, h->Y); + + return 0; +} + +/* + r = p + q + */ + +static void +ge25519_madd(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_precomp *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->yplusx); + fe25519_mul(r->Y, r->Y, q->yminusx); + fe25519_mul(r->T, q->xy2d, p->T); + fe25519_add(t0, p->Z, p->Z); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_add(r->Z, t0, r->T); + fe25519_sub(r->T, t0, r->T); +} + +/* + r = p - q + */ + +static void +ge25519_msub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_precomp *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->yminusx); + fe25519_mul(r->Y, r->Y, q->yplusx); + fe25519_mul(r->T, q->xy2d, p->T); + fe25519_add(t0, p->Z, p->Z); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_sub(r->Z, t0, r->T); + fe25519_add(r->T, t0, r->T); +} + +/* + r = p + */ + +void +ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p) +{ + fe25519_mul(r->X, p->X, p->T); + fe25519_mul(r->Y, p->Y, p->Z); + fe25519_mul(r->Z, p->Z, p->T); +} + +/* + r = p + */ + +void +ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p) +{ + fe25519_mul(r->X, p->X, p->T); + fe25519_mul(r->Y, p->Y, p->Z); + fe25519_mul(r->Z, p->Z, p->T); + fe25519_mul(r->T, p->X, p->Y); +} + +static void +ge25519_p2_0(ge25519_p2 *h) +{ + fe25519_0(h->X); + fe25519_1(h->Y); + fe25519_1(h->Z); +} + +/* + r = 2 * p + */ + +static void +ge25519_p2_dbl(ge25519_p1p1 *r, const ge25519_p2 *p) +{ + fe25519 t0; + + fe25519_sq(r->X, p->X); + fe25519_sq(r->Z, p->Y); + fe25519_sq2(r->T, p->Z); + fe25519_add(r->Y, p->X, p->Y); + fe25519_sq(t0, r->Y); + fe25519_add(r->Y, r->Z, r->X); + fe25519_sub(r->Z, r->Z, r->X); + fe25519_sub(r->X, t0, r->Y); + fe25519_sub(r->T, r->T, r->Z); +} + +static void +ge25519_p3_0(ge25519_p3 *h) +{ + fe25519_0(h->X); + fe25519_1(h->Y); + fe25519_1(h->Z); + fe25519_0(h->T); +} + +static void +ge25519_cached_0(ge25519_cached *h) +{ + fe25519_1(h->YplusX); + fe25519_1(h->YminusX); + fe25519_1(h->Z); + fe25519_0(h->T2d); +} + +/* + r = p + */ + +void +ge25519_p3_to_cached(ge25519_cached *r, const ge25519_p3 *p) +{ + fe25519_add(r->YplusX, p->Y, p->X); + fe25519_sub(r->YminusX, p->Y, p->X); + fe25519_copy(r->Z, p->Z); + fe25519_mul(r->T2d, p->T, d2); +} + +static void +ge25519_p3_to_precomp(ge25519_precomp *pi, const ge25519_p3 *p) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + fe25519 xy; + + fe25519_invert(recip, p->Z); + fe25519_mul(x, p->X, recip); + fe25519_mul(y, p->Y, recip); + fe25519_add(pi->yplusx, y, x); + fe25519_sub(pi->yminusx, y, x); + fe25519_mul(xy, x, y); + fe25519_mul(pi->xy2d, xy, d2); +} + +/* + r = p + */ + +static void +ge25519_p3_to_p2(ge25519_p2 *r, const ge25519_p3 *p) +{ + fe25519_copy(r->X, p->X); + fe25519_copy(r->Y, p->Y); + fe25519_copy(r->Z, p->Z); +} + +void +ge25519_p3_tobytes(unsigned char *s, const ge25519_p3 *h) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + + fe25519_invert(recip, h->Z); + fe25519_mul(x, h->X, recip); + fe25519_mul(y, h->Y, recip); + fe25519_tobytes(s, y); + s[31] ^= fe25519_isnegative(x) << 7; +} + +/* + r = 2 * p + */ + +static void +ge25519_p3_dbl(ge25519_p1p1 *r, const ge25519_p3 *p) +{ + ge25519_p2 q; + ge25519_p3_to_p2(&q, p); + ge25519_p2_dbl(r, &q); +} + +static void +ge25519_precomp_0(ge25519_precomp *h) +{ + fe25519_1(h->yplusx); + fe25519_1(h->yminusx); + fe25519_0(h->xy2d); +} + +static unsigned char +equal(signed char b, signed char c) +{ + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = (uint32_t) x; /* 0: yes; 1..255: no */ + + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + + return y; +} + +static unsigned char +negative(signed char b) +{ + /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + uint64_t x = b; + + x >>= 63; /* 1: yes; 0: no */ + + return x; +} + +static void +ge25519_cmov(ge25519_precomp *t, const ge25519_precomp *u, unsigned char b) +{ + fe25519_cmov(t->yplusx, u->yplusx, b); + fe25519_cmov(t->yminusx, u->yminusx, b); + fe25519_cmov(t->xy2d, u->xy2d, b); +} + +static void +ge25519_cmov_cached(ge25519_cached *t, const ge25519_cached *u, unsigned char b) +{ + fe25519_cmov(t->YplusX, u->YplusX, b); + fe25519_cmov(t->YminusX, u->YminusX, b); + fe25519_cmov(t->Z, u->Z, b); + fe25519_cmov(t->T2d, u->T2d, b); +} + +static void +ge25519_cmov8(ge25519_precomp *t, const ge25519_precomp precomp[8], const signed char b) +{ + ge25519_precomp minust; + const unsigned char bnegative = negative(b); + const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); + + ge25519_precomp_0(t); + ge25519_cmov(t, &precomp[0], equal(babs, 1)); + ge25519_cmov(t, &precomp[1], equal(babs, 2)); + ge25519_cmov(t, &precomp[2], equal(babs, 3)); + ge25519_cmov(t, &precomp[3], equal(babs, 4)); + ge25519_cmov(t, &precomp[4], equal(babs, 5)); + ge25519_cmov(t, &precomp[5], equal(babs, 6)); + ge25519_cmov(t, &precomp[6], equal(babs, 7)); + ge25519_cmov(t, &precomp[7], equal(babs, 8)); + fe25519_copy(minust.yplusx, t->yminusx); + fe25519_copy(minust.yminusx, t->yplusx); + fe25519_neg(minust.xy2d, t->xy2d); + ge25519_cmov(t, &minust, bnegative); +} + +static void +ge25519_cmov8_base(ge25519_precomp *t, const int pos, const signed char b) +{ + static const ge25519_precomp base[32][8] = { /* base[i][j] = (j+1)*256^i*B */ +#ifdef HAVE_TI_MODE +# include "fe_51/base.h" +#else +# include "fe_25_5/base.h" +#endif + }; + ge25519_cmov8(t, base[pos], b); +} + +static void +ge25519_cmov8_cached(ge25519_cached *t, const ge25519_cached cached[8], const signed char b) +{ + ge25519_cached minust; + const unsigned char bnegative = negative(b); + const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); + + ge25519_cached_0(t); + ge25519_cmov_cached(t, &cached[0], equal(babs, 1)); + ge25519_cmov_cached(t, &cached[1], equal(babs, 2)); + ge25519_cmov_cached(t, &cached[2], equal(babs, 3)); + ge25519_cmov_cached(t, &cached[3], equal(babs, 4)); + ge25519_cmov_cached(t, &cached[4], equal(babs, 5)); + ge25519_cmov_cached(t, &cached[5], equal(babs, 6)); + ge25519_cmov_cached(t, &cached[6], equal(babs, 7)); + ge25519_cmov_cached(t, &cached[7], equal(babs, 8)); + fe25519_copy(minust.YplusX, t->YminusX); + fe25519_copy(minust.YminusX, t->YplusX); + fe25519_copy(minust.Z, t->Z); + fe25519_neg(minust.T2d, t->T2d); + ge25519_cmov_cached(t, &minust, bnegative); +} + +/* + r = p - q + */ + +void +ge25519_sub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->YminusX); + fe25519_mul(r->Y, r->Y, q->YplusX); + fe25519_mul(r->T, q->T2d, p->T); + fe25519_mul(r->X, p->Z, q->Z); + fe25519_add(t0, r->X, r->X); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_sub(r->Z, t0, r->T); + fe25519_add(r->T, t0, r->T); +} + +void +ge25519_tobytes(unsigned char *s, const ge25519_p2 *h) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + + fe25519_invert(recip, h->Z); + fe25519_mul(x, h->X, recip); + fe25519_mul(y, h->Y, recip); + fe25519_tobytes(s, y); + s[31] ^= fe25519_isnegative(x) << 7; +} + +/* + r = a * A + b * B + where a = a[0]+256*a[1]+...+256^31 a[31]. + and b = b[0]+256*b[1]+...+256^31 b[31]. + B is the Ed25519 base point (x,4/5) with x positive. + + Only used for signatures verification. + */ + +void +ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, + const ge25519_p3 *A, const unsigned char *b) +{ + static const ge25519_precomp Bi[8] = { +#ifdef HAVE_TI_MODE +# include "fe_51/base2.h" +#else +# include "fe_25_5/base2.h" +#endif + }; + signed char aslide[256]; + signed char bslide[256]; + ge25519_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + ge25519_p1p1 t; + ge25519_p3 u; + ge25519_p3 A2; + int i; + + slide_vartime(aslide, a); + slide_vartime(bslide, b); + + ge25519_p3_to_cached(&Ai[0], A); + + ge25519_p3_dbl(&t, A); + ge25519_p1p1_to_p3(&A2, &t); + + ge25519_add(&t, &A2, &Ai[0]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[1], &u); + + ge25519_add(&t, &A2, &Ai[1]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[2], &u); + + ge25519_add(&t, &A2, &Ai[2]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[3], &u); + + ge25519_add(&t, &A2, &Ai[3]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[4], &u); + + ge25519_add(&t, &A2, &Ai[4]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[5], &u); + + ge25519_add(&t, &A2, &Ai[5]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[6], &u); + + ge25519_add(&t, &A2, &Ai[6]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[7], &u); + + ge25519_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) { + break; + } + } + + for (; i >= 0; --i) { + ge25519_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + if (bslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_madd(&t, &u, &Bi[bslide[i] / 2]); + } else if (bslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_msub(&t, &u, &Bi[(-bslide[i]) / 2]); + } + + ge25519_p1p1_to_p2(r, &t); + } +} + +/* + h = a * p + where a = a[0]+256*a[1]+...+256^31 a[31] + + Preconditions: + a[31] <= 127 + + p is public + */ + +void +ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a, const ge25519_p3 *p) +{ + signed char e[64]; + signed char carry; + ge25519_p1p1 r; + ge25519_p2 s; + ge25519_p1p1 t2, t3, t4, t5, t6, t7, t8; + ge25519_p3 p2, p3, p4, p5, p6, p7, p8; + ge25519_cached pi[8]; + ge25519_cached t; + int i; + + ge25519_p3_to_cached(&pi[1 - 1], p); /* p */ + + ge25519_p3_dbl(&t2, p); + ge25519_p1p1_to_p3(&p2, &t2); + ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */ + + ge25519_add(&t3, p, &pi[2 - 1]); + ge25519_p1p1_to_p3(&p3, &t3); + ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */ + + ge25519_p3_dbl(&t4, &p2); + ge25519_p1p1_to_p3(&p4, &t4); + ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */ + + ge25519_add(&t5, p, &pi[4 - 1]); + ge25519_p1p1_to_p3(&p5, &t5); + ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */ + + ge25519_p3_dbl(&t6, &p3); + ge25519_p1p1_to_p3(&p6, &t6); + ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */ + + ge25519_add(&t7, p, &pi[6 - 1]); + ge25519_p1p1_to_p3(&p7, &t7); + ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */ + + ge25519_p3_dbl(&t8, &p4); + ge25519_p1p1_to_p3(&p8, &t8); + ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */ + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry * ((signed char) 1 << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge25519_p3_0(h); + + for (i = 63; i != 0; i--) { + ge25519_cmov8_cached(&t, pi, e[i]); + ge25519_add(&r, h, &t); + + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + + ge25519_p1p1_to_p3(h, &r); /* *16 */ + } + ge25519_cmov8_cached(&t, pi, e[i]); + ge25519_add(&r, h, &t); + + ge25519_p1p1_to_p3(h, &r); +} + +/* + h = a * B (with precomputation) + where a = a[0]+256*a[1]+...+256^31 a[31] + B is the Ed25519 base point (x,4/5) with x positive + (as bytes: 0x5866666666666666666666666666666666666666666666666666666666666666) + + Preconditions: + a[31] <= 127 + */ + +void +ge25519_scalarmult_base(ge25519_p3 *h, const unsigned char *a) +{ + signed char e[64]; + signed char carry; + ge25519_p1p1 r; + ge25519_p2 s; + ge25519_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry * ((signed char) 1 << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge25519_p3_0(h); + + for (i = 1; i < 64; i += 2) { + ge25519_cmov8_base(&t, i / 2, e[i]); + ge25519_madd(&r, h, &t); + ge25519_p1p1_to_p3(h, &r); + } + + ge25519_p3_dbl(&r, h); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + ge25519_cmov8_base(&t, i / 2, e[i]); + ge25519_madd(&r, h, &t); + ge25519_p1p1_to_p3(h, &r); + } +} + +/* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 */ +static void +ge25519_mul_l(ge25519_p3 *r, const ge25519_p3 *A) +{ + static const signed char aslide[253] = { + 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + ge25519_cached Ai[8]; + ge25519_p1p1 t; + ge25519_p3 u; + ge25519_p3 A2; + int i; + + ge25519_p3_to_cached(&Ai[0], A); + ge25519_p3_dbl(&t, A); + ge25519_p1p1_to_p3(&A2, &t); + ge25519_add(&t, &A2, &Ai[0]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[1], &u); + ge25519_add(&t, &A2, &Ai[1]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[2], &u); + ge25519_add(&t, &A2, &Ai[2]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[3], &u); + ge25519_add(&t, &A2, &Ai[3]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[4], &u); + ge25519_add(&t, &A2, &Ai[4]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[5], &u); + ge25519_add(&t, &A2, &Ai[5]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[6], &u); + ge25519_add(&t, &A2, &Ai[6]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[7], &u); + + ge25519_p3_0(r); + + for (i = 252; i >= 0; --i) { + ge25519_p3_dbl(&t, r); + + if (aslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + ge25519_p1p1_to_p3(r, &t); + } +} + +int +ge25519_is_on_curve(const ge25519_p3 *p) +{ + fe25519 x2; + fe25519 y2; + fe25519 z2; + fe25519 z4; + fe25519 t0; + fe25519 t1; + + fe25519_sq(x2, p->X); + fe25519_sq(y2, p->Y); + fe25519_sq(z2, p->Z); + fe25519_sub(t0, y2, x2); + fe25519_mul(t0, t0, z2); + + fe25519_mul(t1, x2, y2); + fe25519_mul(t1, t1, d); + fe25519_sq(z4, z2); + fe25519_add(t1, t1, z4); + fe25519_sub(t0, t0, t1); + + return fe25519_iszero(t0); +} + +int +ge25519_is_on_main_subgroup(const ge25519_p3 *p) +{ + ge25519_p3 pl; + + ge25519_mul_l(&pl, p); + + return fe25519_iszero(pl.X); +} + +int +ge25519_is_canonical(const unsigned char *s) +{ + unsigned char c; + unsigned char d; + unsigned int i; + + c = (s[31] & 0x7f) ^ 0x7f; + for (i = 30; i > 0; i--) { + c |= s[i] ^ 0xff; + } + c = (((unsigned int) c) - 1U) >> 8; + d = (0xed - 1U - (unsigned int) s[0]) >> 8; + + return 1 - (c & d & 1); +} + +int +ge25519_has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + /* 0 (order 4) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 1 (order 1) */ + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 + (order 8) */ + { 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, + 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, + 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 }, + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 + (order 8) */ + { 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, + 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, + 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a }, + /* p-1 (order 2) */ + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p (=0, order 4) */ + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p+1 (=1, order 1) */ + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } + }; + unsigned char c[7] = { 0 }; + unsigned int k; + size_t i, j; + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + + COMPILER_ASSERT(7 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 31; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= (s[j] & 0x7f) ^ blacklist[i][j]; + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +/* + Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab) mod l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +void +sc25519_mul(unsigned char s[32], const unsigned char a[32], const unsigned char b[32]) +{ + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = a0 * b0; + s1 = a0 * b1 + a1 * b0; + s2 = a0 * b2 + a1 * b1 + a2 * b0; + s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + + a6 * b1 + a7 * b0; + s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + + a6 * b2 + a7 * b1 + a8 * b0; + s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + + a10 * b5 + a11 * b4; + s16 = + a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + carry18 = (s18 + (int64_t) (1L << 20)) >> 21; + s19 += carry18; + s18 -= carry18 * ((uint64_t) 1L << 21); + carry20 = (s20 + (int64_t) (1L << 20)) >> 21; + s21 += carry20; + s20 -= carry20 * ((uint64_t) 1L << 21); + carry22 = (s22 + (int64_t) (1L << 20)) >> 21; + s23 += carry22; + s22 -= carry22 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + carry17 = (s17 + (int64_t) (1L << 20)) >> 21; + s18 += carry17; + s17 -= carry17 * ((uint64_t) 1L << 21); + carry19 = (s19 + (int64_t) (1L << 20)) >> 21; + s20 += carry19; + s19 -= carry19 * ((uint64_t) 1L << 21); + carry21 = (s21 + (int64_t) (1L << 20)) >> 21; + s22 += carry21; + s21 -= carry21 * ((uint64_t) 1L << 21); + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* + Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +void +sc25519_muladd(unsigned char s[32], const unsigned char a[32], + const unsigned char b[32], const unsigned char c[32]) +{ + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + + int64_t c0 = 2097151 & load_3(c); + int64_t c1 = 2097151 & (load_4(c + 2) >> 5); + int64_t c2 = 2097151 & (load_3(c + 5) >> 2); + int64_t c3 = 2097151 & (load_4(c + 7) >> 7); + int64_t c4 = 2097151 & (load_4(c + 10) >> 4); + int64_t c5 = 2097151 & (load_3(c + 13) >> 1); + int64_t c6 = 2097151 & (load_4(c + 15) >> 6); + int64_t c7 = 2097151 & (load_3(c + 18) >> 3); + int64_t c8 = 2097151 & load_3(c + 21); + int64_t c9 = 2097151 & (load_4(c + 23) >> 5); + int64_t c10 = 2097151 & (load_3(c + 26) >> 2); + int64_t c11 = (load_4(c + 28) >> 7); + + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + + a10 * b5 + a11 * b4; + s16 = + a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + carry18 = (s18 + (int64_t) (1L << 20)) >> 21; + s19 += carry18; + s18 -= carry18 * ((uint64_t) 1L << 21); + carry20 = (s20 + (int64_t) (1L << 20)) >> 21; + s21 += carry20; + s20 -= carry20 * ((uint64_t) 1L << 21); + carry22 = (s22 + (int64_t) (1L << 20)) >> 21; + s23 += carry22; + s22 -= carry22 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + carry17 = (s17 + (int64_t) (1L << 20)) >> 21; + s18 += carry17; + s17 -= carry17 * ((uint64_t) 1L << 21); + carry19 = (s19 + (int64_t) (1L << 20)) >> 21; + s20 += carry19; + s19 -= carry19 * ((uint64_t) 1L << 21); + carry21 = (s21 + (int64_t) (1L << 20)) >> 21; + s22 += carry21; + s21 -= carry21 * ((uint64_t) 1L << 21); + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* + Input: + a[0]+256*a[1]+...+256^31*a[31] = a + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = a^2 mod l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +static inline void +sc25519_sq(unsigned char *s, const unsigned char *a) +{ + sc25519_mul(s, a, a); +} + +/* + Input: + s[0]+256*a[1]+...+256^31*a[31] = a + n + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = x * s^(s^n) mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. + */ + +static inline void +sc25519_sqmul(unsigned char s[32], const int n, const unsigned char a[32]) +{ + int i; + + for (i = 0; i < n; i++) { + sc25519_sq(s, s); + } + sc25519_mul(s, s, a); +} + +void +sc25519_invert(unsigned char recip[32], const unsigned char s[32]) +{ + unsigned char _10[32], _100[32], _11[32], _101[32], _111[32], + _1001[32], _1011[32], _1111[32]; + + sc25519_sq(_10, s); + sc25519_sq(_100, _10); + sc25519_mul(_11, _10, s); + sc25519_mul(_101, _10, _11); + sc25519_mul(_111, _10, _101); + sc25519_mul(_1001, _10, _111); + sc25519_mul(_1011, _10, _1001); + sc25519_mul(_1111, _100, _1011); + sc25519_mul(recip, _1111, s); + + sc25519_sqmul(recip, 123 + 3, _101); + sc25519_sqmul(recip, 2 + 2, _11); + sc25519_sqmul(recip, 1 + 4, _1111); + sc25519_sqmul(recip, 1 + 4, _1111); + sc25519_sqmul(recip, 4, _1001); + sc25519_sqmul(recip, 2, _11); + sc25519_sqmul(recip, 1 + 4, _1111); + sc25519_sqmul(recip, 1 + 3, _101); + sc25519_sqmul(recip, 3 + 3, _101); + sc25519_sqmul(recip, 3, _111); + sc25519_sqmul(recip, 1 + 4, _1111); + sc25519_sqmul(recip, 2 + 3, _111); + sc25519_sqmul(recip, 2 + 2, _11); + sc25519_sqmul(recip, 1 + 4, _1011); + sc25519_sqmul(recip, 2 + 4, _1011); + sc25519_sqmul(recip, 6 + 4, _1001); + sc25519_sqmul(recip, 2 + 2, _11); + sc25519_sqmul(recip, 3 + 2, _11); + sc25519_sqmul(recip, 3 + 2, _11); + sc25519_sqmul(recip, 1 + 4, _1001); + sc25519_sqmul(recip, 1 + 3, _111); + sc25519_sqmul(recip, 2 + 4, _1111); + sc25519_sqmul(recip, 1 + 4, _1011); + sc25519_sqmul(recip, 3, _101); + sc25519_sqmul(recip, 2 + 4, _1111); + sc25519_sqmul(recip, 3, _101); + sc25519_sqmul(recip, 1 + 2, _11); +} + +/* + Input: + s[0]+256*s[1]+...+256^63*s[63] = s + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. + */ + +void +sc25519_reduce(unsigned char s[64]) +{ + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +int +sc25519_is_canonical(const unsigned char s[32]) +{ + /* 2^252+27742317777372353535851937790883648493 */ + static const unsigned char L[32] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + }; + unsigned char c = 0; + unsigned char n = 1; + unsigned int i = 32; + + do { + i--; + c |= ((s[i] - L[i]) >> 8) & n; + n &= ((s[i] ^ L[i]) - 1) >> 8; + } while (i != 0); + + return (c != 0); +} + +static void +chi25519(fe25519 out, const fe25519 z) +{ + fe25519 t0, t1, t2, t3; + int i; + + fe25519_sq(t0, z); + fe25519_mul(t1, t0, z); + fe25519_sq(t0, t1); + fe25519_sq(t2, t0); + fe25519_sq(t2, t2); + fe25519_mul(t2, t2, t0); + fe25519_mul(t1, t2, z); + fe25519_sq(t2, t1); + + for (i = 1; i < 5; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 10; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 20; i++) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 10; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 50; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 100; i++) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 50; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 4; i++) { + fe25519_sq(t1, t1); + } + fe25519_mul(out, t1, t0); +} + +static void +ge25519_elligator2(unsigned char s[32], const fe25519 r, const unsigned char x_sign) +{ + fe25519 e; + fe25519 negx; + fe25519 rr2; + fe25519 x, x2, x3; + ge25519_p3 p3; + ge25519_p1p1 p1; + ge25519_p2 p2; + unsigned int e_is_minus_1; + + fe25519_sq2(rr2, r); + rr2[0]++; + fe25519_invert(rr2, rr2); + fe25519_mul(x, curve25519_A, rr2); + fe25519_neg(x, x); + + fe25519_sq(x2, x); + fe25519_mul(x3, x, x2); + fe25519_add(e, x3, x); + fe25519_mul(x2, x2, curve25519_A); + fe25519_add(e, x2, e); + + chi25519(e, e); + + fe25519_tobytes(s, e); + e_is_minus_1 = s[1] & 1; + fe25519_neg(negx, x); + fe25519_cmov(x, negx, e_is_minus_1); + fe25519_0(x2); + fe25519_cmov(x2, curve25519_A, e_is_minus_1); + fe25519_sub(x, x, x2); + + /* yed = (x-1)/(x+1) */ + { + fe25519 one; + fe25519 x_plus_one; + fe25519 x_plus_one_inv; + fe25519 x_minus_one; + fe25519 yed; + + fe25519_1(one); + fe25519_add(x_plus_one, x, one); + fe25519_sub(x_minus_one, x, one); + fe25519_invert(x_plus_one_inv, x_plus_one); + fe25519_mul(yed, x_minus_one, x_plus_one_inv); + fe25519_tobytes(s, yed); + } + + /* recover x */ + s[31] |= x_sign; + if (ge25519_frombytes(&p3, s) != 0) { + abort(); /* LCOV_EXCL_LINE */ + } + + /* multiply by the cofactor */ + ge25519_p3_dbl(&p1, &p3); + ge25519_p1p1_to_p2(&p2, &p1); + ge25519_p2_dbl(&p1, &p2); + ge25519_p1p1_to_p2(&p2, &p1); + ge25519_p2_dbl(&p1, &p2); + ge25519_p1p1_to_p3(&p3, &p1); + + ge25519_p3_tobytes(s, &p3); +} + +void +ge25519_from_uniform(unsigned char s[32], const unsigned char r[32]) +{ + fe25519 r_fe; + unsigned char x_sign; + + memcpy(s, r, 32); + x_sign = s[31] & 0x80; + s[31] &= 0x7f; + fe25519_frombytes(r_fe, s); + ge25519_elligator2(s, r_fe, x_sign); +} + +void +ge25519_from_hash(unsigned char s[32], const unsigned char h[64]) +{ + unsigned char fl[32]; + unsigned char gl[32]; + fe25519 fe_f; + fe25519 fe_g; + size_t i; + unsigned char x_sign; + + x_sign = h[0] & 0x80; + for (i = 0; i < 32; i++) { + fl[i] = h[63 - i]; + gl[i] = h[31 - i]; + } + fl[31] &= 0x7f; + gl[31] &= 0x7f; + fe25519_frombytes(fe_f, fl); + fe25519_frombytes(fe_g, gl); + fe_f[0] += (h[32] >> 7) * 19; + for (i = 0; i < sizeof (fe25519) / sizeof fe_f[0]; i++) { + fe_f[i] += 38 * fe_g[i]; + } + fe25519_reduce(fe_f, fe_f); + ge25519_elligator2(s, fe_f, x_sign); +} + +/* Ristretto group */ + +static int +ristretto255_sqrt_ratio_m1(fe25519 x, const fe25519 u, const fe25519 v) +{ + fe25519 v3; + fe25519 vxx; + fe25519 m_root_check, p_root_check, f_root_check; + fe25519 x_sqrtm1; + int has_m_root, has_p_root, has_f_root; + + fe25519_sq(v3, v); + fe25519_mul(v3, v3, v); /* v3 = v^3 */ + fe25519_sq(x, v3); + fe25519_mul(x, x, v); + fe25519_mul(x, x, u); /* x = uv^7 */ + + fe25519_pow22523(x, x); /* x = (uv^7)^((q-5)/8) */ + fe25519_mul(x, x, v3); + fe25519_mul(x, x, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe25519_sq(vxx, x); + fe25519_mul(vxx, vxx, v); /* vx^2 */ + fe25519_sub(m_root_check, vxx, u); /* vx^2-u */ + fe25519_add(p_root_check, vxx, u); /* vx^2+u */ + fe25519_mul(f_root_check, u, sqrtm1); /* u*sqrt(-1) */ + fe25519_add(f_root_check, vxx, f_root_check); /* vx^2+u*sqrt(-1) */ + has_m_root = fe25519_iszero(m_root_check); + has_p_root = fe25519_iszero(p_root_check); + has_f_root = fe25519_iszero(f_root_check); + fe25519_mul(x_sqrtm1, x, sqrtm1); /* x*sqrt(-1) */ + + fe25519_cmov(x, x_sqrtm1, has_p_root | has_f_root); + fe25519_abs(x, x); + + return has_m_root | has_p_root; +} + +static int +ristretto255_is_canonical(const unsigned char *s) +{ + unsigned char c; + unsigned char d; + unsigned int i; + + c = (s[31] & 0x7f) ^ 0x7f; + for (i = 30; i > 0; i--) { + c |= s[i] ^ 0xff; + } + c = (((unsigned int) c) - 1U) >> 8; + d = (0xed - 1U - (unsigned int) s[0]) >> 8; + + return 1 - (((c & d) | s[0]) & 1); +} + +int +ristretto255_frombytes(ge25519_p3 *h, const unsigned char *s) +{ + fe25519 inv_sqrt; + fe25519 one; + fe25519 s_; + fe25519 ss; + fe25519 u1, u2; + fe25519 u1u1, u2u2; + fe25519 v; + fe25519 v_u2u2; + int was_square; + + if (ristretto255_is_canonical(s) == 0) { + return -1; + } + fe25519_frombytes(s_, s); + fe25519_sq(ss, s_); /* ss = s^2 */ + + fe25519_1(u1); + fe25519_sub(u1, u1, ss); /* u1 = 1-ss */ + fe25519_sq(u1u1, u1); /* u1u1 = u1^2 */ + + fe25519_1(u2); + fe25519_add(u2, u2, ss); /* u2 = 1+ss */ + fe25519_sq(u2u2, u2); /* u2u2 = u2^2 */ + + fe25519_mul(v, d, u1u1); /* v = d*u1^2 */ + fe25519_neg(v, v); /* v = -d*u1^2 */ + fe25519_sub(v, v, u2u2); /* v = -(d*u1^2)-u2^2 */ + + fe25519_mul(v_u2u2, v, u2u2); /* v_u2u2 = v*u2^2 */ + + fe25519_1(one); + was_square = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2); + fe25519_mul(h->X, inv_sqrt, u2); + fe25519_mul(h->Y, inv_sqrt, h->X); + fe25519_mul(h->Y, h->Y, v); + + fe25519_mul(h->X, h->X, s_); + fe25519_add(h->X, h->X, h->X); + fe25519_abs(h->X, h->X); + fe25519_mul(h->Y, u1, h->Y); + fe25519_1(h->Z); + fe25519_mul(h->T, h->X, h->Y); + + return - ((1 - was_square) | + fe25519_isnegative(h->T) | fe25519_iszero(h->Y)); +} + +void +ristretto255_p3_tobytes(unsigned char *s, const ge25519_p3 *h) +{ + fe25519 den1, den2; + fe25519 den_inv; + fe25519 eden; + fe25519 inv_sqrt; + fe25519 ix, iy; + fe25519 one; + fe25519 s_; + fe25519 t_z_inv; + fe25519 u1, u2; + fe25519 u1_u2u2; + fe25519 x_, y_; + fe25519 x_z_inv; + fe25519 z_inv; + fe25519 zmy; + int rotate; + + fe25519_add(u1, h->Z, h->Y); /* u1 = Z+Y */ + fe25519_sub(zmy, h->Z, h->Y); /* zmy = Z-Y */ + fe25519_mul(u1, u1, zmy); /* u1 = (Z+Y)*(Z-Y) */ + fe25519_mul(u2, h->X, h->Y); /* u2 = X*Y */ + + fe25519_sq(u1_u2u2, u2); /* u1_u2u2 = u2^2 */ + fe25519_mul(u1_u2u2, u1, u1_u2u2); /* u1_u2u2 = u1*u2^2 */ + + fe25519_1(one); + (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2); + fe25519_mul(den1, inv_sqrt, u1); /* den1 = inv_sqrt*u1 */ + fe25519_mul(den2, inv_sqrt, u2); /* den2 = inv_sqrt*u2 */ + fe25519_mul(z_inv, den1, den2); /* z_inv = den1*den2 */ + fe25519_mul(z_inv, z_inv, h->T); /* z_inv = den1*den2*T */ + + fe25519_mul(ix, h->X, sqrtm1); /* ix = X*sqrt(-1) */ + fe25519_mul(iy, h->Y, sqrtm1); /* iy = Y*sqrt(-1) */ + fe25519_mul(eden, den1, invsqrtamd); /* eden = den1*sqrt(a-d) */ + + fe25519_mul(t_z_inv, h->T, z_inv); /* t_z_inv = T*z_inv */ + rotate = fe25519_isnegative(t_z_inv); + + fe25519_copy(x_, h->X); + fe25519_copy(y_, h->Y); + fe25519_copy(den_inv, den2); + + fe25519_cmov(x_, iy, rotate); + fe25519_cmov(y_, ix, rotate); + fe25519_cmov(den_inv, eden, rotate); + + fe25519_mul(x_z_inv, x_, z_inv); + fe25519_cneg(y_, y_, fe25519_isnegative(x_z_inv)); + + fe25519_sub(s_, h->Z, y_); + fe25519_mul(s_, den_inv, s_); + fe25519_abs(s_, s_); + fe25519_tobytes(s, s_); +} + +static void +ristretto255_elligator(ge25519_p3 *p, const fe25519 t) +{ + fe25519 c; + fe25519 n; + fe25519 one; + fe25519 r; + fe25519 rpd; + fe25519 s, s_prime; + fe25519 ss; + fe25519 u, v; + fe25519 w0, w1, w2, w3; + int wasnt_square; + + fe25519_1(one); + fe25519_sq(r, t); /* r = t^2 */ + fe25519_mul(r, sqrtm1, r); /* r = sqrt(-1)*t^2 */ + fe25519_add(u, r, one); /* u = r+1 */ + fe25519_mul(u, u, onemsqd); /* u = (r+1)*(1-d^2) */ + fe25519_1(c); + fe25519_neg(c, c); /* c = -1 */ + fe25519_add(rpd, r, d); /* rpd = r*d */ + fe25519_mul(v, r, d); /* v = r*d */ + fe25519_sub(v, c, v); /* v = c-r*d */ + fe25519_mul(v, v, rpd); /* v = (c-r*d)*(r+d) */ + + wasnt_square = 1 - ristretto255_sqrt_ratio_m1(s, u, v); + fe25519_mul(s_prime, s, t); + fe25519_abs(s_prime, s_prime); + fe25519_neg(s_prime, s_prime); /* s_prime = -|s*t| */ + fe25519_cmov(s, s_prime, wasnt_square); + fe25519_cmov(c, r, wasnt_square); + + fe25519_sub(n, r, one); /* n = r-1 */ + fe25519_mul(n, n, c); /* n = c*(r-1) */ + fe25519_mul(n, n, sqdmone); /* n = c*(r-1)*(d-1)^2 */ + fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */ + + fe25519_add(w0, s, s); /* w0 = 2s */ + fe25519_mul(w0, w0, v); /* w0 = 2s*v */ + fe25519_mul(w1, n, sqrtadm1); /* w1 = n*sqrt(ad-1) */ + fe25519_sq(ss, s); /* ss = s^2 */ + fe25519_sub(w2, one, ss); /* w2 = 1-s^2 */ + fe25519_add(w3, one, ss); /* w3 = 1+s^2 */ + + fe25519_mul(p->X, w0, w3); + fe25519_mul(p->Y, w2, w1); + fe25519_mul(p->Z, w1, w3); + fe25519_mul(p->T, w0, w2); +} + +void +ristretto255_from_hash(unsigned char s[32], const unsigned char h[64]) +{ + fe25519 r0, r1; + ge25519_cached p1_cached; + ge25519_p1p1 p_p1p1; + ge25519_p3 p0, p1; + ge25519_p3 p; + + fe25519_frombytes(r0, h); + fe25519_frombytes(r1, h + 32); + ristretto255_elligator(&p0, r0); + ristretto255_elligator(&p1, r1); + ge25519_p3_to_cached(&p1_cached, &p1); + ge25519_add(&p_p1p1, &p0, &p1_cached); + ge25519_p1p1_to_p3(&p, &p_p1p1); + ristretto255_p3_tobytes(s, &p); +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.h b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.h new file mode 100644 index 0000000..634dd2b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10.h @@ -0,0 +1,174 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ed25519_ref10_H +#define ed25519_ref10_H + +#include +#include +#include + +/* + fe means field element. + Here the field is \Z/(2^255-19). + */ + +#ifdef HAVE_TI_MODE +typedef uint64_t fe25519[5]; +#else +typedef int32_t fe25519[10]; +#endif + +void fe25519_invert(fe25519 out, const fe25519 z); +void fe25519_frombytes(fe25519 h, const unsigned char *s); +void fe25519_tobytes(unsigned char *s, const fe25519 h); + +static inline int +sodium_is_zero(const unsigned char *n, const size_t nlen) +{ + size_t i; + volatile unsigned char d = 0U; + + for (i = 0U; i < nlen; i++) { + d |= n[i]; + } + return 1 & ((d - 1) >> 8); +} + +#ifdef HAVE_TI_MODE +# include "ed25519_ref10_fe_51.h" +#else +# include "ed25519_ref10_fe_25_5.h" +#endif + + +/* + ge means group element. + + Here the group is the set of pairs (x,y) of field elements + satisfying -x^2 + y^2 = 1 + d x^2y^2 + where d = -121665/121666. + + Representations: + ge25519_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge25519_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge25519_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge25519_precomp (Duif): (y+x,y-x,2dxy) + */ + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; +} ge25519_p2; + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; + fe25519 T; +} ge25519_p3; + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; + fe25519 T; +} ge25519_p1p1; + +typedef struct { + fe25519 yplusx; + fe25519 yminusx; + fe25519 xy2d; +} ge25519_precomp; + +typedef struct { + fe25519 YplusX; + fe25519 YminusX; + fe25519 Z; + fe25519 T2d; +} ge25519_cached; + +void ge25519_tobytes(unsigned char *s, const ge25519_p2 *h); + +void ge25519_p3_tobytes(unsigned char *s, const ge25519_p3 *h); + +int ge25519_frombytes(ge25519_p3 *h, const unsigned char *s); + +int ge25519_frombytes_negate_vartime(ge25519_p3 *h, const unsigned char *s); + +void ge25519_p3_to_cached(ge25519_cached *r, const ge25519_p3 *p); + +void ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p); + +void ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p); + +void ge25519_add(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q); + +void ge25519_sub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q); + +void ge25519_scalarmult_base(ge25519_p3 *h, const unsigned char *a); + +void ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, + const ge25519_p3 *A, + const unsigned char *b); + +void ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a, + const ge25519_p3 *p); + +int ge25519_is_canonical(const unsigned char *s); + +int ge25519_is_on_curve(const ge25519_p3 *p); + +int ge25519_is_on_main_subgroup(const ge25519_p3 *p); + +int ge25519_has_small_order(const unsigned char s[32]); + +void ge25519_from_uniform(unsigned char s[32], const unsigned char r[32]); + +void ge25519_from_hash(unsigned char s[32], const unsigned char h[64]); + +/* + Ristretto group + */ + +int ristretto255_frombytes(ge25519_p3 *h, const unsigned char *s); + +void ristretto255_p3_tobytes(unsigned char *s, const ge25519_p3 *h); + +void ristretto255_from_hash(unsigned char s[32], const unsigned char h[64]); + +/* + The set of scalars is \Z/l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +void sc25519_invert(unsigned char recip[32], const unsigned char s[32]); + +void sc25519_reduce(unsigned char s[64]); + +void sc25519_mul(unsigned char s[32], const unsigned char a[32], + const unsigned char b[32]); + +void sc25519_muladd(unsigned char s[32], const unsigned char a[32], + const unsigned char b[32], const unsigned char c[32]); + +int sc25519_is_canonical(const unsigned char s[32]); + +#endif diff --git a/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_25_5.h b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_25_5.h new file mode 100644 index 0000000..169b581 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_25_5.h @@ -0,0 +1,1067 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +/* + h = 0 + */ + +static inline void +fe25519_0(fe25519 h) +{ + memset(&h[0], 0, 10 * sizeof h[0]); +} + +/* + h = 1 + */ + +static inline void +fe25519_1(fe25519 h) +{ + h[0] = 1; + h[1] = 0; + memset(&h[2], 0, 8 * sizeof h[0]); +} + +/* + h = f + g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline void +fe25519_add(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t h0 = f[0] + g[0]; + int32_t h1 = f[1] + g[1]; + int32_t h2 = f[2] + g[2]; + int32_t h3 = f[3] + g[3]; + int32_t h4 = f[4] + g[4]; + int32_t h5 = f[5] + g[5]; + int32_t h6 = f[6] + g[6]; + int32_t h7 = f[7] + g[7]; + int32_t h8 = f[8] + g[8]; + int32_t h9 = f[9] + g[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + h = f - g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static void +fe25519_sub(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t h0 = f[0] - g[0]; + int32_t h1 = f[1] - g[1]; + int32_t h2 = f[2] - g[2]; + int32_t h3 = f[3] - g[3]; + int32_t h4 = f[4] - g[4]; + int32_t h5 = f[5] - g[5]; + int32_t h6 = f[6] - g[6]; + int32_t h7 = f[7] - g[7]; + int32_t h8 = f[8] - g[8]; + int32_t h9 = f[9] - g[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + h = -f + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + +static inline void +fe25519_neg(fe25519 h, const fe25519 f) +{ + int32_t h0 = -f[0]; + int32_t h1 = -f[1]; + int32_t h2 = -f[2]; + int32_t h3 = -f[3]; + int32_t h4 = -f[4]; + int32_t h5 = -f[5]; + int32_t h6 = -f[6]; + int32_t h7 = -f[7]; + int32_t h8 = -f[8]; + int32_t h9 = -f[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + * + Preconditions: b in {0,1}. + */ + +static void +fe25519_cmov(fe25519 f, const fe25519 g, unsigned int b) +{ + const uint32_t mask = (uint32_t) (-(int32_t) b); + + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t x0 = f0 ^ g[0]; + int32_t x1 = f1 ^ g[1]; + int32_t x2 = f2 ^ g[2]; + int32_t x3 = f3 ^ g[3]; + int32_t x4 = f4 ^ g[4]; + int32_t x5 = f5 ^ g[5]; + int32_t x6 = f6 ^ g[6]; + int32_t x7 = f7 ^ g[7]; + int32_t x8 = f8 ^ g[8]; + int32_t x9 = f9 ^ g[9]; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + x5 &= mask; + x6 &= mask; + x7 &= mask; + x8 &= mask; + x9 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; +} + +static void +fe25519_cswap(fe25519 f, fe25519 g, unsigned int b) +{ + const uint32_t mask = (uint32_t) (-(int64_t) b); + + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + x5 &= mask; + x6 &= mask; + x7 &= mask; + x8 &= mask; + x9 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; + + g[0] = g0 ^ x0; + g[1] = g1 ^ x1; + g[2] = g2 ^ x2; + g[3] = g3 ^ x3; + g[4] = g4 ^ x4; + g[5] = g5 ^ x5; + g[6] = g6 ^ x6; + g[7] = g7 ^ x7; + g[8] = g8 ^ x8; + g[9] = g9 ^ x9; +} + +/* + h = f + */ + +static inline void +fe25519_copy(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; + h[5] = f5; + h[6] = f6; + h[7] = f7; + h[8] = f8; + h[9] = f9; +} + +/* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline int +fe25519_isnegative(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return s[0] & 1; +} + +/* + return 1 if f == 0 + return 0 if f != 0 + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline int +fe25519_iszero(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return sodium_is_zero(s, 32); +} + +/* + h = f * g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +/* + Notes on implementation strategy: + * + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + * + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + * + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + * + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + * + With tighter constraints on inputs can squeeze carries into int32. + */ + +static void +fe25519_mul(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + + int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int32_t g3_19 = 19 * g3; + int32_t g4_19 = 19 * g4; + int32_t g5_19 = 19 * g5; + int32_t g6_19 = 19 * g6; + int32_t g7_19 = 19 * g7; + int32_t g8_19 = 19 * g8; + int32_t g9_19 = 19 * g9; + int32_t f1_2 = 2 * f1; + int32_t f3_2 = 2 * f3; + int32_t f5_2 = 2 * f5; + int32_t f7_2 = 2 * f7; + int32_t f9_2 = 2 * f9; + + int64_t f0g0 = f0 * (int64_t) g0; + int64_t f0g1 = f0 * (int64_t) g1; + int64_t f0g2 = f0 * (int64_t) g2; + int64_t f0g3 = f0 * (int64_t) g3; + int64_t f0g4 = f0 * (int64_t) g4; + int64_t f0g5 = f0 * (int64_t) g5; + int64_t f0g6 = f0 * (int64_t) g6; + int64_t f0g7 = f0 * (int64_t) g7; + int64_t f0g8 = f0 * (int64_t) g8; + int64_t f0g9 = f0 * (int64_t) g9; + int64_t f1g0 = f1 * (int64_t) g0; + int64_t f1g1_2 = f1_2 * (int64_t) g1; + int64_t f1g2 = f1 * (int64_t) g2; + int64_t f1g3_2 = f1_2 * (int64_t) g3; + int64_t f1g4 = f1 * (int64_t) g4; + int64_t f1g5_2 = f1_2 * (int64_t) g5; + int64_t f1g6 = f1 * (int64_t) g6; + int64_t f1g7_2 = f1_2 * (int64_t) g7; + int64_t f1g8 = f1 * (int64_t) g8; + int64_t f1g9_38 = f1_2 * (int64_t) g9_19; + int64_t f2g0 = f2 * (int64_t) g0; + int64_t f2g1 = f2 * (int64_t) g1; + int64_t f2g2 = f2 * (int64_t) g2; + int64_t f2g3 = f2 * (int64_t) g3; + int64_t f2g4 = f2 * (int64_t) g4; + int64_t f2g5 = f2 * (int64_t) g5; + int64_t f2g6 = f2 * (int64_t) g6; + int64_t f2g7 = f2 * (int64_t) g7; + int64_t f2g8_19 = f2 * (int64_t) g8_19; + int64_t f2g9_19 = f2 * (int64_t) g9_19; + int64_t f3g0 = f3 * (int64_t) g0; + int64_t f3g1_2 = f3_2 * (int64_t) g1; + int64_t f3g2 = f3 * (int64_t) g2; + int64_t f3g3_2 = f3_2 * (int64_t) g3; + int64_t f3g4 = f3 * (int64_t) g4; + int64_t f3g5_2 = f3_2 * (int64_t) g5; + int64_t f3g6 = f3 * (int64_t) g6; + int64_t f3g7_38 = f3_2 * (int64_t) g7_19; + int64_t f3g8_19 = f3 * (int64_t) g8_19; + int64_t f3g9_38 = f3_2 * (int64_t) g9_19; + int64_t f4g0 = f4 * (int64_t) g0; + int64_t f4g1 = f4 * (int64_t) g1; + int64_t f4g2 = f4 * (int64_t) g2; + int64_t f4g3 = f4 * (int64_t) g3; + int64_t f4g4 = f4 * (int64_t) g4; + int64_t f4g5 = f4 * (int64_t) g5; + int64_t f4g6_19 = f4 * (int64_t) g6_19; + int64_t f4g7_19 = f4 * (int64_t) g7_19; + int64_t f4g8_19 = f4 * (int64_t) g8_19; + int64_t f4g9_19 = f4 * (int64_t) g9_19; + int64_t f5g0 = f5 * (int64_t) g0; + int64_t f5g1_2 = f5_2 * (int64_t) g1; + int64_t f5g2 = f5 * (int64_t) g2; + int64_t f5g3_2 = f5_2 * (int64_t) g3; + int64_t f5g4 = f5 * (int64_t) g4; + int64_t f5g5_38 = f5_2 * (int64_t) g5_19; + int64_t f5g6_19 = f5 * (int64_t) g6_19; + int64_t f5g7_38 = f5_2 * (int64_t) g7_19; + int64_t f5g8_19 = f5 * (int64_t) g8_19; + int64_t f5g9_38 = f5_2 * (int64_t) g9_19; + int64_t f6g0 = f6 * (int64_t) g0; + int64_t f6g1 = f6 * (int64_t) g1; + int64_t f6g2 = f6 * (int64_t) g2; + int64_t f6g3 = f6 * (int64_t) g3; + int64_t f6g4_19 = f6 * (int64_t) g4_19; + int64_t f6g5_19 = f6 * (int64_t) g5_19; + int64_t f6g6_19 = f6 * (int64_t) g6_19; + int64_t f6g7_19 = f6 * (int64_t) g7_19; + int64_t f6g8_19 = f6 * (int64_t) g8_19; + int64_t f6g9_19 = f6 * (int64_t) g9_19; + int64_t f7g0 = f7 * (int64_t) g0; + int64_t f7g1_2 = f7_2 * (int64_t) g1; + int64_t f7g2 = f7 * (int64_t) g2; + int64_t f7g3_38 = f7_2 * (int64_t) g3_19; + int64_t f7g4_19 = f7 * (int64_t) g4_19; + int64_t f7g5_38 = f7_2 * (int64_t) g5_19; + int64_t f7g6_19 = f7 * (int64_t) g6_19; + int64_t f7g7_38 = f7_2 * (int64_t) g7_19; + int64_t f7g8_19 = f7 * (int64_t) g8_19; + int64_t f7g9_38 = f7_2 * (int64_t) g9_19; + int64_t f8g0 = f8 * (int64_t) g0; + int64_t f8g1 = f8 * (int64_t) g1; + int64_t f8g2_19 = f8 * (int64_t) g2_19; + int64_t f8g3_19 = f8 * (int64_t) g3_19; + int64_t f8g4_19 = f8 * (int64_t) g4_19; + int64_t f8g5_19 = f8 * (int64_t) g5_19; + int64_t f8g6_19 = f8 * (int64_t) g6_19; + int64_t f8g7_19 = f8 * (int64_t) g7_19; + int64_t f8g8_19 = f8 * (int64_t) g8_19; + int64_t f8g9_19 = f8 * (int64_t) g9_19; + int64_t f9g0 = f9 * (int64_t) g0; + int64_t f9g1_38 = f9_2 * (int64_t) g1_19; + int64_t f9g2_19 = f9 * (int64_t) g2_19; + int64_t f9g3_38 = f9_2 * (int64_t) g3_19; + int64_t f9g4_19 = f9 * (int64_t) g4_19; + int64_t f9g5_38 = f9_2 * (int64_t) g5_19; + int64_t f9g6_19 = f9 * (int64_t) g6_19; + int64_t f9g7_38 = f9_2 * (int64_t) g7_19; + int64_t f9g8_19 = f9 * (int64_t) g8_19; + int64_t f9g9_38 = f9_2 * (int64_t) g9_19; + + int64_t h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + int64_t h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + + f7g4_19 + f8g3_19 + f9g2_19; + int64_t h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + + f7g5_38 + f8g4_19 + f9g3_38; + int64_t h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + + f7g6_19 + f8g5_19 + f9g4_19; + int64_t h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + + f7g7_38 + f8g6_19 + f9g5_38; + int64_t h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + + f8g7_19 + f9g6_19; + int64_t h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + + f7g9_38 + f8g8_19 + f9g7_38; + int64_t h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + + f8g9_19 + f9g8_19; + int64_t h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + + f8g0 + f9g9_38; + int64_t h9 = + f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + h = f * f + Can overlap h with f. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +static void +fe25519_sq(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + h = 2 * f * f + Can overlap h with f. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +static void +fe25519_sq2(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +static void +fe25519_scalar_product(fe25519 h, const fe25519 f, uint32_t n) +{ + int64_t sn = (int64_t) n; + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int64_t h0 = f0 * sn; + int64_t h1 = f1 * sn; + int64_t h2 = f2 * sn; + int64_t h3 = f3 * sn; + int64_t h4 = f4 * sn; + int64_t h5 = f5 * sn; + int64_t h6 = f6 * sn; + int64_t h7 = f7 * sn; + int64_t h8 = f8 * sn; + int64_t h9 = f9 * sn; + int64_t carry0, carry1, carry2, carry3, carry4, carry5, carry6, carry7, + carry8, carry9; + + carry9 = (h9 + ((int64_t) 1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((int64_t) 1 << 25); + carry1 = (h1 + ((int64_t) 1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((int64_t) 1 << 25); + carry3 = (h3 + ((int64_t) 1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((int64_t) 1 << 25); + carry5 = (h5 + ((int64_t) 1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((int64_t) 1 << 25); + carry7 = (h7 + ((int64_t) 1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((int64_t) 1 << 25); + + carry0 = (h0 + ((int64_t) 1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((int64_t) 1 << 26); + carry2 = (h2 + ((int64_t) 1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((int64_t) 1 << 26); + carry4 = (h4 + ((int64_t) 1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((int64_t) 1 << 26); + carry6 = (h6 + ((int64_t) 1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((int64_t) 1 << 26); + carry8 = (h8 + ((int64_t) 1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((int64_t) 1 << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_51.h b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_51.h new file mode 100644 index 0000000..cd8776d --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/ed25519_ref10_fe_51.h @@ -0,0 +1,539 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "private/common.h" +#include "private/quirks.h" +#include "utils.h" + +/* + h = 0 + */ + +static inline void +fe25519_0(fe25519 h) +{ + memset(&h[0], 0, 5 * sizeof h[0]); +} + +/* + h = 1 + */ + +static inline void +fe25519_1(fe25519 h) +{ + h[0] = 1; + memset(&h[1], 0, 4 * sizeof h[0]); +} + +/* + h = f + g + Can overlap h with f or g. + */ + +static inline void +fe25519_add(fe25519 h, const fe25519 f, const fe25519 g) +{ + uint64_t h0 = f[0] + g[0]; + uint64_t h1 = f[1] + g[1]; + uint64_t h2 = f[2] + g[2]; + uint64_t h3 = f[3] + g[3]; + uint64_t h4 = f[4] + g[4]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +/* + h = f - g + */ + +static void +fe25519_sub(fe25519 h, const fe25519 f, const fe25519 g) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint64_t h0, h1, h2, h3, h4; + + h0 = g[0]; + h1 = g[1]; + h2 = g[2]; + h3 = g[3]; + h4 = g[4]; + + h1 += h0 >> 51; + h0 &= mask; + h2 += h1 >> 51; + h1 &= mask; + h3 += h2 >> 51; + h2 &= mask; + h4 += h3 >> 51; + h3 &= mask; + h0 += 19ULL * (h4 >> 51); + h4 &= mask; + + h0 = (f[0] + 0xfffffffffffdaULL) - h0; + h1 = (f[1] + 0xffffffffffffeULL) - h1; + h2 = (f[2] + 0xffffffffffffeULL) - h2; + h3 = (f[3] + 0xffffffffffffeULL) - h3; + h4 = (f[4] + 0xffffffffffffeULL) - h4; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +/* + h = -f + */ + +static inline void +fe25519_neg(fe25519 h, const fe25519 f) +{ + fe25519 zero; + + fe25519_0(zero); + fe25519_sub(h, zero, f); +} + +/* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + * + Preconditions: b in {0,1}. + */ + +static void +fe25519_cmov(fe25519 f, const fe25519 g, unsigned int b) +{ + const uint64_t mask = (uint64_t) (-(int64_t) b); + + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + uint64_t x0 = f0 ^ g[0]; + uint64_t x1 = f1 ^ g[1]; + uint64_t x2 = f2 ^ g[2]; + uint64_t x3 = f3 ^ g[3]; + uint64_t x4 = f4 ^ g[4]; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; +} + +/* +Replace (f,g) with (g,f) if b == 1; +replace (f,g) with (f,g) if b == 0. + +Preconditions: b in {0,1}. +*/ + +static void +fe25519_cswap(fe25519 f, fe25519 g, unsigned int b) +{ + const uint64_t mask = (uint64_t) (-(int64_t) b); + + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + uint64_t g0 = g[0]; + uint64_t g1 = g[1]; + uint64_t g2 = g[2]; + uint64_t g3 = g[3]; + uint64_t g4 = g[4]; + + uint64_t x0 = f0 ^ g0; + uint64_t x1 = f1 ^ g1; + uint64_t x2 = f2 ^ g2; + uint64_t x3 = f3 ^ g3; + uint64_t x4 = f4 ^ g4; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + + g[0] = g0 ^ x0; + g[1] = g1 ^ x1; + g[2] = g2 ^ x2; + g[3] = g3 ^ x3; + g[4] = g4 ^ x4; +} + +/* + h = f + */ + +static inline void +fe25519_copy(fe25519 h, const fe25519 f) +{ + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; +} + +/* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + */ + +static inline int +fe25519_isnegative(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return s[0] & 1; +} + +/* + return 1 if f == 0 + return 0 if f != 0 + */ + +static inline int +fe25519_iszero(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return sodium_is_zero(s, 32); +} + +/* + h = f * g + Can overlap h with f or g. + */ + +static void +fe25519_mul(fe25519 h, const fe25519 f, const fe25519 g) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f1_19, f2_19, f3_19, f4_19; + uint64_t g0, g1, g2, g3, g4; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + g0 = g[0]; + g1 = g[1]; + g2 = g[2]; + g3 = g[3]; + g4 = g[4]; + + f1_19 = 19ULL * f1; + f2_19 = 19ULL * f2; + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) g0); + r0 += ((uint128_t) f1_19) * ((uint128_t) g4); + r0 += ((uint128_t) f2_19) * ((uint128_t) g3); + r0 += ((uint128_t) f3_19) * ((uint128_t) g2); + r0 += ((uint128_t) f4_19) * ((uint128_t) g1); + + r1 = ((uint128_t) f0 ) * ((uint128_t) g1); + r1 += ((uint128_t) f1 ) * ((uint128_t) g0); + r1 += ((uint128_t) f2_19) * ((uint128_t) g4); + r1 += ((uint128_t) f3_19) * ((uint128_t) g3); + r1 += ((uint128_t) f4_19) * ((uint128_t) g2); + + r2 = ((uint128_t) f0 ) * ((uint128_t) g2); + r2 += ((uint128_t) f1 ) * ((uint128_t) g1); + r2 += ((uint128_t) f2 ) * ((uint128_t) g0); + r2 += ((uint128_t) f3_19) * ((uint128_t) g4); + r2 += ((uint128_t) f4_19) * ((uint128_t) g3); + + r3 = ((uint128_t) f0 ) * ((uint128_t) g3); + r3 += ((uint128_t) f1 ) * ((uint128_t) g2); + r3 += ((uint128_t) f2 ) * ((uint128_t) g1); + r3 += ((uint128_t) f3 ) * ((uint128_t) g0); + r3 += ((uint128_t) f4_19) * ((uint128_t) g4); + + r4 = ((uint128_t) f0 ) * ((uint128_t) g4); + r4 += ((uint128_t) f1 ) * ((uint128_t) g3); + r4 += ((uint128_t) f2 ) * ((uint128_t) g2); + r4 += ((uint128_t) f3 ) * ((uint128_t) g1); + r4 += ((uint128_t) f4 ) * ((uint128_t) g0); + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +/* + h = f * f + Can overlap h with f. + */ + +static void +fe25519_sq(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f0_2, f1_2, f1_38, f2_38, f3_38, f3_19, f4_19; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + f0_2 = f0 << 1; + f1_2 = f1 << 1; + + f1_38 = 38ULL * f1; + f2_38 = 38ULL * f2; + f3_38 = 38ULL * f3; + + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) f0); + r0 += ((uint128_t) f1_38) * ((uint128_t) f4); + r0 += ((uint128_t) f2_38) * ((uint128_t) f3); + + r1 = ((uint128_t) f0_2 ) * ((uint128_t) f1); + r1 += ((uint128_t) f2_38) * ((uint128_t) f4); + r1 += ((uint128_t) f3_19) * ((uint128_t) f3); + + r2 = ((uint128_t) f0_2 ) * ((uint128_t) f2); + r2 += ((uint128_t) f1 ) * ((uint128_t) f1); + r2 += ((uint128_t) f3_38) * ((uint128_t) f4); + + r3 = ((uint128_t) f0_2 ) * ((uint128_t) f3); + r3 += ((uint128_t) f1_2 ) * ((uint128_t) f2); + r3 += ((uint128_t) f4_19) * ((uint128_t) f4); + + r4 = ((uint128_t) f0_2 ) * ((uint128_t) f4); + r4 += ((uint128_t) f1_2 ) * ((uint128_t) f3); + r4 += ((uint128_t) f2 ) * ((uint128_t) f2); + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +/* + h = 2 * f * f + Can overlap h with f. +*/ + +static void +fe25519_sq2(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f0_2, f1_2, f1_38, f2_38, f3_38, f3_19, f4_19; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + f0_2 = f0 << 1; + f1_2 = f1 << 1; + + f1_38 = 38ULL * f1; + f2_38 = 38ULL * f2; + f3_38 = 38ULL * f3; + + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) f0); + r0 += ((uint128_t) f1_38) * ((uint128_t) f4); + r0 += ((uint128_t) f2_38) * ((uint128_t) f3); + + r1 = ((uint128_t) f0_2 ) * ((uint128_t) f1); + r1 += ((uint128_t) f2_38) * ((uint128_t) f4); + r1 += ((uint128_t) f3_19) * ((uint128_t) f3); + + r2 = ((uint128_t) f0_2 ) * ((uint128_t) f2); + r2 += ((uint128_t) f1 ) * ((uint128_t) f1); + r2 += ((uint128_t) f3_38) * ((uint128_t) f4); + + r3 = ((uint128_t) f0_2 ) * ((uint128_t) f3); + r3 += ((uint128_t) f1_2 ) * ((uint128_t) f2); + r3 += ((uint128_t) f4_19) * ((uint128_t) f4); + + r4 = ((uint128_t) f0_2 ) * ((uint128_t) f4); + r4 += ((uint128_t) f1_2 ) * ((uint128_t) f3); + r4 += ((uint128_t) f2 ) * ((uint128_t) f2); + + r0 <<= 1; + r1 <<= 1; + r2 <<= 1; + r3 <<= 1; + r4 <<= 1; + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +static void +fe25519_scalar_product(fe25519 h, const fe25519 f, uint32_t n) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t a; + uint128_t sn = (uint128_t) n; + uint64_t h0, h1, h2, h3, h4; + + a = f[0] * sn; + h0 = ((uint64_t) a) & mask; + a = f[1] * sn + ((uint64_t) (a >> 51)); + h1 = ((uint64_t) a) & mask; + a = f[2] * sn + ((uint64_t) (a >> 51)); + h2 = ((uint64_t) a) & mask; + a = f[3] * sn + ((uint64_t) (a >> 51)); + h3 = ((uint64_t) a) & mask; + a = f[4] * sn + ((uint64_t) (a >> 51)); + h4 = ((uint64_t) a) & mask; + + h0 += (a >> 51) * 19ULL; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base.h b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base.h new file mode 100644 index 0000000..e18530b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base.h @@ -0,0 +1,1344 @@ +{ /* 0/31 */ + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 } + }, + { + { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 }, + { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 }, + { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 } + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 } + }, + { + { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 }, + { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 }, + { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 } + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 } + }, + { + { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 }, + { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 }, + { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 } + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 } + }, + { + { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 }, + { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 }, + { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 } + } +}, +{ /* 1/31 */ + { + { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 }, + { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 }, + { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 } + }, + { + { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 }, + { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 }, + { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 } + }, + { + { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 }, + { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 }, + { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 } + }, + { + { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 }, + { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 }, + { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 } + }, + { + { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 }, + { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 }, + { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 } + }, + { + { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 }, + { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 }, + { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 } + }, + { + { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 }, + { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 }, + { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 } + }, + { + { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 }, + { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 }, + { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 } + } +}, +{ /* 2/31 */ + { + { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 }, + { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 }, + { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 } + }, + { + { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 }, + { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 }, + { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 } + }, + { + { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 }, + { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 }, + { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 } + }, + { + { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 }, + { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 }, + { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 } + }, + { + { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 }, + { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 }, + { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 } + }, + { + { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 }, + { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 }, + { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 } + }, + { + { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 }, + { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 }, + { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 } + }, + { + { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 }, + { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 }, + { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 } + } +}, +{ /* 3/31 */ + { + { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 }, + { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 }, + { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 } + }, + { + { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 }, + { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 }, + { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 } + }, + { + { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 }, + { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 }, + { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 } + }, + { + { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 }, + { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 }, + { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 } + }, + { + { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 }, + { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 }, + { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 } + }, + { + { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 }, + { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 }, + { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 } + }, + { + { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 }, + { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 }, + { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 } + }, + { + { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 }, + { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 }, + { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 } + } +}, +{ /* 4/31 */ + { + { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 }, + { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 }, + { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 } + }, + { + { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 }, + { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 }, + { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 } + }, + { + { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 }, + { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 }, + { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 } + }, + { + { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 }, + { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 }, + { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 } + }, + { + { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 }, + { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 }, + { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 } + }, + { + { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 }, + { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 }, + { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 } + }, + { + { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 }, + { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 }, + { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 } + }, + { + { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 }, + { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 }, + { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 } + } +}, +{ /* 5/31 */ + { + { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 }, + { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 }, + { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 } + }, + { + { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 }, + { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 }, + { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 } + }, + { + { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 }, + { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 }, + { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 } + }, + { + { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 }, + { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 }, + { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 } + }, + { + { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 }, + { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 }, + { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 } + }, + { + { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 }, + { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 }, + { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 } + }, + { + { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 }, + { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 }, + { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 } + }, + { + { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 }, + { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 }, + { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 } + } +}, +{ /* 6/31 */ + { + { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 }, + { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 }, + { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 } + }, + { + { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 }, + { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 }, + { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 } + }, + { + { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 }, + { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 }, + { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 } + }, + { + { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 }, + { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 }, + { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 } + }, + { + { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 }, + { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 }, + { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 } + }, + { + { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 }, + { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 }, + { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 } + }, + { + { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 }, + { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 }, + { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 } + }, + { + { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 }, + { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 }, + { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 } + } +}, +{ /* 7/31 */ + { + { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 }, + { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 }, + { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 } + }, + { + { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 }, + { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 }, + { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 } + }, + { + { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 }, + { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 }, + { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 } + }, + { + { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 }, + { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 }, + { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 } + }, + { + { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 }, + { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 }, + { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 } + }, + { + { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 }, + { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 }, + { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 } + }, + { + { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 }, + { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 }, + { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 } + }, + { + { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 }, + { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 }, + { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 } + } +}, +{ /* 8/31 */ + { + { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 }, + { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 }, + { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 } + }, + { + { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 }, + { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 }, + { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 } + }, + { + { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 }, + { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 }, + { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 } + }, + { + { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 }, + { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 }, + { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 } + }, + { + { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 }, + { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 }, + { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 } + }, + { + { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 }, + { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 }, + { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 } + }, + { + { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 }, + { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 }, + { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 } + }, + { + { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 }, + { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 }, + { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 } + } +}, +{ /* 9/31 */ + { + { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 }, + { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 }, + { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 } + }, + { + { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 }, + { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 }, + { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 } + }, + { + { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 }, + { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 }, + { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 } + }, + { + { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 }, + { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 }, + { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 } + }, + { + { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 }, + { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 }, + { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 } + }, + { + { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 }, + { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 }, + { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 } + }, + { + { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 }, + { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 }, + { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 } + }, + { + { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 }, + { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 }, + { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 } + } +}, +{ /* 10/31 */ + { + { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 }, + { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 }, + { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 } + }, + { + { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 }, + { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 }, + { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 } + }, + { + { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 }, + { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 }, + { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 } + }, + { + { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 }, + { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 }, + { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 } + }, + { + { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 }, + { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 }, + { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 } + }, + { + { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 }, + { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 }, + { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 } + }, + { + { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 }, + { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 }, + { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 } + }, + { + { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 }, + { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 }, + { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 } + } +}, +{ /* 11/31 */ + { + { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 }, + { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 }, + { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 } + }, + { + { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 }, + { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 }, + { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 } + }, + { + { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 }, + { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 }, + { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 } + }, + { + { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 }, + { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 }, + { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 } + }, + { + { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 }, + { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 }, + { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 } + }, + { + { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 }, + { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 }, + { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 } + }, + { + { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 }, + { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 }, + { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 } + }, + { + { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 }, + { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 }, + { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 } + } +}, +{ /* 12/31 */ + { + { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 }, + { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 }, + { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 } + }, + { + { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 }, + { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 }, + { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 } + }, + { + { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 }, + { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 }, + { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 } + }, + { + { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 }, + { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 }, + { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 } + }, + { + { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 }, + { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 }, + { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 } + }, + { + { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 }, + { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 }, + { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 } + }, + { + { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 }, + { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 }, + { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 } + }, + { + { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 }, + { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 }, + { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 } + } +}, +{ /* 13/31 */ + { + { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 }, + { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 }, + { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 } + }, + { + { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 }, + { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 }, + { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 } + }, + { + { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 }, + { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 }, + { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 } + }, + { + { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 }, + { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 }, + { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 } + }, + { + { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 }, + { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 }, + { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 } + }, + { + { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 }, + { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 }, + { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 } + }, + { + { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 }, + { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 }, + { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 } + }, + { + { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 }, + { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 }, + { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 } + } +}, +{ /* 14/31 */ + { + { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 }, + { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 }, + { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 } + }, + { + { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 }, + { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 }, + { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 } + }, + { + { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 }, + { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 }, + { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 } + }, + { + { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 }, + { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 }, + { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 } + }, + { + { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 }, + { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 }, + { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 } + }, + { + { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 }, + { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 }, + { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 } + }, + { + { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 }, + { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 }, + { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 } + }, + { + { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 }, + { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 }, + { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 } + } +}, +{ /* 15/31 */ + { + { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 }, + { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 }, + { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 } + }, + { + { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 }, + { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 }, + { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 } + }, + { + { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 }, + { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 }, + { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 } + }, + { + { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 }, + { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 }, + { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 } + }, + { + { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 }, + { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 }, + { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 } + }, + { + { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 }, + { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 }, + { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 } + }, + { + { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 }, + { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 }, + { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 } + }, + { + { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 }, + { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 }, + { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 } + } +}, +{ /* 16/31 */ + { + { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 }, + { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 }, + { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 } + }, + { + { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 }, + { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 }, + { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 } + }, + { + { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 }, + { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 }, + { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 } + }, + { + { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 }, + { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 }, + { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 } + }, + { + { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 }, + { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 }, + { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 } + }, + { + { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 }, + { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 }, + { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 } + }, + { + { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 }, + { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 }, + { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 } + }, + { + { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 }, + { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 }, + { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 } + } +}, +{ /* 17/31 */ + { + { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 }, + { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 }, + { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 } + }, + { + { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 }, + { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 }, + { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 } + }, + { + { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 }, + { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 }, + { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 } + }, + { + { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 }, + { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 }, + { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 } + }, + { + { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 }, + { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 }, + { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 } + }, + { + { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 }, + { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 }, + { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 } + }, + { + { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 }, + { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 }, + { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 } + }, + { + { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 }, + { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 }, + { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 } + } +}, +{ /* 18/31 */ + { + { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 }, + { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 }, + { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 } + }, + { + { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 }, + { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 }, + { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 } + }, + { + { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 }, + { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 }, + { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 } + }, + { + { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 }, + { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 }, + { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 } + }, + { + { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 }, + { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 }, + { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 } + }, + { + { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 }, + { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 }, + { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 } + }, + { + { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 }, + { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 }, + { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 } + }, + { + { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 }, + { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 }, + { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 } + } +}, +{ /* 19/31 */ + { + { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 }, + { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 }, + { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 } + }, + { + { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 }, + { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 }, + { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 } + }, + { + { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 }, + { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 }, + { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 } + }, + { + { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 }, + { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 }, + { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 } + }, + { + { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 }, + { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 }, + { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 } + }, + { + { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 }, + { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 }, + { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 } + }, + { + { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 }, + { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 }, + { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 } + }, + { + { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 }, + { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 }, + { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 } + } +}, +{ /* 20/31 */ + { + { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 }, + { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 }, + { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 } + }, + { + { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 }, + { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 }, + { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 } + }, + { + { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 }, + { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 }, + { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 } + }, + { + { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 }, + { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 }, + { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 } + }, + { + { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 }, + { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 }, + { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 } + }, + { + { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 }, + { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 }, + { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 } + }, + { + { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 }, + { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 }, + { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 } + }, + { + { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 }, + { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 }, + { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 } + } +}, +{ /* 21/31 */ + { + { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 }, + { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 }, + { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 } + }, + { + { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 }, + { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 }, + { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 } + }, + { + { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 }, + { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 }, + { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 } + }, + { + { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 }, + { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 }, + { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 } + }, + { + { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 }, + { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 }, + { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 } + }, + { + { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 }, + { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 }, + { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 } + }, + { + { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 }, + { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 }, + { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 } + }, + { + { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 }, + { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 }, + { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 } + } +}, +{ /* 22/31 */ + { + { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 }, + { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 }, + { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 } + }, + { + { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 }, + { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 }, + { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 } + }, + { + { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 }, + { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 }, + { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 } + }, + { + { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 }, + { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 }, + { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 } + }, + { + { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 }, + { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 }, + { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 } + }, + { + { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 }, + { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 }, + { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 } + }, + { + { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 }, + { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 }, + { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 } + }, + { + { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 }, + { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 }, + { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 } + } +}, +{ /* 23/31 */ + { + { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 }, + { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 }, + { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 } + }, + { + { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 }, + { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 }, + { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 } + }, + { + { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 }, + { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 }, + { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 } + }, + { + { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 }, + { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 }, + { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 } + }, + { + { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 }, + { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 }, + { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 } + }, + { + { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 }, + { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 }, + { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 } + }, + { + { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 }, + { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 }, + { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 } + }, + { + { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 }, + { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 }, + { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 } + } +}, +{ /* 24/31 */ + { + { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 }, + { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 }, + { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 } + }, + { + { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 }, + { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 }, + { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 } + }, + { + { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 }, + { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 }, + { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 } + }, + { + { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 }, + { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 }, + { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 } + }, + { + { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 }, + { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 }, + { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 } + }, + { + { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 }, + { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 }, + { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 } + }, + { + { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 }, + { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 }, + { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 } + }, + { + { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 }, + { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 }, + { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 } + } +}, +{ /* 25/31 */ + { + { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 }, + { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 }, + { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 } + }, + { + { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 }, + { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 }, + { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 } + }, + { + { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 }, + { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 }, + { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 } + }, + { + { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 }, + { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 }, + { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 } + }, + { + { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 }, + { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 }, + { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 } + }, + { + { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 }, + { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 }, + { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 } + }, + { + { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 }, + { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 }, + { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 } + }, + { + { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 }, + { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 }, + { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 } + } +}, +{ /* 26/31 */ + { + { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 }, + { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 }, + { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 } + }, + { + { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 }, + { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 }, + { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 } + }, + { + { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 }, + { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 }, + { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 } + }, + { + { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 }, + { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 }, + { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 } + }, + { + { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 }, + { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 }, + { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 } + }, + { + { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 }, + { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 }, + { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 } + }, + { + { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 }, + { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 }, + { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 } + }, + { + { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 }, + { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 }, + { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 } + } +}, +{ /* 27/31 */ + { + { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 }, + { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 }, + { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 } + }, + { + { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 }, + { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 }, + { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 } + }, + { + { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 }, + { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 }, + { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 } + }, + { + { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 }, + { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 }, + { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 } + }, + { + { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 }, + { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 }, + { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 } + }, + { + { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 }, + { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 }, + { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 } + }, + { + { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 }, + { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 }, + { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 } + }, + { + { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 }, + { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 }, + { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 } + } +}, +{ /* 28/31 */ + { + { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 }, + { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 }, + { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 } + }, + { + { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 }, + { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 }, + { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 } + }, + { + { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 }, + { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 }, + { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 } + }, + { + { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 }, + { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 }, + { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 } + }, + { + { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 }, + { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 }, + { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 } + }, + { + { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 }, + { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 }, + { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 } + }, + { + { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 }, + { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 }, + { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 } + }, + { + { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 }, + { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 }, + { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 } + } +}, +{ /* 29/31 */ + { + { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 }, + { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 }, + { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 } + }, + { + { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 }, + { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 }, + { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 } + }, + { + { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 }, + { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 }, + { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 } + }, + { + { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 }, + { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 }, + { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 } + }, + { + { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 }, + { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 }, + { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 } + }, + { + { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 }, + { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 }, + { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 } + }, + { + { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 }, + { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 }, + { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 } + }, + { + { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 }, + { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 }, + { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 } + } +}, +{ /* 30/31 */ + { + { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 }, + { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 }, + { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 } + }, + { + { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 }, + { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 }, + { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 } + }, + { + { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 }, + { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 }, + { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 } + }, + { + { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 }, + { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 }, + { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 } + }, + { + { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 }, + { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 }, + { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 } + }, + { + { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 }, + { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 }, + { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 } + }, + { + { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 }, + { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 }, + { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 } + }, + { + { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 }, + { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 }, + { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 } + } +}, +{ /* 31/31 */ + { + { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 }, + { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 }, + { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 } + }, + { + { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 }, + { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 }, + { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 } + }, + { + { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 }, + { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 }, + { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 } + }, + { + { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 }, + { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 }, + { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 } + }, + { + { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 }, + { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 }, + { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 } + }, + { + { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 }, + { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 }, + { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 } + }, + { + { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 }, + { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 }, + { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 } + }, + { + { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 }, + { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 }, + { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 } + } +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base2.h b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base2.h new file mode 100644 index 0000000..90a1457 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/base2.h @@ -0,0 +1,40 @@ +{ + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 } +}, +{ + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 } +}, +{ + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 } +}, +{ + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 } +}, +{ + { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 }, + { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 }, + { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 } +}, +{ + { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 }, + { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 }, + { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 } +}, +{ + { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 }, + { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 }, + { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 } +}, +{ + { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 }, + { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 }, + { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 } +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/constants.h b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/constants.h new file mode 100644 index 0000000..dd6da1b --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/constants.h @@ -0,0 +1,40 @@ +/* 37095705934669439343138083508754565189542113879843219016388785533085940283555 */ +static const fe25519 d = { + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 +}; + +/* 2 * d = + * 16295367250680780974490674513165176452449235426866156013048779062215315747161 + */ +static const fe25519 d2 = { + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 }; + +/* sqrt(-1) */ +static const fe25519 sqrtm1 = { + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 +}; + +/* A = 486662 */ +static const fe25519 curve25519_A = { + 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* sqrt(ad - 1) with a = -1 (mod p) */ +static const fe25519 sqrtadm1 = { + 24849947, -153582, -23613485, 6347715, -21072328, -667138, -25271143, -15367704, -870347, 14525639 +}; + +/* 1 / sqrt(a - d) */ +static const fe25519 invsqrtamd = { + 6111485, 4156064, -27798727, 12243468, -25904040, 120897, 20826367, -7060776, 6093568, -1986012 +}; + +/* 1 - d ^ 2 */ +static const fe25519 onemsqd = { + 6275446, -16617371, -22938544, -3773710, 11667077, 7397348, -27922721, 1766195, -24433858, 672203 +}; + +/* (d - 1) ^ 2 */ +static const fe25519 sqdmone = { + 15551795, -11097455, -13425098, -10125071, -11896535, 10178284, -26634327, 4729244, -5282110, -10116402 +}; diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/fe.h b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/fe.h new file mode 100644 index 0000000..f216669 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_25_5/fe.h @@ -0,0 +1,220 @@ +/* + Ignores top bit of h. + */ + +void +fe25519_frombytes(fe25519 h, const unsigned char *s) +{ + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; + h1 += carry0; + h0 -= carry0 * ((uint32_t) 1L << 26); + carry1 = h1 >> 25; + h2 += carry1; + h1 -= carry1 * ((uint32_t) 1L << 25); + carry2 = h2 >> 26; + h3 += carry2; + h2 -= carry2 * ((uint32_t) 1L << 26); + carry3 = h3 >> 25; + h4 += carry3; + h3 -= carry3 * ((uint32_t) 1L << 25); + carry4 = h4 >> 26; + h5 += carry4; + h4 -= carry4 * ((uint32_t) 1L << 26); + carry5 = h5 >> 25; + h6 += carry5; + h5 -= carry5 * ((uint32_t) 1L << 25); + carry6 = h6 >> 26; + h7 += carry6; + h6 -= carry6 * ((uint32_t) 1L << 26); + carry7 = h7 >> 25; + h8 += carry7; + h7 -= carry7 * ((uint32_t) 1L << 25); + carry8 = h8 >> 26; + h9 += carry8; + h8 -= carry8 * ((uint32_t) 1L << 26); + carry9 = h9 >> 25; + h9 -= carry9 * ((uint32_t) 1L << 25); + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + + Goal: Output h0+...+2^230 h9. + */ + +void +fe25519_tobytes(unsigned char *s, const fe25519 h) +{ + fe25519 t; + + fe25519_reduce(t, h); + s[0] = t[0] >> 0; + s[1] = t[0] >> 8; + s[2] = t[0] >> 16; + s[3] = (t[0] >> 24) | (t[1] * ((uint32_t) 1 << 2)); + s[4] = t[1] >> 6; + s[5] = t[1] >> 14; + s[6] = (t[1] >> 22) | (t[2] * ((uint32_t) 1 << 3)); + s[7] = t[2] >> 5; + s[8] = t[2] >> 13; + s[9] = (t[2] >> 21) | (t[3] * ((uint32_t) 1 << 5)); + s[10] = t[3] >> 3; + s[11] = t[3] >> 11; + s[12] = (t[3] >> 19) | (t[4] * ((uint32_t) 1 << 6)); + s[13] = t[4] >> 2; + s[14] = t[4] >> 10; + s[15] = t[4] >> 18; + s[16] = t[5] >> 0; + s[17] = t[5] >> 8; + s[18] = t[5] >> 16; + s[19] = (t[5] >> 24) | (t[6] * ((uint32_t) 1 << 1)); + s[20] = t[6] >> 7; + s[21] = t[6] >> 15; + s[22] = (t[6] >> 23) | (t[7] * ((uint32_t) 1 << 3)); + s[23] = t[7] >> 5; + s[24] = t[7] >> 13; + s[25] = (t[7] >> 21) | (t[8] * ((uint32_t) 1 << 4)); + s[26] = t[8] >> 4; + s[27] = t[8] >> 12; + s[28] = (t[8] >> 20) | (t[9] * ((uint32_t) 1 << 6)); + s[29] = t[9] >> 2; + s[30] = t[9] >> 10; + s[31] = t[9] >> 18; +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_51/base.h b/third_party/heimdal/lib/hcrypto/x25519/fe_51/base.h new file mode 100644 index 0000000..6b3b833 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_51/base.h @@ -0,0 +1,1344 @@ +{ /* 0/31 */ + { + { 1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563 }, + { 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585 }, + { 301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142 } + }, + { + { 1380971894829527, 790832306631236, 2067202295274102, 1995808275510000, 1566530869037010 }, + { 463307831301544, 432984605774163, 1610641361907204, 750899048855000, 1894842303421586 }, + { 748439484463711, 1033211726465151, 1396005112841647, 1611506220286469, 1972177495910992 } + }, + { + { 1601611775252272, 1720807796594148, 1132070835939856, 1260455018889551, 2147779492816911 }, + { 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597 }, + { 1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707 } + }, + { + { 934282339813791, 1846903124198670, 1172395437954843, 1007037127761661, 1830588347719256 }, + { 1694390458783935, 1735906047636159, 705069562067493, 648033061693059, 696214010414170 }, + { 1121406372216585, 192876649532226, 190294192191717, 1994165897297032, 2245000007398739 } + }, + { + { 769950342298419, 132954430919746, 844085933195555, 974092374476333, 726076285546016 }, + { 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893 }, + { 1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339 } + }, + { + { 1388594989461809, 316767091099457, 394298842192982, 1230079486801005, 1440737038838979 }, + { 7380825640100, 146210432690483, 304903576448906, 1198869323871120, 997689833219095 }, + { 1181317918772081, 114573476638901, 262805072233344, 265712217171332, 294181933805782 } + }, + { + { 665000864555967, 2065379846933859, 370231110385876, 350988370788628, 1233371373142985 }, + { 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113 }, + { 965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601 } + }, + { + { 2068619540119183, 1966274918058806, 957728544705549, 729906502578991, 159834893065166 }, + { 2073601412052185, 31021124762708, 264500969797082, 248034690651703, 1030252227928288 }, + { 551790716293402, 1989538725166328, 801169423371717, 2052451893578887, 678432056995012 } + } +}, +{ /* 1/31 */ + { + { 1368953770187805, 790347636712921, 437508475667162, 2142576377050580, 1932081720066286 }, + { 953638594433374, 1092333936795051, 1419774766716690, 805677984380077, 859228993502513 }, + { 1200766035879111, 20142053207432, 1465634435977050, 1645256912097844, 295121984874596 } + }, + { + { 1735718747031557, 1248237894295956, 1204753118328107, 976066523550493, 65943769534592 }, + { 1060098822528990, 1586825862073490, 212301317240126, 1975302711403555, 666724059764335 }, + { 1091990273418756, 1572899409348578, 80968014455247, 306009358661350, 1520450739132526 } + }, + { + { 1480517209436112, 1511153322193952, 1244343858991172, 304788150493241, 369136856496443 }, + { 2151330273626164, 762045184746182, 1688074332551515, 823046109005759, 907602769079491 }, + { 2047386910586836, 168470092900250, 1552838872594810, 340951180073789, 360819374702533 } + }, + { + { 1982622644432056, 2014393600336956, 128909208804214, 1617792623929191, 105294281913815 }, + { 980234343912898, 1712256739246056, 588935272190264, 204298813091998, 841798321043288 }, + { 197561292938973, 454817274782871, 1963754960082318, 2113372252160468, 971377527342673 } + }, + { + { 164699448829328, 3127451757672, 1199504971548753, 1766155447043652, 1899238924683527 }, + { 732262946680281, 1674412764227063, 2182456405662809, 1350894754474250, 558458873295247 }, + { 2103305098582922, 1960809151316468, 715134605001343, 1454892949167181, 40827143824949 } + }, + { + { 1239289043050212, 1744654158124578, 758702410031698, 1796762995074688, 1603056663766 }, + { 2232056027107988, 987343914584615, 2115594492994461, 1819598072792159, 1119305654014850 }, + { 320153677847348, 939613871605645, 641883205761567, 1930009789398224, 329165806634126 } + }, + { + { 980930490474130, 1242488692177893, 1251446316964684, 1086618677993530, 1961430968465772 }, + { 276821765317453, 1536835591188030, 1305212741412361, 61473904210175, 2051377036983058 }, + { 833449923882501, 1750270368490475, 1123347002068295, 185477424765687, 278090826653186 } + }, + { + { 794524995833413, 1849907304548286, 53348672473145, 1272368559505217, 1147304168324779 }, + { 1504846112759364, 1203096289004681, 562139421471418, 274333017451844, 1284344053775441 }, + { 483048732424432, 2116063063343382, 30120189902313, 292451576741007, 1156379271702225 } + } +}, +{ /* 2/31 */ + { + { 928372153029038, 2147692869914564, 1455665844462196, 1986737809425946, 185207050258089 }, + { 137732961814206, 706670923917341, 1387038086865771, 1965643813686352, 1384777115696347 }, + { 481144981981577, 2053319313589856, 2065402289827512, 617954271490316, 1106602634668125 } + }, + { + { 696298019648792, 893299659040895, 1148636718636009, 26734077349617, 2203955659340681 }, + { 657390353372855, 998499966885562, 991893336905797, 810470207106761, 343139804608786 }, + { 791736669492960, 934767652997115, 824656780392914, 1759463253018643, 361530362383518 } + }, + { + { 2022541353055597, 2094700262587466, 1551008075025686, 242785517418164, 695985404963562 }, + { 1287487199965223, 2215311941380308, 1552928390931986, 1664859529680196, 1125004975265243 }, + { 677434665154918, 989582503122485, 1817429540898386, 1052904935475344, 1143826298169798 } + }, + { + { 367266328308408, 318431188922404, 695629353755355, 634085657580832, 24581612564426 }, + { 773360688841258, 1815381330538070, 363773437667376, 539629987070205, 783280434248437 }, + { 180820816194166, 168937968377394, 748416242794470, 1227281252254508, 1567587861004268 } + }, + { + { 478775558583645, 2062896624554807, 699391259285399, 358099408427873, 1277310261461761 }, + { 1984740906540026, 1079164179400229, 1056021349262661, 1659958556483663, 1088529069025527 }, + { 580736401511151, 1842931091388998, 1177201471228238, 2075460256527244, 1301133425678027 } + }, + { + { 1515728832059182, 1575261009617579, 1510246567196186, 191078022609704, 116661716289141 }, + { 1295295738269652, 1714742313707026, 545583042462581, 2034411676262552, 1513248090013606 }, + { 230710545179830, 30821514358353, 760704303452229, 390668103790604, 573437871383156 } + }, + { + { 1169380107545646, 263167233745614, 2022901299054448, 819900753251120, 2023898464874585 }, + { 2102254323485823, 1570832666216754, 34696906544624, 1993213739807337, 70638552271463 }, + { 894132856735058, 548675863558441, 845349339503395, 1942269668326667, 1615682209874691 } + }, + { + { 1287670217537834, 1222355136884920, 1846481788678694, 1150426571265110, 1613523400722047 }, + { 793388516527298, 1315457083650035, 1972286999342417, 1901825953052455, 338269477222410 }, + { 550201530671806, 778605267108140, 2063911101902983, 115500557286349, 2041641272971022 } + } +}, +{ /* 3/31 */ + { + { 717255318455100, 519313764361315, 2080406977303708, 541981206705521, 774328150311600 }, + { 261715221532238, 1795354330069993, 1496878026850283, 499739720521052, 389031152673770 }, + { 1997217696294013, 1717306351628065, 1684313917746180, 1644426076011410, 1857378133465451 } + }, + { + { 1475434724792648, 76931896285979, 1116729029771667, 2002544139318042, 725547833803938 }, + { 2022306639183567, 726296063571875, 315345054448644, 1058733329149221, 1448201136060677 }, + { 1710065158525665, 1895094923036397, 123988286168546, 1145519900776355, 1607510767693874 } + }, + { + { 561605375422540, 1071733543815037, 131496498800990, 1946868434569999, 828138133964203 }, + { 1548495173745801, 442310529226540, 998072547000384, 553054358385281, 644824326376171 }, + { 1445526537029440, 2225519789662536, 914628859347385, 1064754194555068, 1660295614401091 } + }, + { + { 1199690223111956, 24028135822341, 66638289244341, 57626156285975, 565093967979607 }, + { 876926774220824, 554618976488214, 1012056309841565, 839961821554611, 1414499340307677 }, + { 703047626104145, 1266841406201770, 165556500219173, 486991595001879, 1011325891650656 } + }, + { + { 1622861044480487, 1156394801573634, 1869132565415504, 327103985777730, 2095342781472284 }, + { 334886927423922, 489511099221528, 129160865966726, 1720809113143481, 619700195649254 }, + { 1646545795166119, 1758370782583567, 714746174550637, 1472693650165135, 898994790308209 } + }, + { + { 333403773039279, 295772542452938, 1693106465353610, 912330357530760, 471235657950362 }, + { 1811196219982022, 1068969825533602, 289602974833439, 1988956043611592, 863562343398367 }, + { 906282429780072, 2108672665779781, 432396390473936, 150625823801893, 1708930497638539 } + }, + { + { 925664675702328, 21416848568684, 1831436641861340, 601157008940113, 371818055044496 }, + { 1479786007267725, 1738881859066675, 68646196476567, 2146507056100328, 1247662817535471 }, + { 52035296774456, 939969390708103, 312023458773250, 59873523517659, 1231345905848899 } + }, + { + { 643355106415761, 290186807495774, 2013561737429023, 319648069511546, 393736678496162 }, + { 129358342392716, 1932811617704777, 1176749390799681, 398040349861790, 1170779668090425 }, + { 2051980782668029, 121859921510665, 2048329875753063, 1235229850149665, 519062146124755 } + } +}, +{ /* 4/31 */ + { + { 1608170971973096, 415809060360428, 1350468408164766, 2038620059057678, 1026904485989112 }, + { 1837656083115103, 1510134048812070, 906263674192061, 1821064197805734, 565375124676301 }, + { 578027192365650, 2034800251375322, 2128954087207123, 478816193810521, 2196171989962750 } + }, + { + { 1633188840273139, 852787172373708, 1548762607215796, 1266275218902681, 1107218203325133 }, + { 462189358480054, 1784816734159228, 1611334301651368, 1303938263943540, 707589560319424 }, + { 1038829280972848, 38176604650029, 753193246598573, 1136076426528122, 595709990562434 } + }, + { + { 1408451820859834, 2194984964010833, 2198361797561729, 1061962440055713, 1645147963442934 }, + { 4701053362120, 1647641066302348, 1047553002242085, 1923635013395977, 206970314902065 }, + { 1750479161778571, 1362553355169293, 1891721260220598, 966109370862782, 1024913988299801 } + }, + { + { 212699049131723, 1117950018299775, 1873945661751056, 1403802921984058, 130896082652698 }, + { 636808533673210, 1262201711667560, 390951380330599, 1663420692697294, 561951321757406 }, + { 520731594438141, 1446301499955692, 273753264629267, 1565101517999256, 1019411827004672 } + }, + { + { 926527492029409, 1191853477411379, 734233225181171, 184038887541270, 1790426146325343 }, + { 1464651961852572, 1483737295721717, 1519450561335517, 1161429831763785, 405914998179977 }, + { 996126634382301, 796204125879525, 127517800546509, 344155944689303, 615279846169038 } + }, + { + { 738724080975276, 2188666632415296, 1961313708559162, 1506545807547587, 1151301638969740 }, + { 622917337413835, 1218989177089035, 1284857712846592, 970502061709359, 351025208117090 }, + { 2067814584765580, 1677855129927492, 2086109782475197, 235286517313238, 1416314046739645 } + }, + { + { 586844262630358, 307444381952195, 458399356043426, 602068024507062, 1028548203415243 }, + { 678489922928203, 2016657584724032, 90977383049628, 1026831907234582, 615271492942522 }, + { 301225714012278, 1094837270268560, 1202288391010439, 644352775178361, 1647055902137983 } + }, + { + { 1210746697896478, 1416608304244708, 686487477217856, 1245131191434135, 1051238336855737 }, + { 1135604073198207, 1683322080485474, 769147804376683, 2086688130589414, 900445683120379 }, + { 1971518477615628, 401909519527336, 448627091057375, 1409486868273821, 1214789035034363 } + } +}, +{ /* 5/31 */ + { + { 1364039144731711, 1897497433586190, 2203097701135459, 145461396811251, 1349844460790699 }, + { 1045230323257973, 818206601145807, 630513189076103, 1672046528998132, 807204017562437 }, + { 439961968385997, 386362664488986, 1382706320807688, 309894000125359, 2207801346498567 } + }, + { + { 1229004686397588, 920643968530863, 123975893911178, 681423993215777, 1400559197080973 }, + { 2003766096898049, 170074059235165, 1141124258967971, 1485419893480973, 1573762821028725 }, + { 729905708611432, 1270323270673202, 123353058984288, 426460209632942, 2195574535456672 } + }, + { + { 1271140255321235, 2044363183174497, 52125387634689, 1445120246694705, 942541986339084 }, + { 1761608437466135, 583360847526804, 1586706389685493, 2157056599579261, 1170692369685772 }, + { 871476219910823, 1878769545097794, 2241832391238412, 548957640601001, 690047440233174 } + }, + { + { 297194732135507, 1366347803776820, 1301185512245601, 561849853336294, 1533554921345731 }, + { 999628998628371, 1132836708493400, 2084741674517453, 469343353015612, 678782988708035 }, + { 2189427607417022, 699801937082607, 412764402319267, 1478091893643349, 2244675696854460 } + }, + { + { 1712292055966563, 204413590624874, 1405738637332841, 408981300829763, 861082219276721 }, + { 508561155940631, 966928475686665, 2236717801150132, 424543858577297, 2089272956986143 }, + { 221245220129925, 1156020201681217, 491145634799213, 542422431960839, 828100817819207 } + }, + { + { 153756971240384, 1299874139923977, 393099165260502, 1058234455773022, 996989038681183 }, + { 559086812798481, 573177704212711, 1629737083816402, 1399819713462595, 1646954378266038 }, + { 1887963056288059, 228507035730124, 1468368348640282, 930557653420194, 613513962454686 } + }, + { + { 1224529808187553, 1577022856702685, 2206946542980843, 625883007765001, 279930793512158 }, + { 1076287717051609, 1114455570543035, 187297059715481, 250446884292121, 1885187512550540 }, + { 902497362940219, 76749815795675, 1657927525633846, 1420238379745202, 1340321636548352 } + }, + { + { 1129576631190784, 1281994010027327, 996844254743018, 257876363489249, 1150850742055018 }, + { 628740660038789, 1943038498527841, 467786347793886, 1093341428303375, 235413859513003 }, + { 237425418909360, 469614029179605, 1512389769174935, 1241726368345357, 441602891065214 } + } +}, +{ /* 6/31 */ + { + { 1736417953058555, 726531315520508, 1833335034432527, 1629442561574747, 624418919286085 }, + { 1960754663920689, 497040957888962, 1909832851283095, 1271432136996826, 2219780368020940 }, + { 1537037379417136, 1358865369268262, 2130838645654099, 828733687040705, 1999987652890901 } + }, + { + { 629042105241814, 1098854999137608, 887281544569320, 1423102019874777, 7911258951561 }, + { 1811562332665373, 1501882019007673, 2213763501088999, 359573079719636, 36370565049116 }, + { 218907117361280, 1209298913016966, 1944312619096112, 1130690631451061, 1342327389191701 } + }, + { + { 1369976867854704, 1396479602419169, 1765656654398856, 2203659200586299, 998327836117241 }, + { 2230701885562825, 1348173180338974, 2172856128624598, 1426538746123771, 444193481326151 }, + { 784210426627951, 918204562375674, 1284546780452985, 1324534636134684, 1872449409642708 } + }, + { + { 319638829540294, 596282656808406, 2037902696412608, 1557219121643918, 341938082688094 }, + { 1901860206695915, 2004489122065736, 1625847061568236, 973529743399879, 2075287685312905 }, + { 1371853944110545, 1042332820512553, 1949855697918254, 1791195775521505, 37487364849293 } + }, + { + { 687200189577855, 1082536651125675, 644224940871546, 340923196057951, 343581346747396 }, + { 2082717129583892, 27829425539422, 145655066671970, 1690527209845512, 1865260509673478 }, + { 1059729620568824, 2163709103470266, 1440302280256872, 1769143160546397, 869830310425069 } + }, + { + { 1609516219779025, 777277757338817, 2101121130363987, 550762194946473, 1905542338659364 }, + { 2024821921041576, 426948675450149, 595133284085473, 471860860885970, 600321679413000 }, + { 598474602406721, 1468128276358244, 1191923149557635, 1501376424093216, 1281662691293476 } + }, + { + { 1721138489890707, 1264336102277790, 433064545421287, 1359988423149466, 1561871293409447 }, + { 719520245587143, 393380711632345, 132350400863381, 1543271270810729, 1819543295798660 }, + { 396397949784152, 1811354474471839, 1362679985304303, 2117033964846756, 498041172552279 } + }, + { + { 1812471844975748, 1856491995543149, 126579494584102, 1036244859282620, 1975108050082550 }, + { 650623932407995, 1137551288410575, 2125223403615539, 1725658013221271, 2134892965117796 }, + { 522584000310195, 1241762481390450, 1743702789495384, 2227404127826575, 1686746002148897 } + } +}, +{ /* 7/31 */ + { + { 427904865186312, 1703211129693455, 1585368107547509, 1436984488744336, 761188534613978 }, + { 318101947455002, 248138407995851, 1481904195303927, 309278454311197, 1258516760217879 }, + { 1275068538599310, 513726919533379, 349926553492294, 688428871968420, 1702400196000666 } + }, + { + { 1061864036265233, 961611260325381, 321859632700838, 1045600629959517, 1985130202504038 }, + { 1558816436882417, 1962896332636523, 1337709822062152, 1501413830776938, 294436165831932 }, + { 818359826554971, 1862173000996177, 626821592884859, 573655738872376, 1749691246745455 } + }, + { + { 1988022651432119, 1082111498586040, 1834020786104821, 1454826876423687, 692929915223122 }, + { 2146513703733331, 584788900394667, 464965657279958, 2183973639356127, 238371159456790 }, + { 1129007025494441, 2197883144413266, 265142755578169, 971864464758890, 1983715884903702 } + }, + { + { 1291366624493075, 381456718189114, 1711482489312444, 1815233647702022, 892279782992467 }, + { 444548969917454, 1452286453853356, 2113731441506810, 645188273895859, 810317625309512 }, + { 2242724082797924, 1373354730327868, 1006520110883049, 2147330369940688, 1151816104883620 } + }, + { + { 1745720200383796, 1911723143175317, 2056329390702074, 355227174309849, 879232794371100 }, + { 163723479936298, 115424889803150, 1156016391581227, 1894942220753364, 1970549419986329 }, + { 681981452362484, 267208874112496, 1374683991933094, 638600984916117, 646178654558546 } + }, + { + { 13378654854251, 106237307029567, 1944412051589651, 1841976767925457, 230702819835573 }, + { 260683893467075, 854060306077237, 913639551980112, 4704576840123, 280254810808712 }, + { 715374893080287, 1173334812210491, 1806524662079626, 1894596008000979, 398905715033393 } + }, + { + { 500026409727661, 1596431288195371, 1420380351989370, 985211561521489, 392444930785633 }, + { 2096421546958141, 1922523000950363, 789831022876840, 427295144688779, 320923973161730 }, + { 1927770723575450, 1485792977512719, 1850996108474547, 551696031508956, 2126047405475647 } + }, + { + { 2112099158080148, 742570803909715, 6484558077432, 1951119898618916, 93090382703416 }, + { 383905201636970, 859946997631870, 855623867637644, 1017125780577795, 794250831877809 }, + { 77571826285752, 999304298101753, 487841111777762, 1038031143212339, 339066367948762 } + } +}, +{ /* 8/31 */ + { + { 674994775520533, 266035846330789, 826951213393478, 1405007746162285, 1781791018620876 }, + { 1001412661522686, 348196197067298, 1666614366723946, 888424995032760, 580747687801357 }, + { 1939560076207777, 1409892634407635, 552574736069277, 383854338280405, 190706709864139 } + }, + { + { 2177087163428741, 1439255351721944, 1208070840382793, 2230616362004769, 1396886392021913 }, + { 676962063230039, 1880275537148808, 2046721011602706, 888463247083003, 1318301552024067 }, + { 1466980508178206, 617045217998949, 652303580573628, 757303753529064, 207583137376902 } + }, + { + { 1511056752906902, 105403126891277, 493434892772846, 1091943425335976, 1802717338077427 }, + { 1853982405405128, 1878664056251147, 1528011020803992, 1019626468153565, 1128438412189035 }, + { 1963939888391106, 293456433791664, 697897559513649, 985882796904380, 796244541237972 } + }, + { + { 416770998629779, 389655552427054, 1314476859406756, 1749382513022778, 1161905598739491 }, + { 1428358296490651, 1027115282420478, 304840698058337, 441410174026628, 1819358356278573 }, + { 204943430200135, 1554861433819175, 216426658514651, 264149070665950, 2047097371738319 } + }, + { + { 1934415182909034, 1393285083565062, 516409331772960, 1157690734993892, 121039666594268 }, + { 662035583584445, 286736105093098, 1131773000510616, 818494214211439, 472943792054479 }, + { 665784778135882, 1893179629898606, 808313193813106, 276797254706413, 1563426179676396 } + }, + { + { 945205108984232, 526277562959295, 1324180513733566, 1666970227868664, 153547609289173 }, + { 2031433403516252, 203996615228162, 170487168837083, 981513604791390, 843573964916831 }, + { 1476570093962618, 838514669399805, 1857930577281364, 2017007352225784, 317085545220047 } + }, + { + { 1461557121912842, 1600674043318359, 2157134900399597, 1670641601940616, 127765583803283 }, + { 1293543509393474, 2143624609202546, 1058361566797508, 214097127393994, 946888515472729 }, + { 357067959932916, 1290876214345711, 521245575443703, 1494975468601005, 800942377643885 } + }, + { + { 566116659100033, 820247422481740, 994464017954148, 327157611686365, 92591318111744 }, + { 617256647603209, 1652107761099439, 1857213046645471, 1085597175214970, 817432759830522 }, + { 771808161440705, 1323510426395069, 680497615846440, 851580615547985, 1320806384849017 } + } +}, +{ /* 9/31 */ + { + { 1219260086131915, 647169006596815, 79601124759706, 2161724213426748, 404861897060198 }, + { 1327968293887866, 1335500852943256, 1401587164534264, 558137311952440, 1551360549268902 }, + { 417621685193956, 1429953819744454, 396157358457099, 1940470778873255, 214000046234152 } + }, + { + { 1268047918491973, 2172375426948536, 1533916099229249, 1761293575457130, 1590622667026765 }, + { 1627072914981959, 2211603081280073, 1912369601616504, 1191770436221309, 2187309757525860 }, + { 1149147819689533, 378692712667677, 828475842424202, 2218619146419342, 70688125792186 } + }, + { + { 1299739417079761, 1438616663452759, 1536729078504412, 2053896748919838, 1008421032591246 }, + { 2040723824657366, 399555637875075, 632543375452995, 872649937008051, 1235394727030233 }, + { 2211311599327900, 2139787259888175, 938706616835350, 12609661139114, 2081897930719789 } + }, + { + { 1324994503390450, 336982330582631, 1183998925654177, 1091654665913274, 48727673971319 }, + { 1845522914617879, 1222198248335542, 150841072760134, 1927029069940982, 1189913404498011 }, + { 1079559557592645, 2215338383666441, 1903569501302605, 49033973033940, 305703433934152 } + }, + { + { 94653405416909, 1386121349852999, 1062130477891762, 36553947479274, 833669648948846 }, + { 1432015813136298, 440364795295369, 1395647062821501, 1976874522764578, 934452372723352 }, + { 1296625309219774, 2068273464883862, 1858621048097805, 1492281814208508, 2235868981918946 } + }, + { + { 1490330266465570, 1858795661361448, 1436241134969763, 294573218899647, 1208140011028933 }, + { 1282462923712748, 741885683986255, 2027754642827561, 518989529541027, 1826610009555945 }, + { 1525827120027511, 723686461809551, 1597702369236987, 244802101764964, 1502833890372311 } + }, + { + { 113622036244513, 1233740067745854, 674109952278496, 2114345180342965, 166764512856263 }, + { 2041668749310338, 2184405322203901, 1633400637611036, 2110682505536899, 2048144390084644 }, + { 503058759232932, 760293024620937, 2027152777219493, 666858468148475, 1539184379870952 } + }, + { + { 1916168475367211, 915626432541343, 883217071712575, 363427871374304, 1976029821251593 }, + { 678039535434506, 570587290189340, 1605302676614120, 2147762562875701, 1706063797091704 }, + { 1439489648586438, 2194580753290951, 832380563557396, 561521973970522, 584497280718389 } + } +}, +{ /* 10/31 */ + { + { 187989455492609, 681223515948275, 1933493571072456, 1872921007304880, 488162364135671 }, + { 1413466089534451, 410844090765630, 1397263346404072, 408227143123410, 1594561803147811 }, + { 2102170800973153, 719462588665004, 1479649438510153, 1097529543970028, 1302363283777685 } + }, + { + { 942065717847195, 1069313679352961, 2007341951411051, 70973416446291, 1419433790163706 }, + { 1146565545556377, 1661971299445212, 406681704748893, 564452436406089, 1109109865829139 }, + { 2214421081775077, 1165671861210569, 1890453018796184, 3556249878661, 442116172656317 } + }, + { + { 753830546620811, 1666955059895019, 1530775289309243, 1119987029104146, 2164156153857580 }, + { 615171919212796, 1523849404854568, 854560460547503, 2067097370290715, 1765325848586042 }, + { 1094538949313667, 1796592198908825, 870221004284388, 2025558921863561, 1699010892802384 } + }, + { + { 1951351290725195, 1916457206844795, 198025184438026, 1909076887557595, 1938542290318919 }, + { 1014323197538413, 869150639940606, 1756009942696599, 1334952557375672, 1544945379082874 }, + { 764055910920305, 1603590757375439, 146805246592357, 1843313433854297, 954279890114939 } + }, + { + { 80113526615750, 764536758732259, 1055139345100233, 469252651759390, 617897512431515 }, + { 74497112547268, 740094153192149, 1745254631717581, 727713886503130, 1283034364416928 }, + { 525892105991110, 1723776830270342, 1476444848991936, 573789489857760, 133864092632978 } + }, + { + { 542611720192581, 1986812262899321, 1162535242465837, 481498966143464, 544600533583622 }, + { 64123227344372, 1239927720647794, 1360722983445904, 222610813654661, 62429487187991 }, + { 1793193323953132, 91096687857833, 70945970938921, 2158587638946380, 1537042406482111 } + }, + { + { 1895854577604609, 1394895708949416, 1728548428495944, 1140864900240149, 563645333603061 }, + { 141358280486863, 91435889572504, 1087208572552643, 1829599652522921, 1193307020643647 }, + { 1611230858525381, 950720175540785, 499589887488610, 2001656988495019, 88977313255908 } + }, + { + { 1189080501479658, 2184348804772597, 1040818725742319, 2018318290311834, 1712060030915354 }, + { 873966876953756, 1090638350350440, 1708559325189137, 672344594801910, 1320437969700239 }, + { 1508590048271766, 1131769479776094, 101550868699323, 428297785557897, 561791648661744 } + } +}, +{ /* 11/31 */ + { + { 756417570499462, 237882279232602, 2136263418594016, 1701968045454886, 703713185137472 }, + { 1781187809325462, 1697624151492346, 1381393690939988, 175194132284669, 1483054666415238 }, + { 2175517777364616, 708781536456029, 955668231122942, 1967557500069555, 2021208005604118 } + }, + { + { 1115135966606887, 224217372950782, 915967306279222, 593866251291540, 561747094208006 }, + { 1443163092879439, 391875531646162, 2180847134654632, 464538543018753, 1594098196837178 }, + { 850858855888869, 319436476624586, 327807784938441, 740785849558761, 17128415486016 } + }, + { + { 2132756334090067, 536247820155645, 48907151276867, 608473197600695, 1261689545022784 }, + { 1525176236978354, 974205476721062, 293436255662638, 148269621098039, 137961998433963 }, + { 1121075518299410, 2071745529082111, 1265567917414828, 1648196578317805, 496232102750820 } + }, + { + { 122321229299801, 1022922077493685, 2001275453369484, 2017441881607947, 993205880778002 }, + { 654925550560074, 1168810995576858, 575655959430926, 905758704861388, 496774564663534 }, + { 1954109525779738, 2117022646152485, 338102630417180, 1194140505732026, 107881734943492 } + }, + { + { 1714785840001267, 2036500018681589, 1876380234251966, 2056717182974196, 1645855254384642 }, + { 106431476499341, 62482972120563, 1513446655109411, 807258751769522, 538491469114 }, + { 2002850762893643, 1243624520538135, 1486040410574605, 2184752338181213, 378495998083531 } + }, + { + { 922510868424903, 1089502620807680, 402544072617374, 1131446598479839, 1290278588136533 }, + { 1867998812076769, 715425053580701, 39968586461416, 2173068014586163, 653822651801304 }, + { 162892278589453, 182585796682149, 75093073137630, 497037941226502, 133871727117371 } + }, + { + { 1914596576579670, 1608999621851578, 1987629837704609, 1519655314857977, 1819193753409464 }, + { 1949315551096831, 1069003344994464, 1939165033499916, 1548227205730856, 1933767655861407 }, + { 1730519386931635, 1393284965610134, 1597143735726030, 416032382447158, 1429665248828629 } + }, + { + { 360275475604565, 547835731063078, 215360904187529, 596646739879007, 332709650425085 }, + { 47602113726801, 1522314509708010, 437706261372925, 814035330438027, 335930650933545 }, + { 1291597595523886, 1058020588994081, 402837842324045, 1363323695882781, 2105763393033193 } + } +}, +{ /* 12/31 */ + { + { 109521982566564, 1715257748585139, 1112231216891516, 2046641005101484, 134249157157013 }, + { 2156991030936798, 2227544497153325, 1869050094431622, 754875860479115, 1754242344267058 }, + { 1846089562873800, 98894784984326, 1412430299204844, 171351226625762, 1100604760929008 } + }, + { + { 84172382130492, 499710970700046, 425749630620778, 1762872794206857, 612842602127960 }, + { 868309334532756, 1703010512741873, 1952690008738057, 4325269926064, 2071083554962116 }, + { 523094549451158, 401938899487815, 1407690589076010, 2022387426254453, 158660516411257 } + }, + { + { 612867287630009, 448212612103814, 571629077419196, 1466796750919376, 1728478129663858 }, + { 1723848973783452, 2208822520534681, 1718748322776940, 1974268454121942, 1194212502258141 }, + { 1254114807944608, 977770684047110, 2010756238954993, 1783628927194099, 1525962994408256 } + }, + { + { 232464058235826, 1948628555342434, 1835348780427694, 1031609499437291, 64472106918373 }, + { 767338676040683, 754089548318405, 1523192045639075, 435746025122062, 512692508440385 }, + { 1255955808701983, 1700487367990941, 1166401238800299, 1175121994891534, 1190934801395380 } + }, + { + { 349144008168292, 1337012557669162, 1475912332999108, 1321618454900458, 47611291904320 }, + { 877519947135419, 2172838026132651, 272304391224129, 1655143327559984, 886229406429814 }, + { 375806028254706, 214463229793940, 572906353144089, 572168269875638, 697556386112979 } + }, + { + { 1168827102357844, 823864273033637, 2071538752104697, 788062026895924, 599578340743362 }, + { 1948116082078088, 2054898304487796, 2204939184983900, 210526805152138, 786593586607626 }, + { 1915320147894736, 156481169009469, 655050471180417, 592917090415421, 2165897438660879 } + }, + { + { 1726336468579724, 1119932070398949, 1929199510967666, 33918788322959, 1836837863503150 }, + { 829996854845988, 217061778005138, 1686565909803640, 1346948817219846, 1723823550730181 }, + { 384301494966394, 687038900403062, 2211195391021739, 254684538421383, 1245698430589680 } + }, + { + { 1247567493562688, 1978182094455847, 183871474792955, 806570235643435, 288461518067916 }, + { 1449077384734201, 38285445457996, 2136537659177832, 2146493000841573, 725161151123125 }, + { 1201928866368855, 800415690605445, 1703146756828343, 997278587541744, 1858284414104014 } + } +}, +{ /* 13/31 */ + { + { 356468809648877, 782373916933152, 1718002439402870, 1392222252219254, 663171266061951 }, + { 759628738230460, 1012693474275852, 353780233086498, 246080061387552, 2030378857679162 }, + { 2040672435071076, 888593182036908, 1298443657189359, 1804780278521327, 354070726137060 } + }, + { + { 1894938527423184, 1463213041477277, 474410505497651, 247294963033299, 877975941029128 }, + { 207937160991127, 12966911039119, 820997788283092, 1010440472205286, 1701372890140810 }, + { 218882774543183, 533427444716285, 1233243976733245, 435054256891319, 1509568989549904 } + }, + { + { 1888838535711826, 1052177758340622, 1213553803324135, 169182009127332, 463374268115872 }, + { 299137589460312, 1594371588983567, 868058494039073, 257771590636681, 1805012993142921 }, + { 1806842755664364, 2098896946025095, 1356630998422878, 1458279806348064, 347755825962072 } + }, + { + { 1402334161391744, 1560083671046299, 1008585416617747, 1147797150908892, 1420416683642459 }, + { 665506704253369, 273770475169863, 799236974202630, 848328990077558, 1811448782807931 }, + { 1468412523962641, 771866649897997, 1931766110147832, 799561180078482, 524837559150077 } + }, + { + { 2223212657821850, 630416247363666, 2144451165500328, 816911130947791, 1024351058410032 }, + { 1266603897524861, 156378408858100, 1275649024228779, 447738405888420, 253186462063095 }, + { 2022215964509735, 136144366993649, 1800716593296582, 1193970603800203, 871675847064218 } + }, + { + { 1862751661970328, 851596246739884, 1519315554814041, 1542798466547449, 1417975335901520 }, + { 1228168094547481, 334133883362894, 587567568420081, 433612590281181, 603390400373205 }, + { 121893973206505, 1843345804916664, 1703118377384911, 497810164760654, 101150811654673 } + }, + { + { 458346255946468, 290909935619344, 1452768413850679, 550922875254215, 1537286854336538 }, + { 584322311184395, 380661238802118, 114839394528060, 655082270500073, 2111856026034852 }, + { 996965581008991, 2148998626477022, 1012273164934654, 1073876063914522, 1688031788934939 } + }, + { + { 923487018849600, 2085106799623355, 528082801620136, 1606206360876188, 735907091712524 }, + { 1697697887804317, 1335343703828273, 831288615207040, 949416685250051, 288760277392022 }, + { 1419122478109648, 1325574567803701, 602393874111094, 2107893372601700, 1314159682671307 } + } +}, +{ /* 14/31 */ + { + { 2201150872731804, 2180241023425241, 97663456423163, 1633405770247824, 848945042443986 }, + { 1173339555550611, 818605084277583, 47521504364289, 924108720564965, 735423405754506 }, + { 830104860549448, 1886653193241086, 1600929509383773, 1475051275443631, 286679780900937 } + }, + { + { 1577111294832995, 1030899169768747, 144900916293530, 1964672592979567, 568390100955250 }, + { 278388655910247, 487143369099838, 927762205508727, 181017540174210, 1616886700741287 }, + { 1191033906638969, 940823957346562, 1606870843663445, 861684761499847, 658674867251089 } + }, + { + { 1875032594195546, 1427106132796197, 724736390962158, 901860512044740, 635268497268760 }, + { 622869792298357, 1903919278950367, 1922588621661629, 1520574711600434, 1087100760174640 }, + { 25465949416618, 1693639527318811, 1526153382657203, 125943137857169, 145276964043999 } + }, + { + { 214739857969358, 920212862967915, 1939901550972269, 1211862791775221, 85097515720120 }, + { 2006245852772938, 734762734836159, 254642929763427, 1406213292755966, 239303749517686 }, + { 1619678837192149, 1919424032779215, 1357391272956794, 1525634040073113, 1310226789796241 } + }, + { + { 1040763709762123, 1704449869235352, 605263070456329, 1998838089036355, 1312142911487502 }, + { 1996723311435669, 1844342766567060, 985455700466044, 1165924681400960, 311508689870129 }, + { 43173156290518, 2202883069785309, 1137787467085917, 1733636061944606, 1394992037553852 } + }, + { + { 670078326344559, 555655025059356, 471959386282438, 2141455487356409, 849015953823125 }, + { 2197214573372804, 794254097241315, 1030190060513737, 267632515541902, 2040478049202624 }, + { 1812516004670529, 1609256702920783, 1706897079364493, 258549904773295, 996051247540686 } + }, + { + { 1540374301420584, 1764656898914615, 1810104162020396, 923808779163088, 664390074196579 }, + { 1323460699404750, 1262690757880991, 871777133477900, 1060078894988977, 1712236889662886 }, + { 1696163952057966, 1391710137550823, 608793846867416, 1034391509472039, 1780770894075012 } + }, + { + { 1367603834210841, 2131988646583224, 890353773628144, 1908908219165595, 270836895252891 }, + { 597536315471731, 40375058742586, 1942256403956049, 1185484645495932, 312666282024145 }, + { 1919411405316294, 1234508526402192, 1066863051997083, 1008444703737597, 1348810787701552 } + } +}, +{ /* 15/31 */ + { + { 2102881477513865, 1570274565945361, 1573617900503708, 18662635732583, 2232324307922098 }, + { 1853931367696942, 8107973870707, 350214504129299, 775206934582587, 1752317649166792 }, + { 1417148368003523, 721357181628282, 505725498207811, 373232277872983, 261634707184480 } + }, + { + { 2186733281493267, 2250694917008620, 1014829812957440, 479998161452389, 83566193876474 }, + { 1268116367301224, 560157088142809, 802626839600444, 2210189936605713, 1129993785579988 }, + { 615183387352312, 917611676109240, 878893615973325, 978940963313282, 938686890583575 } + }, + { + { 522024729211672, 1045059315315808, 1892245413707790, 1907891107684253, 2059998109500714 }, + { 1799679152208884, 912132775900387, 25967768040979, 432130448590461, 274568990261996 }, + { 98698809797682, 2144627600856209, 1907959298569602, 811491302610148, 1262481774981493 } + }, + { + { 1791451399743152, 1713538728337276, 118349997257490, 1882306388849954, 158235232210248 }, + { 1217809823321928, 2173947284933160, 1986927836272325, 1388114931125539, 12686131160169 }, + { 1650875518872272, 1136263858253897, 1732115601395988, 734312880662190, 1252904681142109 } + }, + { + { 372986456113865, 525430915458171, 2116279931702135, 501422713587815, 1907002872974925 }, + { 803147181835288, 868941437997146, 316299302989663, 943495589630550, 571224287904572 }, + { 227742695588364, 1776969298667369, 628602552821802, 457210915378118, 2041906378111140 } + }, + { + { 815000523470260, 913085688728307, 1052060118271173, 1345536665214223, 541623413135555 }, + { 1580216071604333, 1877997504342444, 857147161260913, 703522726778478, 2182763974211603 }, + { 1870080310923419, 71988220958492, 1783225432016732, 615915287105016, 1035570475990230 } + }, + { + { 730987750830150, 857613889540280, 1083813157271766, 1002817255970169, 1719228484436074 }, + { 377616581647602, 1581980403078513, 804044118130621, 2034382823044191, 643844048472185 }, + { 176957326463017, 1573744060478586, 528642225008045, 1816109618372371, 1515140189765006 } + }, + { + { 1888911448245718, 1387110895611080, 1924503794066429, 1731539523700949, 2230378382645454 }, + { 443392177002051, 233793396845137, 2199506622312416, 1011858706515937, 974676837063129 }, + { 1846351103143623, 1949984838808427, 671247021915253, 1946756846184401, 1929296930380217 } + } +}, +{ /* 16/31 */ + { + { 849646212452002, 1410198775302919, 73767886183695, 1641663456615812, 762256272452411 }, + { 692017667358279, 723305578826727, 1638042139863265, 748219305990306, 334589200523901 }, + { 22893968530686, 2235758574399251, 1661465835630252, 925707319443452, 1203475116966621 } + }, + { + { 801299035785166, 1733292596726131, 1664508947088596, 467749120991922, 1647498584535623 }, + { 903105258014366, 427141894933047, 561187017169777, 1884330244401954, 1914145708422219 }, + { 1344191060517578, 1960935031767890, 1518838929955259, 1781502350597190, 1564784025565682 } + }, + { + { 673723351748086, 1979969272514923, 1175287312495508, 1187589090978666, 1881897672213940 }, + { 1917185587363432, 1098342571752737, 5935801044414, 2000527662351839, 1538640296181569 }, + { 2495540013192, 678856913479236, 224998292422872, 219635787698590, 1972465269000940 } + }, + { + { 271413961212179, 1353052061471651, 344711291283483, 2014925838520662, 2006221033113941 }, + { 194583029968109, 514316781467765, 829677956235672, 1676415686873082, 810104584395840 }, + { 1980510813313589, 1948645276483975, 152063780665900, 129968026417582, 256984195613935 } + }, + { + { 1860190562533102, 1936576191345085, 461100292705964, 1811043097042830, 957486749306835 }, + { 796664815624365, 1543160838872951, 1500897791837765, 1667315977988401, 599303877030711 }, + { 1151480509533204, 2136010406720455, 738796060240027, 319298003765044, 1150614464349587 } + }, + { + { 1731069268103150, 735642447616087, 1364750481334268, 417232839982871, 927108269127661 }, + { 1017222050227968, 1987716148359, 2234319589635701, 621282683093392, 2132553131763026 }, + { 1567828528453324, 1017807205202360, 565295260895298, 829541698429100, 307243822276582 } + }, + { + { 249079270936248, 1501514259790706, 947909724204848, 944551802437487, 552658763982480 }, + { 2089966982947227, 1854140343916181, 2151980759220007, 2139781292261749, 158070445864917 }, + { 1338766321464554, 1906702607371284, 1519569445519894, 115384726262267, 1393058953390992 } + }, + { + { 1364621558265400, 1512388234908357, 1926731583198686, 2041482526432505, 920401122333774 }, + { 1884844597333588, 601480070269079, 620203503079537, 1079527400117915, 1202076693132015 }, + { 840922919763324, 727955812569642, 1303406629750194, 522898432152867, 294161410441865 } + } +}, +{ /* 17/31 */ + { + { 353760790835310, 1598361541848743, 1122905698202299, 1922533590158905, 419107700666580 }, + { 359856369838236, 180914355488683, 861726472646627, 218807937262986, 575626773232501 }, + { 755467689082474, 909202735047934, 730078068932500, 936309075711518, 2007798262842972 } + }, + { + { 1609384177904073, 362745185608627, 1335318541768201, 800965770436248, 547877979267412 }, + { 984339177776787, 815727786505884, 1645154585713747, 1659074964378553, 1686601651984156 }, + { 1697863093781930, 599794399429786, 1104556219769607, 830560774794755, 12812858601017 } + }, + { + { 1168737550514982, 897832437380552, 463140296333799, 302564600022547, 2008360505135501 }, + { 1856930662813910, 678090852002597, 1920179140755167, 1259527833759868, 55540971895511 }, + { 1158643631044921, 476554103621892, 178447851439725, 1305025542653569, 103433927680625 } + }, + { + { 2176793111709008, 1576725716350391, 2009350167273523, 2012390194631546, 2125297410909580 }, + { 825403285195098, 2144208587560784, 1925552004644643, 1915177840006985, 1015952128947864 }, + { 1807108316634472, 1534392066433717, 347342975407218, 1153820745616376, 7375003497471 } + }, + { + { 983061001799725, 431211889901241, 2201903782961093, 817393911064341, 2214616493042167 }, + { 228567918409756, 865093958780220, 358083886450556, 159617889659320, 1360637926292598 }, + { 234147501399755, 2229469128637390, 2175289352258889, 1397401514549353, 1885288963089922 } + }, + { + { 1111762412951562, 252849572507389, 1048714233823341, 146111095601446, 1237505378776770 }, + { 1113790697840279, 1051167139966244, 1045930658550944, 2011366241542643, 1686166824620755 }, + { 1054097349305049, 1872495070333352, 182121071220717, 1064378906787311, 100273572924182 } + }, + { + { 1306410853171605, 1627717417672447, 50983221088417, 1109249951172250, 870201789081392 }, + { 104233794644221, 1548919791188248, 2224541913267306, 2054909377116478, 1043803389015153 }, + { 216762189468802, 707284285441622, 190678557969733, 973969342604308, 1403009538434867 } + }, + { + { 1279024291038477, 344776835218310, 273722096017199, 1834200436811442, 634517197663804 }, + { 343805853118335, 1302216857414201, 566872543223541, 2051138939539004, 321428858384280 }, + { 470067171324852, 1618629234173951, 2000092177515639, 7307679772789, 1117521120249968 } + } +}, +{ /* 18/31 */ + { + { 278151578291475, 1810282338562947, 1771599529530998, 1383659409671631, 685373414471841 }, + { 577009397403102, 1791440261786291, 2177643735971638, 174546149911960, 1412505077782326 }, + { 893719721537457, 1201282458018197, 1522349501711173, 58011597740583, 1130406465887139 } + }, + { + { 412607348255453, 1280455764199780, 2233277987330768, 14180080401665, 331584698417165 }, + { 262483770854550, 990511055108216, 526885552771698, 571664396646158, 354086190278723 }, + { 1820352417585487, 24495617171480, 1547899057533253, 10041836186225, 480457105094042 } + }, + { + { 2023310314989233, 637905337525881, 2106474638900687, 557820711084072, 1687858215057826 }, + { 1144168702609745, 604444390410187, 1544541121756138, 1925315550126027, 626401428894002 }, + { 1922168257351784, 2018674099908659, 1776454117494445, 956539191509034, 36031129147635 } + }, + { + { 544644538748041, 1039872944430374, 876750409130610, 710657711326551, 1216952687484972 }, + { 58242421545916, 2035812695641843, 2118491866122923, 1191684463816273, 46921517454099 }, + { 272268252444639, 1374166457774292, 2230115177009552, 1053149803909880, 1354288411641016 } + }, + { + { 1857910905368338, 1754729879288912, 885945464109877, 1516096106802166, 1602902393369811 }, + { 1193437069800958, 901107149704790, 999672920611411, 477584824802207, 364239578697845 }, + { 886299989548838, 1538292895758047, 1590564179491896, 1944527126709657, 837344427345298 } + }, + { + { 754558365378305, 1712186480903618, 1703656826337531, 750310918489786, 518996040250900 }, + { 1309847803895382, 1462151862813074, 211370866671570, 1544595152703681, 1027691798954090 }, + { 803217563745370, 1884799722343599, 1357706345069218, 2244955901722095, 730869460037413 } + }, + { + { 689299471295966, 1831210565161071, 1375187341585438, 1106284977546171, 1893781834054269 }, + { 696351368613042, 1494385251239250, 738037133616932, 636385507851544, 927483222611406 }, + { 1949114198209333, 1104419699537997, 783495707664463, 1747473107602770, 2002634765788641 } + }, + { + { 1607325776830197, 530883941415333, 1451089452727895, 1581691157083423, 496100432831154 }, + { 1068900648804224, 2006891997072550, 1134049269345549, 1638760646180091, 2055396084625778 }, + { 2222475519314561, 1870703901472013, 1884051508440561, 1344072275216753, 1318025677799069 } + } +}, +{ /* 19/31 */ + { + { 155711679280656, 681100400509288, 389811735211209, 2135723811340709, 408733211204125 }, + { 7813206966729, 194444201427550, 2071405409526507, 1065605076176312, 1645486789731291 }, + { 16625790644959, 1647648827778410, 1579910185572704, 436452271048548, 121070048451050 } + }, + { + { 1037263028552531, 568385780377829, 297953104144430, 1558584511931211, 2238221839292471 }, + { 190565267697443, 672855706028058, 338796554369226, 337687268493904, 853246848691734 }, + { 1763863028400139, 766498079432444, 1321118624818005, 69494294452268, 858786744165651 } + }, + { + { 1292056768563024, 1456632109855638, 1100631247050184, 1386133165675321, 1232898350193752 }, + { 366253102478259, 525676242508811, 1449610995265438, 1183300845322183, 185960306491545 }, + { 28315355815982, 460422265558930, 1799675876678724, 1969256312504498, 1051823843138725 } + }, + { + { 156914999361983, 1606148405719949, 1665208410108430, 317643278692271, 1383783705665320 }, + { 54684536365732, 2210010038536222, 1194984798155308, 535239027773705, 1516355079301361 }, + { 1484387703771650, 198537510937949, 2186282186359116, 617687444857508, 647477376402122 } + }, + { + { 2147715541830533, 500032538445817, 646380016884826, 352227855331122, 1488268620408052 }, + { 159386186465542, 1877626593362941, 618737197060512, 1026674284330807, 1158121760792685 }, + { 1744544377739822, 1964054180355661, 1685781755873170, 2169740670377448, 1286112621104591 } + }, + { + { 81977249784993, 1667943117713086, 1668983819634866, 1605016835177615, 1353960708075544 }, + { 1602253788689063, 439542044889886, 2220348297664483, 657877410752869, 157451572512238 }, + { 1029287186166717, 65860128430192, 525298368814832, 1491902500801986, 1461064796385400 } + }, + { + { 408216988729246, 2121095722306989, 913562102267595, 1879708920318308, 241061448436731 }, + { 1185483484383269, 1356339572588553, 584932367316448, 102132779946470, 1792922621116791 }, + { 1966196870701923, 2230044620318636, 1425982460745905, 261167817826569, 46517743394330 } + }, + { + { 107077591595359, 884959942172345, 27306869797400, 2224911448949390, 964352058245223 }, + { 1730194207717538, 431790042319772, 1831515233279467, 1372080552768581, 1074513929381760 }, + { 1450880638731607, 1019861580989005, 1229729455116861, 1174945729836143, 826083146840706 } + } +}, +{ /* 20/31 */ + { + { 1899935429242705, 1602068751520477, 940583196550370, 82431069053859, 1540863155745696 }, + { 2136688454840028, 2099509000964294, 1690800495246475, 1217643678575476, 828720645084218 }, + { 765548025667841, 462473984016099, 998061409979798, 546353034089527, 2212508972466858 } + }, + { + { 46575283771160, 892570971573071, 1281983193144090, 1491520128287375, 75847005908304 }, + { 1801436127943107, 1734436817907890, 1268728090345068, 167003097070711, 2233597765834956 }, + { 1997562060465113, 1048700225534011, 7615603985628, 1855310849546841, 2242557647635213 } + }, + { + { 1161017320376250, 492624580169043, 2169815802355237, 976496781732542, 1770879511019629 }, + { 1357044908364776, 729130645262438, 1762469072918979, 1365633616878458, 181282906404941 }, + { 1080413443139865, 1155205815510486, 1848782073549786, 622566975152580, 124965574467971 } + }, + { + { 1184526762066993, 247622751762817, 692129017206356, 820018689412496, 2188697339828085 }, + { 2020536369003019, 202261491735136, 1053169669150884, 2056531979272544, 778165514694311 }, + { 237404399610207, 1308324858405118, 1229680749538400, 720131409105291, 1958958863624906 } + }, + { + { 515583508038846, 17656978857189, 1717918437373989, 1568052070792483, 46975803123923 }, + { 281527309158085, 36970532401524, 866906920877543, 2222282602952734, 1289598729589882 }, + { 1278207464902042, 494742455008756, 1262082121427081, 1577236621659884, 1888786707293291 } + }, + { + { 353042527954210, 1830056151907359, 1111731275799225, 174960955838824, 404312815582675 }, + { 2064251142068628, 1666421603389706, 1419271365315441, 468767774902855, 191535130366583 }, + { 1716987058588002, 1859366439773457, 1767194234188234, 64476199777924, 1117233614485261 } + }, + { + { 984292135520292, 135138246951259, 2220652137473167, 1722843421165029, 190482558012909 }, + { 298845952651262, 1166086588952562, 1179896526238434, 1347812759398693, 1412945390096208 }, + { 1143239552672925, 906436640714209, 2177000572812152, 2075299936108548, 325186347798433 } + }, + { + { 721024854374772, 684487861263316, 1373438744094159, 2193186935276995, 1387043709851261 }, + { 418098668140962, 715065997721283, 1471916138376055, 2168570337288357, 937812682637044 }, + { 1043584187226485, 2143395746619356, 2209558562919611, 482427979307092, 847556718384018 } + } +}, +{ /* 21/31 */ + { + { 1248731221520759, 1465200936117687, 540803492710140, 52978634680892, 261434490176109 }, + { 1057329623869501, 620334067429122, 461700859268034, 2012481616501857, 297268569108938 }, + { 1055352180870759, 1553151421852298, 1510903185371259, 1470458349428097, 1226259419062731 } + }, + { + { 1492988790301668, 790326625573331, 1190107028409745, 1389394752159193, 1620408196604194 }, + { 47000654413729, 1004754424173864, 1868044813557703, 173236934059409, 588771199737015 }, + { 30498470091663, 1082245510489825, 576771653181956, 806509986132686, 1317634017056939 } + }, + { + { 420308055751555, 1493354863316002, 165206721528088, 1884845694919786, 2065456951573059 }, + { 1115636332012334, 1854340990964155, 83792697369514, 1972177451994021, 457455116057587 }, + { 1698968457310898, 1435137169051090, 1083661677032510, 938363267483709, 340103887207182 } + }, + { + { 1995325341336574, 911500251774648, 164010755403692, 855378419194762, 1573601397528842 }, + { 241719380661528, 310028521317150, 1215881323380194, 1408214976493624, 2141142156467363 }, + { 1315157046163473, 727368447885818, 1363466668108618, 1668921439990361, 1398483384337907 } + }, + { + { 75029678299646, 1015388206460473, 1849729037055212, 1939814616452984, 444404230394954 }, + { 2053597130993710, 2024431685856332, 2233550957004860, 2012407275509545, 872546993104440 }, + { 1217269667678610, 599909351968693, 1390077048548598, 1471879360694802, 739586172317596 } + }, + { + { 1718318639380794, 1560510726633958, 904462881159922, 1418028351780052, 94404349451937 }, + { 2132502667405250, 214379346175414, 1502748313768060, 1960071701057800, 1353971822643138 }, + { 319394212043702, 2127459436033571, 717646691535162, 663366796076914, 318459064945314 } + }, + { + { 405989424923593, 1960452633787083, 667349034401665, 1492674260767112, 1451061489880787 }, + { 947085906234007, 323284730494107, 1485778563977200, 728576821512394, 901584347702286 }, + { 1575783124125742, 2126210792434375, 1569430791264065, 1402582372904727, 1891780248341114 } + }, + { + { 838432205560695, 1997703511451664, 1018791879907867, 1662001808174331, 78328132957753 }, + { 739152638255629, 2074935399403557, 505483666745895, 1611883356514088, 628654635394878 }, + { 1822054032121349, 643057948186973, 7306757352712, 577249257962099, 284735863382083 } + } +}, +{ /* 22/31 */ + { + { 1366558556363930, 1448606567552086, 1478881020944768, 165803179355898, 1115718458123498 }, + { 204146226972102, 1630511199034723, 2215235214174763, 174665910283542, 956127674017216 }, + { 1562934578796716, 1070893489712745, 11324610642270, 958989751581897, 2172552325473805 } + }, + { + { 1770564423056027, 735523631664565, 1326060113795289, 1509650369341127, 65892421582684 }, + { 623682558650637, 1337866509471512, 990313350206649, 1314236615762469, 1164772974270275 }, + { 223256821462517, 723690150104139, 1000261663630601, 933280913953265, 254872671543046 } + }, + { + { 1969087237026041, 624795725447124, 1335555107635969, 2069986355593023, 1712100149341902 }, + { 1236103475266979, 1837885883267218, 1026072585230455, 1025865513954973, 1801964901432134 }, + { 1115241013365517, 1712251818829143, 2148864332502771, 2096001471438138, 2235017246626125 } + }, + { + { 1299268198601632, 2047148477845621, 2165648650132450, 1612539282026145, 514197911628890 }, + { 118352772338543, 1067608711804704, 1434796676193498, 1683240170548391, 230866769907437 }, + { 1850689576796636, 1601590730430274, 1139674615958142, 1954384401440257, 76039205311 } + }, + { + { 1723387471374172, 997301467038410, 533927635123657, 20928644693965, 1756575222802513 }, + { 2146711623855116, 503278928021499, 625853062251406, 1109121378393107, 1033853809911861 }, + { 571005965509422, 2005213373292546, 1016697270349626, 56607856974274, 914438579435146 } + }, + { + { 1346698876211176, 2076651707527589, 1084761571110205, 265334478828406, 1068954492309671 }, + { 1769967932677654, 1695893319756416, 1151863389675920, 1781042784397689, 400287774418285 }, + { 1851867764003121, 403841933237558, 820549523771987, 761292590207581, 1743735048551143 } + }, + { + { 410915148140008, 2107072311871739, 1004367461876503, 99684895396761, 1180818713503224 }, + { 285945406881439, 648174397347453, 1098403762631981, 1366547441102991, 1505876883139217 }, + { 672095903120153, 1675918957959872, 636236529315028, 1569297300327696, 2164144194785875 } + }, + { + { 1902708175321798, 1035343530915438, 1178560808893263, 301095684058146, 1280977479761118 }, + { 1615357281742403, 404257611616381, 2160201349780978, 1160947379188955, 1578038619549541 }, + { 2013087639791217, 822734930507457, 1785668418619014, 1668650702946164, 389450875221715 } + } +}, +{ /* 23/31 */ + { + { 453918449698368, 106406819929001, 2072540975937135, 308588860670238, 1304394580755385 }, + { 1295082798350326, 2091844511495996, 1851348972587817, 3375039684596, 789440738712837 }, + { 2083069137186154, 848523102004566, 993982213589257, 1405313299916317, 1532824818698468 } + }, + { + { 1495961298852430, 1397203457344779, 1774950217066942, 139302743555696, 66603584342787 }, + { 1782411379088302, 1096724939964781, 27593390721418, 542241850291353, 1540337798439873 }, + { 693543956581437, 171507720360750, 1557908942697227, 1074697073443438, 1104093109037196 } + }, + { + { 345288228393419, 1099643569747172, 134881908403743, 1740551994106740, 248212179299770 }, + { 231429562203065, 1526290236421172, 2021375064026423, 1520954495658041, 806337791525116 }, + { 1079623667189886, 872403650198613, 766894200588288, 2163700860774109, 2023464507911816 } + }, + { + { 854645372543796, 1936406001954827, 151460662541253, 825325739271555, 1554306377287556 }, + { 1497138821904622, 1044820250515590, 1742593886423484, 1237204112746837, 849047450816987 }, + { 667962773375330, 1897271816877105, 1399712621683474, 1143302161683099, 2081798441209593 } + }, + { + { 127147851567005, 1936114012888110, 1704424366552046, 856674880716312, 716603621335359 }, + { 1072409664800960, 2146937497077528, 1508780108920651, 935767602384853, 1112800433544068 }, + { 333549023751292, 280219272863308, 2104176666454852, 1036466864875785, 536135186520207 } + }, + { + { 373666279883137, 146457241530109, 304116267127857, 416088749147715, 1258577131183391 }, + { 1186115062588401, 2251609796968486, 1098944457878953, 1153112761201374, 1791625503417267 }, + { 1870078460219737, 2129630962183380, 852283639691142, 292865602592851, 401904317342226 } + }, + { + { 1361070124828035, 815664541425524, 1026798897364671, 1951790935390647, 555874891834790 }, + { 1546301003424277, 459094500062839, 1097668518375311, 1780297770129643, 720763293687608 }, + { 1212405311403990, 1536693382542438, 61028431067459, 1863929423417129, 1223219538638038 } + }, + { + { 1294303766540260, 1183557465955093, 882271357233093, 63854569425375, 2213283684565087 }, + { 339050984211414, 601386726509773, 413735232134068, 966191255137228, 1839475899458159 }, + { 235605972169408, 2174055643032978, 1538335001838863, 1281866796917192, 1815940222628465 } + } +}, +{ /* 24/31 */ + { + { 1632352921721536, 1833328609514701, 2092779091951987, 1923956201873226, 2210068022482919 }, + { 35271216625062, 1712350667021807, 983664255668860, 98571260373038, 1232645608559836 }, + { 1998172393429622, 1798947921427073, 784387737563581, 1589352214827263, 1589861734168180 } + }, + { + { 1733739258725305, 31715717059538, 201969945218860, 992093044556990, 1194308773174556 }, + { 846415389605137, 746163495539180, 829658752826080, 592067705956946, 957242537821393 }, + { 1758148849754419, 619249044817679, 168089007997045, 1371497636330523, 1867101418880350 } + }, + { + { 326633984209635, 261759506071016, 1700682323676193, 1577907266349064, 1217647663383016 }, + { 1714182387328607, 1477856482074168, 574895689942184, 2159118410227270, 1555532449716575 }, + { 853828206885131, 998498946036955, 1835887550391235, 207627336608048, 258363815956050 } + }, + { + { 141141474651677, 1236728744905256, 643101419899887, 1646615130509173, 1208239602291765 }, + { 1501663228068911, 1354879465566912, 1444432675498247, 897812463852601, 855062598754348 }, + { 714380763546606, 1032824444965790, 1774073483745338, 1063840874947367, 1738680636537158 } + }, + { + { 1640635546696252, 633168953192112, 2212651044092396, 30590958583852, 368515260889378 }, + { 1171650314802029, 1567085444565577, 1453660792008405, 757914533009261, 1619511342778196 }, + { 420958967093237, 971103481109486, 2169549185607107, 1301191633558497, 1661514101014240 } + }, + { + { 907123651818302, 1332556122804146, 1824055253424487, 1367614217442959, 1982558335973172 }, + { 1121533090144639, 1021251337022187, 110469995947421, 1511059774758394, 2110035908131662 }, + { 303213233384524, 2061932261128138, 352862124777736, 40828818670255, 249879468482660 } + }, + { + { 856559257852200, 508517664949010, 1378193767894916, 1723459126947129, 1962275756614521 }, + { 1445691340537320, 40614383122127, 402104303144865, 485134269878232, 1659439323587426 }, + { 20057458979482, 1183363722525800, 2140003847237215, 2053873950687614, 2112017736174909 } + }, + { + { 2228654250927986, 1483591363415267, 1368661293910956, 1076511285177291, 526650682059608 }, + { 709481497028540, 531682216165724, 316963769431931, 1814315888453765, 258560242424104 }, + { 1053447823660455, 1955135194248683, 1010900954918985, 1182614026976701, 1240051576966610 } + } +}, +{ /* 25/31 */ + { + { 1957943897155497, 1788667368028035, 137692910029106, 1039519607062, 826404763313028 }, + { 1848942433095597, 1582009882530495, 1849292741020143, 1068498323302788, 2001402229799484 }, + { 1528282417624269, 2142492439828191, 2179662545816034, 362568973150328, 1591374675250271 } + }, + { + { 160026679434388, 232341189218716, 2149181472355545, 598041771119831, 183859001910173 }, + { 2013278155187349, 662660471354454, 793981225706267, 411706605985744, 804490933124791 }, + { 2051892037280204, 488391251096321, 2230187337030708, 930221970662692, 679002758255210 } + }, + { + { 1530723630438670, 875873929577927, 341560134269988, 449903119530753, 1055551308214179 }, + { 1461835919309432, 1955256480136428, 180866187813063, 1551979252664528, 557743861963950 }, + { 359179641731115, 1324915145732949, 902828372691474, 294254275669987, 1887036027752957 } + }, + { + { 2043271609454323, 2038225437857464, 1317528426475850, 1398989128982787, 2027639881006861 }, + { 2072902725256516, 312132452743412, 309930885642209, 996244312618453, 1590501300352303 }, + { 1397254305160710, 695734355138021, 2233992044438756, 1776180593969996, 1085588199351115 } + }, + { + { 440567051331029, 254894786356681, 493869224930222, 1556322069683366, 1567456540319218 }, + { 1950722461391320, 1907845598854797, 1822757481635527, 2121567704750244, 73811931471221 }, + { 387139307395758, 2058036430315676, 1220915649965325, 1794832055328951, 1230009312169328 } + }, + { + { 1765973779329517, 659344059446977, 19821901606666, 1301928341311214, 1116266004075885 }, + { 1127572801181483, 1224743760571696, 1276219889847274, 1529738721702581, 1589819666871853 }, + { 2181229378964934, 2190885205260020, 1511536077659137, 1246504208580490, 668883326494241 } + }, + { + { 437866655573314, 669026411194768, 81896997980338, 523874406393178, 245052060935236 }, + { 1975438052228868, 1071801519999806, 594652299224319, 1877697652668809, 1489635366987285 }, + { 958592545673770, 233048016518599, 851568750216589, 567703851596087, 1740300006094761 } + }, + { + { 2014540178270324, 192672779514432, 213877182641530, 2194819933853411, 1716422829364835 }, + { 1540769606609725, 2148289943846077, 1597804156127445, 1230603716683868, 815423458809453 }, + { 1738560251245018, 1779576754536888, 1783765347671392, 1880170990446751, 1088225159617541 } + } +}, +{ /* 26/31 */ + { + { 659303913929492, 1956447718227573, 1830568515922666, 841069049744408, 1669607124206368 }, + { 1143465490433355, 1532194726196059, 1093276745494697, 481041706116088, 2121405433561163 }, + { 1686424298744462, 1451806974487153, 266296068846582, 1834686947542675, 1720762336132256 } + }, + { + { 889217026388959, 1043290623284660, 856125087551909, 1669272323124636, 1603340330827879 }, + { 1206396181488998, 333158148435054, 1402633492821422, 1120091191722026, 1945474114550509 }, + { 766720088232571, 1512222781191002, 1189719893490790, 2091302129467914, 2141418006894941 } + }, + { + { 419663647306612, 1998875112167987, 1426599870253707, 1154928355379510, 486538532138187 }, + { 938160078005954, 1421776319053174, 1941643234741774, 180002183320818, 1414380336750546 }, + { 398001940109652, 1577721237663248, 1012748649830402, 1540516006905144, 1011684812884559 } + }, + { + { 1653276489969630, 6081825167624, 1921777941170836, 1604139841794531, 861211053640641 }, + { 996661541407379, 1455877387952927, 744312806857277, 139213896196746, 1000282908547789 }, + { 1450817495603008, 1476865707053229, 1030490562252053, 620966950353376, 1744760161539058 } + }, + { + { 559728410002599, 37056661641185, 2038622963352006, 1637244893271723, 1026565352238948 }, + { 962165956135846, 1116599660248791, 182090178006815, 1455605467021751, 196053588803284 }, + { 796863823080135, 1897365583584155, 420466939481601, 2165972651724672, 932177357788289 } + }, + { + { 877047233620632, 1375632631944375, 643773611882121, 660022738847877, 19353932331831 }, + { 2216943882299338, 394841323190322, 2222656898319671, 558186553950529, 1077236877025190 }, + { 801118384953213, 1914330175515892, 574541023311511, 1471123787903705, 1526158900256288 } + }, + { + { 949617889087234, 2207116611267331, 912920039141287, 501158539198789, 62362560771472 }, + { 1474518386765335, 1760793622169197, 1157399790472736, 1622864308058898, 165428294422792 }, + { 1961673048027128, 102619413083113, 1051982726768458, 1603657989805485, 1941613251499678 } + }, + { + { 1401939116319266, 335306339903072, 72046196085786, 862423201496006, 850518754531384 }, + { 1234706593321979, 1083343891215917, 898273974314935, 1640859118399498, 157578398571149 }, + { 1143483057726416, 1992614991758919, 674268662140796, 1773370048077526, 674318359920189 } + } +}, +{ /* 27/31 */ + { + { 1835401379538542, 173900035308392, 818247630716732, 1762100412152786, 1021506399448291 }, + { 1506632088156630, 2127481795522179, 513812919490255, 140643715928370, 442476620300318 }, + { 2056683376856736, 219094741662735, 2193541883188309, 1841182310235800, 556477468664293 } + }, + { + { 1315019427910827, 1049075855992603, 2066573052986543, 266904467185534, 2040482348591520 }, + { 94096246544434, 922482381166992, 24517828745563, 2139430508542503, 2097139044231004 }, + { 537697207950515, 1399352016347350, 1563663552106345, 2148749520888918, 549922092988516 } + }, + { + { 1747985413252434, 680511052635695, 1809559829982725, 594274250930054, 201673170745982 }, + { 323583936109569, 1973572998577657, 1192219029966558, 79354804385273, 1374043025560347 }, + { 213277331329947, 416202017849623, 1950535221091783, 1313441578103244, 2171386783823658 } + }, + { + { 189088804229831, 993969372859110, 895870121536987, 1547301535298256, 1477373024911350 }, + { 1620578418245010, 541035331188469, 2235785724453865, 2154865809088198, 1974627268751826 }, + { 1346805451740245, 1350981335690626, 942744349501813, 2155094562545502, 1012483751693409 } + }, + { + { 2107080134091762, 1132567062788208, 1824935377687210, 769194804343737, 1857941799971888 }, + { 1074666112436467, 249279386739593, 1174337926625354, 1559013532006480, 1472287775519121 }, + { 1872620123779532, 1892932666768992, 1921559078394978, 1270573311796160, 1438913646755037 } + }, + { + { 837390187648199, 1012253300223599, 989780015893987, 1351393287739814, 328627746545550 }, + { 1028328827183114, 1711043289969857, 1350832470374933, 1923164689604327, 1495656368846911 }, + { 1900828492104143, 430212361082163, 687437570852799, 832514536673512, 1685641495940794 } + }, + { + { 842632847936398, 605670026766216, 290836444839585, 163210774892356, 2213815011799645 }, + { 1176336383453996, 1725477294339771, 12700622672454, 678015708818208, 162724078519879 }, + { 1448049969043497, 1789411762943521, 385587766217753, 90201620913498, 832999441066823 } + }, + { + { 516086333293313, 2240508292484616, 1351669528166508, 1223255565316488, 750235824427138 }, + { 1263624896582495, 1102602401673328, 526302183714372, 2152015839128799, 1483839308490010 }, + { 442991718646863, 1599275157036458, 1925389027579192, 899514691371390, 350263251085160 } + } +}, +{ /* 28/31 */ + { + { 1689713572022143, 593854559254373, 978095044791970, 1985127338729499, 1676069120347625 }, + { 1557207018622683, 340631692799603, 1477725909476187, 614735951619419, 2033237123746766 }, + { 968764929340557, 1225534776710944, 662967304013036, 1155521416178595, 791142883466590 } + }, + { + { 1487081286167458, 993039441814934, 1792378982844640, 698652444999874, 2153908693179754 }, + { 1123181311102823, 685575944875442, 507605465509927, 1412590462117473, 568017325228626 }, + { 560258797465417, 2193971151466401, 1824086900849026, 579056363542056, 1690063960036441 } + }, + { + { 1918407319222416, 353767553059963, 1930426334528099, 1564816146005724, 1861342381708096 }, + { 2131325168777276, 1176636658428908, 1756922641512981, 1390243617176012, 1966325177038383 }, + { 2063958120364491, 2140267332393533, 699896251574968, 273268351312140, 375580724713232 } + }, + { + { 2024297515263178, 416959329722687, 1079014235017302, 171612225573183, 1031677520051053 }, + { 2033900009388450, 1744902869870788, 2190580087917640, 1949474984254121, 231049754293748 }, + { 343868674606581, 550155864008088, 1450580864229630, 481603765195050, 896972360018042 } + }, + { + { 2151139328380127, 314745882084928, 59756825775204, 1676664391494651, 2048348075599360 }, + { 1528930066340597, 1605003907059576, 1055061081337675, 1458319101947665, 1234195845213142 }, + { 830430507734812, 1780282976102377, 1425386760709037, 362399353095425, 2168861579799910 } + }, + { + { 1155762232730333, 980662895504006, 2053766700883521, 490966214077606, 510405877041357 }, + { 1683750316716132, 652278688286128, 1221798761193539, 1897360681476669, 319658166027343 }, + { 618808732869972, 72755186759744, 2060379135624181, 1730731526741822, 48862757828238 } + }, + { + { 1463171970593505, 1143040711767452, 614590986558883, 1409210575145591, 1882816996436803 }, + { 2230133264691131, 563950955091024, 2042915975426398, 827314356293472, 672028980152815 }, + { 264204366029760, 1654686424479449, 2185050199932931, 2207056159091748, 506015669043634 } + }, + { + { 1784446333136569, 1973746527984364, 334856327359575, 1156769775884610, 1023950124675478 }, + { 2065270940578383, 31477096270353, 306421879113491, 181958643936686, 1907105536686083 }, + { 1496516440779464, 1748485652986458, 872778352227340, 818358834654919, 97932669284220 } + } +}, +{ /* 29/31 */ + { + { 471636015770351, 672455402793577, 1804995246884103, 1842309243470804, 1501862504981682 }, + { 1013216974933691, 538921919682598, 1915776722521558, 1742822441583877, 1886550687916656 }, + { 2094270000643336, 303971879192276, 40801275554748, 649448917027930, 1818544418535447 } + }, + { + { 2241737709499165, 549397817447461, 838180519319392, 1725686958520781, 1705639080897747 }, + { 1216074541925116, 50120933933509, 1565829004133810, 721728156134580, 349206064666188 }, + { 948617110470858, 346222547451945, 1126511960599975, 1759386906004538, 493053284802266 } + }, + { + { 1454933046815146, 874696014266362, 1467170975468588, 1432316382418897, 2111710746366763 }, + { 2105387117364450, 1996463405126433, 1303008614294500, 851908115948209, 1353742049788635 }, + { 750300956351719, 1487736556065813, 15158817002104, 1511998221598392, 971739901354129 } + }, + { + { 1874648163531693, 2124487685930551, 1810030029384882, 918400043048335, 586348627300650 }, + { 1235084464747900, 1166111146432082, 1745394857881591, 1405516473883040, 4463504151617 }, + { 1663810156463827, 327797390285791, 1341846161759410, 1964121122800605, 1747470312055380 } + }, + { + { 660005247548233, 2071860029952887, 1358748199950107, 911703252219107, 1014379923023831 }, + { 2206641276178231, 1690587809721504, 1600173622825126, 2156096097634421, 1106822408548216 }, + { 1344788193552206, 1949552134239140, 1735915881729557, 675891104100469, 1834220014427292 } + }, + { + { 1920949492387964, 158885288387530, 70308263664033, 626038464897817, 1468081726101009 }, + { 622221042073383, 1210146474039168, 1742246422343683, 1403839361379025, 417189490895736 }, + { 22727256592983, 168471543384997, 1324340989803650, 1839310709638189, 504999476432775 } + }, + { + { 1313240518756327, 1721896294296942, 52263574587266, 2065069734239232, 804910473424630 }, + { 1337466662091884, 1287645354669772, 2018019646776184, 652181229374245, 898011753211715 }, + { 1969792547910734, 779969968247557, 2011350094423418, 1823964252907487, 1058949448296945 } + }, + { + { 207343737062002, 1118176942430253, 758894594548164, 806764629546266, 1157700123092949 }, + { 1273565321399022, 1638509681964574, 759235866488935, 666015124346707, 897983460943405 }, + { 1717263794012298, 1059601762860786, 1837819172257618, 1054130665797229, 680893204263559 } + } +}, +{ /* 30/31 */ + { + { 2237039662793603, 2249022333361206, 2058613546633703, 149454094845279, 2215176649164582 }, + { 79472182719605, 1851130257050174, 1825744808933107, 821667333481068, 781795293511946 }, + { 755822026485370, 152464789723500, 1178207602290608, 410307889503239, 156581253571278 } + }, + { + { 1418185496130297, 484520167728613, 1646737281442950, 1401487684670265, 1349185550126961 }, + { 1495380034400429, 325049476417173, 46346894893933, 1553408840354856, 828980101835683 }, + { 1280337889310282, 2070832742866672, 1640940617225222, 2098284908289951, 450929509534434 } + }, + { + { 407703353998781, 126572141483652, 286039827513621, 1999255076709338, 2030511179441770 }, + { 1254958221100483, 1153235960999843, 942907704968834, 637105404087392, 1149293270147267 }, + { 894249020470196, 400291701616810, 406878712230981, 1599128793487393, 1145868722604026 } + }, + { + { 1497955250203334, 110116344653260, 1128535642171976, 1900106496009660, 129792717460909 }, + { 452487513298665, 1352120549024569, 1173495883910956, 1999111705922009, 367328130454226 }, + { 1717539401269642, 1475188995688487, 891921989653942, 836824441505699, 1885988485608364 } + }, + { + { 1241784121422547, 187337051947583, 1118481812236193, 428747751936362, 30358898927325 }, + { 2022432361201842, 1088816090685051, 1977843398539868, 1854834215890724, 564238862029357 }, + { 938868489100585, 1100285072929025, 1017806255688848, 1957262154788833, 152787950560442 } + }, + { + { 867319417678923, 620471962942542, 226032203305716, 342001443957629, 1761675818237336 }, + { 1295072362439987, 931227904689414, 1355731432641687, 922235735834035, 892227229410209 }, + { 1680989767906154, 535362787031440, 2136691276706570, 1942228485381244, 1267350086882274 } + }, + { + { 366018233770527, 432660629755596, 126409707644535, 1973842949591662, 645627343442376 }, + { 535509430575217, 546885533737322, 1524675609547799, 2138095752851703, 1260738089896827 }, + { 1159906385590467, 2198530004321610, 714559485023225, 81880727882151, 1484020820037082 } + }, + { + { 1377485731340769, 2046328105512000, 1802058637158797, 62146136768173, 1356993908853901 }, + { 2013612215646735, 1830770575920375, 536135310219832, 609272325580394, 270684344495013 }, + { 1237542585982777, 2228682050256790, 1385281931622824, 593183794882890, 493654978552689 } + } +}, +{ /* 31/31 */ + { + { 47341488007760, 1891414891220257, 983894663308928, 176161768286818, 1126261115179708 }, + { 1694030170963455, 502038567066200, 1691160065225467, 949628319562187, 275110186693066 }, + { 1124515748676336, 1661673816593408, 1499640319059718, 1584929449166988, 558148594103306 } + }, + { + { 1784525599998356, 1619698033617383, 2097300287550715, 258265458103756, 1905684794832758 }, + { 1288941072872766, 931787902039402, 190731008859042, 2006859954667190, 1005931482221702 }, + { 1465551264822703, 152905080555927, 680334307368453, 173227184634745, 666407097159852 } + }, + { + { 2111017076203943, 1378760485794347, 1248583954016456, 1352289194864422, 1895180776543896 }, + { 171348223915638, 662766099800389, 462338943760497, 466917763340314, 656911292869115 }, + { 488623681976577, 866497561541722, 1708105560937768, 1673781214218839, 1506146329818807 } + }, + { + { 160425464456957, 950394373239689, 430497123340934, 711676555398832, 320964687779005 }, + { 988979367990485, 1359729327576302, 1301834257246029, 294141160829308, 29348272277475 }, + { 1434382743317910, 100082049942065, 221102347892623, 186982837860588, 1305765053501834 } + }, + { + { 2205916462268190, 499863829790820, 961960554686616, 158062762756985, 1841471168298305 }, + { 1191737341426592, 1847042034978363, 1382213545049056, 1039952395710448, 788812858896859 }, + { 1346965964571152, 1291881610839830, 2142916164336056, 786821641205979, 1571709146321039 } + }, + { + { 787164375951248, 202869205373189, 1356590421032140, 1431233331032510, 786341368775957 }, + { 492448143532951, 304105152670757, 1761767168301056, 233782684697790, 1981295323106089 }, + { 665807507761866, 1343384868355425, 895831046139653, 439338948736892, 1986828765695105 } + }, + { + { 756096210874553, 1721699973539149, 258765301727885, 1390588532210645, 1212530909934781 }, + { 852891097972275, 1816988871354562, 1543772755726524, 1174710635522444, 202129090724628 }, + { 1205281565824323, 22430498399418, 992947814485516, 1392458699738672, 688441466734558 } + }, + { + { 1050627428414972, 1955849529137135, 2171162376368357, 91745868298214, 447733118757826 }, + { 1287181461435438, 622722465530711, 880952150571872, 741035693459198, 311565274989772 }, + { 1003649078149734, 545233927396469, 1849786171789880, 1318943684880434, 280345687170552 } + } +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_51/base2.h b/third_party/heimdal/lib/hcrypto/x25519/fe_51/base2.h new file mode 100644 index 0000000..d088241 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_51/base2.h @@ -0,0 +1,40 @@ +{ + { 1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563 }, + { 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585 }, + { 301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142 } +}, +{ + { 1601611775252272, 1720807796594148, 1132070835939856, 1260455018889551, 2147779492816911 }, + { 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597 }, + { 1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707 } +}, +{ + { 769950342298419, 132954430919746, 844085933195555, 974092374476333, 726076285546016 }, + { 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893 }, + { 1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339 } +}, +{ + { 665000864555967, 2065379846933859, 370231110385876, 350988370788628, 1233371373142985 }, + { 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113 }, + { 965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601 } +}, +{ + { 1802695059465007, 1664899123557221, 593559490740857, 2160434469266659, 927570450755031 }, + { 1725674970513508, 1933645953859181, 1542344539275782, 1767788773573747, 1297447965928905 }, + { 1381809363726107, 1430341051343062, 2061843536018959, 1551778050872521, 2036394857967624 } +}, +{ + { 1970894096313054, 528066325833207, 1619374932191227, 2207306624415883, 1169170329061080 }, + { 2070390218572616, 1458919061857835, 624171843017421, 1055332792707765, 433987520732508 }, + { 893653801273833, 1168026499324677, 1242553501121234, 1306366254304474, 1086752658510815 } +}, +{ + { 213454002618221, 939771523987438, 1159882208056014, 317388369627517, 621213314200687 }, + { 1971678598905747, 338026507889165, 762398079972271, 655096486107477, 42299032696322 }, + { 177130678690680, 1754759263300204, 1864311296286618, 1180675631479880, 1292726903152791 } +}, +{ + { 1913163449625248, 460779200291993, 2193883288642314, 1008900146920800, 1721983679009502 }, + { 1070401523076875, 1272492007800961, 1910153608563310, 2075579521696771, 1191169788841221 }, + { 692896803108118, 500174642072499, 2068223309439677, 1162190621851337, 1426986007309901 } +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_51/constants.h b/third_party/heimdal/lib/hcrypto/x25519/fe_51/constants.h new file mode 100644 index 0000000..24e5cb5 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_51/constants.h @@ -0,0 +1,41 @@ +/* 37095705934669439343138083508754565189542113879843219016388785533085940283555 */ +static const fe25519 d = { + 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 +}; + +/* 2 * d = + * 16295367250680780974490674513165176452449235426866156013048779062215315747161 + */ +static const fe25519 d2 = { + 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 +}; + +/* sqrt(-1) */ +static const fe25519 sqrtm1 = { + 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 +}; + +/* A = 486662 */ +static const fe25519 curve25519_A = { + 486662, 0, 0, 0, 0 +}; + +/* sqrt(ad - 1) with a = -1 (mod p) */ +static const fe25519 sqrtadm1 = { + 2241493124984347, 425987919032274, 2207028919301688, 1220490630685848, 974799131293748 +}; + +/* 1 / sqrt(a - d) */ +static const fe25519 invsqrtamd = { + 278908739862762, 821645201101625, 8113234426968, 1777959178193151, 2118520810568447 +}; + +/* 1 - d ^ 2 */ +static const fe25519 onemsqd = { + 1136626929484150, 1998550399581263, 496427632559748, 118527312129759, 45110755273534 +}; + +/* (d - 1) ^ 2 */ +static const fe25519 sqdmone = { + 1507062230895904, 1572317787530805, 683053064812840, 317374165784489, 1572899562415810 +}; diff --git a/third_party/heimdal/lib/hcrypto/x25519/fe_51/fe.h b/third_party/heimdal/lib/hcrypto/x25519/fe_51/fe.h new file mode 100644 index 0000000..de87626 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/fe_51/fe.h @@ -0,0 +1,116 @@ +/* + Ignores top bit of h. + */ + +void +fe25519_frombytes(fe25519 h, const unsigned char *s) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint64_t h0, h1, h2, h3, h4; + + h0 = (LOAD64_LE(s ) ) & mask; + h1 = (LOAD64_LE(s + 6) >> 3) & mask; + h2 = (LOAD64_LE(s + 12) >> 6) & mask; + h3 = (LOAD64_LE(s + 19) >> 1) & mask; + h4 = (LOAD64_LE(s + 24) >> 12) & mask; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +static void +fe25519_reduce(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t t[5]; + + t[0] = f[0]; + t[1] = f[1]; + t[2] = f[2]; + t[3] = f[3]; + t[4] = f[4]; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19 * (t[4] >> 51); + t[4] &= mask; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19 * (t[4] >> 51); + t[4] &= mask; + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + + t[0] += 19ULL; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19ULL * (t[4] >> 51); + t[4] &= mask; + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + + t[0] += 0x8000000000000 - 19ULL; + t[1] += 0x8000000000000 - 1ULL; + t[2] += 0x8000000000000 - 1ULL; + t[3] += 0x8000000000000 - 1ULL; + t[4] += 0x8000000000000 - 1ULL; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[4] &= mask; + + h[0] = t[0]; + h[1] = t[1]; + h[2] = t[2]; + h[3] = t[3]; + h[4] = t[4]; +} + +void +fe25519_tobytes(unsigned char *s, const fe25519 h) +{ + fe25519 t; + uint64_t t0, t1, t2, t3; + + fe25519_reduce(t, h); + t0 = t[0] | (t[1] << 51); + t1 = (t[1] >> 13) | (t[2] << 38); + t2 = (t[2] >> 26) | (t[3] << 25); + t3 = (t[3] >> 39) | (t[4] << 12); + STORE64_LE(s + 0, t0); + STORE64_LE(s + 8, t1); + STORE64_LE(s + 16, t2); + STORE64_LE(s + 24, t3); +} diff --git a/third_party/heimdal/lib/hcrypto/x25519/x25519_ref10.c b/third_party/heimdal/lib/hcrypto/x25519/x25519_ref10.c new file mode 100644 index 0000000..d6fced7 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519/x25519_ref10.c @@ -0,0 +1,209 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "ed25519_ref10.h" +#include "x25519_ref10.h" +#include "align.h" + +/* + * Reject small order points early to mitigate the implications of + * unexpected optimizations that would affect the ref10 code. + * See https://eprint.iacr.org/2017/806.pdf for reference. + */ +static int +has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + /* 0 (order 4) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 1 (order 1) */ + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 325606250916557431795983626356110631294008115727848805560023387167927233504 + (order 8) */ + { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, + 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, + 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 }, + /* 39382357235489614581723060781553021112529911719440698176882885853963445705823 + (order 8) */ + { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, + 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, + 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 }, + /* p-1 (order 2) */ + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p (=0, order 4) */ + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p+1 (=1, order 1) */ + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } + }; + unsigned char c[7] = { 0 }; + unsigned int k; + size_t i, j; + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + + COMPILER_ASSERT(7 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 31; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= (s[j] & 0x7f) ^ blacklist[i][j]; + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +static int +crypto_scalarmult_curve25519_ref10(unsigned char *q, + const unsigned char *n, + const unsigned char *p) +{ + unsigned char *t = q; + unsigned int i; + fe25519 x1; + fe25519 x2; + fe25519 z2; + fe25519 x3; + fe25519 z3; + fe25519 tmp0; + fe25519 tmp1; + int pos; + unsigned int swap; + unsigned int b; + + if (has_small_order(p)) { + return -1; + } + for (i = 0; i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + fe25519_frombytes(x1, p); + fe25519_1(x2); + fe25519_0(z2); + fe25519_copy(x3, x1); + fe25519_1(z3); + + swap = 0; + for (pos = 254; pos >= 0; --pos) { + b = t[pos / 8] >> (pos & 7); + b &= 1; + swap ^= b; + fe25519_cswap(x2, x3, swap); + fe25519_cswap(z2, z3, swap); + swap = b; + fe25519_sub(tmp0, x3, z3); + fe25519_sub(tmp1, x2, z2); + fe25519_add(x2, x2, z2); + fe25519_add(z2, x3, z3); + fe25519_mul(z3, tmp0, x2); + fe25519_mul(z2, z2, tmp1); + fe25519_sq(tmp0, tmp1); + fe25519_sq(tmp1, x2); + fe25519_add(x3, z3, z2); + fe25519_sub(z2, z3, z2); + fe25519_mul(x2, tmp1, tmp0); + fe25519_sub(tmp1, tmp1, tmp0); + fe25519_sq(z2, z2); + fe25519_scalar_product(z3, tmp1, 121666); + fe25519_sq(x3, x3); + fe25519_add(tmp0, tmp0, z3); + fe25519_mul(z3, x1, z2); + fe25519_mul(z2, tmp1, tmp0); + } + fe25519_cswap(x2, x3, swap); + fe25519_cswap(z2, z3, swap); + + fe25519_invert(z2, z2); + fe25519_mul(x2, x2, z2); + fe25519_tobytes(q, x2); + + return 0; +} + +static void +edwards_to_montgomery(fe25519 montgomeryX, const fe25519 edwardsY, const fe25519 edwardsZ) +{ + fe25519 tempX; + fe25519 tempZ; + + fe25519_add(tempX, edwardsZ, edwardsY); + fe25519_sub(tempZ, edwardsZ, edwardsY); + fe25519_invert(tempZ, tempZ); + fe25519_mul(montgomeryX, tempX, tempZ); +} + +int +crypto_scalarmult_curve25519_base(unsigned char *q, + const unsigned char *n) +{ + unsigned char *t = q; + ge25519_p3 A; + fe25519 pk; + unsigned int i; + + for (i = 0; i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + ge25519_scalarmult_base(&A, t); + edwards_to_montgomery(pk, A.Y, A.Z); + fe25519_tobytes(q, pk); + + return 0; +} + +int +crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + size_t i; + volatile unsigned char d = 0; + + if (crypto_scalarmult_curve25519_ref10(q, n, p) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + for (i = 0; i < crypto_scalarmult_curve25519_BYTES; i++) { + d |= q[i]; + } + return -(1 & ((d - 1) >> 8)); +} + diff --git a/third_party/heimdal/lib/hcrypto/x25519_ref10.h b/third_party/heimdal/lib/hcrypto/x25519_ref10.h new file mode 100644 index 0000000..f43cc02 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/x25519_ref10.h @@ -0,0 +1,55 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef x25519_ref10_H +#define x25519_ref10_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_scalarmult_curve25519_BYTES 32U +size_t crypto_scalarmult_curve25519_bytes(void); + +#define crypto_scalarmult_curve25519_SCALARBYTES 32U +size_t crypto_scalarmult_curve25519_scalarbytes(void); + +/* + * NOTE: Do not use the result of this function directly for key exchange. + * + * Hash the result with the public keys in order to compute a shared + * secret key: H(q || client_pk || server_pk) + * + * Or unless this is not an option, use the crypto_kx() API instead. + */ +#define crypto_scalarmult_curve25519 hc_hcrypto_scalarmult_curve25519 +int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, + const unsigned char *p); + +#define crypto_scalarmult_curve25519_base hc_hcrypto_scalarmult_curve25519_base +int crypto_scalarmult_curve25519_base(unsigned char *q, + const unsigned char *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/heimdal/lib/hdb/Makefile.am b/third_party/heimdal/lib/hdb/Makefile.am new file mode 100644 index 0000000..4a55995 --- /dev/null +++ b/third_party/heimdal/lib/hdb/Makefile.am @@ -0,0 +1,170 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 +AM_CPPFLAGS += $(INCLUDE_openldap) -DHDB_DB_DIR=\"$(DIR_hdbdir)\" +AM_CPPFLAGS += -I$(srcdir)/../krb5 +AM_CPPFLAGS += $(INCLUDE_sqlite3) +AM_CPPFLAGS += $(INCLUDE_libintl) +AM_CPPFLAGS += -DHDB_DEFAULT_DB_TYPE=\"$(db_type):\" +if HAVE_DBHEADER +AM_CPPFLAGS += -I$(DBHEADER) +endif + +BUILT_SOURCES = \ + $(gen_files_hdb) \ + hdb_err.c \ + hdb_err.h \ + $(srcdir)/hdb-protos.h \ + $(srcdir)/hdb-private.h + +gen_files_hdb = \ + asn1_Event.c \ + asn1_GENERATION.c \ + asn1_HDB_EncTypeList.c \ + asn1_HDB_Ext_Aliases.c \ + asn1_HDB_Ext_Constrained_delegation_acl.c \ + asn1_HDB_Ext_KeyRotation.c \ + asn1_HDB_Ext_KeySet.c \ + asn1_HDB_Ext_Lan_Manager_OWF.c \ + asn1_HDB_Ext_Password.c \ + asn1_HDB_Ext_PKINIT_acl.c \ + asn1_HDB_Ext_PKINIT_cert.c \ + asn1_HDB_Ext_PKINIT_hash.c \ + asn1_HDB_EntryOrAlias.c \ + asn1_HDB_entry_alias.c \ + asn1_HDB_entry.c \ + asn1_HDB_extension.c \ + asn1_HDB_extensions.c \ + asn1_HDB_keyset.c \ + asn1_HDBFlags.c \ + asn1_Key.c \ + asn1_KeyRotation.c \ + asn1_KeyRotationFlags.c \ + asn1_Keys.c \ + asn1_Salt.c + +CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \ + hdb_asn1{,-priv}.h hdb_asn1_files hdb_asn1-template.c \ + hdb_asn1_syms.c hdb_asn1_oids.c hdb_asn1.json \ + testhdb-* + +LDADD = libhdb.la \ + ../krb5/libkrb5.la \ + ../asn1/libasn1.la \ + $(LIB_hcrypto) \ + $(LIB_roken) \ + $(LIB_openldap) \ + $(LIB_libintl) \ + $(LIB_ldopen) + + +if OPENLDAP_MODULE + +ldap_so = hdb_ldap.la +hdb_ldap_la_SOURCES = hdb-ldap.c +hdb_ldap_la_LDFLAGS = -module -avoid-version +hdb_ldap_la_LIBADD = $(LIB_openldap) libhdb.la + +else + +ldap = hdb-ldap.c +ldap_lib = $(LIB_openldap) + +endif + + +lib_LTLIBRARIES = libhdb.la $(ldap_so) +libhdb_la_LDFLAGS = -version-info 11:0:2 + +if versionscript +libhdb_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +# test_hdbkeys and test_mkey are not tests -- they are manual test utils +noinst_PROGRAMS = test_dbinfo test_hdbkeys test_mkey test_namespace test_concurrency +TESTS = test_dbinfo test_namespace test_concurrency + +dist_libhdb_la_SOURCES = \ + common.c \ + db.c \ + db3.c \ + ext.c \ + $(ldap) \ + hdb.c \ + hdb-sqlite.c \ + hdb-keytab.c \ + hdb-mdb.c \ + hdb-mitdb.c \ + hdb_locl.h \ + keys.c \ + keytab.c \ + dbinfo.c \ + mkey.c \ + ndbm.c \ + print.c + +nodist_libhdb_la_SOURCES = $(BUILT_SOURCES) + +libhdb_la_DEPENDENCIES = version-script.map + +include_HEADERS = hdb.h $(srcdir)/hdb-protos.h +nodist_include_HEADERS = hdb_err.h hdb_asn1.h + +noinst_HEADERS = $(srcdir)/hdb-private.h + +libhdb_la_LIBADD = \ + $(LIB_com_err) \ + ../krb5/libkrb5.la \ + ../asn1/libasn1.la \ + $(LIB_sqlite3) \ + $(LIBADD_roken) \ + $(ldap_lib) \ + $(LIB_dlopen) \ + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) + +HDB_PROTOS = $(srcdir)/hdb-protos.h $(srcdir)/hdb-private.h + +ALL_OBJECTS = $(libhdb_la_OBJECTS) +ALL_OBJECTS += $(test_dbinfo_OBJECTS) +ALL_OBJECTS += $(test_hdbkeys_OBJECTS) +ALL_OBJECTS += $(test_mkey_OBJECTS) +ALL_OBJECTS += $(test_namespace_OBJECTS) +ALL_OBJECTS += $(test_concurrency_OBJECTS) + +$(ALL_OBJECTS): $(HDB_PROTOS) hdb_asn1.h hdb_asn1-priv.h hdb_err.h + +test_namespace_LDADD = $(LDADD) $(test_hdbkeys_LIBS) $(LIB_heimbase) + +$(srcdir)/hdb-protos.h: $(dist_libhdb_la_SOURCES) + cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -o hdb-protos.h $(dist_libhdb_la_SOURCES) || rm -f hdb-protos.h + +$(srcdir)/hdb-private.h: $(dist_libhdb_la_SOURCES) + cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p hdb-private.h $(dist_libhdb_la_SOURCES) || rm -f hdb-private.h + +$(gen_files_hdb) hdb_asn1.h hdb_asn1-priv.h: hdb_asn1_files + for genfile in '$(gen_files_hdb)'; do \ + $(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $${genfile}; \ + done + +hdb_asn1_files: $(ASN1_COMPILE_DEP) $(srcdir)/hdb.asn1 + $(ASN1_COMPILE) --option-file=$(srcdir)/hdb.opt $(srcdir)/hdb.asn1 hdb_asn1 + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i $$(cat hdb_asn1_files) + +# to help stupid solaris make + +hdb_err.h: hdb_err.et + +EXTRA_DIST = \ + NTMakefile \ + libhdb-version.rc \ + libhdb-exports.def \ + hdb.asn1 \ + hdb_err.et \ + hdb.schema \ + version-script.map \ + data-mkey.mit.des3.le \ + data-mkey.mit.des3.be diff --git a/third_party/heimdal/lib/hdb/NTMakefile b/third_party/heimdal/lib/hdb/NTMakefile new file mode 100644 index 0000000..f4801f7 --- /dev/null +++ b/third_party/heimdal/lib/hdb/NTMakefile @@ -0,0 +1,189 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\hdb + +intcflags=-DASN1_LIB + +!include ../../windows/NTMakefile.w32 + +$(OBJ)\asn1_hdb_asn1.c $(OBJ)\hdb_asn1.h $(OBJ)\hdb_asn1-priv.h: $(BINDIR)\asn1_compile.exe hdb.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --one-code-file --option-file=$(SRCDIR)\hdb.opt $(SRCDIR)\hdb.asn1 hdb_asn1 + cd $(SRCDIR) + +!ifdef OPENLDAP_MODULE + +ldap_dll = $(BINDIR)\hdb_ldap.dll +ldap_lib = $(LIBDIR)\hdb_ldap.lib +ldap_objs = $(OBJ)\hdb-ldap.obj + +$(ldap_dll): $(ldap_objs) + $(DLLGUILINK) -implib:$(ldap_lib) + $(DLLPREP) + +clean:: + -$(RM) $(ldap_dll) + -$(RM) $(ldap_lib) + +!else + +ldap = $(OBJ)\hdb-ldap.obj +ldap_c = hdb-ldap.c + +!endif + +dist_libhdb_la_SOURCES = \ + common.c \ + db.c \ + db3.c \ + ext.c \ + $(ldap_c) \ + hdb.c \ + hdb-sqlite.c \ + hdb-keytab.c \ + hdb-mitdb.c \ + hdb-mdb.c \ + hdb_locl.h \ + keys.c \ + keytab.c \ + dbinfo.c \ + mkey.c \ + ndbm.c \ + print.c + +libhdb_OBJs = \ + $(OBJ)\common.obj \ + $(OBJ)\db.obj \ + $(OBJ)\db3.obj \ + $(OBJ)\ext.obj \ + $(ldap) \ + $(OBJ)\hdb.obj \ + $(OBJ)\hdb-sqlite.obj \ + $(OBJ)\hdb-keytab.obj \ + $(OBJ)\hdb-mitdb.obj \ + $(OBJ)\keys.obj \ + $(OBJ)\keytab.obj \ + $(OBJ)\dbinfo.obj \ + $(OBJ)\mkey.obj \ + $(OBJ)\ndbm.obj \ + $(OBJ)\print.obj \ + $(OBJ)\asn1_hdb_asn1.obj \ + $(OBJ)\hdb_err.obj + +$(OBJ)\hdb_err.c $(OBJ)\hdb_err.h: hdb_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\hdb_err.et + cd $(SRCDIR) + +$(OBJ)\hdb-protos.h: $(dist_libhdb_la_SOURCES) + $(PERL) ../../cf/make-proto.pl -q -P remove -o $@ $(dist_libhdb_la_SOURCES) \ + || $(RM) $@ + +$(OBJ)\hdb-private.h: $(dist_libhdb_la_SOURCES) + $(PERL) ../../cf/make-proto.pl -q -P remote -p $@ $(dist_libhdb_la_SOURCES) \ + || $(RM) $@ + +INCFILES= \ + $(INCDIR)\hdb.h \ + $(INCDIR)\hdb-protos.h \ + $(OBJ)\hdb-private.h \ + $(INCDIR)\hdb_err.h \ + $(INCDIR)\hdb_asn1.h \ + $(INCDIR)\hdb_asn1-priv.h + +!ifndef STATICLIBS + +RES=$(OBJ)\libhdb-version.res + +$(LIBHDB): $(BINDIR)\libhdb.dll + +$(BINDIR)\libhdb.dll: $(libhdb_OBJs) $(ldap_lib) $(LIBHEIMBASE) $(LIBHEIMDAL) $(LIBSQLITE) $(LIBCOMERR) $(LIBROKEN) $(RES) + $(DLLGUILINK) -def:libhdb-exports.def -implib:$(LIBHDB) + $(DLLPREP_NODIST) + +clean:: + -$(RM) $(BINDIR)\libhdb.* + +!else + +$(LIBHDB): $(libhdb_OBJs) $(ldap_lib) + $(LIBCON) + +!endif + +all:: $(INCFILES) $(LIBHDB) + +clean:: + -$(RM) $(INCFILES) + -$(RM) $(LIBHDB) + +test:: test-binaries test-run + +test-binaries: $(OBJ)\test_dbinfo.exe $(OBJ)\test_hdbkeys.exe $(OBJ)\test_namespace.exe + +$(OBJ)\test_dbinfo.exe: $(OBJ)\test_dbinfo.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_hdbkeys.exe: $(OBJ)\test_hdbkeys.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_namespace.exe: $(OBJ)\test_namespace.obj $(LIBHDB) $(LIBHEIMDAL) $(LIBHEIMBASE) $(LIBROKEN) $(LIBVERS) + $(EXECONLINK) + $(EXEPREP_NODIST) + +test-run: + cd $(OBJ) + -test_dbinfo.exe + -test_hdbkeys.exe + -test_namespace.exe + cd $(SRCDIR) + +!ifdef OPENLDAP_INC +openldap_inc_flag=-I$(OPENLDAP_INC) +!else +openldap_inc_flag= +!endif + +hdb_cflags=$(openldap_inc_flag) -I$(OBJ) + +{}.c{$(OBJ)}.obj:: + $(C2OBJ_P) $(hdb_cflags) -DASN1_LIB + +{$(OBJ)}.c{$(OBJ)}.obj:: + $(C2OBJ_P) $(hdb_cflags) + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libhdb-exports.def + +test:: test-exports diff --git a/third_party/heimdal/lib/hdb/common.c b/third_party/heimdal/lib/hdb/common.c new file mode 100644 index 0000000..3b8c7c5 --- /dev/null +++ b/third_party/heimdal/lib/hdb/common.c @@ -0,0 +1,1906 @@ +/* + * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include "hdb_locl.h" + +int +hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key) +{ + Principal new; + size_t len = 0; + int ret; + + ret = copy_Principal(p, &new); + if(ret) + return ret; + new.name.name_type = 0; + + ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret); + if (ret == 0 && key->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + free_Principal(&new); + return ret; +} + +int +hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p) +{ + return decode_Principal(key->data, key->length, p, NULL); +} + +int +hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value) +{ + size_t len = 0; + int ret; + + ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret); + if (ret == 0 && value->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + return ret; +} + +int +hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent) +{ + return decode_HDB_entry(value->data, value->length, ent, NULL); +} + +int +hdb_entry_alias2value(krb5_context context, + const hdb_entry_alias *alias, + krb5_data *value) +{ + size_t len = 0; + int ret; + + ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length, + alias, &len, ret); + if (ret == 0 && value->length != len) + krb5_abortx(context, "internal asn.1 encoder error"); + return ret; +} + +int +hdb_value2entry_alias(krb5_context context, krb5_data *value, + hdb_entry_alias *ent) +{ + return decode_HDB_entry_alias(value->data, value->length, ent, NULL); +} + +/* + * Some old databases may not have stored the salt with each key, which will + * break clients when aliases or canonicalization are used. Generate a + * default salt based on the real principal name in the entry to handle + * this case. + */ +static krb5_error_code +add_default_salts(krb5_context context, HDB *db, hdb_entry *entry) +{ + krb5_error_code ret; + size_t i; + krb5_salt pwsalt; + + ret = krb5_get_pw_salt(context, entry->principal, &pwsalt); + if (ret) + return ret; + + for (i = 0; i < entry->keys.len; i++) { + Key *key = &entry->keys.val[i]; + + if (key->salt != NULL || + _krb5_enctype_requires_random_salt(context, key->key.keytype)) + continue; + + key->salt = calloc(1, sizeof(*key->salt)); + if (key->salt == NULL) { + ret = krb5_enomem(context); + break; + } + + key->salt->type = KRB5_PADATA_PW_SALT; + + ret = krb5_data_copy(&key->salt->salt, + pwsalt.saltvalue.data, + pwsalt.saltvalue.length); + if (ret) + break; + } + + krb5_free_salt(context, pwsalt); + + return ret; +} + +static krb5_error_code +fetch_entry_or_alias(krb5_context context, + HDB *db, + krb5_const_principal principal, + unsigned flags, + hdb_entry *entry) +{ + HDB_EntryOrAlias eoa; + krb5_principal enterprise_principal = NULL; + krb5_data key, value; + krb5_error_code ret; + + value.length = 0; + value.data = 0; + key = value; + + if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + if (principal->name.name_string.len != 1) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, "malformed principal: " + "enterprise name with %d name components", + principal->name.name_string.len); + return ret; + } + ret = krb5_parse_name(context, principal->name.name_string.val[0], + &enterprise_principal); + if (ret) + return ret; + principal = enterprise_principal; + } + + ret = hdb_principal2key(context, principal, &key); + if (ret == 0) + ret = db->hdb__get(context, db, key, &value); + if (ret == 0) + ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); + if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) { + *entry = eoa.u.entry; + entry->aliased = 0; + } else if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias) { + krb5_data_free(&key); + ret = hdb_principal2key(context, eoa.u.alias.principal, &key); + if (ret == 0) { + krb5_data_free(&value); + ret = db->hdb__get(context, db, key, &value); + } + if (ret == 0) + /* No alias chaining */ + ret = hdb_value2entry(context, &value, entry); + krb5_free_principal(context, eoa.u.alias.principal); + entry->aliased = 1; + } else if (ret == 0) + ret = ENOTSUP; + if (ret == 0 && enterprise_principal) { + /* + * Whilst Windows does not canonicalize enterprise principal names if + * the canonicalize flag is unset, the original specification in + * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should. + */ + entry->flags.force_canonicalize = 1; + } + +#if 0 + /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */ + if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias && + (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) { + + /* `principal' was alias but canon not req'd */ + free_HDB_entry(entry); + ret = HDB_ERR_NOENTRY; + } +#endif + + krb5_free_principal(context, enterprise_principal); + krb5_data_free(&value); + krb5_data_free(&key); + principal = enterprise_principal = NULL; + return ret; +} + +/* + * We have only one type of aliases in our HDB entries, but we really need two: + * hard and soft. + * + * Hard aliases should be treated as if they were distinct principals with the + * same keys. + * + * Soft aliases should be treated as configuration to issue referrals, and they + * can only result in referrals to other realms. + * + * Rather than add a type of aliases, we'll use a convention where the form of + * the target of the alias indicates whether the alias is hard or soft. + * + * TODO We could also use an attribute of the aliased entry. + */ +static int +is_soft_alias_p(krb5_context context, + krb5_const_principal principal, + unsigned int flags, + hdb_entry *h) +{ + /* Target is a WELLKNOWN/REFERRALS/TARGET/... -> soft alias */ + if (krb5_principal_get_num_comp(context, h->principal) >= 3 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 0), + KRB5_WELLKNOWN_NAME) == 0 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 1), + "REFERRALS") == 0 && + strcmp(krb5_principal_get_comp_string(context, h->principal, 2), + "TARGET") == 0) + return 1; + + /* + * Pre-8.0 we had only soft aliases for a while, and one site used aliases + * of referrals-targetNN@TARGET-REALM. + */ + if (krb5_principal_get_num_comp(context, h->principal) == 1 && + strncmp("referrals-target", + krb5_principal_get_comp_string(context, h->principal, 0), + sizeof("referrals-target") - 1) == 0) + return 1; + + /* All other cases are hard aliases */ + return 0; +} + +krb5_error_code +_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry *entry) +{ + krb5_error_code ret; + int soft_aliased = 0; + int same_realm; + + ret = fetch_entry_or_alias(context, db, principal, flags, entry); + if (ret) + return ret; + + if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) { + /* Decrypt the current keys */ + ret = hdb_unseal_keys(context, db, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + /* Decrypt the key history too */ + ret = hdb_unseal_keys_kvno(context, db, 0, flags, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } else if ((flags & HDB_F_DECRYPT)) { + if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->kvno) { + /* Decrypt the current keys */ + ret = hdb_unseal_keys(context, db, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } else { + if ((flags & HDB_F_ALL_KVNOS)) + kvno = 0; + /* + * Find and decrypt the keys from the history that we want, + * and swap them with the current keys + */ + ret = hdb_unseal_keys_kvno(context, db, kvno, flags, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } + } + if ((flags & HDB_F_FOR_AS_REQ) && (flags & HDB_F_GET_CLIENT)) { + /* + * Generate default salt for any principals missing one; note such + * principals could include those for which a random (non-password) + * key was generated, but given the salt will be ignored by a keytab + * client it doesn't hurt to include the default salt. + */ + ret = add_default_salts(context, db, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } + + if (!entry->aliased) + return 0; + + soft_aliased = is_soft_alias_p(context, principal, flags, entry); + + /* Never return HDB_ERR_WRONG_REALM to kadm5 or other non-KDC callers */ + if ((flags & HDB_F_ADMIN_DATA)) + return 0; + + same_realm = krb5_realm_compare(context, principal, entry->principal); + + if (entry->aliased && !soft_aliased) { + /* + * This is a hard alias. We'll make the entry's name be the same as + * the alias. + * + * Except, we allow for disabling this for same-realm aliases, mainly + * for our tests. + */ + if (same_realm && + krb5_config_get_bool_default(context, NULL, FALSE, "hdb", + "same_realm_aliases_are_soft", NULL)) + return 0; + + /* EPNs are always soft */ + if (principal->name.name_type != KRB5_NT_ENTERPRISE_PRINCIPAL) { + krb5_free_principal(context, entry->principal); + ret = krb5_copy_principal(context, principal, &entry->principal); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } + return 0; + } + + /* Same realm -> not a referral, therefore this is a hard alias */ + if (same_realm) { + if (soft_aliased) { + /* Soft alias to the same realm?! No. */ + hdb_free_entry(context, db, entry); + return HDB_ERR_NOENTRY; + } + return 0; + } + + /* Not same realm && not hard alias */ + return HDB_ERR_WRONG_REALM; +} + +static krb5_error_code +hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) +{ + const HDB_Ext_Aliases *aliases; + krb5_error_code code; + hdb_entry oldentry; + krb5_data value; + size_t i; + + code = db->hdb__get(context, db, *key, &value); + if (code == HDB_ERR_NOENTRY) + return 0; + else if (code) + return code; + + code = hdb_value2entry(context, &value, &oldentry); + krb5_data_free(&value); + if (code) + return code; + + code = hdb_entry_get_aliases(&oldentry, &aliases); + if (code || aliases == NULL) { + free_HDB_entry(&oldentry); + return code; + } + for (i = 0; i < aliases->aliases.len; i++) { + krb5_data akey; + + code = hdb_principal2key(context, &aliases->aliases.val[i], &akey); + if (code == 0) { + code = db->hdb__del(context, db, akey); + krb5_data_free(&akey); + if (code == HDB_ERR_NOENTRY) + code = 0; + } + if (code) { + free_HDB_entry(&oldentry); + return code; + } + } + free_HDB_entry(&oldentry); + return 0; +} + +static krb5_error_code +hdb_add_aliases(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry) +{ + const HDB_Ext_Aliases *aliases; + krb5_error_code code; + krb5_data key, value; + size_t i; + + code = hdb_entry_get_aliases(entry, &aliases); + if (code || aliases == NULL) + return code; + + for (i = 0; i < aliases->aliases.len; i++) { + hdb_entry_alias entryalias; + entryalias.principal = entry->principal; + + code = hdb_entry_alias2value(context, &entryalias, &value); + if (code) + return code; + + code = hdb_principal2key(context, &aliases->aliases.val[i], &key); + if (code == 0) { + code = db->hdb__put(context, db, flags, key, value); + krb5_data_free(&key); + if (code == HDB_ERR_EXISTS) + /* + * Assuming hdb_check_aliases() was called, this must be a + * duplicate in the alias list. + */ + code = 0; + } + krb5_data_free(&value); + if (code) + return code; + } + return 0; +} + +/* Check if new aliases are already used for other entries */ +static krb5_error_code +hdb_check_aliases(krb5_context context, HDB *db, hdb_entry *entry) +{ + const HDB_Ext_Aliases *aliases = NULL; + HDB_EntryOrAlias eoa; + krb5_data akey, value; + size_t i; + int ret; + + memset(&eoa, 0, sizeof(eoa)); + krb5_data_zero(&value); + akey = value; + + ret = hdb_entry_get_aliases(entry, &aliases); + for (i = 0; ret == 0 && aliases && i < aliases->aliases.len; i++) { + ret = hdb_principal2key(context, &aliases->aliases.val[i], &akey); + if (ret == 0) + ret = db->hdb__get(context, db, akey, &value); + if (ret == 0) + ret = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); + if (ret == 0 && eoa.element != choice_HDB_EntryOrAlias_entry && + eoa.element != choice_HDB_EntryOrAlias_alias) + ret = ENOTSUP; + if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_entry) + /* New alias names an existing non-alias entry in the HDB */ + ret = HDB_ERR_EXISTS; + if (ret == 0 && eoa.element == choice_HDB_EntryOrAlias_alias && + !krb5_principal_compare(context, eoa.u.alias.principal, + entry->principal)) + /* New alias names an existing alias of a different entry */ + ret = HDB_ERR_EXISTS; + if (ret == HDB_ERR_NOENTRY) /* from db->hdb__get */ + /* New alias is a name that doesn't exist in the HDB */ + ret = 0; + + free_HDB_EntryOrAlias(&eoa); + krb5_data_free(&value); + krb5_data_free(&akey); + } + return ret; +} + +/* + * Many HDB entries don't have `etypes' setup. Historically we use the + * enctypes of the selected keyset as the entry's supported enctypes, but that + * is problematic. By doing this at store time and, if need be, at fetch time, + * we can make sure to stop deriving supported etypes from keys in the long + * run. We also need kadm5/kadmin support for etypes. We'll use this function + * there to derive etypes when using a kadm5_principal_ent_t that lacks the new + * TL data for etypes. + */ +krb5_error_code +hdb_derive_etypes(krb5_context context, hdb_entry *e, HDB_Ext_KeySet *base_keys) +{ + krb5_error_code ret = 0; + size_t i, k, netypes; + HDB_extension *ext; + + if (!base_keys && + (ext = hdb_find_extension(e, choice_HDB_extension_data_hist_keys))) + base_keys = &ext->data.u.hist_keys; + + netypes = e->keys.len; + if (netypes == 0 && base_keys) { + /* There's no way that base_keys->val[i].keys.len == 0, but hey */ + for (i = 0; netypes == 0 && i < base_keys->len; i++) + netypes = base_keys->val[i].keys.len; + } + + if (netypes == 0) + return 0; + + if (e->etypes != NULL) { + free(e->etypes->val); + e->etypes->len = 0; + e->etypes->val = 0; + } else if ((e->etypes = calloc(1, sizeof(e->etypes[0]))) == NULL) { + ret = krb5_enomem(context); + } + if (ret == 0 && + (e->etypes->val = calloc(netypes, sizeof(e->etypes->val[0]))) == NULL) + ret = krb5_enomem(context); + if (ret) { + free(e->etypes); + e->etypes = 0; + return ret; + } + e->etypes->len = netypes; + for (i = 0; i < e->keys.len && i < netypes; i++) + e->etypes->val[i] = e->keys.val[i].key.keytype; + if (!base_keys || i) + return 0; + for (k = 0; i == 0 && k < base_keys->len; k++) { + if (!base_keys->val[k].keys.len) + continue; + for (; i < base_keys->val[k].keys.len; i++) + e->etypes->val[i] = base_keys->val[k].keys.val[i].key.keytype; + } + return 0; +} + +krb5_error_code +_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + krb5_data key, value; + int code; + + if (entry->flags.do_not_store || + entry->flags.force_canonicalize) + return HDB_ERR_MISUSE; + /* check if new aliases already is used */ + code = hdb_check_aliases(context, db, entry); + if (code) + return code; + + if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE)) + return 0; + + if ((flags & HDB_F_PRECHECK)) { + code = hdb_principal2key(context, entry->principal, &key); + if (code) + return code; + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code == 0) + krb5_data_free(&value); + if (code == HDB_ERR_NOENTRY) + return 0; + return code ? code : HDB_ERR_EXISTS; + } + + if ((entry->etypes == NULL || entry->etypes->len == 0) && + (code = hdb_derive_etypes(context, entry, NULL))) + return code; + + if (entry->generation == NULL) { + struct timeval t; + entry->generation = malloc(sizeof(*entry->generation)); + if(entry->generation == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + gettimeofday(&t, NULL); + entry->generation->time = t.tv_sec; + entry->generation->usec = t.tv_usec; + entry->generation->gen = 0; + } else + entry->generation->gen++; + + code = hdb_seal_keys(context, db, entry); + if (code) + return code; + + code = hdb_principal2key(context, entry->principal, &key); + if (code) + return code; + + /* remove aliases */ + code = hdb_remove_aliases(context, db, &key); + if (code) { + krb5_data_free(&key); + return code; + } + code = hdb_entry2value(context, entry, &value); + if (code == 0) + code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value); + krb5_data_free(&value); + krb5_data_free(&key); + if (code) + return code; + + code = hdb_add_aliases(context, db, flags, entry); + + return code; +} + +krb5_error_code +_hdb_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) +{ + krb5_data key, value; + HDB_EntryOrAlias eoa; + int is_alias = -1; + int code; + + /* + * We only allow deletion of entries by canonical name. To remove an + * alias use kadm5_modify_principal(). + * + * We need to determine if this is an alias. We decode as a + * HDB_EntryOrAlias, which is expensive -- we could decode as a + * HDB_entry_alias instead and assume it's an entry if decoding fails... + */ + + code = hdb_principal2key(context, principal, &key); + if (code == 0) + code = db->hdb__get(context, db, key, &value); + if (code == 0) { + code = decode_HDB_EntryOrAlias(value.data, value.length, &eoa, NULL); + krb5_data_free(&value); + } + if (code == 0) { + is_alias = eoa.element == choice_HDB_EntryOrAlias_entry ? 0 : 1; + free_HDB_EntryOrAlias(&eoa); + } + + if ((flags & HDB_F_PRECHECK)) { + if (code == 0 && is_alias) + krb5_set_error_message(context, code = HDB_ERR_NOENTRY, + "Cannot delete alias of principal"); + krb5_data_free(&key); + return code; + } + + if (code == 0) + code = hdb_remove_aliases(context, db, &key); + if (code == 0) + code = db->hdb__del(context, db, key); + krb5_data_free(&key); + return code; +} + +/* PRF+(K_base, pad, keylen(etype)) */ +static krb5_error_code +derive_Key1(krb5_context context, + krb5_data *pad, + EncryptionKey *base, + krb5int32 etype, + EncryptionKey *nk) +{ + krb5_error_code ret; + krb5_crypto crypto = NULL; + krb5_data out; + size_t len; + + out.data = 0; + out.length = 0; + + ret = krb5_enctype_keysize(context, base->keytype, &len); + if (ret == 0) + ret = krb5_crypto_init(context, base, 0, &crypto); + if (ret == 0) + ret = krb5_crypto_prfplus(context, crypto, pad, len, &out); + if (crypto) + krb5_crypto_destroy(context, crypto); + if (ret == 0) + ret = krb5_random_to_key(context, etype, out.data, out.length, nk); + krb5_data_free(&out); + return ret; +} + +/* PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) */ +/* XXX Make it PRF+(PRF+(K_base, princ, keylen(K_base.etype)), and lift it, kvno, keylen(etype)) */ +static krb5_error_code +derive_Key(krb5_context context, + const char *princ, + krb5uint32 kvno, + EncryptionKey *base, + krb5int32 etype, + Key *nk) +{ + krb5_error_code ret = 0; + EncryptionKey intermediate; + krb5_data pad; + + nk->salt = NULL; + nk->mkvno = NULL; + nk->key.keytype = 0; + nk->key.keyvalue.data = 0; + nk->key.keyvalue.length = 0; + + intermediate.keytype = 0; + intermediate.keyvalue.data = 0; + intermediate.keyvalue.length = 0; + if (princ) { + /* Derive intermediate key for the given principal */ + /* XXX Lift to optimize? */ + pad.data = (void *)(uintptr_t)princ; + pad.length = strlen(princ); + ret = derive_Key1(context, &pad, base, etype, &intermediate); + if (ret == 0) + base = &intermediate; + } /* else `base' is already an intermediate key for the desired princ */ + + /* Derive final key for `kvno' from intermediate key */ + kvno = htonl(kvno); + pad.data = &kvno; + pad.length = sizeof(kvno); + if (ret == 0) + ret = derive_Key1(context, &pad, base, etype, &nk->key); + free_EncryptionKey(&intermediate); + return ret; +} + +/* + * PRF+(PRF+(K_base, princ, keylen(etype)), kvno, keylen(etype)) for one + * enctype. + */ +static krb5_error_code +derive_Keys(krb5_context context, + const char *princ, + krb5uint32 kvno, + krb5int32 etype, + const Keys *base, + Keys *dk) + +{ + krb5_error_code ret = 0; + size_t i; + Key nk; + + dk->len = 0; + dk->val = 0; + + /* + * The enctypes of the base keys is the list of enctypes to derive keys + * for. Still, we derive all keys from the first base key. + */ + for (i = 0; ret == 0 && i < base->len; i++) { + if (etype != KRB5_ENCTYPE_NULL && etype != base->val[i].key.keytype) + continue; + ret = derive_Key(context, princ, kvno, &base->val[0].key, + base->val[i].key.keytype, &nk); + if (ret) + break; + ret = add_Keys(dk, &nk); + free_Key(&nk); + /* + * FIXME We need to finish kdc/kadm5/kadmin support for the `etypes' so + * we can reduce the number of keys in keytabs to just those in current + * use and only of *one* enctype. + * + * What we could do is derive *one* key and for the others output a + * one-byte key of the intended enctype (which will never work). + * + * We'll never need any keys but the first one... + */ + } + + if (ret) + free_Keys(dk); + return ret; +} + +/* Helper for derive_keys_for_kr() */ +static krb5_error_code +derive_keyset(krb5_context context, + const Keys *base_keys, + const char *princ, + krb5int32 etype, + krb5uint32 kvno, + KerberosTime set_time, /* "now" */ + hdb_keyset *dks) +{ + dks->kvno = kvno; + dks->keys.val = 0; + dks->set_time = malloc(sizeof(*(dks->set_time))); + if (dks->set_time == NULL) + return krb5_enomem(context); + *dks->set_time = set_time; + return derive_Keys(context, princ, kvno, etype, base_keys, &dks->keys); +} + +/* Possibly derive and install in `h' a keyset identified by `t' */ +static krb5_error_code +derive_keys_for_kr(krb5_context context, + hdb_entry *h, + HDB_Ext_KeySet *base_keys, + int is_current_keyset, + int rotation_period_offset, + const char *princ, + krb5int32 etype, + krb5uint32 kvno_wanted, + KerberosTime t, + struct KeyRotation *krp) +{ + krb5_error_code ret; + hdb_keyset dks; + KerberosTime set_time, n; + krb5uint32 kvno; + size_t i; + + if (rotation_period_offset < -1 || rotation_period_offset > 1) + return EINVAL; /* wat */ + + /* + * Compute `kvno' and `set_time' given `t' and `krp'. + * + * There be signed 32-bit time_t dragons here. + * + * (t - krp->epoch < 0) is better than (krp->epoch < t), making us more + * tolerant of signed 32-bit time_t here near 2038. Of course, we have + * signed 32-bit time_t dragons elsewhere. + * + * We don't need to check for n == 0 && rotation_period_offset < 0 because + * only derive_keys_for_current_kr() calls us with non-zero rotation period + * offsets, and it will never call us in that case. + */ + if (t - krp->epoch < 0) + return 0; /* This KR is not relevant yet */ + n = (t - krp->epoch) / krp->period; + n += rotation_period_offset; + set_time = krp->epoch + krp->period * n; + kvno = krp->base_kvno + n; + + /* + * Since this principal is virtual, or has virtual keys, we're going to + * derive a "password expiration time" for it in order to help httpkadmind + * and other tools figure out when to request keys again. + * + * The kadm5 representation of principals does not include the set_time of + * keys/keysets, so we can't have httpkadmind derive a Cache-Control from + * that without adding yet another "TL data". Since adding TL data is a + * huge pain, we'll just use the `pw_end' field of `HDB_entry' to + * communicate when this principal's keys will change next. + */ + if (h->pw_end[0] == 0) { + KerberosTime used = (t - krp->epoch) % krp->period; + KerberosTime left = krp->period - used; + + /* + * If `h->pw_end[0]' == 0 then this must be the current period of the + * current KR we're deriving keys for. See upstairs. + * + * If there's more than a quarter of this time period left, then we'll + * set `h->pw_end[0]' to one quarter before the end of this time + * period. Else we'll set it to 1/4 after (we'll be including the next + * set of derived keys, so there's no harm in waiting that long to + * refetch). + */ + if (left > krp->period >> 2) + h->pw_end[0] = set_time + krp->period - (krp->period >> 2); + else + h->pw_end[0] = set_time + krp->period + (krp->period >> 2); + } + + + /* + * Do not waste cycles computing keys not wanted or needed. + * A past kvno is too old if its set_time + rotation period is in the past + * by more than half a rotation period, since then no service ticket + * encrypted with keys of that kvno can still be extant. + * + * A future kvno is not coming up soon enough if we're more than a quarter + * of the rotation period away from it. + * + * Recall: the assumption for virtually-keyed principals is that services + * fetch their future keys frequently enough that they'll never miss having + * the keys they need. + */ + if (!is_current_keyset || rotation_period_offset != 0) { + if ((kvno_wanted && kvno != kvno_wanted) || + t - (set_time + krp->period + (krp->period >> 1)) > 0 || + (set_time - t > 0 && (set_time - t) > (krp->period >> 2))) + return 0; + } + + for (i = 0; i < base_keys->len; i++) { + if (base_keys->val[i].kvno == krp->base_key_kvno) + break; + } + if (i == base_keys->len) { + /* Base key not found! */ + if (kvno_wanted || is_current_keyset) { + krb5_set_error_message(context, ret = HDB_ERR_KVNO_NOT_FOUND, + "Base key version %u not found for %s", + krp->base_key_kvno, princ); + return ret; + } + return 0; + } + + ret = derive_keyset(context, &base_keys->val[i].keys, princ, etype, kvno, + set_time, &dks); + if (ret == 0) + ret = hdb_install_keyset(context, h, is_current_keyset, &dks); + + free_HDB_keyset(&dks); + return ret; +} + +/* Derive and install current keys, and possibly preceding or next keys */ +static krb5_error_code +derive_keys_for_current_kr(krb5_context context, + hdb_entry *h, + HDB_Ext_KeySet *base_keys, + const char *princ, + unsigned int flags, + krb5int32 etype, + krb5uint32 kvno_wanted, + KerberosTime t, + struct KeyRotation *krp, + KerberosTime future_epoch) +{ + krb5_error_code ret; + + /* derive_keys_for_kr() for current kvno and install as the current keys */ + ret = derive_keys_for_kr(context, h, base_keys, 1, 0, princ, etype, + kvno_wanted, t, krp); + if (!(flags & HDB_F_ALL_KVNOS)) + return ret; + + /* */ + + + /* + * derive_keys_for_kr() for prev kvno if still needed -- it can only be + * needed if the prev kvno's start time is within this KR's epoch. + * + * Note that derive_keys_for_kr() can return without doing anything if this + * is isn't the current keyset. So these conditions need not be + * sufficiently narrow. + */ + if (ret == 0 && t - krp->epoch >= krp->period) + ret = derive_keys_for_kr(context, h, base_keys, 0, -1, princ, etype, + kvno_wanted, t, krp); + /* + * derive_keys_for_kr() for next kvno if near enough, but only if it + * doesn't start after the next KR's epoch. + */ + if (future_epoch && + t - krp->epoch >= 0 /* We know! Hint to the compiler */) { + KerberosTime next_kvno_start, n; + + n = (t - krp->epoch) / krp->period; + next_kvno_start = krp->epoch + krp->period * (n + 1); + if (future_epoch - next_kvno_start <= 0) + return ret; + } + if (ret == 0) + ret = derive_keys_for_kr(context, h, base_keys, 0, 1, princ, etype, + kvno_wanted, t, krp); + return ret; +} + +/* + * Derive and install all keysets in `h' that `princ' needs at time `now'. + * + * This mutates the entry `h' to + * + * a) not have base keys, + * b) have keys derived from the base keys according to + * c) the key rotation periods for the base principal (possibly the same + * principal if it's a concrete principal with virtual keys), and the + * requested time, enctype, and kvno (all of which are optional, with zero + * implying some default). + * + * Arguments: + * + * - `flags' is the flags passed to `hdb_fetch_kvno()' + * - `princ' is the name of the principal we'll end up with in `entry' + * - `h_is_namespace' indicates whether `h' is for a namespace or a concrete + * principal (that might nonetheless have virtual/derived keys) + * - `t' is the time such that the derived keys are for kvnos needed at `t' + * - `etype' indicates what enctype to derive keys for (0 for all enctypes in + * `entry->etypes') + * - `kvno' requests a particular kvno, or all if zero + * + * The caller doesn't know if the principal needs key derivation -- we make + * that determination in this function. + * + * Note that this function is fully deterministic for any given set of + * arguments and HDB contents. + * + * Definitions: + * + * - A keyset is a set of keys for a single kvno. + * - A keyset is relevant IFF: + * - it is the keyset for a time period identified by `t' in a + * corresponding KR + * - it is a keyset for a past time period for which there may be extant, + * not-yet-expired tickets that a service may need to decrypt + * - it is a keyset for an upcoming time period that a service will need to + * fetch before that time period becomes current, that way the service + * can have keytab entries for those keys in time for when the KDC starts + * encrypting service tickets to those keys + * + * This function derives the keyset(s) for the current KR first. The idea is + * to optimize the order of resulting keytabs so that the most likely keys to + * be used come first. + * + * Invariants: + * + * - KR metadata is sane because sanity is checked for when storing HDB + * entries + * - KRs are sorted by epoch in descending order; KR #0's epoch is the most + * recent + * - KR periods are non-zero (we divide by period) + * - kvnos are numerically ordered and correspond to time periods + * - within each KR, the kvnos for larger times are larger than (or equal + * to) the kvnos of earlier times + * - at KR boundaries, the first kvno of the newer boundary is larger than + * the kvno of the last time period of the previous KR + * - the time `t' must fall into exactly one KR period + * - the time `t' must fall into exactly one period within a KR period + * - at most two kvnos will be relevant from the KR that `t' falls into + * (the current kvno for `t', and possibly either the preceding, or the + * next) + * - at most one kvno from non-current KRs will be derived: possibly one for a + * preceding KR, and possibly one from an upcoming KR + * + * There can be: + * + * - no KR extension (not a namespace principal, and no virtual keys) + * - 1, 2, or 3 KRs (see above) + * - the newest KR may have the `deleted' flag, meaning "does not exist after + * this epoch" + * + * Note that the last time period in any older KR can be partial. + * + * Timeline diagram: + * + * .......|--+--+...+--|---+---+---+...+--|----+... + * T20 T10 T11 RT12 T1n T01 + * ^ ^ ^ ^ ^ ^ ^ T00 + * | | | T22 T2n | | ^ + * ^ | T21 | | | + * princ | | epoch of | epoch of + * did | | middle KR | newest epoch + * not | | | + * exist! | start of Note that T1n + * | second kvno is shown as shorter + * | in 1st epoch than preceding periods + * | + * ^ + * first KR's + * epoch, and start + * of its first kvno + * + * Tmn == the start of the Mth KR's Nth time period. + * (higher M -> older KR; lower M -> newer KR) + * (N is the reverse: lower N -> older time period in KR) + * T20 == start of oldest KR -- no keys before this time will be derived. + * T2n == last time period in oldest KR + * T10 == start of middle KR + * T1n == last time period in middle KR + * T00 == start of newest KR + * T0n == current time period in newest KR for wall clock time + */ +static krb5_error_code +derive_keys(krb5_context context, + unsigned flags, + krb5_const_principal princ, + int h_is_namespace, + krb5_timestamp t, + krb5int32 etype, + krb5uint32 kvno, + hdb_entry *h) +{ + HDB_Ext_KeyRotation kr; + HDB_Ext_KeySet base_keys; + krb5_error_code ret = 0; + size_t current_kr, future_kr, past_kr, i; + char *p = NULL; + int valid = 1; + + if (!h_is_namespace && !h->flags.virtual_keys) + return 0; + h->flags.virtual = 1; + + kr.len = 0; + kr.val = 0; + if (ret == 0) { + const HDB_Ext_KeyRotation *ckr; + + /* Installing keys invalidates `ckr', so we copy it */ + ret = hdb_entry_get_key_rotation(context, h, &ckr); + if (!ckr) + return ret; + if (ret == 0) + ret = copy_HDB_Ext_KeyRotation(ckr, &kr); + } + + /* Get the base keys from the entry, and remove them */ + base_keys.val = 0; + base_keys.len = 0; + if (ret == 0) + ret = _hdb_remove_base_keys(context, h, &base_keys, &kr); + + /* Make sure we have h->etypes */ + if (ret == 0 && !h->etypes) + ret = hdb_derive_etypes(context, h, &base_keys); + + /* Keys not desired? Don't derive them! */ + if (ret || !(flags & HDB_F_DECRYPT)) { + free_HDB_Ext_KeyRotation(&kr); + free_HDB_Ext_KeySet(&base_keys); + return ret; + } + + /* The principal name will be used in key derivation and error messages */ + if (ret == 0) + ret = krb5_unparse_name(context, princ, &p); + + /* Sanity check key rotations, determine current & last kr */ + if (ret == 0 && kr.len < 1) + krb5_set_error_message(context, ret = HDB_ERR_NOENTRY, + "no key rotation periods for %s", p); + if (ret == 0) + current_kr = future_kr = past_kr = kr.len; + else + current_kr = future_kr = past_kr = 1; + + /* + * Identify a current, next, and previous KRs if there are any. + * + * There can be up to three KRs, ordered by epoch, descending, making up a + * timeline like: + * + * ...|---------|--------|------> + * ^ | | | + * | | | | + * | | | Newest KR (kr.val[0]) + * | | Middle KR (kr.val[1]) + * | Oldest (last) KR (kr.val[2]) + * | + * Before the begging of time for this namespace + * + * We step through these from future towards past looking for the best + * future, current, and past KRs. The best current KR is one that has its + * epoch nearest to `t' but in the past of `t'. + * + * We validate KRs before storing HDB entries with the KR extension, so we + * can assume they are valid here. However, we do some validity checking, + * and if they're not valid, we pick the best current KR and ignore the + * others. + * + * In principle there cannot be two future KRs, but this function is + * deterministic and takes a time value, so it should not enforce this just + * so we can test. Enforcement of such rules should be done at store time. + */ + for (i = 0; ret == 0 && i < kr.len; i++) { + /* Minimal validation: order and period */ + if (i && kr.val[i - 1].epoch - kr.val[i].epoch <= 0) { + future_kr = past_kr = kr.len; + valid = 0; + } + if (!kr.val[i].period) { + future_kr = past_kr = kr.len; + valid = 0; + continue; + } + if (t - kr.val[i].epoch >= 0) { + /* + * `t' is in the future of this KR's epoch, so it's a candidate for + * either current or past KR. + */ + if (current_kr == kr.len) + current_kr = i; /* First curr KR candidate; should be best */ + else if (kr.val[current_kr].epoch - kr.val[i].epoch < 0) + current_kr = i; /* Invalid KRs, but better curr KR cand. */ + else if (valid && past_kr == kr.len) + past_kr = i; + } else if (valid) { + /* This KR is in the future of `t', a candidate for next KR */ + future_kr = i; + } + } + if (ret == 0 && current_kr == kr.len) + /* No current KR -> too soon */ + krb5_set_error_message(context, ret = HDB_ERR_NOENTRY, + "Too soon for virtual principal to exist"); + + /* Check that the principal has not been marked deleted */ + if (ret == 0 && current_kr < kr.len && kr.val[current_kr].flags.deleted) + krb5_set_error_message(context, ret = HDB_ERR_NOENTRY, + "virtual principal %s does not exist " + "because last key rotation period " + "marks deletion", p); + + /* See `derive_keys_for_kr()' */ + if (h->pw_end == NULL && + (h->pw_end = calloc(1, sizeof(h->pw_end[0]))) == NULL) + ret = krb5_enomem(context); + + /* + * Derive and set in `h' its current kvno and current keys. + * + * This will set h->kvno as well. + * + * This may set up to TWO keysets for the current key rotation period: + * - current keys (h->keys and h->kvno) + * - possibly one future + * OR + * possibly one past keyset in hist_keys for the current_kr + */ + if (ret == 0 && current_kr < kr.len) + ret = derive_keys_for_current_kr(context, h, &base_keys, p, flags, + etype, kvno, t, &kr.val[current_kr], + current_kr ? kr.val[0].epoch : 0); + + /* + * Derive and set in `h' its future keys for next KR if it is soon to be + * current. + * + * We want to derive keys for the first kvno of the next (future) KR if + * it's sufficiently close to `t', meaning within 1 period of the current + * KR, but we want these keys to be available sooner, so 1.5 of the current + * period. + */ + if (ret == 0 && future_kr < kr.len && (flags & HDB_F_ALL_KVNOS)) + ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno, + kr.val[future_kr].epoch, &kr.val[future_kr]); + + /* + * Derive and set in `h' its past keys for the previous KR if its last time + * period could still have extant, unexpired service tickets encrypted in + * its keys. + */ + if (ret == 0 && past_kr < kr.len && (flags & HDB_F_ALL_KVNOS)) + ret = derive_keys_for_kr(context, h, &base_keys, 0, 0, p, etype, kvno, + kr.val[current_kr].epoch - 1, &kr.val[past_kr]); + + /* + * Impose a bound on h->max_life so that [when the KDC is the caller] + * the KDC won't issue tickets longer lived than this. + */ + if (ret == 0 && !h->max_life && + (h->max_life = calloc(1, sizeof(h->max_life[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && *h->max_life > kr.val[current_kr].period >> 1) + *h->max_life = kr.val[current_kr].period >> 1; + + if (ret == 0 && h->pw_end[0] == 0) + /* Shouldn't happen */ + h->pw_end[0] = kr.val[current_kr].epoch + + kr.val[current_kr].period * + (1 + (t - kr.val[current_kr].epoch) / kr.val[current_kr].period); + + free_HDB_Ext_KeyRotation(&kr); + free_HDB_Ext_KeySet(&base_keys); + free(p); + return ret; +} + +/* + * Pick a best kvno for the given principal at the given time. + * + * Implements the [hdb] new_service_key_delay configuration parameter. + * + * In order for disparate keytab provisioning systems such as OSKT and our own + * kadmin ext_keytab and httpkadmind's get-keys to coexist, we need to be able + * to force keys set by the former to not become current keys until users of + * the latter have had a chance to fetch those keys into their keytabs. To do + * this we have to search the list of keys in the entry looking for the newest + * keys older than `now - db->new_service_key_delay'. + * + * The context is that OSKT's krb5_keytab is very happy to change keys in a way + * that requires all members of a cluster to rekey together. If one also + * wishes to have cluster members that opt out of this and just fetch current, + * past, and future keys periodically, then the keys set by OSKT must not come + * into effect until all the opt-out members have had a chance to fetch the new + * keys. + * + * The assumption is that services will fetch new keys periodically, say, every + * four hours. Then one can set `[hdb] new_service_key_delay = 8h' in the + * configuration and new keys set by OSKT will not be used until 8h after they + * are set. + * + * Naturally, this applies only to concrete principals with concrete keys. + */ +static krb5_error_code +pick_kvno(krb5_context context, + HDB *db, + unsigned flags, + krb5_timestamp now, + krb5uint32 kvno, + hdb_entry *h) +{ + HDB_extension *ext; + HDB_Ext_KeySet keys; + time_t current = 0; + time_t best; + size_t i; + + /* + * If we want a specific kvno, or if the caller doesn't want new keys + * delayed, or if there's no new-key delay configured, or we're not + * fetching for use as a service principal, then we're out. + */ + if (!(flags & HDB_F_DELAY_NEW_KEYS) || kvno || h->flags.virtual || + h->flags.virtual_keys || db->new_service_key_delay <= 0) + return 0; + + /* No history -> current keyset is the only one and therefore the best */ + ext = hdb_find_extension(h, choice_HDB_extension_data_hist_keys); + if (!ext) + return 0; + + /* Assume the current keyset is the best to start with */ + (void) hdb_entry_get_pw_change_time(h, ¤t); + if (current == 0 && h->modified_by) + current = h->modified_by->time; + if (current == 0) + current = h->created_by.time; + + /* Current keyset starts out as best */ + best = current; + kvno = h->kvno; + + /* Look for a better keyset in the history */ + keys = ext->data.u.hist_keys; + for (i = 0; i < keys.len; i++) { + /* No set_time? Ignore. Too new? Ignore */ + if (!keys.val[i].set_time || + keys.val[i].set_time[0] + db->new_service_key_delay > now) + continue; + + /* + * Ignore the keyset with kvno 1 when the entry has better kvnos + * because kadmin's `ank -r' command immediately changes the keys. + */ + if (kvno > 1 && keys.val[i].kvno == 1) + continue; + + /* + * This keyset's set_time older than the previous best? Ignore. + * However, if the current best is the entry's current and that one + * is too new, then don't ignore this one. + */ + if (keys.val[i].set_time[0] < best && + (best != current || current + db->new_service_key_delay < now)) + continue; + + /* + * If two good enough keysets have the same set_time, take the keyset + * with the highest kvno. + */ + if (keys.val[i].set_time[0] == best && keys.val[i].kvno <= kvno) + continue; + + /* + * This keyset is clearly more current than the previous best keyset + * but still old enough to use for encrypting tickets with. + */ + best = keys.val[i].set_time[0]; + kvno = keys.val[i].kvno; + } + return hdb_change_kvno(context, kvno, h); +} + +/* + * Make a WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname} or + * WELLKNOWN/HOSTBASED-NAMESPACE/${svc}/${hostname}/${domainname} principal + * object, with the service and hostname components take from `wanted', but if + * the service name is not in the list `db->virtual_hostbased_princ_svcs[]' + * then use "_" (wildcard) instead. This way we can have different attributes + * for different services in the same namespaces. + * + * For example, virtual hostbased service names for the "host" service might + * have ok-as-delegate set, but ones for the "HTTP" service might not. + */ +static krb5_error_code +make_namespace_princ(krb5_context context, + HDB *db, + krb5_const_principal wanted, + krb5_principal *namespace) +{ + krb5_error_code ret = 0; + const char *realm = krb5_principal_get_realm(context, wanted); + const char *comp0 = krb5_principal_get_comp_string(context, wanted, 0); + const char *comp1 = krb5_principal_get_comp_string(context, wanted, 1); + const char *comp2 = krb5_principal_get_comp_string(context, wanted, 2); + char * const *svcs = db->virtual_hostbased_princ_svcs; + size_t i; + + *namespace = NULL; + if (comp0 == NULL || comp1 == NULL) + return EINVAL; + if (strcmp(comp0, "krbtgt") == 0) + return 0; + + for (i = 0; svcs && svcs[i]; i++) { + if (strcmp(comp0, svcs[i]) == 0) { + comp0 = svcs[i]; + break; + } + } + if (!svcs || !svcs[i]) + comp0 = "_"; + + /* First go around, need a namespace princ. Make it! */ + ret = krb5_build_principal(context, namespace, strlen(realm), + realm, KRB5_WELLKNOWN_NAME, + HDB_WK_NAMESPACE, comp0, NULL); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, *namespace, 3, comp1); + if (ret == 0 && comp2) + /* Support domain-based names */ + ret = krb5_principal_set_comp_string(context, *namespace, 4, comp2); + /* Caller frees `*namespace' on error */ + return ret; +} + +static int +is_namespace_princ_p(krb5_context context, + krb5_const_principal princ) +{ + return + krb5_principal_get_num_comp(context, princ) >= 4 + && strcmp(krb5_principal_get_comp_string(context, princ, 0), + KRB5_WELLKNOWN_NAME) == 0 + && strcmp(krb5_principal_get_comp_string(context, princ, 1), + HDB_WK_NAMESPACE) == 0; +} + +/* See call site */ +static krb5_error_code +rewrite_hostname(krb5_context context, + krb5_const_principal wanted_princ, + krb5_const_principal ns_princ, + krb5_const_principal found_ns_princ, + char **s) +{ + const char *ns_host_part, *wanted_host_part, *found_host_part; + const char *p, *r; + size_t ns_host_part_len, wanted_host_part_len; + + wanted_host_part = krb5_principal_get_comp_string(context, wanted_princ, 1); + wanted_host_part_len = strlen(wanted_host_part); + if (wanted_host_part_len > 256) { + krb5_set_error_message(context, HDB_ERR_NOENTRY, + "Aliases of host-based principals longer than " + "256 bytes not supported"); + return HDB_ERR_NOENTRY; + } + + ns_host_part = krb5_principal_get_comp_string(context, ns_princ, 3); + ns_host_part_len = strlen(ns_host_part); + + /* Find `ns_host_part' as the tail of `wanted_host_part' */ + for (r = p = strstr(wanted_host_part, ns_host_part); + r && strnlen(r, ns_host_part_len + 1) > ns_host_part_len; + p = (r = strstr(r, ns_host_part)) ? r : p) + ; + if (!p || strnlen(p, ns_host_part_len + 1) != ns_host_part_len) + return HDB_ERR_NOENTRY; /* Can't happen */ + if (p == wanted_host_part || p[-1] != '.') + return HDB_ERR_NOENTRY; + + found_host_part = + krb5_principal_get_comp_string(context, found_ns_princ, 3); + return + asprintf(s, "%.*s%s", (int)(p - wanted_host_part), wanted_host_part, + found_host_part) < 0 || + *s == NULL ? krb5_enomem(context) : 0; +} + +/* + * Fix `h->principal' to match the desired `princ' in the namespace + * `nsprinc' (which is either the same as `h->principal' or an alias + * of it). + */ +static krb5_error_code +fix_princ_name(krb5_context context, + krb5_const_principal princ, + krb5_const_principal nsprinc, + hdb_entry *h) +{ + krb5_error_code ret = 0; + char *s = NULL; + + if (!nsprinc) + return 0; + if (krb5_principal_get_num_comp(context, princ) < 2) + return HDB_ERR_NOENTRY; + + /* `nsprinc' must be a namespace principal */ + + if (krb5_principal_compare(context, nsprinc, h->principal)) { + /* + * `h' is the HDB entry for `nsprinc', and `nsprinc' is its canonical + * name. + * + * Set the entry's principal name to the desired name. The keys will + * be fixed next (upstairs, but don't forget to!). + */ + free_Principal(h->principal); + return copy_Principal(princ, h->principal); + } + + if (!is_namespace_princ_p(context, h->principal)) { + /* + * The alias is a namespace, but the canonical name is not. WAT. + * + * Well, the KDC will just issue a referral anyways, so we can leave + * `h->principal' as is... + * + * Remove all of `h's keys just in case, and leave + * `h->principal' as-is. + */ + free_Keys(&h->keys); + (void) hdb_entry_clear_password(context, h); + return hdb_clear_extension(context, h, + choice_HDB_extension_data_hist_keys); + } + + /* + * A namespace alias of a namespace entry. + * + * We'll want to rewrite the original principal accordingly. + * + * E.g., if the caller wanted host/foo.ns.test.h5l.se and we + * found WELLKNOWN/HOSTBASED-NAMESPACE/ns.test.h5l.se is an + * alias of WELLKNOWN/HOSTBASED-NAMESPACE/ns.example.org, then + * we'll want to treat host/foo.ns.test.h5l.se as an alias of + * host/foo.ns.example.org. + */ + if (krb5_principal_get_num_comp(context, h->principal) != + 2 + krb5_principal_get_num_comp(context, princ)) + ret = HDB_ERR_NOENTRY; /* Only host-based services for now */ + if (ret == 0) + ret = rewrite_hostname(context, princ, nsprinc, h->principal, &s); + if (ret == 0) { + krb5_free_principal(context, h->principal); + h->principal = NULL; + ret = krb5_make_principal(context, &h->principal, + krb5_principal_get_realm(context, princ), + krb5_principal_get_comp_string(context, + princ, 0), + s, + NULL); + } + free(s); + return ret; +} + +/* Wrapper around db->hdb_fetch_kvno() that implements virtual princs/keys */ +static krb5_error_code +fetch_it(krb5_context context, + HDB *db, + krb5_const_principal princ, + unsigned flags, + krb5_timestamp t, + krb5int32 etype, + krb5uint32 kvno, + hdb_entry *ent) +{ + krb5_const_principal tmpprinc = princ; + krb5_principal nsprinc = NULL; + krb5_error_code ret = 0; + const char *comp0 = krb5_principal_get_comp_string(context, princ, 0); + const char *comp1 = krb5_principal_get_comp_string(context, princ, 1); + const char *tmp; + size_t mindots = db->virtual_hostbased_princ_ndots; + size_t maxdots = db->virtual_hostbased_princ_maxdots; + size_t hdots = 0; + char *host = NULL; + int do_search = 0; + + if (!db->enable_virtual_hostbased_princs) + maxdots = mindots = 0; + if (db->enable_virtual_hostbased_princs && comp1 && + (comp0 == NULL || (strcmp("krbtgt", comp0) != 0 && strcmp(KRB5_WELLKNOWN_NAME, comp0) != 0))) { + char *htmp; + + if ((host = strdup(comp1)) == NULL) + return krb5_enomem(context); + + /* Strip out any :port */ + htmp = strchr(host, ':'); + if (htmp) { + if (strchr(htmp + 1, ':')) { + /* Extra ':'s? No virtualization for you! */ + free(host); + host = NULL; + } else { + *htmp = '\0'; + } + } + /* Count dots in `host' */ + for (hdots = 0, htmp = host; htmp && *htmp; htmp++) + if (*htmp == '.') + hdots++; + + do_search = 1; + } + + tmp = host ? host : comp1; + for (ret = HDB_ERR_NOENTRY; ret == HDB_ERR_NOENTRY; tmpprinc = nsprinc) { + krb5_error_code ret2 = 0; + + /* + * We break out of this loop with ret == 0 only if we found the HDB + * entry we were looking for or the HDB entry for a matching namespace. + * + * Otherwise we break out with ret != 0, typically HDB_ERR_NOENTRY. + * + * First time through we lookup the principal as given. + * + * Next we lookup a namespace principal, stripping off hostname labels + * from the left until we find one or get tired of looking or run out + * of labels. + */ + ret = db->hdb_fetch_kvno(context, db, tmpprinc, flags, kvno, ent); + if (ret == 0 && nsprinc && ent->flags.invalid) { + free_HDB_entry(ent); + ret = HDB_ERR_NOENTRY; + } + if (ret != HDB_ERR_NOENTRY || hdots == 0 || hdots < mindots || !tmp || + !do_search) + break; + + /* + * Breadcrumb: + * + * - if we found a concrete principal, but it's been marked + * as now-virtual, then we must keep going + * + * But this will be coded in the future. + * + * Maybe we can take attributes from the concrete principal... + */ + + /* + * The namespace's hostname will not have more labels than maxdots + 1. + * Thus we truncate immediately down to maxdots + 1 if we haven't yet. + * + * Example: with maxdots == 3, + * foo.bar.baz.app.blah.example -> baz.app.blah.example + */ + while (maxdots && hdots > maxdots && tmp) { + tmp = strchr(tmp, '.'); + /* tmp != NULL because maxdots > 0; we check to quiet linters */ + if (tmp == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } + tmp++; + hdots--; + } + + if (nsprinc == NULL) + /* First go around, need a namespace princ. Make it! */ + ret2 = make_namespace_princ(context, db, tmpprinc, &nsprinc); + + /* Update the hostname component of the namespace principal */ + if (ret2 == 0) + ret2 = krb5_principal_set_comp_string(context, nsprinc, 3, tmp); + if (ret2) + ret = ret2; + + if (tmp) { + /* Strip off left-most label for the next go-around */ + if ((tmp = strchr(tmp, '.'))) + tmp++; + hdots--; + } /* else we'll break out after the next db->hdb_fetch_kvno() call */ + } + + /* + * If unencrypted keys were requested, derive them. There may not be any + * key derivation to do, but that's decided in derive_keys(). + */ + if (ret == 0 || ret == HDB_ERR_WRONG_REALM) { + krb5_error_code save_ret = ret; + + /* Fix the principal name if namespaced */ + ret = fix_princ_name(context, princ, nsprinc, ent); + + /* Derive keys if namespaced or virtual */ + if (ret == 0) + ret = derive_keys(context, flags, princ, !!nsprinc, t, etype, kvno, + ent); + /* Pick the best kvno for this principal at the given time */ + if (ret == 0) + ret = pick_kvno(context, db, flags, t, kvno, ent); + if (ret == 0) + ret = save_ret; + } + +out: + if (ret != 0 && ret != HDB_ERR_WRONG_REALM) + hdb_free_entry(context, db, ent); + krb5_free_principal(context, nsprinc); + free(host); + return ret; +} + +/** + * Fetch a principal's HDB entry, possibly generating virtual keys from base + * keys according to strict key rotation schedules. If a time is given, other + * than HDB I/O, this function is pure, thus usable for testing. + * + * HDB writers should use `db->hdb_fetch_kvno()' to avoid materializing virtual + * principals. + * + * HDB readers should use this function rather than `db->hdb_fetch_kvno()' + * unless they only want to see concrete principals and not bother generating + * any virtual keys. + * + * @param context Context + * @param db HDB + * @param principal Principal name + * @param flags Fetch flags + * @param t For virtual keys, use this as the point in time (use zero to mean "now") + * @param etype Key enctype (use KRB5_ENCTYPE_NULL to mean "preferred") + * @param kvno Key version number (use zero to mean "current") + * @param h Output HDB entry + * + * @return Zero or HDB_ERR_WRONG_REALM on success, an error code otherwise. + */ +krb5_error_code +hdb_fetch_kvno(krb5_context context, + HDB *db, + krb5_const_principal principal, + unsigned int flags, + krb5_timestamp t, + krb5int32 etype, + krb5uint32 kvno, + hdb_entry *h) +{ + krb5_error_code ret; + krb5_timestamp now; + + krb5_timeofday(context, &now); + + flags |= kvno ? HDB_F_KVNO_SPECIFIED : 0; /* XXX is this needed */ + ret = fetch_it(context, db, principal, flags, t ? t : now, etype, kvno, h); + if (ret == 0 && t == 0 && h->flags.virtual && + h->pw_end && h->pw_end[0] < now) { + /* + * This shouldn't happen! + * + * Do not allow h->pw_end[0] to be in the past for virtual principals + * outside testing. This is just to prevent the AS/TGS from failing. + */ + h->pw_end[0] = now + 3600; + } + if (ret == HDB_ERR_NOENTRY) + krb5_set_error_message(context, ret, "no such entry found in hdb"); + return ret; +} + +size_t ASN1CALL +length_hdb_keyset(HDB_keyset *data) +{ + return length_HDB_keyset(data); +} + +size_t ASN1CALL +length_hdb_entry(HDB_entry *data) +{ + return length_HDB_entry(data); +} + +size_t ASN1CALL +length_hdb_entry_alias(HDB_entry_alias *data) +{ + return length_HDB_entry_alias(data); +} + +void ASN1CALL +free_hdb_keyset(HDB_keyset *data) +{ + free_HDB_keyset(data); +} + +void ASN1CALL +free_hdb_entry(HDB_entry *data) +{ + free_HDB_entry(data); +} + +void ASN1CALL +free_hdb_entry_alias(HDB_entry_alias *data) +{ + free_HDB_entry_alias(data); +} + +size_t ASN1CALL +copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to) +{ + return copy_HDB_keyset(from, to); +} + +size_t ASN1CALL +copy_hdb_entry(const HDB_entry *from, HDB_entry *to) +{ + return copy_HDB_entry(from, to); +} + +size_t ASN1CALL +copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to) +{ + return copy_HDB_entry_alias(from, to); +} + +int ASN1CALL +decode_hdb_keyset(const unsigned char *p, + size_t len, + HDB_keyset *data, + size_t *size) +{ + return decode_HDB_keyset(p, len, data, size); +} + +int ASN1CALL +decode_hdb_entry(const unsigned char *p, + size_t len, + HDB_entry *data, + size_t *size) +{ + return decode_HDB_entry(p, len, data, size); +} + +int ASN1CALL +decode_hdb_entry_alias(const unsigned char *p, + size_t len, + HDB_entry_alias *data, + size_t *size) +{ + return decode_HDB_entry_alias(p, len, data, size); +} + +int ASN1CALL +encode_hdb_keyset(unsigned char *p, + size_t len, + const HDB_keyset *data, + size_t *size) +{ + return encode_HDB_keyset(p, len, data, size); +} + +int ASN1CALL +encode_hdb_entry(unsigned char *p, + size_t len, + const HDB_entry *data, + size_t *size) +{ + return encode_HDB_entry(p, len, data, size); +} + +int ASN1CALL +encode_hdb_entry_alias(unsigned char *p, + size_t len, + const HDB_entry_alias *data, + size_t *size) +{ + return encode_HDB_entry_alias(p, len, data, size); +} diff --git a/third_party/heimdal/lib/hdb/data-mkey.mit.des3.be b/third_party/heimdal/lib/hdb/data-mkey.mit.des3.be new file mode 100644 index 0000000..4278ed3 Binary files /dev/null and b/third_party/heimdal/lib/hdb/data-mkey.mit.des3.be differ diff --git a/third_party/heimdal/lib/hdb/data-mkey.mit.des3.le b/third_party/heimdal/lib/hdb/data-mkey.mit.des3.le new file mode 100644 index 0000000..19fdc93 Binary files /dev/null and b/third_party/heimdal/lib/hdb/data-mkey.mit.des3.le differ diff --git a/third_party/heimdal/lib/hdb/db.c b/third_party/heimdal/lib/hdb/db.c new file mode 100644 index 0000000..5fcce7b --- /dev/null +++ b/third_party/heimdal/lib/hdb/db.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#if defined(HAVE_DB1) + +#if defined(HAVE_DB_185_H) +#include +#elif defined(HAVE_DB_H) +#include +#endif + +typedef struct { + HDB hdb; /* generic members */ + int lock_fd; /* DB-specific */ + int do_sync; /* DB-specific */ +} DB1_HDB; + +static krb5_error_code +DB_close(krb5_context context, HDB *db) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + DB *d = (DB*)db->hdb_db; + + heim_assert(d != 0, "Closing already closed HDB"); + + (*d->close)(d); + db->hdb_db = 0; + + if (db1->lock_fd >= 0) { + close(db1->lock_fd); + db1->lock_fd = -1; + } + + return 0; +} + +static krb5_error_code +DB_destroy(krb5_context context, HDB *db) +{ + krb5_error_code ret; + + ret = hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(db->hdb_name); + free(db); + return ret; +} + +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + DB *d = (DB*)db->hdb_db; + krb5_error_code ret = 0; + + db1->do_sync = on; + if (on) { + ret = (*d->sync)(d, 0); + if (ret == -1) { + ret = errno; + krb5_set_error_message(context, ret, "Database %s put sync error: %s", + db->hdb_name, strerror(ret)); + } + } + return ret; +} + +static krb5_error_code +DB_lock(krb5_context context, HDB *db, int operation) +{ + + return 0; +} + +static krb5_error_code +DB_unlock(krb5_context context, HDB *db) +{ + + return 0; +} + + +static krb5_error_code +DB_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry, int flag) +{ + DB *d = (DB*)db->hdb_db; + DBT key, value; + krb5_data key_data, data; + int code; + + code = (*d->seq)(d, &key, &value, flag); + if(code == -1) { + code = errno; + krb5_set_error_message(context, code, "Database %s seq error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code == 1) { + krb5_clear_error_message(context); + return HDB_ERR_NOENTRY; + } + + key_data.data = key.data; + key_data.length = key.size; + data.data = value.data; + data.length = value.size; + memset(entry, 0, sizeof(*entry)); + if (hdb_value2entry(context, &data, entry)) + return DB_seq(context, db, flags, entry, R_NEXT); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, entry); + if (code) + hdb_free_entry (context, db, entry); + } + if (code == 0 && entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { + code = ENOMEM; + krb5_set_error_message(context, code, "malloc: out of memory"); + hdb_free_entry (context, db, entry); + } else { + hdb_key2principal(context, &key_data, entry->principal); + } + } + return code; +} + + +static krb5_error_code +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return DB_seq(context, db, flags, entry, R_FIRST); +} + + +static krb5_error_code +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return DB_seq(context, db, flags, entry, R_NEXT); +} + +static krb5_error_code +DB_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old, *new; + + if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0) + new_name += sizeof("db:") - 1; + else if (strncmp(new_name, "db1:", sizeof("db1:") - 1) == 0) + new_name += sizeof("db1:") - 1; + asprintf(&old, "%s.db", db->hdb_name); + asprintf(&new, "%s.db", new_name); + ret = rename(old, new); + free(old); + free(new); + if(ret) + return errno; + + free(db->hdb_name); + db->hdb_name = strdup(new_name); + return 0; +} + +static krb5_error_code +DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + k.data = key.data; + k.size = key.length; + code = (*d->get)(d, &k, &v, 0); + if(code < 0) { + code = errno; + krb5_set_error_message(context, code, "Database %s get error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code == 1) { + krb5_clear_error_message(context); + return HDB_ERR_NOENTRY; + } + + krb5_data_copy(reply, v.data, v.size); + return 0; +} + +static krb5_error_code +DB__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + k.data = key.data; + k.size = key.length; + v.data = value.data; + v.size = value.length; + krb5_clear_error_message(context); + code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); + if(code < 0) { + code = errno; + krb5_set_error_message(context, code, "Database %s put error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code == 1) { + return HDB_ERR_EXISTS; + } + + return db->hdb_set_sync(context, db, db1->do_sync); +} + +static krb5_error_code +DB__del(krb5_context context, HDB *db, krb5_data key) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k; + krb5_error_code code; + k.data = key.data; + k.size = key.length; + krb5_clear_error_message(context); + code = (*d->del)(d, &k, 0); + if (code == 1) + return HDB_ERR_NOENTRY; + if (code < 0) { + code = errno; + krb5_set_error_message(context, code, "Database %s del error: %s", + db->hdb_name, strerror(code)); + return code; + } + return db->hdb_set_sync(context, db, db1->do_sync); +} + +static DB * +_open_db(char *fn, int flags, int mode, int *fd) +{ +#ifndef O_EXLOCK + int op; + int ret; + + *fd = open(fn, flags, mode); + if (*fd == -1) + return NULL; + + if ((flags & O_ACCMODE) == O_RDONLY) + op = LOCK_SH; + else + op = LOCK_EX; + + ret = flock(*fd, op); + if (ret == -1) { + int saved_errno; + + saved_errno = errno; + close(*fd); + errno = saved_errno; + return NULL; + } +#else + if ((flags & O_ACCMODE) == O_RDONLY) + flags |= O_SHLOCK; + else + flags |= O_EXLOCK; +#endif + + return dbopen(fn, flags, mode, DB_BTREE, NULL); +} + +static krb5_error_code +DB_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + char *fn; + krb5_error_code ret; + + asprintf(&fn, "%s.db", db->hdb_name); + if (fn == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + db->hdb_db = _open_db(fn, flags, mode, &db1->lock_fd); + free(fn); + /* try to open without .db extension */ + if(db->hdb_db == NULL && errno == ENOENT) + db->hdb_db = _open_db(db->hdb_name, flags, mode, &db1->lock_fd); + if(db->hdb_db == NULL) { + krb5_set_error_message(context, errno, "dbopen (%s): %s", + db->hdb_name, strerror(errno)); + return errno; + } + if((flags & O_ACCMODE) == O_RDONLY) + ret = hdb_check_db_format(context, db); + else + ret = hdb_init_db(context, db); + if(ret == HDB_ERR_NOENTRY) { + krb5_clear_error_message(context); + return 0; + } + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (flags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + return ret; +} + +krb5_error_code +hdb_db1_create(krb5_context context, HDB **db, + const char *filename) +{ + DB1_HDB **db1 = (DB1_HDB **)db; + *db = calloc(1, sizeof(**db1)); /* Allocate space for the larger db1 */ + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = NULL; + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + (*db)->hdb_open = DB_open; + (*db)->hdb_close = DB_close; + (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; + (*db)->hdb_store = _hdb_store; + (*db)->hdb_remove = _hdb_remove; + (*db)->hdb_firstkey = DB_firstkey; + (*db)->hdb_nextkey= DB_nextkey; + (*db)->hdb_lock = DB_lock; + (*db)->hdb_unlock = DB_unlock; + (*db)->hdb_rename = DB_rename; + (*db)->hdb__get = DB__get; + (*db)->hdb__put = DB__put; + (*db)->hdb__del = DB__del; + (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; + + (*db1)->lock_fd = -1; + (*db1)->do_sync = 1; + return 0; +} + +#endif /* defined(HAVE_DB1) */ diff --git a/third_party/heimdal/lib/hdb/db3.c b/third_party/heimdal/lib/hdb/db3.c new file mode 100644 index 0000000..9d0c0a9 --- /dev/null +++ b/third_party/heimdal/lib/hdb/db3.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#include + +#if HAVE_DB3 + +#ifdef HAVE_DBHEADER +#include +#elif HAVE_DB6_DB_H +#include +#elif HAVE_DB5_DB_H +#include +#elif HAVE_DB4_DB_H +#include +#elif HAVE_DB3_DB_H +#include +#else +#include +#endif + +typedef struct { + HDB hdb; /* generic members */ + int lock_fd; /* DB3-specific */ + int do_sync; /* DB3-specific */ +} DB3_HDB; + + +static krb5_error_code +DB_close(krb5_context context, HDB *db) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DB *d = (DB*)db->hdb_db; + DBC *dbcp = (DBC*)db->hdb_dbc; + + heim_assert(d != 0, "Closing already closed HDB"); + + if (dbcp != NULL) + dbcp->c_close(dbcp); + if (d != NULL) + d->close(d, 0); + if (db3->lock_fd >= 0) + close(db3->lock_fd); + + db3->lock_fd = -1; + db->hdb_dbc = 0; + db->hdb_db = 0; + + return 0; +} + +static krb5_error_code +DB_destroy(krb5_context context, HDB *db) +{ + krb5_error_code ret; + + ret = hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(db->hdb_name); + free(db); + return ret; +} + +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DB *d = (DB*)db->hdb_db; + krb5_error_code ret = 0; + + db3->do_sync = on; + if (on) { + ret = (*d->sync)(d, 0); + if (ret) { + if (ret == EACCES || ret == ENOSPC || ret == EINVAL) { + krb5_set_error_message(context, ret, + "Database %s put sync error: %s", + db->hdb_name, strerror(ret)); + } else { + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, + "Database %s put sync error: unknown (%d)", + db->hdb_name, ret); + } + } + } + return ret; +} + +static krb5_error_code +DB_lock(krb5_context context, HDB *db, int operation) +{ + + return 0; +} + +static krb5_error_code +DB_unlock(krb5_context context, HDB *db) +{ + + return 0; +} + + +static krb5_error_code +DB_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry, int flag) +{ + DBT key, value; + DBC *dbcp = db->hdb_dbc; + krb5_data key_data, data; + int code; + + memset(&key, 0, sizeof(DBT)); + memset(&value, 0, sizeof(DBT)); + code = (*dbcp->c_get)(dbcp, &key, &value, flag); + if (code == DB_NOTFOUND) + return HDB_ERR_NOENTRY; + if (code) + return code; + + key_data.data = key.data; + key_data.length = key.size; + data.data = value.data; + data.length = value.size; + memset(entry, 0, sizeof(*entry)); + if (hdb_value2entry(context, &data, entry)) + return DB_seq(context, db, flags, entry, DB_NEXT); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, entry); + if (code) + hdb_free_entry (context, db, entry); + } + if (entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } else { + hdb_key2principal(context, &key_data, entry->principal); + } + } + return 0; +} + + +static krb5_error_code +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return DB_seq(context, db, flags, entry, DB_FIRST); +} + + +static krb5_error_code +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return DB_seq(context, db, flags, entry, DB_NEXT); +} + +static krb5_error_code +DB_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old, *new; + + if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0) + new_name += sizeof("db:") - 1; + else if (strncmp(new_name, "db3:", sizeof("db3:") - 1) == 0) + new_name += sizeof("db3:") - 1; + + ret = asprintf(&old, "%s.db", db->hdb_name); + if (ret == -1) + return ENOMEM; + ret = asprintf(&new, "%s.db", new_name); + if (ret == -1) { + free(old); + return ENOMEM; + } + ret = rename(old, new); + free(old); + if(ret) { + free(new); + return errno; + } + + free(db->hdb_name); + new[strlen(new) - 3] = '\0'; + db->hdb_name = new; + return 0; +} + +static krb5_error_code +DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + memset(&k, 0, sizeof(DBT)); + memset(&v, 0, sizeof(DBT)); + k.data = key.data; + k.size = key.length; + k.flags = 0; + code = (*d->get)(d, NULL, &k, &v, 0); + if(code == DB_NOTFOUND) + return HDB_ERR_NOENTRY; + if(code) + return code; + + krb5_data_copy(reply, v.data, v.size); + return 0; +} + +static krb5_error_code +DB__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + memset(&k, 0, sizeof(DBT)); + memset(&v, 0, sizeof(DBT)); + k.data = key.data; + k.size = key.length; + k.flags = 0; + v.data = value.data; + v.size = value.length; + v.flags = 0; + code = (*d->put)(d, NULL, &k, &v, replace ? 0 : DB_NOOVERWRITE); + if(code == DB_KEYEXIST) + return HDB_ERR_EXISTS; + if (code) { + /* + * Berkeley DB 3 and up have a terrible error reporting + * interface... + * + * DB->err() doesn't output a string. + * DB->set_errcall()'s callback function doesn't have a void * + * argument that can be used to place the error somewhere. + * + * The only thing we could do is fopen()/fdopen() a file, set it + * with DB->set_errfile(), then call DB->err(), then read the + * message from the file, unset it with DB->set_errfile(), close + * it and delete it. That's a lot of work... so we don't do it. + */ + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s put error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s put error: unknown (%d)", + db->hdb_name, code); + } + return code; + } + return db->hdb_set_sync(context, db, db3->do_sync); +} + +static krb5_error_code +DB__del(krb5_context context, HDB *db, krb5_data key) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k; + krb5_error_code code; + memset(&k, 0, sizeof(DBT)); + k.data = key.data; + k.size = key.length; + k.flags = 0; + code = (*d->del)(d, NULL, &k, 0); + if(code == DB_NOTFOUND) + return HDB_ERR_NOENTRY; + if (code) { + if (code == EACCES || code == ENOSPC || code == EINVAL) { + krb5_set_error_message(context, code, + "Database %s del error: %s", + db->hdb_name, strerror(code)); + } else { + code = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, code, + "Database %s del error: unknown (%d)", + db->hdb_name, code); + } + return code; + } + return db->hdb_set_sync(context, db, db3->do_sync); +} + +#define RD_CACHE_SZ 0x8000 /* Minimal read cache size */ +#define WR_CACHE_SZ 0x8000 /* Minimal write cache size */ + +static int +_open_db(DB *d, char *fn, int myflags, int flags, mode_t mode, int *fd) +{ + int ret; + int cache_size = (myflags & DB_RDONLY) ? RD_CACHE_SZ : WR_CACHE_SZ; + + *fd = open(fn, flags, mode); + + if (*fd == -1) + return errno; + + /* + * Without DB_FCNTL_LOCKING, the DB library complains when initializing + * a database in an empty file. Since the database is our lock file, + * we create it before Berkeley DB does, so a new DB always starts empty. + */ + myflags |= DB_FCNTL_LOCKING; + + ret = flock(*fd, (myflags&DB_RDONLY) ? LOCK_SH : LOCK_EX); + if (ret == -1) { + ret = errno; + close(*fd); + *fd = -1; + return ret; + } + + d->set_cachesize(d, 0, cache_size, 0); + +#if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR >= 1)) + ret = (*d->open)(d, NULL, fn, NULL, DB_BTREE, myflags, mode); +#else + ret = (*d->open)(d, fn, NULL, DB_BTREE, myflags, mode); +#endif + + if (ret != 0) { + close(*fd); + *fd = -1; + } + + return ret; +} + +static krb5_error_code +DB_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DBC *dbc = NULL; + char *fn; + krb5_error_code ret; + DB *d; + int myflags = 0; + int aret; + + heim_assert(db->hdb_db == 0, "Opening already open HDB"); + + if (flags & O_CREAT) + myflags |= DB_CREATE; + + if (flags & O_EXCL) + myflags |= DB_EXCL; + + if((flags & O_ACCMODE) == O_RDONLY) + myflags |= DB_RDONLY; + + if (flags & O_TRUNC) + myflags |= DB_TRUNCATE; + + aret = asprintf(&fn, "%s.db", db->hdb_name); + if (aret == -1) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + if (db_create(&d, NULL, 0) != 0) { + free(fn); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + db->hdb_db = d; + + /* From here on out always DB_close() before returning on error */ + + ret = _open_db(d, fn, myflags, flags, mode, &db3->lock_fd); + free(fn); + if (ret == ENOENT) { + /* try to open without .db extension */ + ret = _open_db(d, db->hdb_name, myflags, flags, mode, &db3->lock_fd); + } + + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "opening %s: %s", + db->hdb_name, strerror(ret)); + return ret; + } + +#ifndef DB_CURSOR_BULK +# define DB_CURSOR_BULK 0 /* Missing with DB < 4.8 */ +#endif + ret = (*d->cursor)(d, NULL, &dbc, DB_CURSOR_BULK); + + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "d->cursor: %s", strerror(ret)); + return ret; + } + db->hdb_dbc = dbc; + + if((flags & O_ACCMODE) == O_RDONLY) + ret = hdb_check_db_format(context, db); + else + ret = hdb_init_db(context, db); + if(ret == HDB_ERR_NOENTRY) + return 0; + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (flags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + + return ret; +} + +krb5_error_code +hdb_db3_create(krb5_context context, HDB **db, + const char *filename) +{ + DB3_HDB **db3 = (DB3_HDB **)db; + *db3 = calloc(1, sizeof(**db3)); /* Allocate space for the larger db3 */ + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = NULL; + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + (*db)->hdb_open = DB_open; + (*db)->hdb_close = DB_close; + (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; + (*db)->hdb_store = _hdb_store; + (*db)->hdb_remove = _hdb_remove; + (*db)->hdb_firstkey = DB_firstkey; + (*db)->hdb_nextkey= DB_nextkey; + (*db)->hdb_lock = DB_lock; + (*db)->hdb_unlock = DB_unlock; + (*db)->hdb_rename = DB_rename; + (*db)->hdb__get = DB__get; + (*db)->hdb__put = DB__put; + (*db)->hdb__del = DB__del; + (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; + + (*db3)->lock_fd = -1; + return 0; +} +#endif /* HAVE_DB3 */ diff --git a/third_party/heimdal/lib/hdb/dbinfo.c b/third_party/heimdal/lib/hdb/dbinfo.c new file mode 100644 index 0000000..60b11f8 --- /dev/null +++ b/third_party/heimdal/lib/hdb/dbinfo.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +struct hdb_dbinfo { + char *label; + char *realm; + char *dbname; + char *mkey_file; + char *acl_file; + char *log_file; + const krb5_config_binding *binding; + struct hdb_dbinfo *next; +}; + +static int +get_dbinfo(krb5_context context, + const krb5_config_binding *db_binding, + const char *label, + struct hdb_dbinfo **db) +{ + struct hdb_dbinfo *di; + const char *p; + + *db = NULL; + + p = krb5_config_get_string(context, db_binding, "dbname", NULL); + if(p == NULL) + return 0; + + di = calloc(1, sizeof(*di)); + if (di == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + di->label = strdup(label); + di->dbname = strdup(p); + + p = krb5_config_get_string(context, db_binding, "realm", NULL); + if(p) + di->realm = strdup(p); + p = krb5_config_get_string(context, db_binding, "mkey_file", NULL); + if(p) + di->mkey_file = strdup(p); + p = krb5_config_get_string(context, db_binding, "acl_file", NULL); + if(p) + di->acl_file = strdup(p); + p = krb5_config_get_string(context, db_binding, "log_file", NULL); + if(p) + di->log_file = strdup(p); + + di->binding = db_binding; + + *db = di; + return 0; +} + + +int +hdb_get_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) +{ + const krb5_config_binding *db_binding; + struct hdb_dbinfo *di, **dt, *databases; + const char *default_dbname = HDB_DEFAULT_DB; + const char *default_mkey = HDB_DB_DIR "/m-key"; + const char *default_acl = HDB_DB_DIR "/kadmind.acl"; + const char *p; + int ret; + + *dbp = NULL; + dt = NULL; + databases = NULL; + + db_binding = krb5_config_get_list(context, NULL, + "kdc", + "database", + NULL); + if (db_binding) { + + ret = get_dbinfo(context, db_binding, "default", &databases); + if (ret == 0 && databases != NULL) + dt = &databases->next; + + for ( ; db_binding != NULL; db_binding = db_binding->next) { + + if (db_binding->type != krb5_config_list) + continue; + + ret = get_dbinfo(context, db_binding->u.list, + db_binding->name, &di); + if (ret) + krb5_err(context, 1, ret, "failed getting realm"); + + if (di == NULL) + continue; + + if (dt) + *dt = di; + else { + hdb_free_dbinfo(context, &databases); + databases = di; + } + dt = &di->next; + + } + } + + if (databases == NULL) { + /* if there are none specified, create one and use defaults */ + databases = calloc(1, sizeof(*databases)); + databases->label = strdup("default"); + } + + for (di = databases; di; di = di->next) { + if (di->dbname == NULL) { + di->dbname = strdup(default_dbname); + if (di->mkey_file == NULL) + di->mkey_file = strdup(default_mkey); + } + if (di->mkey_file == NULL) { + p = strrchr(di->dbname, '.'); + if(p == NULL || strchr(p, '/') != NULL) + /* final pathname component does not contain a . */ + ret = asprintf(&di->mkey_file, "%s.mkey", di->dbname); + else + /* the filename is something.else, replace .else with + .mkey */ + ret = asprintf(&di->mkey_file, "%.*s.mkey", + (int)(p - di->dbname), di->dbname); + if (ret == -1) { + hdb_free_dbinfo(context, &databases); + return ENOMEM; + } + } + if(di->acl_file == NULL) + di->acl_file = strdup(default_acl); + } + *dbp = databases; + return 0; +} + + +struct hdb_dbinfo * +hdb_dbinfo_get_next(struct hdb_dbinfo *dbp, struct hdb_dbinfo *dbprevp) +{ + if (dbprevp == NULL) + return dbp; + else + return dbprevp->next; +} + +const char * +hdb_dbinfo_get_label(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->label; +} + +const char * +hdb_dbinfo_get_realm(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->realm; +} + +const char * +hdb_dbinfo_get_dbname(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->dbname; +} + +const char * +hdb_dbinfo_get_mkey_file(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->mkey_file; +} + +const char * +hdb_dbinfo_get_acl_file(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->acl_file; +} + +const char * +hdb_dbinfo_get_log_file(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->log_file; +} + +const krb5_config_binding * +hdb_dbinfo_get_binding(krb5_context context, struct hdb_dbinfo *dbp) +{ + return dbp->binding; +} + +void +hdb_free_dbinfo(krb5_context context, struct hdb_dbinfo **dbp) +{ + struct hdb_dbinfo *di, *ndi; + + for(di = *dbp; di != NULL; di = ndi) { + ndi = di->next; + free (di->label); + free (di->realm); + free (di->dbname); + free (di->mkey_file); + free (di->acl_file); + free (di->log_file); + free(di); + } + *dbp = NULL; +} + +/** + * Return the directory where the hdb database resides. + * + * @param context Kerberos 5 context. + * + * @return string pointing to directory. + */ + +const char * +hdb_db_dir(krb5_context context) +{ + const char *p; + + p = krb5_config_get_string(context, NULL, "hdb", "db-dir", NULL); + if (p) + return p; + + return HDB_DB_DIR; +} + +/** + * Return the default hdb database resides. + * + * @param context Kerberos 5 context. + * + * @return string pointing to directory. + */ + +const char * +hdb_default_db(krb5_context context) +{ + static char *default_hdb = NULL; + struct hdb_dbinfo *dbinfo = NULL; + struct hdb_dbinfo *d = NULL; + const char *s; + + if (default_hdb) + return default_hdb; + + (void) hdb_get_dbinfo(context, &dbinfo); + while ((d = hdb_dbinfo_get_next(dbinfo, d)) != NULL) { + if ((s = hdb_dbinfo_get_dbname(context, d)) && + (default_hdb = strdup(s))) + break; + } + + hdb_free_dbinfo(context, &dbinfo); + return default_hdb ? default_hdb : HDB_DEFAULT_DB; +} diff --git a/third_party/heimdal/lib/hdb/ext.c b/third_party/heimdal/lib/hdb/ext.c new file mode 100644 index 0000000..465a235 --- /dev/null +++ b/third_party/heimdal/lib/hdb/ext.c @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2004 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#include + +krb5_error_code +hdb_entry_check_mandatory(krb5_context context, const hdb_entry *ent) +{ + size_t i; + + if (ent->extensions == NULL) + return 0; + + /* + * check for unknown extensions and if they were tagged mandatory + */ + + for (i = 0; i < ent->extensions->len; i++) { + if (ent->extensions->val[i].data.element != + choice_HDB_extension_data_asn1_ellipsis) + continue; + if (ent->extensions->val[i].mandatory) { + krb5_set_error_message(context, HDB_ERR_MANDATORY_OPTION, + "Principal has unknown " + "mandatory extension"); + return HDB_ERR_MANDATORY_OPTION; + } + } + return 0; +} + +HDB_extension * +hdb_find_extension(const hdb_entry *entry, int type) +{ + size_t i; + + if (entry->extensions == NULL) + return NULL; + + for (i = 0; i < entry->extensions->len; i++) + if (entry->extensions->val[i].data.element == (unsigned)type) + return &entry->extensions->val[i]; + return NULL; +} + +/* + * Replace the extension `ext' in `entry'. Make a copy of the + * extension, so the caller must still free `ext' on both success and + * failure. Returns 0 or error code. + */ + +krb5_error_code +hdb_replace_extension(krb5_context context, + hdb_entry *entry, + const HDB_extension *ext) +{ + HDB_extension *ext2; + int ret; + + ext2 = NULL; + + if (entry->extensions == NULL) { + entry->extensions = calloc(1, sizeof(*entry->extensions)); + if (entry->extensions == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + } else if (ext->data.element != choice_HDB_extension_data_asn1_ellipsis) { + ext2 = hdb_find_extension(entry, ext->data.element); + } else { + /* + * This is an unknown extension, and we are asked to replace a + * possible entry in `entry' that is of the same type. This + * might seem impossible, but ASN.1 CHOICE comes to our + * rescue. The first tag in each branch in the CHOICE is + * unique, so just find the element in the list that have the + * same tag was we are putting into the list. + */ + Der_class replace_class, list_class; + Der_type replace_type, list_type; + unsigned int replace_tag, list_tag; + size_t size; + size_t i; + + ret = der_get_tag(ext->data.u.asn1_ellipsis.data, + ext->data.u.asn1_ellipsis.length, + &replace_class, &replace_type, &replace_tag, + &size); + if (ret) { + krb5_set_error_message(context, ret, "hdb: failed to decode " + "replacement hdb extension"); + return ret; + } + + for (i = 0; i < entry->extensions->len; i++) { + HDB_extension *ext3 = &entry->extensions->val[i]; + + if (ext3->data.element != choice_HDB_extension_data_asn1_ellipsis) + continue; + + ret = der_get_tag(ext3->data.u.asn1_ellipsis.data, + ext3->data.u.asn1_ellipsis.length, + &list_class, &list_type, &list_tag, + &size); + if (ret) { + krb5_set_error_message(context, ret, "hdb: failed to decode " + "present hdb extension"); + return ret; + } + + if (MAKE_TAG(replace_class,replace_type,replace_type) == + MAKE_TAG(list_class,list_type,list_type)) { + ext2 = ext3; + break; + } + } + } + + if (ext2) { + free_HDB_extension(ext2); + ret = copy_HDB_extension(ext, ext2); + if (ret) + krb5_set_error_message(context, ret, "hdb: failed to copy replacement " + "hdb extension"); + return ret; + } + + return add_HDB_extensions(entry->extensions, ext); +} + +krb5_error_code +hdb_clear_extension(krb5_context context, + hdb_entry *entry, + int type) +{ + size_t i; + + if (entry->extensions == NULL) + return 0; + + for (i = 0; i < entry->extensions->len; ) { + if (entry->extensions->val[i].data.element == (unsigned)type) + (void) remove_HDB_extensions(entry->extensions, i); + else + i++; + } + if (entry->extensions->len == 0) { + free(entry->extensions->val); + free(entry->extensions); + entry->extensions = NULL; + } + + return 0; +} + + +krb5_error_code +hdb_entry_get_pkinit_acl(const hdb_entry *entry, const HDB_Ext_PKINIT_acl **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_acl); + if (ext) + *a = &ext->data.u.pkinit_acl; + else + *a = NULL; + + return 0; +} + +krb5_error_code +hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert_hash); + if (ext) + *a = &ext->data.u.pkinit_cert_hash; + else + *a = NULL; + + return 0; +} + +krb5_error_code +hdb_entry_get_pkinit_cert(const hdb_entry *entry, const HDB_Ext_PKINIT_cert **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert); + if (ext) + *a = &ext->data.u.pkinit_cert; + else + *a = NULL; + + return 0; +} + +krb5_error_code +hdb_entry_get_krb5_config(const hdb_entry *entry, heim_octet_string *c) +{ + const HDB_extension *ext; + + c->data = NULL; + c->length = 0; + ext = hdb_find_extension(entry, choice_HDB_extension_data_krb5_config); + if (ext) + *c = ext->data.u.krb5_config; + return 0; +} + +krb5_error_code +hdb_entry_set_krb5_config(krb5_context context, + hdb_entry *entry, + heim_octet_string *s) +{ + HDB_extension ext; + + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_last_pw_change; + /* hdb_replace_extension() copies this, so no need to copy it here */ + ext.data.u.krb5_config = *s; + return hdb_replace_extension(context, entry, &ext); +} + +krb5_error_code +hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_last_pw_change); + if (ext) + *t = ext->data.u.last_pw_change; + else + *t = 0; + + return 0; +} + +krb5_error_code +hdb_entry_set_pw_change_time(krb5_context context, + hdb_entry *entry, + time_t t) +{ + HDB_extension ext; + + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_last_pw_change; + if (t == 0) + t = time(NULL); + ext.data.u.last_pw_change = t; + + return hdb_replace_extension(context, entry, &ext); +} + +int +hdb_entry_get_password(krb5_context context, HDB *db, + const hdb_entry *entry, char **p) +{ + HDB_extension *ext; + char *str; + int ret; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_password); + if (ext) { + heim_utf8_string xstr; + heim_octet_string pw; + + if (db->hdb_master_key_set && ext->data.u.password.mkvno) { + hdb_master_key key; + + key = _hdb_find_master_key(ext->data.u.password.mkvno, + db->hdb_master_key); + + if (key == NULL) { + krb5_set_error_message(context, HDB_ERR_NO_MKEY, + "master key %d missing", + *ext->data.u.password.mkvno); + return HDB_ERR_NO_MKEY; + } + + ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, + ext->data.u.password.password.data, + ext->data.u.password.password.length, + &pw); + } else { + ret = der_copy_octet_string(&ext->data.u.password.password, &pw); + } + if (ret) { + krb5_clear_error_message(context); + return ret; + } + + xstr = pw.data; + if (xstr[pw.length - 1] != '\0') { + krb5_set_error_message(context, EINVAL, "malformed password"); + return EINVAL; + } + + *p = strdup(xstr); + + der_free_octet_string(&pw); + if (*p == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + return 0; + } + + ret = krb5_unparse_name(context, entry->principal, &str); + if (ret == 0) { + krb5_set_error_message(context, ENOENT, + "no password attribute for %s", str); + free(str); + } else + krb5_clear_error_message(context); + + return ENOENT; +} + +int +hdb_entry_set_password(krb5_context context, HDB *db, + hdb_entry *entry, const char *p) +{ + HDB_extension ext; + hdb_master_key key; + int ret; + + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_password; + + if (db->hdb_master_key_set) { + + key = _hdb_find_master_key(NULL, db->hdb_master_key); + if (key == NULL) { + krb5_set_error_message(context, HDB_ERR_NO_MKEY, + "hdb_entry_set_password: " + "failed to find masterkey"); + return HDB_ERR_NO_MKEY; + } + + ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, + p, strlen(p) + 1, + &ext.data.u.password.password); + if (ret) + return ret; + + ext.data.u.password.mkvno = + malloc(sizeof(*ext.data.u.password.mkvno)); + if (ext.data.u.password.mkvno == NULL) { + free_HDB_extension(&ext); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + *ext.data.u.password.mkvno = _hdb_mkey_version(key); + + } else { + ext.data.u.password.mkvno = NULL; + + ret = krb5_data_copy(&ext.data.u.password.password, + p, strlen(p) + 1); + if (ret) { + krb5_set_error_message(context, ret, "malloc: out of memory"); + free_HDB_extension(&ext); + return ret; + } + } + + ret = hdb_replace_extension(context, entry, &ext); + + free_HDB_extension(&ext); + + return ret; +} + +int +hdb_entry_clear_password(krb5_context context, hdb_entry *entry) +{ + return hdb_clear_extension(context, entry, + choice_HDB_extension_data_password); +} + +krb5_error_code +hdb_entry_get_ConstrainedDelegACL(const hdb_entry *entry, + const HDB_Ext_Constrained_delegation_acl **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, + choice_HDB_extension_data_allowed_to_delegate_to); + if (ext) + *a = &ext->data.u.allowed_to_delegate_to; + else + *a = NULL; + + return 0; +} + +krb5_error_code +hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_aliases); + if (ext) + *a = &ext->data.u.aliases; + else + *a = NULL; + + return 0; +} + +unsigned int +hdb_entry_get_kvno_diff_clnt(const hdb_entry *entry) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, + choice_HDB_extension_data_hist_kvno_diff_clnt); + if (ext) + return ext->data.u.hist_kvno_diff_clnt; + return 1; +} + +krb5_error_code +hdb_entry_set_kvno_diff_clnt(krb5_context context, hdb_entry *entry, + unsigned int diff) +{ + HDB_extension ext; + + if (diff > 16384) + return EINVAL; + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt; + ext.data.u.hist_kvno_diff_clnt = diff; + return hdb_replace_extension(context, entry, &ext); +} + +krb5_error_code +hdb_entry_clear_kvno_diff_clnt(krb5_context context, hdb_entry *entry) +{ + return hdb_clear_extension(context, entry, + choice_HDB_extension_data_hist_kvno_diff_clnt); +} + +unsigned int +hdb_entry_get_kvno_diff_svc(const hdb_entry *entry) +{ + const HDB_extension *ext; + + ext = hdb_find_extension(entry, + choice_HDB_extension_data_hist_kvno_diff_svc); + if (ext) + return ext->data.u.hist_kvno_diff_svc; + return 1024; /* max_life effectively provides a better default */ +} + +krb5_error_code +hdb_entry_set_kvno_diff_svc(krb5_context context, hdb_entry *entry, + unsigned int diff) +{ + HDB_extension ext; + + if (diff > 16384) + return EINVAL; + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc; + ext.data.u.hist_kvno_diff_svc = diff; + return hdb_replace_extension(context, entry, &ext); +} + +krb5_error_code +hdb_entry_clear_kvno_diff_svc(krb5_context context, hdb_entry *entry) +{ + return hdb_clear_extension(context, entry, + choice_HDB_extension_data_hist_kvno_diff_svc); +} + +krb5_error_code +hdb_set_last_modified_by(krb5_context context, hdb_entry *entry, + krb5_principal modby, time_t modtime) +{ + krb5_error_code ret; + Event *old_ev; + Event *ev; + + old_ev = entry->modified_by; + + ev = calloc(1, sizeof (*ev)); + if (!ev) + return ENOMEM; + if (modby) + ret = krb5_copy_principal(context, modby, &ev->principal); + else + ret = krb5_parse_name(context, "root/admin", &ev->principal); + if (ret) { + free(ev); + return ret; + } + ev->time = modtime; + if (!ev->time) + time(&ev->time); + + entry->modified_by = ev; + if (old_ev) + free_Event(old_ev); + return 0; +} + +krb5_error_code +hdb_entry_get_key_rotation(krb5_context context, + const hdb_entry *entry, + const HDB_Ext_KeyRotation **kr) +{ + HDB_extension *ext = + hdb_find_extension(entry, choice_HDB_extension_data_key_rotation); + + *kr = ext ? &ext->data.u.key_rotation : NULL; + return 0; +} + +krb5_error_code +hdb_validate_key_rotation(krb5_context context, + const KeyRotation *past_kr, + const KeyRotation *new_kr) +{ + unsigned int last_kvno; + + if (new_kr->period < 1) { + krb5_set_error_message(context, EINVAL, + "Key rotation periods must be non-zero " + "and positive"); + return EINVAL; + } + if (new_kr->base_key_kvno < 1 || new_kr->base_kvno < 1) { + krb5_set_error_message(context, EINVAL, + "Key version number zero not allowed " + "for key rotation"); + return EINVAL; + } + if (!past_kr) + return 0; + + if (past_kr->base_key_kvno == new_kr->base_key_kvno) { + /* + * The new base keys can be the same as the old, but must have + * different kvnos. (Well, not must must. It's a convention for now.) + */ + krb5_set_error_message(context, EINVAL, + "Base key version numbers for KRs must differ"); + return EINVAL; + } + if (new_kr->epoch - past_kr->epoch <= 0) { + krb5_set_error_message(context, EINVAL, + "New key rotation periods must start later " + "than existing ones"); + return EINVAL; + } + + last_kvno = 1 + ((new_kr->epoch - past_kr->epoch) / past_kr->period); + if (new_kr->base_kvno <= last_kvno) { + krb5_set_error_message(context, EINVAL, + "New key rotation base kvno must be larger " + "than the last kvno for the current key " + "rotation (%u)", last_kvno); + return EINVAL; + } + return 0; +} + +static int +kr_eq(const KeyRotation *a, const KeyRotation *b) +{ + return !!( + a->epoch == b->epoch && + a->period == b->period && + a->base_kvno == b->base_kvno && + a->base_key_kvno == b->base_key_kvno && + KeyRotationFlags2int(a->flags) == KeyRotationFlags2int(b->flags) + ); +} + +krb5_error_code +hdb_validate_key_rotations(krb5_context context, + const HDB_Ext_KeyRotation *existing, + const HDB_Ext_KeyRotation *krs) +{ + krb5_error_code ret = 0; + size_t added = 0; + size_t i; + + if ((!existing || !existing->len) && (!krs || !krs->len)) + return 0; /* Nothing to do; weird */ + + /* + * HDB_Ext_KeyRotation has to have 1..3 elements, and this is enforced by + * the ASN.1 compiler and the code it generates. Nonetheless we'll check + * that there's not zero elements. + */ + if ((!krs || !krs->len)) { + /* + * NOTE: We can clear this on concrete principals with virtual keys + * though. The caller can check for that case. + */ + krb5_set_error_message(context, EINVAL, + "Cannot clear key rotation metadata on " + "virtual principal namespaces"); + ret = EINVAL; + } + + /* Validate the new KRs by themselves */ + for (i = 0; ret == 0 && i < krs->len; i++) { + ret = hdb_validate_key_rotation(context, + i+1 < krs->len ? &krs->val[i+1] : 0, + &krs->val[i]); + } + if (ret || !existing || !existing->len) + return ret; + + if (existing->len == krs->len) { + /* Check for no change */ + for (i = 0; i < krs->len; i++) + if (!kr_eq(&existing->val[i], &krs->val[i])) + break; + if (i == krs->len) + return 0; /* No change */ + } + + /* + * Check that new KRs make sense in the context of the previous KRs. + * + * Permitted changes: + * + * - add one new KR in front + * - drop old KRs + * + * Start by checking if we're adding a KR, then go on to check for dropped + * KRs and/or last KR alteration. + */ + if (existing->val[0].epoch == krs->val[0].epoch || + existing->val[0].base_kvno == krs->val[0].base_kvno) { + if (!kr_eq(&existing->val[0], &krs->val[0])) { + krb5_set_error_message(context, EINVAL, + "Key rotation change not sensible"); + ret = EINVAL; + } + /* Key rotation *not* added */ + } else { + /* Key rotation added; check it first */ + ret = hdb_validate_key_rotation(context, + &existing->val[0], + &krs->val[0]); + added = 1; + } + for (i = 0; ret == 0 && i < existing->len && i + added < krs->len; i++) + if (!kr_eq(&existing->val[i], &krs->val[i + added])) + krb5_set_error_message(context, ret = EINVAL, + "Only last key rotation may be truncated"); + return ret; +} + +/* XXX We need a function to "revoke" the past */ + +/** + * This function adds a KeyRotation value to an entry, validating the + * change. One of `entry' and `krs' must be NULL, and the other non-NULL, and + * whichever is given will be altered. + * + * @param context Context + * @param entry An HDB entry + * @param krs A key rotation extension for hdb_entry + * @param kr A new KeyRotation value + * + * @return Zero on success, an error otherwise. + */ +krb5_error_code +hdb_entry_add_key_rotation(krb5_context context, + hdb_entry *entry, + HDB_Ext_KeyRotation *krs, + const KeyRotation *kr) +{ + krb5_error_code ret; + HDB_extension new_ext; + HDB_extension *ext = &new_ext; + KeyRotation tmp; + size_t i, sz; + + if (kr->period < 1) { + krb5_set_error_message(context, EINVAL, + "Key rotation period cannot be zero"); + return EINVAL; + } + + new_ext.mandatory = TRUE; + new_ext.data.element = choice_HDB_extension_data_key_rotation; + new_ext.data.u.key_rotation.len = 0; + new_ext.data.u.key_rotation.val = 0; + + if (entry && krs) + return EINVAL; + + if (entry) { + ext = hdb_find_extension(entry, choice_HDB_extension_data_key_rotation); + if (!ext) + ext = &new_ext; + } else { + const KeyRotation *prev_kr = &krs->val[0]; + unsigned int last_kvno = 0; + + if (kr->epoch - prev_kr->epoch <= 0) { + krb5_set_error_message(context, EINVAL, + "New key rotation periods must start later " + "than existing ones"); + return EINVAL; + } + + if (kr->base_kvno <= prev_kr->base_kvno || + kr->base_kvno - prev_kr->base_kvno <= + (last_kvno = 1 + + ((kr->epoch - prev_kr->epoch) / prev_kr->period))) { + krb5_set_error_message(context, EINVAL, + "New key rotation base kvno must be larger " + "than the last kvno for the current key " + "rotation (%u)", last_kvno); + return EINVAL; + } + } + + /* First, append */ + ret = add_HDB_Ext_KeyRotation(&ext->data.u.key_rotation, kr); + if (ret) + return ret; + + /* Rotate new to front */ + tmp = ext->data.u.key_rotation.val[ext->data.u.key_rotation.len - 1]; + sz = sizeof(ext->data.u.key_rotation.val[0]); + memmove(&ext->data.u.key_rotation.val[1], &ext->data.u.key_rotation.val[0], + (ext->data.u.key_rotation.len - 1) * sz); + ext->data.u.key_rotation.val[0] = tmp; + + /* Drop too old entries */ + for (i = 3; i < ext->data.u.key_rotation.len; i++) + free_KeyRotation(&ext->data.u.key_rotation.val[i]); + ext->data.u.key_rotation.len = + ext->data.u.key_rotation.len > 3 ? 3 : ext->data.u.key_rotation.len; + + if (ext != &new_ext) + return 0; + + /* Install new extension */ + if (ret == 0 && entry) + ret = hdb_replace_extension(context, entry, ext); + free_HDB_extension(&new_ext); + return ret; +} diff --git a/third_party/heimdal/lib/hdb/hdb-keytab.c b/third_party/heimdal/lib/hdb/hdb-keytab.c new file mode 100644 index 0000000..c9b469c --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb-keytab.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#include + +typedef struct { + char *path; + krb5_keytab keytab; +} *hdb_keytab; + +/* + * + */ + +static krb5_error_code +hkt_close(krb5_context context, HDB *db) +{ + hdb_keytab k = (hdb_keytab)db->hdb_db; + krb5_error_code ret; + + assert(k->keytab); + + ret = krb5_kt_close(context, k->keytab); + k->keytab = NULL; + + return ret; +} + +static krb5_error_code +hkt_destroy(krb5_context context, HDB *db) +{ + hdb_keytab k = (hdb_keytab)db->hdb_db; + krb5_error_code ret; + + ret = hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + + free(k->path); + free(k); + + free(db->hdb_name); + free(db); + return ret; +} + +static krb5_error_code +hkt_lock(krb5_context context, HDB *db, int operation) +{ + return 0; +} + +static krb5_error_code +hkt_unlock(krb5_context context, HDB *db) +{ + return 0; +} + +static krb5_error_code +hkt_firstkey(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry) +{ + return HDB_ERR_DB_INUSE; +} + +static krb5_error_code +hkt_nextkey(krb5_context context, HDB * db, unsigned flags, + hdb_entry * entry) +{ + return HDB_ERR_DB_INUSE; +} + +static krb5_error_code +hkt_open(krb5_context context, HDB * db, int flags, mode_t mode) +{ + hdb_keytab k = (hdb_keytab)db->hdb_db; + krb5_error_code ret; + + assert(k->keytab == NULL); + + ret = krb5_kt_resolve(context, k->path, &k->keytab); + if (ret) + return ret; + + return 0; +} + +static krb5_error_code +hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry * entry) +{ + hdb_keytab k = (hdb_keytab)db->hdb_db; + krb5_error_code ret; + krb5_keytab_entry ktentry; + + if (!(flags & HDB_F_KVNO_SPECIFIED)) { + /* Preserve previous behaviour if no kvno specified */ + kvno = 0; + } + + memset(&ktentry, 0, sizeof(ktentry)); + + entry->flags.server = 1; + entry->flags.forwardable = 1; + entry->flags.renewable = 1; + + /* Not recorded in the OD backend, make something up */ + ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND", + &entry->created_by.principal); + if (ret) + goto out; + + /* + * XXX really needs to try all enctypes and just not pick the + * first one, even if that happens to be des3-cbc-sha1 (ie best + * enctype) in the Apple case. A while loop over all known + * enctypes should work. + */ + + ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry); + if (ret) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + ret = krb5_copy_principal(context, principal, &entry->principal); + if (ret) + goto out; + + ret = _hdb_keytab2hdb_entry(context, &ktentry, entry); + + out: + if (ret) { + free_HDB_entry(entry); + memset(entry, 0, sizeof(*entry)); + } + krb5_kt_free_entry(context, &ktentry); + + return ret; +} + +static krb5_error_code +hkt_store(krb5_context context, HDB * db, unsigned flags, + hdb_entry * entry) +{ + return HDB_ERR_DB_INUSE; +} + + +krb5_error_code +hdb_keytab_create(krb5_context context, HDB ** db, const char *arg) +{ + hdb_keytab k; + + *db = calloc(1, sizeof(**db)); + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + memset(*db, 0, sizeof(**db)); + + k = calloc(1, sizeof(*k)); + if (k == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + k->path = strdup(arg); + if (k->path == NULL) { + free(k); + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + + (*db)->hdb_db = k; + + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_open = hkt_open; + (*db)->hdb_close = hkt_close; + (*db)->hdb_fetch_kvno = hkt_fetch_kvno; + (*db)->hdb_store = hkt_store; + (*db)->hdb_remove = NULL; + (*db)->hdb_firstkey = hkt_firstkey; + (*db)->hdb_nextkey = hkt_nextkey; + (*db)->hdb_lock = hkt_lock; + (*db)->hdb_unlock = hkt_unlock; + (*db)->hdb_rename = NULL; + (*db)->hdb__get = NULL; + (*db)->hdb__put = NULL; + (*db)->hdb__del = NULL; + (*db)->hdb_destroy = hkt_destroy; + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/hdb-ldap.c b/third_party/heimdal/lib/hdb/hdb-ldap.c new file mode 100644 index 0000000..902426d --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb-ldap.c @@ -0,0 +1,2118 @@ +/* + * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd. + * Copyright (c) 2004, Andrew Bartlett. + * Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan. + * Copyright (c) 2015, Timothy Pearson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#ifdef OPENLDAP + +#include +#include +#include +#include + +static krb5_error_code LDAP__connect(krb5_context context, HDB *); +static krb5_error_code LDAP_close(krb5_context context, HDB *); + +static krb5_error_code +LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, + int flags, hdb_entry * ent); + +static const char *default_structural_object = "account"; +static char *structural_object; +static const char *default_ldap_url = "ldapi:///"; +static krb5_boolean samba_forwardable; + +struct hdbldapdb { + LDAP *h_lp; + int h_msgid; + char *h_base; + char *h_url; + char *h_bind_dn; + char *h_bind_password; + krb5_boolean h_start_tls; + char *h_createbase; +}; + +#define HDB2LDAP(db) (((struct hdbldapdb *)(db)->hdb_db)->h_lp) +#define HDB2MSGID(db) (((struct hdbldapdb *)(db)->hdb_db)->h_msgid) +#define HDBSETMSGID(db,msgid) \ + do { ((struct hdbldapdb *)(db)->hdb_db)->h_msgid = msgid; } while(0) +#define HDB2BASE(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_base) +#define HDB2URL(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_url) +#define HDB2BINDDN(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_dn) +#define HDB2BINDPW(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_password) +#define HDB2CREATE(db) (((struct hdbldapdb *)(db)->hdb_db)->h_createbase) + +/* + * + */ + +static char * krb5kdcentry_attrs[] = { + "cn", + "createTimestamp", + "creatorsName", + "krb5EncryptionType", + "krb5KDCFlags", + "krb5Key", + "krb5KeyVersionNumber", + "krb5MaxLife", + "krb5MaxRenew", + "krb5PasswordEnd", + "krb5PrincipalName", + "krb5PrincipalRealm", + "krb5ExtendedAttributes", + "krb5ValidEnd", + "krb5ValidStart", + "modifiersName", + "modifyTimestamp", + "objectClass", + "sambaAcctFlags", + "sambaKickoffTime", + "sambaNTPassword", + "sambaPwdLastSet", + "sambaPwdMustChange", + "uid", + NULL +}; + +static char *krb5principal_attrs[] = { + "cn", + "createTimestamp", + "creatorsName", + "krb5PrincipalName", + "krb5PrincipalRealm", + "modifiersName", + "modifyTimestamp", + "objectClass", + "uid", + NULL +}; + +static int +LDAP_no_size_limit(krb5_context context, LDAP *lp) +{ + int ret, limit = LDAP_NO_LIMIT; + + ret = ldap_set_option(lp, LDAP_OPT_SIZELIMIT, (const void *)&limit); + if (ret != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_set_option: %s", + ldap_err2string(ret)); + return HDB_ERR_BADVERSION; + } + return 0; +} + +static int +check_ldap(krb5_context context, HDB *db, int ret) +{ + switch (ret) { + case LDAP_SUCCESS: + return 0; + case LDAP_SERVER_DOWN: + LDAP_close(context, db); + return 1; + default: + return 1; + } +} + +static krb5_error_code +LDAP__setmod(LDAPMod *** modlist, int modop, const char *attribute, + int *pIndex) +{ + int cMods; + + if (*modlist == NULL) { + *modlist = (LDAPMod **)ber_memcalloc(1, sizeof(LDAPMod *)); + if (*modlist == NULL) + return ENOMEM; + } + + for (cMods = 0; (*modlist)[cMods] != NULL; cMods++) { + if ((*modlist)[cMods]->mod_op == modop && + strcasecmp((*modlist)[cMods]->mod_type, attribute) == 0) { + break; + } + } + + *pIndex = cMods; + + if ((*modlist)[cMods] == NULL) { + LDAPMod *mod; + + *modlist = (LDAPMod **)ber_memrealloc(*modlist, + (cMods + 2) * sizeof(LDAPMod *)); + if (*modlist == NULL) + return ENOMEM; + + (*modlist)[cMods] = (LDAPMod *)ber_memalloc(sizeof(LDAPMod)); + if ((*modlist)[cMods] == NULL) + return ENOMEM; + + mod = (*modlist)[cMods]; + mod->mod_op = modop; + mod->mod_type = ber_strdup(attribute); + if (mod->mod_type == NULL) { + ber_memfree(mod); + (*modlist)[cMods] = NULL; + return ENOMEM; + } + + if (modop & LDAP_MOD_BVALUES) { + mod->mod_bvalues = NULL; + } else { + mod->mod_values = NULL; + } + + (*modlist)[cMods + 1] = NULL; + } + + return 0; +} + +static krb5_error_code +LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute, + unsigned char *value, size_t len) +{ + krb5_error_code ret; + int cMods, i = 0; + + ret = LDAP__setmod(modlist, modop | LDAP_MOD_BVALUES, attribute, &cMods); + if (ret) + return ret; + + if (value != NULL) { + struct berval **bv; + + bv = (*modlist)[cMods]->mod_bvalues; + if (bv != NULL) { + for (i = 0; bv[i] != NULL; i++) + ; + bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv)); + } else + bv = ber_memalloc(2 * sizeof(*bv)); + if (bv == NULL) + return ENOMEM; + + (*modlist)[cMods]->mod_bvalues = bv; + + bv[i] = ber_memalloc(sizeof(**bv));; + if (bv[i] == NULL) + return ENOMEM; + + bv[i]->bv_val = (void *)value; + bv[i]->bv_len = len; + + bv[i + 1] = NULL; + } + + return 0; +} + +static krb5_error_code +LDAP_addmod(LDAPMod *** modlist, int modop, const char *attribute, + const char *value) +{ + int cMods, i = 0; + krb5_error_code ret; + + ret = LDAP__setmod(modlist, modop, attribute, &cMods); + if (ret) + return ret; + + if (value != NULL) { + char **bv; + + bv = (*modlist)[cMods]->mod_values; + if (bv != NULL) { + for (i = 0; bv[i] != NULL; i++) + ; + bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv)); + } else + bv = ber_memalloc(2 * sizeof(*bv)); + if (bv == NULL) + return ENOMEM; + + (*modlist)[cMods]->mod_values = bv; + + bv[i] = ber_strdup(value); + if (bv[i] == NULL) + return ENOMEM; + + bv[i + 1] = NULL; + } + + return 0; +} + +static krb5_error_code +LDAP_addmod_generalized_time(LDAPMod *** mods, int modop, + const char *attribute, KerberosTime * time) +{ + char buf[22]; + struct tm *tm; + + /* XXX not threadsafe */ + tm = gmtime(time); + strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm); + + return LDAP_addmod(mods, modop, attribute, buf); +} + +static krb5_error_code +LDAP_addmod_integer(krb5_context context, + LDAPMod *** mods, int modop, + const char *attribute, unsigned long l) +{ + krb5_error_code ret; + char *buf; + + ret = asprintf(&buf, "%ld", l); + if (ret < 0) { + krb5_set_error_message(context, ENOMEM, + "asprintf: out of memory:"); + return ENOMEM; + } + ret = LDAP_addmod(mods, modop, attribute, buf); + free (buf); + return ret; +} + +static krb5_error_code +LDAP_get_string_value(HDB * db, LDAPMessage * entry, + const char *attribute, char **ptr) +{ + struct berval **vals; + + vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute); + if (vals == NULL || vals[0] == NULL) { + *ptr = NULL; + return HDB_ERR_NOENTRY; + } + + *ptr = malloc(vals[0]->bv_len + 1); + if (*ptr == NULL) { + ldap_value_free_len(vals); + return ENOMEM; + } + + memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len); + (*ptr)[vals[0]->bv_len] = 0; + + ldap_value_free_len(vals); + + return 0; +} + +static krb5_error_code +LDAP_get_integer_value(HDB * db, LDAPMessage * entry, + const char *attribute, int *ptr) +{ + krb5_error_code ret; + char *val; + + ret = LDAP_get_string_value(db, entry, attribute, &val); + if (ret) + return ret; + *ptr = atoi(val); + free(val); + return 0; +} + +static krb5_error_code +LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry, + const char *attribute, KerberosTime * kt) +{ + char *tmp, *gentime; + struct tm tm; + int ret; + + *kt = 0; + + ret = LDAP_get_string_value(db, entry, attribute, &gentime); + if (ret) + return ret; + + memset(&tm, 0, sizeof tm); + tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm); + if (tmp == NULL) { + free(gentime); + return HDB_ERR_NOENTRY; + } + + free(gentime); + + *kt = timegm(&tm); + + return 0; +} + +static int +bervalstrcmp(struct berval *v, const char *str) +{ + size_t len = strlen(str); + return (v->bv_len == len) && strncasecmp(str, (char *)v->bv_val, len) == 0; +} + + +static krb5_error_code +LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry * ent, + LDAPMessage * msg, LDAPMod *** pmods, krb5_boolean *pis_new_entry) +{ + krb5_error_code ret; + krb5_boolean is_new_entry = FALSE; + char *tmp = NULL; + LDAPMod **mods = NULL; + hdb_entry orig; + unsigned long oflags, nflags; + int i; + + krb5_boolean is_samba_account = FALSE; + krb5_boolean is_account = FALSE; + krb5_boolean is_heimdal_entry = FALSE; + krb5_boolean is_heimdal_principal = FALSE; + + struct berval **vals; + + *pmods = NULL; + + if (msg != NULL) { + + ret = LDAP_message2entry(context, db, msg, 0, &orig); + if (ret) + goto out; + + vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass"); + if (vals) { + int num_objectclasses = ldap_count_values_len(vals); + for (i=0; i < num_objectclasses; i++) { + if (bervalstrcmp(vals[i], "sambaSamAccount")) + is_samba_account = TRUE; + else if (bervalstrcmp(vals[i], structural_object)) + is_account = TRUE; + else if (bervalstrcmp(vals[i], "krb5Principal")) + is_heimdal_principal = TRUE; + else if (bervalstrcmp(vals[i], "krb5KDCEntry")) + is_heimdal_entry = TRUE; + } + ldap_value_free_len(vals); + } + + /* + * If this is just a "account" entry and no other objectclass + * is hanging on this entry, it's really a new entry. + */ + if (is_samba_account == FALSE && is_heimdal_principal == FALSE && + is_heimdal_entry == FALSE) { + if (is_account == TRUE) { + is_new_entry = TRUE; + } else { + ret = HDB_ERR_NOENTRY; + goto out; + } + } + } else + is_new_entry = TRUE; + + if (is_new_entry) { + + /* to make it perfectly obvious we're depending on + * orig being intiialized to zero */ + memset(&orig, 0, sizeof(orig)); + + /* account is the structural object class */ + if (is_account == FALSE) { + ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top"); + if (ret) + goto out; + + ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", + structural_object); + is_account = TRUE; + if (ret) + goto out; + } + + ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal"); + is_heimdal_principal = TRUE; + if (ret) + goto out; + + ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry"); + is_heimdal_entry = TRUE; + if (ret) + goto out; + } + + if (is_new_entry || + krb5_principal_compare(context, ent->principal, orig.principal) + == FALSE) + { + if (is_heimdal_principal || is_heimdal_entry) { + + ret = krb5_unparse_name(context, ent->principal, &tmp); + if (ret) + goto out; + + ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, + "krb5PrincipalName", tmp); + if (ret) { + free(tmp); + goto out; + } + free(tmp); + } + + if (is_account || is_samba_account) { + ret = krb5_unparse_name_short(context, ent->principal, &tmp); + if (ret) + goto out; + ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp); + if (ret) { + free(tmp); + goto out; + } + free(tmp); + } + } + + if (is_heimdal_entry && (ent->kvno != orig.kvno || is_new_entry)) { + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "krb5KeyVersionNumber", + ent->kvno); + if (ret) + goto out; + } + + if (is_heimdal_entry && ent->extensions) { + if (!is_new_entry) { + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes"); + if (vals) { + ldap_value_free_len(vals); + ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5ExtendedAttributes", NULL); + if (ret) + goto out; + } + } + + for (i = 0; i < ent->extensions->len; i++) { + unsigned char *buf; + size_t size, sz = 0; + + ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->extensions->val[i], &sz, ret); + if (ret) + goto out; + if (size != sz) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5ExtendedAttributes", buf, sz); + if (ret) + goto out; + } + } + + if (is_heimdal_entry && ent->valid_start) { + if (orig.valid_end == NULL + || (*(ent->valid_start) != *(orig.valid_start))) { + ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, + "krb5ValidStart", + ent->valid_start); + if (ret) + goto out; + } + } + + if (ent->valid_end) { + if (orig.valid_end == NULL || (*(ent->valid_end) != *(orig.valid_end))) { + if (is_heimdal_entry) { + ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, + "krb5ValidEnd", + ent->valid_end); + if (ret) + goto out; + } + if (is_samba_account) { + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "sambaKickoffTime", + *(ent->valid_end)); + if (ret) + goto out; + } + } + } + + if (ent->pw_end) { + if (orig.pw_end == NULL || (*(ent->pw_end) != *(orig.pw_end))) { + if (is_heimdal_entry) { + ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, + "krb5PasswordEnd", + ent->pw_end); + if (ret) + goto out; + } + + if (is_samba_account) { + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "sambaPwdMustChange", + *(ent->pw_end)); + if (ret) + goto out; + } + } + } + + +#if 0 /* we we have last_pw_change */ + if (is_samba_account && ent->last_pw_change) { + if (orig.last_pw_change == NULL || (*(ent->last_pw_change) != *(orig.last_pw_change))) { + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "sambaPwdLastSet", + *(ent->last_pw_change)); + if (ret) + goto out; + } + } +#endif + + if (is_heimdal_entry && ent->max_life) { + if (orig.max_life == NULL + || (*(ent->max_life) != *(orig.max_life))) { + + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "krb5MaxLife", + *(ent->max_life)); + if (ret) + goto out; + } + } + + if (is_heimdal_entry && ent->max_renew) { + if (orig.max_renew == NULL + || (*(ent->max_renew) != *(orig.max_renew))) { + + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "krb5MaxRenew", + *(ent->max_renew)); + if (ret) + goto out; + } + } + + oflags = HDBFlags2int(orig.flags); + nflags = HDBFlags2int(ent->flags); + + if (is_heimdal_entry && oflags != nflags) { + + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "krb5KDCFlags", + nflags); + if (ret) + goto out; + } + + /* Remove keys if they exists, and then replace keys. */ + if (!is_new_entry && orig.keys.len > 0) { + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); + if (vals) { + ldap_value_free_len(vals); + + ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL); + if (ret) + goto out; + } + } + + for (i = 0; i < ent->keys.len; i++) { + + if (is_samba_account + && ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { + char *ntHexPassword; + char *nt; + time_t now = time(NULL); + + /* the key might have been 'sealed', but samba passwords + are clear in the directory */ + ret = hdb_unseal_key(context, db, &ent->keys.val[i]); + if (ret) + goto out; + + nt = ent->keys.val[i].key.keyvalue.data; + /* store in ntPassword, not krb5key */ + ret = hex_encode(nt, 16, &ntHexPassword); + if (ret < 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "hdb-ldap: failed to " + "hex encode key"); + goto out; + } + ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword", + ntHexPassword); + free(ntHexPassword); + if (ret) + goto out; + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "sambaPwdLastSet", now); + if (ret) + goto out; + + /* have to kill the LM passwod if it exists */ + vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword"); + if (vals) { + ldap_value_free_len(vals); + ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, + "sambaLMPassword", NULL); + if (ret) + goto out; + } + + } else if (is_heimdal_entry) { + unsigned char *buf; + size_t len, buf_size; + + ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->keys.val[i], &len, ret); + if (ret) + goto out; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + /* addmod_len _owns_ the key, doesn't need to copy it */ + ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len); + if (ret) + goto out; + } + } + + if (ent->etypes) { + int add_krb5EncryptionType = 0; + + /* + * Only add/modify krb5EncryptionType if it's a new heimdal + * entry or krb5EncryptionType already exists on the entry. + */ + + if (!is_new_entry) { + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); + if (vals) { + ldap_value_free_len(vals); + ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType", + NULL); + if (ret) + goto out; + add_krb5EncryptionType = 1; + } + } else if (is_heimdal_entry) + add_krb5EncryptionType = 1; + + if (add_krb5EncryptionType) { + for (i = 0; i < ent->etypes->len; i++) { + if (is_samba_account && + ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) + { + ; + } else if (is_heimdal_entry) { + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD, + "krb5EncryptionType", + ent->etypes->val[i]); + if (ret) + goto out; + } + } + } + } + + /* for clarity */ + ret = 0; + + out: + + *pis_new_entry = is_new_entry; + + if (ret == 0) + *pmods = mods; + else if (mods != NULL) { + ldap_mods_free(mods, 1); + *pmods = NULL; + } + + if (msg) + hdb_free_entry(context, db, &orig); + + return ret; +} + +static krb5_error_code +LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, + krb5_principal * principal) +{ + krb5_error_code ret; + int rc; + const char *filter = "(objectClass=krb5Principal)"; + LDAPMessage *res = NULL, *e; + char *p; + + ret = LDAP_no_size_limit(context, HDB2LDAP(db)); + if (ret) + goto out; + + rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, + filter, krb5principal_attrs, 0, + NULL, NULL, NULL, + 0, &res); + if (check_ldap(context, db, rc)) { + ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, "ldap_search_ext_s: " + "filter: %s error: %s", + filter, ldap_err2string(rc)); + goto out; + } + + e = ldap_first_entry(HDB2LDAP(db), res); + if (e == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p); + if (ret) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + ret = krb5_parse_name(context, p, principal); + free(p); + + out: + if (res) + ldap_msgfree(res); + + return ret; +} + +static int +need_quote(unsigned char c) +{ + return (c & 0x80) || + (c < 32) || + (c == '(') || + (c == ')') || + (c == '*') || + (c == '\\') || + (c == 0x7f); +} + +static const char hexchar[] = "0123456789ABCDEF"; + +static krb5_error_code +escape_value(krb5_context context, const char *unquoted, char **quoted) +{ + size_t i, len; + + for (i = 0, len = 0; unquoted[i] != '\0'; i++, len++) { + if (need_quote((unsigned char)unquoted[i])) + len += 2; + } + + *quoted = malloc(len + 1); + if (*quoted == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + for (i = 0; unquoted[0] ; unquoted++) { + if (need_quote((unsigned char)unquoted[0])) { + (*quoted)[i++] = '\\'; + (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf]; + (*quoted)[i++] = hexchar[(unquoted[0] ) & 0xf]; + } else + (*quoted)[i++] = (char)unquoted[0]; + } + (*quoted)[i] = '\0'; + return 0; +} + + +static krb5_error_code +LDAP__lookup_princ(krb5_context context, + HDB *db, + const char *princname, + const char *userid, + LDAPMessage **msg) +{ + krb5_error_code ret; + int rc; + char *quote, *filter = NULL; + + ret = LDAP__connect(context, db); + if (ret) + return ret; + + /* + * Quote searches that contain filter language, this quote + * searches for *@REALM, which takes very long time. + */ + + ret = escape_value(context, princname, "e); + if (ret) + goto out; + + rc = asprintf(&filter, + "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))", + quote); + free(quote); + + if (rc < 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + + ret = LDAP_no_size_limit(context, HDB2LDAP(db)); + if (ret) + goto out; + + rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), + LDAP_SCOPE_SUBTREE, filter, + krb5kdcentry_attrs, 0, + NULL, NULL, NULL, + 0, msg); + if (check_ldap(context, db, rc)) { + ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, "ldap_search_ext_s: " + "filter: %s - error: %s", + filter, ldap_err2string(rc)); + goto out; + } + + if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) { + free(filter); + filter = NULL; + ldap_msgfree(*msg); + *msg = NULL; + + ret = escape_value(context, userid, "e); + if (ret) + goto out; + + rc = asprintf(&filter, + "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))", + structural_object, quote); + free(quote); + if (rc < 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "asprintf: out of memory"); + goto out; + } + + ret = LDAP_no_size_limit(context, HDB2LDAP(db)); + if (ret) + goto out; + + rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, + filter, krb5kdcentry_attrs, 0, + NULL, NULL, NULL, + 0, msg); + if (check_ldap(context, db, rc)) { + ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, + "ldap_search_ext_s: filter: %s error: %s", + filter, ldap_err2string(rc)); + goto out; + } + } + + ret = 0; + + out: + if (filter) + free(filter); + + return ret; +} + +static krb5_error_code +LDAP_principal2message(krb5_context context, HDB * db, + krb5_const_principal princ, LDAPMessage ** msg) +{ + char *name, *name_short = NULL; + krb5_error_code ret; + krb5_realm *r, *r0; + + *msg = NULL; + + ret = krb5_unparse_name(context, princ, &name); + if (ret) + return ret; + + ret = krb5_get_default_realms(context, &r0); + if(ret) { + free(name); + return ret; + } + for (r = r0; *r != NULL; r++) { + if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) { + ret = krb5_unparse_name_short(context, princ, &name_short); + if (ret) { + krb5_free_host_realm(context, r0); + free(name); + return ret; + } + break; + } + } + krb5_free_host_realm(context, r0); + + ret = LDAP__lookup_princ(context, db, name, name_short, msg); + free(name); + free(name_short); + + return ret; +} + +/* + * Construct an hdb_entry from a directory entry. + */ +static krb5_error_code +LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, + int flags, hdb_entry * ent) +{ + char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; + char *samba_acct_flags = NULL; + struct berval **keys; + struct berval **extensions; + struct berval **vals; + int tmp, tmp_time, i, ret, have_arcfour = 0; + + memset(ent, 0, sizeof(*ent)); + ent->flags = int2HDBFlags(0); + + ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name); + if (ret == 0) { + ret = krb5_parse_name(context, unparsed_name, &ent->principal); + if (ret) + goto out; + } else { + ret = LDAP_get_string_value(db, msg, "uid", + &unparsed_name); + if (ret == 0) { + ret = krb5_parse_name(context, unparsed_name, &ent->principal); + if (ret) + goto out; + } else { + krb5_set_error_message(context, HDB_ERR_NOENTRY, + "hdb-ldap: ldap entry missing" + "principal name"); + return HDB_ERR_NOENTRY; + } + } + + { + int integer; + ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber", + &integer); + if (ret) + ent->kvno = 0; + else + ent->kvno = integer; + } + + keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); + if (keys != NULL) { + size_t l; + + ent->keys.len = ldap_count_values_len(keys); + ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key)); + if (ent->keys.val == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "calloc: out of memory"); + goto out; + } + for (i = 0; i < ent->keys.len; i++) { + decode_Key((unsigned char *) keys[i]->bv_val, + (size_t) keys[i]->bv_len, &ent->keys.val[i], &l); + } + ber_bvecfree(keys); + } else { +#if 1 + /* + * This violates the ASN1 but it allows a principal to + * be related to a general directory entry without creating + * the keys. Hopefully it's OK. + */ + ent->keys.len = 0; + ent->keys.val = NULL; +#else + ret = HDB_ERR_NOENTRY; + goto out; +#endif + } + + extensions = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes"); + if (extensions != NULL) { + size_t l; + + ent->extensions = calloc(1, sizeof(*(ent->extensions))); + if (ent->extensions == NULL) { + ret = krb5_enomem(context); + goto out; + } + ent->extensions->len = ldap_count_values_len(extensions); + ent->extensions->val = (HDB_extension *) calloc(ent->extensions->len, sizeof(HDB_extension)); + if (ent->extensions->val == NULL) { + ent->extensions->len = 0; + ret = krb5_enomem(context); + goto out; + } + for (i = 0; i < ent->extensions->len; i++) { + ret = decode_HDB_extension((unsigned char *) extensions[i]->bv_val, + (size_t) extensions[i]->bv_len, &ent->extensions->val[i], &l); + if (ret) + krb5_set_error_message(context, ret, "decode_HDB_extension failed"); + } + ber_bvecfree(extensions); + } else { + ent->extensions = NULL; + } + + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); + if (vals != NULL) { + ent->etypes = malloc(sizeof(*(ent->etypes))); + if (ent->etypes == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret,"malloc: out of memory"); + goto out; + } + ent->etypes->len = ldap_count_values_len(vals); + ent->etypes->val = calloc(ent->etypes->len, + sizeof(ent->etypes->val[0])); + if (ent->etypes->val == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + ent->etypes->len = 0; + goto out; + } + for (i = 0; i < ent->etypes->len; i++) { + char *buf; + + buf = malloc(vals[i]->bv_len + 1); + if (buf == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + memcpy(buf, vals[i]->bv_val, vals[i]->bv_len); + buf[vals[i]->bv_len] = '\0'; + ent->etypes->val[i] = atoi(buf); + free(buf); + } + ldap_value_free_len(vals); + } + + for (i = 0; i < ent->keys.len; i++) { + if (ent->keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { + have_arcfour = 1; + break; + } + } + + /* manually construct the NT (type 23) key */ + ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN); + if (ret == 0 && have_arcfour == 0) { + unsigned *etypes; + Key *ks; + + ks = realloc(ent->keys.val, + (ent->keys.len + 1) * + sizeof(ent->keys.val[0])); + if (ks == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ent->keys.val = ks; + memset(&ent->keys.val[ent->keys.len], 0, sizeof(Key)); + ent->keys.val[ent->keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; + ret = krb5_data_alloc (&ent->keys.val[ent->keys.len].key.keyvalue, 16); + if (ret) { + krb5_set_error_message(context, ret, "malloc: out of memory"); + ret = ENOMEM; + goto out; + } + ret = hex_decode(ntPasswordIN, + ent->keys.val[ent->keys.len].key.keyvalue.data, 16); + ent->keys.len++; + if (ret == -1) { + krb5_set_error_message(context, ret = EINVAL, + "invalid hex encoding of password"); + goto out; + } + + if (ent->etypes == NULL) { + ent->etypes = malloc(sizeof(*(ent->etypes))); + if (ent->etypes == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ent->etypes->val = NULL; + ent->etypes->len = 0; + } + + for (i = 0; i < ent->etypes->len; i++) + if (ent->etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5) + break; + /* If there is no ARCFOUR enctype, add one */ + if (i == ent->etypes->len) { + etypes = realloc(ent->etypes->val, + (ent->etypes->len + 1) * + sizeof(ent->etypes->val[0])); + if (etypes == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ent->etypes->val = etypes; + ent->etypes->val[ent->etypes->len] = + ETYPE_ARCFOUR_HMAC_MD5; + ent->etypes->len++; + } + } + + ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp", + &ent->created_by.time); + if (ret) + ent->created_by.time = time(NULL); + + ent->created_by.principal = NULL; + + if (flags & HDB_F_ADMIN_DATA) { + ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); + if (ret == 0) { + LDAP_dn2principal(context, db, dn, &ent->created_by.principal); + free(dn); + } + + ent->modified_by = calloc(1, sizeof(*ent->modified_by)); + if (ent->modified_by == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + + ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", + &ent->modified_by->time); + if (ret == 0) { + ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); + if (ret == 0) { + LDAP_dn2principal(context, db, dn, &ent->modified_by->principal); + free(dn); + } else { + free(ent->modified_by); + ent->modified_by = NULL; + } + } + } + + ent->valid_start = malloc(sizeof(*ent->valid_start)); + if (ent->valid_start == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", + ent->valid_start); + if (ret) { + /* OPTIONAL */ + free(ent->valid_start); + ent->valid_start = NULL; + } + + ent->valid_end = malloc(sizeof(*ent->valid_end)); + if (ent->valid_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", + ent->valid_end); + if (ret) { + /* OPTIONAL */ + free(ent->valid_end); + ent->valid_end = NULL; + } + + ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time); + if (ret == 0) { + if (ent->valid_end == NULL) { + ent->valid_end = malloc(sizeof(*ent->valid_end)); + if (ent->valid_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + } + *ent->valid_end = tmp_time; + } + + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", + ent->pw_end); + if (ret) { + /* OPTIONAL */ + free(ent->pw_end); + ent->pw_end = NULL; + } + + ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); + if (ret == 0) { + time_t delta; + + delta = krb5_config_get_time_default(context, NULL, + 0, + "kadmin", + "password_lifetime", + NULL); + + if (delta) { + if (ent->pw_end == NULL) { + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + } + + *ent->pw_end = tmp_time + delta; + } + } + + ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); + if (ret == 0) { + if (ent->pw_end == NULL) { + ent->pw_end = malloc(sizeof(*ent->pw_end)); + if (ent->pw_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + } + *ent->pw_end = tmp_time; + } + + /* OPTIONAL */ + ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); + if (ret == 0) + hdb_entry_set_pw_change_time(context, ent, tmp_time); + + { + int max_life; + + ent->max_life = malloc(sizeof(*ent->max_life)); + if (ent->max_life == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life); + if (ret) { + free(ent->max_life); + ent->max_life = NULL; + } else + *ent->max_life = max_life; + } + + { + int max_renew; + + ent->max_renew = malloc(sizeof(*ent->max_renew)); + if (ent->max_renew == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew); + if (ret) { + free(ent->max_renew); + ent->max_renew = NULL; + } else + *ent->max_renew = max_renew; + } + + ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp); + if (ret) + tmp = 0; + + ent->flags = int2HDBFlags(tmp); + + /* Try and find Samba flags to put into the mix */ + ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags); + if (ret == 0) { + /* parse the [UXW...] string: + + 'N' No password + 'D' Disabled + 'H' Homedir required + 'T' Temp account. + 'U' User account (normal) + 'M' MNS logon user account - what is this ? + 'W' Workstation account + 'S' Server account + 'L' Locked account + 'X' No Xpiry on password + 'I' Interdomain trust account + + */ + + int flags_len = strlen(samba_acct_flags); + + if (flags_len < 2) + goto out2; + + if (samba_acct_flags[0] != '[' + || samba_acct_flags[flags_len - 1] != ']') + goto out2; + + /* Allow forwarding */ + if (samba_forwardable) + ent->flags.forwardable = TRUE; + + for (i=0; i < flags_len; i++) { + switch (samba_acct_flags[i]) { + case ' ': + case '[': + case ']': + break; + case 'N': + /* how to handle no password in kerberos? */ + break; + case 'D': + ent->flags.invalid = TRUE; + break; + case 'H': + break; + case 'T': + /* temp duplicate */ + ent->flags.invalid = TRUE; + break; + case 'U': + ent->flags.client = TRUE; + break; + case 'M': + break; + case 'W': + case 'S': + ent->flags.server = TRUE; + ent->flags.client = TRUE; + break; + case 'L': + ent->flags.invalid = TRUE; + break; + case 'X': + if (ent->pw_end) { + free(ent->pw_end); + ent->pw_end = NULL; + } + break; + case 'I': + ent->flags.server = TRUE; + ent->flags.client = TRUE; + break; + } + } + out2: + free(samba_acct_flags); + } + + ret = 0; + +out: + free(unparsed_name); + free(ntPasswordIN); + + if (ret) + hdb_free_entry(context, db, ent); + + return ret; +} + +static krb5_error_code +LDAP_close(krb5_context context, HDB * db) +{ + if (HDB2LDAP(db)) { + ldap_unbind_ext(HDB2LDAP(db), NULL, NULL); + ((struct hdbldapdb *)db->hdb_db)->h_lp = NULL; + } + + return 0; +} + +static krb5_error_code +LDAP_lock(krb5_context context, HDB * db, int operation) +{ + return 0; +} + +static krb5_error_code +LDAP_unlock(krb5_context context, HDB * db) +{ + return 0; +} + +static krb5_error_code +LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) +{ + int msgid, rc, parserc; + krb5_error_code ret; + LDAPMessage *e; + + msgid = HDB2MSGID(db); + if (msgid < 0) + return HDB_ERR_NOENTRY; + + do { + rc = ldap_result(HDB2LDAP(db), msgid, LDAP_MSG_ONE, NULL, &e); + switch (rc) { + case LDAP_RES_SEARCH_REFERENCE: + ldap_msgfree(e); + ret = 0; + break; + case LDAP_RES_SEARCH_ENTRY: + /* We have an entry. Parse it. */ + ret = LDAP_message2entry(context, db, e, flags, entry); + ldap_msgfree(e); + break; + case LDAP_RES_SEARCH_RESULT: + /* We're probably at the end of the results. If not, abandon. */ + parserc = + ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL, + NULL, NULL, 1); + ret = HDB_ERR_NOENTRY; + if (parserc != LDAP_SUCCESS + && parserc != LDAP_MORE_RESULTS_TO_RETURN) { + krb5_set_error_message(context, ret, "ldap_parse_result: %s", + ldap_err2string(parserc)); + ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL); + } + HDBSETMSGID(db, -1); + break; + case LDAP_SERVER_DOWN: + ldap_msgfree(e); + LDAP_close(context, db); + HDBSETMSGID(db, -1); + ret = ENETDOWN; + break; + default: + /* Some unspecified error (timeout?). Abandon. */ + ldap_msgfree(e); + ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL); + ret = HDB_ERR_NOENTRY; + HDBSETMSGID(db, -1); + break; + } + } while (rc == LDAP_RES_SEARCH_REFERENCE); + + if (ret == 0) { + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + ret = hdb_unseal_keys(context, db, entry); + if (ret) + hdb_free_entry(context, db, entry); + } + } + + return ret; +} + +static krb5_error_code +LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, + hdb_entry *entry) +{ + krb5_error_code ret; + int msgid; + + ret = LDAP__connect(context, db); + if (ret) + return ret; + + ret = LDAP_no_size_limit(context, HDB2LDAP(db)); + if (ret) + return ret; + + ret = ldap_search_ext(HDB2LDAP(db), HDB2BASE(db), + LDAP_SCOPE_SUBTREE, + "(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))", + krb5kdcentry_attrs, 0, + NULL, NULL, NULL, 0, &msgid); + if (ret != LDAP_SUCCESS || msgid < 0) + return HDB_ERR_NOENTRY; + + HDBSETMSGID(db, msgid); + + return LDAP_seq(context, db, flags, entry); +} + +static krb5_error_code +LDAP_nextkey(krb5_context context, HDB * db, unsigned flags, + hdb_entry * entry) +{ + return LDAP_seq(context, db, flags, entry); +} + +static krb5_error_code +LDAP__connect(krb5_context context, HDB * db) +{ + int rc, version = LDAP_VERSION3; + /* + * Empty credentials to do a SASL bind with LDAP. Note that empty + * different from NULL credentials. If you provide NULL + * credentials instead of empty credentials you will get a SASL + * bind in progress message. + */ + struct berval bv = { 0, "" }; + const char *sasl_method = "EXTERNAL"; + const char *bind_dn = NULL; + + if (HDB2BINDDN(db) != NULL && HDB2BINDPW(db) != NULL) { + /* A bind DN was specified; use SASL SIMPLE */ + bind_dn = HDB2BINDDN(db); + sasl_method = LDAP_SASL_SIMPLE; + bv.bv_val = HDB2BINDPW(db); + bv.bv_len = strlen(bv.bv_val); + } + + if (HDB2LDAP(db)) { + /* connection has been opened. ping server. */ + struct sockaddr_un addr; + socklen_t len = sizeof(addr); + int sd; + + if (ldap_get_option(HDB2LDAP(db), LDAP_OPT_DESC, &sd) == 0 && + getpeername(sd, (struct sockaddr *) &addr, &len) < 0) { + /* the other end has died. reopen. */ + LDAP_close(context, db); + } + } + + if (HDB2LDAP(db) != NULL) /* server is UP */ + return 0; + + rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, HDB2URL(db)); + if (rc != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_NOENTRY, "ldap_initialize: %s", + ldap_err2string(rc)); + return HDB_ERR_NOENTRY; + } + + rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION, + (const void *)&version); + if (rc != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_set_option: %s", ldap_err2string(rc)); + LDAP_close(context, db); + return HDB_ERR_BADVERSION; + } + + if (((struct hdbldapdb *)db->hdb_db)->h_start_tls) { + rc = ldap_start_tls_s(HDB2LDAP(db), NULL, NULL); + + if (rc != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_start_tls_s: %s", ldap_err2string(rc)); + LDAP_close(context, db); + return HDB_ERR_BADVERSION; + } + } + + rc = ldap_sasl_bind_s(HDB2LDAP(db), bind_dn, sasl_method, &bv, + NULL, NULL, NULL); + if (rc != LDAP_SUCCESS) { + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_sasl_bind_s: %s", ldap_err2string(rc)); + LDAP_close(context, db); + return HDB_ERR_BADVERSION; + } + + return 0; +} + +static krb5_error_code +LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode) +{ + /* Not the right place for this. */ +#ifdef HAVE_SIGACTION + struct sigaction sa; + + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + + sigaction(SIGPIPE, &sa, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGACTION */ + + return LDAP__connect(context, db); +} + +static krb5_error_code +LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry * entry) +{ + LDAPMessage *msg, *e; + krb5_error_code ret; + + ret = LDAP_principal2message(context, db, principal, &msg); + if (ret) + return ret; + + e = ldap_first_entry(HDB2LDAP(db), msg); + if (e == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + ret = LDAP_message2entry(context, db, e, flags, entry); + if (ret == 0) { + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + ret = hdb_unseal_keys(context, db, entry); + if (ret) + hdb_free_entry(context, db, entry); + } + } + + out: + ldap_msgfree(msg); + + return ret; +} + +#if 0 +static krb5_error_code +LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, + unsigned flags, hdb_entry * entry) +{ + return LDAP_fetch_kvno(context, db, principal, + flags & (~HDB_F_KVNO_SPECIFIED), 0, entry); +} +#endif + +static krb5_error_code +LDAP_store(krb5_context context, HDB * db, unsigned flags, + hdb_entry * entry) +{ + LDAPMod **mods = NULL; + krb5_error_code ret; + const char *errfn; + int rc; + LDAPMessage *msg = NULL, *e = NULL; + char *dn = NULL, *name = NULL; + krb5_boolean is_new_entry; + + if ((flags & HDB_F_PRECHECK)) + return 0; /* we can't guarantee whether we'll be able to perform it */ + + ret = LDAP_principal2message(context, db, entry->principal, &msg); + if (ret == 0) + e = ldap_first_entry(HDB2LDAP(db), msg); + + ret = krb5_unparse_name(context, entry->principal, &name); + if (ret) { + free(name); + return ret; + } + + ret = hdb_seal_keys(context, db, entry); + if (ret) + goto out; + + /* turn new entry into LDAPMod array */ + ret = LDAP_entry2mods(context, db, entry, e, &mods, &is_new_entry); + if (ret) + goto out; + + if (e == NULL) { + ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db)); + if (ret < 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "asprintf: out of memory"); + goto out; + } + } else if ((flags & HDB_F_REPLACE) || (is_new_entry)) { + /* Entry exists, and we're allowed to replace it. */ + /* Entry may also exist but need to be modified to create a new principal. */ + dn = ldap_get_dn(HDB2LDAP(db), e); + } else { + /* Entry exists, but we're not allowed to replace it. Bail. */ + ret = HDB_ERR_EXISTS; + goto out; + } + + /* write entry into directory */ + if (e == NULL) { + /* didn't exist before */ + rc = ldap_add_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL ); + errfn = "ldap_add_ext_s"; + } else { + /* already existed, send deltas only */ + rc = ldap_modify_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL ); + errfn = "ldap_modify_ext_s"; + } + + if (check_ldap(context, db, rc)) { + char *ld_error = NULL; + ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING, + &ld_error); + ret = HDB_ERR_CANT_LOCK_DB; + krb5_set_error_message(context, ret, "%s: %s (DN=%s) %s: %s", + errfn, name, dn, ldap_err2string(rc), ld_error); + } else + ret = 0; + + out: + /* free stuff */ + if (dn) + free(dn); + if (msg) + ldap_msgfree(msg); + if (mods) + ldap_mods_free(mods, 1); + if (name) + free(name); + + return ret; +} + +static krb5_error_code +LDAP_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) +{ + krb5_error_code ret; + LDAPMessage *msg, *e; + char *dn = NULL; + int rc, limit = LDAP_NO_LIMIT; + + if ((flags & HDB_F_PRECHECK)) + return 0; /* we can't guarantee whether we'll be able to perform it */ + + ret = LDAP_principal2message(context, db, principal, &msg); + if (ret) + goto out; + + e = ldap_first_entry(HDB2LDAP(db), msg); + if (e == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + dn = ldap_get_dn(HDB2LDAP(db), e); + if (dn == NULL) { + ret = HDB_ERR_NOENTRY; + goto out; + } + + rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit); + if (rc != LDAP_SUCCESS) { + ret = HDB_ERR_BADVERSION; + krb5_set_error_message(context, ret, "ldap_set_option: %s", + ldap_err2string(rc)); + goto out; + } + + /* HACK: This should check if we need to delete the object or just some attributes */ + + rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL ); + if (check_ldap(context, db, rc)) { + ret = HDB_ERR_CANT_LOCK_DB; + krb5_set_error_message(context, ret, "ldap_delete_ext_s: %s", + ldap_err2string(rc)); + } else + ret = 0; + + out: + if (dn != NULL) + free(dn); + if (msg != NULL) + ldap_msgfree(msg); + + return ret; +} + +static krb5_error_code +LDAP_destroy(krb5_context context, HDB * db) +{ + krb5_error_code ret; + + LDAP_close(context, db); + + ret = hdb_clear_master_key(context, db); + if (HDB2BASE(db)) + free(HDB2BASE(db)); + if (HDB2CREATE(db)) + free(HDB2CREATE(db)); + if (HDB2URL(db)) + free(HDB2URL(db)); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + if (db->hdb_name) + free(db->hdb_name); + free(db->hdb_db); + free(db); + + return ret; +} + +static krb5_error_code +LDAP_set_sync(krb5_context context, HDB * db, int on) +{ + (void)on; + return 0; +} + +static krb5_error_code +hdb_ldap_common(krb5_context context, + HDB ** db, + const char *search_base, + const char *url) +{ + struct hdbldapdb *h; + const char *create_base = NULL; + const char *ldap_secret_file = NULL; + + if (url == NULL || url[0] == '\0') { + const char *p; + p = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-url", NULL); + if (p == NULL) + p = default_ldap_url; + + url = p; + } + + if (search_base == NULL || search_base[0] == '\0') { + krb5_set_error_message(context, ENOMEM, "ldap search base not configured"); + return ENOMEM; /* XXX */ + } + + if (structural_object == NULL) { + const char *p; + + p = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-structural-object", NULL); + if (p == NULL) + p = default_structural_object; + structural_object = strdup(p); + if (structural_object == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + } + + samba_forwardable = + krb5_config_get_bool_default(context, NULL, TRUE, + "kdc", "hdb-samba-forwardable", NULL); + + *db = calloc(1, sizeof(**db)); + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + memset(*db, 0, sizeof(**db)); + + h = calloc(1, sizeof(*h)); + if (h == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_db = h; + + /* XXX */ + if (asprintf(&(*db)->hdb_name, "ldap:%s", search_base) == -1) { + LDAP_destroy(context, *db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); + return ENOMEM; + } + + h->h_url = strdup(url); + h->h_base = strdup(search_base); + if (h->h_url == NULL || h->h_base == NULL) { + LDAP_destroy(context, *db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); + return ENOMEM; + } + + ldap_secret_file = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-secret-file", NULL); + if (ldap_secret_file != NULL) { + krb5_config_binding *tmp; + krb5_error_code ret; + const char *p; + + ret = krb5_config_parse_file(context, ldap_secret_file, &tmp); + if (ret) + return ret; + + p = krb5_config_get_string(context, tmp, "kdc", + "hdb-ldap-bind-dn", NULL); + if (p != NULL) + h->h_bind_dn = strdup(p); + + p = krb5_config_get_string(context, tmp, "kdc", + "hdb-ldap-bind-password", NULL); + if (p != NULL) + h->h_bind_password = strdup(p); + + krb5_config_file_free(context, tmp); + } + + h->h_start_tls = + krb5_config_get_bool_default(context, NULL, FALSE, + "kdc", "hdb-ldap-start-tls", NULL); + + create_base = krb5_config_get_string(context, NULL, "kdc", + "hdb-ldap-create-base", NULL); + if (create_base == NULL) + create_base = h->h_base; + + h->h_createbase = strdup(create_base); + if (h->h_createbase == NULL) { + LDAP_destroy(context, *db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); + return ENOMEM; + } + + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_SHARED_DIRECTORY; + (*db)->hdb_open = LDAP_open; + (*db)->hdb_close = LDAP_close; + (*db)->hdb_fetch_kvno = LDAP_fetch_kvno; + (*db)->hdb_store = LDAP_store; + (*db)->hdb_remove = LDAP_remove; + (*db)->hdb_firstkey = LDAP_firstkey; + (*db)->hdb_nextkey = LDAP_nextkey; + (*db)->hdb_lock = LDAP_lock; + (*db)->hdb_unlock = LDAP_unlock; + (*db)->hdb_rename = NULL; + (*db)->hdb__get = NULL; + (*db)->hdb__put = NULL; + (*db)->hdb__del = NULL; + (*db)->hdb_destroy = LDAP_destroy; + (*db)->hdb_set_sync = LDAP_set_sync; + + return 0; +} + +#ifdef OPENLDAP_MODULE +static +#endif + +krb5_error_code +hdb_ldap_create(krb5_context context, HDB ** db, const char *arg) +{ + return hdb_ldap_common(context, db, arg, NULL); +} + +#ifdef OPENLDAP_MODULE +static +#endif + +krb5_error_code +hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg) +{ + krb5_error_code ret; + char *search_base, *p; + + if (asprintf(&p, "ldapi:%s", arg) == -1 || p == NULL) { + *db = NULL; + krb5_set_error_message(context, ENOMEM, "out of memory"); + return ENOMEM; + } + search_base = strchr(p + strlen("ldapi://"), ':'); + if (search_base == NULL) { + *db = NULL; + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "search base missing"); + return HDB_ERR_BADVERSION; + } + *search_base = '\0'; + search_base++; + + ret = hdb_ldap_common(context, db, search_base, p); + free(p); + return ret; +} + +#ifdef OPENLDAP_MODULE +static krb5_error_code +init(krb5_context context, void **ctx) +{ + *ctx = NULL; + return 0; +} + +static void +fini(void *ctx) +{ +} + +struct hdb_method hdb_ldap_interface = { + HDB_INTERFACE_VERSION, + init, + fini, + 0 /*is_file_based*/, 0 /*can_taste*/, + "ldap", + hdb_ldap_create +}; + +struct hdb_method hdb_ldapi_interface = { + HDB_INTERFACE_VERSION, + init, + fini, + 0 /*is_file_based*/, 0 /*can_taste*/, + "ldapi", + hdb_ldapi_create +}; +#endif + +#endif /* OPENLDAP */ diff --git a/third_party/heimdal/lib/hdb/hdb-mdb.c b/third_party/heimdal/lib/hdb/hdb-mdb.c new file mode 100644 index 0000000..dd1f274 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb-mdb.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (c) 2011 - Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#if HAVE_LMDB + +/* LMDB */ + +#include + +#define KILO 1024 + +#define E(sym, kret) case sym: ret = kret; ename = #sym; break + +/* Note: calls krb5_set_error_message() */ +static krb5_error_code +mdb2krb5_code(krb5_context context, int code) +{ + krb5_error_code ret = 0; + const char *ename = "UNKNOWN"; + const char *estr = mdb_strerror(code); + + switch (code) { + case MDB_SUCCESS: return 0; + E(MDB_KEYEXIST, HDB_ERR_EXISTS); + E(MDB_NOTFOUND, HDB_ERR_NOENTRY); + E(MDB_PAGE_NOTFOUND, HDB_ERR_UK_SERROR); + E(MDB_CORRUPTED, HDB_ERR_UK_SERROR); + E(MDB_PANIC, HDB_ERR_UK_SERROR); + E(MDB_VERSION_MISMATCH, HDB_ERR_UK_SERROR); + E(MDB_INVALID, HDB_ERR_UK_SERROR); + E(MDB_MAP_FULL, HDB_ERR_UK_SERROR); + E(MDB_DBS_FULL, HDB_ERR_UK_SERROR); + E(MDB_READERS_FULL, HDB_ERR_UK_SERROR); + E(MDB_TLS_FULL, HDB_ERR_UK_SERROR); + E(MDB_TXN_FULL, HDB_ERR_UK_SERROR); + E(MDB_CURSOR_FULL, HDB_ERR_UK_SERROR); + E(MDB_PAGE_FULL, HDB_ERR_UK_SERROR); + E(MDB_MAP_RESIZED, HDB_ERR_UK_SERROR); + E(MDB_INCOMPATIBLE, HDB_ERR_UK_SERROR); + E(MDB_BAD_RSLOT, HDB_ERR_UK_SERROR); + E(MDB_BAD_TXN, HDB_ERR_UK_SERROR); + E(MDB_BAD_VALSIZE, HDB_ERR_UK_SERROR); + E(MDB_BAD_DBI, HDB_ERR_UK_SERROR); + default: + if (code > 0 && code < 100) + ret = code; + else + ret = HDB_ERR_UK_SERROR; + break; + } + if (ret) + krb5_set_error_message(context, ret, "MDB error %s (%d): %s", + ename, code, estr); + return ret; +} + +typedef struct mdb_info { + MDB_env *e; + MDB_txn *t; + MDB_dbi d; + MDB_cursor *c; + int oflags; + mode_t mode; + size_t mapsize; + unsigned int in_tx:1; +} mdb_info; + +/* See below */ +struct keep_it_open { + char *path; + MDB_env *env; + MDB_dbi d; + unsigned int oflags; + size_t refs; + size_t mapsize; + unsigned int valid:1; + struct keep_it_open *next; +} *keep_them_open; +HEIMDAL_MUTEX keep_them_open_lock = HEIMDAL_MUTEX_INITIALIZER; + +/* + * On Unix LMDB uses fcntl() byte-range locks, and unlike SQLite3 (which also + * uses fcntl() byte-range locks) LMDB takes no precautions to avoid early + * first-close()s that cause other threads' locks to get dropped. No, LMDB + * requires the caller to take such precautions. For us that means opening one + * mdb env per-{HDB, mode} (where mode is read-write or read-only), never + * closing it, and sharing it with all threads. + * + * Sharing an MDB_env * across multiple threads is documented to be safe, and + * internally LMDB uses pread(2), pwrite(2), and mmap(2) for I/O, using + * read(2)/write(2) only in the DB copy routines that we don't use. + * + * On WIN32 we don't have to do any of this, however, to avoid ifdef spaghetti, + * we share this code on all platforms, even if it isn't strictly needed. + * + * Also, one must call mdb_open() (aka mdb_dbi_open()) only once per call to + * mdb_env_open() and per B-tree. We only use one B-tree in each LMDB: the + * main one. + * + * On success this outputs an `MDB_env *' (the handle for the LMDB) and an + * `MDB_dbi' (the handle for the main B-tree in the LMDB). + * + * ALSO, LMDB requires that we re-open the `MDB_env' when the database grows + * larger than the mmap size. We handle this by finding in `keep_them_open' + * the env we already have, marking it unusable, and the finding some other + * better one or opening a new one and adding it to the list. + */ +static krb5_error_code +my_mdb_env_create_and_open(krb5_context context, + mdb_info *mi, + const char *path, + int mapfull) +{ + struct keep_it_open *p, *n; + MDB_txn *txn = NULL; + unsigned int flags = MDB_NOSUBDIR | MDB_NOTLS; + struct stat st; + size_t mapsize = 0; + int max_readers; + int locked = 0; + int code = 0; + + mi->oflags &= O_ACCMODE; + flags |= (mi->oflags == O_RDONLY) ? MDB_RDONLY : 0; + + mi->e = NULL; + + /* + * Allocate a new object, in case we don't already have one in + * `keep_them_open'; if we don't need it, we'll free it. This way we do + * some of the work of creating one while not holding a lock. + */ + if ((n = calloc(1, sizeof(*n))) == NULL || + (n->path = strdup(path)) == NULL) { + free(n); + return krb5_enomem(context); + } + n->oflags = mi->oflags; + + max_readers = krb5_config_get_int_default(context, NULL, 0, "kdc", + "hdb-mdb-maxreaders", NULL); + mapsize = krb5_config_get_int_default(context, NULL, 0, "kdc", "hdb-mdb-mapsize", + NULL); + if (mapsize > INT_MAX) + mapsize = 0; + + memset(&st, 0, sizeof(st)); + if (stat(path, &st) == 0 && st.st_size > mapsize * KILO) + mapsize += (st.st_size + (st.st_size >> 2)) / KILO; + if (mapsize < 100 * 1024) + mapsize = 100 * 1024; /* 100MB */ + if (mapsize < mi->mapsize) + mapsize = mi->mapsize; + if (mapfull) + mapsize += 10 * 1024; + if ((code = mdb_env_create(&n->env)) || + (max_readers && (code = mdb_env_set_maxreaders(n->env, max_readers)))) + goto out; + + /* Look for an existing env */ + HEIMDAL_MUTEX_lock(&keep_them_open_lock); + locked = 1; + for (p = keep_them_open; p; p = p->next) { + if (strcmp(p->path, path) != 0) + continue; + if (p->mapsize > mapsize) + /* Always increase mapsize */ + mapsize = p->mapsize + (p->mapsize >> 1); + if (!p->valid || p->oflags != mi->oflags) + continue; + /* Found one; output it and get out */ + mi->e = p->env; + mi->d = p->d; + p->refs++; + goto out; + } + + /* Did not find one, so open and add this one to the list */ + + /* Open the LMDB itself */ + n->refs = 1; + n->valid = 1; + krb5_debug(context, 5, "Opening HDB LMDB %s with mapsize %llu", + path, (unsigned long long)mapsize * KILO); + code = mdb_env_set_mapsize(n->env, mapsize * KILO); + if (code == 0) + code = mdb_env_open(n->env, path, flags, mi->mode); + if (code == 0) + /* Open a transaction so we can resolve the main B-tree */ + code = mdb_txn_begin(n->env, NULL, MDB_RDONLY, &txn); + if (code == 0) + /* Resolve the main B-tree */ + code = mdb_open(txn, NULL, 0, &n->d); + if (code) + goto out; + + /* Successfully opened the LMDB; output the two handles */ + mi->mapsize = n->mapsize = mapsize; + mi->e = n->env; + mi->d = n->d; + + /* Add this keep_it_open to the front of the list */ + n->next = keep_them_open; + keep_them_open = n; + n = NULL; + +out: + if (locked) + HEIMDAL_MUTEX_unlock(&keep_them_open_lock); + if (n) { + if (n->env) + mdb_env_close(n->env); + free(n->path); + free(n); + } + (void) mdb_txn_commit(txn); /* Safe when `txn == NULL' */ + return mdb2krb5_code(context, code); +} + +static void +my_mdb_env_close(krb5_context context, + const char *db_name, + MDB_env **envp) +{ + struct keep_it_open **prev; + struct keep_it_open *p, *old; + size_t refs_seen = 0; + size_t slen = strlen(db_name); + MDB_env *env = *envp; + + if (env == NULL) + return; + + HEIMDAL_MUTEX_lock(&keep_them_open_lock); + for (p = keep_them_open; p; p = p->next) { + /* + * We can have multiple open ones and we need to know if this is the + * last one, so we can't break out early. + */ + if (p->env == env) + refs_seen += (--(p->refs)); + else if (strncmp(db_name, p->path, slen) == 0 && + strcmp(p->path + slen, ".mdb") == 0) + refs_seen += p->refs; + } + krb5_debug(context, 6, "Closing HDB LMDB %s / %p; refs %llu", db_name, env, + (unsigned long long)refs_seen); + prev = &keep_them_open; + for (p = keep_them_open; !refs_seen && p; ) { + /* We're the last close */ + if (p->refs || + strncmp(db_name, p->path, slen) != 0 || + strcmp(p->path + slen, ".mdb") != 0) { + + /* Not us; this keep_it_open stays */ + prev = &p->next; + p = p->next; + continue; + } + + /* Close and remove this one */ + krb5_debug(context, 6, "Closing HDB LMDB %s (mapsize was %llu)", + db_name, (unsigned long long)p->mapsize * KILO); + old = p; + *prev = (p = p->next); /* prev stays */ + mdb_env_close(old->env); + free(old->path); + free(old); + } + HEIMDAL_MUTEX_unlock(&keep_them_open_lock); +} + +/* + * This is a wrapper around my_mdb_env_create_and_open(). It may close an + * existing MDB_env in mi->e if it's there. If we need to reopen because the + * MDB grew too much, then we call this. + */ +static krb5_error_code +my_reopen_mdb(krb5_context context, HDB *db, int mapfull) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + char *fn; + krb5_error_code ret = 0; + + /* No-op if we don't have an open one */ + my_mdb_env_close(context, db->hdb_name, &mi->e); + if (asprintf(&fn, "%s.mdb", db->hdb_name) == -1) + ret = krb5_enomem(context); + if (ret == 0) + ret = my_mdb_env_create_and_open(context, mi, fn, mapfull); + free(fn); + return ret; +} + +static krb5_error_code +DB_close(krb5_context context, HDB *db) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + + mdb_cursor_close(mi->c); + mdb_txn_abort(mi->t); + my_mdb_env_close(context, db->hdb_name, &mi->e); + mi->c = 0; + mi->t = 0; + mi->e = 0; + return 0; +} + +static krb5_error_code +DB_destroy(krb5_context context, HDB *db) +{ + krb5_error_code ret; + + ret = hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(db->hdb_name); + free(db->hdb_db); + free(db); + return ret; +} + +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + + mdb_env_set_flags(mi->e, MDB_NOSYNC, !on); + return mdb_env_sync(mi->e, 0); +} + +static krb5_error_code +DB_lock(krb5_context context, HDB *db, int operation) +{ + db->lock_count++; + return 0; +} + +static krb5_error_code +DB_unlock(krb5_context context, HDB *db) +{ + if (db->lock_count > 1) { + db->lock_count--; + return 0; + } + heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); + db->lock_count--; + return 0; +} + + +static krb5_error_code +DB_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry, int flag) +{ + mdb_info *mi = db->hdb_db; + MDB_val key, value; + krb5_data key_data, data; + int code; + + /* + * No need to worry about MDB_MAP_FULL when we're scanning the DB since we + * have snapshot semantics, and any DB growth from other transactions + * should not affect us. + */ + key.mv_size = 0; + value.mv_size = 0; + code = mdb_cursor_get(mi->c, &key, &value, flag); + if (code) + return mdb2krb5_code(context, code); + + key_data.data = key.mv_data; + key_data.length = key.mv_size; + data.data = value.mv_data; + data.length = value.mv_size; + memset(entry, 0, sizeof(*entry)); + if (hdb_value2entry(context, &data, entry)) + return DB_seq(context, db, flags, entry, MDB_NEXT); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, entry); + if (code) + hdb_free_entry (context, db, entry); + } + if (entry->principal == NULL) { + entry->principal = malloc(sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } else { + hdb_key2principal(context, &key_data, entry->principal); + } + } + return 0; +} + + +static krb5_error_code +DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + krb5_error_code ret = 0; + mdb_info *mi = db->hdb_db; + int tries = 3; + int code = 0; + + /* Always start with a fresh cursor to pick up latest DB state */ + + do { + if (mi->t) + mdb_txn_abort(mi->t); + mi->t = NULL; + if (code) + code = my_reopen_mdb(context, db, 1); + if (code == 0) + code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &mi->t); + if (code == 0) + code = mdb_cursor_open(mi->t, mi->d, &mi->c); + if (code == 0) { + ret = DB_seq(context, db, flags, entry, MDB_FIRST); + break; + } + } while (code == MDB_MAP_FULL && --tries > 0); + + if (code || ret) { + mdb_txn_abort(mi->t); + mi->t = NULL; + } + return ret ? ret : mdb2krb5_code(context, code); +} + + +static krb5_error_code +DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return DB_seq(context, db, flags, entry, MDB_NEXT); +} + +static krb5_error_code +DB_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old, *new; + + if (strncmp(new_name, "mdb:", sizeof("mdb:") - 1) == 0) + new_name += sizeof("mdb:") - 1; + else if (strncmp(new_name, "lmdb:", sizeof("lmdb:") - 1) == 0) + new_name += sizeof("lmdb:") - 1; + if (asprintf(&old, "%s.mdb", db->hdb_name) == -1) + return ENOMEM; + if (asprintf(&new, "%s.mdb", new_name) == -1) { + free(old); + return ENOMEM; + } + ret = rename(old, new); + free(old); + free(new); + if(ret) + return errno; + + free(db->hdb_name); + db->hdb_name = strdup(new_name); + return 0; +} + +static krb5_error_code +DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn = NULL; + MDB_val k, v; + int tries = 3; + int code = 0; + + k.mv_data = key.data; + k.mv_size = key.length; + + do { + if (txn) { + mdb_txn_abort(txn); + txn = NULL; + } + if (code) + code = my_reopen_mdb(context, db, 1); + if (code == 0) + code = mdb_txn_begin(mi->e, NULL, MDB_RDONLY, &txn); + if (code == 0) + code = mdb_get(txn, mi->d, &k, &v); + if (code == 0) + krb5_data_copy(reply, v.mv_data, v.mv_size); + } while (code == MDB_MAP_FULL && --tries > 0); + + if (code) + mdb_txn_abort(txn); + else + (void) mdb_txn_commit(txn); /* Empty transaction? -> commit */ + return mdb2krb5_code(context, code); +} + +static krb5_error_code +DB__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn = NULL; + MDB_val k, v; + int tries = 3; + int code = 0; + + k.mv_data = key.data; + k.mv_size = key.length; + v.mv_data = value.data; + v.mv_size = value.length; + + do { + if (txn) { + mdb_txn_abort(txn); + txn = NULL; + } + if (code) + code = my_reopen_mdb(context, db, 1); + if (code == 0) + code = mdb_txn_begin(mi->e, NULL, 0, &txn); + if (code == 0) + code = mdb_put(txn, mi->d, &k, &v, replace ? 0 : MDB_NOOVERWRITE); + if (code == 0) { + /* + * No need to call mdb_env_sync(); it's done automatically if + * MDB_NOSYNC is not set. + */ + code = mdb_txn_commit(txn); + txn = NULL; + } + } while (code == MDB_MAP_FULL && --tries > 0); + if (txn) + mdb_txn_abort(txn); + return mdb2krb5_code(context, code); +} + +static krb5_error_code +DB__del(krb5_context context, HDB *db, krb5_data key) +{ + mdb_info *mi = (mdb_info*)db->hdb_db; + MDB_txn *txn = NULL; + MDB_val k; + int tries = 3; + int code = 0; + + k.mv_data = key.data; + k.mv_size = key.length; + + do { + if (txn) { + mdb_txn_abort(txn); + txn = NULL; + } + if (code) + code = my_reopen_mdb(context, db, 1); + if (code == 0) + code = mdb_txn_begin(mi->e, NULL, 0, &txn); + if (code == 0) + code = mdb_del(txn, mi->d, &k, NULL); + if (code == 0) { + /* + * No need to call mdb_env_sync(); it's done automatically if + * MDB_NOSYNC is not set. + */ + code = mdb_txn_commit(txn); + txn = NULL; + } + } while (code == MDB_MAP_FULL && --tries > 0); + + if (txn) + mdb_txn_abort(txn); + return mdb2krb5_code(context, code); +} + +static krb5_error_code +DB_open(krb5_context context, HDB *db, int oflags, mode_t mode) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + krb5_error_code ret; + + mi->e = NULL; + mi->mode = mode; + mi->oflags = oflags & O_ACCMODE; + ret = my_reopen_mdb(context, db, 0); + if (ret) { + krb5_prepend_error_message(context, ret, "opening %s:", db->hdb_name); + return ret; + } + + if ((oflags & O_ACCMODE) == O_RDONLY) { + ret = hdb_check_db_format(context, db); + /* + * Dubious: if the DB is not initialized, shouldn't we tell the + * caller?? + */ + if (ret == HDB_ERR_NOENTRY) + return 0; + } else { + /* hdb_init_db() calls hdb_check_db_format() */ + ret = hdb_init_db(context, db); + } + if (ret) { + DB_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (oflags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + + return ret; +} + +krb5_error_code +hdb_mdb_create(krb5_context context, HDB **db, + const char *filename) +{ + *db = calloc(1, sizeof(**db)); + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = calloc(1, sizeof(mdb_info)); + if ((*db)->hdb_db == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free((*db)->hdb_db); + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + (*db)->hdb_open = DB_open; + (*db)->hdb_close = DB_close; + (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; + (*db)->hdb_store = _hdb_store; + (*db)->hdb_remove = _hdb_remove; + (*db)->hdb_firstkey = DB_firstkey; + (*db)->hdb_nextkey= DB_nextkey; + (*db)->hdb_lock = DB_lock; + (*db)->hdb_unlock = DB_unlock; + (*db)->hdb_rename = DB_rename; + (*db)->hdb__get = DB__get; + (*db)->hdb__put = DB__put; + (*db)->hdb__del = DB__del; + (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; + return 0; +} +#endif /* HAVE_LMDB */ diff --git a/third_party/heimdal/lib/hdb/hdb-mitdb.c b/third_party/heimdal/lib/hdb/hdb-mitdb.c new file mode 100644 index 0000000..ae315cd --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb-mitdb.c @@ -0,0 +1,1498 @@ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 +#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 +#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 +#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 +#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 +#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 +#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 +#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 +#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 +#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 +#define KRB5_KDB_DISALLOW_SVR 0x00001000 +#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 +#define KRB5_KDB_SUPPORT_DESMD5 0x00004000 +#define KRB5_KDB_NEW_PRINC 0x00008000 + +/* + +key: krb5_unparse_name + NUL + + 16: baselength + 32: attributes + 32: max time + 32: max renewable time + 32: client expire + 32: passwd expire + 32: last successful passwd + 32: last failed attempt + 32: num of failed attempts + 16: num tl data + 16: num data data + 16: principal length + length: principal + for num tl data times + 16: tl data type + 16: tl data length + length: length + for num key data times + 16: version (num keyblocks) + 16: kvno + for version times: + 16: type + 16: length + length: keydata + + +key_data_contents[0] + + int16: length + read-of-data: key-encrypted, key-usage 0, master-key + +salt: + version2 = salt in key_data->key_data_contents[1] + else default salt. + +*/ + +#include "hdb_locl.h" + +typedef struct MITDB { + HDB db; /* Generic */ + int do_sync; /* MITDB-specific */ +} MITDB; + +static void +attr_to_flags(unsigned attr, HDBFlags *flags) +{ + flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); + flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); + flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); + flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); + flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); + /* DUP_SKEY */ + flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); + flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); + flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); + flags->require_pwchange = !!(attr & KRB5_KDB_REQUIRES_PWCHANGE); + flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); + flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); + flags->client = 1; /* XXX */ +} + +#define KDB_V1_BASE_LENGTH 38 + +#define CHECK(x) do { if ((x)) goto out; } while(0) + +#ifdef HAVE_DB1 +static krb5_error_code +mdb_principal2key(krb5_context context, + krb5_const_principal principal, + krb5_data *key) +{ + krb5_error_code ret; + char *str; + + ret = krb5_unparse_name(context, principal, &str); + if (ret) + return ret; + key->data = str; + key->length = strlen(str) + 1; + return 0; +} +#endif /* HAVE_DB1 */ + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 +#define KRB5_KDB_SALTTYPE_CERTHASH 6 + +static krb5_error_code +fix_salt(krb5_context context, hdb_entry *ent, Key *k) +{ + krb5_error_code ret; + Salt *salt = k->salt; + /* fix salt type */ + switch((int)salt->type) { + case KRB5_KDB_SALTTYPE_NORMAL: + salt->type = KRB5_PADATA_PW_SALT; + break; + case KRB5_KDB_SALTTYPE_V4: + krb5_data_free(&salt->salt); + salt->type = KRB5_PADATA_PW_SALT; + break; + case KRB5_KDB_SALTTYPE_NOREALM: + { + size_t len; + size_t i; + char *p; + + len = 0; + for (i = 0; i < ent->principal->name.name_string.len; ++i) + len += strlen(ent->principal->name.name_string.val[i]); + ret = krb5_data_alloc (&salt->salt, len); + if (ret) + return ret; + p = salt->salt.data; + for (i = 0; i < ent->principal->name.name_string.len; ++i) { + memcpy (p, + ent->principal->name.name_string.val[i], + strlen(ent->principal->name.name_string.val[i])); + p += strlen(ent->principal->name.name_string.val[i]); + } + + salt->type = KRB5_PADATA_PW_SALT; + break; + } + case KRB5_KDB_SALTTYPE_ONLYREALM: + krb5_data_free(&salt->salt); + ret = krb5_data_copy(&salt->salt, + ent->principal->realm, + strlen(ent->principal->realm)); + if(ret) + return ret; + salt->type = KRB5_PADATA_PW_SALT; + break; + case KRB5_KDB_SALTTYPE_SPECIAL: + salt->type = KRB5_PADATA_PW_SALT; + break; + case KRB5_KDB_SALTTYPE_AFS3: + krb5_data_free(&salt->salt); + ret = krb5_data_copy(&salt->salt, + ent->principal->realm, + strlen(ent->principal->realm)); + if(ret) + return ret; + salt->type = KRB5_PADATA_AFS3_SALT; + break; + case KRB5_KDB_SALTTYPE_CERTHASH: + krb5_data_free(&salt->salt); + free(k->salt); + k->salt = NULL; + break; + default: + abort(); + } + return 0; +} + + +/** + * This function takes a key from a krb5_storage from an MIT KDB encoded + * entry and places it in the given Key object. + * + * @param context Context + * @param entry HDB entry + * @param sp krb5_storage with current offset set to the beginning of a + * key + * @param version See comments in caller body for the backstory on this + * @param k Key * to load the key into + */ +static krb5_error_code +mdb_keyvalue2key(krb5_context context, hdb_entry *entry, krb5_storage *sp, uint16_t version, Key *k) +{ + size_t i; + uint16_t u16, type; + krb5_error_code ret; + + k->mkvno = malloc(sizeof(*k->mkvno)); + if (k->mkvno == NULL) { + ret = ENOMEM; + goto out; + } + *k->mkvno = 1; + + for (i = 0; i < version; i++) { + CHECK(ret = krb5_ret_uint16(sp, &type)); + CHECK(ret = krb5_ret_uint16(sp, &u16)); + if (i == 0) { + /* This "version" means we have a key */ + k->key.keytype = type; + /* + * MIT stores keys encrypted keys as {16-bit length + * of plaintext key, {encrypted key}}. The reason + * for this is that the Kerberos cryptosystem is not + * length-preserving. Heimdal's approach is to + * truncate the plaintext to the expected length of + * the key given its enctype, so we ignore this + * 16-bit length-of-plaintext-key field. + */ + if (u16 > 2) { + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ + k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ + k->key.keyvalue.data = malloc(k->key.keyvalue.length); + krb5_storage_read(sp, k->key.keyvalue.data, + k->key.keyvalue.length); + } else { + /* We'll ignore this key; see our caller */ + k->key.keyvalue.length = 0; + k->key.keyvalue.data = NULL; + krb5_storage_seek(sp, u16, SEEK_CUR); /* skip real length */ + } + } else if (i == 1) { + /* This "version" means we have a salt */ + k->salt = calloc(1, sizeof(*k->salt)); + if (k->salt == NULL) { + ret = ENOMEM; + goto out; + } + k->salt->type = type; + if (u16 != 0) { + k->salt->salt.data = malloc(u16); + if (k->salt->salt.data == NULL) { + ret = ENOMEM; + goto out; + } + k->salt->salt.length = u16; + krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); + } + fix_salt(context, entry, k); + } else { + /* + * Whatever this "version" might be, we skip it + * + * XXX A krb5.conf parameter requesting that we log + * about strangeness like this, or return an error + * from here, might be nice. + */ + krb5_storage_seek(sp, u16, SEEK_CUR); + } + } + + return 0; + +out: + free_Key(k); + return ret; +} + + +static krb5_error_code +add_1des_dup(krb5_context context, Keys *keys, Key *key, krb5_keytype keytype) +{ + key->key.keytype = keytype; + return add_Keys(keys, key); +} + +/* + * This monstrosity is here so we can avoid having to do enctype + * similarity checking in the KDC. This helper function dups 1DES keys + * in a keyset for all the similar 1DES enctypes for which keys are + * missing. And, of course, we do this only if there's any 1DES keys in + * the keyset to begin with. + */ +static krb5_error_code +dup_similar_keys_in_keyset(krb5_context context, Keys *keys) +{ + krb5_error_code ret; + size_t i, k; + Key key; + int keyset_has_1des_crc = 0; + int keyset_has_1des_md4 = 0; + int keyset_has_1des_md5 = 0; + + memset(&key, 0, sizeof (key)); + k = keys->len; + for (i = 0; i < keys->len; i++) { + if (keys->val[i].key.keytype == ETYPE_DES_CBC_CRC) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD4) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } else if (keys->val[i].key.keytype == ETYPE_DES_CBC_MD5) { + keyset_has_1des_crc = 1; + if (k == keys->len) + k = i; + } + } + if (k == keys->len) + return 0; + + ret = copy_Key(&keys->val[k], &key); + if (ret) + return ret; + if (!keyset_has_1des_crc) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_CRC); + if (ret) + goto out; + } + if (!keyset_has_1des_md4) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD4); + if (ret) + goto out; + } + if (!keyset_has_1des_md5) { + ret = add_1des_dup(context, keys, &key, ETYPE_DES_CBC_MD5); + if (ret) + goto out; + } + +out: + free_Key(&key); + return ret; +} + + +static krb5_error_code +dup_similar_keys(krb5_context context, hdb_entry *entry) +{ + krb5_error_code ret; + HDB_Ext_KeySet *hist_keys; + HDB_extension *extp; + size_t i; + + ret = dup_similar_keys_in_keyset(context, &entry->keys); + if (ret) + return ret; + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) + return 0; + + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + ret = dup_similar_keys_in_keyset(context, &hist_keys->val[i].keys); + if (ret) + return ret; + } + return 0; +} + + +/** + * This function parses an MIT krb5 encoded KDB entry and fills in the + * given HDB entry with it. + * + * @param context krb5_context + * @param data Encoded MIT KDB entry + * @param target_kvno Desired kvno, or 0 for the entry's current kvno + * @param entry Desired kvno, or 0 for the entry's current kvno + */ +krb5_error_code +_hdb_mdb_value2entry(krb5_context context, krb5_data *data, + krb5_kvno target_kvno, hdb_entry *entry) +{ + krb5_error_code ret; + krb5_storage *sp; + Key k; + krb5_kvno key_kvno; + uint32_t u32; + uint16_t u16, num_keys, num_tl; + ssize_t sz; + size_t i; + char *p; + + memset(&k, 0, sizeof (k)); + memset(entry, 0, sizeof(*entry)); + + sp = krb5_storage_from_data(data); + if (sp == NULL) { + krb5_set_error_message(context, ENOMEM, "out of memory"); + return ENOMEM; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + /* + * 16: baselength + * + * The story here is that these 16 bits have to be a constant: + * KDB_V1_BASE_LENGTH. Once upon a time a different value here + * would have been used to indicate the presence of "extra data" + * between the "base" contents and the {principal name, TL data, + * keys} that follow it. Nothing supports such "extra data" + * nowadays, so neither do we here. + * + * XXX But... surely we ought to log about this extra data, or skip + * it, or something, in case anyone has MIT KDBs with ancient + * entries in them... Logging would allow the admin to know which + * entries to dump with MIT krb5's kdb5_util. But logging would be + * noisy. For now we do nothing. + */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } + /* 32: attributes */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + attr_to_flags(u32, &entry->flags); + + /* 32: max time */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + if (u32) { + entry->max_life = malloc(sizeof(*entry->max_life)); + *entry->max_life = u32; + } + /* 32: max renewable time */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + if (u32) { + entry->max_renew = malloc(sizeof(*entry->max_renew)); + *entry->max_renew = u32; + } + /* 32: client expire */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + if (u32) { + entry->valid_end = malloc(sizeof(*entry->valid_end)); + *entry->valid_end = u32; + } + /* 32: passwd expire */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + if (u32) { + entry->pw_end = malloc(sizeof(*entry->pw_end)); + *entry->pw_end = u32; + } + /* 32: last successful passwd */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + /* 32: last failed attempt */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + /* 32: num of failed attempts */ + CHECK(ret = krb5_ret_uint32(sp, &u32)); + /* 16: num tl data */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + num_tl = u16; + /* 16: num key data */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + num_keys = u16; + /* 16: principal length */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + /* length: principal */ + { + /* + * Note that the principal name includes the NUL in the entry, + * but we don't want to take chances, so we add an extra NUL. + */ + p = malloc(u16 + 1); + if (p == NULL) { + ret = ENOMEM; + goto out; + } + sz = krb5_storage_read(sp, p, u16); + if (sz != u16) { + ret = EINVAL; /* XXX */ + goto out; + } + p[u16] = '\0'; + CHECK(ret = krb5_parse_name(context, p, &entry->principal)); + free(p); + } + /* for num tl data times + 16: tl data type + 16: tl data length + length: length */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 + for (i = 0; i < num_tl; i++) { + int tl_type; + krb5_principal modby; + /* 16: TL data type */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + tl_type = u16; + /* 16: TL data length */ + CHECK(ret = krb5_ret_uint16(sp, &u16)); + /* + * For rollback to MIT purposes we really must understand some + * TL data! + * + * XXX Move all this to separate functions, one per-TL type. + */ + switch (tl_type) { + case mit_KRB5_TL_LAST_PWD_CHANGE: + CHECK(ret = krb5_ret_uint32(sp, &u32)); + CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32)); + break; + case mit_KRB5_TL_MOD_PRINC: + if (u16 < 5) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */ + p = malloc(u16 - 4 + 1); + if (!p) { + ret = ENOMEM; + goto out; + } + p[u16 - 4] = '\0'; + sz = krb5_storage_read(sp, p, u16 - 4); + if (sz != u16 - 4) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_parse_name(context, p, &modby)); + CHECK(ret = hdb_set_last_modified_by(context, entry, modby, u32)); + krb5_free_principal(context, modby); + free(p); + break; + default: + krb5_storage_seek(sp, u16, SEEK_CUR); + break; + } + } + /* + * for num key data times + * 16: "version" + * 16: kvno + * for version times: + * 16: type + * 16: length + * length: keydata + * + * "version" here is really 1 or 2, the first meaning there's only + * keys for this kvno, the second meaning there's keys and salt[s?]. + * That's right... hold that gag reflex, you can do it. + */ + for (i = 0; i < num_keys; i++) { + uint16_t version; + + CHECK(ret = krb5_ret_uint16(sp, &u16)); + version = u16; + CHECK(ret = krb5_ret_uint16(sp, &u16)); + key_kvno = u16; + + ret = mdb_keyvalue2key(context, entry, sp, version, &k); + if (ret) + goto out; + if (k.key.keytype == 0 || k.key.keyvalue.length == 0) { + /* + * Older MIT KDBs may have enctype 0 / length 0 keys. We + * ignore these. + */ + free_Key(&k); + continue; + } + + if ((target_kvno == 0 && entry->kvno < key_kvno) || + (target_kvno == key_kvno && entry->kvno != target_kvno)) { + /* + * MIT's KDB doesn't keep track of kvno. The highest kvno + * is the current kvno, and we just found a new highest + * kvno or the desired kvno. + * + * Note that there's no guarantee of any key ordering, but + * generally MIT KDB entries have keys in strictly + * descending kvno order. + * + * XXX We do assume that keys are clustered by kvno. If + * not, then bad. It might be possible to construct + * non-clustered keys via the kadm5 API. It wouldn't be + * hard to cope with this, since if it happens the worst + * that will happen is that some of the current keys can be + * found in the history extension, and we could just pull + * them back out in that case. + */ + ret = hdb_add_current_keys_to_history(context, entry); + if (ret) + goto out; + free_Keys(&entry->keys); + ret = add_Keys(&entry->keys, &k); + free_Key(&k); + if (ret) + goto out; + entry->kvno = key_kvno; + continue; + } + + if (entry->kvno == key_kvno) { + /* + * Note that if key_kvno == 0 and target_kvno == 0 then we + * end up adding those keys here. Yeah, kvno 0 is very + * special for us, but just in case, we keep such keys. + */ + ret = add_Keys(&entry->keys, &k); + free_Key(&k); + if (ret) + goto out; + entry->kvno = key_kvno; + } else { + ret = hdb_add_history_key(context, entry, key_kvno, &k); + if (ret) + goto out; + free_Key(&k); + } + } + + if (target_kvno != 0 && entry->kvno != target_kvno) { + ret = HDB_ERR_KVNO_NOT_FOUND; + goto out; + } + + krb5_storage_free(sp); + + return dup_similar_keys(context, entry); + +out: + krb5_storage_free(sp); + + if (ret == HEIM_ERR_EOF) + /* Better error code than "end of file" */ + ret = HEIM_ERR_BAD_HDBENT_ENCODING; + free_HDB_entry(entry); + free_Key(&k); + return ret; +} + +#if 0 +static krb5_error_code +mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) +{ + return EINVAL; +} +#endif + +#if HAVE_DB1 + +#if defined(HAVE_DB_185_H) +#include +#elif defined(HAVE_DB_H) +#include +#endif + + +static krb5_error_code +mdb_close(krb5_context context, HDB *db) +{ + DB *d = (DB*)db->hdb_db; + (*d->close)(d); + return 0; +} + +static krb5_error_code +mdb_destroy(krb5_context context, HDB *db) +{ + krb5_error_code ret; + + ret = hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(db->hdb_name); + free(db); + return ret; +} + +static krb5_error_code +mdb_set_sync(krb5_context context, HDB *db, int on) +{ + MITDB *mdb = (MITDB *)db; + DB *d = (DB*)db->hdb_db; + + mdb->do_sync = on; + if (on) + return fsync((*d->fd)(d)); + return 0; +} + +static krb5_error_code +mdb_lock(krb5_context context, HDB *db, int operation) +{ + DB *d = (DB*)db->hdb_db; + int fd = (*d->fd)(d); + krb5_error_code ret; + + if (db->lock_count > 1) { + db->lock_count++; + if (db->lock_type == HDB_WLOCK || db->lock_count == operation) + return 0; + } + + if(fd < 0) { + krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, + "Can't lock database: %s", db->hdb_name); + return HDB_ERR_CANT_LOCK_DB; + } + ret = hdb_lock(fd, operation); + if (ret) + return ret; + db->lock_count++; + return 0; +} + +static krb5_error_code +mdb_unlock(krb5_context context, HDB *db) +{ + DB *d = (DB*)db->hdb_db; + int fd = (*d->fd)(d); + + if (db->lock_count > 1) { + db->lock_count--; + return 0; + } + heim_assert(db->lock_count == 1, "HDB lock/unlock sequence does not match"); + db->lock_count--; + + if(fd < 0) { + krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, + "Can't unlock database: %s", db->hdb_name); + return HDB_ERR_CANT_LOCK_DB; + } + return hdb_unlock(fd); +} + + +static krb5_error_code +mdb_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry, int flag) +{ + DB *d = (DB*)db->hdb_db; + DBT key, value; + krb5_data data; + int code; + + code = db->hdb_lock(context, db, HDB_RLOCK); + if(code == -1) { + krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); + return HDB_ERR_DB_INUSE; + } + code = (*d->seq)(d, &key, &value, flag); + db->hdb_unlock(context, db); /* XXX check value */ + if(code == -1) { + code = errno; + krb5_set_error_message(context, code, "Database %s seq error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code == 1) { + krb5_clear_error_message(context); + return HDB_ERR_NOENTRY; + } + + data.data = value.data; + data.length = value.size; + memset(entry, 0, sizeof(*entry)); + + if (_hdb_mdb_value2entry(context, &data, 0, entry)) + return mdb_seq(context, db, flags, entry, R_NEXT); + + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + code = hdb_unseal_keys (context, db, entry); + if (code) + hdb_free_entry (context, db, entry); + } + + return code; +} + + +static krb5_error_code +mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return mdb_seq(context, db, flags, entry, R_FIRST); +} + + +static krb5_error_code +mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + return mdb_seq(context, db, flags, entry, R_NEXT); +} + +static krb5_error_code +mdb_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old = NULL; + char *new = NULL; + + if (asprintf(&old, "%s.db", db->hdb_name) < 0) + goto out; + if (asprintf(&new, "%s.db", new_name) < 0) + goto out; + ret = rename(old, new); + if(ret) + goto out; + + free(db->hdb_name); + db->hdb_name = strdup(new_name); + errno = 0; + +out: + free(old); + free(new); + return errno; +} + +static krb5_error_code +mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + k.data = key.data; + k.size = key.length; + code = db->hdb_lock(context, db, HDB_RLOCK); + if(code) + return code; + code = (*d->get)(d, &k, &v, 0); + db->hdb_unlock(context, db); + if(code < 0) { + code = errno; + krb5_set_error_message(context, code, "Database %s get error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code == 1) { + krb5_clear_error_message(context); + return HDB_ERR_NOENTRY; + } + + krb5_data_copy(reply, v.data, v.size); + return 0; +} + +static krb5_error_code +mdb__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ + MITDB *mdb = (MITDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k, v; + int code; + + k.data = key.data; + k.size = key.length; + v.data = value.data; + v.size = value.length; + code = db->hdb_lock(context, db, HDB_WLOCK); + if(code) + return code; + code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); + if (code == 0) { + code = mdb_set_sync(context, db, mdb->do_sync); + db->hdb_unlock(context, db); + return code; + } + db->hdb_unlock(context, db); + if(code < 0) { + code = errno; + krb5_set_error_message(context, code, "Database %s put error: %s", + db->hdb_name, strerror(code)); + return code; + } + krb5_clear_error_message(context); + return HDB_ERR_EXISTS; +} + +static krb5_error_code +mdb__del(krb5_context context, HDB *db, krb5_data key) +{ + MITDB *mdb = (MITDB *)db; + DB *d = (DB*)db->hdb_db; + DBT k; + krb5_error_code code; + k.data = key.data; + k.size = key.length; + code = db->hdb_lock(context, db, HDB_WLOCK); + if(code) + return code; + code = (*d->del)(d, &k, 0); + if (code == 0) { + code = mdb_set_sync(context, db, mdb->do_sync); + db->hdb_unlock(context, db); + return code; + } + db->hdb_unlock(context, db); + if(code == 1) { + code = errno; + krb5_set_error_message(context, code, "Database %s put error: %s", + db->hdb_name, strerror(code)); + return code; + } + if(code < 0) + return errno; + return 0; +} + +static krb5_error_code +mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry *entry) +{ + krb5_data key, value; + krb5_error_code ret; + + ret = mdb_principal2key(context, principal, &key); + if (ret) + return ret; + ret = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if(ret) + return ret; + ret = _hdb_mdb_value2entry(context, &value, kvno, entry); + krb5_data_free(&value); + if (ret) + return ret; + + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + ret = hdb_unseal_keys (context, db, entry); + if (ret) { + hdb_free_entry(context, db, entry); + return ret; + } + } + + return 0; +} + +static krb5_error_code +mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + krb5_error_code ret; + krb5_storage *sp = NULL; + krb5_storage *spent = NULL; + krb5_data line = { 0, 0 }; + krb5_data kdb_ent = { 0, 0 }; + krb5_data key = { 0, 0 }; + krb5_data value = { 0, 0 }; + krb5_ssize_t sz; + + if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE)) + return 0; + + if ((flags & HDB_F_PRECHECK)) { + ret = mdb_principal2key(context, entry->principal, &key); + if (ret) return ret; + ret = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (ret == 0) + krb5_data_free(&value); + if (ret == HDB_ERR_NOENTRY) + return 0; + return ret ? ret : HDB_ERR_EXISTS; + } + + sp = krb5_storage_emem(); + if (!sp) return ENOMEM; + ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */ + ret = hdb_seal_keys(context, db, entry); + if (ret) return ret; + ret = entry2mit_string_int(context, sp, entry); + if (ret) goto out; + sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */ + ret = ENOMEM; + if (sz != 2) goto out; + ret = krb5_storage_to_data(sp, &line); + if (ret) goto out; + + ret = ENOMEM; + spent = krb5_storage_emem(); + if (!spent) goto out; + ret = _hdb_mit_dump2mitdb_entry(context, line.data, spent); + if (ret) goto out; + ret = krb5_storage_to_data(spent, &kdb_ent); + if (ret) goto out; + ret = mdb_principal2key(context, entry->principal, &key); + if (ret) goto out; + ret = mdb__put(context, db, 1, key, kdb_ent); + +out: + if (sp) + krb5_storage_free(sp); + if (spent) + krb5_storage_free(spent); + krb5_data_free(&line); + krb5_data_free(&kdb_ent); + krb5_data_free(&key); + + return ret; +} + +static krb5_error_code +mdb_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) +{ + krb5_error_code code; + krb5_data key; + krb5_data value = { 0, 0 }; + + mdb_principal2key(context, principal, &key); + + if ((flags & HDB_F_PRECHECK)) { + code = db->hdb__get(context, db, key, &value); + krb5_data_free(&key); + if (code == 0) { + krb5_data_free(&value); + return 0; + } + return code; + } + + code = db->hdb__del(context, db, key); + krb5_data_free(&key); + return code; +} + +static krb5_error_code +mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + char *fn; + char *actual_fn; + krb5_error_code ret; + struct stat st; + + if (asprintf(&fn, "%s.db", db->hdb_name) < 0) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + if (stat(fn, &st) == 0) + actual_fn = fn; + else + actual_fn = db->hdb_name; + db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); + if (db->hdb_db == NULL) { + switch (errno) { +#ifdef EFTYPE + case EFTYPE: +#endif + case EINVAL: + db->hdb_db = dbopen(actual_fn, flags, mode, DB_HASH, NULL); + } + } + free(fn); + + if (db->hdb_db == NULL) { + ret = errno; + krb5_set_error_message(context, ret, "dbopen (%s): %s", + db->hdb_name, strerror(ret)); + return ret; + } +#if 0 + /* + * Don't do this -- MIT won't be able to handle the + * HDB_DB_FORMAT_ENTRY key. + */ + if ((flags & O_ACCMODE) != O_RDONLY) + ret = hdb_init_db(context, db); +#endif + ret = hdb_check_db_format(context, db); + if (ret == HDB_ERR_NOENTRY) { + krb5_clear_error_message(context); + return 0; + } + if (ret) { + mdb_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (flags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + return ret; +} + +krb5_error_code +hdb_mitdb_create(krb5_context context, HDB **db, + const char *filename) +{ + MITDB **mdb = (MITDB **)db; + *mdb = calloc(1, sizeof(**mdb)); + if (*mdb == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = NULL; + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*mdb)->do_sync = 1; + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = 0; + (*db)->hdb_open = mdb_open; + (*db)->hdb_close = mdb_close; + (*db)->hdb_fetch_kvno = mdb_fetch_kvno; + (*db)->hdb_store = mdb_store; + (*db)->hdb_remove = mdb_remove; + (*db)->hdb_firstkey = mdb_firstkey; + (*db)->hdb_nextkey= mdb_nextkey; + (*db)->hdb_lock = mdb_lock; + (*db)->hdb_unlock = mdb_unlock; + (*db)->hdb_rename = mdb_rename; + (*db)->hdb__get = mdb__get; + (*db)->hdb__put = mdb__put; + (*db)->hdb__del = mdb__del; + (*db)->hdb_destroy = mdb_destroy; + (*db)->hdb_set_sync = mdb_set_sync; + return 0; +} + +#endif /* HAVE_DB1 */ + +/* +can have any number of princ stanzas. +format is as follows (only \n indicates newlines) +princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) +%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) +%d\t (number of tl_data) +%d\t (number of key data, e.g. how many keys for this user) +%d\t (extra data length) +%s\t (principal name) +%d\t (attributes) +%d\t (max lifetime, seconds) +%d\t (max renewable life, seconds) +%d\t (expiration, seconds since epoch or 2145830400 for never) +%d\t (password expiration, seconds, 0 for never) +%d\t (last successful auth, seconds since epoch) +%d\t (last failed auth, per above) +%d\t (failed auth count) +foreach tl_data 0 to number of tl_data - 1 as above + %d\t%d\t (data type, data length) + foreach tl_data 0 to length-1 + %02x (tl data contents[element n]) + except if tl_data length is 0 + %d (always -1) + \t +foreach key 0 to number of keys - 1 as above + %d\t%d\t (key data version, kvno) + foreach version 0 to key data version - 1 (a key or a salt) + %d\t%d\t(data type for this key, data length for this key) + foreach key data length 0 to length-1 + %02x (key data contents[element n]) + except if key_data length is 0 + %d (always -1) + \t +foreach extra data length 0 to length - 1 + %02x (extra data part) +unless no extra data + %d (always -1) +;\n + +*/ + +#if 0 +/* Why ever did we loop? */ +static char * +nexttoken(char **p) +{ + char *q; + do { + q = strsep(p, " \t"); + } while(q && *q == '\0'); + return q; +} +#endif + +static char * +nexttoken(char **p, size_t len, const char *what) +{ + char *q; + + if (*p == NULL) + return NULL; + + q = *p; + *p += len; + /* Must be followed by a delimiter (right?) */ + if (strsep(p, " \t") != q + len) { + warnx("No tokens left in dump entry while looking for %s", what); + return NULL; + } + if (*q == '\0') + warnx("Empty last token in dump entry while looking for %s", what); + return q; +} + +static size_t +getdata(char **p, unsigned char *buf, size_t len, const char *what) +{ + size_t i; + int v; + char *q = nexttoken(p, 0, what); + if (q == NULL) { + warnx("Failed to find hex-encoded binary data (%s) in dump", what); + return 0; + } + i = 0; + while (*q && i < len) { + if (sscanf(q, "%02x", &v) != 1) + break; + buf[i++] = v; + q += 2; + } + return i; +} + +static int +getint(char **p, const char *what, int *val) +{ + char *q = nexttoken(p, 0, what); + if (!q) { + warnx("Failed to find a signed integer (%s) in dump", what); + return 1; + } + if (sscanf(q, "%d", val) != 1) + return 1; + return 0; +} + +static unsigned int +getuint(char **p, const char *what) +{ + int val; + char *q = nexttoken(p, 0, what); + if (!q) { + warnx("Failed to find an unsigned integer (%s) in dump", what); + return 0; + } + if (sscanf(q, "%u", &val) != 1) + return 0; + return val; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +#define CHECK_UINT(num) \ + if ((num) < 0 || (num) > INT_MAX) return EINVAL +#define CHECK_UINT16(num) \ + if ((num) < 0 || (num) > 1<<15) return EINVAL +#define CHECK_NUM(num, maxv) \ + if ((num) > (maxv)) return EINVAL + +/* + * This utility function converts an MIT dump entry to an MIT on-disk + * encoded entry, which can then be decoded with _hdb_mdb_value2entry(). + * This allows us to have a single decoding function (_hdb_mdb_value2entry), + * which makes the code cleaner (less code duplication), if a bit less + * efficient. It also will allow us to have a function to dump an HDB + * entry in MIT format so we can dump HDB into MIT format for rollback + * purposes. And that will allow us to write to MIT KDBs, again + * somewhat inefficiently, also for migration/rollback purposes. + */ +int +_hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) +{ + krb5_error_code ret = EINVAL; + char *p = line, *q; + char *princ; + krb5_ssize_t sz; + size_t i; + size_t princ_len; + unsigned int num_tl_data; + size_t num_key_data; + unsigned int attributes; + int tmp; + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + q = nexttoken(&p, 0, "record type (princ or policy)"); + if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || + strcmp(q, "princ") != 0) { + warnx("Supposed MIT dump entry does not start with 'kdb5_util', " + "'policy', nor 'princ'"); + return -1; + } + if (getint(&p, "constant '38'", &tmp) || tmp != 38) { + warnx("Dump entry does not start with '38'"); + return EINVAL; + } +#define KDB_V1_BASE_LENGTH 38 + ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); + if (ret) return ret; + + princ_len = getuint(&p, "principal name length"); + if (princ_len > (1<<15) - 1) { + warnx("Principal name in dump entry too long (%llu)", + (unsigned long long)princ_len); + return EINVAL; + } + num_tl_data = getuint(&p, "number of TL data"); + num_key_data = getuint(&p, "number of key data"); + (void) getint(&p, "5th field, length of 'extra data'", &tmp); + princ = nexttoken(&p, (int)princ_len, "principal name"); + if (princ == NULL) { + warnx("Failed to read principal name (expected length %llu)", + (unsigned long long)princ_len); + return -1; + } + + attributes = getuint(&p, "attributes"); + ret = krb5_store_uint32(sp, attributes); + if (ret) return ret; + + if (getint(&p, "max life", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p, "max renewable life", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p, "expiration", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p, "pw expiration", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p, "last auth", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p, "last failed auth", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + if (getint(&p,"fail auth count", &tmp)) return EINVAL; + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + /* add TL data count */ + CHECK_NUM(num_tl_data, 1023); + ret = krb5_store_uint16(sp, num_tl_data); + if (ret) return ret; + + /* add key count */ + CHECK_NUM(num_key_data, 1023); + ret = krb5_store_uint16(sp, num_key_data); + if (ret) return ret; + + /* add principal unparsed name length and unparsed name */ + princ_len = strlen(princ); + princ_len++; /* must count and write the NUL in the on-disk encoding */ + ret = krb5_store_uint16(sp, princ_len); + if (ret) return ret; + sz = krb5_storage_write(sp, princ, princ_len); + if (sz != princ_len) return ENOMEM; + + /* scan and write TL data */ + for (i = 0; i < num_tl_data; i++) { + char *reading_what; + int tl_type, tl_length; + unsigned char *buf; + + if (getint(&p, "TL data type", &tl_type) || + getint(&p, "data length", &tl_length)) + return EINVAL; + + if (asprintf(&reading_what, "TL data type %d (length %d)", + tl_type, tl_length) < 0) + return ENOMEM; + + /* + * XXX Leaking reading_what, but only on ENOMEM cases anyways, + * so we don't care. + */ + CHECK_UINT16(tl_type); + ret = krb5_store_uint16(sp, tl_type); + if (ret) return ret; + CHECK_UINT16(tl_length); + ret = krb5_store_uint16(sp, tl_length); + if (ret) return ret; + + if (tl_length) { + buf = malloc(tl_length); + if (!buf) return ENOMEM; + if (getdata(&p, buf, tl_length, reading_what) != tl_length) { + free(buf); + return EINVAL; + } + sz = krb5_storage_write(sp, buf, tl_length); + free(buf); + if (sz != tl_length) return ENOMEM; + } else { + if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL; + } + free(reading_what); + } + + for (i = 0; i < num_key_data; i++) { + unsigned char *buf; + int key_versions; + int kvno; + int keytype; + int keylen; + size_t k; + + if (getint(&p, "key data 'version'", &key_versions)) return EINVAL; + CHECK_UINT16(key_versions); + ret = krb5_store_int16(sp, key_versions); + if (ret) return ret; + + if (getint(&p, "kvno", &kvno)) return EINVAL; + CHECK_UINT16(kvno); + ret = krb5_store_int16(sp, kvno); + if (ret) return ret; + + for (k = 0; k < key_versions; k++) { + if (getint(&p, "enctype", &keytype)) return EINVAL; + CHECK_UINT16(keytype); + ret = krb5_store_int16(sp, keytype); + if (ret) return ret; + + if (getint(&p, "encrypted key length", &keylen)) return EINVAL; + CHECK_UINT16(keylen); + ret = krb5_store_int16(sp, keylen); + if (ret) return ret; + + if (keylen) { + buf = malloc(keylen); + if (!buf) return ENOMEM; + if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) { + free(buf); + return EINVAL; + } + sz = krb5_storage_write(sp, buf, keylen); + free(buf); + if (sz != keylen) return ENOMEM; + } else { + if (strcmp(nexttoken(&p, 0, + "'-1' zero-length key/salt field"), + "-1") != 0) { + warnx("Expected '-1' field because key/salt length is 0"); + return -1; + } + } + } + } + /* + * The rest is "extra data", but there's never any and we wouldn't + * know what to do with it. + */ + /* nexttoken(&p, 0, "extra data"); */ + return 0; +} + diff --git a/third_party/heimdal/lib/hdb/hdb-sqlite.c b/third_party/heimdal/lib/hdb/hdb-sqlite.c new file mode 100644 index 0000000..4bb2f8e --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb-sqlite.c @@ -0,0 +1,1075 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#include "sqlite3.h" + +#define MAX_RETRIES 10 + +typedef struct hdb_sqlite_db { + double version; + sqlite3 *db; + char *db_file; + + sqlite3_stmt *connect; + sqlite3_stmt *get_version; + sqlite3_stmt *fetch; + sqlite3_stmt *get_ids; + sqlite3_stmt *add_entry; + sqlite3_stmt *add_principal; + sqlite3_stmt *add_alias; + sqlite3_stmt *delete_aliases; + sqlite3_stmt *update_entry; + sqlite3_stmt *remove; + sqlite3_stmt *get_all_entries; + +} hdb_sqlite_db; + +/* This should be used to mark updates which make the code incompatible + * with databases created with previous versions. Don't update it if + * compatibility is not broken. */ +#define HDBSQLITE_VERSION 0.1 + +#define _HDBSQLITE_STRINGIFY(x) #x +#define HDBSQLITE_STRINGIFY(x) _HDBSQLITE_STRINGIFY(x) + +#define HDBSQLITE_CREATE_TABLES \ + " BEGIN TRANSACTION;" \ + " CREATE TABLE Version (number REAL);" \ + " INSERT INTO Version (number)" \ + " VALUES (" HDBSQLITE_STRINGIFY(HDBSQLITE_VERSION) ");" \ + " CREATE TABLE Principal" \ + " (id INTEGER PRIMARY KEY," \ + " principal TEXT UNIQUE NOT NULL," \ + " canonical INTEGER," \ + " entry INTEGER);" \ + " CREATE TABLE Entry" \ + " (id INTEGER PRIMARY KEY," \ + " data BLOB);" \ + " COMMIT" +#define HDBSQLITE_CREATE_TRIGGERS \ + " CREATE TRIGGER remove_principals AFTER DELETE ON Entry" \ + " BEGIN" \ + " DELETE FROM Principal" \ + " WHERE entry = OLD.id;" \ + " END" +#define HDBSQLITE_CONNECT \ + " PRAGMA journal_mode = WAL" +#define HDBSQLITE_GET_VERSION \ + " SELECT number FROM Version" +#define HDBSQLITE_FETCH \ + " SELECT Entry.data FROM Principal, Entry" \ + " WHERE Principal.principal = ? AND" \ + " Entry.id = Principal.entry" +#define HDBSQLITE_GET_IDS \ + " SELECT id, entry FROM Principal" \ + " WHERE principal = ?" +#define HDBSQLITE_ADD_ENTRY \ + " INSERT INTO Entry (data) VALUES (?)" +#define HDBSQLITE_ADD_PRINCIPAL \ + " INSERT INTO Principal (principal, entry, canonical)" \ + " VALUES (?, last_insert_rowid(), 1)" +#define HDBSQLITE_ADD_ALIAS \ + " INSERT INTO Principal (principal, entry, canonical)" \ + " VALUES(?, ?, 0)" +#define HDBSQLITE_DELETE_ALIASES \ + " DELETE FROM Principal" \ + " WHERE entry = ? AND canonical = 0" +#define HDBSQLITE_UPDATE_ENTRY \ + " UPDATE Entry SET data = ?" \ + " WHERE id = ?" +#define HDBSQLITE_REMOVE \ + " DELETE FROM ENTRY WHERE id = " \ + " (SELECT entry FROM Principal" \ + " WHERE principal = ?)" +#define HDBSQLITE_GET_ALL_ENTRIES \ + " SELECT data FROM Entry" + +/** + * Wrapper around sqlite3_prepare_v2. + * + * @param context The current krb5 context + * @param statement Where to store the pointer to the statement + * after preparing it + * @param str SQL code for the statement + * + * @return 0 if OK, an error code if not + */ +static krb5_error_code +hdb_sqlite_prepare_stmt(krb5_context context, + sqlite3 *db, + sqlite3_stmt **statement, + const char *str) +{ + int ret, tries = 0; + + ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); + while((tries++ < MAX_RETRIES) && + ((ret == SQLITE_BUSY) || + (ret == SQLITE_IOERR_BLOCKED) || + (ret == SQLITE_LOCKED))) { + krb5_warnx(context, "hdb-sqlite: prepare busy"); + sleep(1); + ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); + } + + if (ret != SQLITE_OK) { + krb5_set_error_message(context, HDB_ERR_UK_RERROR, + "Failed to prepare stmt %s: %s", + str, sqlite3_errmsg(db)); + return HDB_ERR_UK_RERROR; + } + + return 0; +} + +static krb5_error_code +prep_stmts(krb5_context context, hdb_sqlite_db *hsdb) +{ + int ret; + + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->connect, + HDBSQLITE_CONNECT); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_version, + HDBSQLITE_GET_VERSION); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->fetch, + HDBSQLITE_FETCH); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_ids, + HDBSQLITE_GET_IDS); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_entry, + HDBSQLITE_ADD_ENTRY); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_principal, + HDBSQLITE_ADD_PRINCIPAL); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->add_alias, + HDBSQLITE_ADD_ALIAS); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->delete_aliases, + HDBSQLITE_DELETE_ALIASES); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->update_entry, + HDBSQLITE_UPDATE_ENTRY); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->remove, + HDBSQLITE_REMOVE); + if (ret) + return ret; + ret = hdb_sqlite_prepare_stmt(context, hsdb->db, + &hsdb->get_all_entries, + HDBSQLITE_GET_ALL_ENTRIES); + return ret; +} + +static void +finalize_stmts(krb5_context context, hdb_sqlite_db *hsdb) +{ + if (hsdb->connect != NULL) + sqlite3_finalize(hsdb->connect); + hsdb->connect = NULL; + + if (hsdb->get_version != NULL) + sqlite3_finalize(hsdb->get_version); + hsdb->get_version = NULL; + + if (hsdb->fetch != NULL) + sqlite3_finalize(hsdb->fetch); + hsdb->fetch = NULL; + + if (hsdb->get_ids != NULL) + sqlite3_finalize(hsdb->get_ids); + hsdb->get_ids = NULL; + + if (hsdb->add_entry != NULL) + sqlite3_finalize(hsdb->add_entry); + hsdb->add_entry = NULL; + + if (hsdb->add_principal != NULL) + sqlite3_finalize(hsdb->add_principal); + hsdb->add_principal = NULL; + + if (hsdb->add_alias != NULL) + sqlite3_finalize(hsdb->add_alias); + hsdb->add_alias = NULL; + + if (hsdb->delete_aliases != NULL) + sqlite3_finalize(hsdb->delete_aliases); + hsdb->delete_aliases = NULL; + + if (hsdb->update_entry != NULL) + sqlite3_finalize(hsdb->update_entry); + hsdb->update_entry = NULL; + + if (hsdb->remove != NULL) + sqlite3_finalize(hsdb->remove); + hsdb->remove = NULL; + + if (hsdb->get_all_entries != NULL) + sqlite3_finalize(hsdb->get_all_entries); + hsdb->get_all_entries = NULL; +} + +/** + * A wrapper around sqlite3_exec. + * + * @param context The current krb5 context + * @param database An open sqlite3 database handle + * @param statement SQL code to execute + * @param error_code What to return if the statement fails + * + * @return 0 if OK, else error_code + */ +static krb5_error_code +hdb_sqlite_exec_stmt(krb5_context context, + hdb_sqlite_db *hsdb, + const char *statement, + krb5_error_code error_code) +{ + int ret; + int reinit_stmts = 0; + sqlite3 *database = hsdb->db; + + ret = sqlite3_exec(database, statement, NULL, NULL, NULL); + + while(((ret == SQLITE_BUSY) || + (ret == SQLITE_IOERR_BLOCKED) || + (ret == SQLITE_LOCKED))) { + if (reinit_stmts == 0 && ret == SQLITE_BUSY) { + finalize_stmts(context, hsdb); + reinit_stmts = 1; + } + krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid()); + sleep(1); + ret = sqlite3_exec(database, statement, NULL, NULL, NULL); + } + + if (ret != SQLITE_OK && error_code) { + krb5_set_error_message(context, error_code, + "Execute %s: %s", statement, + sqlite3_errmsg(database)); + return error_code; + } + + if (reinit_stmts) + return prep_stmts(context, hsdb); + + return 0; +} + +/** + * + */ + +static krb5_error_code +bind_principal(krb5_context context, krb5_const_principal principal, sqlite3_stmt *stmt, int key) +{ + krb5_error_code ret; + char *str = NULL; + + ret = krb5_unparse_name(context, principal, &str); + if (ret) + return ret; + + sqlite3_bind_text(stmt, key, str, -1, SQLITE_TRANSIENT); + free(str); + return 0; +} + +static int hdb_sqlite_step(krb5_context, sqlite3 *, sqlite3_stmt *); + +/** + * Opens an sqlite3 database handle to a file, may create the + * database file depending on flags. + * + * @param context The current krb5 context + * @param db Heimdal database handle + * @param flags Controls whether or not the file may be created, + * may be 0 or SQLITE_OPEN_CREATE + */ +static krb5_error_code +hdb_sqlite_open_database(krb5_context context, HDB *db, int flags) +{ + int ret; + hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db; + + ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db, + SQLITE_OPEN_READWRITE | flags, NULL); + + if (ret) { + if (hsdb->db) { + ret = ENOENT; + krb5_set_error_message(context, ret, + "Error opening sqlite database %s: %s", + hsdb->db_file, sqlite3_errmsg(hsdb->db)); + sqlite3_close(hsdb->db); + hsdb->db = NULL; + } else + ret = krb5_enomem(context); + return ret; + } + return 0; +} + +static int +hdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt) +{ + int ret; + + ret = sqlite3_step(stmt); + while(((ret == SQLITE_BUSY) || + (ret == SQLITE_IOERR_BLOCKED) || + (ret == SQLITE_LOCKED))) { + krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid()); + sleep(1); + ret = sqlite3_step(stmt); + } + return ret; +} + +/** + * Closes the database and frees memory allocated for statements. + * + * @param context The current krb5 context + * @param db Heimdal database handle + */ +static krb5_error_code +hdb_sqlite_close_database(krb5_context context, HDB *db) +{ + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + + finalize_stmts(context, hsdb); + + /* XXX Use sqlite3_close_v2() when we upgrade SQLite3 */ + if (sqlite3_close(hsdb->db) != SQLITE_OK) { + krb5_set_error_message(context, HDB_ERR_UK_SERROR, + "SQLite BEGIN TRANSACTION failed: %s", + sqlite3_errmsg(hsdb->db)); + return HDB_ERR_UK_SERROR; + } + + return 0; +} + +/** + * Opens an sqlite database file and prepares it for use. + * If the file does not exist it will be created. + * + * @param context The current krb5_context + * @param db The heimdal database handle + * @param filename Where to store the database file + * + * @return 0 if everything worked, an error code if not + */ +static krb5_error_code +hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) +{ + int ret; + int created_file = 0; + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + + hsdb->db_file = strdup(filename); + if(hsdb->db_file == NULL) + return ENOMEM; + + ret = hdb_sqlite_open_database(context, db, 0); + if (ret) { + ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE); + if (ret) goto out; + + created_file = 1; + + hdb_sqlite_exec_stmt(context, hsdb, + "PRAGMA main.page_size = 8192", + HDB_ERR_UK_SERROR); + + ret = hdb_sqlite_exec_stmt(context, hsdb, + HDBSQLITE_CREATE_TABLES, + HDB_ERR_UK_SERROR); + if (ret) goto out; + + ret = hdb_sqlite_exec_stmt(context, hsdb, + HDBSQLITE_CREATE_TRIGGERS, + HDB_ERR_UK_SERROR); + if (ret) goto out; + } + + ret = prep_stmts(context, hsdb); + if (ret) goto out; + + sqlite3_reset(hsdb->connect); + (void) hdb_sqlite_step(context, hsdb->db, hsdb->connect); + sqlite3_reset(hsdb->connect); + + ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version); + if(ret == SQLITE_ROW) { + hsdb->version = sqlite3_column_double(hsdb->get_version, 0); + } + sqlite3_reset(hsdb->get_version); + ret = 0; + + if(hsdb->version != HDBSQLITE_VERSION) { + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch"); + } + + if(ret) goto out; + + return 0; + + out: + if (hsdb->db) + sqlite3_close(hsdb->db); + if (created_file) + unlink(hsdb->db_file); + free(hsdb->db_file); + hsdb->db_file = NULL; + + return ret; +} + +/** + * Retrieves an entry by searching for the given + * principal in the Principal database table, both + * for canonical principals and aliases. + * + * @param context The current krb5_context + * @param db Heimdal database handle + * @param principal The principal whose entry to search for + * @param flags Currently only for HDB_F_DECRYPT + * @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used + * + * @return 0 if everything worked, an error code if not + */ +static krb5_error_code +hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry *entry) +{ + int sqlite_error; + krb5_error_code ret; + hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); + sqlite3_stmt *fetch = hsdb->fetch; + krb5_data value; + krb5_principal enterprise_principal = NULL; + + if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + if (principal->name.name_string.len != 1) { + ret = KRB5_PARSE_MALFORMED; + krb5_set_error_message(context, ret, "malformed principal: " + "enterprise name with %d name components", + principal->name.name_string.len); + return ret; + } + ret = krb5_parse_name(context, principal->name.name_string.val[0], + &enterprise_principal); + if (ret) + return ret; + principal = enterprise_principal; + } + + ret = bind_principal(context, principal, fetch, 1); + krb5_free_principal(context, enterprise_principal); + if (ret) + return ret; + + sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); + if (sqlite_error != SQLITE_ROW) { + if(sqlite_error == SQLITE_DONE) { + ret = HDB_ERR_NOENTRY; + goto out; + } else { + ret = HDB_ERR_UK_RERROR; + krb5_set_error_message(context, ret, + "sqlite fetch failed: %d", + sqlite_error); + goto out; + } + } + + value.length = sqlite3_column_bytes(fetch, 0); + value.data = (void *) sqlite3_column_blob(fetch, 0); + + ret = hdb_value2entry(context, &value, entry); + if(ret) + goto out; + + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + ret = hdb_unseal_keys(context, db, entry); + if(ret) { + hdb_free_entry(context, db, entry); + goto out; + } + } + + ret = 0; + +out: + + sqlite3_clear_bindings(fetch); + sqlite3_reset(fetch); + + + return ret; +} + +/** + * Convenience function to step a prepared statement with no + * value once. + * + * @param context The current krb5_context + * @param statement A prepared sqlite3 statement + * + * @return 0 if everything worked, an error code if not + */ +static krb5_error_code +hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement) +{ + int ret; + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + + ret = hdb_sqlite_step(context, hsdb->db, statement); + sqlite3_clear_bindings(statement); + sqlite3_reset(statement); + + return ret; +} + + +/** + * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE + * a previous entry may be replaced. + * + * @param context The current krb5_context + * @param db Heimdal database handle + * @param flags May currently only contain HDB_F_REPLACE + * @param entry The data to store + * + * @return 0 if everything worked, an error code if not + */ +static krb5_error_code +hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, + hdb_entry *entry) +{ + int ret; + int i; + sqlite_int64 entry_id; + const HDB_Ext_Aliases *aliases; + + hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); + krb5_data value; + sqlite3_stmt *get_ids = hsdb->get_ids; + + krb5_data_zero(&value); + + ret = hdb_sqlite_exec_stmt(context, hsdb, + "BEGIN IMMEDIATE TRANSACTION", + HDB_ERR_UK_SERROR); + if(ret != SQLITE_OK) { + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, + "SQLite BEGIN TRANSACTION failed: %s", + sqlite3_errmsg(hsdb->db)); + goto rollback; + } + + ret = hdb_seal_keys(context, db, entry); + if(ret) { + goto rollback; + } + + ret = hdb_entry2value(context, entry, &value); + if(ret) { + goto rollback; + } + + ret = bind_principal(context, entry->principal, get_ids, 1); + if (ret) + goto rollback; + + ret = hdb_sqlite_step(context, hsdb->db, get_ids); + + if(ret == SQLITE_DONE) { /* No such principal */ + + sqlite3_bind_blob(hsdb->add_entry, 1, + value.data, value.length, SQLITE_STATIC); + ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); + sqlite3_clear_bindings(hsdb->add_entry); + sqlite3_reset(hsdb->add_entry); + if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; + goto rollback; + } + + ret = bind_principal(context, entry->principal, hsdb->add_principal, 1); + if (ret) + goto rollback; + + ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); + sqlite3_clear_bindings(hsdb->add_principal); + sqlite3_reset(hsdb->add_principal); + if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; + goto rollback; + } + + /* Now let's learn what Entry ID we got for the new principal */ + sqlite3_reset(get_ids); + ret = hdb_sqlite_step(context, hsdb->db, get_ids); + if (ret != SQLITE_ROW) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + + entry_id = sqlite3_column_int64(get_ids, 1); + + } else if(ret == SQLITE_ROW) { /* Found a principal */ + + if(!(flags & HDB_F_REPLACE)) { + ret = HDB_ERR_EXISTS; + goto rollback; + } + + entry_id = sqlite3_column_int64(get_ids, 1); + + sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); + ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + + sqlite3_bind_blob(hsdb->update_entry, 1, + value.data, value.length, SQLITE_STATIC); + sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); + ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + + } else { + /* Error! */ + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + + ret = hdb_entry_get_aliases(entry, &aliases); + if(ret || aliases == NULL) + goto commit; + + for(i = 0; i < aliases->aliases.len; i++) { + + ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1); + if (ret) + goto rollback; + + sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); + ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); + if (ret == SQLITE_CONSTRAINT) { + ret = HDB_ERR_EXISTS; + goto rollback; + } + if (ret != SQLITE_DONE) { + ret = HDB_ERR_UK_SERROR; + goto rollback; + } + } + +commit: + krb5_data_free(&value); + sqlite3_clear_bindings(get_ids); + sqlite3_reset(get_ids); + + if ((flags & HDB_F_PRECHECK)) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return 0; + } + + ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR); + if(ret != SQLITE_OK) + krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s", + (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db)); + + return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR; + +rollback: + krb5_data_free(&value); + sqlite3_clear_bindings(get_ids); + sqlite3_reset(get_ids); + krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", + ret, sqlite3_errmsg(hsdb->db)); + + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return ret; +} + +/** + * This may be called often by other code, since the BDB backends + * can not have several open connections. SQLite can handle + * many processes with open handles to the database file + * and closing/opening the handle is an expensive operation. + * Hence, this function does nothing. + * + * @param context The current krb5 context + * @param db Heimdal database handle + * + * @return Always returns 0 + */ +static krb5_error_code +hdb_sqlite_close(krb5_context context, HDB *db) +{ + return 0; +} + +/** + * The opposite of hdb_sqlite_close. Since SQLite accepts + * many open handles to the database file the handle does not + * need to be closed, or reopened. + * + * @param context The current krb5 context + * @param db Heimdal database handle + * @param flags + * @param mode_t + * + * @return Always returns 0 + */ +static krb5_error_code +hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + return 0; +} + +/** + * Closes the databse and frees all resources. + * + * @param context The current krb5 context + * @param db Heimdal database handle + * + * @return 0 on success, an error code if not + */ +static krb5_error_code +hdb_sqlite_destroy(krb5_context context, HDB *db) +{ + int ret, ret2; + hdb_sqlite_db *hsdb; + + ret = hdb_clear_master_key(context, db); + + ret2 = hdb_sqlite_close_database(context, db); + + hsdb = (hdb_sqlite_db*)(db->hdb_db); + + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(hsdb->db_file); + free(db->hdb_name); + free(db->hdb_db); + free(db); + + return ret ? ret : ret2; +} + +static krb5_error_code +hdb_sqlite_set_sync(krb5_context context, HDB *db, int on) +{ + return hdb_sqlite_exec_stmt(context, (hdb_sqlite_db*)(db->hdb_db), + on ? "PRAGMA main.synchronous = NORMAL" : + "PRAGMA main.synchronous = OFF", + HDB_ERR_UK_SERROR); +} + +/* + * Not sure if this is needed. + */ +static krb5_error_code +hdb_sqlite_lock(krb5_context context, HDB *db, int operation) +{ + krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, + "lock not implemented"); + return HDB_ERR_CANT_LOCK_DB; +} + +/* + * Not sure if this is needed. + */ +static krb5_error_code +hdb_sqlite_unlock(krb5_context context, HDB *db) +{ + krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, + "unlock not implemented"); + return HDB_ERR_CANT_LOCK_DB; +} + +/* + * Should get the next entry, to allow iteration over all entries. + */ +static krb5_error_code +hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, + hdb_entry *entry) +{ + krb5_error_code ret = 0; + int sqlite_error; + krb5_data value; + + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + + sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries); + if(sqlite_error == SQLITE_ROW) { + /* Found an entry */ + value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); + value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); + memset(entry, 0, sizeof(*entry)); + ret = hdb_value2entry(context, &value, entry); + } + else if(sqlite_error == SQLITE_DONE) { + /* No more entries */ + ret = HDB_ERR_NOENTRY; + sqlite3_reset(hsdb->get_all_entries); + } + else { + ret = HDB_ERR_UK_RERROR; + krb5_set_error_message(context, HDB_ERR_UK_RERROR, + "SELECT failed after returning one or " + "more rows: %s", sqlite3_errmsg(hsdb->db)); + + } + + return ret; +} + +/* + * Should get the first entry in the database. + * What is flags used for? + */ +static krb5_error_code +hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags, + hdb_entry *entry) +{ + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + krb5_error_code ret; + + sqlite3_reset(hsdb->get_all_entries); + + ret = hdb_sqlite_nextkey(context, db, flags, entry); + if(ret) + return ret; + + return 0; +} + +/* + * Renames the database file. + */ +static krb5_error_code +hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name) +{ + krb5_error_code ret, ret2; + hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; + + krb5_warnx(context, "hdb_sqlite_rename"); + + if (strncasecmp(new_name, "sqlite:", 7) == 0) + new_name += 7; + + ret = hdb_sqlite_close_database(context, db); + + if (rename(hsdb->db_file, new_name) == -1) + return errno; + + free(hsdb->db_file); + ret2 = hdb_sqlite_make_database(context, db, new_name); + return ret ? ret : ret2; +} + +/* + * Removes a principal, including aliases and associated entry. + */ +static krb5_error_code +hdb_sqlite_remove(krb5_context context, HDB *db, + unsigned flags, krb5_const_principal principal) +{ + krb5_error_code ret; + hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); + sqlite3_stmt *get_ids = hsdb->get_ids; + sqlite3_stmt *rm = hsdb->remove; + + ret = bind_principal(context, principal, rm, 1); + + if (ret == 0) + ret = hdb_sqlite_exec_stmt(context, hsdb, + "BEGIN IMMEDIATE TRANSACTION", + HDB_ERR_UK_SERROR); + if (ret != SQLITE_OK) { + ret = HDB_ERR_UK_SERROR; + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + krb5_set_error_message(context, ret, + "SQLite BEGIN TRANSACTION failed: %s", + sqlite3_errmsg(hsdb->db)); + return ret; + } + + if ((flags & HDB_F_PRECHECK)) { + ret = bind_principal(context, principal, get_ids, 1); + if (ret) + return ret; + + ret = hdb_sqlite_step(context, hsdb->db, get_ids); + sqlite3_clear_bindings(get_ids); + sqlite3_reset(get_ids); + if (ret == SQLITE_DONE) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return HDB_ERR_NOENTRY; + } + } + + ret = hdb_sqlite_step(context, hsdb->db, rm); + sqlite3_clear_bindings(rm); + sqlite3_reset(rm); + if (ret != SQLITE_DONE) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, "sqlite remove failed: %d", ret); + return ret; + } + + if ((flags & HDB_F_PRECHECK)) { + (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); + return 0; + } + + ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR); + if (ret != SQLITE_OK) + krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s", + (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db)); + + return 0; +} + +/** + * Create SQLITE object, and creates the on disk database if its doesn't exists. + * + * @param context A Kerberos 5 context. + * @param db a returned database handle. + * @param filename filename + * + * @return 0 on success, an error code if not + */ + +krb5_error_code +hdb_sqlite_create(krb5_context context, HDB **db, const char *filename) +{ + krb5_error_code ret; + hdb_sqlite_db *hsdb; + + *db = calloc(1, sizeof (**db)); + if (*db == NULL) + return krb5_enomem(context); + + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + return krb5_enomem(context); + } + + hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb)); + if (hsdb == NULL) { + free((*db)->hdb_name); + free(*db); + *db = NULL; + return krb5_enomem(context); + } + + (*db)->hdb_db = hsdb; + + /* XXX make_database should make sure everything else is freed on error */ + ret = hdb_sqlite_make_database(context, *db, filename); + if (ret) { + free((*db)->hdb_db); + free(*db); + *db = NULL; + return ret; + } + + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + + (*db)->hdb_open = hdb_sqlite_open; + (*db)->hdb_close = hdb_sqlite_close; + + (*db)->hdb_lock = hdb_sqlite_lock; + (*db)->hdb_unlock = hdb_sqlite_unlock; + (*db)->hdb_firstkey = hdb_sqlite_firstkey; + (*db)->hdb_nextkey = hdb_sqlite_nextkey; + (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno; + (*db)->hdb_store = hdb_sqlite_store; + (*db)->hdb_remove = hdb_sqlite_remove; + (*db)->hdb_destroy = hdb_sqlite_destroy; + (*db)->hdb_rename = hdb_sqlite_rename; + (*db)->hdb_set_sync = hdb_sqlite_set_sync; + (*db)->hdb__get = NULL; + (*db)->hdb__put = NULL; + (*db)->hdb__del = NULL; + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/hdb.asn1 b/third_party/heimdal/lib/hdb/hdb.asn1 new file mode 100644 index 0000000..35b5e29 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.asn1 @@ -0,0 +1,254 @@ +-- $Id$ +HDB DEFINITIONS ::= +BEGIN + +IMPORTS EncryptionKey, KerberosTime, Principal FROM krb5; + +hdb_db_format INTEGER ::= 2 -- format of database, + -- update when making changes + +-- these must have the same value as the pa-* counterparts +hdb-pw-salt INTEGER ::= 3 +hdb-afs3-salt INTEGER ::= 10 + +Salt ::= SEQUENCE { + type[0] INTEGER (0..4294967295), + salt[1] OCTET STRING, + opaque[2] OCTET STRING OPTIONAL +} + +Key ::= SEQUENCE { + mkvno[0] INTEGER (0..4294967295) OPTIONAL, -- master key version number + key[1] EncryptionKey, + salt[2] Salt OPTIONAL +} + +Event ::= SEQUENCE { + time[0] KerberosTime, + principal[1] Principal OPTIONAL +} + +HDBFlags ::= BIT STRING { + initial(0), -- require as-req + forwardable(1), -- may issue forwardable + proxiable(2), -- may issue proxiable + renewable(3), -- may issue renewable + postdate(4), -- may issue postdatable + server(5), -- may be server + client(6), -- may be client + invalid(7), -- entry is invalid + require-preauth(8), -- must use preauth + change-pw(9), -- change password service + require-hwauth(10), -- must use hwauth + ok-as-delegate(11), -- as in TicketFlags + user-to-user(12), -- may use user-to-user auth + immutable(13), -- may not be deleted + trusted-for-delegation(14), -- Trusted to print forwardabled tickets + allow-kerberos4(15), -- Allow Kerberos 4 requests + allow-digest(16), -- Allow digest requests + locked-out(17), -- Account is locked out, + -- authentication will be denied + require-pwchange(18), -- require a passwd change + + materialize(19), -- store even if within virtual namespace + virtual-keys(20), -- entry stored; keys mostly derived + virtual(21), -- entry not stored; keys always derived + synthetic(22), -- entry not stored; for PKINIT + no-auth-data-reqd(23), -- omit PAC from service tickets + auth-data-reqd(24), -- include PAC in service tickets + + force-canonicalize(30), -- force the KDC to return the canonical + -- principal irrespective of the setting + -- of the canonicalize KDC option + -- (principals cannot have this flag + -- set when stored into the HDB) + do-not-store(31) -- Not to be modified and stored in HDB +} + +GENERATION ::= SEQUENCE { + time[0] KerberosTime, -- timestamp + usec[1] INTEGER (0..4294967295), -- microseconds + gen[2] INTEGER (0..4294967295) -- generation number +} + +HDB-Ext-PKINIT-acl ::= SEQUENCE OF SEQUENCE { + subject[0] UTF8String, + issuer[1] UTF8String OPTIONAL, + anchor[2] UTF8String OPTIONAL +} + +HDB-Ext-PKINIT-hash ::= SEQUENCE OF SEQUENCE { + digest-type[0] OBJECT IDENTIFIER, + digest[1] OCTET STRING +} + +HDB-Ext-PKINIT-cert ::= SEQUENCE OF SEQUENCE { + cert[0] OCTET STRING +} + +HDB-Ext-Constrained-delegation-acl ::= SEQUENCE OF Principal + +-- hdb-ext-referrals ::= PA-SERVER-REFERRAL-DATA + +HDB-Ext-Lan-Manager-OWF ::= OCTET STRING + +HDB-Ext-Password ::= SEQUENCE { + mkvno[0] INTEGER (0..4294967295) OPTIONAL, -- master key version number + password OCTET STRING +} + +HDB-Ext-Aliases ::= SEQUENCE { + case-insensitive[0] BOOLEAN, -- case insensitive name allowed + aliases[1] SEQUENCE OF Principal -- all names, inc primary +} + +Keys ::= SEQUENCE OF Key + +HDB_keyset ::= SEQUENCE { + kvno[0] INTEGER (0..4294967295), + keys[1] Keys, + set-time[2] KerberosTime OPTIONAL, -- time this keyset was created/set + ... +} + +HDB-Ext-KeySet ::= SEQUENCE OF HDB_keyset + +-- +-- We need a function of current (or given, but it will always be current) time +-- and a base hdb_entry or its HDB-Ext-KeyRotation and service ticket lifetime, +-- that outputs a sequence of {kvno, set_time, max_life} representing past keys +-- (up to one per past and current KeyRotation), current keys (for the current +-- KeyRotation), up to one future key for the current KeyRotation, and up to +-- one future key for the _next_ (future) KeyRotation if there is one. +-- +-- We have to impose constraints on new KeyRotation elements of +-- HDB-Ext-KeyRotation. +-- +-- So virtual keysets (keytabs) will contain: +-- +-- - up to one past keyset for all KeyRotation periods that are "applicable" +-- - the current keyset for all KeyRotation periods that are "applicable" +-- - up to one future keyset for all KeyRotation periods that are "applicable" +-- +-- An applicable KeyRotation period is: +-- +-- - the KeyRotation whose `epoch` is a) in the past and b) nearest to the +-- current time - we call this the current KeyRotation +-- - a KeyRotation whose `epoch` is nearest but in the past of the current +-- one +-- - a KeyRotation whose `epoch` is nearest but in the future of the current +-- one +-- +-- A service principal's max ticket life will be bounded by half the current +-- key rotation period. +-- +-- Note: There can be more than one applicable past KeyRotation, and more than +-- one applicable KeyRotation. We might not want to permit this. +-- However, it's probably easier to permit it, though we might not test +-- end-to-end. +-- +-- Testing: +-- +-- - We should have standalone unit tests for all these pure functions. +-- +-- - We should have a test that uses kadm5 and GSS to test against a KDC using +-- small key rotation periods on the order of seconds, with back-off in case +-- of losing a race condition. +-- +KeyRotationFlags ::= BIT STRING { + deleted(0), -- if set on a materialized principal, this will mean + -- the principal does not exist + -- if set on a namespace, this will mean that + -- only materialized principal below it exist + parent(1) -- if set on a materialized principal, this will mean + -- that the keys for kvnos in this KeyRotation spec + -- will be derived from the parent's base keys and + -- corresponding KeyRotation spec + -- if set on a namespace, this flag will be ignored + -- (or we could support nested namespaces?) +} +KeyRotation ::= SEQUENCE { + -- base-kvno is always computed at set time and set for the principal, + -- and is never subject to admin choice. The base-kvno is that of the + -- current kvno at that period's `from` given the previous period. + -- + -- Also, insertion of KeyRotation elements before existing ones (in + -- time) is never permitted, and all new KeyRotation elements must be + -- in the future relative to existing ones. + -- + -- HDB-Ext-KeyRotation will always be sorted (as stored) by `from`, in + -- descending order. + -- + -- Max service ticket lifetime will be constrained to no more than half + -- the period of the the applicable KeyRotation elements. + -- + flags[0] KeyRotationFlags, + epoch[1] KerberosTime, -- start of this period + period[2] INTEGER(0..4294967295), -- key rotation seconds + base-kvno[3] INTEGER(0..4294967295), -- starting from this kvno + base-key-kvno[4]INTEGER(0..4294967295), -- kvno of base-key + ... +} + +HDB-Ext-KeyRotation ::= SEQUENCE SIZE (1..3) OF KeyRotation + +HDB-extension ::= SEQUENCE { + mandatory[0] BOOLEAN, -- kdc MUST understand this extension, + -- if not the whole entry must + -- be rejected + data[1] CHOICE { + pkinit-acl[0] HDB-Ext-PKINIT-acl, + pkinit-cert-hash[1] HDB-Ext-PKINIT-hash, + allowed-to-delegate-to[2] HDB-Ext-Constrained-delegation-acl, +-- referral-info[3] HDB-Ext-Referrals, + lm-owf[4] HDB-Ext-Lan-Manager-OWF, + password[5] HDB-Ext-Password, + aliases[6] HDB-Ext-Aliases, + last-pw-change[7] KerberosTime, + pkinit-cert[8] HDB-Ext-PKINIT-cert, + hist-keys[9] HDB-Ext-KeySet, + hist-kvno-diff-clnt[10] INTEGER (0..4294967295), + hist-kvno-diff-svc[11] INTEGER (0..4294967295), + policy[12] UTF8String, + principal-id[13] INTEGER(-9223372036854775808..9223372036854775807), + key-rotation[14] HDB-Ext-KeyRotation, + krb5-config[15] OCTET STRING, + ... + }, + ... +} + +HDB-extensions ::= SEQUENCE OF HDB-extension + +-- Just for convenience, for encoding this as TL data in lib/kadm5 +HDB-EncTypeList ::= SEQUENCE OF INTEGER (0..4294967295) + +HDB_entry ::= SEQUENCE { + principal[0] Principal OPTIONAL, -- this is optional only + -- for compatibility with libkrb5 + kvno[1] INTEGER (0..4294967295), + keys[2] Keys, + created-by[3] Event, + modified-by[4] Event OPTIONAL, + valid-start[5] KerberosTime OPTIONAL, + valid-end[6] KerberosTime OPTIONAL, + pw-end[7] KerberosTime OPTIONAL, + max-life[8] INTEGER (-2147483648..2147483647) OPTIONAL, + max-renew[9] INTEGER (-2147483648..2147483647) OPTIONAL, + flags[10] HDBFlags, + etypes[11] HDB-EncTypeList OPTIONAL, + generation[12] GENERATION OPTIONAL, + extensions[13] HDB-extensions OPTIONAL, + session-etypes[14] HDB-EncTypeList OPTIONAL +} + +HDB_entry_alias ::= [APPLICATION 0] SEQUENCE { + principal[0] Principal OPTIONAL +} + +HDB-EntryOrAlias ::= CHOICE { + entry HDB_entry, + alias HDB_entry_alias +} + +END diff --git a/third_party/heimdal/lib/hdb/hdb.c b/third_party/heimdal/lib/hdb/hdb.c new file mode 100644 index 0000000..864b4f6 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include "hdb_locl.h" + +#ifdef HAVE_DLFCN_H +#include +#endif + +/*! @mainpage Heimdal database backend library + * + * @section intro Introduction + * + * Heimdal libhdb library provides the backend support for Heimdal kdc + * and kadmind. Its here where plugins for diffrent database engines + * can be pluged in and extend support for here Heimdal get the + * principal and policy data from. + * + * Example of Heimdal backend are: + * - Berkeley DB 1.85 + * - Berkeley DB 3.0 + * - Berkeley DB 4.0 + * - New Berkeley DB + * - LDAP + * + * + * The project web page: http://www.h5l.org/ + * + */ + +const int hdb_interface_version = HDB_INTERFACE_VERSION; + +static struct hdb_method methods[] = { + /* "db:" should be db3 if we have db3, or db1 if we have db1 */ +#if HAVE_DB3 + { HDB_INTERFACE_VERSION, NULL, NULL, 1 /*is_file_based*/, 1 /*can_taste*/, + "db:", hdb_db3_create}, +#elif HAVE_DB1 + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db:", hdb_db1_create}, +#endif +#if HAVE_DB1 + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db1:", hdb_db1_create}, +#endif +#if HAVE_DB3 + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "db3:", hdb_db3_create}, +#endif +#if HAVE_DB1 + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "mit-db:", hdb_mitdb_create}, +#endif +#if HAVE_LMDB + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "mdb:", hdb_mdb_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "lmdb:", hdb_mdb_create}, +#endif +#if HAVE_NDBM + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "ndbm:", hdb_ndbm_create}, +#endif +#ifdef HAVE_SQLITE3 + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "sqlite:", hdb_sqlite_create}, +#endif + /* The keytab interface can't use its hdb_open() method to "taste" a DB */ + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 0, "keytab:", hdb_keytab_create}, + /* The rest are not file-based */ +#if defined(OPENLDAP) && !defined(OPENLDAP_MODULE) + { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:", hdb_ldap_create}, + { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:", hdb_ldapi_create}, +#elif defined(OPENLDAP) + { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldap:", NULL}, + { HDB_INTERFACE_VERSION, NULL, NULL, 0, 0, "ldapi:", NULL}, +#endif + { 0, NULL, NULL, 0, 0, NULL, NULL} +}; + +/** + * Returns the Keys of `e' for `kvno', or NULL if not found. The Keys will + * remain valid provided that the entry is not mutated. + * + * @param context Context + * @param e The HDB entry + * @param kvno The kvno + * + * @return A pointer to the Keys for the requested kvno. + */ +const Keys * +hdb_kvno2keys(krb5_context context, + const hdb_entry *e, + krb5_kvno kvno) +{ + HDB_Ext_KeySet *hist_keys; + HDB_extension *extp; + size_t i; + + if (kvno == 0 || e->kvno == kvno) + return &e->keys; + + extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys); + if (extp == NULL) + return 0; + + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == kvno) + return &hist_keys->val[i].keys; + } + + return NULL; +} + +/* Based on remove_HDB_Ext_KeySet(), generated by the ASN.1 compiler */ +static int +dequeue_HDB_Ext_KeySet(HDB_Ext_KeySet *data, unsigned int element, hdb_keyset *ks) +{ + if (element >= data->len) { + ks->kvno = 0; + ks->keys.len = 0; + ks->keys.val = 0; + ks->set_time = 0; + return ASN1_OVERRUN; + } + *ks = data->val[element]; + data->len--; + /* Swap instead of memmove()... changes the order of elements */ + if (element < data->len) + data->val[element] = data->val[data->len]; + if (data->len == 0) { + free(data->val); + data->val = 0; + } + return 0; +} + + +/** + * Removes from `e' and optionally outputs the keyset for the requested `kvno'. + * + * @param context Context + * @param e The HDB entry + * @param kvno The key version number + * @param ks A pointer to a variable of type hdb_keyset (may be NULL) + * + * @return Zero on success, an error code otherwise. + */ +krb5_error_code +hdb_remove_keys(krb5_context context, + hdb_entry *e, + krb5_kvno kvno, + hdb_keyset *ks) +{ + HDB_Ext_KeySet *hist_keys; + HDB_extension *extp; + size_t i; + + if (kvno == 0 || e->kvno == kvno) { + if (ks) { + KerberosTime t; + + (void) hdb_entry_get_pw_change_time(e, &t); + if (t) { + if ((ks->set_time = malloc(sizeof(*ks->set_time))) == NULL) + return krb5_enomem(context); + *ks->set_time = t; + } + ks->kvno = e->kvno; + ks->keys = e->keys; + e->keys.len = 0; + e->keys.val = NULL; + e->kvno = 0; + } else { + free_Keys(&e->keys); + } + return 0; + } + + if (ks) { + ks->kvno = 0; + ks->keys.len = 0; + ks->keys.val = 0; + ks->set_time = 0; + } + + extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys); + if (extp == NULL) + return 0; + + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno != kvno) + continue; + if (ks) + return dequeue_HDB_Ext_KeySet(hist_keys, i, ks); + return remove_HDB_Ext_KeySet(hist_keys, i); + } + return HDB_ERR_NOENTRY; +} + +/** + * Removes from `e' and outputs all the base keys for virtual principal and/or + * key derivation. + * + * @param context Context + * @param e The HDB entry + * @param ks A pointer to a variable of type HDB_Ext_KeySet + * @param ckr A pointer to stable (copied) HDB_Ext_KeyRotation + * + * @return Zero on success, an error code otherwise. + */ +krb5_error_code +_hdb_remove_base_keys(krb5_context context, + hdb_entry *e, + HDB_Ext_KeySet *base_keys, + const HDB_Ext_KeyRotation *ckr) +{ + krb5_error_code ret = 0; + size_t i, k; + + base_keys->len = 0; + if ((base_keys->val = calloc(ckr->len, sizeof(base_keys->val[0]))) == NULL) + ret = krb5_enomem(context); + + for (k = i = 0; ret == 0 && i < ckr->len; i++) { + const KeyRotation *krp = &ckr->val[i]; + + /* + * WARNING: O(N * M) where M is number of keysets and N is the number + * of base keysets. + * + * In practice N will never be > 3 because the ASN.1 module imposes + * that as a constraint, and M will generally be the same as N, so this + * will be O(1) after all. + */ + ret = hdb_remove_keys(context, e, krp->base_key_kvno, + &base_keys->val[k]); + if (ret == 0) + k++; + else if (ret == HDB_ERR_NOENTRY) + ret = 0; + } + if (ret == 0) + base_keys->len = k; + else + free_HDB_Ext_KeySet(base_keys); + return 0; +} + +/** + * Removes from `e' and outputs all the base keys for virtual principal and/or + * key derivation. + * + * @param context Context + * @param e The HDB entry + * @param is_current_keyset Whether to make the keys the current keys for `e' + * @param ks A pointer to an hdb_keyset containing the keys to set + * + * @return Zero on success, an error code otherwise. + */ +krb5_error_code +hdb_install_keyset(krb5_context context, + hdb_entry *e, + int is_current_keyset, + const hdb_keyset *ks) +{ + krb5_error_code ret = 0; + + if (is_current_keyset) { + if (e->keys.len && + (ret = hdb_add_current_keys_to_history(context, e))) + return ret; + free_Keys(&e->keys); + e->kvno = ks->kvno; + if (ret == 0) + ret = copy_Keys(&ks->keys, &e->keys); + if (ret == 0 && ks->set_time) + ret = hdb_entry_set_pw_change_time(context, e, *ks->set_time); + return ret; + } + return hdb_add_history_keyset(context, e, ks); +} + + +krb5_error_code +hdb_next_enctype2key(krb5_context context, + const hdb_entry *e, + const Keys *keyset, + krb5_enctype enctype, + Key **key) +{ + const Keys *keys = keyset ? keyset : &e->keys; + Key *k; + + for (k = *key ? (*key) + 1 : keys->val; k < keys->val + keys->len; k++) { + if(k->key.keytype == enctype){ + *key = k; + return 0; + } + } + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "No next enctype %d for hdb-entry", + (int)enctype); + return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ +} + +krb5_error_code +hdb_enctype2key(krb5_context context, + const hdb_entry *e, + const Keys *keyset, + krb5_enctype enctype, + Key **key) +{ + *key = NULL; + return hdb_next_enctype2key(context, e, keyset, enctype, key); +} + +void +hdb_free_key(Key *key) +{ + memset_s(key->key.keyvalue.data, + key->key.keyvalue.length, + 0, + key->key.keyvalue.length); + free_Key(key); + free(key); +} + + +krb5_error_code +hdb_lock(int fd, int operation) +{ + int i, code = 0; + + for(i = 0; i < 3; i++){ + code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB); + if(code == 0 || errno != EWOULDBLOCK) + break; + sleep(1); + } + if(code == 0) + return 0; + if(errno == EWOULDBLOCK) + return HDB_ERR_DB_INUSE; + return HDB_ERR_CANT_LOCK_DB; +} + +krb5_error_code +hdb_unlock(int fd) +{ + int code; + code = flock(fd, LOCK_UN); + if(code) + return 4711 /* XXX */; + return 0; +} + +void +hdb_free_entry(krb5_context context, HDB *db, hdb_entry *ent) +{ + Key *k; + size_t i; + + if (db && db->hdb_free_entry_context) + db->hdb_free_entry_context(context, db, ent); + + for(i = 0; i < ent->keys.len; i++) { + k = &ent->keys.val[i]; + + memset_s(k->key.keyvalue.data, + k->key.keyvalue.length, + 0, + k->key.keyvalue.length); + } + free_HDB_entry(ent); +} + +krb5_error_code +hdb_foreach(krb5_context context, + HDB *db, + unsigned flags, + hdb_foreach_func_t func, + void *data) +{ + krb5_error_code ret; + hdb_entry entry; + ret = db->hdb_firstkey(context, db, flags, &entry); + if (ret == 0) + krb5_clear_error_message(context); + while(ret == 0){ + ret = (*func)(context, db, &entry, data); + hdb_free_entry(context, db, &entry); + if(ret == 0) + ret = db->hdb_nextkey(context, db, flags, &entry); + } + if(ret == HDB_ERR_NOENTRY) + ret = 0; + return ret; +} + +krb5_error_code +hdb_check_db_format(krb5_context context, HDB *db) +{ + krb5_data tag; + krb5_data version; + krb5_error_code ret, ret2; + unsigned ver; + int foo; + + ret = db->hdb_lock(context, db, HDB_RLOCK); + if (ret) + return ret; + + tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY; + tag.length = strlen(tag.data); + ret = (*db->hdb__get)(context, db, tag, &version); + ret2 = db->hdb_unlock(context, db); + if(ret) + return ret; + if (ret2) + return ret2; + foo = sscanf(version.data, "%u", &ver); + krb5_data_free (&version); + if (foo != 1) + return HDB_ERR_BADVERSION; + if(ver != HDB_DB_FORMAT) + return HDB_ERR_BADVERSION; + return 0; +} + +krb5_error_code +hdb_init_db(krb5_context context, HDB *db) +{ + krb5_error_code ret, ret2; + krb5_data tag; + krb5_data version; + char ver[32]; + + ret = hdb_check_db_format(context, db); + if(ret != HDB_ERR_NOENTRY) + return ret; + + ret = db->hdb_lock(context, db, HDB_WLOCK); + if (ret) + return ret; + + tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY; + tag.length = strlen(tag.data); + snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT); + version.data = ver; + version.length = strlen(version.data) + 1; /* zero terminated */ + ret = (*db->hdb__put)(context, db, 0, tag, version); + ret2 = db->hdb_unlock(context, db); + if (ret) { + if (ret2) + krb5_clear_error_message(context); + return ret; + } + return ret2; +} + +/* + * `default_dbmethod' is the last resort default. + * + * In hdb_create() we may try all the `methods[]' until one succeeds or all + * fail. + */ +#if defined(HAVE_LMDB) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_mdb_create }; +#elif defined(HAVE_DB3) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db3_create }; +#elif defined(HAVE_DB1) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, 1, 1, "", hdb_db1_create }; +#elif defined(HAVE_NDBM) +static struct hdb_method default_dbmethod = + { HDB_INTERFACE_VERSION, NULL, NULL, 0, 1, "", hdb_ndbm_create }; +#else +static struct hdb_method default_dbmethod = + { 0, NULL, NULL, 0, 0, NULL, NULL}; +#endif + +static int +is_pathish(const char *s) +{ + if (s[0] == '/' || + strncmp(s, "./", sizeof("./") - 1) == 0 || + strncmp(s, "../", sizeof("../") - 1) == 0) + return 1; +#ifdef WIN32 + if (s[0] == '\\' || (isalpha((unsigned char)s[0]) && s[0] == ':') || + strncmp(s, ".\\", sizeof(".\\") - 1) == 0 || + strncmp(s, "\\\\", sizeof("\\\\") - 1) == 0) + return 1; +#endif + return 0; +} + +static const struct hdb_method * +has_method_prefix(const char *filename) +{ + const struct hdb_method *h; + + for (h = methods; h->prefix != NULL; ++h) + if (strncmp(filename, h->prefix, strlen(h->prefix)) == 0) + return h; + return NULL; +} + +/* + * find the relevant method for `filename', returning a pointer to the + * rest in `rest'. + * return NULL if there's no such method. + */ + +static const struct hdb_method * +find_method(const char *filename, const char **rest) +{ + const struct hdb_method *h = has_method_prefix(filename); + + *rest = h ? filename + strlen(h->prefix) : filename; + return h; +} + +struct cb_s { + const char *residual; + const char *filename; + const struct hdb_method *h; +}; + +static krb5_error_code KRB5_LIB_CALL +callback(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + const struct hdb_method *h = (const struct hdb_method *)plug; + struct cb_s *cb_ctx = (struct cb_s *)userctx; + + if (strncmp(cb_ctx->filename, h->prefix, strlen(h->prefix)) == 0) { + cb_ctx->residual = cb_ctx->filename + strlen(h->prefix) + 1; + cb_ctx->h = h; + return 0; + } + return KRB5_PLUGIN_NO_HANDLE; +} + +static char * +make_sym(const char *prefix) +{ + char *s, *sym; + + errno = 0; + if (prefix == NULL || prefix[0] == '\0') + return NULL; + if ((s = strdup(prefix)) == NULL) + return NULL; + if (strchr(s, ':') != NULL) + *strchr(s, ':') = '\0'; + if (asprintf(&sym, "hdb_%s_interface", s) == -1) + sym = NULL; + free(s); + return sym; +} + +static const char *hdb_plugin_deps[] = { "hdb", "krb5", NULL }; + +krb5_error_code +hdb_list_builtin(krb5_context context, char **list) +{ + const struct hdb_method *h; + size_t len = 0; + char *buf = NULL; + + for (h = methods; h->prefix != NULL; ++h) { + if (h->prefix[0] == '\0') + continue; + len += strlen(h->prefix) + 2; + } + + len += 1; + buf = malloc(len); + if (buf == NULL) { + return krb5_enomem(context); + } + buf[0] = '\0'; + + for (h = methods; h->prefix != NULL; ++h) { + if (h->create == NULL) { + struct cb_s cb_ctx; + char *f; + struct heim_plugin_data hdb_plugin_data; + + hdb_plugin_data.module = "krb5"; + hdb_plugin_data.min_version = HDB_INTERFACE_VERSION; + hdb_plugin_data.deps = hdb_plugin_deps; + hdb_plugin_data.get_instance = hdb_get_instance; + + /* Try loading the plugin */ + if (asprintf(&f, "%sfoo", h->prefix) == -1) + f = NULL; + if ((hdb_plugin_data.name = make_sym(h->prefix)) == NULL) { + free(buf); + free(f); + return krb5_enomem(context); + } + cb_ctx.filename = f; + cb_ctx.residual = NULL; + cb_ctx.h = NULL; + (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0, + &cb_ctx, callback); + free(f); + free(rk_UNCONST(hdb_plugin_data.name)); + if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) + continue; + } + if (h != methods) + strlcat(buf, ", ", len); + strlcat(buf, h->prefix, len); + } + *list = buf; + return 0; +} + +krb5_error_code +_hdb_keytab2hdb_entry(krb5_context context, + const krb5_keytab_entry *ktentry, + hdb_entry *entry) +{ + entry->kvno = ktentry->vno; + entry->created_by.time = ktentry->timestamp; + + entry->keys.val = calloc(1, sizeof(entry->keys.val[0])); + if (entry->keys.val == NULL) + return ENOMEM; + entry->keys.len = 1; + + entry->keys.val[0].mkvno = NULL; + entry->keys.val[0].salt = NULL; + + return krb5_copy_keyblock_contents(context, + &ktentry->keyblock, + &entry->keys.val[0].key); +} + +static krb5_error_code +load_config(krb5_context context, HDB *db) +{ + db->enable_virtual_hostbased_princs = + krb5_config_get_bool_default(context, NULL, FALSE, "hdb", + "enable_virtual_hostbased_princs", + NULL); + db->virtual_hostbased_princ_ndots = + krb5_config_get_int_default(context, NULL, 1, "hdb", + "virtual_hostbased_princ_mindots", + NULL); + db->virtual_hostbased_princ_maxdots = + krb5_config_get_int_default(context, NULL, 0, "hdb", + "virtual_hostbased_princ_maxdots", + NULL); + db->new_service_key_delay = + krb5_config_get_time_default(context, NULL, 0, "hdb", + "new_service_key_delay", NULL); + /* + * XXX Needs freeing in the HDB backends because we don't have a + * first-class hdb_close() :( + */ + db->virtual_hostbased_princ_svcs = + krb5_config_get_strings(context, NULL, "hdb", + "virtual_hostbased_princ_svcs", NULL); + /* Check for ENOMEM */ + if (db->virtual_hostbased_princ_svcs == NULL + && krb5_config_get_string(context, NULL, "hdb", + "virtual_hostbased_princ_svcs", NULL)) { + return krb5_enomem(context); + } + return 0; +} + +/** + * Create a handle for a Kerberos database + * + * Create a handle for a Kerberos database backend specified by a + * filename. Doesn't actually create or even open an HDB file(s); + * you have to call the hdb_open() open method of the resulting HDB + * to open the database, and you have to use O_CREAT to create it. + * + * If `filename' does not have a backend type prefix, all file-based + * backends will be tried until one succeeds or all fail, and if the + * HDB exists for some backend, that will be used. A build-time + * default backend type will be used if the `filename' does not exist. + * + * Note that the actual filename may have a suffix added, such as + * ".db". Also, for backends such as "ldap:" and "ldapi:" the + * `filename' is more like a URI. + * + * @param [in] context Context + * @param [out] db HDB handle output + * @param [in] filename The name of the HDB + * + * @return Zero on success else a krb5 error code. + */ + +krb5_error_code +hdb_create(krb5_context context, HDB **db, const char *filename) +{ + krb5_error_code ret = ENOTSUP; + struct cb_s cb_ctx; + + *db = NULL; + if (filename == NULL) + filename = hdb_default_db(context); + + cb_ctx.h = find_method(filename, &cb_ctx.residual); + cb_ctx.filename = filename; + + if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) { + struct heim_plugin_data hdb_plugin_data; + + /* + * `filename' does not start with a known HDB backend prefix. + * + * Try plugins. + */ + hdb_plugin_data.module = "krb5"; + hdb_plugin_data.min_version = HDB_INTERFACE_VERSION; + hdb_plugin_data.deps = hdb_plugin_deps; + hdb_plugin_data.get_instance = hdb_get_instance; + + if ((hdb_plugin_data.name = make_sym(filename)) == NULL) + return krb5_enomem(context); + + (void)_krb5_plugin_run_f(context, &hdb_plugin_data, 0 /* flags */, + &cb_ctx, callback); + + free(rk_UNCONST(hdb_plugin_data.name)); + } + + if (cb_ctx.h == NULL || cb_ctx.h->create == NULL) { + int pathish = is_pathish(filename); + /* + * `filename' does not start with a known HDB backend prefix and it + * wasn't handled by any plugin. + * + * If it's "filename-ish", try all builtin HDB backends that are + * local-file-ish, but use hdb_open() to see if the HDB exists and stop + * when a backend is found for which the HDB exists. + */ + if (!pathish) { + krb5_set_error_message(context, ret = ENOTSUP, + "No database support for %s", + cb_ctx.filename); + return ret; + } + for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) { + if (cb_ctx.h->is_file_based) + continue; + if (!cb_ctx.h->can_taste) + continue; + /* Taste the file */ + ret = (*cb_ctx.h->create)(context, db, filename); + if (ret == 0) + ret = (*db)->hdb_open(context, *db, O_RDONLY, 0); + if (ret == 0) { + (void) (*db)->hdb_close(context, *db); + break; + } + if (*db) + (*db)->hdb_destroy(context, *db); + *db = NULL; + } + if (cb_ctx.h->prefix == NULL) + cb_ctx.h = NULL; + } +#ifdef HDB_DEFAULT_DB_TYPE + if (cb_ctx.h == NULL) { + /* + * If still we've not picked a backend, use a build configuration time + * default. + */ + for (cb_ctx.h = methods; cb_ctx.h->prefix != NULL; cb_ctx.h++) + if (strcmp(cb_ctx.h->prefix, HDB_DEFAULT_DB_TYPE) == 0) + break; + if (cb_ctx.h->prefix == NULL) + cb_ctx.h = NULL; + } +#endif + if (cb_ctx.h == NULL) + /* Last resort default */ + cb_ctx.h = &default_dbmethod; + if (cb_ctx.h->prefix == NULL) { + krb5_set_error_message(context, ENOTSUP, + "Could not determine default DB backend for %s", + filename); + return ENOTSUP; + } + if (!*db) { + ret = (*cb_ctx.h->create)(context, db, cb_ctx.residual); + if (ret == 0) + (*db)->hdb_method_name = cb_ctx.h->prefix; + } + if (ret == 0 && *db) + ret = load_config(context, *db); + if (ret && *db) { + (*db)->hdb_destroy(context, *db); + *db = NULL; + } + return ret; +} + +uintptr_t KRB5_CALLCONV +hdb_get_instance(const char *libname) +{ + static const char *instance = "libhdb"; + + if (strcmp(libname, "hdb") == 0) + return (uintptr_t)instance; + else if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/hdb.h b/third_party/heimdal/lib/hdb/hdb.h new file mode 100644 index 0000000..e5d2371 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.h @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __HDB_H__ +#define __HDB_H__ + +#include + +#include + +#include + +#include +#include +#include + +#define HDB_DB_FORMAT hdb_db_format + +typedef HDB_keyset hdb_keyset; +typedef HDB_entry hdb_entry; +typedef HDB_entry_alias hdb_entry_alias; + +struct hdb_dbinfo; + +enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; + +/* flags for various functions */ +#define HDB_F_DECRYPT 0x00001 /* decrypt keys */ +#define HDB_F_REPLACE 0x00002 /* replace entry */ +#define HDB_F_GET_CLIENT 0x00004 /* fetch client */ +#define HDB_F_GET_SERVER 0x00008 /* fetch server */ +#define HDB_F_GET_KRBTGT 0x00010 /* fetch krbtgt */ +#define HDB_F_GET_ANY ( HDB_F_GET_CLIENT | \ + HDB_F_GET_SERVER | \ + HDB_F_GET_KRBTGT ) /* fetch any of client,server,krbtgt */ +#define HDB_F_CANON 0x00020 /* want canonicalition */ +#define HDB_F_ADMIN_DATA 0x00040 /* want data that kdc don't use */ +#define HDB_F_KVNO_SPECIFIED 0x00080 /* we want a particular KVNO */ +#define HDB_F_LIVE_CLNT_KVNOS 0x00200 /* we want all live keys for pre-auth */ +#define HDB_F_LIVE_SVC_KVNOS 0x00400 /* we want all live keys for tix */ +#define HDB_F_ALL_KVNOS 0x00800 /* we want all the keys, live or not */ +#define HDB_F_FOR_AS_REQ 0x01000 /* fetch is for a AS REQ */ +#define HDB_F_FOR_TGS_REQ 0x02000 /* fetch is for a TGS REQ */ +#define HDB_F_PRECHECK 0x04000 /* check that the operation would succeed */ +#define HDB_F_DELAY_NEW_KEYS 0x08000 /* apply [hdb] new_service_key_delay */ +#define HDB_F_SYNTHETIC_OK 0x10000 /* synthetic principal for PKINIT or GSS preauth OK */ +#define HDB_F_GET_FAST_COOKIE 0x20000 /* fetch the FX-COOKIE key (not a normal principal) */ +#define HDB_F_ARMOR_PRINCIPAL 0x40000 /* fetch is for the client of an armor ticket */ +#define HDB_F_USER2USER_PRINCIPAL 0x80000 /* fetch is for the server of a user2user tgs-req */ + +/* hdb_capability_flags */ +#define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1 +#define HDB_CAP_F_HANDLE_PASSWORDS 2 +#define HDB_CAP_F_PASSWORD_UPDATE_KEYS 4 +#define HDB_CAP_F_SHARED_DIRECTORY 8 + +#define heim_pcontext krb5_context +#define heim_pconfig void * + +typedef struct hdb_request_desc { + HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; +} *hdb_request_t; + +#undef heim_pcontext +#undef heim_pconfig + +/* key usage for master key */ +#define HDB_KU_MKEY 0x484442 + +/* + * Second component of WELLKNOWN namespace principals, the third component is + * the common DNS suffix of the implied virtual hosts. + */ +#define HDB_WK_NAMESPACE "HOSTBASED-NAMESPACE" + +typedef struct hdb_master_key_data *hdb_master_key; + +/** + * HDB backend function pointer structure + * + * The HDB structure is what the KDC and kadmind framework uses to + * query the backend database when talking about principals. + */ + +typedef struct HDB { + void *hdb_db; + void *hdb_dbc; /** don't use, only for DB3 */ + const char *hdb_method_name; + char *hdb_name; + int hdb_master_key_set; + hdb_master_key hdb_master_key; + int hdb_openp; + int hdb_capability_flags; + int lock_count; + int lock_type; + /* + * These fields cache config values. + * + * XXX Move these into a structure that we point to so that we + * don't need to break the ABI every time we add a field. + */ + int enable_virtual_hostbased_princs; + size_t virtual_hostbased_princ_ndots; /* Min. # of .s in hostname */ + size_t virtual_hostbased_princ_maxdots; /* Max. # of .s in namespace */ + char **virtual_hostbased_princ_svcs; /* Which svcs are not wildcarded */ + time_t new_service_key_delay; /* Delay for new keys */ + /** + * Open (or create) the a Kerberos database. + * + * Open (or create) the a Kerberos database that was resolved with + * hdb_create(). The third and fourth flag to the function are the + * same as open(), thus passing O_CREAT will create the data base + * if it doesn't exists. + * + * Then done the caller should call hdb_close(), and to release + * all resources hdb_destroy(). + */ + krb5_error_code (*hdb_open)(krb5_context, struct HDB*, int, mode_t); + /** + * Close the database for transaction + * + * Closes the database for further transactions, wont release any + * permanant resources. the database can be ->hdb_open-ed again. + */ + krb5_error_code (*hdb_close)(krb5_context, struct HDB*); + /** + * Free backend-specific entry context. + */ + void (*hdb_free_entry_context)(krb5_context, struct HDB*, hdb_entry*); + /** + * Fetch an entry from the backend + * + * Fetch an entry from the backend, flags are what type of entry + * should be fetch: client, server, krbtgt. + * knvo (if specified and flags HDB_F_KVNO_SPECIFIED set) is the kvno to get + */ + krb5_error_code (*hdb_fetch_kvno)(krb5_context, struct HDB*, + krb5_const_principal, unsigned, krb5_kvno, + hdb_entry*); + /** + * Store an entry to database + */ + krb5_error_code (*hdb_store)(krb5_context, struct HDB*, + unsigned, hdb_entry*); + /** + * Remove an entry from the database. + */ + krb5_error_code (*hdb_remove)(krb5_context, struct HDB*, + unsigned, krb5_const_principal); + /** + * As part of iteration, fetch one entry + */ + krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*, + unsigned, hdb_entry*); + /** + * As part of iteration, fetch next entry + */ + krb5_error_code (*hdb_nextkey)(krb5_context, struct HDB*, + unsigned, hdb_entry*); + /** + * Lock database + * + * A lock can only be held by one consumers. Transaction can still + * happen on the database while the lock is held, so the entry is + * only useful for syncroning creation of the database and renaming of the database. + */ + krb5_error_code (*hdb_lock)(krb5_context, struct HDB*, int); + /** + * Unlock database + */ + krb5_error_code (*hdb_unlock)(krb5_context, struct HDB*); + /** + * Rename the data base. + * + * Assume that the database is not hdb_open'ed and not locked. + */ + krb5_error_code (*hdb_rename)(krb5_context, struct HDB*, const char*); + /** + * Get an hdb_entry from a classical DB backend + * + * This function takes a principal key (krb5_data) and returns all + * data related to principal in the return krb5_data. The returned + * encoded entry is of type hdb_entry or hdb_entry_alias. + */ + krb5_error_code (*hdb__get)(krb5_context, struct HDB*, + krb5_data, krb5_data*); + /** + * Store an hdb_entry from a classical DB backend + * + * This function takes a principal key (krb5_data) and encoded + * hdb_entry or hdb_entry_alias as the data to store. + * + * For a file-based DB, this must synchronize to disk when done. + * This is sub-optimal for kadm5_s_rename_principal(), and for + * kadm5_s_modify_principal() when using principal aliases; to + * improve this so that only one fsync() need be done + * per-transaction will require HDB API extensions. + */ + krb5_error_code (*hdb__put)(krb5_context, struct HDB*, int, + krb5_data, krb5_data); + /** + * Delete and hdb_entry from a classical DB backend + * + * This function takes a principal key (krb5_data) naming the record + * to delete. + * + * Same discussion as in @ref HDB::hdb__put + */ + krb5_error_code (*hdb__del)(krb5_context, struct HDB*, krb5_data); + /** + * Destroy the handle to the database. + * + * Destroy the handle to the database, deallocate all memory and + * related resources. Does not remove any permanent data. Its the + * logical reverse of hdb_create() function that is the entry + * point for the module. + */ + krb5_error_code (*hdb_destroy)(krb5_context, struct HDB*); + /** + * Get the list of realms this backend handles. + * This call is optional to support. The returned realms are used + * for announcing the realms over bonjour. Free returned array + * with krb5_free_host_realm(). + */ + krb5_error_code (*hdb_get_realms)(krb5_context, struct HDB *, krb5_realm **); + /** + * Change password. + * + * Will update keys for the entry when given password. The new + * keys must be written into the entry and will then later be + * ->hdb_store() into the database. The backend will still perform + * all other operations, increasing the kvno, and update + * modification timestamp. + * + * The backend needs to call _kadm5_set_keys() and perform password + * quality checks. + */ + krb5_error_code (*hdb_password)(krb5_context, struct HDB*, hdb_entry*, const char *, int); + + /** + * Authentication auditing. Note that this function is called by + * both the AS and TGS, but currently only the AS sets the auth + * event type. This may change in a future version. + * + * Event details are available by querying the request using + * heim_audit_getkv(HDB_REQUEST_KV_...). + * + * In case the entry is locked out, the backend should set the + * hdb_entry.flags.locked-out flag. + */ + krb5_error_code (*hdb_audit)(krb5_context, struct HDB *, hdb_entry *, hdb_request_t); + + /** + * Check if delegation is allowed. + */ + krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal); + + /** + * Check if resource-based constrained delegation (RBCD) is allowed. + */ + krb5_error_code (*hdb_check_rbcd)(krb5_context, struct HDB *, const hdb_entry *, const hdb_entry *, const hdb_entry *, const hdb_entry *, krb5_const_principal, krb5_const_pac, krb5_const_pac, const hdb_entry *); + + /** + * Check if this name is an alias for the supplied client for PKINIT userPrinicpalName logins + */ + krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry *, krb5_const_principal); + + /** + * Check if s4u2self is allowed from this client to this server or the SPN is a valid SPN of this client (for user2user) + */ + krb5_error_code (*hdb_check_client_matches_target_service)(krb5_context, struct HDB *, hdb_entry *, hdb_entry *); + + /** + * Enable/disable synchronous updates + * + * Calling this with 0 disables sync. Calling it with non-zero enables + * sync and does an fsync(). + */ + krb5_error_code (*hdb_set_sync)(krb5_context, struct HDB *, int); +}HDB; + +#define HDB_INTERFACE_VERSION 11 + +struct hdb_method { + HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context); + unsigned int is_file_based:1; + unsigned int can_taste:1; + const char *prefix; + krb5_error_code (*create)(krb5_context, HDB **, const char *filename); +}; + +/* dump entry format, for hdb_print_entry() */ +typedef enum hdb_dump_format { + HDB_DUMP_HEIMDAL = 0, + HDB_DUMP_MIT = 1, +} hdb_dump_format_t; + +struct hdb_print_entry_arg { + FILE *out; + hdb_dump_format_t fmt; +}; + +typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*, + hdb_entry*, void*); +extern krb5_kt_ops hdb_kt_ops; +extern krb5_kt_ops hdb_get_kt_ops; + +extern const int hdb_interface_version; + +#include + +#endif /* __HDB_H__ */ diff --git a/third_party/heimdal/lib/hdb/hdb.opt b/third_party/heimdal/lib/hdb/hdb.opt new file mode 100644 index 0000000..a96eb63 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.opt @@ -0,0 +1,9 @@ +--sequence=HDB-extensions +--sequence=HDB-Ext-KeyRotation +--sequence=HDB-Ext-KeySet +--sequence=Keys +--decorate=HDB_entry:void:context?::: +# The `aliased` field is for indicating whether a name used in an HDB +# lookup was an alias. This could be useful to applications when hard +# aliasing is implemented in an HDB backend, as it should be. +--decorate=HDB_entry:int:aliased::: diff --git a/third_party/heimdal/lib/hdb/hdb.schema b/third_party/heimdal/lib/hdb/hdb.schema new file mode 100644 index 0000000..f9fb080 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb.schema @@ -0,0 +1,144 @@ +# Definitions for a Kerberos V KDC schema +# +# $Id$ +# +# This version is compatible with OpenLDAP 1.8 +# +# OID Base is iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) padl(5322) kdcSchema(10) +# +# Syntaxes are under 1.3.6.1.4.1.5322.10.0 +# Attributes types are under 1.3.6.1.4.1.5322.10.1 +# Object classes are under 1.3.6.1.4.1.5322.10.2 + +# Syntax definitions + +#krb5KDCFlagsSyntax SYNTAX ::= { +# WITH SYNTAX INTEGER +#-- initial(0), -- require as-req +#-- forwardable(1), -- may issue forwardable +#-- proxiable(2), -- may issue proxiable +#-- renewable(3), -- may issue renewable +#-- postdate(4), -- may issue postdatable +#-- server(5), -- may be server +#-- client(6), -- may be client +#-- invalid(7), -- entry is invalid +#-- require-preauth(8), -- must use preauth +#-- change-pw(9), -- change password service +#-- require-hwauth(10), -- must use hwauth +#-- ok-as-delegate(11), -- as in TicketFlags +#-- user-to-user(12), -- may use user-to-user auth +#-- immutable(13) -- may not be deleted +# ID { 1.3.6.1.4.1.5322.10.0.1 } +#} + +#krb5PrincipalNameSyntax SYNTAX ::= { +# WITH SYNTAX OCTET STRING +#-- String representations of distinguished names as per RFC1510 +# ID { 1.3.6.1.4.1.5322.10.0.2 } +#} + +# Attribute type definitions + +attributetype ( 1.3.6.1.4.1.5322.10.1.1 + NAME 'krb5PrincipalName' + DESC 'The unparsed Kerberos principal name' + EQUALITY caseExactIA5Match + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.2 + NAME 'krb5KeyVersionNumber' + EQUALITY integerMatch + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.3 + NAME 'krb5MaxLife' + EQUALITY integerMatch + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.4 + NAME 'krb5MaxRenew' + EQUALITY integerMatch + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.5 + NAME 'krb5KDCFlags' + EQUALITY integerMatch + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.6 + NAME 'krb5EncryptionType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.7 + NAME 'krb5ValidStart' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.8 + NAME 'krb5ValidEnd' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.9 + NAME 'krb5PasswordEnd' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE ) + +# this is temporary; keys will eventually +# be child entries or compound attributes. +attributetype ( 1.3.6.1.4.1.5322.10.1.10 + NAME 'krb5Key' + DESC 'Encoded ASN1 Key as an octet string' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.11 + NAME 'krb5PrincipalRealm' + DESC 'Distinguished name of krb5Realm entry' + SUP distinguishedName ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.12 + NAME 'krb5RealmName' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} ) + +attributetype ( 1.3.6.1.4.1.5322.10.1.13 + NAME 'krb5ExtendedAttributes' + DESC 'Encoded ASN1 HDB Extension Attributes as an octet string' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 ) + +# Object class definitions + +objectclass ( 1.3.6.1.4.1.5322.10.2.1 + NAME 'krb5Principal' + SUP top + AUXILIARY + MUST ( krb5PrincipalName ) + MAY ( cn $ krb5PrincipalRealm ) ) + +objectclass ( 1.3.6.1.4.1.5322.10.2.2 + NAME 'krb5KDCEntry' + SUP krb5Principal + AUXILIARY + MUST ( krb5KeyVersionNumber ) + MAY ( krb5ValidStart $ krb5ValidEnd $ krb5PasswordEnd $ + krb5MaxLife $ krb5MaxRenew $ krb5KDCFlags $ + krb5EncryptionType $ krb5Key $ krb5ExtendedAttributes ) ) + +objectclass ( 1.3.6.1.4.1.5322.10.2.3 + NAME 'krb5Realm' + SUP top + AUXILIARY + MUST ( krb5RealmName ) ) + diff --git a/third_party/heimdal/lib/hdb/hdb_err.et b/third_party/heimdal/lib/hdb/hdb_err.et new file mode 100644 index 0000000..6a79ffa --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb_err.et @@ -0,0 +1,33 @@ +# +# Error messages for the hdb library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table hdb + +prefix HDB_ERR + +index 1 +#error_code INUSE, "Entry already exists in database" +error_code UK_SERROR, "Database store error" +error_code UK_RERROR, "Database read error" +error_code NOENTRY, "No such entry in the database" +error_code DB_INUSE, "Database is locked or in use--try again later" +error_code DB_CHANGED, "Database was modified during read" +error_code RECURSIVELOCK, "Attempt to lock database twice" +error_code NOTLOCKED, "Attempt to unlock database when not locked" +error_code BADLOCKMODE, "Invalid kdb lock mode" +error_code CANT_LOCK_DB, "Insufficient access to lock database" +error_code EXISTS, "Entry already exists in database" +error_code BADVERSION, "Wrong database version" +error_code NO_MKEY, "No correct master key" +error_code MANDATORY_OPTION, "Entry contains unknown mandatory extension" +error_code NO_WRITE_SUPPORT, "HDB backend doesn't contain write support" +error_code NOT_FOUND_HERE, "The secret for this entry is not replicated to this database" +error_code MISUSE, "Incorrect use of the API" +error_code KVNO_NOT_FOUND, "Entry key version number not found" +error_code WRONG_REALM, "The principal exists in another realm." + +end diff --git a/third_party/heimdal/lib/hdb/hdb_locl.h b/third_party/heimdal/lib/hdb/hdb_locl.h new file mode 100644 index 0000000..fd7b184 --- /dev/null +++ b/third_party/heimdal/lib/hdb/hdb_locl.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997-2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __HDB_LOCL_H__ +#define __HDB_LOCL_H__ + +#include + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#include + +#include "crypto-headers.h" +#include +#include +#include + +#define HDB_DEFAULT_DB HDB_DB_DIR "/heimdal" +#define HDB_DB_FORMAT_ENTRY "hdb/db-format" + +#endif /* __HDB_LOCL_H__ */ diff --git a/third_party/heimdal/lib/hdb/keys.c b/third_party/heimdal/lib/hdb/keys.c new file mode 100644 index 0000000..457e5da --- /dev/null +++ b/third_party/heimdal/lib/hdb/keys.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 1997 - 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include "hdb_locl.h" + +#include +#include + +/* + * free all the memory used by (len, keys) + */ + +void +hdb_free_keys(krb5_context context, int len, Key *keys) +{ + size_t i; + + for (i = 0; i < len; i++) { + free(keys[i].mkvno); + keys[i].mkvno = NULL; + if (keys[i].salt != NULL) { + free_Salt(keys[i].salt); + free(keys[i].salt); + keys[i].salt = NULL; + } + krb5_free_keyblock_contents(context, &keys[i].key); + } + free (keys); +} + +/* + * for each entry in `default_keys' try to parse it as a sequence + * of etype:salttype:salt, syntax of this if something like: + * [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it + * means all etypes, and if string is omitted is means the default + * string (for that principal). Additional special values: + * v5 == pw-salt, and + * v4 == des:pw-salt: + * afs or afs3 == des:afs3-salt + */ + +static const krb5_enctype des_etypes[] = { + KRB5_ENCTYPE_DES_CBC_MD5, + KRB5_ENCTYPE_DES_CBC_MD4, + KRB5_ENCTYPE_DES_CBC_CRC +}; + +static const krb5_enctype all_etypes[] = { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + KRB5_ENCTYPE_DES3_CBC_SHA1, + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 +}; + +static krb5_error_code +parse_key_set(krb5_context context, const char *key, + krb5_enctype **ret_enctypes, size_t *ret_num_enctypes, + krb5_salt *salt, krb5_principal principal) +{ + const char *p; + char buf[3][256]; + int num_buf = 0; + int i, num_enctypes = 0; + krb5_enctype e; + const krb5_enctype *enctypes = NULL; + krb5_error_code ret; + + p = key; + + *ret_enctypes = NULL; + *ret_num_enctypes = 0; + + /* split p in a list of :-separated strings */ + for(num_buf = 0; num_buf < 3; num_buf++) + if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1) + break; + + salt->saltvalue.data = NULL; + salt->saltvalue.length = 0; + + for(i = 0; i < num_buf; i++) { + if(enctypes == NULL && num_buf > 1) { + /* this might be a etype specifier */ + /* XXX there should be a string_to_etypes handling + special cases like `des' and `all' */ + if(strcmp(buf[i], "des") == 0) { + enctypes = des_etypes; + num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]); + } else if(strcmp(buf[i], "des3") == 0) { + e = KRB5_ENCTYPE_DES3_CBC_SHA1; + enctypes = &e; + num_enctypes = 1; + } else { + ret = krb5_string_to_enctype(context, buf[i], &e); + if (ret == 0) { + enctypes = &e; + num_enctypes = 1; + } else + return ret; + } + continue; + } + if(salt->salttype == 0) { + /* interpret string as a salt specifier, if no etype + is set, this sets default values */ + /* XXX should perhaps use string_to_salttype, but that + interface sucks */ + if(strcmp(buf[i], "pw-salt") == 0) { + if(enctypes == NULL) { + enctypes = all_etypes; + num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]); + } + salt->salttype = KRB5_PW_SALT; + } else if(strcmp(buf[i], "afs3-salt") == 0) { + if(enctypes == NULL) { + enctypes = des_etypes; + num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]); + } + salt->salttype = KRB5_AFS3_SALT; + } + continue; + } + + if (salt->saltvalue.data != NULL) + free(salt->saltvalue.data); + /* if there is a final string, use it as the string to + salt with, this is mostly useful with null salt for + v4 compat, and a cell name for afs compat */ + salt->saltvalue.data = strdup(buf[i]); + if (salt->saltvalue.data == NULL) + return krb5_enomem(context); + salt->saltvalue.length = strlen(buf[i]); + } + + if(enctypes == NULL || salt->salttype == 0) { + krb5_free_salt(context, *salt); + krb5_set_error_message(context, EINVAL, "bad value for default_keys `%s'", key); + return EINVAL; + } + + /* if no salt was specified make up default salt */ + if(salt->saltvalue.data == NULL) { + if(salt->salttype == KRB5_PW_SALT) { + ret = krb5_get_pw_salt(context, principal, salt); + if (ret) + return ret; + } else if(salt->salttype == KRB5_AFS3_SALT) { + krb5_const_realm realm = krb5_principal_get_realm(context, principal); + salt->saltvalue.data = strdup(realm); + if(salt->saltvalue.data == NULL) { + krb5_set_error_message(context, ENOMEM, + "out of memory while " + "parsing salt specifiers"); + return ENOMEM; + } + strlwr(salt->saltvalue.data); + salt->saltvalue.length = strlen(realm); + } + } + + *ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes); + if (*ret_enctypes == NULL) { + krb5_free_salt(context, *salt); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes); + *ret_num_enctypes = num_enctypes; + + return 0; +} + +/** + * This function prunes an HDB entry's historic keys by kvno. + * + * @param context Context + * @param entry HDB entry + * @param kvno Keyset kvno to prune, or zero to prune all too-old keys + */ +krb5_error_code +hdb_prune_keys_kvno(krb5_context context, hdb_entry *entry, int kvno) +{ + HDB_extension *ext; + HDB_Ext_KeySet *keys; + hdb_keyset *elem; + time_t keep_time = 0; + size_t nelem; + size_t i; + + /* + * XXX Pruning old keys for namespace principals may not be desirable, but! + * as long as the `set_time's of the base keys for a namespace principal + * match the `epoch's of the corresponding KeyRotation periods, it will be + * perfectly acceptable to prune old [base] keys for namespace principals + * just as for any other principal. Therefore, we may not need to make any + * changes here w.r.t. namespace principals. + */ + + ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (ext == NULL) + return 0; + keys = &ext->data.u.hist_keys; + nelem = keys->len; + + /* + * Optionally drop key history for keys older than now - max_life, which is + * all the keys no longer needed to decrypt extant tickets. + */ + if (kvno == 0 && entry->max_life != NULL && nelem > 0) { + time_t ceiling = time(NULL) - *entry->max_life; + + /* + * Compute most recent key timestamp that predates the current time + * by at least the entry's maximum ticket lifetime. + */ + for (i = 0; i < nelem; ++i) { + elem = &keys->val[i]; + if (elem->set_time && *elem->set_time < ceiling + && (keep_time == 0 || *elem->set_time > keep_time)) + keep_time = *elem->set_time; + } + } + + if (kvno == 0 && keep_time == 0) + return 0; + + for (i = 0; i < nelem; /* see below */) { + elem = &keys->val[i]; + if ((kvno && kvno == elem->kvno) || + (keep_time && elem->set_time && *elem->set_time < keep_time)) { + remove_HDB_Ext_KeySet(keys, i); + /* + * Removing the i'th element shifts the tail down, continue + * at same index with reduced upper bound. + */ + --nelem; + continue; + } + ++i; + } + + return 0; +} + +/** + * This function prunes an HDB entry's keys that are too old to have been used + * to mint still valid tickets (based on the entry's maximum ticket lifetime). + * + * @param context Context + * @param entry HDB entry + */ +krb5_error_code +hdb_prune_keys(krb5_context context, hdb_entry *entry) +{ + if (!krb5_config_get_bool_default(context, NULL, FALSE, + "kadmin", "prune-key-history", NULL)) + return 0; + return hdb_prune_keys_kvno(context, entry, 0); +} + +/** + * This function adds a keyset to an HDB entry's key history. + * + * @param context Context + * @param entry HDB entry + * @param kvno Key version number of the key to add to the history + * @param key The Key to add + */ +krb5_error_code +hdb_add_history_keyset(krb5_context context, + hdb_entry *entry, + const hdb_keyset *ks) +{ + size_t i; + HDB_Ext_KeySet *hist_keys; + HDB_extension ext; + HDB_extension *extp; + krb5_error_code ret = 0; + + memset(&ext, 0, sizeof (ext)); + + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) { + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_keys; + ext.data.u.hist_keys.len = 0; + ext.data.u.hist_keys.val = 0; + extp = &ext; + } + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == ks->kvno) { + /* Replace existing */ + free_HDB_keyset(&hist_keys->val[i]); + ret = copy_HDB_keyset(ks, &hist_keys->val[i]); + break; + } + } + if (i >= hist_keys->len) + ret = add_HDB_Ext_KeySet(hist_keys, ks); /* Append new */ + if (ret == 0 && extp == &ext) + ret = hdb_replace_extension(context, entry, &ext); + free_HDB_extension(&ext); + return ret; +} + +/** + * This function adds an HDB entry's current keyset to the entry's key + * history. The current keyset is left alone; the caller is responsible + * for freeing it. + * + * @param context Context + * @param entry HDB entry + * + * @return Zero on success, or an error code otherwise. + */ +krb5_error_code +hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry) +{ + krb5_error_code ret; + hdb_keyset ks; + time_t newtime; + + if (entry->keys.len == 0) + return 0; /* nothing to do */ + + ret = hdb_entry_get_pw_change_time(entry, &newtime); + if (ret) + return ret; + + ks.keys = entry->keys; + ks.kvno = entry->kvno; + ks.set_time = &newtime; + + ret = hdb_add_history_keyset(context, entry, &ks); + if (ret == 0) + ret = hdb_prune_keys(context, entry); + return ret; +} + +/** + * This function adds a key to an HDB entry's key history. + * + * @param context Context + * @param entry HDB entry + * @param kvno Key version number of the key to add to the history + * @param key The Key to add + * + * @return Zero on success, or an error code otherwise. + */ +krb5_error_code +hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key) +{ + size_t i; + hdb_keyset keyset; + HDB_Ext_KeySet *hist_keys; + HDB_extension ext; + HDB_extension *extp; + krb5_error_code ret; + + memset(&keyset, 0, sizeof (keyset)); + memset(&ext, 0, sizeof (ext)); + + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) { + ext.data.element = choice_HDB_extension_data_hist_keys; + extp = &ext; + } + + extp->mandatory = FALSE; + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == kvno) { + ret = add_Keys(&hist_keys->val[i].keys, key); + goto out; + } + } + + keyset.kvno = kvno; + ret = add_Keys(&keyset.keys, key); + if (ret) + goto out; + ret = add_HDB_Ext_KeySet(hist_keys, &keyset); + if (ret) + goto out; + if (extp == &ext) { + ret = hdb_replace_extension(context, entry, &ext); + if (ret) + goto out; + } + +out: + free_HDB_keyset(&keyset); + free_HDB_extension(&ext); + return ret; +} + +/** + * This function changes an hdb_entry's kvno, swapping the current key + * set with a historical keyset. If no historical keys are found then + * an error is returned (the caller can still set entry->kvno directly). + * + * @param context krb5_context + * @param new_kvno New kvno for the entry + * @param entry hdb_entry to modify + */ +krb5_error_code +hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry) +{ + HDB_extension ext; + HDB_extension *extp; + hdb_keyset keyset; + HDB_Ext_KeySet *hist_keys; + size_t i; + int found = 0; + krb5_error_code ret; + + if (entry->kvno == new_kvno) + return 0; + + extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (extp == NULL) { + memset(&ext, 0, sizeof (ext)); + ext.data.element = choice_HDB_extension_data_hist_keys; + extp = &ext; + } + + memset(&keyset, 0, sizeof (keyset)); + hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < hist_keys->len; i++) { + if (hist_keys->val[i].kvno == new_kvno) { + found = 1; + ret = copy_HDB_keyset(&hist_keys->val[i], &keyset); + if (ret) + goto out; + ret = remove_HDB_Ext_KeySet(hist_keys, i); + if (ret) + goto out; + break; + } + } + + if (!found) + return HDB_ERR_KVNO_NOT_FOUND; + + ret = hdb_add_current_keys_to_history(context, entry); + if (ret) + goto out; + + /* Note: we do nothing with keyset.set_time */ + entry->kvno = new_kvno; + entry->keys = keyset.keys; /* shortcut */ + memset(&keyset.keys, 0, sizeof (keyset.keys)); + +out: + free_HDB_keyset(&keyset); + return ret; +} + + +static krb5_error_code +add_enctype_to_key_set(Key **key_set, size_t *nkeyset, + krb5_enctype enctype, krb5_salt *salt) +{ + krb5_error_code ret; + Key key, *tmp; + + memset(&key, 0, sizeof(key)); + + tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0])); + if (tmp == NULL) + return ENOMEM; + + *key_set = tmp; + + key.key.keytype = enctype; + key.key.keyvalue.length = 0; + key.key.keyvalue.data = NULL; + + if (salt) { + key.salt = calloc(1, sizeof(*key.salt)); + if (key.salt == NULL) { + free_Key(&key); + return ENOMEM; + } + + key.salt->type = salt->salttype; + krb5_data_zero (&key.salt->salt); + + ret = krb5_data_copy(&key.salt->salt, + salt->saltvalue.data, + salt->saltvalue.length); + if (ret) { + free_Key(&key); + return ret; + } + } else + key.salt = NULL; + + (*key_set)[*nkeyset] = key; + + *nkeyset += 1; + + return 0; +} + + +static +krb5_error_code +ks_tuple2str(krb5_context context, int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, char ***ks_tuple_strs) +{ + size_t i; + char **ksnames; + krb5_error_code rc = KRB5_PROG_ETYPE_NOSUPP; + + *ks_tuple_strs = NULL; + if (n_ks_tuple < 1) + return 0; + + if ((ksnames = calloc(n_ks_tuple + 1, sizeof (*ksnames))) == NULL) + return (errno); + + for (i = 0; i < n_ks_tuple; i++) { + char *ename, *sname; + + if (krb5_enctype_to_string(context, ks_tuple[i].ks_enctype, &ename)) + goto out; + if (krb5_salttype_to_string(context, ks_tuple[i].ks_enctype, + ks_tuple[i].ks_salttype, &sname)) { + free(ename); + goto out; + } + + if (asprintf(&ksnames[i], "%s:%s", ename, sname) == -1) { + rc = errno; + free(ename); + free(sname); + goto out; + } + free(ename); + free(sname); + } + + ksnames[i] = NULL; + *ks_tuple_strs = ksnames; + return 0; + +out: + for (i = 0; i < n_ks_tuple; i++) + free(ksnames[i]); + free(ksnames); + return (rc); +} + +/* + * + */ + +static char ** +glob_rules_keys(krb5_context context, krb5_const_principal principal) +{ + const krb5_config_binding *list; + krb5_principal pattern; + krb5_error_code ret; + + list = krb5_config_get_list(context, NULL, "kadmin", + "default_key_rules", NULL); + if (list == NULL) + return NULL; + + while (list) { + if (list->type == krb5_config_string) { + ret = krb5_parse_name(context, list->name, &pattern); + if (ret == 0) { + ret = krb5_principal_match(context, principal, pattern); + krb5_free_principal(context, pattern); + if (ret) { + return krb5_config_get_strings(context, list, + list->name, NULL); + } + } + } + list = list->next; + } + return NULL; +} + +/* + * NIST guidance in Section 5.1 of [SP800-132] requires that a portion + * of the salt of at least 128 bits shall be randomly generated. + */ +static krb5_error_code +add_random_to_salt(krb5_context context, krb5_salt *in, krb5_salt *out) +{ + krb5_error_code ret; + char *p; + unsigned char random[16]; + char *s; + int slen; + + krb5_generate_random_block(random, sizeof(random)); + + slen = rk_base64_encode(random, sizeof(random), &s); + if (slen < 0) + return ENOMEM; + + ret = krb5_data_alloc(&out->saltvalue, slen + in->saltvalue.length); + if (ret) { + free(s); + return ret; + } + + p = out->saltvalue.data; + memcpy(p, s, slen); + memcpy(&p[slen], in->saltvalue.data, in->saltvalue.length); + + out->salttype = in->salttype; + free(s); + + return 0; +} + +/* + * Generate the `key_set' from the [kadmin]default_keys statement. If + * `no_salt' is set, salt is not important (and will not be set) since + * it's random keys that is going to be created. + */ + +krb5_error_code +hdb_generate_key_set(krb5_context context, krb5_principal principal, + krb5_key_salt_tuple *ks_tuple, int n_ks_tuple, + Key **ret_key_set, size_t *nkeyset, int no_salt) +{ + char **ktypes = NULL; + char **kp; + krb5_error_code ret; + Key *k, *key_set; + size_t i, j; + char **ks_tuple_strs; + char **config_ktypes = NULL; + static const char *default_keytypes[] = { + "aes256-cts-hmac-sha1-96:pw-salt", + "des3-cbc-sha1:pw-salt", + "arcfour-hmac-md5:pw-salt", + NULL + }; + + if ((ret = ks_tuple2str(context, n_ks_tuple, ks_tuple, &ks_tuple_strs))) + return ret; + + ktypes = ks_tuple_strs; + if (ktypes == NULL) { + config_ktypes = glob_rules_keys(context, principal); + ktypes = config_ktypes; + } + if (ktypes == NULL) { + config_ktypes = krb5_config_get_strings(context, NULL, "kadmin", + "default_keys", NULL); + ktypes = config_ktypes; + } + if (ktypes == NULL) + ktypes = (char **)(intptr_t)default_keytypes; + + *ret_key_set = key_set = NULL; + *nkeyset = 0; + + for(kp = ktypes; kp && *kp; kp++) { + const char *p; + krb5_salt salt; + krb5_enctype *enctypes; + size_t num_enctypes; + + p = *kp; + /* check alias */ + if(strcmp(p, "v5") == 0) + p = "pw-salt"; + else if(strcmp(p, "v4") == 0) + p = "des:pw-salt:"; + else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0) + p = "des:afs3-salt"; + else if (strcmp(p, "arcfour-hmac-md5") == 0) + p = "arcfour-hmac-md5:pw-salt"; + + memset(&salt, 0, sizeof(salt)); + + ret = parse_key_set(context, p, + &enctypes, &num_enctypes, &salt, principal); + if (ret) { + krb5_warn(context, ret, "bad value for default_keys `%s'", *kp); + ret = 0; + krb5_free_salt(context, salt); + continue; + } + + for (i = 0; i < num_enctypes; i++) { + krb5_salt *saltp = no_salt ? NULL : &salt; + krb5_salt rsalt; + + /* find duplicates */ + for (j = 0; j < *nkeyset; j++) { + + k = &key_set[j]; + + if (k->key.keytype == enctypes[i]) { + if (no_salt) + break; + if (k->salt == NULL && salt.salttype == KRB5_PW_SALT) + break; + if (k->salt->type == salt.salttype && + k->salt->salt.length == salt.saltvalue.length && + memcmp(k->salt->salt.data, salt.saltvalue.data, + salt.saltvalue.length) == 0) + break; + } + } + /* not a duplicate, lets add it */ + if (j < *nkeyset) + continue; + + memset(&rsalt, 0, sizeof(rsalt)); + + /* prepend salt with randomness if required */ + if (!no_salt && + _krb5_enctype_requires_random_salt(context, enctypes[i])) { + saltp = &rsalt; + ret = add_random_to_salt(context, &salt, &rsalt); + } + + if (ret == 0) + ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], + saltp); + krb5_free_salt(context, rsalt); + + if (ret) { + free(enctypes); + krb5_free_salt(context, salt); + goto out; + } + } + free(enctypes); + krb5_free_salt(context, salt); + } + + *ret_key_set = key_set; + + out: + if (config_ktypes != NULL) + krb5_config_free_strings(config_ktypes); + + for(kp = ks_tuple_strs; kp && *kp; kp++) + free(*kp); + free(ks_tuple_strs); + + if (ret) { + krb5_warn(context, ret, + "failed to parse the [kadmin]default_keys values"); + + for (i = 0; i < *nkeyset; i++) + free_Key(&key_set[i]); + free(key_set); + } else if (*nkeyset == 0) { + krb5_warnx(context, + "failed to parse any of the [kadmin]default_keys values"); + ret = EINVAL; /* XXX */ + } + + return ret; +} + + +krb5_error_code +hdb_generate_key_set_password_with_ks_tuple(krb5_context context, + krb5_principal principal, + const char *password, + krb5_key_salt_tuple *ks_tuple, + int n_ks_tuple, + Key **keys, size_t *num_keys) +{ + krb5_error_code ret; + size_t i; + + ret = hdb_generate_key_set(context, principal, ks_tuple, n_ks_tuple, + keys, num_keys, 0); + if (ret) + return ret; + + for (i = 0; i < (*num_keys); i++) { + krb5_salt salt; + Key *key = &(*keys)[i]; + + salt.salttype = key->salt->type; + salt.saltvalue.length = key->salt->salt.length; + salt.saltvalue.data = key->salt->salt.data; + + ret = krb5_string_to_key_salt (context, + key->key.keytype, + password, + salt, + &key->key); + if(ret) + break; + } + + if(ret) { + hdb_free_keys (context, *num_keys, *keys); + return ret; + } + return ret; +} + + +krb5_error_code +hdb_generate_key_set_password(krb5_context context, + krb5_principal principal, + const char *password, + Key **keys, size_t *num_keys) +{ + + return hdb_generate_key_set_password_with_ks_tuple(context, principal, + password, NULL, 0, + keys, num_keys); +} diff --git a/third_party/heimdal/lib/hdb/keytab.c b/third_party/heimdal/lib/hdb/keytab.c new file mode 100644 index 0000000..df16cb7 --- /dev/null +++ b/third_party/heimdal/lib/hdb/keytab.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +/* keytab backend for HDB databases */ + +struct hdb_data { + char *dbname; + char *mkey; +}; + +struct hdb_cursor { + HDB *db; + hdb_entry hdb_entry; + int first, next; + int key_idx; +}; + +/* + * the format for HDB keytabs is: + * HDB:[HDBFORMAT:database-specific-data[:mkey=mkey-file]] + */ + +static krb5_error_code KRB5_CALLCONV +hdb_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct hdb_data *d; + const char *db, *mkey; + + d = malloc(sizeof(*d)); + if(d == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + db = name; + mkey = strstr(name, ":mkey="); + if(mkey == NULL || mkey[6] == '\0') { + if(*name == '\0') + d->dbname = NULL; + else { + d->dbname = strdup(name); + if(d->dbname == NULL) { + free(d); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + } + d->mkey = NULL; + } else { + d->dbname = malloc(mkey - db + 1); + if(d->dbname == NULL) { + free(d); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + memmove(d->dbname, db, mkey - db); + d->dbname[mkey - db] = '\0'; + + d->mkey = strdup(mkey + 6); + if(d->mkey == NULL) { + free(d->dbname); + free(d); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + } + id->data = d; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +hdb_close(krb5_context context, krb5_keytab id) +{ + struct hdb_data *d = id->data; + + free(d->dbname); + free(d->mkey); + free(d); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +hdb_get_name(krb5_context context, + krb5_keytab id, + char *name, + size_t namesize) +{ + struct hdb_data *d = id->data; + + snprintf(name, namesize, "%s%s%s", + d->dbname ? d->dbname : "", + (d->dbname || d->mkey) ? ":" : "", + d->mkey ? d->mkey : ""); + return 0; +} + +/* + * try to figure out the database (`dbname') and master-key (`mkey') + * that should be used for `principal'. + */ + +static krb5_error_code +find_db (krb5_context context, + char **dbname, + char **mkey, + krb5_const_principal principal) +{ + krb5_const_realm realm = krb5_principal_get_realm(context, principal); + krb5_error_code ret; + struct hdb_dbinfo *head, *dbinfo = NULL; + + *dbname = *mkey = NULL; + + ret = hdb_get_dbinfo(context, &head); + if (ret) + return ret; + + while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) { + const char *p = hdb_dbinfo_get_realm(context, dbinfo); + if (p && strcmp (realm, p) == 0) { + p = hdb_dbinfo_get_dbname(context, dbinfo); + if (p) + *dbname = strdup(p); + p = hdb_dbinfo_get_mkey_file(context, dbinfo); + if (p) + *mkey = strdup(p); + break; + } + } + hdb_free_dbinfo(context, &head); + if (*dbname == NULL && + (*dbname = strdup(hdb_default_db(context))) == NULL) { + free(*mkey); + *mkey = NULL; + return krb5_enomem(context); + } + return 0; +} + +/* + * find the keytab entry in `id' for `principal, kvno, enctype' and return + * it in `entry'. return 0 or an error code + */ + +static krb5_error_code KRB5_CALLCONV +hdb_get_entry(krb5_context context, + krb5_keytab id, + krb5_const_principal principal, + krb5_kvno kvno, + krb5_enctype enctype, + krb5_keytab_entry *entry) +{ + hdb_entry ent; + krb5_error_code ret; + struct hdb_data *d = id->data; + const char *dbname = d->dbname; + const char *mkey = d->mkey; + char *fdbname = NULL, *fmkey = NULL; + HDB *db; + size_t i; + + if (!principal) + return KRB5_KT_NOTFOUND; + + memset(&ent, 0, sizeof(ent)); + + if (dbname == NULL) { + ret = find_db(context, &fdbname, &fmkey, principal); + if (ret) + return ret; + dbname = fdbname; + mkey = fmkey; + } + + ret = hdb_create (context, &db, dbname); + if (ret) + goto out2; + ret = hdb_set_master_keyfile (context, db, mkey); + if (ret) { + (*db->hdb_destroy)(context, db); + goto out2; + } + + ret = (*db->hdb_open)(context, db, O_RDONLY, 0); + if (ret) { + (*db->hdb_destroy)(context, db); + goto out2; + } + + ret = hdb_fetch_kvno(context, db, principal, + HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED| + HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, + 0, 0, kvno, &ent); + + if (ret == HDB_ERR_WRONG_REALM || ret == HDB_ERR_NOENTRY) + ret = KRB5_KT_NOTFOUND; + if (ret) + goto out; + + if(kvno && (krb5_kvno)ent.kvno != kvno) { + hdb_free_entry(context, db, &ent); + ret = KRB5_KT_NOTFOUND; + goto out; + } + if(enctype == 0) + if(ent.keys.len > 0) + enctype = ent.keys.val[0].key.keytype; + ret = KRB5_KT_NOTFOUND; + for(i = 0; i < ent.keys.len; i++) { + if(ent.keys.val[i].key.keytype == enctype) { + krb5_copy_principal(context, principal, &entry->principal); + entry->vno = ent.kvno; + krb5_copy_keyblock_contents(context, + &ent.keys.val[i].key, + &entry->keyblock); + ret = 0; + break; + } + } + hdb_free_entry(context, db, &ent); + out: + (*db->hdb_close)(context, db); + (*db->hdb_destroy)(context, db); + out2: + free(fdbname); + free(fmkey); + return ret; +} + +/* + * find the keytab entry in `id' for `principal, kvno, enctype' and return + * it in `entry'. return 0 or an error code + */ + +static krb5_error_code KRB5_CALLCONV +hdb_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + krb5_error_code ret; + struct hdb_cursor *c; + struct hdb_data *d = id->data; + const char *dbname = d->dbname; + const char *mkey = d->mkey; + HDB *db; + + if (dbname == NULL) { + /* + * We don't support enumerating without being told what + * backend to enumerate on + */ + ret = KRB5_KT_NOTFOUND; + return ret; + } + + ret = hdb_create (context, &db, dbname); + if (ret) + return ret; + ret = hdb_set_master_keyfile (context, db, mkey); + if (ret) { + (*db->hdb_destroy)(context, db); + return ret; + } + + ret = (*db->hdb_open)(context, db, O_RDONLY, 0); + if (ret) { + (*db->hdb_destroy)(context, db); + return ret; + } + + cursor->data = c = malloc (sizeof(*c)); + if(c == NULL){ + (*db->hdb_close)(context, db); + (*db->hdb_destroy)(context, db); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + c->db = db; + c->first = TRUE; + c->next = TRUE; + c->key_idx = 0; + + cursor->data = c; + return ret; +} + +static int KRB5_CALLCONV +hdb_next_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor) +{ + struct hdb_cursor *c = cursor->data; + krb5_error_code ret; + + memset(entry, 0, sizeof(*entry)); + + if (c->first) { + c->first = FALSE; + ret = (c->db->hdb_firstkey)(context, c->db, + HDB_F_DECRYPT| + HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, + &c->hdb_entry); + if (ret == HDB_ERR_NOENTRY) + return KRB5_KT_END; + else if (ret) + return ret; + + if (c->hdb_entry.keys.len == 0) + hdb_free_entry(context, c->db, &c->hdb_entry); + else + c->next = FALSE; + } + + while (c->next) { + ret = (c->db->hdb_nextkey)(context, c->db, + HDB_F_DECRYPT| + HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, + &c->hdb_entry); + if (ret == HDB_ERR_NOENTRY) + return KRB5_KT_END; + else if (ret) + return ret; + + /* If no keys on this entry, try again */ + if (c->hdb_entry.keys.len == 0) + hdb_free_entry(context, c->db, &c->hdb_entry); + else + c->next = FALSE; + } + + /* + * Return next enc type (keytabs are one slot per key, while + * hdb is one record per principal. + */ + + ret = krb5_copy_principal(context, + c->hdb_entry.principal, + &entry->principal); + if (ret) + return ret; + + entry->vno = c->hdb_entry.kvno; + ret = krb5_copy_keyblock_contents(context, + &c->hdb_entry.keys.val[c->key_idx].key, + &entry->keyblock); + if (ret) { + krb5_free_principal(context, entry->principal); + memset(entry, 0, sizeof(*entry)); + return ret; + } + c->key_idx++; + + /* + * Once we get to the end of the list, signal that we want the + * next entry + */ + + if ((size_t)c->key_idx == c->hdb_entry.keys.len) { + hdb_free_entry(context, c->db, &c->hdb_entry); + c->next = TRUE; + c->key_idx = 0; + } + + return 0; +} + + +static int KRB5_CALLCONV +hdb_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + struct hdb_cursor *c = cursor->data; + + if (!c->next) + hdb_free_entry(context, c->db, &c->hdb_entry); + + (c->db->hdb_close)(context, c->db); + (c->db->hdb_destroy)(context, c->db); + + free(c); + return 0; +} + +krb5_kt_ops hdb_kt_ops = { + "HDB", + hdb_resolve, + hdb_get_name, + hdb_close, + NULL, /* destroy */ + hdb_get_entry, + hdb_start_seq_get, + hdb_next_entry, + hdb_end_seq_get, + NULL, /* add */ + NULL, /* remove */ + NULL, + 0 +}; + +krb5_kt_ops hdb_get_kt_ops = { + "HDBGET", + hdb_resolve, + hdb_get_name, + hdb_close, + NULL, + hdb_get_entry, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 +}; diff --git a/third_party/heimdal/lib/hdb/libhdb-exports.def b/third_party/heimdal/lib/hdb/libhdb-exports.def new file mode 100644 index 0000000..72a7fb7 --- /dev/null +++ b/third_party/heimdal/lib/hdb/libhdb-exports.def @@ -0,0 +1,180 @@ +EXPORTS + encode_HDB_keyset + _hdb_fetch_kvno + _hdb_remove + _hdb_store + hdb_add_current_keys_to_history + hdb_add_history_key + hdb_add_history_keyset + hdb_add_master_key + hdb_change_kvno + hdb_check_db_format + hdb_clear_extension + hdb_clear_master_key + hdb_create + hdb_db_dir + hdb_dbinfo_get_acl_file + hdb_dbinfo_get_binding + hdb_dbinfo_get_dbname + hdb_dbinfo_get_label + hdb_dbinfo_get_log_file + hdb_dbinfo_get_mkey_file + hdb_dbinfo_get_next + hdb_dbinfo_get_realm + hdb_derive_etypes + hdb_default_db + hdb_enctype2key + hdb_entry2string + hdb_entry2value + hdb_entry_add_key_rotation + hdb_entry_alias2value + hdb_entry_check_mandatory + hdb_entry_clear_password + hdb_entry_get_ConstrainedDelegACL + hdb_entry_get_aliases + hdb_entry_get_key_rotation + hdb_entry_get_krb5_config + hdb_entry_get_password + hdb_entry_get_pkinit_acl + hdb_entry_get_pkinit_cert + hdb_entry_get_pkinit_hash + hdb_entry_get_pw_change_time + hdb_entry_set_krb5_config + hdb_entry_set_password + hdb_entry_set_pw_change_time + hdb_fetch_kvno + hdb_find_extension + hdb_foreach + hdb_free_dbinfo + hdb_free_entry + hdb_free_key + hdb_free_keys + hdb_free_master_key + hdb_generate_key_set + hdb_generate_key_set_password + hdb_generate_key_set_password_with_ks_tuple + hdb_get_dbinfo + hdb_get_instance + hdb_init_db + hdb_install_keyset + hdb_interface_version DATA + hdb_key2principal + hdb_kvno2keys + hdb_list_builtin + hdb_lock + hdb_next_enctype2key + hdb_principal2key + hdb_print_entry + hdb_process_master_key + hdb_prune_keys + hdb_prune_keys_kvno + hdb_read_master_key + hdb_remove_keys + hdb_replace_extension + hdb_seal_key + hdb_seal_key_mkey + hdb_seal_keys + hdb_seal_keys_mkey + hdb_set_last_modified_by + hdb_set_master_key + hdb_set_master_keyfile + hdb_unlock + hdb_unseal_key + hdb_unseal_key_mkey + hdb_unseal_keys + hdb_unseal_keys_kvno + hdb_unseal_keys_mkey + hdb_validate_key_rotation + hdb_validate_key_rotations + hdb_value2entry + hdb_value2entry_alias + hdb_write_master_key + length_HDB_keyset + initialize_hdb_error_table_r + + hdb_kt_ops + hdb_get_kt_ops + +; MIT KDB related entries + _hdb_mdb_value2entry + _hdb_mit_dump2mitdb_entry + +; some random bits needed for libkadm + add_HDB_Ext_KeyRotation + add_HDB_Ext_KeySet + add_Keys + asn1_HDBFlags_units + copy_Event + copy_HDB_EncTypeList + copy_hdb_entry + copy_HDB_entry + copy_hdb_entry_alias + copy_HDB_entry_alias + copy_HDB_EntryOrAlias + copy_HDB_extensions + copy_HDB_Ext_KeyRotation + copy_Key + copy_Keys + copy_Salt + decode_HDB_EncTypeList + decode_hdb_entry + decode_HDB_entry + decode_hdb_entry_alias + decode_HDB_entry_alias + decode_HDB_EntryOrAlias + decode_HDB_Ext_Aliases + decode_HDB_extension + decode_HDB_Ext_KeyRotation + decode_HDB_Ext_PKINIT_acl + decode_Key + decode_Keys + encode_HDB_EncTypeList + encode_hdb_entry + encode_HDB_entry + encode_hdb_entry_alias + encode_HDB_entry_alias + encode_HDB_EntryOrAlias + encode_HDB_Ext_Aliases + encode_HDB_extension + encode_HDB_Ext_KeyRotation + encode_HDB_Ext_PKINIT_acl + encode_hdb_keyset + encode_Key + encode_Keys + free_Event + free_HDB_EncTypeList + free_hdb_entry + free_HDB_entry + free_hdb_entry_alias + free_HDB_entry_alias + free_HDB_EntryOrAlias + free_HDB_Ext_Aliases + free_HDB_extension + free_HDB_extensions + free_HDB_Ext_KeyRotation + free_HDB_Ext_KeySet + free_HDB_Ext_PKINIT_acl + free_hdb_keyset + free_HDB_keyset + free_Key + free_Keys + free_Salt + HDBFlags2int + int2HDBFlags + int2KeyRotationFlags + KeyRotationFlags2int + length_HDB_EncTypeList + length_hdb_entry + length_HDB_entry + length_hdb_entry_alias + length_HDB_entry_alias + length_HDB_EntryOrAlias + length_HDB_Ext_Aliases + length_HDB_extension + length_HDB_Ext_KeyRotation + length_HDB_Ext_PKINIT_acl + length_hdb_keyset + length_Key + length_Keys + remove_HDB_Ext_KeyRotation + remove_Keys diff --git a/third_party/heimdal/lib/hdb/libhdb-version.rc b/third_party/heimdal/lib/hdb/libhdb-version.rc new file mode 100644 index 0000000..b0d417b --- /dev/null +++ b/third_party/heimdal/lib/hdb/libhdb-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_DLL +#define RC_FILE_DESC_0409 "Heimdal DB Library" +#define RC_FILE_ORIG_0409 "libhdb.dll" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/hdb/mkey.c b/third_party/heimdal/lib/hdb/mkey.c new file mode 100644 index 0000000..cfc27d4 --- /dev/null +++ b/third_party/heimdal/lib/hdb/mkey.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2000 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +struct hdb_master_key_data { + krb5_keytab_entry keytab; + krb5_crypto crypto; + struct hdb_master_key_data *next; + unsigned int key_usage; +}; + +void +hdb_free_master_key(krb5_context context, hdb_master_key mkey) +{ + struct hdb_master_key_data *ptr; + while(mkey) { + krb5_kt_free_entry(context, &mkey->keytab); + if (mkey->crypto) + krb5_crypto_destroy(context, mkey->crypto); + ptr = mkey; + mkey = mkey->next; + free(ptr); + } +} + +krb5_error_code +hdb_process_master_key(krb5_context context, + int kvno, krb5_keyblock *key, krb5_enctype etype, + hdb_master_key *mkey) +{ + krb5_error_code ret; + + *mkey = calloc(1, sizeof(**mkey)); + if(*mkey == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*mkey)->key_usage = HDB_KU_MKEY; + (*mkey)->keytab.vno = kvno; + ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); + if(ret) + goto fail; + ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock); + if(ret) + goto fail; + if(etype != 0) + (*mkey)->keytab.keyblock.keytype = etype; + (*mkey)->keytab.timestamp = time(NULL); + ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto); + if(ret) + goto fail; + return 0; + fail: + hdb_free_master_key(context, *mkey); + *mkey = NULL; + return ret; +} + +krb5_error_code +hdb_add_master_key(krb5_context context, krb5_keyblock *key, + hdb_master_key *inout) +{ + int vno = 0; + hdb_master_key p; + krb5_error_code ret; + + for(p = *inout; p; p = p->next) + vno = max(vno, p->keytab.vno); + vno++; + ret = hdb_process_master_key(context, vno, key, 0, &p); + if(ret) + return ret; + p->next = *inout; + *inout = p; + return 0; +} + +static krb5_error_code +read_master_keytab(krb5_context context, const char *filename, + hdb_master_key *mkey) +{ + krb5_error_code ret; + krb5_keytab id; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + hdb_master_key p; + + *mkey = NULL; + ret = krb5_kt_resolve(context, filename, &id); + if(ret) + return ret; + + ret = krb5_kt_start_seq_get(context, id, &cursor); + if(ret) + goto out; + while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { + p = calloc(1, sizeof(*p)); + if (p == NULL) { + ret = ENOMEM; + break; + } + p->keytab = entry; + p->next = *mkey; + *mkey = p; + ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); + if (ret) + break; + } + krb5_kt_end_seq_get(context, id, &cursor); + out: + krb5_kt_close(context, id); + if (ret) { + hdb_free_master_key(context, *mkey); + *mkey = NULL; + } + return ret; +} + +/* read a MIT master keyfile */ +static krb5_error_code +read_master_mit(krb5_context context, const char *filename, + int byteorder, hdb_master_key *mkey) +{ + int fd; + krb5_error_code ret; + krb5_storage *sp; + int16_t enctype; + krb5_keyblock key; + + fd = open(filename, O_RDONLY | O_BINARY); + if(fd < 0) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "failed to open %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + sp = krb5_storage_from_fd(fd); + if(sp == NULL) { + close(fd); + return errno; + } + krb5_storage_set_flags(sp, byteorder); + /* could possibly use ret_keyblock here, but do it with more + checks for now */ + { + ret = krb5_ret_int16(sp, &enctype); + if (ret) + goto out; + ret = krb5_enctype_valid(context, enctype); + if (ret) + goto out; + key.keytype = enctype; + ret = krb5_ret_data(sp, &key.keyvalue); + if(ret) + goto out; + } + ret = hdb_process_master_key(context, 1, &key, 0, mkey); + krb5_free_keyblock_contents(context, &key); + out: + krb5_storage_free(sp); + close(fd); + return ret; +} + +/* read an old master key file */ +static krb5_error_code +read_master_encryptionkey(krb5_context context, const char *filename, + hdb_master_key *mkey) +{ + int fd; + krb5_keyblock key; + krb5_error_code ret; + unsigned char buf[256]; + ssize_t len; + size_t ret_len; + + fd = open(filename, O_RDONLY | O_BINARY); + if(fd < 0) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "failed to open %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + + len = read(fd, buf, sizeof(buf)); + close(fd); + if(len < 0) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "error reading %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + + ret = decode_EncryptionKey(buf, len, &key, &ret_len); + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + if(ret) + return ret; + + /* Originally, the keytype was just that, and later it got changed + to des-cbc-md5, but we always used des in cfb64 mode. This + should cover all cases, but will break if someone has hacked + this code to really use des-cbc-md5 -- but then that's not my + problem. */ + if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5) + key.keytype = ETYPE_DES_CFB64_NONE; + + ret = hdb_process_master_key(context, 0, &key, 0, mkey); + krb5_free_keyblock_contents(context, &key); + return ret; +} + +/* read a krb4 /.k style file */ +static krb5_error_code +read_master_krb4(krb5_context context, const char *filename, + hdb_master_key *mkey) +{ + int fd; + krb5_keyblock key; + krb5_error_code ret; + unsigned char buf[256]; + ssize_t len; + + fd = open(filename, O_RDONLY | O_BINARY); + if(fd < 0) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "failed to open %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + + len = read(fd, buf, sizeof(buf)); + close(fd); + if(len < 0) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "error reading %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + if(len != 8) { + krb5_set_error_message(context, HEIM_ERR_EOF, + "bad contents of %s", filename); + return HEIM_ERR_EOF; /* XXX file might be too large */ + } + + memset(&key, 0, sizeof(key)); + key.keytype = ETYPE_DES_PCBC_NONE; + ret = krb5_data_copy(&key.keyvalue, buf, len); + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + if(ret) + return ret; + + ret = hdb_process_master_key(context, 0, &key, 0, mkey); + krb5_free_keyblock_contents(context, &key); + return ret; +} + +krb5_error_code +hdb_read_master_key(krb5_context context, const char *filename, + hdb_master_key *mkey) +{ + FILE *f; + unsigned char buf[16]; + krb5_error_code ret; + + off_t len; + + *mkey = NULL; + + if(filename == NULL) + filename = HDB_DB_DIR "/m-key"; + + f = fopen(filename, "r"); + if(f == NULL) { + int save_errno = errno; + krb5_set_error_message(context, save_errno, "failed to open %s: %s", + filename, strerror(save_errno)); + return save_errno; + } + + if(fread(buf, 1, 2, f) != 2) { + fclose(f); + krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename); + return HEIM_ERR_EOF; + } + + fseek(f, 0, SEEK_END); + len = ftell(f); + + if(fclose(f) != 0) + return errno; + + if(len < 0) + return errno; + + if(len == 8) { + ret = read_master_krb4(context, filename, mkey); + } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) { + ret = read_master_encryptionkey(context, filename, mkey); + } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) { + ret = read_master_keytab(context, filename, mkey); + } else { + /* + * Check both LittleEndian and BigEndian since they key file + * might be moved from a machine with diffrent byte order, or + * its running on MacOS X that always uses BE master keys. + */ + ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey); + if (ret) + ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey); + } + return ret; +} + +krb5_error_code +hdb_write_master_key(krb5_context context, const char *filename, + hdb_master_key mkey) +{ + krb5_error_code ret; + hdb_master_key p; + krb5_keytab kt; + + if(filename == NULL) + filename = HDB_DB_DIR "/m-key"; + + ret = krb5_kt_resolve(context, filename, &kt); + if(ret) + return ret; + + for(p = mkey; p; p = p->next) { + ret = krb5_kt_add_entry(context, kt, &p->keytab); + } + + krb5_kt_close(context, kt); + + return ret; +} + +krb5_error_code +_hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage) +{ + if (db->hdb_master_key_set == 0) + return HDB_ERR_NO_MKEY; + db->hdb_master_key->key_usage = key_usage; + return 0; +} + +hdb_master_key +_hdb_find_master_key(unsigned int *mkvno, hdb_master_key mkey) +{ + hdb_master_key ret = NULL; + while(mkey) { + if(ret == NULL && mkey->keytab.vno == 0) + ret = mkey; + if(mkvno == NULL) { + if(ret == NULL || mkey->keytab.vno > ret->keytab.vno) + ret = mkey; + } else if((uint32_t)mkey->keytab.vno == *mkvno) + return mkey; + mkey = mkey->next; + } + return ret; +} + +int +_hdb_mkey_version(hdb_master_key mkey) +{ + return mkey->keytab.vno; +} + +int +_hdb_mkey_decrypt(krb5_context context, hdb_master_key key, + krb5_key_usage usage, + void *ptr, size_t size, krb5_data *res) +{ + return krb5_decrypt(context, key->crypto, usage, + ptr, size, res); +} + +int +_hdb_mkey_encrypt(krb5_context context, hdb_master_key key, + krb5_key_usage usage, + const void *ptr, size_t size, krb5_data *res) +{ + return krb5_encrypt(context, key->crypto, usage, + ptr, size, res); +} + +krb5_error_code +hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) +{ + + krb5_error_code ret; + krb5_data res; + size_t keysize; + + hdb_master_key key; + + if(k->mkvno == NULL) + return 0; + + key = _hdb_find_master_key(k->mkvno, mkey); + + if (key == NULL) + return HDB_ERR_NO_MKEY; + + ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, + k->key.keyvalue.data, + k->key.keyvalue.length, + &res); + if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + /* try to decrypt with MIT key usage */ + ret = _hdb_mkey_decrypt(context, key, 0, + k->key.keyvalue.data, + k->key.keyvalue.length, + &res); + } + if (ret) + return ret; + + /* fixup keylength if the key got padded when encrypting it */ + ret = krb5_enctype_keysize(context, k->key.keytype, &keysize); + if (ret) { + krb5_data_free(&res); + return ret; + } + if (keysize > res.length) { + krb5_data_free(&res); + return KRB5_BAD_KEYSIZE; + } + + memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); + free(k->key.keyvalue.data); + k->key.keyvalue = res; + k->key.keyvalue.length = keysize; + free(k->mkvno); + k->mkvno = NULL; + + return 0; +} + +krb5_error_code +hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) +{ + size_t i; + + for(i = 0; i < ent->keys.len; i++){ + krb5_error_code ret; + + ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey); + if (ret) + return ret; + } + return 0; +} + +krb5_error_code +hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) +{ + if (db->hdb_master_key_set == 0) + return 0; + return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); +} + +/* + * Unseal the keys for the given kvno (or all of them) of entry. + * + * If kvno == 0 -> unseal all. + * if kvno != 0 -> unseal the requested kvno and make sure it's the one listed + * as the current keyset for the entry (swapping it with a + * historical keyset if need be). + */ +krb5_error_code +hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, + unsigned flags, hdb_entry *ent) +{ + krb5_error_code ret = HDB_ERR_NOENTRY; + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys; + Key *tmp_val; + time_t tmp_set_time; + unsigned int tmp_len; + unsigned int kvno_diff = 0; + krb5_kvno tmp_kvno; + size_t i, k; + int exclude_dead = 0; + KerberosTime now = 0; + + if (kvno == 0) + ret = 0; + + if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) { + exclude_dead = 1; + now = time(NULL); + if (HDB_F_LIVE_CLNT_KVNOS) + kvno_diff = hdb_entry_get_kvno_diff_clnt(ent); + else + kvno_diff = hdb_entry_get_kvno_diff_svc(ent); + } + + ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (ext == NULL || (&ext->data.u.hist_keys)->len == 0) + return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); + + /* For swapping; see below */ + tmp_len = ent->keys.len; + tmp_val = ent->keys.val; + tmp_kvno = ent->kvno; + (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time); + + hist_keys = &ext->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + if (kvno != 0 && hist_keys->val[i].kvno != kvno) + continue; + + if (exclude_dead && + ((ent->max_life != NULL && + hist_keys->val[i].set_time != NULL && + (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) || + (hist_keys->val[i].kvno < kvno && + (kvno - hist_keys->val[i].kvno) > kvno_diff))) + /* + * The KDC may want to to check for this keyset's set_time + * is within the TGS principal's max_life, say. But we stop + * here. + */ + continue; + + /* Either the keys we want, or all the keys */ + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + ret = hdb_unseal_key_mkey(context, + &hist_keys->val[i].keys.val[k], + db->hdb_master_key); + /* + * If kvno == 0 we might not want to bail here! E.g., if we + * no longer have the right master key, so just ignore this. + * + * We could filter out keys that we can't decrypt here + * because of HDB_ERR_NO_MKEY. However, it seems safest to + * filter them out only where necessary, say, in kadm5. + */ + if (ret && kvno != 0) + return ret; + if (ret && ret != HDB_ERR_NO_MKEY) + return (ret); + } + + if (kvno == 0) + continue; + + /* + * What follows is a bit of a hack. + * + * This is the keyset we're being asked for, but it's not the + * current keyset. So we add the current keyset to the history, + * leave the one we were asked for in the history, and pretend + * the one we were asked for is also the current keyset. + * + * This is a bit of a defensive hack in case an entry fetched + * this way ever gets modified then stored: if the keyset is not + * changed we can detect this and put things back, else we won't + * drop any keysets from history by accident. + * + * Note too that we only ever get called with a non-zero kvno + * either in the KDC or in cases where we aren't changing the + * HDB entry anyways, which is why this is just a defensive + * hack. We also don't fetch specific kvnos in the dump case, + * so there's no danger that we'll dump this entry and load it + * again, repeatedly causing the history to grow boundelessly. + */ + + /* Swap key sets */ + ent->kvno = hist_keys->val[i].kvno; + ent->keys.val = hist_keys->val[i].keys.val; + ent->keys.len = hist_keys->val[i].keys.len; + if (hist_keys->val[i].set_time != NULL) + /* Sloppy, but the callers we expect won't care */ + (void) hdb_entry_set_pw_change_time(context, ent, + *hist_keys->val[i].set_time); + hist_keys->val[i].kvno = tmp_kvno; + hist_keys->val[i].keys.val = tmp_val; + hist_keys->val[i].keys.len = tmp_len; + if (hist_keys->val[i].set_time != NULL) + /* Sloppy, but the callers we expect won't care */ + *hist_keys->val[i].set_time = tmp_set_time; + + return 0; + } + + return (ret); +} + +krb5_error_code +hdb_unseal_key(krb5_context context, HDB *db, Key *k) +{ + if (db->hdb_master_key_set == 0) + return 0; + return hdb_unseal_key_mkey(context, k, db->hdb_master_key); +} + +krb5_error_code +hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) +{ + krb5_error_code ret; + krb5_data res; + hdb_master_key key; + + if(k->mkvno != NULL) + return 0; + + key = _hdb_find_master_key(k->mkvno, mkey); + + if (key == NULL) + return HDB_ERR_NO_MKEY; + + ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, + k->key.keyvalue.data, + k->key.keyvalue.length, + &res); + if (ret) + return ret; + + memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); + free(k->key.keyvalue.data); + k->key.keyvalue = res; + + if (k->mkvno == NULL) { + k->mkvno = malloc(sizeof(*k->mkvno)); + if (k->mkvno == NULL) + return ENOMEM; + } + *k->mkvno = key->keytab.vno; + + return 0; +} + +krb5_error_code +hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) +{ + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys; + size_t i, k; + krb5_error_code ret; + + for(i = 0; i < ent->keys.len; i++){ + ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); + if (ret) + return ret; + } + + ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (ext == NULL) + return 0; + hist_keys = &ext->data.u.hist_keys; + + for (i = 0; i < hist_keys->len; i++) { + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k], + mkey); + if (ret) + return ret; + } + } + + return 0; +} + +krb5_error_code +hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent) +{ + if (db->hdb_master_key_set == 0) + return 0; + + return hdb_seal_keys_mkey(context, ent, db->hdb_master_key); +} + +krb5_error_code +hdb_seal_key(krb5_context context, HDB *db, Key *k) +{ + if (db->hdb_master_key_set == 0) + return 0; + + return hdb_seal_key_mkey(context, k, db->hdb_master_key); +} + +krb5_error_code +hdb_set_master_key(krb5_context context, + HDB *db, + krb5_keyblock *key) +{ + krb5_error_code ret; + hdb_master_key mkey; + + ret = hdb_process_master_key(context, 0, key, 0, &mkey); + if (ret) + return ret; + db->hdb_master_key = mkey; +#if 0 /* XXX - why? */ + des_set_random_generator_seed(key.keyvalue.data); +#endif + db->hdb_master_key_set = 1; + db->hdb_master_key->key_usage = HDB_KU_MKEY; + return 0; +} + +krb5_error_code +hdb_set_master_keyfile (krb5_context context, + HDB *db, + const char *keyfile) +{ + hdb_master_key key; + krb5_error_code ret; + + ret = hdb_read_master_key(context, keyfile, &key); + if (ret) { + if (ret != ENOENT) + return ret; + krb5_clear_error_message(context); + return 0; + } + db->hdb_master_key = key; + db->hdb_master_key_set = 1; + return ret; +} + +krb5_error_code +hdb_clear_master_key (krb5_context context, + HDB *db) +{ + if (db->hdb_master_key_set) { + hdb_free_master_key(context, db->hdb_master_key); + db->hdb_master_key_set = 0; + } + return 0; +} diff --git a/third_party/heimdal/lib/hdb/ndbm.c b/third_party/heimdal/lib/hdb/ndbm.c new file mode 100644 index 0000000..52c52c8 --- /dev/null +++ b/third_party/heimdal/lib/hdb/ndbm.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" + +#if HAVE_NDBM + +#if defined(HAVE_GDBM_NDBM_H) +#include +#define WRITE_SUPPORT 1 +#elif defined(HAVE_NDBM_H) +#include +#elif defined(HAVE_DBM_H) +#define WRITE_SUPPORT 1 +#include +#endif + +struct ndbm_db { + DBM *db; + int lock_fd; +}; + +static krb5_error_code +NDBM_destroy(krb5_context context, HDB *db) +{ + hdb_clear_master_key(context, db); + krb5_config_free_strings(db->virtual_hostbased_princ_svcs); + free(db->hdb_name); + free(db); + return 0; +} + +static krb5_error_code +NDBM_lock(krb5_context context, HDB *db, int operation) +{ + struct ndbm_db *d = db->hdb_db; + return hdb_lock(d->lock_fd, operation); +} + +static krb5_error_code +NDBM_unlock(krb5_context context, HDB *db) +{ + struct ndbm_db *d = db->hdb_db; + return hdb_unlock(d->lock_fd); +} + +static krb5_error_code +NDBM_seq(krb5_context context, HDB *db, + unsigned flags, hdb_entry *entry, int first) + +{ + struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; + datum key, value; + krb5_data key_data, data; + krb5_error_code ret = 0; + + if(first) + key = dbm_firstkey(d->db); + else + key = dbm_nextkey(d->db); + if(key.dptr == NULL) + return HDB_ERR_NOENTRY; + key_data.data = key.dptr; + key_data.length = key.dsize; + ret = db->hdb_lock(context, db, HDB_RLOCK); + if(ret) return ret; + value = dbm_fetch(d->db, key); + db->hdb_unlock(context, db); + data.data = value.dptr; + data.length = value.dsize; + memset(entry, 0, sizeof(*entry)); + if(hdb_value2entry(context, &data, entry)) + return NDBM_seq(context, db, flags, entry, 0); + if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { + ret = hdb_unseal_keys (context, db, entry); + if (ret) + hdb_free_entry (context, db, entry); + } + if (ret == 0 && entry->principal == NULL) { + entry->principal = malloc (sizeof(*entry->principal)); + if (entry->principal == NULL) { + hdb_free_entry (context, db, entry); + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + } else { + hdb_key2principal (context, &key_data, entry->principal); + } + } + return ret; +} + + +static krb5_error_code +NDBM_firstkey(krb5_context context, HDB *db,unsigned flags,hdb_entry *entry) +{ + return NDBM_seq(context, db, flags, entry, 1); +} + + +static krb5_error_code +NDBM_nextkey(krb5_context context, HDB *db, unsigned flags,hdb_entry *entry) +{ + return NDBM_seq(context, db, flags, entry, 0); +} + +static krb5_error_code +open_lock_file(krb5_context context, const char *db_name, int *fd) +{ + char *lock_file; + int ret = 0; + + /* lock old and new databases */ + if (asprintf(&lock_file, "%s.lock", db_name) == -1) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + *fd = open(lock_file, O_RDWR | O_CREAT, 0600); + if(*fd < 0) { + ret = errno; + krb5_set_error_message(context, ret, "open(%s): %s", lock_file, + strerror(ret)); + } + free(lock_file); + return ret; +} + + +static krb5_error_code +NDBM_rename(krb5_context context, HDB *db, const char *new_name) +{ + int ret; + char *old_dir = NULL, *old_pag = NULL; + char *new_dir = NULL, *new_pag = NULL; + int old_lock_fd, new_lock_fd; + + /* lock old and new databases */ + ret = open_lock_file(context, db->hdb_name, &old_lock_fd); + if (ret) + return ret; + + ret = hdb_lock(old_lock_fd, HDB_WLOCK); + if(ret) { + close(old_lock_fd); + return ret; + } + + ret = open_lock_file(context, new_name, &new_lock_fd); + if (ret) { + hdb_unlock(old_lock_fd); + close(old_lock_fd); + return ret; + } + + ret = hdb_lock(new_lock_fd, HDB_WLOCK); + if(ret) { + hdb_unlock(old_lock_fd); + close(old_lock_fd); + close(new_lock_fd); + return ret; + } + + if (asprintf(&old_dir, "%s.dir", db->hdb_name) == -1) { + old_dir = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&old_pag, "%s.pag", db->hdb_name) == -1) { + old_pag = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&new_dir, "%s.dir", new_name) == -1) { + new_dir = NULL; + ret = ENOMEM; + goto out; + } + if (asprintf(&new_pag, "%s.pag", new_name) == -1) { + new_pag = NULL; + ret = ENOMEM; + goto out; + } + + ret = rename(old_dir, new_dir) || rename(old_pag, new_pag); + if (ret) { + ret = errno; + if (ret == 0) + ret = EPERM; + krb5_set_error_message(context, ret, "rename: %s", strerror(ret)); + } + + out: + free(old_dir); + free(old_pag); + free(new_dir); + free(new_pag); + + hdb_unlock(new_lock_fd); + hdb_unlock(old_lock_fd); + close(new_lock_fd); + close(old_lock_fd); + + if(ret) + return ret; + + free(db->hdb_name); + db->hdb_name = strdup(new_name); + return 0; +} + +static krb5_error_code +NDBM__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; + datum k, v; + int code; + + k.dptr = key.data; + k.dsize = key.length; + code = db->hdb_lock(context, db, HDB_RLOCK); + if(code) + return code; + v = dbm_fetch(d->db, k); + db->hdb_unlock(context, db); + if(v.dptr == NULL) + return HDB_ERR_NOENTRY; + + krb5_data_copy(reply, v.dptr, v.dsize); + return 0; +} + +static krb5_error_code +NDBM__put(krb5_context context, HDB *db, int replace, + krb5_data key, krb5_data value) +{ +#ifdef WRITE_SUPPORT + struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; + datum k, v; + int code; + + k.dptr = key.data; + k.dsize = key.length; + v.dptr = value.data; + v.dsize = value.length; + + code = db->hdb_lock(context, db, HDB_WLOCK); + if(code) + return code; + code = dbm_store(d->db, k, v, replace ? DBM_REPLACE : DBM_INSERT); + db->hdb_unlock(context, db); + if(code == 1) + return HDB_ERR_EXISTS; + if (code < 0) + return code; + return 0; +#else + return HDB_ERR_NO_WRITE_SUPPORT; +#endif +} + +static krb5_error_code +NDBM__del(krb5_context context, HDB *db, krb5_data key) +{ + struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; + datum k; + int code; + krb5_error_code ret; + + k.dptr = key.data; + k.dsize = key.length; + ret = db->hdb_lock(context, db, HDB_WLOCK); + if(ret) return ret; + code = dbm_delete(d->db, k); + db->hdb_unlock(context, db); + if(code < 0) + return errno; + return 0; +} + + +static krb5_error_code +NDBM_close(krb5_context context, HDB *db) +{ + struct ndbm_db *d = db->hdb_db; + dbm_close(d->db); + close(d->lock_fd); + free(d); + return 0; +} + +static krb5_error_code +NDBM_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + krb5_error_code ret; + struct ndbm_db *d = malloc(sizeof(*d)); + + if(d == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + d->db = dbm_open((char*)db->hdb_name, flags, mode); + if(d->db == NULL){ + ret = errno; + free(d); + krb5_set_error_message(context, ret, "dbm_open(%s): %s", db->hdb_name, + strerror(ret)); + return ret; + } + + ret = open_lock_file(context, db->hdb_name, &d->lock_fd); + if (ret) { + ret = errno; + dbm_close(d->db); + free(d); + krb5_set_error_message(context, ret, "open(lock file): %s", + strerror(ret)); + return ret; + } + + db->hdb_db = d; + if((flags & O_ACCMODE) == O_RDONLY) + ret = hdb_check_db_format(context, db); + else + ret = hdb_init_db(context, db); + if(ret == HDB_ERR_NOENTRY) + return 0; + if (ret) { + NDBM_close(context, db); + krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", + (flags & O_ACCMODE) == O_RDONLY ? + "checking format of" : "initialize", + db->hdb_name); + } + return ret; +} + +krb5_error_code +hdb_ndbm_create(krb5_context context, HDB **db, + const char *filename) +{ + *db = calloc(1, sizeof(**db)); + if (*db == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + (*db)->hdb_db = NULL; + (*db)->hdb_name = strdup(filename); + if ((*db)->hdb_name == NULL) { + free(*db); + *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + (*db)->hdb_master_key_set = 0; + (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + (*db)->hdb_open = NDBM_open; + (*db)->hdb_close = NDBM_close; + (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; + (*db)->hdb_store = _hdb_store; + (*db)->hdb_remove = _hdb_remove; + (*db)->hdb_firstkey = NDBM_firstkey; + (*db)->hdb_nextkey= NDBM_nextkey; + (*db)->hdb_lock = NDBM_lock; + (*db)->hdb_unlock = NDBM_unlock; + (*db)->hdb_rename = NDBM_rename; + (*db)->hdb__get = NDBM__get; + (*db)->hdb__put = NDBM__put; + (*db)->hdb__del = NDBM__del; + (*db)->hdb_destroy = NDBM_destroy; + return 0; +} + +#endif /* HAVE_NDBM */ diff --git a/third_party/heimdal/lib/hdb/print.c b/third_party/heimdal/lib/hdb/print.c new file mode 100644 index 0000000..7f25358 --- /dev/null +++ b/third_party/heimdal/lib/hdb/print.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 1999-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "hdb_locl.h" +#include +#include + +/* + This is the present contents of a dump line. This might change at + any time. Fields are separated by white space. + + principal + keyblock + kvno + keys... + mkvno + enctype + keyvalue + salt (- means use normal salt) + creation date and principal + modification date and principal + principal valid from date (not used) + principal valid end date (not used) + principal key expires (not used) + max ticket life + max renewable life + flags + generation number + */ + +/* + * These utility functions return the number of bytes written or -1, and + * they set an error in the context. + */ +static ssize_t +append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...) +{ + ssize_t sz; + char *s; + int rc; + va_list ap; + va_start(ap, fmt); + rc = vasprintf(&s, fmt, ap); + va_end(ap); + if(rc < 0) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return -1; + } + sz = krb5_storage_write(sp, s, strlen(s)); + free(s); + return sz; +} + +static krb5_error_code +append_hex(krb5_context context, krb5_storage *sp, + int always_encode, int lower, krb5_data *data) +{ + ssize_t sz; + int printable = 1; + size_t i; + char *p; + + p = data->data; + if (!always_encode) { + for (i = 0; i < data->length; i++) { + if (!isalnum((unsigned char)p[i]) && p[i] != '.'){ + printable = 0; + break; + } + } + } + if (printable && !always_encode) + return append_string(context, sp, "\"%.*s\"", + data->length, data->data); + sz = hex_encode(data->data, data->length, &p); + if (sz == -1) return sz; + if (lower) + strlwr(p); + sz = append_string(context, sp, "%s", p); + free(p); + return sz; +} + +static char * +time2str(time_t t) +{ + static char buf[128]; + strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&t)); + return buf; +} + +static ssize_t +append_event(krb5_context context, krb5_storage *sp, Event *ev) +{ + krb5_error_code ret; + ssize_t sz; + char *pr = NULL; + if(ev == NULL) + return append_string(context, sp, "- "); + if (ev->principal != NULL) { + ret = krb5_unparse_name(context, ev->principal, &pr); + if (ret) return -1; /* krb5_unparse_name() sets error info */ + } + sz = append_string(context, sp, "%s:%s ", time2str(ev->time), + pr ? pr : "UNKNOWN"); + free(pr); + return sz; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +static ssize_t +append_mit_key(krb5_context context, krb5_storage *sp, + krb5_const_principal princ, + unsigned int kvno, Key *key) +{ + krb5_error_code ret; + krb5_salt k5salt; + ssize_t sz; + size_t key_versions = key->salt ? 2 : 1; + size_t decrypted_key_length; + char buf[2]; + krb5_data keylenbytes; + unsigned int salttype; + + sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno, + key->key.keytype, key->key.keyvalue.length + 2); + if (sz == -1) return sz; + ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length); + if (ret) return -1; /* XXX we lose the error code */ + buf[0] = decrypted_key_length & 0xff; + buf[1] = (decrypted_key_length & 0xff00) >> 8; + keylenbytes.data = buf; + keylenbytes.length = sizeof (buf); + sz = append_hex(context, sp, 1, 1, &keylenbytes); + if (sz == -1) return sz; + sz = append_hex(context, sp, 1, 1, &key->key.keyvalue); + if (!key->salt) + return sz; + + /* Map salt to MIT KDB style */ + switch (key->salt->type) { + case KRB5_PADATA_PW_SALT: + + /* + * Compute normal salt and then see whether it matches the stored one + */ + ret = krb5_get_pw_salt(context, princ, &k5salt); + if (ret) return -1; + if (k5salt.saltvalue.length == key->salt->salt.length && + memcmp(k5salt.saltvalue.data, key->salt->salt.data, + k5salt.saltvalue.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */ + else if (key->salt->salt.length == strlen(princ->realm) && + memcmp(key->salt->salt.data, princ->realm, + key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */ + else if (key->salt->salt.length == + k5salt.saltvalue.length - strlen(princ->realm) && + memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm), + key->salt->salt.data, key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */ + else + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* hope for best */ + + break; + + case KRB5_PADATA_AFS3_SALT: + salttype = KRB5_KDB_SALTTYPE_AFS3; + break; + + default: + return -1; + } + + sz = append_string(context, sp, "\t%u\t%u\t", salttype, + key->salt->salt.length); + if (sz == -1) return sz; + return append_hex(context, sp, 1, 1, &key->salt->salt); +} + +static krb5_error_code +entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) +{ + char *p; + size_t i; + krb5_error_code ret; + + /* --- principal */ + ret = krb5_unparse_name(context, ent->principal, &p); + if(ret) + return ret; + append_string(context, sp, "%s ", p); + free(p); + /* --- kvno */ + append_string(context, sp, "%d", ent->kvno); + /* --- keys */ + for(i = 0; i < ent->keys.len; i++){ + /* --- mkvno, keytype */ + if(ent->keys.val[i].mkvno) + append_string(context, sp, ":%d:%d:", + *ent->keys.val[i].mkvno, + ent->keys.val[i].key.keytype); + else + append_string(context, sp, "::%d:", + ent->keys.val[i].key.keytype); + /* --- keydata */ + append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue); + append_string(context, sp, ":"); + /* --- salt */ + if(ent->keys.val[i].salt){ + append_string(context, sp, "%u/", ent->keys.val[i].salt->type); + append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt); + }else + append_string(context, sp, "-"); + } + append_string(context, sp, " "); + /* --- created by */ + append_event(context, sp, &ent->created_by); + /* --- modified by */ + append_event(context, sp, ent->modified_by); + + /* --- valid start */ + if(ent->valid_start) + append_string(context, sp, "%s ", time2str(*ent->valid_start)); + else + append_string(context, sp, "- "); + + /* --- valid end */ + if(ent->valid_end) + append_string(context, sp, "%s ", time2str(*ent->valid_end)); + else + append_string(context, sp, "- "); + + /* --- password ends */ + if(ent->pw_end) + append_string(context, sp, "%s ", time2str(*ent->pw_end)); + else + append_string(context, sp, "- "); + + /* --- max life */ + if(ent->max_life) + append_string(context, sp, "%d ", *ent->max_life); + else + append_string(context, sp, "- "); + + /* --- max renewable life */ + if(ent->max_renew) + append_string(context, sp, "%d ", *ent->max_renew); + else + append_string(context, sp, "- "); + + /* --- flags */ + append_string(context, sp, "%d ", HDBFlags2int(ent->flags)); + + /* --- generation number */ + if(ent->generation) { + append_string(context, sp, "%s:%d:%d ", time2str(ent->generation->time), + ent->generation->usec, + ent->generation->gen); + } else + append_string(context, sp, "- "); + + /* --- extensions */ + if(ent->extensions && ent->extensions->len > 0) { + for(i = 0; i < ent->extensions->len; i++) { + void *d; + size_t size, sz = 0; + + ASN1_MALLOC_ENCODE(HDB_extension, d, size, + &ent->extensions->val[i], &sz, ret); + if (ret) { + krb5_clear_error_message(context); + return ret; + } + if(size != sz) + krb5_abortx(context, "internal asn.1 encoder error"); + + if (hex_encode(d, size, &p) < 0) { + free(d); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + free(d); + append_string(context, sp, "%s%s", p, + ent->extensions->len - 1 != i ? ":" : ""); + free(p); + } + } else + append_string(context, sp, "-"); + + return 0; +} + +#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 +#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 +#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 +#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 +#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 +#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 +#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 +#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 +#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 +#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 +#define KRB5_KDB_DISALLOW_SVR 0x00001000 +#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 +#define KRB5_KDB_SUPPORT_DESMD5 0x00004000 +#define KRB5_KDB_NEW_PRINC 0x00008000 + +static int +flags_to_attr(HDBFlags flags) +{ + int a = 0; + + if (!flags.postdate) + a |= KRB5_KDB_DISALLOW_POSTDATED; + if (!flags.forwardable) + a |= KRB5_KDB_DISALLOW_FORWARDABLE; + if (flags.initial) + a |= KRB5_KDB_DISALLOW_TGT_BASED; + if (!flags.renewable) + a |= KRB5_KDB_DISALLOW_RENEWABLE; + if (!flags.proxiable) + a |= KRB5_KDB_DISALLOW_PROXIABLE; + if (flags.invalid) + a |= KRB5_KDB_DISALLOW_ALL_TIX; + if (flags.require_preauth) + a |= KRB5_KDB_REQUIRES_PRE_AUTH; + if (flags.require_hwauth) + a |= KRB5_KDB_REQUIRES_HW_AUTH; + if (!flags.server) + a |= KRB5_KDB_DISALLOW_SVR; + if (flags.change_pw) + a |= KRB5_KDB_PWCHANGE_SERVICE; + return a; +} + +krb5_error_code +entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) +{ + krb5_error_code ret; + ssize_t sz; + size_t i, k; + size_t num_tl_data = 0; + size_t num_key_data = 0; + char *p; + HDB_Ext_KeySet *hist_keys = NULL; + HDB_extension *extp; + time_t last_pw_chg = 0; + time_t exp = 0; + time_t pwexp = 0; + unsigned int max_life = 0; + unsigned int max_renew = 0; + + if (ent->modified_by) + num_tl_data++; + + ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg); + if (ret) return ret; + if (last_pw_chg) + num_tl_data++; + + extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (extp) + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < ent->keys.len;i++) { + if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5) + continue; + num_key_data++; + } + if (hist_keys) { + for (i = 0; i < hist_keys->len; i++) { + /* + * MIT uses the highest kvno as the current kvno instead of + * tracking kvno separately, so we can't dump keysets with kvno + * higher than the entry's kvno. + */ + if (hist_keys->val[i].kvno >= ent->kvno) + continue; + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + num_key_data++; + } + } + } + + ret = krb5_unparse_name(context, ent->principal, &p); + if (ret) return ret; + sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d", + strlen(p), num_tl_data, num_key_data, p, + flags_to_attr(ent->flags)); + free(p); + if (sz == -1) return ENOMEM; + + if (ent->max_life) + max_life = *ent->max_life; + if (ent->max_renew) + max_renew = *ent->max_renew; + if (ent->valid_end) + exp = *ent->valid_end; + if (ent->pw_end) + pwexp = *ent->pw_end; + + sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0", + max_life, max_renew, exp, pwexp); + if (sz == -1) return ENOMEM; + + /* Dump TL data we know: last pw chg and modified_by */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 + if (last_pw_chg) { + krb5_data d; + time_t val; + unsigned char *ptr; + + ptr = (unsigned char *)&last_pw_chg; + val = ((unsigned long)ptr[3] << 24) | (ptr[2] << 16) + | (ptr[1] << 8) | ptr[0]; + d.data = &val; + d.length = sizeof (last_pw_chg); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_LAST_PWD_CHANGE, d.length); + if (sz == -1) return ENOMEM; + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) return ENOMEM; + } + if (ent->modified_by) { + krb5_data d; + unsigned int val; + size_t plen; + unsigned char *ptr; + char *modby_p; + + ptr = (unsigned char *)&ent->modified_by->time; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (ent->modified_by->time); + ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p); + if (ret) + return ret; + plen = strlen(modby_p); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_MOD_PRINC, + d.length + plen + 1 /* NULL counted */); + if (sz == -1) { + free(modby_p); + return ENOMEM; + } + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) { + free(modby_p); + return ENOMEM; + } + d.data = modby_p; + d.length = plen + 1; + sz = append_hex(context, sp, 1, 1, &d); + free(modby_p); + if (sz == -1) + return ENOMEM; + } + /* + * Dump keys (remembering to not include any with kvno higher than + * the entry's because MIT doesn't track entry kvno separately from + * the entry's keys -- max kvno is it) + */ + for (i = 0; i < ent->keys.len; i++) { + if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5) + continue; + sz = append_mit_key(context, sp, ent->principal, ent->kvno, + &ent->keys.val[i]); + if (sz == -1) return ENOMEM; + } + for (i = 0; hist_keys && i < ent->kvno; i++) { + size_t m; + + /* dump historical keys */ + for (k = 0; k < hist_keys->len; k++) { + if (hist_keys->val[k].kvno != ent->kvno - i) + continue; + for (m = 0; m < hist_keys->val[k].keys.len; m++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + sz = append_mit_key(context, sp, ent->principal, + hist_keys->val[k].kvno, + &hist_keys->val[k].keys.val[m]); + if (sz == -1) return ENOMEM; + } + } + } + sz = append_string(context, sp, "\t-1;"); /* "extra data" */ + if (sz == -1) return ENOMEM; + return 0; +} + +krb5_error_code +hdb_entry2string(krb5_context context, hdb_entry *ent, char **str) +{ + krb5_error_code ret; + krb5_data data; + krb5_storage *sp; + + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + ret = entry2string_int(context, sp, ent); + if (ret) { + krb5_storage_free(sp); + return ret; + } + + krb5_storage_write(sp, "\0", 1); + krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + *str = data.data; + return 0; +} + +/* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */ + +krb5_error_code +hdb_print_entry(krb5_context context, HDB *db, hdb_entry *entry, + void *data) +{ + struct hdb_print_entry_arg *parg = data; + krb5_error_code ret; + krb5_storage *sp; + + fflush(parg->out); + sp = krb5_storage_from_fd(fileno(parg->out)); + if (sp == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + switch (parg->fmt) { + case HDB_DUMP_HEIMDAL: + ret = entry2string_int(context, sp, entry); + break; + case HDB_DUMP_MIT: + ret = entry2mit_string_int(context, sp, entry); + break; + default: + heim_abort("Only two dump formats supported: Heimdal and MIT"); + } + if (ret) { + krb5_storage_free(sp); + return ret; + } + + krb5_storage_write(sp, "\n", 1); + krb5_storage_free(sp); + return 0; +} diff --git a/third_party/heimdal/lib/hdb/test_concurrency.c b/third_party/heimdal/lib/hdb/test_concurrency.c new file mode 100644 index 0000000..35c01f5 --- /dev/null +++ b/third_party/heimdal/lib/hdb/test_concurrency.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This test tries to test reader/writer concurrency for the SQLite3 and LMDB + * HDB backends. We're hoping to find that one thread or process can dump the + * HDB while another writes -- this way backups and ipropd-master need not + * block write transactions when dumping a huge HDB. + * + * It has two modes: threaded, and forked. + * + * Apparently, neither LMDB nor SQLite3 give us the desired level of + * concurrency in threaded mode, with this test not making progress. This is + * surprising, at least for SQLite3, which is supposed to support N readers, 1 + * writer and be thread-safe. LMDB also is supposed to support N readers, 1 + * writers, but perhaps not all in one process? + */ + +#include "hdb_locl.h" +#include +#include +#include +#include + +struct tsync { + pthread_mutex_t lock; + pthread_cond_t rcv; + pthread_cond_t wcv; + const char *hdb_name; + const char *fname; + volatile int writer_go; + volatile int reader_go; + int writer_go_pipe[2]; + int reader_go_pipe[2]; +}; + +static void * +threaded_reader(void *d) +{ + krb5_error_code ret; + krb5_context context; + struct tsync *s = d; + hdb_entry entr; + HDB *dbr = NULL; + + printf("Reader thread opening HDB\n"); + + if ((krb5_init_context(&context))) + errx(1, "krb5_init_context failed"); + + printf("Reader thread waiting for writer to create the HDB\n"); + (void) pthread_mutex_lock(&s->lock); + s->writer_go = 1; + (void) pthread_cond_signal(&s->wcv); + while (!s->reader_go) + (void) pthread_cond_wait(&s->rcv, &s->lock); + s->reader_go = 0; + (void) pthread_mutex_unlock(&s->lock); + + /* Open a new HDB handle to read */ + if ((ret = hdb_create(context, &dbr, s->hdb_name))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not get a handle for HDB %s (read)", + s->hdb_name); + } + if ((ret = dbr->hdb_open(context, dbr, O_RDONLY, 0))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not open HDB %s", s->hdb_name); + } + if ((ret = dbr->hdb_firstkey(context, dbr, 0, &entr))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); + } + free_HDB_entry(&entr); + + /* Tell the writer to go ahead and write */ + printf("Reader thread iterated one entry; telling writer to write more\n"); + s->writer_go = 1; + (void) pthread_mutex_lock(&s->lock); + (void) pthread_cond_signal(&s->wcv); + + /* Wait for the writer to have written one more entry to the HDB */ + printf("Reader thread waiting for writer\n"); + while (!s->reader_go) + (void) pthread_cond_wait(&s->rcv, &s->lock); + s->reader_go = 0; + (void) pthread_mutex_unlock(&s->lock); + + /* Iterate the rest */ + printf("Reader thread iterating another entry\n"); + if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, + "Could not iterate while writing to HDB %s", s->hdb_name); + } + printf("Reader thread iterated another entry\n"); + free_HDB_entry(&entr); + if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { + //(void) unlink(s->fname); + krb5_warn(context, ret, + "HDB %s sees writes committed since starting iteration", + s->hdb_name); + } else if (ret != HDB_ERR_NOENTRY) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, + "Could not iterate while writing to HDB %s (2)", s->hdb_name); + } + + /* Tell the writer we're done */ + printf("Reader thread telling writer to go\n"); + s->writer_go = 1; + (void) pthread_cond_signal(&s->wcv); + (void) pthread_mutex_unlock(&s->lock); + + dbr->hdb_close(context, dbr); + dbr->hdb_destroy(context, dbr); + krb5_free_context(context); + printf("Reader thread exiting\n"); + return 0; +} + +static void +forked_reader(struct tsync *s) +{ + krb5_error_code ret; + krb5_context context; + hdb_entry entr; + ssize_t bytes; + char b[1]; + HDB *dbr = NULL; + + printf("Reader process opening HDB\n"); + + (void) close(s->writer_go_pipe[0]); + (void) close(s->reader_go_pipe[1]); + s->writer_go_pipe[0] = -1; + s->reader_go_pipe[1] = -1; + if ((krb5_init_context(&context))) + errx(1, "krb5_init_context failed"); + + printf("Reader process waiting for writer\n"); + while ((bytes = read(s->reader_go_pipe[0], b, sizeof(b))) == -1 && + errno == EINTR) + ; + if (bytes == -1) + err(1, "Could not read from reader-go pipe (error)"); + + /* Open a new HDB handle to read */ + if ((ret = hdb_create(context, &dbr, s->hdb_name))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not get a handle for HDB %s (read)", + s->hdb_name); + } + if ((ret = dbr->hdb_open(context, dbr, O_RDONLY, 0))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not open HDB %s", s->hdb_name); + } + if ((ret = dbr->hdb_firstkey(context, dbr, 0, &entr))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); + } + printf("Reader process iterated one entry\n"); + free_HDB_entry(&entr); + + /* Tell the writer to go ahead and write */ + printf("Reader process iterated one entry; telling writer to write more\n"); + while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 && + errno == EINTR) + ; + if (bytes == -1) + err(1, "Could not write to writer-go pipe (error)"); + + + /* Wait for the writer to have written one more entry to the HDB */ + printf("Reader process waiting for writer\n"); + while ((bytes = read(s->reader_go_pipe[0], b, sizeof(b))) == -1 && + errno == EINTR) + ; + if (bytes == -1) + err(1, "Could not read from reader-go pipe (error)"); + if (bytes == 0) + errx(1, "Could not read from reader-go pipe (EOF)"); + + /* Iterate the rest */ + if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr))) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, + "Could not iterate while writing to HDB %s", s->hdb_name); + } + free_HDB_entry(&entr); + printf("Reader process iterated another entry\n"); + if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { + //(void) unlink(s->fname); + krb5_warn(context, ret, + "HDB %s sees writes committed since starting iteration (%s)", + s->hdb_name, entr.principal->name.name_string.val[0]); + } else if (ret != HDB_ERR_NOENTRY) { + //(void) unlink(s->fname); + krb5_err(context, 1, ret, + "Could not iterate while writing to HDB %s (2)", s->hdb_name); + } + + /* Tell the writer we're done */ + printf("Reader process done; telling writer to go\n"); + while ((bytes = write(s->writer_go_pipe[1], "", sizeof(""))) == -1 && + errno == EINTR) + ; + if (bytes == -1) + err(1, "Could not write to writer-go pipe (error)"); + + dbr->hdb_close(context, dbr); + dbr->hdb_destroy(context, dbr); + krb5_free_context(context); + (void) close(s->writer_go_pipe[1]); + (void) close(s->reader_go_pipe[0]); + printf("Reader process exiting\n"); + _exit(0); +} + +static krb5_error_code +make_entry(krb5_context context, hdb_entry *entry, const char *name) +{ + krb5_error_code ret; + + memset(entry, 0, sizeof(*entry)); + entry->kvno = 2; + entry->keys.len = 0; + entry->keys.val = NULL; + entry->created_by.time = time(NULL); + entry->modified_by = NULL; + entry->valid_start = NULL; + entry->valid_end = NULL; + entry->max_life = NULL; + entry->max_renew = NULL; + entry->etypes = NULL; + entry->generation = NULL; + entry->extensions = NULL; + if ((ret = krb5_make_principal(context, &entry->principal, + "TEST.H5L.SE", name, NULL))) + return ret; + if ((ret = krb5_make_principal(context, &entry->created_by.principal, + "TEST.H5L.SE", "tester", NULL))) + return ret; + return 0; +} + +static void +readers_turn(struct tsync *s, pid_t child, int threaded) +{ + if (threaded) { + (void) pthread_mutex_lock(&s->lock); + s->reader_go = 1; + (void) pthread_cond_signal(&s->rcv); + + while (!s->writer_go) + (void) pthread_cond_wait(&s->wcv, &s->lock); + s->writer_go = 0; + (void) pthread_mutex_unlock(&s->lock); + } else { + ssize_t bytes; + char b[1]; + + while ((bytes = write(s->reader_go_pipe[1], "", sizeof(""))) == -1 && + errno == EINTR) + ; + if (bytes == -1) { + kill(child, SIGKILL); + err(1, "Could not write to reader-go pipe (error)"); + } + if (bytes == 0) { + kill(child, SIGKILL); + err(1, "Could not write to reader-go pipe (EOF?)"); + } + + while ((bytes = read(s->writer_go_pipe[0], b, sizeof(b))) == -1 && + errno == EINTR) + ; + if (bytes == -1) { + kill(child, SIGKILL); + err(1, "Could not read from writer-go pipe"); + } + if (bytes == 0) { + kill(child, SIGKILL); + errx(1, "Child errored"); + } + s->writer_go = 0; + } +} + +static void +test_hdb_concurrency(char *name, const char *ext, int threaded) +{ + krb5_error_code ret; + krb5_context context; + char *fname = strchr(name, ':') + 1; + char *fname_ext = NULL; + pthread_t reader_thread; + struct tsync ts; + hdb_entry entw; + pid_t child = getpid(); + HDB *dbw = NULL; + int status; + int fd; + + memset(&ts, 0, sizeof(ts)); + (void) pthread_cond_init(&ts.rcv, NULL); + (void) pthread_cond_init(&ts.wcv, NULL); + (void) pthread_mutex_init(&ts.lock, NULL); + + if ((krb5_init_context(&context))) + errx(1, "krb5_init_context failed"); + + /* Use mkstemp() then unlink() to avoid warnings about mktemp(); ugh */ + if ((fd = mkstemp(fname)) == -1) + err(1, "mkstemp(%s)", fname); + (void) close(fd); + (void) unlink(fname); + if (asprintf(&fname_ext, "%s%s", fname, ext ? ext : "") == -1 || + fname_ext == NULL) + err(1, "Out of memory"); + ts.hdb_name = name; + ts.fname = fname_ext; + + if (threaded) { + printf("Starting reader thread\n"); + (void) pthread_mutex_lock(&ts.lock); + if ((errno = pthread_create(&reader_thread, NULL, threaded_reader, &ts))) { + (void) unlink(fname_ext); + krb5_err(context, 1, errno, "Could not create a thread to read HDB"); + } + + /* Wait for reader */ + while (!ts.writer_go) + (void) pthread_cond_wait(&ts.wcv, &ts.lock); + (void) pthread_mutex_unlock(&ts.lock); + } else { + printf("Starting reader process\n"); + if (pipe(ts.writer_go_pipe) == -1) + err(1, "Could not create a pipe"); + if (pipe(ts.reader_go_pipe) == -1) + err(1, "Could not create a pipe"); + switch ((child = fork())) { + case -1: err(1, "Could not fork a child"); + case 0: forked_reader(&ts); _exit(0); + default: break; + } + (void) close(ts.writer_go_pipe[1]); + ts.writer_go_pipe[1] = -1; + } + + printf("Writing two entries into HDB\n"); + if ((ret = hdb_create(context, &dbw, name))) + krb5_err(context, 1, ret, "Could not get a handle for HDB %s (write)", + name); + if ((ret = dbw->hdb_open(context, dbw, O_RDWR | O_CREAT, 0600))) + krb5_err(context, 1, ret, "Could not create HDB %s", name); + + /* Add two entries */ + memset(&entw, 0, sizeof(entw)); + if ((ret = make_entry(context, &entw, "foo")) || + (ret = dbw->hdb_store(context, dbw, 0, &entw))) { + (void) unlink(fname_ext); + krb5_err(context, 1, ret, + "Could not store entry for \"foo\" in HDB %s", name); + } + free_HDB_entry(&entw); + if ((ret = make_entry(context, &entw, "bar")) || + (ret = dbw->hdb_store(context, dbw, 0, &entw))) { + (void) unlink(fname_ext); + krb5_err(context, 1, ret, + "Could not store entry for \"foo\" in HDB %s", name); + } + free_HDB_entry(&entw); + + /* Tell the reader to start reading */ + readers_turn(&ts, child, threaded); + + /* Store one more entry */ + if ((ret = make_entry(context, &entw, "foobar")) || + (ret = dbw->hdb_store(context, dbw, 0, &entw))) { + (void) unlink(fname_ext); + krb5_err(context, 1, ret, + "Could not store entry for \"foobar\" in HDB %s " + "while iterating it", name); + } + free_HDB_entry(&entw); + + /* Tell the reader to go again */ + readers_turn(&ts, child, threaded); + + dbw->hdb_close(context, dbw); + dbw->hdb_destroy(context, dbw); + if (threaded) { + (void) pthread_join(reader_thread, NULL); + } else { + (void) close(ts.writer_go_pipe[1]); + (void) close(ts.reader_go_pipe[0]); + (void) close(ts.reader_go_pipe[1]); + while (wait(&status) == -1 && errno == EINTR) + ; + (void) close(ts.writer_go_pipe[0]); + if (!WIFEXITED(status)) + errx(1, "Child reader died"); + if (WEXITSTATUS(status) != 0) + errx(1, "Child reader errored"); + } + (void) unlink(fname_ext); + krb5_free_context(context); +} + +static int use_fork; +static int use_threads; +static int help_flag; +static int version_flag; + +struct getargs args[] = { + { "use-fork", 'f', arg_flag, &use_fork, NULL, NULL }, + { "use-threads", 't', arg_flag, &use_threads, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +int +main(int argc, char **argv) +{ + char stemplate[sizeof("sqlite:testhdb-XXXXXX")]; +#ifdef HAVE_LMDB + char ltemplate[sizeof("lmdb:testhdb-XXXXXX")]; +#endif + int o = 0; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &o)) + krb5_std_usage(1, args, num_args); + + if (help_flag) + krb5_std_usage(0, args, num_args); + + if (version_flag){ + print_version(NULL); + return 0; + } + + if (!use_fork && !use_threads) + use_threads = use_fork = 1; + +#ifdef HAVE_FORK + if (use_fork) { + printf("Testing SQLite3 HDB backend (multi-process)\n"); + memcpy(stemplate, "sqlite:testhdb-XXXXXX", sizeof("sqlite:testhdb-XXXXXX")); + test_hdb_concurrency(stemplate, "", 0); + +#ifdef HAVE_LMDB + printf("Testing LMDB HDB backend (multi-process)\n"); + memcpy(ltemplate, "lmdb:testhdb-XXXXXX", sizeof("lmdb:testhdb-XXXXXX")); + test_hdb_concurrency(ltemplate, ".lmdb", 0); +#endif + } +#endif + + if (use_threads) { + printf("Testing SQLite3 HDB backend (multi-process)\n"); + memcpy(stemplate, "sqlite:testhdb-XXXXXX", sizeof("sqlite:testhdb-XXXXXX")); + test_hdb_concurrency(stemplate, "", 1); + +#ifdef HAVE_LMDB + printf("Testing LMDB HDB backend (multi-process)\n"); + memcpy(ltemplate, "lmdb:testhdb-XXXXXX", sizeof("lmdb:testhdb-XXXXXX")); + test_hdb_concurrency(ltemplate, ".lmdb", 1); +#endif + } + return 0; +} diff --git a/third_party/heimdal/lib/hdb/test_dbinfo.c b/third_party/heimdal/lib/hdb/test_dbinfo.c new file mode 100644 index 0000000..195fd41 --- /dev/null +++ b/third_party/heimdal/lib/hdb/test_dbinfo.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#include + +static int help_flag; +static int version_flag; + +struct getargs args[] = { + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +/* + * Prove that HDB_EntryOrAlias being a CHOICE of hdb_entry or hdb_entry_alias + * adds nothing to the encoding of those types. + */ +static +void +check_HDB_EntryOrAlias(krb5_context context) +{ + HDB_EntryOrAlias eoa; + hdb_entry entry; + hdb_entry_alias alias; + krb5_data v; + size_t len; + int ret; + + memset(&entry, 0, sizeof(entry)); + memset(&alias, 0, sizeof(alias)); + memset(&eoa, 0, sizeof(eoa)); + krb5_data_zero(&v); + + ret = krb5_make_principal(context, &alias.principal, "KTH.SE", "foo", + NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_make_principal"); + ASN1_MALLOC_ENCODE(HDB_entry_alias, v.data, v.length, &alias, &len, ret); + if (ret) + krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias"); + if (v.length != len) + abort(); + ret = decode_HDB_EntryOrAlias(v.data, v.length, &eoa, &len); + if (ret) + krb5_err(context, 1, ret, "decode_HDB_EntryOrAlias"); + if (v.length != len) + abort(); + free_HDB_EntryOrAlias(&eoa); + free_HDB_entry_alias(&alias); + krb5_data_free(&v); + + ret = krb5_make_principal(context, &entry.principal, "KTH.SE", "foo", + NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_make_principal"); + entry.kvno = 5; + entry.flags.initial = 1; + ASN1_MALLOC_ENCODE(HDB_entry, v.data, v.length, &entry, &len, ret); + if (ret) + krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias"); + if (v.length != len) + abort(); + ret = decode_HDB_EntryOrAlias(v.data, v.length, &eoa, &len); + if (ret) + krb5_err(context, 1, ret, "decode_HDB_EntryOrAlias"); + if (v.length != len) + abort(); + free_HDB_EntryOrAlias(&eoa); + free_HDB_entry(&entry); + krb5_data_free(&v); +} + +int +main(int argc, char **argv) +{ + struct hdb_dbinfo *info, *d; + krb5_context context; + int ret, o = 0; + + setprogname(argv[0]); + + if(getarg(args, num_args, argc, argv, &o)) + krb5_std_usage(1, args, num_args); + + if(help_flag) + krb5_std_usage(0, args, num_args); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + ret = krb5_init_context(&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + check_HDB_EntryOrAlias(context); + + ret = hdb_get_dbinfo(context, &info); + if (ret) + krb5_err(context, 1, ret, "hdb_get_dbinfo"); + + d = NULL; + while ((d = hdb_dbinfo_get_next(info, d)) != NULL) { + const char *s; + s = hdb_dbinfo_get_label(context, d); + printf("label: %s\n", s ? s : "no label"); + s = hdb_dbinfo_get_realm(context, d); + printf("\trealm: %s\n", s ? s : "no realm"); + s = hdb_dbinfo_get_dbname(context, d); + printf("\tdbname: %s\n", s ? s : "no dbname"); + s = hdb_dbinfo_get_mkey_file(context, d); + printf("\tmkey_file: %s\n", s ? s : "no mkey file"); + s = hdb_dbinfo_get_acl_file(context, d); + printf("\tacl_file: %s\n", s ? s : "no acl file"); + } + + hdb_free_dbinfo(context, &info); + + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/test_hdbkeys.c b/third_party/heimdal/lib/hdb/test_hdbkeys.c new file mode 100644 index 0000000..d6bc31d --- /dev/null +++ b/third_party/heimdal/lib/hdb/test_hdbkeys.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hdb_locl.h" +#include +#include + +static int help_flag; +static int version_flag; +static int kvno_integer = 1; + +struct getargs args[] = { + { "kvno", 'd', arg_integer, &kvno_integer, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +int +main(int argc, char **argv) +{ + krb5_principal principal; + krb5_context context; + char *principal_str, *password_str, *str; + int ret, o = 0; + hdb_keyset keyset; + size_t length, len; + void *data; + + setprogname(argv[0]); + + if(getarg(args, num_args, argc, argv, &o)) + krb5_std_usage(1, args, num_args); + + if(help_flag) + krb5_std_usage(0, args, num_args); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + ret = krb5_init_context(&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + if (argc != 3) + errx(1, "username and password missing"); + + principal_str = argv[1]; + password_str = argv[2]; + + ret = krb5_parse_name (context, principal_str, &principal); + if (ret) + krb5_err (context, 1, ret, "krb5_parse_name %s", principal_str); + + memset(&keyset, 0, sizeof(keyset)); + + keyset.kvno = kvno_integer; + keyset.set_time = malloc(sizeof (*keyset.set_time)); + if (keyset.set_time == NULL) + errx(1, "couldn't allocate set_time field of keyset"); + *keyset.set_time = time(NULL); + + ret = hdb_generate_key_set_password(context, principal, password_str, + &keyset.keys.val, &len); + if (ret) + krb5_err(context, 1, ret, "hdb_generate_key_set_password"); + keyset.keys.len = len; + + if (keyset.keys.len == 0) + krb5_errx (context, 1, "hdb_generate_key_set_password length 0"); + + krb5_free_principal (context, principal); + + ASN1_MALLOC_ENCODE(HDB_keyset, data, length, &keyset, &len, ret); + if (ret) + krb5_errx(context, 1, "encode keyset"); + if (len != length) + krb5_abortx(context, "foo"); + + krb5_free_context(context); + + ret = rk_base64_encode(data, length, &str); + if (ret < 0) + errx(1, "base64_encode"); + + printf("keyset: %s\n", str); + + free(data); + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/test_mkey.c b/third_party/heimdal/lib/hdb/test_mkey.c new file mode 100644 index 0000000..97399c6 --- /dev/null +++ b/third_party/heimdal/lib/hdb/test_mkey.c @@ -0,0 +1,55 @@ + +#include "hdb_locl.h" +#include +#include + +static char *mkey_file; +static int help_flag; +static int version_flag; + +struct getargs args[] = { + { "mkey-file", 0, arg_string, &mkey_file, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +int +main(int argc, char **argv) +{ + krb5_context context; + int ret, o = 0; + + setprogname(argv[0]); + + if(getarg(args, num_args, argc, argv, &o)) + krb5_std_usage(1, args, num_args); + + if(help_flag) + krb5_std_usage(0, args, num_args); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context failed: %d", ret); + + if (mkey_file) { + hdb_master_key mkey; + + ret = hdb_read_master_key(context, mkey_file, &mkey); + if (ret) + krb5_err(context, 1, ret, "failed to read master key %s", mkey_file); + + hdb_free_master_key(context, mkey); + } else + krb5_errx(context, 1, "no command option given"); + + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/hdb/test_namespace.c b/third_party/heimdal/lib/hdb/test_namespace.c new file mode 100644 index 0000000..f9b4cdb --- /dev/null +++ b/third_party/heimdal/lib/hdb/test_namespace.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This program implements an ephemeral, memory-based HDB backend, stores into + * it just one HDB entry -one for a namespace- then checks that virtual + * principals are returned below that namespace by hdb_fetch_kvno(), and that + * the logic for automatic key rotation of virtual principals is correct. + */ + +#include "hdb_locl.h" +#include + +static KeyRotation krs[2]; +static const char *base_pw[2] = { "Testing123...", "Tested123..." }; + +typedef struct { + HDB hdb; /* generic members */ + /* + * Make this dict a global, add a mutex lock around it, and a .finit and/or + * atexit() handler to free it, and we'd have a first-class MEMORY HDB. + * + * What would a first-class MEMORY HDB be good for though, besides testing? + * + * However, we could move this dict into `HDB' and then have _hdb_store() + * and friends support it as a cache for frequently-used & seldom-changing + * entries, such as: K/M, namespaces, and krbtgt principals. That would + * speed up lookups, especially for backends with poor reader-writer + * concurrency (DB, LMDB) and LDAP. Such entries could be cached for a + * minute or three at a time. + */ + heim_dict_t dict; +} TEST_HDB; + +struct hdb_called { + int create; + int init; + int fini; +}; + +static krb5_error_code +TDB_close(krb5_context context, HDB *db) +{ + return 0; +} + +static krb5_error_code +TDB_destroy(krb5_context context, HDB *db) +{ + TEST_HDB *tdb = (void *)db; + + heim_release(tdb->dict); + free(tdb->hdb.hdb_name); + free(tdb); + return 0; +} + +static krb5_error_code +TDB_set_sync(krb5_context context, HDB *db, int on) +{ + return 0; +} + +static krb5_error_code +TDB_lock(krb5_context context, HDB *db, int operation) +{ + + return 0; +} + +static krb5_error_code +TDB_unlock(krb5_context context, HDB *db) +{ + + return 0; +} + +static krb5_error_code +TDB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + /* XXX Implement */ + /* Tricky thing: heim_dict_iterate_f() is inconvenient here */ + /* We need this to check that virtual principals aren't created */ + return 0; +} + +static krb5_error_code +TDB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) +{ + /* XXX Implement */ + /* Tricky thing: heim_dict_iterate_f() is inconvenient here */ + /* We need this to check that virtual principals aren't created */ + return 0; +} + +static krb5_error_code +TDB_rename(krb5_context context, HDB *db, const char *new_name) +{ + return EEXIST; +} + +static krb5_error_code +TDB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + krb5_error_code ret = 0; + TEST_HDB *tdb = (void *)db; + heim_object_t k, v = NULL; + + if ((k = heim_data_create(key.data, key.length)) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && (v = heim_dict_get_value(tdb->dict, k)) == NULL) + ret = HDB_ERR_NOENTRY; + if (ret == 0) + ret = krb5_data_copy(reply, heim_data_get_ptr(v), heim_data_get_length(v)); + heim_release(k); + return ret; +} + +static krb5_error_code +TDB__put(krb5_context context, HDB *db, int rplc, krb5_data kd, krb5_data vd) +{ + krb5_error_code ret = 0; + TEST_HDB *tdb = (void *)db; + heim_object_t k = NULL; + heim_object_t v = NULL; + + if ((k = heim_data_create(kd.data, kd.length)) == NULL || + (v = heim_data_create(vd.data, vd.length)) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && !rplc && heim_dict_get_value(tdb->dict, k) != NULL) + ret = HDB_ERR_EXISTS; + if (ret == 0 && heim_dict_set_value(tdb->dict, k, v)) + ret = krb5_enomem(context); + heim_release(k); + heim_release(v); + return ret; +} + +static krb5_error_code +TDB__del(krb5_context context, HDB *db, krb5_data key) +{ + krb5_error_code ret = 0; + TEST_HDB *tdb = (void *)db; + heim_object_t k; + + if ((k = heim_data_create(key.data, key.length)) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && heim_dict_get_value(tdb->dict, k) == NULL) + ret = HDB_ERR_NOENTRY; + if (ret == 0) + heim_dict_delete_key(tdb->dict, k); + heim_release(k); + return ret; +} + +static krb5_error_code +TDB_open(krb5_context context, HDB *db, int flags, mode_t mode) +{ + return 0; +} + +static krb5_error_code +hdb_test_create(krb5_context context, struct HDB **db, const char *arg) +{ + TEST_HDB *tdb; + + if ((tdb = calloc(1, sizeof(tdb[0]))) == NULL || + (tdb->hdb.hdb_name = strdup(arg)) == NULL || + (tdb->dict = heim_dict_create(10)) == NULL) { + if (tdb) + free(tdb->hdb.hdb_name); + free(tdb); + return krb5_enomem(context); + } + + tdb->hdb.hdb_db = NULL; + tdb->hdb.hdb_master_key_set = 0; + tdb->hdb.hdb_openp = 0; + tdb->hdb.hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; + tdb->hdb.hdb_open = TDB_open; + tdb->hdb.hdb_close = TDB_close; + tdb->hdb.hdb_fetch_kvno = _hdb_fetch_kvno; + tdb->hdb.hdb_store = _hdb_store; + tdb->hdb.hdb_remove = _hdb_remove; + tdb->hdb.hdb_firstkey = TDB_firstkey; + tdb->hdb.hdb_nextkey= TDB_nextkey; + tdb->hdb.hdb_lock = TDB_lock; + tdb->hdb.hdb_unlock = TDB_unlock; + tdb->hdb.hdb_rename = TDB_rename; + tdb->hdb.hdb__get = TDB__get; + tdb->hdb.hdb__put = TDB__put; + tdb->hdb.hdb__del = TDB__del; + tdb->hdb.hdb_destroy = TDB_destroy; + tdb->hdb.hdb_set_sync = TDB_set_sync; + *db = &tdb->hdb; + + return 0; +} + +static krb5_error_code +hdb_test_init(krb5_context context, void **ctx) +{ + *ctx = NULL; + return 0; +} + +static void hdb_test_fini(void *ctx) +{ +} + +struct hdb_method hdb_test = +{ +#ifdef WIN32 + /* Not c99 */ + HDB_INTERFACE_VERSION, + hdb_test_init, + hdb_test_fini, + 1 /*is_file_based*/, 1 /*can_taste*/, + "test", + hdb_test_create +#else + .minor_version = HDB_INTERFACE_VERSION, + .init = hdb_test_init, + .fini = hdb_test_fini, + .is_file_based = 1, + .can_taste = 1, + .prefix = "test", + .create = hdb_test_create +#endif +}; + +static krb5_error_code +make_base_key(krb5_context context, + krb5_const_principal p, + const char *pw, + krb5_keyblock *k) +{ + return krb5_string_to_key(context, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + pw, p, k); +} + +static krb5_error_code +tderive_key(krb5_context context, + const char *p, + KeyRotation *kr, + int toffset, + krb5_keyblock *base, + krb5int32 etype, + krb5_keyblock *k, + uint32_t *kvno, + time_t *set_time) +{ + krb5_error_code ret = 0; + krb5_crypto crypto = NULL; + EncryptionKey intermediate; + krb5_data pad, out; + size_t len; + int n; + + n = toffset / kr->period; + *set_time = kr->epoch + kr->period * n; + *kvno = kr->base_kvno + n; + + out.data = 0; + out.length = 0; + + /* Derive intermediate key */ + pad.data = (void *)(uintptr_t)p; + pad.length = strlen(p); + ret = krb5_enctype_keysize(context, base->keytype, &len); + if (ret == 0) + ret = krb5_crypto_init(context, base, 0, &crypto); + if (ret == 0) + ret = krb5_crypto_prfplus(context, crypto, &pad, len, &out); + if (crypto) + krb5_crypto_destroy(context, crypto); + crypto = NULL; + if (ret == 0) + ret = krb5_random_to_key(context, etype, out.data, out.length, + &intermediate); + krb5_data_free(&out); + + /* Derive final key */ + pad.data = kvno; + pad.length = sizeof(*kvno); + if (ret == 0) + ret = krb5_enctype_keysize(context, etype, &len); + if (ret == 0) + ret = krb5_crypto_init(context, &intermediate, 0, &crypto); + if (ret == 0) { + *kvno = htonl(*kvno); + ret = krb5_crypto_prfplus(context, crypto, &pad, len, &out); + *kvno = ntohl(*kvno); + } + if (crypto) + krb5_crypto_destroy(context, crypto); + if (ret == 0) + ret = krb5_random_to_key(context, etype, out.data, out.length, k); + krb5_data_free(&out); + + free_EncryptionKey(&intermediate); + return ret; +} + +/* Create a namespace principal */ +static void +make_namespace(krb5_context context, HDB *db, const char *name) +{ + krb5_error_code ret = 0; + hdb_entry e; + Key k; + + memset(&k, 0, sizeof(k)); + k.mkvno = 0; + k.salt = 0; + + /* Setup the HDB entry */ + memset(&e, 0, sizeof(e)); + e.created_by.time = krs[0].epoch; + e.valid_start = e.valid_end = e.pw_end = 0; + e.generation = 0; + e.flags = int2HDBFlags(0); + e.flags.server = e.flags.client = 1; + e.flags.virtual = 1; + + /* Setup etypes */ + if (ret == 0 && + (e.etypes = malloc(sizeof(*e.etypes))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + e.etypes->len = 3; + if (ret == 0 && + (e.etypes->val = calloc(e.etypes->len, + sizeof(e.etypes->val[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) { + e.etypes->val[0] = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128; + e.etypes->val[1] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192; + e.etypes->val[2] = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96; + } + + /* Setup max_life and max_renew */ + if (ret == 0 && + (e.max_life = malloc(sizeof(*e.max_life))) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && + (e.max_renew = malloc(sizeof(*e.max_renew))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + /* Make it long, so we see the clamped max */ + *e.max_renew = 2 * ((*e.max_life = 15 * 24 * 3600)); + + /* Setup principal name and created_by */ + if (ret == 0) + ret = krb5_parse_name(context, name, &e.principal); + if (ret == 0) + ret = krb5_parse_name(context, "admin@BAR.EXAMPLE", + &e.created_by.principal); + + /* Make base keys for first epoch */ + if (ret == 0) + ret = make_base_key(context, e.principal, base_pw[0], &k.key); + if (ret == 0) + add_Keys(&e.keys, &k); + if (ret == 0) + ret = hdb_entry_set_pw_change_time(context, &e, krs[0].epoch); + free_Key(&k); + e.kvno = krs[0].base_key_kvno; + + /* Move them to history */ + if (ret == 0) + ret = hdb_add_current_keys_to_history(context, &e); + free_Keys(&e.keys); + + /* Make base keys for second epoch */ + if (ret == 0) + ret = make_base_key(context, e.principal, base_pw[1], &k.key); + if (ret == 0) + add_Keys(&e.keys, &k); + e.kvno = krs[1].base_key_kvno; + if (ret == 0) + ret = hdb_entry_set_pw_change_time(context, &e, krs[1].epoch); + + /* Add the key rotation metadata */ + if (ret == 0) + ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[0]); + if (ret == 0) + ret = hdb_entry_add_key_rotation(context, &e, 0, &krs[1]); + + if (ret == 0) + ret = db->hdb_store(context, db, 0, &e); + if (ret) + krb5_err(context, 1, ret, "failed to setup a namespace principal"); + free_Key(&k); + hdb_free_entry(context, db, &e); +} + +#define WK_PREFIX "WELLKNOWN/" HDB_WK_NAMESPACE "/" + +static const char *expected[] = { + WK_PREFIX "_/bar.example@BAR.EXAMPLE", + "HTTP/bar.example@BAR.EXAMPLE", + "HTTP/foo.bar.example@BAR.EXAMPLE", + "host/foo.bar.example@BAR.EXAMPLE", + "HTTP/blah.foo.bar.example@BAR.EXAMPLE", +}; +static const char *unexpected[] = { + WK_PREFIX "_/no.example@BAZ.EXAMPLE", + "HTTP/no.example@BAR.EXAMPLE", + "HTTP/foo.no.example@BAR.EXAMPLE", + "HTTP/blah.foo.no.example@BAR.EXAMPLE", +}; + +/* + * We'll fetch as many entries as we have principal names in `expected[]', for + * as many KeyRotation periods as we have (between 1 and 3), and for up to 5 + * different time offsets in each period. + */ +#define NUM_OFFSETS 5 +static hdb_entry e[ + (sizeof(expected) / sizeof(expected[0])) * + (sizeof(krs) / sizeof(krs[0])) * + NUM_OFFSETS +]; + +static int +hist_key_compar(const void *va, const void *vb) +{ + const hdb_keyset *a = va; + const hdb_keyset *b = vb; + + return a->kvno - b->kvno; +} + +/* + * Fetch keys for some decent time in the given kr. + * + * `kr' is an index into the global `krs[]'. + * `t' is a number 0..4 inclusive that identifies a time period relative to the + * epoch of `krs[kr]' (see code below). + */ +static void +fetch_entries(krb5_context context, + HDB *db, + size_t kr, + size_t t, + int must_fail) +{ + krb5_error_code ret = 0; + krb5_principal p = NULL; + krb5_keyblock base_key, dk; + hdb_entry *ep; + hdb_entry no; + size_t i, b; + int toffset = 0; + + memset(&base_key, 0, sizeof(base_key)); + + /* Work out offset of first entry in `e[]' */ + assert(kr < sizeof(krs) / sizeof(krs[0])); + assert(t < NUM_OFFSETS); + b = (kr * NUM_OFFSETS + t) * (sizeof(expected) / sizeof(expected[0])); + assert(b < sizeof(e) / sizeof(e[0])); + assert(sizeof(e) / sizeof(e[0]) - b >= + (sizeof(expected) / sizeof(expected[0]))); + + switch (t) { + case 0: toffset = 1; break; /* epoch + 1s */ + case 1: toffset = 1 + (krs[kr].period >> 1); break; /* epoch + period/2 */ + case 2: toffset = 1 + (krs[kr].period >> 2); break; /* epoch + period/4 */ + case 3: toffset = 1 + (krs[kr].period >> 3); break; /* epoch + period/8 */ + case 4: toffset = 1 - (krs[kr].period >> 3); break; /* epoch - period/8 */ + } + + for (i = 0; ret == 0 && i < sizeof(expected) / sizeof(expected[0]); i++) { + ep = &e[b + i]; + memset(ep, 0, sizeof(*ep)); + if (ret == 0) + ret = krb5_parse_name(context, expected[i], &p); + if (ret == 0 && i == 0) { + if (toffset < 0 && kr) + ret = make_base_key(context, p, base_pw[kr - 1], &base_key); + else + ret = make_base_key(context, p, base_pw[kr], &base_key); + } + if (ret == 0) + ret = hdb_fetch_kvno(context, db, p, + HDB_F_DECRYPT | HDB_F_ALL_KVNOS, + krs[kr].epoch + toffset, 0, 0, ep); + if (i && must_fail && ret == 0) + krb5_errx(context, 1, + "virtual principal that shouldn't exist does"); + if (kr == 0 && toffset < 0 && ret == HDB_ERR_NOENTRY) + continue; + if (kr == 0 && toffset < 0) { + /* + * Virtual principals don't exist before their earliest key + * rotation epoch's start time. + */ + if (i == 0) { + if (ret) + krb5_errx(context, 1, + "namespace principal does not exist before its time"); + } else if (i != 0) { + if (ret == 0) + krb5_errx(context, 1, + "virtual principal exists before its time"); + if (ret != HDB_ERR_NOENTRY) + krb5_errx(context, 1, "wrong error code"); + ret = 0; + } + } else { + if (ret == 0 && + !krb5_principal_compare(context, p, ep->principal)) + krb5_errx(context, 1, "wrong principal in fetched entry"); + } + + { + HDB_Ext_KeySet *hist_keys; + HDB_extension *ext; + ext = hdb_find_extension(ep, + choice_HDB_extension_data_hist_keys); + if (ext) { + /* Sort key history by kvno, why not */ + hist_keys = &ext->data.u.hist_keys; + qsort(hist_keys->val, hist_keys->len, + sizeof(hist_keys->val[0]), hist_key_compar); + } + } + + krb5_free_principal(context, p); + } + if (ret && must_fail) { + free_EncryptionKey(&base_key); + return; + } + if (ret) + krb5_err(context, 1, ret, "virtual principal test failed"); + + for (i = 0; i < sizeof(unexpected) / sizeof(unexpected[0]); i++) { + memset(&no, 0, sizeof(no)); + if (ret == 0) + ret = krb5_parse_name(context, unexpected[i], &p); + if (ret == 0) + ret = hdb_fetch_kvno(context, db, p, HDB_F_DECRYPT, + krs[kr].epoch + toffset, 0, 0, &no); + if (ret == 0) + krb5_errx(context, 1, "bogus principal exists, wat"); + krb5_free_principal(context, p); + ret = 0; + } + + if (kr == 0 && toffset < 0) + return; + + /* + * XXX + * + * Add check that derived keys are a) different, b) as expected, using a + * set of test vectors or else by computing the expected keys here with + * code that's not shared with lib/hdb/common.c. + * + * Add check that we get expected past and/or future keys, not just current + * keys. + */ + for (i = 1; ret == 0 && i < sizeof(expected) / sizeof(expected[0]); i++) { + uint32_t kvno; + time_t set_time, chg_time; + + ep = &e[b + i]; + if (toffset > 0) { + ret = tderive_key(context, expected[i], &krs[kr], toffset, + &base_key, base_key.keytype, &dk, &kvno, &set_time); + } else /* XXX */{ + /* XXX */ + assert(kr); + ret = tderive_key(context, expected[i], &krs[kr - 1], + krs[kr].epoch - krs[kr - 1].epoch + toffset, + &base_key, base_key.keytype, &dk, &kvno, &set_time); + } + if (ret) + krb5_err(context, 1, ret, "deriving keys for comparison"); + + if (kvno != ep->kvno) + krb5_errx(context, 1, "kvno mismatch (%u != %u)", kvno, ep->kvno); + (void) hdb_entry_get_pw_change_time(ep, &chg_time); + if (set_time != chg_time) + krb5_errx(context, 1, "key change time mismatch"); + if (ep->keys.len == 0) + krb5_errx(context, 1, "no keys!"); + if (ep->keys.val[0].key.keytype != dk.keytype) + krb5_errx(context, 1, "enctype mismatch!"); + if (ep->keys.val[0].key.keyvalue.length != + dk.keyvalue.length) + krb5_errx(context, 1, "key length mismatch!"); + if (memcmp(ep->keys.val[0].key.keyvalue.data, + dk.keyvalue.data, dk.keyvalue.length) != 0) + krb5_errx(context, 1, "key mismatch!"); + if (memcmp(ep->keys.val[0].key.keyvalue.data, + e[b + i - 1].keys.val[0].key.keyvalue.data, + dk.keyvalue.length) == 0) + krb5_errx(context, 1, "different virtual principals have the same keys!"); + /* XXX Add check that we have the expected number of history keys */ + free_EncryptionKey(&dk); + } + free_EncryptionKey(&base_key); +} + +static void +check_kvnos(krb5_context context) +{ + HDB_Ext_KeySet keysets; + size_t i, k, m, p; /* iterator indices */ + + keysets.len = 0; + keysets.val = 0; + + /* For every principal name */ + for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++) { + free_HDB_Ext_KeySet(&keysets); + + /* For every entry we've fetched for it */ + for (k = 0; k < sizeof(e)/sizeof(e[0]); k++) { + HDB_Ext_KeySet *hist_keys; + HDB_extension *ext; + hdb_entry *ep; + int match = 0; + + if ((k % NUM_OFFSETS) != i) + continue; + + ep = &e[k]; + if (ep->principal == NULL) + continue; /* Didn't fetch this one */ + + /* + * Check that the current keys for it match what we've seen already + * or else add them to `keysets'. + */ + for (m = 0; m < keysets.len; m++) { + if (ep->kvno == keysets.val[m].kvno) { + /* Check the key is the same */ + if (ep->keys.val[0].key.keytype != + keysets.val[m].keys.val[0].key.keytype || + ep->keys.val[0].key.keyvalue.length != + keysets.val[m].keys.val[0].key.keyvalue.length || + memcmp(ep->keys.val[0].key.keyvalue.data, + keysets.val[m].keys.val[0].key.keyvalue.data, + ep->keys.val[0].key.keyvalue.length) != 0) + krb5_errx(context, 1, + "key mismatch for same princ & kvno"); + match = 1; + } + } + if (m == keysets.len) { + hdb_keyset ks; + + ks.kvno = ep->kvno; + ks.keys = ep->keys; + ks.set_time = 0; + if (add_HDB_Ext_KeySet(&keysets, &ks)) + krb5_err(context, 1, ENOMEM, "out of memory"); + match = 1; + } + if (match) + continue; + + /* For all non-current keysets, repeat the above */ + ext = hdb_find_extension(ep, + choice_HDB_extension_data_hist_keys); + if (!ext) + continue; + hist_keys = &ext->data.u.hist_keys; + for (p = 0; p < hist_keys->len; p++) { + for (m = 0; m < keysets.len; m++) { + if (keysets.val[m].kvno == hist_keys->val[p].kvno) + if (ep->keys.val[0].key.keytype != + keysets.val[m].keys.val[0].key.keytype || + ep->keys.val[0].key.keyvalue.length != + keysets.val[m].keys.val[0].key.keyvalue.length || + memcmp(ep->keys.val[0].key.keyvalue.data, + keysets.val[m].keys.val[0].key.keyvalue.data, + ep->keys.val[0].key.keyvalue.length) != 0) + krb5_errx(context, 1, + "key mismatch for same princ & kvno"); + } + if (m == keysets.len) { + hdb_keyset ks; + ks.kvno = ep->kvno; + ks.keys = ep->keys; + ks.set_time = 0; + if (add_HDB_Ext_KeySet(&keysets, &ks)) + krb5_err(context, 1, ENOMEM, "out of memory"); + } + } + } + } + free_HDB_Ext_KeySet(&keysets); +} + +static void +print_em(krb5_context context) +{ + HDB_Ext_KeySet *hist_keys; + HDB_extension *ext; + size_t i, p; + + for (i = 0; i < sizeof(e)/sizeof(e[0]); i++) { + const char *name = expected[i % (sizeof(expected)/sizeof(expected[0]))]; + char *x; + + if (0 == i % (sizeof(expected)/sizeof(expected[0]))) + continue; + if (e[i].principal == NULL) + continue; + hex_encode(e[i].keys.val[0].key.keyvalue.data, + e[i].keys.val[0].key.keyvalue.length, &x); + printf("%s %u %s\n", x, e[i].kvno, name); + free(x); + + ext = hdb_find_extension(&e[i], choice_HDB_extension_data_hist_keys); + if (!ext) + continue; + hist_keys = &ext->data.u.hist_keys; + for (p = 0; p < hist_keys->len; p++) { + hex_encode(hist_keys->val[p].keys.val[0].key.keyvalue.data, + hist_keys->val[p].keys.val[0].key.keyvalue.length, &x); + printf("%s %u %s\n", x, hist_keys->val[p].kvno, name); + free(x); + } + } +} + +#if 0 +static void +check_expected_kvnos(krb5_context context) +{ + HDB_Ext_KeySet *hist_keys; + HDB_extension *ext; + size_t i, k, m, p; + + for (i = 0; i < sizeof(expected)/sizeof(expected[0]); i++) { + for (k = 0; k < sizeof(krs)/sizeof(krs[0]); k++) { + hdb_entry *ep = &e[k * sizeof(expected)/sizeof(expected[0]) + i]; + + if (ep->principal == NULL) + continue; + for (m = 0; m < NUM_OFFSETS; m++) { + ext = hdb_find_extension(ep, + choice_HDB_extension_data_hist_keys); + if (!ext) + continue; + hist_keys = &ext->data.u.hist_keys; + for (p = 0; p < hist_keys->len; p++) { + fprintf(stderr, "%s at %lu, %lu: history kvno %u\n", + expected[i], k, m, hist_keys->val[p].kvno); + } + } + fprintf(stderr, "%s at %lu: kvno %u\n", expected[i], k, + ep->kvno); + } + } +} +#endif + +#define SOME_TIME 1596318329 +#define SOME_BASE_KVNO 150 +#define SOME_EPOCH (SOME_TIME - (7 * 24 * 3600) - (SOME_TIME % (7 * 24 * 3600))) +#define SOME_PERIOD 3600 + +#define CONF \ + "[hdb]\n" \ + "\tenable_virtual_hostbased_princs = true\n" \ + "\tvirtual_hostbased_princ_mindots = 1\n" \ + "\tvirtual_hostbased_princ_maxdots = 3\n" \ + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + size_t i; + HDB *db = NULL; + + setprogname(argv[0]); + memset(e, 0, sizeof(e)); + ret = krb5_init_context(&context); + if (ret == 0) + ret = krb5_set_config(context, CONF); + if (ret == 0) + ret = krb5_plugin_register(context, PLUGIN_TYPE_DATA, "hdb_test_interface", + &hdb_test); + if (ret == 0) + ret = hdb_create(context, &db, "test:mem"); + if (ret) + krb5_err(context, 1, ret, "failed to setup HDB driver and test"); + + assert(db->enable_virtual_hostbased_princs); + assert(db->virtual_hostbased_princ_ndots == 1); + assert(db->virtual_hostbased_princ_maxdots == 3); + + /* Setup key rotation metadata in a convenient way */ + /* + * FIXME Reorder these two KRs to match how we store them to avoid + * confusion. #0 should be future-most, #1 should past-post. + */ + krs[0].flags = krs[1].flags = int2KeyRotationFlags(0); + krs[0].epoch = SOME_EPOCH - 20 * 24 * 3600; + krs[0].period = SOME_PERIOD >> 1; + krs[0].base_kvno = 150; + krs[0].base_key_kvno = 1; + krs[1].epoch = SOME_TIME; + krs[1].period = SOME_PERIOD; + krs[1].base_kvno = krs[0].base_kvno + 1 + (krs[1].epoch + (krs[0].period - 1) - krs[0].epoch) / krs[0].period; + krs[1].base_key_kvno = 2; + + { + HDB_Ext_KeyRotation existing_krs, new_krs; + KeyRotation ordered_krs[2]; + + ordered_krs[0] = krs[1]; + ordered_krs[1] = krs[0]; + existing_krs.len = 0; + existing_krs.val = 0; + new_krs.len = 1; + new_krs.val = &ordered_krs[1]; + if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) || + (ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs))) + krb5_err(context, 1, ret, "Valid KeyRotation thought invalid"); + new_krs.len = 1; + new_krs.val = &ordered_krs[0]; + if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) || + (ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs))) + krb5_err(context, 1, ret, "Valid KeyRotation thought invalid"); + new_krs.len = 2; + new_krs.val = &ordered_krs[0]; + if ((ret = hdb_validate_key_rotations(context, NULL, &new_krs)) || + (ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs))) + krb5_err(context, 1, ret, "Valid KeyRotation thought invalid"); + existing_krs.len = 1; + existing_krs.val = &ordered_krs[1]; + if ((ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs))) + krb5_err(context, 1, ret, "Valid KeyRotation thought invalid"); + existing_krs.len = 2; + existing_krs.val = &ordered_krs[0]; + if ((ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs))) + krb5_err(context, 1, ret, "Valid KeyRotation thought invalid"); + + new_krs.len = 2; + new_krs.val = &krs[0]; + if ((ret = hdb_validate_key_rotations(context, &existing_krs, + &new_krs)) == 0) + krb5_errx(context, 1, "Invalid KeyRotation thought valid"); + } + + make_namespace(context, db, WK_PREFIX "_/bar.example@BAR.EXAMPLE"); + + fetch_entries(context, db, 1, 0, 0); + fetch_entries(context, db, 1, 1, 0); + fetch_entries(context, db, 1, 2, 0); + fetch_entries(context, db, 1, 3, 0); + fetch_entries(context, db, 1, 4, 0); /* Just before newest KR */ + + fetch_entries(context, db, 0, 0, 0); + fetch_entries(context, db, 0, 1, 0); + fetch_entries(context, db, 0, 2, 0); + fetch_entries(context, db, 0, 3, 0); + fetch_entries(context, db, 0, 4, 1); /* Must fail: just before 1st KR */ + + /* + * Check that for every virtual principal in `expected[]', all the keysets + * with the same kvno, in all the entries fetched for different times, + * match. + */ + check_kvnos(context); + +#if 0 + /* + * Check that for every virtual principal in `expected[]' we have the + * expected key history. + */ + check_expected_kvnos(context); +#endif + + /* + * XXX Add various tests here, checking `e[]': + * + * - Extract all {principal, kvno, key} for all keys, current and + * otherwise, then sort by {key, kvno, principal}, then check that the + * only time we have matching keys is when the kvno and principal also + * match. + */ + + print_em(context); + + /* + * XXX Test adding a third KR, a 4th KR, dropping KRs... + */ + + /* Cleanup */ + for (i = 0; ret == 0 && i < sizeof(e) / sizeof(e[0]); i++) + hdb_free_entry(context, db, &e[i]); + db->hdb_destroy(context, db); + krb5_free_context(context); + return 0; +} diff --git a/third_party/heimdal/lib/hdb/version-script.map b/third_party/heimdal/lib/hdb/version-script.map new file mode 100644 index 0000000..058060d --- /dev/null +++ b/third_party/heimdal/lib/hdb/version-script.map @@ -0,0 +1,189 @@ +# $Id$ + +HEIMDAL_HDB_1.0 { + global: + _hdb_fetch_kvno; + _hdb_remove; + _hdb_store; + hdb_add_current_keys_to_history; + hdb_add_history_key; + hdb_add_history_keyset; + hdb_add_master_key; + hdb_change_kvno; + hdb_check_db_format; + hdb_clear_extension; + hdb_clear_master_key; + hdb_create; + hdb_db_dir; + hdb_dbinfo_get_acl_file; + hdb_dbinfo_get_binding; + hdb_dbinfo_get_dbname; + hdb_dbinfo_get_label; + hdb_dbinfo_get_log_file; + hdb_dbinfo_get_mkey_file; + hdb_dbinfo_get_next; + hdb_dbinfo_get_realm; + hdb_default_db; + hdb_derive_etypes; + hdb_enctype2key; + hdb_entry2string; + hdb_entry2value; + hdb_entry_add_key_rotation; + hdb_entry_alias2value; + hdb_entry_check_mandatory; + hdb_entry_clear_password; + hdb_entry_get_ConstrainedDelegACL; + hdb_entry_get_aliases; + hdb_entry_get_key_rotation; + hdb_entry_get_krb5_config; + hdb_entry_get_password; + hdb_entry_get_pkinit_acl; + hdb_entry_get_pkinit_cert; + hdb_entry_get_pkinit_hash; + hdb_entry_get_pw_change_time; + hdb_entry_set_krb5_config; + hdb_entry_set_password; + hdb_entry_set_pw_change_time; + hdb_fetch_kvno; + hdb_find_extension; + hdb_foreach; + hdb_free_dbinfo; + hdb_free_entry; + hdb_free_key; + hdb_free_keys; + hdb_free_master_key; + hdb_generate_key_set; + hdb_generate_key_set_password; + hdb_generate_key_set_password_with_ks_tuple; + hdb_get_dbinfo; + hdb_get_instance; + hdb_init_db; + hdb_install_keyset; + hdb_key2principal; + hdb_kvno2keys; + hdb_list_builtin; + hdb_lock; + hdb_next_enctype2key; + hdb_principal2key; + hdb_print_entry; + hdb_process_master_key; + hdb_prune_keys; + hdb_prune_keys_kvno; + hdb_read_master_key; + hdb_remove_keys; + hdb_replace_extension; + hdb_seal_key; + hdb_seal_key_mkey; + hdb_seal_keys; + hdb_seal_keys_mkey; + hdb_set_last_modified_by; + hdb_set_master_key; + hdb_set_master_keyfile; + hdb_unlock; + hdb_unseal_key; + hdb_unseal_key_mkey; + hdb_unseal_keys; + hdb_unseal_keys_kvno; + hdb_unseal_keys_mkey; + hdb_validate_key_rotation; + hdb_validate_key_rotations; + hdb_value2entry; + hdb_value2entry_alias; + hdb_write_master_key; + length_hdb_keyset; + length_HDB_keyset; + hdb_interface_version; + initialize_hdb_error_table_r; + + # MIT KDB related entries + _hdb_mdb_value2entry; + _hdb_mit_dump2mitdb_entry; + + hdb_kt_ops; + hdb_get_kt_ops; + + # some random bits needed for libkadm + add_HDB_Ext_KeyRotation; + add_HDB_Ext_KeySet; + add_HDB_Ext_KeySet; + add_Keys; + add_Keys; + asn1_HDBFlags_units; + copy_Event; + copy_HDB_EncTypeList; + copy_hdb_entry; + copy_hdb_entry_alias; + copy_HDB_entry; + copy_HDB_entry_alias; + copy_HDB_EntryOrAlias; + copy_HDB_extensions; + copy_HDB_Ext_KeyRotation; + copy_Key; + copy_Keys; + copy_Salt; + decode_HDB_EncTypeList; + decode_hdb_entry; + decode_hdb_entry_alias; + decode_HDB_entry; + decode_HDB_entry_alias; + decode_HDB_EntryOrAlias; + decode_HDB_Ext_Aliases; + decode_HDB_extension; + decode_HDB_Ext_KeyRotation; + decode_HDB_Ext_PKINIT_acl; + decode_Key; + decode_Keys; + encode_HDB_EncTypeList; + encode_hdb_entry; + encode_hdb_entry_alias; + encode_HDB_entry; + encode_HDB_entry_alias; + encode_HDB_EntryOrAlias; + encode_HDB_Ext_Aliases; + encode_HDB_extension; + encode_HDB_Ext_KeyRotation; + encode_HDB_Ext_PKINIT_acl; + encode_hdb_keyset; + encode_HDB_keyset; + encode_Key; + encode_Keys; + free_Event; + free_HDB_EncTypeList; + free_hdb_entry; + free_hdb_entry_alias; + free_HDB_entry; + free_HDB_entry_alias; + free_HDB_EntryOrAlias; + free_HDB_Ext_Aliases; + free_HDB_extension; + free_HDB_extensions; + free_HDB_Ext_KeyRotation; + free_HDB_Ext_KeySet; + free_HDB_Ext_PKINIT_acl; + free_hdb_keyset; + free_HDB_keyset; + free_Key; + free_Keys; + free_Salt; + HDBFlags2int; + int2HDBFlags; + int2KeyRotationFlags; + KeyRotationFlags2int; + length_HDB_EncTypeList; + length_hdb_entry; + length_hdb_entry_alias; + length_HDB_entry; + length_HDB_entry_alias; + length_HDB_EntryOrAlias; + length_HDB_Ext_Aliases; + length_HDB_extension; + length_HDB_Ext_KeyRotation; + length_HDB_Ext_PKINIT_acl; + length_Key; + length_Keys; + remove_HDB_Ext_KeyRotation; + remove_Keys; + + local: + *; +}; diff --git a/third_party/heimdal/lib/heimdal/NTMakefile b/third_party/heimdal/lib/heimdal/NTMakefile new file mode 100644 index 0000000..dc7d459 --- /dev/null +++ b/third_party/heimdal/lib/heimdal/NTMakefile @@ -0,0 +1,98 @@ +######################################################################## +# +# Copyright (c) 2009, 2010 Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR = lib\heimdal + +!include ../../windows/NTMakefile.w32 + +!ifndef STATICLIBS + +DLLDEPS= \ + $(LIBASN1) \ + $(LIBCOMERR) \ + $(LIBHCRYPTO) \ + $(LIBHX509) \ + $(LIBKRB5) \ + $(LIBROKEN) \ + $(LIBSQLITE) \ + $(LIBWIND) \ + $(LIBLTM) \ + $(LIBX25519) \ + $(LIBHEIMBASE) + +DLLSDKDEPS= \ + $(PTHREAD_LIB) \ + secur32.lib \ + shell32.lib \ + dnsapi.lib \ + shlwapi.lib \ + version.lib + + +dlllflags=$(dlllflags) /DELAYLOAD:bcrypt.dll +DLLSDKDEPS=$(DLLSDKDEPS)\ + bcrypt.lib \ + delayimp.lib + +DEF=$(OBJ)\heimdal.def + +RES=$(OBJ)\heimdal-version.res + +DEFSRC= ..\asn1\libasn1-exports.def \ + ..\wind\libwind-exports.def \ + ..\hcrypto\libhcrypto-exports.def \ + ..\hx509\libhx509-exports.def \ + $(OBJDIR)\lib\krb5\libkrb5-exports.def + +$(DEF): $(DEFSRC) + copy $(DEFSRC: = + ) $(DEF) + +DLL=$(BINDIR)\heimdal.dll + +$(LIBHEIMDAL): $(BINDIR)\heimdal.dll + +$(DLL): $(DLLDEPS) $(DEF) $(RES) + $(DLLGUILINK_C) $(DLLDEPS) $(DLLSDKDEPS) $(RES) \ + -def:$(DEF) -out:$(DLL) \ + -implib:$(LIBHEIMDAL) + $(DLLPREP_NODIST) + +clean:: + -$(RM) $(BINDIR)\heimdal.* + +!else + +$(LIBHEIMDAL): $(LIBASN1) $(LIBWIND) $(LIBHCRYPTO) $(LIBHX509) $(LIBKRB5) $(LIBHEIMBASE) + $(LIBCON) + +!endif + +all:: $(LIBHEIMDAL) diff --git a/third_party/heimdal/lib/heimdal/heimdal-version.rc b/third_party/heimdal/lib/heimdal/heimdal-version.rc new file mode 100644 index 0000000..1da512c --- /dev/null +++ b/third_party/heimdal/lib/heimdal/heimdal-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_DLL +#define RC_FILE_DESC_0409 "Heimdal Kerberos Library" +#define RC_FILE_ORIG_0409 "heimdal.dll" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/hx509/ChangeLog b/third_party/heimdal/lib/hx509/ChangeLog new file mode 100644 index 0000000..d00f1f3 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ChangeLog @@ -0,0 +1,2749 @@ +2008-07-14 Love Hörnquist Åstrand + + * hxtool.c: Break out print_eval_types(). + +2008-06-21 Love Hörnquist Åstrand + + * ks_p12.c: pass in time_now to unevelope + + * cms.c: Pass in time_now to unevelope, us verify context time in + verify_signed. + +2008-05-23 Love Hörnquist Åstrand + + * hx_locl.h: Include for TYPE_MAX defines. + +2008-04-29 Love Hörnquist Åstrand + + * sel-lex.l: Use _hx509_sel_yyerror() instead of error_message(). + +2008-04-20 Love Hörnquist Åstrand + + * sel-lex.l: Include + +2008-04-17 Love Hörnquist Åstrand + + * Makefile.am: Update make-proto usage. + +2008-04-15 Love Hörnquist Åstrand + + * ca.c: BasicConstraints.pathLenConstraint unsigned int. + + * sel-lex.l: Prefix sel_error with _hx509_ since its global on + platforms w/o symbol versioning. + + * sel.h: rename yyerror to sel_yyerror in the whole library, not + just the lexer + + * sel-lex.l: rename yyerror to sel_yyerror in the whole library, + not just the lexer + +2008-04-14 Love Hörnquist Åstrand + + * sel-lex.l: Rename yyerror to sel_yyerror and make it static. + +2008-04-08 Love Hörnquist Åstrand + + * hx509.h: Make self-standing by including missing files. + +2008-04-07 Love Hörnquist Åstrand + + * ks_p11.c: Use unsigned where appropriate. + + * softp11.c: call va_start before using vsnprintf. + + * crypto.c: make refcount slightly more sane. + + * keyset.c: make refcount slightly more sane. + + * cert.c: make refcount slightly more sane. + +2008-03-19 Love Hörnquist Åstrand + + * test_nist2.in: Try to find unzip. + +2008-03-16 Love Hörnquist Åstrand + + * version-script.map: add missing symbols + + * spnego: Make delegated credentials delegated directly, Oleg + Sharoiko pointed out that it always didnt work with the old + code. Also add som missing cred and context pass-thou functions in + the SPNEGO layer. + +2008-03-14 Love Hörnquist Åstrand + + * rename to be more consistent, export for teting + + * Add language to support querying certificates to find a + match. Support constructs like "1.3.6.1.5.2.3.5" IN + %{certificate.eku} AND %{certificate.subject} TAILMATCH "C=SE". + +2008-02-26 Love Hörnquist Åstrand + + * version-script.map: add hx509_pem_read + + * hxtool-commands.in: Add --pem to cms-verify-sd. + + * test_cms.in: Test verifying PEM signature files. + + * hxtool.c: Support verifying PEM signature files. + +2008-02-25 Love Hörnquist Åstrand + + * Makefile.am: libhx509_la_OBJECTS depends on hx_locl.h + +2008-02-11 Love Hörnquist Åstrand + + * Use ldap-prep (with libwind) to compare names + +2008-01-27 Love Hörnquist Åstrand + + * cert.c (hx509_query_match_eku): update to support the NULL + eku (reset), clearify the old behaivor with regards repetitive + calls. + + * Add matching on EKU, validate EKUs, add hxtool matching glue, + add check. Adapted from pach from Tim Miller of Mitre + +2008-01-21 Love Hörnquist Åstrand + + * test_soft_pkcs11.c: use func for more C_ functions. + +2008-01-18 Love Hörnquist Åstrand + + * version-script.map: Export hx509_free_error_string(). + +2008-01-17 Love Hörnquist Åstrand + + * version-script.map: only export C_GetFunctionList + + * test_soft_pkcs11.c: use C_GetFunctionList + + * softp11.c: fix comment, remove label. + + * softp11.c: Add option app-fatal to control if softtoken should + abort() on erroneous input from applications. + +2008-01-16 Love Hörnquist Åstrand + + * test_pkcs11.in: Test password less certificates too + + * keyset.c: document HX509_CERTS_UNPROTECT_ALL + + * ks_file.c: Support HX509_CERTS_UNPROTECT_ALL. + + * hx509.h: Add HX509_CERTS_UNPROTECT_ALL. + + * test_soft_pkcs11.c: Only log in if needed. + +2008-01-15 Love Hörnquist Åstrand + + * softp11.c: Support PINs to login to the store. + + * Makefile.am: add java pkcs11 test + + * test_java_pkcs11.in: first version of disable java test + + * softp11.c: Drop unused stuff. + + * cert.c: Spelling, Add hx509_cert_get_SPKI_AlgorithmIdentifier, + remove unused stuff, add hx509_context to some functions. + + * softp11.c: Add more glue to figure out what keytype this + certificate is using. + +2008-01-14 Love Hörnquist Åstrand + + * test_pkcs11.in: test debug + + * Add a PKCS11 provider supporting signing and verifing sigatures. + +2008-01-13 Love Hörnquist Åstrand + + * version-script.map: Replace hx509_name_to_der_name with + hx509_name_binary. + + * print.c: make print_func static + +2007-12-26 Love Hörnquist Åstrand + + * print.c: doxygen + + * env.c: doxygen + + * doxygen.c: add more groups + + * ca.c: doxygen. + +2007-12-17 Love Hörnquist Åstrand + + * ca.c: doxygen + +2007-12-16 Love Hörnquist Åstrand + + * error.c: doxygen + +2007-12-15 Love Hörnquist Åstrand + + * More documentation + + * lock.c: Add page referance + + * keyset.c: some more documentation. + + * cms.c: Doxygen documentation. + +2007-12-11 Love Hörnquist Åstrand + + * *.[ch]: More documentation + +2007-12-09 Love Hörnquist Åstrand + + * handle refcount on NULL. + + * test_nist_pkcs12.in: drop echo -n, doesn't work with posix sh + +2007-12-08 Love Hörnquist Åstrand + + * test_nist2.in: Print that this is version 2 of the tests + + * test_nist.in: Drop printing of $id. + + * hx509.h: Add HX509_VHN_F_ALLOW_NO_MATCH. + + * name.c: spelling. + + * cert.c: make work the doxygen. + + * name.c: fix doxygen compiling. + + * Makefile.am: add doxygen.c + + * doxygen.c: Add doxygen main page. + + * cert.c: Add doxygen. + + * revoke.c (_hx509_revoke_ref): new function. + +2007-11-16 Love Hörnquist Åstrand + + * ks_keychain.c: Check if SecKeyGetCSPHandle needs prototype. + +2007-08-16 Love Hörnquist Åstrand + + * data/nist-data: Make work on case senstive filesystems too. + +2007-08-09 Love Hörnquist Åstrand + + * cert.c: match rfc822 contrains better, provide better error + strings. + +2007-08-08 Love Hörnquist Åstrand + + * cert.c: "self-signed doesn't count" doesn't apply to trust + anchor certificate. make trust anchor check consistant. + + * revoke.c: make compile. + + * revoke.c (verify_crl): set error strings. + + * revoke.c (verify_crl): handle with the signer is the + CRLsigner (shortcut). + + * cert.c: Fix NC, comment on how to use _hx509_check_key_usage. + +2007-08-03 Love Hörnquist Åstrand + + * test_nist2.in, Makefile, test/nist*: Add nist pkits tests. + + * revoke.c: Update to use CERT_REVOKED error, shortcut out of OCSP + checking when OCSP reply is a revocation reply. + + * hx509_err.et: Make CERT_REVOKED error OCSP/CRL agnostic. + + * name.c (_hx509_Name_to_string): make printableString handle + space (0x20) diffrences as required by rfc3280. + + * revoke.c: Search for the right issuer when looking for the + issuer of the CRL signer. + +2007-08-02 Love Hörnquist Åstrand + + * revoke.c: Handle CRL signing certificate better, try to not + revalidate invalid CRLs over and over. + +2007-08-01 Love Hörnquist Åstrand + + * cms.c: remove stale comment. + + * test_nist.in: Unpack PKITS_data.zip and run tests. + + * test_nist_cert.in: Adapt to new nist pkits framework. + + * test_nist_pkcs12.in: Adapt to new nist pkits framework. + + * Makefile.am: clean PKITS_data + +2007-07-16 Love Hörnquist Åstrand + + * Makefile.am: Add version-script.map to EXTRA_DIST + +2007-07-12 Love Hörnquist Åstrand + + * Makefile.am: Add depenency on asn1_compile for asn1 built files. + +2007-07-10 Love Hörnquist Åstrand + + * peer.c: update (c), indent. + + * Makefile.am: New library version. + +2007-06-28 Love Hörnquist Åstrand + + * ks_p11.c: Add sha2 types. + + * ref/pkcs11.h: Sync with scute. + + * ref/pkcs11.h: Add sha2 CKM's. + + * print.c: Print authorityInfoAccess. + + * cert.c: Rename proxyCertInfo oid. + + * ca.c: Rename proxyCertInfo oid. + + * print.c: Rename proxyCertInfo oid. + +2007-06-26 Love Hörnquist Åstrand + + * test_ca.in: Adapt to new request handling. + + * req.c: Allow export some of the request parameters. + + * hxtool-commands.in: Adapt to new request handling. + + * hxtool.c: Adapt to new request handling. + + * test_req.in: Adapt to new request handling. + + * version-script.map: Add initialize_hx_error_table_r. + + * req.c: Move _hx509_request_print here. + + * hxtool.c: use _hx509_request_print + + * version-script.map: Export more crap^W semiprivate functions. + + * hxtool.c: don't _hx509_abort + + * version-script.map: add missing ; + +2007-06-25 Love Hörnquist Åstrand + + * cms.c: Use hx509_crypto_random_iv. + + * crypto.c: Split out the iv creation from hx509_crypto_encrypt + since _hx509_pbe_encrypt needs to use the iv from the s2k + function. + + * test_cert.in: Test PEM and DER FILE writing functionallity. + + * ks_file.c: Add writing DER certificates. + + * hxtool.c: Update to new hx509_pem_write(). + + * test_cms.in: test creation of PEM signeddata. + + * hx509.h: PEM struct/function declarations. + + * ks_file.c: Use PEM encoding/decoding functions. + + * file.c: PEM encode/decoding functions. + + * ks_file.c: Use hx509_pem_write. + + * version-script.map: Export some semi-private functions. + + * hxtool.c: Enable writing out signed data as a pem attachment. + + * hxtool-commands.in (cms-create-signed): add --pem + + * file.c (hx509_pem_write): Add. + + * test_ca.in: Issue and test null subject cert. + + * cert.c: Match is first component is in a CN=. + + * test_ca.in: Test hostname if first CN. + + * Makefile.am: Add version script. + + * version-script.map: Limited exported symbols. + + * test_ca.in: test --hostname. + + * test_chain.in: test max-depth + + * hx509.h: fixate HX509_HN_HOSTNAME at 0. + + * hxtool-commands.in: add --hostname add --max-depth + + * cert.c: Verify hostname and max-depth. + + * hxtool.c: Verify hostname and test max-depth. + +2007-06-24 Love Hörnquist Åstrand + + * test_cms.in: Test --id-by-name. + + * hxtool-commands.in: add cms-create-sd --id-by-name + + * hxtool.c: Use HX509_CMS_SIGATURE_ID_NAME. + + * cms.c: Implement and use HX509_CMS_SIGATURE_ID_NAME. + + * hx509.h: Add HX509_CMS_SIGATURE_ID_NAME, use subject name for + CMS.Identifier. hx509_hostname_type: add hostname type for + matching. + + * cert.c (match_general_name): more strict rfc822Name matching. + (hx509_verify_hostname): add hostname type for matching. + +2007-06-19 Love Hörnquist Åstrand + + * hxtool.c: Make compile again. + + * hxtool.c: Added peap-server for to make windows peap clients + happy. + + * hxtool.c: Unify parse_oid code. + + * hxtool.c: Implement --content-type. + + * hxtool-commands.in: Add content-type. + + * test_cert.in: more cert and keyset tests. + +2007-06-18 Love Hörnquist Åstrand + + * revoke.c: Avoid stomping on NULL. + + * revoke.c: Avoid reusing i. + + * cert.c: Provide __attribute__ for _hx509_abort. + + * ks_file.c: Fail if not finding iv. + + * keyset.c: Avoid useing freed memory. + + * crypto.c: Free memory in failure case. + + * crypto.c: Free memory in failure case. + +2007-06-12 Love Hörnquist Åstrand + + * *.c: Add hx509_cert_init_data and use everywhere + + * hx_locl.h: Now that KEYCHAIN:system-anchors is fast again, use + that. + + * ks_keychain.c: Implement trust anchor support with + SecTrustCopyAnchorCertificates. + + * keyset.c: Set ref to 1 for the new object. + + * cert.c: Fix logic for allow_default_trust_anchors + + * keyset.c: Add refcounting to keystores. + + * cert.c: Change logic for default trust anchors, make it be + either default trust anchor, the user supplied, or non at all. + +2007-06-08 Love Hörnquist Åstrand + + * Makefile.am: Add data/j.pem. + + * Makefile.am: Add test_windows.in. + +2007-06-06 Love Hörnquist Åstrand + + * ks_keychain.c: rename functions, leaks less memory and more + paranoia. + + * test_cms.in: Test cms peer-alg. + + * crypto.c (rsa_create_signature): make oid_id_pkcs1_rsaEncryption + mean rsa-with-sha1 but oid oid_id_pkcs1_rsaEncryption in algorithm + field. XXX should probably use another algorithmIdentifier for + this. + + * peer.c: Make free function return void. + + * cms.c (hx509_cms_create_signed_1): Use hx509_peer_info to select + the signature algorithm too. + + * hxtool-commands.in: Add cms-create-sd --peer-alg. + + * req.c: Use _hx509_crypto_default_sig_alg. + + * test_windows.in: Create crl, because everyone needs one. + + * Makefile.am: add wcrl.crl + +2007-06-05 Love Hörnquist Åstrand + + * hx_locl.h: Disable KEYCHAIN for now, its slow. + + * cms.c: When we are not using pkcs7-data, avoid seing + signedAttributes since some clients get upset by that (pkcs7 based + or just plain broken). + + * ks_keychain.c: Provide rsa signatures. + + * ks_keychain.c: Limit the searches to the selected keychain. + + * ks_keychain.c: include -framework Security specific header files + after #ifdef + + * ks_keychain.c: Find and attach private key (does not provide + operations yet though). + + * ks_p11.c: Prefix rsa method with p11_ + + * ks_keychain.c: Allow opening a specific chain, making "system" + special and be the system X509Anchors file. By not specifing any + keychain ("KEYCHAIN:"), all keychains are probed. + +2007-06-04 Love Hörnquist Åstrand + + * hxtool.c (verify): Friendlier error message. + + * cert.c: Read in and use default trust anchors if they exists. + + * hx_locl.h: Add concept of default_trust_anchors. + + * ks_keychain.c: Remove err(), remove extra empty comment, fix + _iter function. + + * error.c (hx509_get_error_string): if the error code is not the + one we expect, punt and use the default com_err/strerror string + instead. + + * keyset.c (hx509_certs_merge): its ok to merge in the NULL set of + certs. + + * test_windows.in: Fix status string. + + * ks_p12.c (store_func): free whole CertBag, not just the data + part. + + * print.c: Check that the self-signed cert is really self-signed. + + * print.c: Use selfsigned for CRL DP whine, tell if its a + self-signed. + + * print.c: Whine if its a non CA/proxy and doesn't have CRL DP. + + * ca.c: Add cRLSign to CA certs. + + * cert.c: Register NULL and KEYCHAIN. + + * ks_null.c: register the NULL keystore. + + * Makefile.am: Add ks_keychain.c and related libs. + + * test_crypto.in: Print certificate with utf8. + + * print.c: Leak less memory. + + * hxtool.c: Leak less memory. + + * print.c: Leak less memory, use functions that does same but + more. + + * name.c (quote_string): don't sign extend the (signed) char to + avoid printing too much, add an assert to check that we didn't + overrun the buffer. + + * name.c: Use right element out of the CHOICE for printableString + and utf8String + + * ks_keychain.c: Certificate only KeyChain backend. + + * name.c: Reset name before parsing it. + +2007-06-03 Love Hörnquist Åstrand + + * revoke.c (hx509_crl_*): fix sizeof() mistakes to fix memory + corruption. + + * hxtool.c: Add lifetime to crls. + + * hxtool-commands.in: Add lifetime to crls. + + * revoke.c: Add lifetime to crls. + + * test_ca.in: More crl checks. + + * revoke.c: Add revoking certs. + + * hxtool-commands.in: argument is certificates.. for crl-sign + + * hxtool.c (certificate_copy): free lock + + * revoke.c: Fix hx509_set_error_string calls, add + hx509_crl_add_revoked_certs(), implement hx509_crl_{alloc,free}. + + * hxtool.c (crl_sign): free lock + + * cert.c (hx509_context_free): free querystat + +2007-06-02 Love Hörnquist Åstrand + + * test_chain.in: test ocsp-verify + + * revoke.c (hx509_ocsp_verify): explain what its useful for and + provide sane error message. + + * hx509_err.et: New error code, CERT_NOT_IN_OCSP + + * hxtool.c: New command ocsp-verify, check if ocsp contains all + certs and are valid (exist and non expired). + + * hxtool-commands.in: New command ocsp-verify. + +2007-06-01 Love Hörnquist Åstrand + + * test_ca.in: Create crl and verify that is works. + + * hxtool.c: Sign CRL command. + + * hx509.h: Add hx509_crl. + + * hxtool-commands.in: Add crl-sign commands. + + * revoke.c: Support to generate an empty CRL. + + * tst-crypto-select2: Switched default types. + + * tst-crypto-select1: Switched default types. + + * ca.c: Use default AlgorithmIdentifier. + + * cms.c: Use default AlgorithmIdentifier. + + * crypto.c: Provide default AlgorithmIdentifier and use them. + + * hx_locl.h: Provide default AlgorithmIdentifier. + + * keyset.c (hx509_certs_find): collects stats for queries. + + * cert.c: Sort and print more info. + + * hx_locl.h: Add querystat to hx509_context. + + * test_*.in: sprinle stat saveing + + * Makefile.am: Add stat and objdir. + + * collector.c (_hx509_collector_alloc): return error code instead + of pointer. + + * hxtool.c: Add statistic hook. + + * ks_file.c: Update _hx509_collector_alloc prototype. + + * ks_p12.c: Update _hx509_collector_alloc prototype. + + * ks_p11.c: Update _hx509_collector_alloc prototype. + + * hxtool-commands.in: Add statistics hook. + + * cert.c: Statistics printing. + + * ks_p12.c: plug memory leak + + * ca.c (hx509_ca_tbs_add_crl_dp_uri): plug memory leak + +2007-05-31 Love Hörnquist Åstrand + + * print.c: print utf8 type SAN's + + * Makefile.am: Fix windows client cert name. + + * test_windows.in: Add crl-uri for the ee certs. + + * print.c: Printf formating. + + * ca.c: Add glue for adding CRL dps. + + * test_ca.in: Readd the crl adding code, it works (somewhat) now. + + * print.c: Fix printing of CRL DPnames (I hate IMPLICIT encoded + structures). + + * hxtool-commands.in: make ca and alias of certificate-sign + +2007-05-30 Love Hörnquist Åstrand + + * crypto.c (hx509_crypto_select): copy AI to the right place. + + * hxtool-commands.in: Add ca --ms-upn. + + * hxtool.c: add --ms-upn and add more EKU's for pk-init client. + + * ca.c: Add hx509_ca_tbs_add_san_ms_upn and refactor code. + + * test_crypto.in: Resurect killed e. + + * test_crypto.in: check for aes256-cbc + + * tst-crypto-select7: check for aes256-cbc + + * test_windows.in: test windows stuff + + * hxtool.c: add ca --domain-controller option, add secret key + option to avaible. + + * ca.c: Add hx509_ca_tbs_set_domaincontroller. + + * hxtool-commands.in: add ca --domain-controller + + * hxtool.c: hook for testing secrety key algs + + * crypto.c: Add selection code for secret key crypto. + + * hx509.h: Add HX509_SELECT_SECRET_ENC. + +2007-05-13 Love Hörnquist Åstrand + + * ks_p11.c: add more mechtypes + +2007-05-10 Love Hörnquist Åstrand + + * print.c: Indent. + + * hxtool-commands.in: add test-crypto command + + * hxtool.c: test crypto command + + * cms.c (hx509_cms_create_signed_1): if no eContentType is given, + use pkcs7-data. + + * print.c: add Netscape cert comment + + * crypto.c: Try both the empty password and the NULL + password (nothing vs the octet string \x00\x00). + + * print.c: Add some US Fed PKI oids. + + * ks_p11.c: Add some more hashes. + +2007-04-24 Love Hörnquist Åstrand + + * hxtool.c (crypto_select): stop memory leak + +2007-04-19 Love Hörnquist Åstrand + + * peer.c (hx509_peer_info_free): free memory used too + + * hxtool.c (crypto_select): only free peer if it was used. + +2007-04-18 Love Hörnquist Åstrand + + * hxtool.c: free template + + * ks_mem.c (mem_free): free key array too + + * hxtool.c: free private key and tbs + + * hxtool.c (hxtool_ca): free signer + + * hxtool.c (crypto_available): free peer too. + + * ca.c (get_AuthorityKeyIdentifier): leak less memory + + * hxtool.c (hxtool_ca): free SPKI + + * hxtool.c (hxtool_ca): free cert + + * ks_mem.c (mem_getkeys): allocate one more the we have elements + so its possible to store the NULL pointer at the end. + +2007-04-16 Love Hörnquist Åstrand + + * Makefile.am: CLEANFILES += cert-null.pem cert-sub-ca2.pem + +2007-02-05 Love Hörnquist Åstrand + + * ca.c: Disable CRLDistributionPoints for now, its IMPLICIT code + in the asn1 parser. + + * print.c: Add some more \n's. + +2007-02-03 Love Hörnquist Åstrand + + * file.c: Allow mapping using heim_octet_string. + + * hxtool.c: Add options to generate detached signatures. + + * cms.c: Add flags to generate detached signatures. + + * hx509.h: Flag to generate detached signatures. + + * test_cms.in: Support detached sigatures. + + * name.c (hx509_general_name_unparse): unparse the other + GeneralName nametypes. + + * print.c: Use less printf. Use hx509_general_name_unparse. + + * cert.c: Fix printing and plug leak-on-error. + +2007-01-31 Love Hörnquist Åstrand + + * test_ca.in: Add test for ca --crl-uri. + + * hxtool.c: Add ca --crl-uri. + + * hxtool-commands.in: add ca --crl-uri + + * ca.c: Code to set CRLDistributionPoints in certificates. + + * print.c: Check CRLDistributionPointNames. + + * name.c (hx509_general_name_unparse): function for unparsing + GeneralName, only supports GeneralName.URI + + * cert.c (is_proxy_cert): free info if we wont return it. + +2007-01-30 Love Hörnquist Åstrand + + * hxtool.c: Try to help how to use this command. + +2007-01-21 Love Hörnquist Åstrand + + * switch to sha256 as default digest for signing + +2007-01-20 Love Hörnquist Åstrand + + * test_ca.in: Really test sub-ca code, add basic constraints tests + +2007-01-17 Love Hörnquist Åstrand + + * Makefile.am: Fix makefile problem. + +2007-01-16 Love Hörnquist Åstrand + + * hxtool.c: Set num of bits before we generate the key. + +2007-01-15 Love Hörnquist Åstrand + + * cms.c (hx509_cms_create_signed_1): use hx509_cert_binary + + * ks_p12.c (store_func): use hx509_cert_binary + + * ks_file.c (store_func): use hx509_cert_binary + + * cert.c (hx509_cert_binary): return binary encoded + certificate (DER format) + +2007-01-14 Love Hörnquist Åstrand + + * ca.c (hx509_ca_tbs_subject_expand): new function. + + * name.c (hx509_name_expand): if env is NULL, return directly + + * test_ca.in: test template handling + + * hx509.h: Add template flags. + + * Makefile.am: clean out new files + + * hxtool.c: Add certificate template processing, fix hx509_err + usage. + + * hxtool-commands.in: Add certificate template processing. + + * ca.c: Add certificate template processing. Fix return messages + from hx509_ca_tbs_add_eku. + + * cert.c: Export more stuff from certificate. + +2007-01-13 Love Hörnquist Åstrand + + * ca.c: update (c) + + * ca.c: (hx509_ca_tbs_add_eku): filter out dups. + + * hxtool.c: Add type email and add email eku when using option + --email. + + * Makefile.am: add env.c + + * name.c: Remove abort, add error handling. + + * test_name.c: test name expansion + + * name.c: add hx509_name_expand + + * env.c: key-value pair help functions + +2007-01-12 Love Hörnquist Åstrand + + * ca.c: Don't issue certs with subject DN that is NULL and have no + SANs + + * print.c: Fix previous test. + + * print.c: Check there is a SAN if subject DN is NULL. + + * test_ca.in: test email, null subject dn + + * hxtool.c: Allow setting parameters to private key generation. + + * hx_locl.h: Allow setting parameters to private key generation. + + * crypto.c: Allow setting parameters to private key generation. + + * hxtool.c (eval_types): add jid if user gave one + + * hxtool-commands.in (certificate-sign): add --jid + + * ca.c (hx509_ca_tbs_add_san_jid): Allow adding + id-pkix-on-xmppAddr OtherName. + + * print.c: Print id-pkix-on-xmppAddr OtherName. + +2007-01-11 Love Hörnquist Åstrand + + * no random, no RSA/DH tests + + * hxtool.c (info): print status of random generator + + * Makefile.am: remove files created by tests + + * error.c: constify + + * name.c: constify + + * revoke.c: constify + + * hx_locl.h: constify + + * keyset.c: constify + + * ks_p11.c: constify + + * hx_locl.h: make printinfo char * argument const. + + * cms.c: move _hx509_set_digest_alg from cms.c to crypto.c since + its only used there. + + * crypto.c: remove no longer used stuff, move set_digest_alg here + from cms.c since its only used here. + + * Makefile.am: add data/test-nopw.p12 to EXTRA_DIST + +2007-01-10 Love Hörnquist Åstrand + + * print.c: BasicConstraints vs criticality bit is complicated and + not really possible to evaluate on its own, silly RFC3280. + + * ca.c: Make basicConstraints critical if this is a CA. + + * print.c: fix the version vs extension test + + * print.c: More validation checks. + + * name.c (hx509_name_cmp): add + +2007-01-09 Love Hörnquist Åstrand + + * ks_p11.c (collect_private_key): Missing CKA_MODULUS is ok + too (XXX why should these be fetched given they are not used). + + * test_ca.in: rename all files to PEM files, since that is what + they are. + + * hxtool.c: copy out the key with the self signed CA cert + + * Factor out private key operation out of the signing, operations, + support import, export, and generation of private keys. Add + support for writing PEM and PKCS12 files with private keys in them. + + * data/gen-req.sh: Generate a no password pkcs12 file. + +2007-01-08 Love Hörnquist Åstrand + + * cms.c: Check for internal ASN1 encoder error. + +2007-01-05 Love Hörnquist Åstrand + + * Makefile.am: Drop most of the pkcs11 files. + + * test_ca.in: test reissueing ca certificate (xxx time + validAfter). + + * hxtool.c: Allow setting serialNumber (needed for reissuing + certificates) Change --key argument to --out-key. + + * hxtool-commands.in (issue-certificate): Allow setting + serialNumber (needed for reissuing certificates), Change --key + argument to --out-key. + + * ref: Replace with Marcus Brinkmann of g10 Code GmbH pkcs11 + headerfile that is compatible with GPL (file taken from scute) + +2007-01-04 Love Hörnquist Åstrand + + * test_ca.in: Test to generate key and use them. + + * hxtool.c: handle other keys the pkcs10 requested keys + + * hxtool-commands.in: add generate key commands + + * req.c (_hx509_request_to_pkcs10): PKCS10 needs to have a subject + + * hxtool-commands.in: Spelling. + + * ca.c (hx509_ca_tbs_set_proxy): allow negative pathLenConstraint + to signal no limit + + * ks_file.c: Try all formats on the binary file before giving up, + this way we can handle binary rsa keys too. + + * data/key2.der: new test key + +2007-01-04 David Love + + * Makefile.am (hxtool_LDADD): Add libasn1.la + + * hxtool.c (pcert_verify): Fix format string. + +2006-12-31 Love Hörnquist Åstrand + + * hxtool.c: Allow setting path length + + * cert.c: Fix test for proxy certs chain length, it was too + restrictive. + + * data: regen + + * data/openssl.cnf: (proxy_cert) make length 0 + + * test_ca.in: Issue a long living cert. + + * hxtool.c: add --lifetime to ca command. + + * hxtool-commands.in: add --lifetime to ca command. + + * ca.c: allow setting notBefore and notAfter. + + * test_ca.in: Test generation of proxy certificates. + + * ca.c: Allow generation of proxy certificates, always include + BasicConstraints, fix error codes. + + * hxtool.c: Allow generation of proxy certificates. + + * test_name.c: make hx509_parse_name take a hx509_context. + + * name.c: Split building RDN to a separate function. + +2006-12-30 Love Hörnquist Åstrand + + * Makefile.am: clean test_ca files. + + * test_ca.in: test issuing self-signed and CA certificates. + + * hxtool.c: Add bits to allow issuing self-signed and CA + certificates. + + * hxtool-commands.in: Add bits to allow issuing self-signed and CA + certificates. + + * ca.c: Add bits to allow issuing CA certificates. + + * revoke.c: use new OCSPSigning. + + * ca.c: Add Subject Key Identifier. + + * ca.c: Add Authority Key Identifier. + + * cert.c: Locally export _hx509_find_extension_subject_key_id. + Handle AuthorityKeyIdentifier where only authorityCertSerialNumber + and authorityCertSerialNumber is set. + + * hxtool-commands.in: Add dnsname and rfc822 SANs. + + * test_ca.in: Test dnsname and rfc822 SANs. + + * ca.c: Add dnsname and rfc822 SANs. + + * hxtool.c: Add dnsname and rfc822 SANs. + + * test_ca.in: test adding eku, ku and san to the + certificate (https and pk-init) + + * hxtool.c: Add eku, ku and san to the certificate. + + * ca.c: Add eku, ku and san to the certificate. + + * hxtool-commands.in: Add --type and --pk-init-principal + + * ocsp.asn1: remove id-kp-OCSPSigning, its in rfc2459.asn1 now + +2006-12-29 Love Hörnquist Åstrand + + * ca.c: Add KeyUsage extension. + + * Makefile.am: add ca.c, add sign-certificate tests. + + * crypto.c: Add _hx509_create_signature_bitstring. + + * hxtool-commands.in: Add the sign-certificate tool. + + * hxtool.c: Add the sign-certificate tool. + + * cert.c: Add HX509_QUERY_OPTION_KU_KEYCERTSIGN. + + * hx509.h: Add hx509_ca_tbs and HX509_QUERY_OPTION_KU_KEYCERTSIGN. + + * test_ca.in: Basic test of generating a pkcs10 request, signing + it and verifying the chain. + + * ca.c: Naive certificate signer. + +2006-12-28 Love Hörnquist Åstrand + + * hxtool.c: add hxtool_hex + +2006-12-22 Love Hörnquist Åstrand + + * Makefile.am: use top_builddir for libasn1.la + +2006-12-11 Love Hörnquist Åstrand + + * hxtool.c (print_certificate): print serial number. + + * name.c (no): add S=stateOrProvinceName + +2006-12-09 Love Hörnquist Åstrand + + * crypto.c (_hx509_private_key_assign_rsa): set a default sig alg + + * ks_file.c (try_decrypt): pass down AlgorithmIdentifier that key + uses to do sigatures so there is no need to hardcode RSA into this + function. + +2006-12-08 Love Hörnquist Åstrand + + * ks_file.c: Pass filename to the parse functions and use it in + the error messages + + * test_chain.in: test proxy cert (third level) + + * hx509_err.et: fix errorstring for PROXY_CERT_NAME_WRONG + + * data: regen + + * Makefile.am: EXTRA_DIST: add + data/proxy10-child-child-test.{key,crt} + + * data/gen-req.sh: Fix names and restrictions on the proxy + certificates + + * cert.c: Clairfy and make proxy cert handling work for multiple + levels, before it was too restrictive. More helpful error message. + +2006-12-07 Love Hörnquist Åstrand + + * cert.c (check_key_usage): tell what keyusages are missing + + * print.c: Split OtherName printing code to a oid lookup and print + function. + + * print.c (Time2string): print hour as hour not min + + * Makefile.am: CLEANFILES += test + +2006-12-06 Love Hörnquist Åstrand + + * Makefile.am (EXTRA_DIST): add data/pkinit-proxy* files + + * Makefile.am (EXTRA_DIST): add tst-crypto* files + + * cert.c (hx509_query_match_issuer_serial): make a copy of the + data + + * cert.c (hx509_query_match_issuer_serial): allow matching on + issuer and serial num + + * cert.c (_hx509_calculate_path): add flag to allow leaving out + trust anchor + + * cms.c (hx509_cms_create_signed_1): when building the path, omit + the trust anchors. + + * crypto.c (rsa_create_signature): Abort when signature is longer, + not shorter. + + * cms.c: Provide time to _hx509_calculate_path so we don't send no + longer valid certs to our peer. + + * cert.c (find_parent): when checking for certs and its not a + trust anchor, require time be in range. + (_hx509_query_match_cert): Add time validity-testing to query mask + + * hx_locl.h: add time validity-testing to query mask + + * test_cms.in: Tests for CMS SignedData with incomplete chain from + the signer. + +2006-11-28 Love Hörnquist Åstrand + + * cms.c (hx509_cms_verify_signed): specify what signature we + failed to verify + + * Makefile.am: Depend on LIB_com_err for AIX. + + * keyset.c: Remove anther strndup that causes AIX to fall over. + + * cert.c: Don't check the trust anchors expiration time since they + are transported out of band, from RFC3820. + + * cms.c: sprinkle more error strings + + * crypto.c: sprinkle more error strings + + * hxtool.c: use unsigned int as counter to fit better with the + asn1 compiler + + * crypto.c: use unsigned int as counter to fit better with the + asn1 compiler + +2006-11-27 Love Hörnquist Åstrand + + * cms.c: Remove trailing white space. + + * crypto.c: rewrite comment to make more sense + + * crypto.c (hx509_crypto_select): check sig_algs[j]->key_oid + + * hxtool-commands.in (crypto-available): add --type + + * crypto.c (hx509_crypto_available): let alg pass if its keyless + + * hxtool-commands.in: Expand crypto-select + + * cms.c: Rename hx509_select to hx509_crypto_select. + + * hxtool-commands.in: Add crypto-select and crypto-available. + + * hxtool.c: Add crypto-select and crypto-available. + + * crypto.c (hx509_crypto_available): use right index. + (hx509_crypto_free_algs): new function + + * crypto.c (hx509_crypto_select): improve + (hx509_crypto_available): new function + +2006-11-26 Love Hörnquist Åstrand + + * cert.c: Sprinkle more error string and hx509_contexts. + + * cms.c: Sprinkle more error strings. + + * crypto.c: Sprinkle error string and hx509_contexts. + + * crypto.c: Add some more comments about how this works. + + * crypto.c (hx509_select): new function. + + * Makefile.am: add peer.c + + * hxtool.c: Update hx509_cms_create_signed_1. + + * hx_locl.h: add struct hx509_peer_info + + * peer.c: Allow selection of digest/sig-alg + + * cms.c: Allow selection of a better digest using hx509_peer_info. + + * revoke.c: Handle that _hx509_verify_signature takes a context. + + * cert.c: Handle that _hx509_verify_signature takes a context. + +2006-11-25 Love Hörnquist Åstrand + + * cms.c: Sprinkle error strings. + + * crypto.c: Sprinkle context and error strings. + +2006-11-24 Love Hörnquist Åstrand + + * name.c: Handle printing and parsing raw oids in name. + +2006-11-23 Love Hörnquist Åstrand + + * cert.c (_hx509_calculate_path): allow to calculate optimistic + path when we don't know the trust anchors, just follow the chain + upward until we no longer find a parent or we hit the max limit. + + * cms.c (hx509_cms_create_signed_1): provide a best effort path to + the trust anchors to be stored in the SignedData packet, if find + parents until trust anchor or max length. + + * data: regen + + * data/gen-req.sh: Build pk-init proxy cert. + +2006-11-16 Love Hörnquist Åstrand + + * error.c (hx509_get_error_string): Put ", " between strings in + error message. + +2006-11-13 Love Hörnquist Åstrand + + * data/openssl.cnf: Change realm to TEST.H5L.SE + +2006-11-07 Love Hörnquist Åstrand + + * revoke.c: Sprinkle error strings. + +2006-11-04 Love Hörnquist Åstrand + + * hx_locl.h: add context variable to cmp function. + + * cert.c (hx509_query_match_cmp_func): allow setting the match + function. + +2006-10-24 Love Hörnquist Åstrand + + * ks_p11.c: Return less EINVAL. + + * hx509_err.et: add more pkcs11 errors + + * hx509_err.et: more error-codes + + * revoke.c: Return less EINVAL. + + * ks_dir.c: sprinkel more hx509_set_error_string + + * ks_file.c: Return less EINVAL. + + * hxtool.c: Pass in context to _hx509_parse_private_key. + + * ks_file.c: Sprinkle more hx509_context so we can return propper + errors. + + * hx509_err.et: add HX509_PARSING_KEY_FAILED + + * crypto.c: Sprinkle more hx509_context so we can return propper + errors. + + * collector.c: No more EINVAL. + + * hx509_err.et: add HX509_LOCAL_ATTRIBUTE_MISSING + + * cert.c (hx509_cert_get_base_subject): one less EINVAL + (_hx509_cert_private_decrypt): one less EINVAL + +2006-10-22 Love Hörnquist Åstrand + + * collector.c: indent + + * hxtool.c: Try to not leak memory. + + * req.c: clean memory before free + + * crypto.c (_hx509_private_key2SPKI): indent + + * req.c: Try to not leak memory. + +2006-10-21 Love Hörnquist Åstrand + + * test_crypto.in: Read 50 kilobyte random data + + * revoke.c: Try to not leak memory. + + * hxtool.c: Try to not leak memory. + + * crypto.c (hx509_crypto_destroy): free oid. + + * error.c: Clean error string on failure just to make sure. + + * cms.c: Try to not leak memory (again). + + * hxtool.c: use a sensable content type + + * cms.c: Try harder to free certificate. + +2006-10-20 Love Hörnquist Åstrand + + * Makefile.am: Add make check data. + +2006-10-19 Love Hörnquist Åstrand + + * ks_p11.c (p11_list_keys): make element of search_data[0] + constants and set them later + + * Makefile.am: Add more files. + +2006-10-17 Love Hörnquist Åstrand + + * ks_file.c: set ret, remember to free ivdata + +2006-10-16 Love Hörnquist Åstrand + + * hx_locl.h: Include . + + * test_crypto.in: Test random-data. + + * hxtool.c: RAND_bytes() return 1 for cryptographic strong data, + check for that. + + * Makefile.am: clean random-data + + * hxtool.c: Add random-data command, use sl_slc_help. + + * hxtool-commands.in: Add random-data. + + * ks_p12.c: Remember to release certs. + + * ks_p11.c: Remember to release certs. + +2006-10-14 Love Hörnquist Åstrand + + * prefix der primitives with der_ + + * lock.c: Match the prompt type PROMPT exact. + + * hx_locl.h: Drop heim_any.h + +2006-10-11 Love Hörnquist Åstrand + + * ks_p11.c (p11_release_module): j needs to be used as inter loop + index. From Douglas Engert. + + * ks_file.c (parse_rsa_private_key): try all passwords and + prompter. + +2006-10-10 Love Hörnquist Åstrand + + * test_*.in: Parameterise the invocation of hxtool, so we can make + it run under TESTS_ENVIRONMENT. From Andrew Bartlett + +2006-10-08 Love Hörnquist Åstrand + + * test_crypto.in: Put all test stuck at 2006-09-25 since all their + chains where valied then. + + * hxtool.c: Implement --time= option. + + * hxtool-commands.in: Add option time. + + * Makefile.am: test_name is a PROGRAM_TESTS + + * ks_p11.c: Return HX509_PKCS11_NO_SLOT when there are no slots + and HX509_PKCS11_NO_TOKEN when there are no token. For use in PAM + modules that want to detect when to use smartcard login and when + not to. Patched based on code from Douglas Engert. + + * hx509_err.et: Add new pkcs11 related errors in a new section: + keystore related error. Patched based on code from Douglas + Engert. + +2006-10-07 Love Hörnquist Åstrand + + * Makefile.am: Make depenency for slc built files just like + everywhere else. + + * cert.c: Add all openssl algs and init asn1 et + +2006-10-06 Love Hörnquist Åstrand + + * ks_file.c (parse_rsa_private_key): free type earlier. + + * ks_file.c (parse_rsa_private_key): free type after use + + * name.c (_hx509_Name_to_string): remove dup const + +2006-10-02 Love Hörnquist Åstrand + + * Makefile.am: Add more libs to libhx509 + +2006-10-01 Love Hörnquist Åstrand + + * ks_p11.c: Fix double free's, NULL ptr de-reference, and conform + better to pkcs11. From Douglas Engert. + + * ref: remove ^M, it breaks solaris 10s cc. From Harald Barth + +2006-09-19 Love Hörnquist Åstrand + + * test_crypto.in: Bleichenbacher bad cert from Ralf-Philipp + Weinmann and Andrew Pyshkin, pad right. + + * data: starfield test root cert and Ralf-Philipp and Andreis + correctly padded bad cert + +2006-09-15 Love Hörnquist Åstrand + + * test_crypto.in: Add test for yutaka certs. + + * cert.c: Add a strict rfc3280 verification flag. rfc3280 requires + certificates to have KeyUsage.keyCertSign if they are to be used + for signing of certificates, but the step in the verifiation is + optional. + + * hxtool.c: Improve printing and error reporting. + +2006-09-13 Love Hörnquist Åstrand + + * test_crypto.in,Makefile.am,data/bleichenbacher-{bad,good}.pem: + test bleichenbacher from eay + +2006-09-12 Love Hörnquist Åstrand + + * hxtool.c: Make common function for all getarg_strings and + hx509_certs_append commonly used. + + * cms.c: HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT is a negative + flag, treat it was such. + +2006-09-11 Love Hörnquist Åstrand + + * req.c: Use the new add_GeneralNames function. + + * hx509.h: Add HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT. + + * ks_p12.c: Adapt to new signature of hx509_cms_unenvelope. + + * hxtool.c: Adapt to new signature of hx509_cms_unenvelope. + + * cms.c: Allow passing in encryptedContent and flag. Add new flag + HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT. + +2006-09-08 Love Hörnquist Åstrand + + * ks_p11.c: cast void * to char * when using it for %s formating + in printf. + + * name.c: New function _hx509_Name_to_string. + +2006-09-07 Love Hörnquist Åstrand + + * ks_file.c: Sprinkle error messages. + + * cms.c: Sprinkle even more error messages. + + * cms.c: Sprinkle some error messages. + + * cms.c (find_CMSIdentifier): only free string when we allocated + one. + + * ks_p11.c: Don't build most of the pkcs11 module if there are no + dlopen(). + +2006-09-06 Love Hörnquist Åstrand + + * cms.c (hx509_cms_unenvelope): try to save the error string from + find_CMSIdentifier so we have one more bit of information what + went wrong. + + * hxtool.c: More pretty printing, make verify_signed return the + error string from the library. + + * cms.c: Try returning what certificates failed to parse or be + found. + + * ks_p11.c (p11_list_keys): fetch CKA_LABEL and use it to set the + friendlyname for the certificate. + +2006-09-05 Love Hörnquist Åstrand + + * crypto.c: check that there are no extra bytes in the checksum + and that the parameters are NULL or the NULL-type. All to avoid + having excess data that can be used to fake the signature. + + * hxtool.c: print keyusage + + * print.c: add hx509_cert_keyusage_print, simplify oid printing + + * cert.c: add _hx509_cert_get_keyusage + + * ks_p11.c: keep one session around for the whole life of the keyset + + * test_query.in: tests more selection + + * hxtool.c: improve pretty printing in print and query + + * hxtool{.c,-commands.in}: add selection on KU and printing to query + + * test_cms.in: Add cms test for digitalSignature and + keyEncipherment certs. + + * name.c (no): Add serialNumber + + * ks_p11.c (p11_get_session): return better error messages + +2006-09-04 Love Hörnquist Åstrand + + * ref: update to pkcs11 reference files 2.20 + + * ks_p11.c: add more mechflags + + * name.c (no): add OU and sort + + * revoke.c: pass context to _hx509_create_signature + + * ks_p11.c (p11_printinfo): print proper plural s + + * ks_p11.c: save the mechs supported when initing the token, print + them in printinfo. + + * hx_locl.h: Include . + + * cms.c: pass context to _hx509_create_signature + + * req.c: pass context to _hx509_create_signature + + * keyset.c (hx509_certs_info): print information about the keyset. + + * hxtool.c (pcert_print) print keystore info when --info flag is + given. + + * hxtool-commands.in: Add hxtool print --info. + + * test_query.in: Test hxtool print --info. + + * hx_locl.h (hx509_keyset_ops): add printinfo + + * crypto.c: Start to hang the private key operations of the + private key, pass hx509_context to create_checksum. + +2006-05-29 Love Hörnquist Åstrand + + * ks_p11.c: Iterate over all slots, not just the first/selected + one. + +2006-05-27 Love Hörnquist Åstrand + + * cert.c: Add release function for certifiates so backend knowns + when its no longer used. + + * ks_p11.c: Add reference counting on certifiates, push out + CK_SESSION_HANDLE from slot. + + * cms.c: sprinkle more hx509_clear_error_string + +2006-05-22 Love Hörnquist Åstrand + + * ks_p11.c: Sprinkle some hx509_set_error_strings + +2006-05-13 Love Hörnquist Åstrand + + * hxtool.c: Avoid shadowing. + + * revoke.c: Avoid shadowing. + + * ks_file.c: Avoid shadowing. + + * cert.c: Avoid shadowing. + +2006-05-12 Love Hörnquist Åstrand + + * lock.c (hx509_prompt_hidden): reshuffle to avoid gcc warning + + * hx509.h: Reshuffle the prompter types, remove the hidden field. + + * lock.c (hx509_prompt_hidden): return if the prompt should be + hidden or not + + * revoke.c (hx509_revoke_free): allow free of NULL. + +2006-05-11 Love Hörnquist Åstrand + + * ks_file.c (file_init): Avoid shadowing ret (and thus avoiding + crashing). + + * ks_dir.c: Implement DIR: caches useing FILE: caches. + + * ks_p11.c: Catch more errors. + +2006-05-08 Love Hörnquist Åstrand + + * crypto.c (hx509_crypto_encrypt): free correctly in error + path. From Andrew Bartlett. + + * crypto.c: If RAND_bytes fails, then we will attempt to + double-free crypt->key.data. From Andrew Bartlett. + +2006-05-05 Love Hörnquist Åstrand + + * name.c: Rename u_intXX_t to uintXX_t + +2006-05-03 Love Hörnquist Åstrand + + * TODO: More to do about the about the PKCS11 code. + + * ks_p11.c: Use the prompter from the lock function. + + * lock.c: Deal with that hx509_prompt.reply is no longer a + pointer. + + * hx509.h: Make hx509_prompt.reply not a pointer. + +2006-05-02 Love Hörnquist Åstrand + + * keyset.c: Sprinkle setting error strings. + + * crypto.c: Sprinkle setting error strings. + + * collector.c: Sprinkle setting error strings. + + * cms.c: Sprinkle setting error strings. + +2006-05-01 Love Hörnquist Åstrand + + * test_name.c: renamed one error code + + * name.c: renamed one error code + + * ks_p11.c: _hx509_set_cert_attribute changed signature + + * hxtool.c (pcert_print): use hx509_err so I can test it + + * error.c (hx509_set_error_stringv): clear errors on malloc + failure + + * hx509_err.et: Add some more errors + + * cert.c: Sprinkle setting error strings. + + * cms.c: _hx509_path_append changed signature. + + * revoke.c: changed signature of _hx509_check_key_usage + + * keyset.c: changed signature of _hx509_query_match_cert + + * hx509.h: Add support for error strings. + + * cms.c: changed signature of _hx509_check_key_usage + + * Makefile.am: ibhx509_la_files += error.c + + * ks_file.c: Sprinkel setting error strings. + + * cert.c: Sprinkel setting error strings. + + * hx_locl.h: Add support for error strings. + + * error.c: Add string error handling functions. + + * keyset.c (hx509_certs_init): pass the right error code back + +2006-04-30 Love Hörnquist Åstrand + + * revoke.c: Revert previous patch. + (hx509_ocsp_verify): new function that returns the expiration of + certificate in ocsp data-blob + + * cert.c: Reverse previous patch, lets do it another way. + + * cert.c (hx509_revoke_verify): update usage + + * revoke.c: Make compile. + + * revoke.c: Add the expiration time the crl/ocsp info expire + + * name.c: Add hx509_name_is_null_p + + * cert.c: remove _hx509_cert_private_sigature + +2006-04-29 Love Hörnquist Åstrand + + * name.c: Expose more of Name. + + * hxtool.c (main): add missing argument to printf + + * data/openssl.cnf: Add EKU for the KDC certificate + + * cert.c (hx509_cert_get_base_subject): reject un-canon proxy + certs, not the reverse + (add_to_list): constify and fix argument order to + copy_octet_string + (hx509_cert_find_subjectAltName_otherName): make work + +2006-04-28 Love Hörnquist Åstrand + + * data/{pkinit,kdc}.{crt,key}: pkinit certificates + + * data/gen-req.sh: Generate pkinit certificates. + + * data/openssl.cnf: Add pkinit glue. + + * cert.c (hx509_verify_hostname): implement stub function + +2006-04-27 Love Hörnquist Åstrand + + * TODO: CRL delta support + +2006-04-26 Love Hörnquist Åstrand + + * data/.cvsignore: ignore leftover from OpenSSL cert generation + + * hx509_err.et: Add name malformated error + + * name.c (hx509_parse_name): don't abort on error, rather return + error + + * test_name.c: Test failure parsing name. + + * cert.c: When verifying certificates, store subject basename for + later consumption. + + * test_name.c: test to parse and print name and check that they + are the same. + + * name.c (hx509_parse_name): fix length argument to printf string + + * name.c (hx509_parse_name): fix length argument to stringtooid, 1 + too short. + + * cert.c: remove debug printf's + + * name.c (hx509_parse_name): make compile pre c99 + + * data/gen-req.sh: OpenSSL have a serious issue of user confusion + -subj in -ca takes the arguments in LDAP order. -subj for x509 + takes it in x509 order. + + * cert.c (hx509_verify_path): handle the case where the where two + proxy certs in a chain. + + * test_chain.in: enable two proxy certificates in a chain test + + * test_chain.in: tests proxy certificates + + * data: re-gen + + * data/gen-req.sh: build proxy certificates + + * data/openssl.cnf: add def for proxy10_cert + + * hx509_err.et: Add another proxy certificate error. + + * cert.c (hx509_verify_path): Need to mangle name to remove the CN + of the subject, copying issuer only works for one level but is + better then doing no checking at all. + + * hxtool.c: Add verify --allow-proxy-certificate. + + * hxtool-commands.in: add verify --allow-proxy-certificate + + * hx509_err.et: Add proxy certificate errors. + + * cert.c: Fix comment about subject name of proxy certificate. + + * test_chain.in: tests for proxy certs + + * data/gen-req.sh: gen proxy and non-proxy tests certificates + + * data/openssl.cnf: Add definition for proxy certs + + * data/*proxy-test.*: Add proxy certificates + + * cert.c (hx509_verify_path): verify proxy certificate have no san + or ian + + * cert.c (hx509_verify_set_proxy_certificate): Add + (*): rename policy cert to proxy cert + + * cert.c: Initial support for proxy certificates. + +2006-04-24 Love Hörnquist Åstrand + + * hxtool.c: some error checking + + * name.c: Switch over to asn1 generaed oids. + + * TODO: merge with old todo file + +2006-04-23 Love Hörnquist Åstrand + + * test_query.in: make quiet + + * test_req.in: SKIP test if there is no RSA support. + + * hxtool.c: print dh method too + + * test_chain.in: SKIP test if there is no RSA support. + + * test_cms.in: SKIP test if there is no RSA support. + + * test_nist.in: SKIP test if there is no RSA support. + +2006-04-22 Love Hörnquist Åstrand + + * hxtool-commands.in: Allow passing in pool and anchor to + signedData + + * hxtool.c: Allow passing in pool and anchor to signedData + + * test_cms.in: Test that certs in signed data is picked up. + + * hx_locl.h: Expose the path building function to internal + functions. + + * cert.c: Expose the path building function to internal functions. + + * hxtool-commands.in: cms-envelope: Add support for choosing the + encryption type + + * hxtool.c (cms_create_enveloped): Add support for choosing the + encryption type + + * test_cms.in: Test generating des-ede3 aes-128 aes-256 enveloped + data + + * crypto.c: Add names to cipher types. + + * cert.c (hx509_query_match_friendly_name): fix return value + + * data/gen-req.sh: generate tests for enveloped data using + des-ede3 and aes256 + + * test_cms.in: add tests for enveloped data using des-ede3 and + aes256 + + * cert.c (hx509_query_match_friendly_name): New function. + +2006-04-21 Love Hörnquist Åstrand + + * ks_p11.c: Add support for parsing slot-number. + + * crypto.c (oid_private_rc2_40): simply + + * crypto.c: Use oids from asn1 generator. + + * ks_file.c (file_init): reset length when done with a part + + * test_cms.in: check with test.combined.crt. + + * data/gen-req.sh: Create test.combined.crt. + + * test_cms.in: Test signed data using keyfile that is encrypted. + + * ks_file.c: Remove (commented out) debug printf + + * ks_file.c (parse_rsa_private_key): use EVP_get_cipherbyname + + * ks_file.c (parse_rsa_private_key): make working for one + password. + + * ks_file.c (parse_rsa_private_key): Implement enought for + testing. + + * hx_locl.h: Add + + * ks_file.c: Add glue code for PEM encrypted password files. + + * test_cms.in: Add commeted out password protected PEM file, + remove password for those tests that doesn't need it. + + * test_cms.in: adapt test now that we can use any certificate and + trust anchor + + * collector.c: handle PEM RSA PRIVATE KEY files + + * cert.c: Remove unused function. + + * ks_dir.c: move code here from ks_file.c now that its no longer + used. + + * ks_file.c: Add support for parsing unencrypted RSA PRIVATE KEY + + * crypto.c: Handle rsa private keys better. + +2006-04-20 Love Hörnquist Åstrand + + * hxtool.c: Use hx509_cms_{,un}wrap_ContentInfo + + * cms.c: Make hx509_cms_{,un}wrap_ContentInfo usable in asn1 + un-aware code. + + * cert.c (hx509_verify_path): if trust anchor is not self signed, + don't check sig From Douglas Engert. + + * test_chain.in: test "sub-cert -> sub-ca" + + * crypto.c: Use the right length for the sha256 checksums. + +2006-04-15 Love Hörnquist Åstrand + + * crypto.c: Fix breakage from sha256 code. + + * crypto.c: Add SHA256 support, and symbols for the other new + SHA-2 types. + +2006-04-14 Love Hörnquist Åstrand + + * test_cms.in: test rc2-40 rc2-64 rc2-128 enveloped data + + * data/test-enveloped-rc2-{40,64,128}: add tests cases for rc2 + + * cms.c: Update prototypes changes for hx509_crypto_[gs]et_params. + + * crypto.c: Break out the parameter handling code for encrypting + data to handle RC2. Needed for Windows 2k pk-init support. + +2006-04-04 Love Hörnquist Åstrand + + * Makefile.am: Split libhx509_la_SOURCES into build file and + distributed files so we can avoid building prototypes for + build-files. + +2006-04-03 Love Hörnquist Åstrand + + * TODO: split certificate request into pkcs10 and CRMF + + * hxtool-commands.in: Add nonce flag to ocsp-fetch + + * hxtool.c: control sending nonce + + * hxtool.c (request_create): store the request in a file, no in + bitbucket. + + * cert.c: expose print_cert_subject internally + + * hxtool.c: Add ocsp_print. + + * hxtool-commands.in: New command "ocsp-print". + + * hx_locl.h: Include . + + * revoke.c (verify_ocsp): require issuer to match too. + (free_ocsp): new function + (hx509_revoke_ocsp_print): new function, print ocsp reply + + * Makefile.am: build CRMF files + + * data/key.der: needed for cert request test + + * test_req.in: adapt to rename of pkcs10-create to request-create + + * hxtool.c: adapt to rename of pkcs10-create to request-create + + * hxtool-commands.in: Rename pkcs10-create to request-create + + * crypto.c: (_hx509_parse_private_key): Avoid crashing on bad input. + + * hxtool.c (pkcs10_create): use opt->subject_string + + * hxtool-commands.in: Add pkcs10-create --subject + + * Makefile.am: Add test_req to tests. + + * test_req.in: Test for pkcs10 commands. + + * name.c (hx509_parse_name): new function. + + * hxtool.c (pkcs10_create): implement + + * hxtool-commands.in (pkcs10-create): Add arguments + + * crypto.c: Add _hx509_private_key2SPKI and support + functions (only support RSA for now). + +2006-04-02 Love Hörnquist Åstrand + + * hxtool-commands.in: Add pkcs10-create command. + + * hx509.h: Add hx509_request. + + * TODO: more stuff + + * Makefile.am: Add req.c + + * req.c: Create certificate requests, prototype converts the + request in a pkcs10 packet. + + * hxtool.c: Add pkcs10_create + + * name.c (hx509_name_copy): new function. + +2006-04-01 Love Hörnquist Åstrand + + * TODO: fill out what do + + * hxtool-commands.in: add pkcs10-print + + * hx_locl.h: Include . + + * pkcs10.asn1: PKCS#10 + + * hxtool.c (pkcs10_print): new function. + + * test_chain.in: test ocsp keyhash + + * data: generate ocsp keyhash version too + + * revoke.c (load_ocsp): test that we got back a BasicReponse + + * ocsp.asn1: Add asn1_id_pkix_ocsp*. + + * Makefile.am: Add asn1_id_pkix_ocsp*. + + * cert.c: Add HX509_QUERY_MATCH_KEY_HASH_SHA1 + + * hx_locl.h: Add HX509_QUERY_MATCH_KEY_HASH_SHA1 + + * revoke.c: Support OCSPResponderID.byKey, indent. + + * revoke.c (hx509_ocsp_request): Add nonce to ocsp request. + + * hxtool.c: Add nonce to ocsp request. + + * test_chain.in: Added crl tests + + * data/nist-data: rename missing-crl to missing-revoke + + * data: make ca use openssl ca command so we can add ocsp tests, + and regen certs + + * test_chain.in: Add revoked ocsp cert test + + * cert.c: rename missing-crl to missing-revoke + + * revoke.c: refactor code, fix a un-init-ed variable + + * test_chain.in: rename missing-crl to missing-revoke add ocsp + tests + + * test_cms.in: rename missing-crl to missing-revoke + + * hxtool.c: rename missing-crl to missing-revoke + + * hxtool-commands.in: rename missing-crl to missing-revoke + + * revoke.c: Plug one memory leak. + + * revoke.c: Renamed generic CRL related errors. + + * hx509_err.et: Comments and renamed generic CRL related errors + + * revoke.c: Add ocsp checker. + + * ocsp.asn1: Add id-kp-OCSPSigning + + * hxtool-commands.in: add url-path argument to ocsp-fetch + + * hxtool.c: implement ocsp-fetch + + * cert.c: Use HX509_DEFAULT_OCSP_TIME_DIFF. + + * hx_locl.h: Add ocsp_time_diff to hx509_context + + * crypto.c (_hx509_verify_signature_bitstring): new function, + commonly use when checking certificates + + * cms.c (hx509_cms_envelope_1): check for internal ASN.1 encoder + error + + * cert.c: Add ocsp glue, use new + _hx509_verify_signature_bitstring, add eku checking function. + +2006-03-31 Love Hörnquist Åstrand + + * Makefile.am: add id_kp_OCSPSigning.x + + * revoke.c: Pick out certs in ocsp response + + * TODO: list of stuff to verify + + * revoke.c: Add code to load OCSPBasicOCSPResponse files, reload + crl when its changed on disk. + + * cert.c: Update for ocsp merge. handle building path w/o + subject (using subject key id) + + * ks_p12.c: _hx509_map_file changed prototype. + + * file.c: _hx509_map_file changed prototype, returns struct stat + if requested. + + * ks_file.c: _hx509_map_file changed prototype. + + * hxtool.c: Add stub for ocsp-fetch, _hx509_map_file changed + prototype, add ocsp parsing to verify command. + + * hx_locl.h: rename HX509_CTX_CRL_MISSING_OK to + HX509_CTX_VERIFY_MISSING_OK now that we have OCSP glue + +2006-03-30 Love Hörnquist Åstrand + + * hx_locl.h: Add to make it compile on Solaris, + from Alex V. Labuta. + +2006-03-28 Love Hörnquist Åstrand + + * crypto.c (_hx509_pbe_decrypt): try all passwords, not just the + first one. + +2006-03-27 Love Hörnquist Åstrand + + * print.c (check_altName): Print the othername oid. + + * crypto.c: Manual page claims RSA_public_decrypt will return -1 + on error, lets check for that + + * crypto.c (_hx509_pbe_decrypt): also try the empty password + + * collector.c (match_localkeyid): no need to add back the cert to + the cert pool, its already there. + + * crypto.c: Add REQUIRE_SIGNER + + * cert.c (hx509_cert_free): ok to free NULL + + * hx509_err.et: Add new error code SIGNATURE_WITHOUT_SIGNER. + + * name.c (_hx509_name_ds_cmp): make DirectoryString case + insenstive + (hx509_name_to_string): less spacing + + * cms.c: Check for signature error, check consitency of error + +2006-03-26 Love Hörnquist Åstrand + + * collector.c (_hx509_collector_alloc): handle errors + + * cert.c (hx509_query_alloc): allocate slight more more then a + sizeof(pointer) + + * crypto.c (_hx509_private_key_assign_key_file): ask for password + if nothing matches. + + * cert.c: Expose more of the hx509_query interface. + + * collector.c: hx509_certs_find is now exposed. + + * cms.c: hx509_certs_find is now exposed. + + * revoke.c: hx509_certs_find is now exposed. + + * keyset.c (hx509_certs_free): allow free-ing NULL + (hx509_certs_find): expose + (hx509_get_one_cert): new function + + * hxtool.c: hx509_certs_find is now exposed. + + * hx_locl.h: Remove hx509_query, its exposed now. + + * hx509.h: Add hx509_query. + +2006-02-22 Love Hörnquist Åstrand + + * cert.c: Add exceptions for null (empty) subjectNames + + * data/nist-data: Add some more name constraints tests. + + * data/nist-data: Add some of the test from 4.13 Name Constraints. + + * cert.c: Name constraits needs to be evaluated in block as they + appear in the certificates, they can not be joined to one + list. One example of this is: + + - cert is cn=foo,dc=bar,dc=baz + - subca is dc=foo,dc=baz with name restriction dc=kaka,dc=baz + - ca is dc=baz with name restriction dc=baz + + If the name restrictions are merged to a list, the certificate + will pass this test. + +2006-02-14 Love Hörnquist Åstrand + + * cert.c: Handle more name constraints cases. + + * crypto.c (dsa_verify_signature): if test if malloc failed + +2006-01-31 Love Hörnquist Åstrand + + * cms.c: Drop partial pkcs12 string2key implementation. + +2006-01-20 Love Hörnquist Åstrand + + * data/nist-data: Add commited out DSA tests (they fail). + + * data/nist-data: Add 4.2 Validity Periods. + + * test_nist.in: Make less verbose to use. + + * Makefile.am: Add test_nist_cert. + + * data/nist-data: Add some more CRL-tests. + + * test_nist.in: Print $id instead of . when running the tests. + + * test_nist.in: Drop verifying certifiates, its done in another + test now. + + * data/nist-data: fixup kill-rectangle leftovers + + * data/nist-data: Drop verifying certifiates, its done in another + test now. Add more crl tests. comment out all unused tests. + + * test_nist_cert.in: test parse all nist certs + +2006-01-19 Love Hörnquist Åstrand + + * hx509_err.et: Add HX509_CRL_UNKNOWN_EXTENSION. + + * revoke.c: Check for unknown extentions in CRLs and CRLEntries. + + * test_nist.in: Parse new format to handle CRL info. + + * test_chain.in: Add --missing-crl. + + * name.c (hx509_unparse_der_name): Rename from hx509_parse_name. + (_hx509_unparse_Name): Add. + + * hxtool-commands.in: Add --missing-crl to verify commands. + + * hx509_err.et: Add CRL errors. + + * cert.c (hx509_context_set_missing_crl): new function Add CRL + handling. + + * hx_locl.h: Add HX509_CTX_CRL_MISSING_OK. + + * revoke.c: Parse and verify CRLs (simplistic). + + * hxtool.c: Parse CRL info. + + * data/nist-data: Change format so we can deal with CRLs, also + note the test-id from PKITS. + + * data: regenerate test + + * data/gen-req.sh: use static-file to generate tests + + * data/static-file: new file to use for commited tests + + * test_cms.in: Use static file, add --missing-crl. + +2006-01-18 Love Hörnquist Åstrand + + * print.c: Its cRLReason, not cRLReasons. + + * hxtool.c: Attach revoke context to verify context. + + * data/nist-data: change syntax to make match better with crl + checks + + * cert.c: Verify no certificates has been revoked with the new + revoke interface. + + * Makefile.am: libhx509_la_SOURCES += revoke.c + + * revoke.c: Add framework for handling CRLs. + + * hx509.h: Add hx509_revoke_ctx. + +2006-01-13 Love Hörnquist Åstrand + + * delete crypto_headers.h, use global file instead. + + * crypto.c (PBE_string2key): libdes now supports PKCS12_key_gen + +2006-01-12 Love Hörnquist Åstrand + + * crypto_headers.h: Need BN_is_negative too. + +2006-01-11 Love Hörnquist Åstrand + + * ks_p11.c (p11_rsa_public_decrypt): since is wrong, don't provide + it. PKCS11 can't do public_decrypt, it support verify though. All + this doesn't matter, since the code never go though this path. + + * crypto_headers.h: Provide glue to compile with less warnings + with OpenSSL + +2006-01-08 Love Hörnquist Åstrand + + * Makefile.am: Depend on LIB_des + + * lock.c: Use "crypto_headers.h". + + * crypto_headers.h: Include the two diffrent implementation of + crypto headers. + + * cert.c: Use "crypto-headers.h". Load ENGINE configuration. + + * crypto.c: Make compile with both OpenSSL and heimdal libdes. + + * ks_p11.c: Add code for public key decryption (not supported yet) + and use "crypto-headers.h". + + +2006-01-04 Love Hörnquist Åstrand + + * add a hx509_context where we can store configuration + + * p11.c,Makefile.am: pkcs11 is now supported by library, remove + old files. + + * ks_p11.c: more paranoid on refcount, set refcounter ealier, + reset pointers after free + + * collector.c (struct private_key): remove temporary key data + storage, convert directly to a key + (match_localkeyid): match certificate and key using localkeyid + (match_keys): match certificate and key using _hx509_match_keys + (_hx509_collector_collect): rewrite to use match_keys and + match_localkeyid + + * crypto.c (_hx509_match_keys): function that determins if a + private key matches a certificate, used when there is no + localkeyid. + (*) reset free pointer + + * ks_file.c: Rewrite to use collector and mapping support + function. + + * ks_p11.c (rsa_pkcs1_method): constify + + * ks_p11.c: drop extra wrapping of p11_init + + * crypto.c (_hx509_private_key_assign_key_file): use function to + extact rsa key + + * cert.c: Revert previous, refcounter is unsigned, so it can never + be negative. + + * cert.c (hx509_cert_ref): more refcount paranoia + + * ks_p11.c: Implement rsa_private_decrypt and add stubs for public + ditto. + + * ks_p11.c: Less printf, less memory leaks. + + * ks_p11.c: Implement signing using pkcs11. + + * ks_p11.c: Partly assign private key, enough to complete + collection, but not any crypto functionallity. + + * collector.c: Use hx509_private_key to assign private keys. + + * crypto.c: Remove most of the EVP_PKEY code, and use RSA + directly, this temporary removes DSA support. + + * hxtool.c (print_f): print if there is a friendly name and if + there is a private key + +2006-01-03 Love Hörnquist Åstrand + + * name.c: Avoid warning from missing __attribute__((noreturn)) + + * lock.c (_hx509_lock_unlock_certs): return unlock certificates + + * crypto.c (_hx509_private_key_assign_ptr): new function, exposes + EVP_PKEY + (_hx509_private_key_assign_key_file): remember to free private key + if there is one. + + * cert.c (_hx509_abort): add newline to output and flush stdout + + * Makefile.am: libhx509_la_SOURCES += collector.c + + * hx_locl.h: forward type declaration of struct hx509_collector. + + * collector.c: Support functions to collect certificates and + private keys and then match them. + + * ks_p12.c: Use the new hx509_collector support functions. + + * ks_p11.c: Add enough glue to support certificate iteration. + + * test_nist_pkcs12.in: Less verbose. + + * cert.c (hx509_cert_free): if there is a private key assosited + with this cert, free it + + * print.c: Use _hx509_abort. + + * ks_p12.c: Use _hx509_abort. + + * hxtool.c: Use _hx509_abort. + + * crypto.c: Use _hx509_abort. + + * cms.c: Use _hx509_abort. + + * cert.c: Use _hx509_abort. + + * name.c: use _hx509_abort + +2006-01-02 Love Hörnquist Åstrand + + * name.c (hx509_name_to_string): don't cut bmpString in half. + + * name.c (hx509_name_to_string): don't overwrite with 1 byte with + bmpString. + + * ks_file.c (parse_certificate): avoid stomping before array + + * name.c (oidtostring): avoid leaking memory + + * keyset.c: Add _hx509_ks_dir_register. + + * Makefile.am (libhx509_la_SOURCES): += ks_dir.c + + * hxtool-commands.in: Remove pkcs11. + + * hxtool.c: Remove pcert_pkcs11. + + * ks_file.c: Factor out certificate parsing code. + + * ks_dir.c: Add new keystore that treats all files in a directory + a keystore, useful for regression tests. + +2005-12-12 Love Hörnquist Åstrand + + * test_nist_pkcs12.in: Test parse PKCS12 files from NIST. + + * data/nist-data: Can handle DSA certificate. + + * hxtool.c: Print error code on failure. + +2005-10-29 Love Hörnquist Åstrand + + * crypto.c: Support DSA signature operations. + +2005-10-04 Love Hörnquist Åstrand + + * print.c: Validate that issuerAltName and subjectAltName isn't + empty. + +2005-09-14 Love Hörnquist Åstrand + + * p11.c: Cast to unsigned char to avoid warning. + + * keyset.c: Register pkcs11 module. + + * Makefile.am: Add ks_p11.c, install hxtool. + + * ks_p11.c: Starting point of a pkcs11 module. + +2005-09-04 Love Hörnquist Åstrand + + * lock.c: Implement prompter. + + * hxtool-commands.in: add --content to print + + * hxtool.c: Split verify and print. + + * cms.c: _hx509_pbe_decrypt now takes a hx509_lock. + + * crypto.c: Make _hx509_pbe_decrypt take a hx509_lock, workaround + for empty password. + + * name.c: Add DC, handle all Directory strings, fix signless + problems. + +2005-09-03 Love Hörnquist Åstrand + + * test_query.in: Pass in --pass to all commands. + + * hxtool.c: Use option --pass. + + * hxtool-commands.in: Add --pass to all commands. + + * hx509_err.et: add UNKNOWN_LOCK_COMMAND and CRYPTO_NO_PROMPTER + + * test_cms.in: pass in password to cms-create-sd + + * crypto.c: Abstract out PBE_string2key so I can add PBE2 s2k + later. Avoid signess warnings with OpenSSL. + + * cms.c: Use void * instead of char * for to avoid signedness + issues + + * cert.c (hx509_cert_get_attribute): remove const, its not + + * ks_p12.c: Cast size_t to unsigned long when print. + + * name.c: Fix signedness warning. + + * test_query.in: Use echo, the function check isn't defined here. + +2005-08-11 Love Hörnquist Åstrand + + * hxtool-commands.in: Add more options that was missing. + +2005-07-28 Love Hörnquist Åstrand + + * test_cms.in: Use --certificate= for enveloped/unenvelope. + + * hxtool.c: Use --certificate= for enveloped/unenvelope. Clean + up. + + * test_cms.in: add EnvelopeData tests + + * hxtool.c: use id-envelopedData for ContentInfo + + * hxtool-commands.in: add contentinfo wrapping for create/unwrap + enveloped data + + * hxtool.c: add contentinfo wrapping for create/unwrap enveloped + data + + * data/gen-req.sh: add enveloped data (aes128) + + * crypto.c: add "new" RC2 oid + +2005-07-27 Love Hörnquist Åstrand + + * hx_locl.h, cert.c: Add HX509_QUERY_MATCH_FUNCTION that allows + caller to match by function, note that this doesn't not work + directly for backends that implements ->query, they must do their + own processing. (I'm running out of flags, only 12 left now) + + * test_cms.in: verify ContentInfo wrapping code in hxtool + + * hxtool-commands.in (cms_create_sd): support wrapping in content + info spelling + + * hxtool.c (cms_create_sd): support wrapping in content info + + * test_cms.in: test more cms signeddata messages + + * data/gen-req.sh: generate SignedData + + * hxtool.c (cms_create_sd): support certificate store, add support + to unwrap a ContentInfo the SignedData inside. + + * crypto.c: sprinkel rk_UNCONST + + * crypto.c: add DER NULL to the digest oid's + + * hxtool-commands.in: add --content-info to cms-verify-sd + + * cms.c (hx509_cms_create_signed_1): pass in a full + AlgorithmIdentifier instead of heim_oid for digest_alg + + * crypto.c: make digest_alg a digest_oid, it's not needed right + now + + * hx509_err.et: add CERT_NOT_FOUND + + * keyset.c (_hx509_certs_find): add error code for cert not + found + + * cms.c (hx509_cms_verify_signed): add external store of + certificates, use the right digest algorithm identifier. + + * cert.c: fix const warning + + * ks_p12.c: slightly less verbose + + * cert.c: add hx509_cert_find_subjectAltName_otherName, add + HX509_QUERY_MATCH_FRIENDLY_NAME + + * hx509.h: add hx509_octet_string_list, remove bad comment + + * hx_locl.h: add HX509_QUERY_MATCH_FRIENDLY_NAME + + * keyset.c (hx509_certs_append): needs a hx509_lock, add one + + * Makefile.am: add test cases tempfiles to CLEANFILES + + * Makefile.am: add test_query to TESTS, fix dependency on hxtool + sources on hxtool-commands.h + + * hxtool-commands.in: explain what signer is for create-sd + + * hxtool.c: add query, add more options to verify-sd and create-sd + + * test_cms.in: add more cms tests + + * hxtool-commands.in: add query, add more options to verify-sd + + * test_query.in: test query interface + + * data: fix filenames for ds/ke files, add pkcs12 files, regen + + * hxtool.c,Makefile.am,hxtool-commands.in: switch to slc + +2005-07-26 Love Hörnquist Åstrand + + * cert.c (hx509_verify_destroy_ctx): add + + * hxtool.c: free hx509_verify_ctx + + * name.c (_hx509_name_ds_cmp): make sure all strings are not equal + +2005-07-25 Love Hörnquist Åstrand + + * hxtool.c: return error + + * keyset.c: return errors from iterations + + * test_chain.in: clean up checks + + * ks_file.c (parse_certificate): return errno's not 1 in case of + error + + * ks_file.c (file_iter): make sure endpointer is NULL + + * ks_mem.c (mem_iter): follow conversion and return NULL when we + get to the end, not ENOENT. + + * Makefile.am: test_chain depends on hxtool + + * data: test certs that lasts 10 years + + * data/gen-req.sh: script to generate test certs + + * Makefile.am: Add regression tests. + + * data: test certificate and keys + + * test_chain.in: test chain + + * hxtool.c (cms_create_sd): add KU digitalSigature as a + requirement to the query + + * hx_locl.h: add KeyUsage query bits + + * hx509_err.et: add KeyUsage error + + * cms.c: add checks for KeyUsage + + * cert.c: more checks on KeyUsage, allow to query on them too + +2005-07-24 Love Hörnquist Åstrand + + * cms.c: Add missing break. + + * hx_locl.h,cms.c,cert.c: allow matching on SubjectKeyId + + * hxtool.c: Use _hx509_map_file, _hx509_unmap_file and + _hx509_write_file. + + * file.c (_hx509_write_file): in case of write error, return errno + + * file.c (_hx509_write_file): add a function that write a data + blob to disk too + + * Fix id-tags + + * Import mostly complete X.509 and CMS library. Handles, PEM, DER, + PKCS12 encoded certicates. Verificate RSA chains and handled + CMS's SignedData, and EnvelopedData. + + diff --git a/third_party/heimdal/lib/hx509/Makefile.am b/third_party/heimdal/lib/hx509/Makefile.am new file mode 100644 index 0000000..fe13451 --- /dev/null +++ b/third_party/heimdal/lib/hx509/Makefile.am @@ -0,0 +1,398 @@ +include $(top_srcdir)/Makefile.am.common + +AM_CPPFLAGS += $(INCLUDE_openssl_crypto) + +lib_LTLIBRARIES = libhx509.la libhx509template.la +libhx509_la_LDFLAGS = -version-info 5:0:0 +libhx509template_la_LDFLAGS = -version-info 5:0:0 + +BUILT_SOURCES = \ + sel-gram.h \ + hx509_err.c \ + hx509_err.h + +AM_YFLAGS = -d -o sel-gram.c + +dist_libhx509_la_SOURCES = \ + ca.c \ + cert.c \ + char_map.h \ + cms.c \ + collector.c \ + crypto.c \ + crypto-ec.c \ + doxygen.c \ + error.c \ + env.c \ + file.c \ + hx509.h \ + hx_locl.h \ + sel.c \ + sel.h \ + sel-gram.y \ + sel-lex.l \ + keyset.c \ + ks_dir.c \ + ks_file.c \ + ks_mem.c \ + ks_null.c \ + ks_p11.c \ + ks_p12.c \ + ks_keychain.c \ + lock.c \ + name.c \ + peer.c \ + print.c \ + softp11.c \ + ref/pkcs11.h \ + req.c \ + revoke.c + +dist_libhx509template_la_SOURCES = $(dist_libhx509_la_SOURCES) + +sel-gram.h: sel-gram.c +sel-lex.c: sel-gram.h + +libhx509_la_DEPENDENCIES = version-script.map +libhx509template_la_DEPENDENCIES = version-script.map + +libhx509_la_LIBADD = \ + $(LIB_com_err) \ + $(LIB_hcrypto) \ + $(LIB_openssl_crypto) \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(top_builddir)/lib/base/libheimbase.la \ + $(LIBADD_roken) \ + $(LIB_dlopen) + +libhx509template_la_LIBADD = \ + $(LIB_com_err) \ + $(LIB_hcrypto) \ + $(LIB_openssl_crypto) \ + $(top_builddir)/lib/asn1/libasn1template.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(top_builddir)/lib/base/libheimbase.la \ + $(LIBADD_roken) \ + $(LIB_dlopen) + +if FRAMEWORK_SECURITY +libhx509_la_LDFLAGS += -framework Security -framework CoreFoundation +libhx509template_la_LDFLAGS += -framework Security -framework CoreFoundation +endif + +if versionscript +libhx509_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +libhx509template_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif +$(libhx509_la_OBJECTS): $(srcdir)/version-script.map $(nodist_include_HEADERS) $(priv_headers) +$(libhx509template_la_OBJECTS): $(srcdir)/version-script.map $(nodist_include_HEADERS) $(priv_headers) + +nodist_libhx509_la_SOURCES = $(BUILT_SOURCES) +nodist_libhx509template_la_SOURCES = $(BUILT_SOURCES) + +dist_include_HEADERS = hx509.h $(srcdir)/hx509-protos.h + +noinst_HEADERS = $(srcdir)/hx509-private.h + +nodist_include_HEADERS = hx509_err.h + +ALL_OBJECTS = $(libhx509_la_OBJECTS) +ALL_OBJECTS += $(hxtool_OBJECTS) + +HX509_PROTOS = $(srcdir)/hx509-protos.h $(srcdir)/hx509-private.h + +$(ALL_OBJECTS): $(HX509_PROTOS) + +$(libhx509_la_OBJECTS): $(srcdir)/hx_locl.h +$(libhx509template_la_OBJECTS): $(srcdir)/hx_locl.h + +$(srcdir)/hx509-protos.h: $(dist_libhx509_la_SOURCES) + $(heim_verbose)cd $(srcdir) && perl ../../cf/make-proto.pl -R '^(_|^C)' -E HX509_LIB -q -P comment -o hx509-protos.h $(dist_libhx509_la_SOURCES) || rm -f hx509-protos.h + +$(srcdir)/hx509-private.h: $(dist_libhx509_la_SOURCES) + $(heim_verbose)cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p hx509-private.h $(dist_libhx509_la_SOURCES) || rm -f hx509-private.h + +bin_PROGRAMS = hxtool + +hxtool-commands.c hxtool-commands.h: hxtool-commands.in $(SLC) + $(heim_verbose)$(SLC) $(srcdir)/hxtool-commands.in + +dist_hxtool_SOURCES = hxtool.c +nodist_hxtool_SOURCES = hxtool-commands.c hxtool-commands.h + +$(hxtool_OBJECTS): hxtool-commands.h $(nodist_include_HEADERS) + +hxtool_LDADD = \ + libhx509template.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_hcrypto) \ + $(LIB_roken) \ + $(top_builddir)/lib/sl/libsl.la + +CLEANFILES = $(BUILT_SOURCES) sel-gram.c sel-lex.c \ + $(TESTS) \ + hxtool-commands.c hxtool-commands.h *.tmp \ + request.out \ + out.pem out2.pem \ + sd sd.pem \ + sd.data sd.data.out \ + ev.data ev.data.out \ + cert-null.pem cert-sub-ca2.pem \ + cert-ee.pem cert-ca.pem \ + cert-sub-ee.pem cert-sub-ca.pem \ + cert-proxy.der cert-ca.der cert-ee.der pkcs10-request.der \ + wca.pem wuser.pem wdc.pem wcrl.crl \ + random-data statfile crl.crl \ + test p11dbg.log pkcs11.cfg \ + test-rc-file.rc + +clean-local: + @echo "cleaning PKITS" ; rm -rf PKITS_data + +# +# regression tests +# + +check_SCRIPTS = $(SCRIPT_TESTS) +check_PROGRAMS = $(PROGRAM_TESTS) test_soft_pkcs11 + +LDADD = libhx509.la + +test_soft_pkcs11_LDADD = libhx509.la $(top_builddir)/lib/asn1/libasn1.la + +test_name_LDADD = libhx509.la $(LIB_roken) $(top_builddir)/lib/asn1/libasn1.la +test_expr_LDADD = libhx509.la $(LIB_roken) $(top_builddir)/lib/asn1/libasn1.la + +TESTS = $(SCRIPT_TESTS) $(PROGRAM_TESTS) + +PROGRAM_TESTS = \ + test_name \ + test_expr + +SCRIPT_TESTS = \ + test_ca \ + test_cert \ + test_chain \ + test_cms \ + test_crypto \ + test_nist \ + test_nist2 \ + test_pkcs11 \ + test_java_pkcs11 \ + test_nist_cert \ + test_nist_pkcs12 \ + test_req \ + test_windows \ + test_query + +do_subst = $(heim_verbose)sed -e 's,[@]srcdir[@],$(srcdir),g' \ + -e 's,[@]objdir[@],$(top_builddir)/lib/hx509,g' \ + -e 's,[@]egrep[@],$(EGREP),g' + +test_ca: test_ca.in Makefile + $(do_subst) < $(srcdir)/test_ca.in > test_ca.tmp + $(heim_verbose)chmod +x test_ca.tmp + mv test_ca.tmp test_ca + +test_cert: test_cert.in Makefile + $(do_subst) < $(srcdir)/test_cert.in > test_cert.tmp + $(heim_verbose)chmod +x test_cert.tmp + mv test_cert.tmp test_cert + +test_chain: test_chain.in Makefile + $(do_subst) < $(srcdir)/test_chain.in > test_chain.tmp + $(heim_verbose)chmod +x test_chain.tmp + mv test_chain.tmp test_chain + +test_cms: test_cms.in Makefile + $(do_subst) < $(srcdir)/test_cms.in > test_cms.tmp + $(heim_verbose)chmod +x test_cms.tmp + mv test_cms.tmp test_cms + +test_crypto: test_crypto.in Makefile + $(do_subst) < $(srcdir)/test_crypto.in > test_crypto.tmp + $(heim_verbose)chmod +x test_crypto.tmp + mv test_crypto.tmp test_crypto + +test_nist: test_nist.in Makefile + $(do_subst) < $(srcdir)/test_nist.in > test_nist.tmp + $(heim_verbose)chmod +x test_nist.tmp + mv test_nist.tmp test_nist + +test_nist2: test_nist2.in Makefile + $(do_subst) < $(srcdir)/test_nist2.in > test_nist2.tmp + $(heim_verbose)chmod +x test_nist2.tmp + mv test_nist2.tmp test_nist2 + +test_pkcs11: test_pkcs11.in Makefile + $(do_subst) < $(srcdir)/test_pkcs11.in > test_pkcs11.tmp + $(heim_verbose)chmod +x test_pkcs11.tmp + mv test_pkcs11.tmp test_pkcs11 + +test_java_pkcs11: test_java_pkcs11.in Makefile + $(do_subst) < $(srcdir)/test_java_pkcs11.in > test_java_pkcs11.tmp + $(heim_verbose)chmod +x test_java_pkcs11.tmp + mv test_java_pkcs11.tmp test_java_pkcs11 + +test_nist_cert: test_nist_cert.in Makefile + $(do_subst) < $(srcdir)/test_nist_cert.in > test_nist_cert.tmp + $(heim_verbose)chmod +x test_nist_cert.tmp + mv test_nist_cert.tmp test_nist_cert + +test_nist_pkcs12: test_nist_pkcs12.in Makefile + $(do_subst) < $(srcdir)/test_nist_pkcs12.in > test_nist_pkcs12.tmp + $(heim_verbose)chmod +x test_nist_pkcs12.tmp + mv test_nist_pkcs12.tmp test_nist_pkcs12 + +test_req: test_req.in Makefile + $(do_subst) < $(srcdir)/test_req.in > test_req.tmp + $(heim_verbose)chmod +x test_req.tmp + mv test_req.tmp test_req + +test_windows: test_windows.in Makefile + $(do_subst) < $(srcdir)/test_windows.in > test_windows.tmp + $(heim_verbose)chmod +x test_windows.tmp + mv test_windows.tmp test_windows + +test_query: test_query.in Makefile + $(do_subst) < $(srcdir)/test_query.in > test_query.tmp + $(heim_verbose)chmod +x test_query.tmp + mv test_query.tmp test_query + +EXTRA_DIST = \ + NTMakefile \ + hxtool-version.rc \ + libhx509-exports.def \ + version-script.map \ + hx509_err.et \ + hxtool-commands.in \ + quote.py \ + test_ca.in \ + test_chain.in \ + test_cert.in \ + test_cms.in \ + test_crypto.in \ + test_nist.in \ + test_nist2.in \ + test_nist_cert.in \ + test_nist_pkcs12.in \ + test_pkcs11.in \ + test_java_pkcs11.in \ + test_query.in \ + test_req.in \ + test_windows.in \ + tst-crypto-available1 \ + tst-crypto-available2 \ + tst-crypto-available3 \ + tst-crypto-select \ + tst-crypto-select1 \ + tst-crypto-select2 \ + tst-crypto-select3 \ + tst-crypto-select4 \ + tst-crypto-select5 \ + tst-crypto-select6 \ + tst-crypto-select7 \ + data/PKITS_data.zip \ + data/eccurve.pem \ + data/https.crt \ + data/https.key \ + data/mkcert.sh \ + data/nist-result2 \ + data/n0ll.pem \ + data/secp256r1TestCA.cert.pem \ + data/secp256r1TestCA.key.pem \ + data/secp256r1TestCA.pem \ + data/secp256r2TestClient.cert.pem \ + data/secp256r2TestClient.key.pem \ + data/secp256r2TestClient.pem \ + data/secp256r2TestServer.cert.pem \ + data/secp256r2TestServer.key.pem \ + data/secp256r2TestServer.pem \ + data/bleichenbacher-bad.pem \ + data/bleichenbacher-good.pem \ + data/bleichenbacher-sf-pad-correct.pem \ + data/ca.crt \ + data/ca.key \ + data/crl1.crl \ + data/crl1.der \ + data/gen-req.sh \ + data/j.pem \ + data/kdc.crt \ + data/kdc.key \ + data/key.der \ + data/key2.der \ + data/nist-data \ + data/nist-data2 \ + data/no-proxy-test.crt \ + data/no-proxy-test.key \ + data/ocsp-req1.der \ + data/ocsp-req2.der \ + data/ocsp-resp1-2.der \ + data/ocsp-resp1-3.der \ + data/ocsp-resp1-ca.der \ + data/ocsp-resp1-keyhash.der \ + data/ocsp-resp1-ocsp-no-cert.der \ + data/ocsp-resp1-ocsp.der \ + data/ocsp-resp1.der \ + data/ocsp-resp2.der \ + data/ocsp-responder.crt \ + data/ocsp-responder.key \ + data/openssl.1.0.cnf \ + data/openssl.1.1.cnf \ + data/pkinit-proxy-chain.crt \ + data/pkinit-proxy.crt \ + data/pkinit-proxy.key \ + data/pkinit-pw.key \ + data/pkinit.crt \ + data/pkinit.key \ + data/pkinit-ec.crt \ + data/pkinit-ec.key \ + data/proxy-level-test.crt \ + data/proxy-level-test.key \ + data/proxy-test.crt \ + data/proxy-test.key \ + data/proxy10-child-test.crt \ + data/proxy10-child-test.key \ + data/proxy10-child-child-test.crt \ + data/proxy10-child-child-test.key \ + data/proxy10-test.crt \ + data/proxy10-test.key \ + data/revoke.crt \ + data/revoke.key \ + data/sf-class2-root.pem \ + data/static-file \ + data/sub-ca.crt \ + data/sub-ca.key \ + data/sub-cert.crt \ + data/sub-cert.key \ + data/sub-cert.p12 \ + data/test-ds-only.crt \ + data/test-ds-only.key \ + data/test-enveloped-aes-128 \ + data/test-enveloped-aes-256 \ + data/test-enveloped-des \ + data/test-enveloped-des-ede3 \ + data/test-enveloped-rc2-128 \ + data/test-enveloped-rc2-40 \ + data/test-enveloped-rc2-64 \ + data/test-ke-only.crt \ + data/test-ke-only.key \ + data/test-nopw.p12 \ + data/test-pw.key \ + data/test-signed-data \ + data/test-signed-data-noattr \ + data/test-signed-data-noattr-nocerts \ + data/test-signed-sha-1 \ + data/test-signed-sha-256 \ + data/test-signed-sha-512 \ + data/test.combined.crt \ + data/test.crt \ + data/test.key \ + data/test.p12 \ + data/win-u16-in-printablestring.der \ + data/yutaka-pad-broken-ca.pem \ + data/yutaka-pad-broken-cert.pem \ + data/yutaka-pad-ok-ca.pem \ + data/yutaka-pad-ok-cert.pem \ + data/yutaka-pad.key diff --git a/third_party/heimdal/lib/hx509/NTMakefile b/third_party/heimdal/lib/hx509/NTMakefile new file mode 100644 index 0000000..4d5ff09 --- /dev/null +++ b/third_party/heimdal/lib/hx509/NTMakefile @@ -0,0 +1,180 @@ +######################################################################## +# +# Copyright (c) 2009-2017, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\hx509 +intcflags=-I$(OBJ) +localcflags=-DASN1_LIB + +!include ../../windows/NTMakefile.w32 + +libhx509_la_OBJS = \ + $(OBJ)\ca.obj \ + $(OBJ)\cert.obj \ + $(OBJ)\cms.obj \ + $(OBJ)\collector.obj \ + $(OBJ)\crypto.obj \ + $(OBJ)\crypto-ec.obj \ + $(OBJ)\error.obj \ + $(OBJ)\env.obj \ + $(OBJ)\file.obj \ + $(OBJ)\hx509_err.obj \ + $(OBJ)\sel.obj \ + $(OBJ)\sel-gram.obj \ + $(OBJ)\sel-lex.obj \ + $(OBJ)\keyset.obj \ + $(OBJ)\ks_dir.obj \ + $(OBJ)\ks_file.obj \ + $(OBJ)\ks_mem.obj \ + $(OBJ)\ks_null.obj \ + $(OBJ)\ks_p11.obj \ + $(OBJ)\ks_p12.obj \ + $(OBJ)\ks_keychain.obj \ + $(OBJ)\lock.obj \ + $(OBJ)\name.obj \ + $(OBJ)\peer.obj \ + $(OBJ)\print.obj \ + $(OBJ)\softp11.obj \ + $(OBJ)\req.obj \ + $(OBJ)\revoke.obj + +$(LIBHX509): $(libhx509_la_OBJS) + $(LIBCON) + +dist_libhx509_la_SOURCES = \ + $(SRCDIR)\ca.c \ + $(SRCDIR)\cert.c \ + $(SRCDIR)\cms.c \ + $(SRCDIR)\collector.c \ + $(SRCDIR)\crypto.c \ + $(SRCDIR)\crypto-ec.c \ + $(SRCDIR)\doxygen.c \ + $(SRCDIR)\error.c \ + $(SRCDIR)\env.c \ + $(SRCDIR)\file.c \ + $(SRCDIR)\hx509.h \ + $(SRCDIR)\hx_locl.h \ + $(SRCDIR)\sel.c \ + $(SRCDIR)\sel.h \ + $(SRCDIR)\sel-gram.y \ + $(SRCDIR)\sel-lex.l \ + $(SRCDIR)\keyset.c \ + $(SRCDIR)\ks_dir.c \ + $(SRCDIR)\ks_file.c \ + $(SRCDIR)\ks_mem.c \ + $(SRCDIR)\ks_null.c \ + $(SRCDIR)\ks_p11.c \ + $(SRCDIR)\ks_p12.c \ + $(SRCDIR)\ks_keychain.c \ + $(SRCDIR)\lock.c \ + $(SRCDIR)\name.c \ + $(SRCDIR)\peer.c \ + $(SRCDIR)\print.c \ + $(SRCDIR)\softp11.c \ + $(SRCDIR)\ref\pkcs11.h \ + $(SRCDIR)\req.c \ + $(SRCDIR)\revoke.c + +{}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -DBUILD_HX509_LIB -DASN1_LIB + +{$(OBJ)}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -DBUILD_HX509_LIB -DASN1_LIB + +asn1_compile=$(BINDIR)\asn1_compile.exe + +INCFILES= \ + $(INCDIR)\hx509.h \ + $(INCDIR)\hx509-protos.h \ + $(INCDIR)\hx509-private.h \ + $(INCDIR)\hx509_err.h + +hxtool.c: $(OBJ)\hxtool-commands.h + +SLC=$(BINDIR)\slc.exe + +$(OBJ)\hxtool-commands.c $(OBJ)\hxtool-commands.h: hxtool-commands.in $(SLC) + cd $(OBJ) + $(CP) $(SRCDIR)\hxtool-commands.in $(OBJ)\hxtool-commands.in + $(SLC) hxtool-commands.in + cd $(SRCDIR) + +$(BINDIR)\hxtool.exe: $(OBJ)\tool\hxtool.obj $(OBJ)\tool\hxtool-commands.obj $(LIBHEIMDAL) $(OBJ)\hxtool-version.res + $(EXECONLINK) $(LIBHEIMDAL) $(LIBROKEN) $(LIBSL) $(LIBVERS) $(LIBCOMERR) $(LIB_openssl_crypto) + $(EXEPREP) + +$(OBJ)\hx509-protos.h: + cd $(OBJ) + $(PERL) $(SRCDIR)\..\..\cf\make-proto.pl -R "^(_|^C)" -E HX509_LIB -q -P remove -o hx509-protos.h $(dist_libhx509_la_SOURCES) || $(RM) -f hx509-protos.h + cd $(SRCDIR) + +$(OBJ)\hx509-private.h: + cd $(OBJ) + $(PERL) $(SRCDIR)\..\..\cf\make-proto.pl -q -P remove -p hx509-private.h $(dist_libhx509_la_SOURCES) || $(RM) -f hx509-private.h + cd $(SRCDIR) + +$(OBJ)\hx509_err.c $(OBJ)\hx509_err.h: hx509_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\hx509_err.et + cd $(SRCDIR) + +$(OBJ)\sel-gram.obj: $(OBJ)\sel-gram.c + $(C2OBJ) -I$(SRCDIR) + +$(OBJ)\sel-lex.obj: $(OBJ)\sel-lex.c + $(C2OBJ) -I$(SRCDIR) -I$(OBJ) -DYY_NO_UNISTD_H + +$(OBJ)\sel-gram.c: sel-gram.y + $(YACC) -o $@ --defines=$(OBJ)\sel-gram.h sel-gram.y + +$(OBJ)\sel-lex.c: sel-lex.l + $(LEX) -P_hx509_sel_yy -o$@ sel-lex.l + +all:: $(INCFILES) $(LIBHX509) + +prep:: mktooldir + +mktooldir: +! if !exist($(OBJ)\tool) + $(MKDIR) $(OBJ)\tool +! endif + +all-tools:: $(BINDIR)\hxtool.exe + +clean:: + -$(RM) $(BINDIR)\hxtool.* + -$(RM) $(OBJ)\tool\*.* + +{}.c{$(OBJ)\tool}.obj:: + $(C2OBJ_C) /Fd$(OBJ)\tool\ /Fo$(OBJ)\tool\ $(MPOPT) /UASN1_LIB $< + +{$(OBJ)}.c{$(OBJ)\tool}.obj:: + $(C2OBJ_C) /Fd$(OBJ)\tool\ /Fo$(OBJ)\tool\ $(MPOPT) /UASN1_LIB $< + diff --git a/third_party/heimdal/lib/hx509/TODO b/third_party/heimdal/lib/hx509/TODO new file mode 100644 index 0000000..ecdfa8d --- /dev/null +++ b/third_party/heimdal/lib/hx509/TODO @@ -0,0 +1,61 @@ +Handle private_key_ops better, esp wrt ->key_oid + +Better support for keyex negotiation, DH and ECDH. + +x501 name + parsing + comparing (ldap canonlisation rules) + +DSA support +DSA2 support + +Rewrite the pkcs11 code to support the following: + + * Reset the pin on card change. + * Ref count the lock structure to make sure we have a + prompter when we need it. + * Add support for CK_TOKEN_INFO.CKF_PROTECTED_AUTHENTICATION_PATH + +x509 policy mappings support + +CRL delta support + +Qualified statement + https://bugzilla.mozilla.org/show_bug.cgi?id=277797#c2 + + +Signed Receipts + http://www.faqs.org/rfcs/rfc2634.html + chapter 2 + +tests + nist tests + name constrains + policy mappings + http://csrc.nist.gov/pki/testing/x509paths.html + + building path using Subject/Issuer vs SubjKeyID vs AuthKeyID + negative tests + all checksums + conditions/branches + +pkcs7 + handle pkcs7 support in CMS ? + +certificate request + generate pkcs10 request + from existing cert + generate CRMF request + pk-init KDC/client + web server/client + jabber server/client + email + + +x509 issues: + + OtherName is left unspecified, but it's used by other + specs. creating this hole where a application/CA can't specify + policy for SubjectAltName what covers whole space. For example, a + CA is trusted to provide authentication but not authorization. + diff --git a/third_party/heimdal/lib/hx509/ca.c b/third_party/heimdal/lib/hx509/ca.c new file mode 100644 index 0000000..37fb403 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ca.c @@ -0,0 +1,3099 @@ +/* + * Copyright (c) 2006 - 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_ca Hx509 CA functions + * + * See the library functions here: @ref hx509_ca + */ + +struct hx509_ca_tbs { + hx509_name subject; + SubjectPublicKeyInfo spki; + KeyUsage ku; + ExtKeyUsage eku; + GeneralNames san; + CertificatePolicies cps; + PolicyMappings pms; + heim_integer serial; + struct { + unsigned int proxy:1; + unsigned int ca:1; + unsigned int key:1; + unsigned int serial:1; + unsigned int domaincontroller:1; + unsigned int xUniqueID:1; + } flags; + time_t notBefore; + time_t notAfter; + HeimPkinitPrincMaxLifeSecs pkinitTicketMaxLife; + int pathLenConstraint; /* both for CA and Proxy */ + CRLDistributionPoints crldp; + heim_bit_string subjectUniqueID; + heim_bit_string issuerUniqueID; + AlgorithmIdentifier *sigalg; +}; + +/** + * Allocate an to-be-signed certificate object that will be converted + * into an certificate. + * + * @param context A hx509 context. + * @param tbs returned to-be-signed certicate object, free with + * hx509_ca_tbs_free(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs) +{ + *tbs = calloc(1, sizeof(**tbs)); + if (*tbs == NULL) + return ENOMEM; + + return 0; +} + +/** + * Free an To Be Signed object. + * + * @param tbs object to free. + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_ca_tbs_free(hx509_ca_tbs *tbs) +{ + if (tbs == NULL || *tbs == NULL) + return; + + free_SubjectPublicKeyInfo(&(*tbs)->spki); + free_CertificatePolicies(&(*tbs)->cps); + free_PolicyMappings(&(*tbs)->pms); + free_GeneralNames(&(*tbs)->san); + free_ExtKeyUsage(&(*tbs)->eku); + der_free_heim_integer(&(*tbs)->serial); + free_CRLDistributionPoints(&(*tbs)->crldp); + der_free_bit_string(&(*tbs)->subjectUniqueID); + der_free_bit_string(&(*tbs)->issuerUniqueID); + if ((*tbs)->subject) + hx509_name_free(&(*tbs)->subject); + if ((*tbs)->sigalg) { + free_AlgorithmIdentifier((*tbs)->sigalg); + free((*tbs)->sigalg); + } + + memset(*tbs, 0, sizeof(**tbs)); + free(*tbs); + *tbs = NULL; +} + +/** + * Set the absolute time when the certificate is valid from. If not + * set the current time will be used. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param t time the certificated will start to be valid + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_notBefore(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notBefore = t; + return 0; +} + +/** + * Set the absolute time when the certificate is valid to. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param t time when the certificate will expire + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_notAfter(hx509_context context, + hx509_ca_tbs tbs, + time_t t) +{ + tbs->notAfter = t; + return 0; +} + +/** + * Set the relative time when the certificiate is going to expire. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param delta seconds to the certificate is going to expire. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_notAfter_lifetime(hx509_context context, + hx509_ca_tbs tbs, + time_t delta) +{ + return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_pkinit_max_life(hx509_context context, + hx509_ca_tbs tbs, + time_t max_life) +{ + tbs->pkinitTicketMaxLife = max_life; + return 0; +} + +static const struct units templatebits[] = { + { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU }, + { "KeyUsage", HX509_CA_TEMPLATE_KU }, + { "SPKI", HX509_CA_TEMPLATE_SPKI }, + { "notAfter", HX509_CA_TEMPLATE_NOTAFTER }, + { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE }, + { "serial", HX509_CA_TEMPLATE_SERIAL }, + { "subject", HX509_CA_TEMPLATE_SUBJECT }, + { "pkinitMaxLife", HX509_CA_TEMPLATE_PKINIT_MAX_LIFE }, + { NULL, 0 } +}; + +/** + * Make of template units, use to build flags argument to + * hx509_ca_tbs_set_template() with parse_units(). + * + * @return an units structure. + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION const struct units * HX509_LIB_CALL +hx509_ca_tbs_template_units(void) +{ + return templatebits; +} + +/** + * Initialize the to-be-signed certificate object from a template certificate. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param flags bit field selecting what to copy from the template + * certificate. + * @param cert template certificate. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_template(hx509_context context, + hx509_ca_tbs tbs, + int flags, + hx509_cert cert) +{ + int ret; + + if (flags & HX509_CA_TEMPLATE_SUBJECT) { + if (tbs->subject) + hx509_name_free(&tbs->subject); + ret = hx509_cert_get_subject(cert, &tbs->subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to get subject from template"); + return ret; + } + } + if (flags & HX509_CA_TEMPLATE_SERIAL) { + der_free_heim_integer(&tbs->serial); + ret = hx509_cert_get_serialnumber(cert, &tbs->serial); + tbs->flags.serial = !ret; + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy serial number"); + return ret; + } + } + if (flags & HX509_CA_TEMPLATE_NOTBEFORE) + tbs->notBefore = hx509_cert_get_notBefore(cert); + if (flags & HX509_CA_TEMPLATE_NOTAFTER) + tbs->notAfter = hx509_cert_get_notAfter(cert); + if (flags & HX509_CA_TEMPLATE_SPKI) { + free_SubjectPublicKeyInfo(&tbs->spki); + ret = hx509_cert_get_SPKI(context, cert, &tbs->spki); + tbs->flags.key = !ret; + if (ret) + return ret; + } + if (flags & HX509_CA_TEMPLATE_KU) { + ret = _hx509_cert_get_keyusage(context, cert, &tbs->ku); + if (ret) + return ret; + } + if (flags & HX509_CA_TEMPLATE_EKU) { + ExtKeyUsage eku; + size_t i; + ret = _hx509_cert_get_eku(context, cert, &eku); + if (ret) + return ret; + for (i = 0; i < eku.len; i++) { + ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]); + if (ret) { + free_ExtKeyUsage(&eku); + return ret; + } + } + free_ExtKeyUsage(&eku); + } + if (flags & HX509_CA_TEMPLATE_PKINIT_MAX_LIFE) { + time_t max_life; + + if ((max_life = hx509_cert_get_pkinit_max_life(context, cert, 0)) > 0) + hx509_ca_tbs_set_pkinit_max_life(context, tbs, max_life); + } + return 0; +} + +/** + * Make the to-be-signed certificate object a CA certificate. If the + * pathLenConstraint is negative path length constraint is used. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param pathLenConstraint path length constraint, negative, no + * constraint. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_ca(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.ca = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + +/** + * Make the to-be-signed certificate object a proxy certificate. If the + * pathLenConstraint is negative path length constraint is used. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param pathLenConstraint path length constraint, negative, no + * constraint. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_proxy(hx509_context context, + hx509_ca_tbs tbs, + int pathLenConstraint) +{ + tbs->flags.proxy = 1; + tbs->pathLenConstraint = pathLenConstraint; + return 0; +} + + +/** + * Make the to-be-signed certificate object a windows domain controller certificate. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_domaincontroller(hx509_context context, + hx509_ca_tbs tbs) +{ + tbs->flags.domaincontroller = 1; + return 0; +} + +/** + * Set the subject public key info (SPKI) in the to-be-signed certificate + * object. SPKI is the public key and key related parameters in the + * certificate. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param spki subject public key info to use for the to-be-signed certificate object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_spki(hx509_context context, + hx509_ca_tbs tbs, + const SubjectPublicKeyInfo *spki) +{ + int ret; + free_SubjectPublicKeyInfo(&tbs->spki); + ret = copy_SubjectPublicKeyInfo(spki, &tbs->spki); + tbs->flags.key = !ret; + return ret; +} + +/** + * Set the serial number to use for to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param serialNumber serial number to use for the to-be-signed + * certificate object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_serialnumber(hx509_context context, + hx509_ca_tbs tbs, + const heim_integer *serialNumber) +{ + int ret; + der_free_heim_integer(&tbs->serial); + ret = der_copy_heim_integer(serialNumber, &tbs->serial); + tbs->flags.serial = !ret; + return ret; +} + +/** + * Copy elements of a CSR into a TBS, but only if all of them are authorized. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param req CSR + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_from_csr(hx509_context context, + hx509_ca_tbs tbs, + hx509_request req) +{ + hx509_san_type san_type; + heim_oid oid = { 0, NULL }; + KeyUsage ku; + size_t i; + char *s = NULL; + int ret; + + if (hx509_request_count_unauthorized(req)) { + hx509_set_error_string(context, 0, EACCES, + "Some certificate features requested in the CSR were not authorized"); + return EACCES; + } + + ret = hx509_request_get_ku(context, req, &ku); + if (ret == 0 && KeyUsage2int(ku)) + ret = hx509_ca_tbs_add_ku(context, tbs, ku); + + for (i = 0; ret == 0; i++) { + free(s); s = NULL; + der_free_oid(&oid); + ret = hx509_request_get_eku(req, i, &s); + if (ret == 0) + ret = der_parse_heim_oid(s, ".", &oid); + if (ret == 0) + ret = hx509_ca_tbs_add_eku(context, tbs, &oid); + } + if (ret == HX509_NO_ITEM) + ret = 0; + + for (i = 0; ret == 0; i++) { + free(s); s = NULL; + ret = hx509_request_get_san(req, i, &san_type, &s); + if (ret == 0) + ret = hx509_ca_tbs_add_san(context, tbs, san_type, s); + } + if (ret == HX509_NO_ITEM) + ret = 0; + + der_free_oid(&oid); + free(s); + return ret; +} + +/** + * An an extended key usage to the to-be-signed certificate object. + * Duplicates will detected and not added. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param oid extended key usage to add. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_ku(hx509_context context, + hx509_ca_tbs tbs, + KeyUsage ku) +{ + tbs->ku = ku; + return 0; +} + +/** + * An an extended key usage to the to-be-signed certificate object. + * Duplicates will detected and not added. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param oid extended key usage to add. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_eku(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid) +{ + void *ptr; + int ret; + unsigned i; + + /* search for duplicates */ + for (i = 0; i < tbs->eku.len; i++) { + if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0) + return 0; + } + + ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + tbs->eku.val = ptr; + ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + tbs->eku.len += 1; + return 0; +} + +/** + * Add a certificate policy to the to-be-signed certificate object. Duplicates + * will detected and not added. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param oid policy OID. + * @param cps_uri CPS URI to qualify policy with. + * @param user_notice user notice display text to qualify policy with. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_pol(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const char *cps_uri, + const char *user_notice) +{ + PolicyQualifierInfos pqis; + PolicyQualifierInfo pqi; + PolicyInformation pi; + size_t i, size; + int ret = 0; + + /* search for duplicates */ + for (i = 0; i < tbs->cps.len; i++) { + if (der_heim_oid_cmp(oid, &tbs->cps.val[i].policyIdentifier) == 0) + return 0; + } + + memset(&pi, 0, sizeof(pi)); + memset(&pqi, 0, sizeof(pqi)); + memset(&pqis, 0, sizeof(pqis)); + + pi.policyIdentifier = *oid; + if (cps_uri) { + CPSuri uri; + + uri.length = strlen(cps_uri); + uri.data = (void *)(uintptr_t)cps_uri; + pqi.policyQualifierId = asn1_oid_id_pkix_qt_cps; + + ASN1_MALLOC_ENCODE(CPSuri, + pqi.qualifier.data, + pqi.qualifier.length, + &uri, &size, ret); + if (ret == 0) { + ret = add_PolicyQualifierInfos(&pqis, &pqi); + free_heim_any(&pqi.qualifier); + } + } + if (ret == 0 && user_notice) { + DisplayText dt; + UserNotice un; + + dt.element = choice_DisplayText_utf8String; + dt.u.utf8String = (void *)(uintptr_t)user_notice; + un.explicitText = &dt; + un.noticeRef = 0; + + pqi.policyQualifierId = asn1_oid_id_pkix_qt_unotice; + ASN1_MALLOC_ENCODE(UserNotice, + pqi.qualifier.data, + pqi.qualifier.length, + &un, &size, ret); + if (ret == 0) { + ret = add_PolicyQualifierInfos(&pqis, &pqi); + free_heim_any(&pqi.qualifier); + } + } + + pi.policyQualifiers = pqis.len ? &pqis : 0; + + if (ret == 0) + ret = add_CertificatePolicies(&tbs->cps, &pi); + + free_PolicyQualifierInfos(&pqis); + return ret; +} + +/** + * Add a certificate policy mapping to the to-be-signed certificate object. + * Duplicates will detected and not added. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param issuer issuerDomainPolicy policy OID. + * @param subject subjectDomainPolicy policy OID. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_pol_mapping(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *issuer, + const heim_oid *subject) +{ + PolicyMapping pm; + size_t i; + + /* search for duplicates */ + for (i = 0; i < tbs->pms.len; i++) { + PolicyMapping *pmp = &tbs->pms.val[i]; + if (der_heim_oid_cmp(issuer, &pmp->issuerDomainPolicy) == 0 && + der_heim_oid_cmp(subject, &pmp->subjectDomainPolicy) == 0) + return 0; + } + + memset(&pm, 0, sizeof(pm)); + pm.issuerDomainPolicy = *issuer; + pm.subjectDomainPolicy = *subject; + return add_PolicyMappings(&tbs->pms, &pm); +} + +/** + * Add CRL distribution point URI to the to-be-signed certificate + * object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param uri uri to the CRL. + * @param issuername name of the issuer. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_crl_dp_uri(hx509_context context, + hx509_ca_tbs tbs, + const char *uri, + hx509_name issuername) +{ + DistributionPointName dpn; + DistributionPoint dp; + GeneralNames crlissuer; + GeneralName gn, ign; + Name in; + int ret; + + memset(&dp, 0, sizeof(dp)); + memset(&gn, 0, sizeof(gn)); + memset(&ign, 0, sizeof(ign)); + memset(&in, 0, sizeof(in)); + gn.element = choice_GeneralName_uniformResourceIdentifier; + gn.u.uniformResourceIdentifier.data = rk_UNCONST(uri); + gn.u.uniformResourceIdentifier.length = strlen(uri); + dpn.element = choice_DistributionPointName_fullName; + dpn.u.fullName.len = 1; + dpn.u.fullName.val = &gn; + dp.distributionPoint = &dpn; + + if (issuername) { + ign.element = choice_GeneralName_directoryName; + ret = hx509_name_to_Name(issuername, &ign.u.directoryName); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + crlissuer.len = 1; + crlissuer.val = &ign; + dp.cRLIssuer = &crlissuer; + } + + ret = add_CRLDistributionPoints(&tbs->crldp, &dp); + if (issuername) + free_Name(&ign.u.directoryName); + + if (ret) + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; +} + +/** + * Add Subject Alternative Name otherName to the to-be-signed + * certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param oid the oid of the OtherName. + * @param os data in the other name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_otherName(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const heim_octet_string *os) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_otherName; + gn.u.otherName.type_id = *oid; + gn.u.otherName.value = *os; + + return add_GeneralNames(&tbs->san, &gn); +} + +static +int +dequote_strndup(hx509_context context, const char *in, size_t len, char **out) +{ + size_t i, k; + char *s; + + *out = NULL; + if ((s = malloc(len + 1)) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + for (k = i = 0; i < len; i++) { + if (in[i] == '\\') { + switch (in[++i]) { + case 't': s[k++] = '\t'; break; + case 'b': s[k++] = '\b'; break; + case 'n': s[k++] = '\n'; break; + case '0': + for (i++; i < len; i++) { + if (in[i] == '\0') + break; + if (in[i++] == '\\' && in[i] == '0') + continue; + hx509_set_error_string(context, 0, + HX509_PARSING_NAME_FAILED, + "embedded NULs not supported in " + "PKINIT SANs"); + free(s); + return HX509_PARSING_NAME_FAILED; + } + break; + case '\0': + hx509_set_error_string(context, 0, + HX509_PARSING_NAME_FAILED, + "trailing unquoted backslashes not " + "allowed in PKINIT SANs"); + free(s); + return HX509_PARSING_NAME_FAILED; + default: s[k++] = in[i]; break; + } + } else { + s[k++] = in[i]; + } + } + s[k] = '\0'; + + *out = s; + return 0; +} + +int +_hx509_make_pkinit_san(hx509_context context, + const char *principal, + heim_octet_string *os) +{ + KRB5PrincipalName p; + size_t size; + int ret; + + os->data = NULL; + os->length = 0; + memset(&p, 0, sizeof(p)); + + /* Parse principal */ + { + const char *str, *str_start; + size_t n, i; + + /* Count number of components */ + n = 1; + for (str = principal; *str != '\0' && *str != '@'; str++) { + if (*str == '\\') { + if (str[1] == '\0') { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "trailing \\ in principal name"); + goto out; + } + str++; + } else if(*str == '/') { + n++; + } else if(*str == '@') { + break; + } + } + if (*str != '@') { + /* Note that we allow the realm to be empty */ + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, "Missing @ in principal"); + goto out; + }; + + p.principalName.name_string.val = + calloc(n, sizeof(*p.principalName.name_string.val)); + if (p.principalName.name_string.val == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } + p.principalName.name_string.len = n; + p.principalName.name_type = KRB5_NT_PRINCIPAL; + + for (i = 0, str_start = str = principal; *str != '\0'; str++) { + if (*str=='\\') { + str++; + } else if(*str == '/') { + /* Note that we allow components to be empty */ + ret = dequote_strndup(context, str_start, str - str_start, + &p.principalName.name_string.val[i++]); + if (ret) + goto out; + str_start = str + 1; + } else if(*str == '@') { + ret = dequote_strndup(context, str_start, str - str_start, + &p.principalName.name_string.val[i++]); + if (ret == 0) + ret = dequote_strndup(context, str + 1, strlen(str + 1), &p.realm); + if (ret) + goto out; + break; + } + } + } + + ASN1_MALLOC_ENCODE(KRB5PrincipalName, os->data, os->length, &p, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != os->length) + _hx509_abort("internal ASN.1 encoder error"); + +out: + free_KRB5PrincipalName(&p); + return ret; +} + +static int +add_ia5string_san(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const char *string) +{ + SRVName ustring; + heim_octet_string os; + size_t size; + int ret; + + ustring.data = (void *)(uintptr_t)string; + ustring.length = strlen(string); + + os.length = 0; + os.data = NULL; + + ASN1_MALLOC_ENCODE(SRVName, os.data, os.length, &ustring, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + return ret; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, tbs, oid, &os); + free(os.data); + return ret; +} + +/** + * Add DNSSRV Subject Alternative Name to the to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param dnssrv An ASCII string of the for _Service.Name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_dnssrv(hx509_context context, + hx509_ca_tbs tbs, + const char *dnssrv) +{ + size_t i, len; + + /* Minimal DNSSRV input validation */ + if (dnssrv == 0 || dnssrv[0] != '_') { + hx509_set_error_string(context, 0, EINVAL, "Invalid DNSSRV name"); + return EINVAL; + } + for (i = 1, len = strlen(dnssrv); i < len; i++) { + if (dnssrv[i] == '.' && dnssrv[i + 1] != '\0') + break; + } + if (i == len) { + hx509_set_error_string(context, 0, EINVAL, "Invalid DNSSRV name"); + return EINVAL; + } + + return add_ia5string_san(context, tbs, + &asn1_oid_id_pkix_on_dnsSRV, dnssrv); +} + +/** + * Add Kerberos Subject Alternative Name to the to-be-signed + * certificate object. The principal string is a UTF8 string. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param principal Kerberos principal to add to the certificate. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_pkinit(hx509_context context, + hx509_ca_tbs tbs, + const char *principal) +{ + heim_octet_string os; + int ret; + + ret = _hx509_make_pkinit_san(context, principal, &os); + if (ret == 0) + ret = hx509_ca_tbs_add_san_otherName(context, tbs, + &asn1_oid_id_pkinit_san, &os); + free(os.data); + return ret; +} + +/* + * + */ + +static int +add_utf8_san(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const char *string) +{ + const PKIXXmppAddr ustring = (const PKIXXmppAddr)(uintptr_t)string; + heim_octet_string os; + size_t size; + int ret; + + os.length = 0; + os.data = NULL; + + ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + return ret; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, tbs, oid, &os); + free(os.data); + return ret; +} + +/** + * Add Microsoft UPN Subject Alternative Name to the to-be-signed + * certificate object. The principal string is a UTF8 string. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param principal Microsoft UPN string. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_ms_upn(hx509_context context, + hx509_ca_tbs tbs, + const char *principal) +{ + return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal); +} + +/** + * Add a Jabber/XMPP jid Subject Alternative Name to the to-be-signed + * certificate object. The jid is an UTF8 string. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param jid string of an a jabber id in UTF8. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_jid(hx509_context context, + hx509_ca_tbs tbs, + const char *jid) +{ + return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid); +} + + +/** + * Add a Subject Alternative Name hostname to to-be-signed certificate + * object. A domain match starts with ., an exact match does not. + * + * Example of a an domain match: .domain.se matches the hostname + * host.domain.se. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param dnsname a hostame. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_hostname(hx509_context context, + hx509_ca_tbs tbs, + const char *dnsname) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_dNSName; + gn.u.dNSName.data = rk_UNCONST(dnsname); + gn.u.dNSName.length = strlen(dnsname); + + return add_GeneralNames(&tbs->san, &gn); +} + +/** + * Add a Subject Alternative Name rfc822 (email address) to + * to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param rfc822Name a string to a email address. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_rfc822name(hx509_context context, + hx509_ca_tbs tbs, + const char *rfc822Name) +{ + GeneralName gn; + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_rfc822Name; + gn.u.rfc822Name.data = rk_UNCONST(rfc822Name); + gn.u.rfc822Name.length = strlen(rfc822Name); + + return add_GeneralNames(&tbs->san, &gn); +} + +/* + * PermanentIdentifier is one SAN for naming devices with TPMs after their + * endorsement keys or EK certificates. See TPM 2.0 Keys for Device Identity + * and Attestation, Version 1.00, Revision 2, 9/17/2020 (DRAFT). + * + * The text on the form of permanent identifiers for TPM endorsement keys sans + * certificates is clearly problematic, saying: "When the TPM does not have an + * EK certificate, the identifierValue is a digest of a concatenation of the + * UTF8 string “EkPubkey” (terminating NULL not included) with the binary EK + * public key", but since arbitrary binary is not necessarily valid UTF-8... + * and since NULs embedded in UTF-8 might be OK in some contexts but really + * isn't in C (and Heimdal's ASN.1 compiler does not allow NULs in the + * middle of strings)... That just cannot be correct. Since elsewhere the TCG + * specs use the hex encoding of the SHA-256 digest of the DER encoding of + * public keys, that's what we should support in Heimdal, and maybe send in a + * comment. + * + * Also, even where one should use hex encoding of the SHA-256 digest of the + * DER encoding of public keys, how should the public keys be represented? + * Presumably as SPKIs, with all the required parameters and no more. + */ + +/** + * Add a Subject Alternative Name of PermanentIdentifier type to a to-be-signed + * certificate object. The permanent identifier form for TPM endorsement key + * certificates is the hex encoding of the SHA-256 digest of the DER encoding + * of the certificate. The permanent identifier form for TPM endorsement keys + * are of the form "EkPubkey", where the form of is + * not well specified at this point. It is the caller's responsibility to + * format the identifierValue. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param str permanent identifier name in the form "[]:[]". + * @param assigner The OID of an assigner. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_permanentIdentifier_string(hx509_context context, + hx509_ca_tbs tbs, + const char *str) +{ + const heim_oid *found = NULL; + heim_oid oid; + const char *oidstr, *id; + char *freeme, *p; + int ret; + + memset(&oid, 0, sizeof(oid)); + if ((freeme = strdup(str)) == NULL) + return hx509_enomem(context); + + oidstr = freeme; + p = strchr(freeme, ':'); + if (!p) { + hx509_set_error_string(context, 0, EINVAL, + "Invalid PermanentIdentifier string (should be \"[]:[]\")"); + free(freeme); + return EINVAL; + } + if (p) { + *(p++) = '\0'; + id = p; + } + if (oidstr[0] != '\0') { + ret = der_find_heim_oid_by_name(oidstr, &found); + if (ret) { + ret = der_parse_heim_oid(oidstr, " .", &oid); + if (ret == 0) + found = &oid; + } + } + ret = hx509_ca_tbs_add_san_permanentIdentifier(context, tbs, id, found); + if (found == &oid) + der_free_oid(&oid); + free(freeme); + return ret; +} + +/** + * Add a Subject Alternative Name of PermanentIdentifier type to a to-be-signed + * certificate object. The permanent identifier form for TPM endorsement key + * certificates is the hex encoding of the SHA-256 digest of the DER encoding + * of the certificate. The permanent identifier form for TPM endorsement keys + * are of the form "EkPubkey", where the form of is + * not well specified at this point. It is the caller's responsibility to + * format the identifierValue. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param identifierValue The permanent identifier name. + * @param assigner The OID of an assigner. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_permanentIdentifier(hx509_context context, + hx509_ca_tbs tbs, + const char *identifierValue, + const heim_oid *assigner) +{ + PermanentIdentifier pi; + heim_utf8_string s = (void *)(uintptr_t)identifierValue; + heim_octet_string os; + size_t size; + int ret; + + pi.identifierValue = &s; + pi.assigner = (heim_oid*)(uintptr_t)assigner; + os.length = 0; + os.data = NULL; + + ASN1_MALLOC_ENCODE(PermanentIdentifier, os.data, os.length, &pi, &size, + ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + return ret; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, tbs, + &asn1_oid_id_pkix_on_permanentIdentifier, + &os); + free(os.data); + return ret; +} + +/** + * Add a Subject Alternative Name of HardwareModuleName type to a to-be-signed + * certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param str a string of the form ":". + * @param hwserial The serial number. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_hardwareModuleName_string(hx509_context context, + hx509_ca_tbs tbs, + const char *str) +{ + const heim_oid *found = NULL; + heim_oid oid; + const char *oidstr, *sno; + char *freeme, *p; + int ret; + + memset(&oid, 0, sizeof(oid)); + if ((freeme = strdup(str)) == NULL) + return hx509_enomem(context); + + oidstr = freeme; + p = strchr(freeme, ':'); + if (!p) { + hx509_set_error_string(context, 0, EINVAL, + "Invalid HardwareModuleName string (should be " + "\":\")"); + free(freeme); + return EINVAL; + } + if (p) { + *(p++) = '\0'; + sno = p; + } + if (oidstr[0] == '\0') { + found = &asn1_oid_tcg_tpm20; + } else { + ret = der_find_heim_oid_by_name(oidstr, &found); + if (ret) { + ret = der_parse_heim_oid(oidstr, " .", &oid); + if (ret == 0) + found = &oid; + } + } + if (!found) { + hx509_set_error_string(context, 0, EINVAL, + "Could not resolve or parse OID \"%s\"", + oidstr); + free(freeme); + return EINVAL; + } + ret = hx509_ca_tbs_add_san_hardwareModuleName(context, tbs, found, sno); + if (found == &oid) + der_free_oid(&oid); + free(freeme); + return ret; +} + +/** + * Add a Subject Alternative Name of HardwareModuleName type to a to-be-signed + * certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param hwtype The hardwar module type (e.g., `&asn1_oid_tcg_tpm20'). + * @param hwserial The serial number. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san_hardwareModuleName(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *hwtype, + const char *hwserial) +{ + HardwareModuleName hm; + heim_octet_string os; + size_t size; + int ret; + + hm.hwType = *hwtype; + hm.hwSerialNum.data = (void *)(uintptr_t)hwserial; + hm.hwSerialNum.length = strlen(hwserial); + os.length = 0; + os.data = NULL; + + ASN1_MALLOC_ENCODE(HardwareModuleName, os.data, os.length, &hm, &size, + ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + return ret; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, tbs, + &asn1_oid_id_on_hardwareModuleName, + &os); + free(os.data); + return ret; +} + +/** + * Add a Subject Alternative Name of the given type to the + * to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param rfc822Name a string to a email address. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_add_san(hx509_context context, + hx509_ca_tbs tbs, + hx509_san_type type, + const char *s) +{ + switch (type) { + case HX509_SAN_TYPE_EMAIL: + return hx509_ca_tbs_add_san_rfc822name(context, tbs, s); + case HX509_SAN_TYPE_DNSNAME: + return hx509_ca_tbs_add_san_hostname(context, tbs, s); + case HX509_SAN_TYPE_DN: + return ENOTSUP; + case HX509_SAN_TYPE_REGISTERED_ID: + return ENOTSUP; + case HX509_SAN_TYPE_XMPP: + return hx509_ca_tbs_add_san_jid(context, tbs, s); + case HX509_SAN_TYPE_PKINIT: + return hx509_ca_tbs_add_san_pkinit(context, tbs, s); + case HX509_SAN_TYPE_MS_UPN: + return hx509_ca_tbs_add_san_ms_upn(context, tbs, s); + default: + return ENOTSUP; + } +} + +/** + * Set the subject name of a to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param subject the name to set a subject. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_subject(hx509_context context, + hx509_ca_tbs tbs, + hx509_name subject) +{ + if (tbs->subject) + hx509_name_free(&tbs->subject); + return hx509_name_copy(context, subject, &tbs->subject); +} + +/** + * Set the issuerUniqueID and subjectUniqueID + * + * These are only supposed to be used considered with version 2 + * certificates, replaced by the two extensions SubjectKeyIdentifier + * and IssuerKeyIdentifier. This function is to allow application + * using legacy protocol to issue them. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param issuerUniqueID to be set + * @param subjectUniqueID to be set + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_unique(hx509_context context, + hx509_ca_tbs tbs, + const heim_bit_string *subjectUniqueID, + const heim_bit_string *issuerUniqueID) +{ + int ret; + + der_free_bit_string(&tbs->subjectUniqueID); + der_free_bit_string(&tbs->issuerUniqueID); + + if (subjectUniqueID) { + ret = der_copy_bit_string(subjectUniqueID, &tbs->subjectUniqueID); + if (ret) + return ret; + } + + if (issuerUniqueID) { + ret = der_copy_bit_string(issuerUniqueID, &tbs->issuerUniqueID); + if (ret) + return ret; + } + + return 0; +} + +/** + * Expand the the subject name in the to-be-signed certificate object + * using hx509_name_expand(). + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param env environment variable to expand variables in the subject + * name, see hx509_env_init(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_subject_expand(hx509_context context, + hx509_ca_tbs tbs, + hx509_env env) +{ + return hx509_name_expand(context, tbs->subject, env); +} + +/** + * Get the name of a to-be-signed certificate object. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * + * @return An hx509 name. + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION hx509_name HX509_LIB_CALL +hx509_ca_tbs_get_name(hx509_ca_tbs tbs) +{ + return tbs->subject; +} + +/** + * Set signature algorithm on the to be signed certificate + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param sigalg signature algorithm to use + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_tbs_set_signature_algorithm(hx509_context context, + hx509_ca_tbs tbs, + const AlgorithmIdentifier *sigalg) +{ + int ret; + + tbs->sigalg = calloc(1, sizeof(*tbs->sigalg)); + if (tbs->sigalg == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); + return ENOMEM; + } + ret = copy_AlgorithmIdentifier(sigalg, tbs->sigalg); + if (ret) { + free(tbs->sigalg); + tbs->sigalg = NULL; + return ret; + } + return 0; +} + +/* + * + */ + +static int +add_extension(hx509_context context, + TBSCertificate *tbsc, + int critical_flag, + const heim_oid *oid, + const heim_octet_string *data) +{ + Extension ext; + int ret; + + memset(&ext, 0, sizeof(ext)); + + ext.critical = critical_flag; + ret = der_copy_oid(oid, &ext.extnID); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_octet_string(data, &ext.extnValue); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = add_Extensions(tbsc->extensions, &ext); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } +out: + free_Extension(&ext); + return ret; +} + +static int +build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject) +{ + char *tstr; + time_t t; + int ret; + + ret = copy_Name(issuer, subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy subject name"); + return ret; + } + + t = time(NULL); + ret = asprintf(&tstr, "ts-%lu", (unsigned long)t); + if (ret == -1 || tstr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Failed to copy subject name"); + return ENOMEM; + } + /* prefix with CN=,...*/ + ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr); + free(tstr); + if (ret) + free_Name(subject); + return ret; +} + +static int +ca_sign(hx509_context context, + hx509_ca_tbs tbs, + hx509_private_key signer, + const AuthorityKeyIdentifier *ai, + const Name *issuername, + hx509_cert *certificate) +{ + heim_error_t error = NULL; + heim_octet_string data; + Certificate c; + TBSCertificate *tbsc; + size_t size; + int ret; + const AlgorithmIdentifier *sigalg; + time_t notBefore; + time_t notAfter; + + sigalg = tbs->sigalg; + if (sigalg == NULL) + sigalg = _hx509_crypto_default_sig_alg; + + memset(&c, 0, sizeof(c)); + + /* + * Default values are: Valid since 24h ago, valid one year into + * the future, KeyUsage digitalSignature and keyEncipherment set, + * and keyCertSign for CA certificates. + */ + notBefore = tbs->notBefore; + if (notBefore == 0) + notBefore = time(NULL) - 3600 * 24; + notAfter = tbs->notAfter; + if (notAfter == 0) + notAfter = time(NULL) + 3600 * 24 * 365; + + if (tbs->flags.ca) { + tbs->ku.keyCertSign = 1; + tbs->ku.cRLSign = 1; + } else if (KeyUsage2int(tbs->ku) == 0) { + tbs->ku.digitalSignature = 1; + tbs->ku.keyEncipherment = 1; + } + + /* + * + */ + + tbsc = &c.tbsCertificate; + + /* Default subject Name to empty */ + if (tbs->subject == NULL && + (ret = hx509_empty_name(context, &tbs->subject))) + return ret; + + /* Sanity checks */ + if (tbs->flags.key == 0) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "No public key set"); + return ret; + } + /* + * Don't put restrictions on proxy certificate's subject name, it + * will be generated below. + */ + if (!tbs->flags.proxy) { + if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) { + hx509_set_error_string(context, 0, EINVAL, + "Empty subject and no SubjectAltNames"); + return EINVAL; + } + } + if (tbs->flags.ca && tbs->flags.proxy) { + hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA " + "at the same time"); + return EINVAL; + } + if (tbs->flags.proxy) { + if (tbs->san.len > 0) { + hx509_set_error_string(context, 0, EINVAL, + "Proxy certificate is not allowed " + "to have SubjectAltNames"); + return EINVAL; + } + } + + /* version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, */ + tbsc->version = calloc(1, sizeof(*tbsc->version)); + if (tbsc->version == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + *tbsc->version = rfc3280_version_3; + /* serialNumber CertificateSerialNumber, */ + if (tbs->flags.serial) { + ret = der_copy_heim_integer(&tbs->serial, &tbsc->serialNumber); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } else { + /* + * If no explicit serial number is specified, 20 random bytes should be + * sufficiently collision resistant. Since the serial number must be a + * positive integer, ensure minimal ASN.1 DER form by forcing the high + * bit off and the next bit on (thus avoiding an all zero first octet). + */ + tbsc->serialNumber.length = 20; + tbsc->serialNumber.data = malloc(tbsc->serialNumber.length); + if (tbsc->serialNumber.data == NULL){ + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = RAND_bytes(tbsc->serialNumber.data, tbsc->serialNumber.length); + if (ret != 1) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + hx509_set_error_string(context, 0, ret, "Failed to generate random bytes"); + goto out; + } + ((unsigned char *)tbsc->serialNumber.data)[0] &= 0x7f; + ((unsigned char *)tbsc->serialNumber.data)[0] |= 0x40; + } + /* signature AlgorithmIdentifier, */ + ret = copy_AlgorithmIdentifier(sigalg, &tbsc->signature); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy signature alg"); + goto out; + } + /* issuer Name, */ + if (issuername) + ret = copy_Name(issuername, &tbsc->issuer); + else + ret = hx509_name_to_Name(tbs->subject, &tbsc->issuer); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy issuer name"); + goto out; + } + /* validity Validity, */ + { + /* + * From RFC 5280, section 4.1.2.5: + * + * CAs conforming to this profile MUST always encode certificate + * validity dates through the year 2049 as UTCTime; certificate validity + * dates in 2050 or later MUST be encoded as GeneralizedTime. + * Conforming applications MUST be able to process validity dates that + * are encoded in either UTCTime or GeneralizedTime. + * + * 2524608000 is seconds since the epoch for 2050-01-01T00:00:00Z. + * + * Both, ...u.generalTime and ...u..utcTime are time_t. + */ + if (notBefore < 1 || (int64_t)notBefore < 2524608000) + tbsc->validity.notBefore.element = choice_Time_utcTime; + else + tbsc->validity.notBefore.element = choice_Time_generalTime; + tbsc->validity.notBefore.u.generalTime = notBefore; + + if (notAfter < 1 || (int64_t)notAfter < 2524608000) + tbsc->validity.notAfter.element = choice_Time_utcTime; + else + tbsc->validity.notAfter.element = choice_Time_generalTime; + tbsc->validity.notAfter.u.generalTime = notAfter; + } + /* subject Name, */ + if (tbs->flags.proxy) { + ret = build_proxy_prefix(context, &tbsc->issuer, &tbsc->subject); + if (ret) + goto out; + } else { + ret = hx509_name_to_Name(tbs->subject, &tbsc->subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy subject name"); + goto out; + } + } + /* subjectPublicKeyInfo SubjectPublicKeyInfo, */ + ret = copy_SubjectPublicKeyInfo(&tbs->spki, &tbsc->subjectPublicKeyInfo); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy spki"); + goto out; + } + /* issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL */ + if (tbs->issuerUniqueID.length) { + tbsc->issuerUniqueID = calloc(1, sizeof(*tbsc->issuerUniqueID)); + if (tbsc->issuerUniqueID == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_bit_string(&tbs->issuerUniqueID, tbsc->issuerUniqueID); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } + /* subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL */ + if (tbs->subjectUniqueID.length) { + tbsc->subjectUniqueID = calloc(1, sizeof(*tbsc->subjectUniqueID)); + if (tbsc->subjectUniqueID == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + ret = der_copy_bit_string(&tbs->subjectUniqueID, tbsc->subjectUniqueID); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } + + /* extensions [3] EXPLICIT Extensions OPTIONAL */ + tbsc->extensions = calloc(1, sizeof(*tbsc->extensions)); + if (tbsc->extensions == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + /* Add the text BMP string Domaincontroller to the cert */ + if (tbs->flags.domaincontroller) { + data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d" + "\x00\x61\x00\x69\x00\x6e\x00\x43" + "\x00\x6f\x00\x6e\x00\x74\x00\x72" + "\x00\x6f\x00\x6c\x00\x6c\x00\x65" + "\x00\x72"); + data.length = 34; + + ret = add_extension(context, tbsc, 0, + &asn1_oid_id_ms_cert_enroll_domaincontroller, + &data); + if (ret) + goto out; + } + + /* Add KeyUsage */ + if (KeyUsage2int(tbs->ku) > 0) { + ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, + &tbs->ku, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 1, + &asn1_oid_id_x509_ce_keyUsage, &data); + free(data.data); + if (ret) + goto out; + } + + /* Add ExtendedKeyUsage */ + if (tbs->eku.len > 0) { + ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length, + &tbs->eku, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 1, + &asn1_oid_id_x509_ce_extKeyUsage, &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Subject Alternative Name */ + if (tbs->san.len > 0) { + ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length, + &tbs->san, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + + /* The SAN extension is critical if the subject Name is empty */ + ret = add_extension(context, tbsc, hx509_name_is_null_p(tbs->subject), + &asn1_oid_id_x509_ce_subjectAltName, &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Authority Key Identifier */ + if (ai) { + ASN1_MALLOC_ENCODE(AuthorityKeyIdentifier, data.data, data.length, + ai, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + &asn1_oid_id_x509_ce_authorityKeyIdentifier, + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Subject Key Identifier */ + { + SubjectKeyIdentifier si; + unsigned char hash[SHA_DIGEST_LENGTH]; + + { + EVP_MD_CTX *ctx; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); + EVP_DigestUpdate(ctx, tbs->spki.subjectPublicKey.data, + tbs->spki.subjectPublicKey.length / 8); + EVP_DigestFinal_ex(ctx, hash, NULL); + EVP_MD_CTX_destroy(ctx); + } + + si.data = hash; + si.length = sizeof(hash); + + ASN1_MALLOC_ENCODE(SubjectKeyIdentifier, data.data, data.length, + &si, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + &asn1_oid_id_x509_ce_subjectKeyIdentifier, + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add BasicConstraints */ + { + BasicConstraints bc; + unsigned int path; + + memset(&bc, 0, sizeof(bc)); + + if (tbs->flags.ca) { + bc.cA = 1; + if (tbs->pathLenConstraint >= 0) { + path = tbs->pathLenConstraint; + bc.pathLenConstraint = &path; + } + } + + ASN1_MALLOC_ENCODE(BasicConstraints, data.data, data.length, + &bc, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + /* Critical if this is a CA */ + ret = add_extension(context, tbsc, tbs->flags.ca, + &asn1_oid_id_x509_ce_basicConstraints, + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Proxy */ + if (tbs->flags.proxy) { + ProxyCertInfo info; + + memset(&info, 0, sizeof(info)); + + if (tbs->pathLenConstraint >= 0) { + info.pCPathLenConstraint = + malloc(sizeof(*info.pCPathLenConstraint)); + if (info.pCPathLenConstraint == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + *info.pCPathLenConstraint = tbs->pathLenConstraint; + } + + ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll, + &info.proxyPolicy.policyLanguage); + if (ret) { + free_ProxyCertInfo(&info); + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + ASN1_MALLOC_ENCODE(ProxyCertInfo, data.data, data.length, + &info, &size, ret); + free_ProxyCertInfo(&info); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, 0, + &asn1_oid_id_pkix_pe_proxyCertInfo, + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add CRL distribution point */ + if (tbs->crldp.len) { + ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length, + &tbs->crldp, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, FALSE, + &asn1_oid_id_x509_ce_cRLDistributionPoints, + &data); + free(data.data); + if (ret) + goto out; + } + + /* Add CertificatePolicies */ + if (tbs->cps.len) { + ASN1_MALLOC_ENCODE(CertificatePolicies, data.data, data.length, + &tbs->cps, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, FALSE, + &asn1_oid_id_x509_ce_certificatePolicies, &data); + free(data.data); + if (ret) + goto out; + } + + /* Add PolicyMappings */ + if (tbs->cps.len) { + ASN1_MALLOC_ENCODE(PolicyMappings, data.data, data.length, + &tbs->pms, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, FALSE, + &asn1_oid_id_x509_ce_policyMappings, &data); + free(data.data); + if (ret) + goto out; + } + + /* Add Heimdal PKINIT ticket max life extension */ + if (tbs->pkinitTicketMaxLife > 0) { + ASN1_MALLOC_ENCODE(HeimPkinitPrincMaxLifeSecs, data.data, data.length, + &tbs->pkinitTicketMaxLife, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, FALSE, + &asn1_oid_id_heim_ce_pkinit_princ_max_life, &data); + free(data.data); + if (ret) + goto out; + } + + ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + goto out; + } + if (data.length != size) + _hx509_abort("internal ASN.1 encoder error"); + + ret = _hx509_create_signature_bitstring(context, + signer, + sigalg, + &data, + &c.signatureAlgorithm, + &c.signatureValue); + free(data.data); + if (ret) + goto out; + + *certificate = hx509_cert_init(context, &c, &error); + if (*certificate == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + goto out; + } + + free_Certificate(&c); + + return 0; + +out: + free_Certificate(&c); + return ret; +} + +static int +get_AuthorityKeyIdentifier(hx509_context context, + const Certificate *certificate, + AuthorityKeyIdentifier *ai) +{ + SubjectKeyIdentifier si; + int ret; + + ret = _hx509_find_extension_subject_key_id(certificate, &si); + if (ret == 0) { + ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier)); + if (ai->keyIdentifier == NULL) { + free_SubjectKeyIdentifier(&si); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ret = der_copy_octet_string(&si, ai->keyIdentifier); + free_SubjectKeyIdentifier(&si); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } else { + GeneralNames gns; + GeneralName gn; + Name name; + + memset(&gn, 0, sizeof(gn)); + memset(&gns, 0, sizeof(gns)); + memset(&name, 0, sizeof(name)); + + ai->authorityCertIssuer = + calloc(1, sizeof(*ai->authorityCertIssuer)); + if (ai->authorityCertIssuer == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + ai->authorityCertSerialNumber = + calloc(1, sizeof(*ai->authorityCertSerialNumber)); + if (ai->authorityCertSerialNumber == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + /* + * XXX unbreak when asn1 compiler handle IMPLICIT + * + * This is so horrible. + */ + + ret = copy_Name(&certificate->tbsCertificate.subject, &name); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_directoryName; + gn.u.directoryName.element = choice_Name_rdnSequence; + gn.u.directoryName.u.rdnSequence = name.u.rdnSequence; + + ret = add_GeneralNames(&gns, &gn); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + + ai->authorityCertIssuer->val = gns.val; + ai->authorityCertIssuer->len = gns.len; + + ret = der_copy_heim_integer(&certificate->tbsCertificate.serialNumber, + ai->authorityCertSerialNumber); + if (ai->authorityCertSerialNumber == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + } +out: + if (ret) + free_AuthorityKeyIdentifier(ai); + return ret; +} + + +/** + * Sign a to-be-signed certificate object with a issuer certificate. + * + * The caller needs to at least have called the following functions on the + * to-be-signed certificate object: + * - hx509_ca_tbs_init() + * - hx509_ca_tbs_set_subject() + * - hx509_ca_tbs_set_spki() + * + * When done the to-be-signed certificate object should be freed with + * hx509_ca_tbs_free(). + * + * When creating self-signed certificate use hx509_ca_sign_self() instead. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param signer the CA certificate object to sign with (need private key). + * @param certificate return cerificate, free with hx509_cert_free(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_sign(hx509_context context, + hx509_ca_tbs tbs, + hx509_cert signer, + hx509_cert *certificate) +{ + const Certificate *signer_cert; + AuthorityKeyIdentifier ai; + int ret; + + memset(&ai, 0, sizeof(ai)); + + signer_cert = _hx509_get_cert(signer); + + ret = get_AuthorityKeyIdentifier(context, signer_cert, &ai); + if (ret) + goto out; + + ret = ca_sign(context, + tbs, + _hx509_cert_private_key(signer), + &ai, + &signer_cert->tbsCertificate.subject, + certificate); + +out: + free_AuthorityKeyIdentifier(&ai); + + return ret; +} + +/** + * Work just like hx509_ca_sign() but signs it-self. + * + * @param context A hx509 context. + * @param tbs object to be signed. + * @param signer private key to sign with. + * @param certificate return cerificate, free with hx509_cert_free(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_ca + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ca_sign_self(hx509_context context, + hx509_ca_tbs tbs, + hx509_private_key signer, + hx509_cert *certificate) +{ + return ca_sign(context, + tbs, + signer, + NULL, + NULL, + certificate); +} + +/* + * The following used to be `kdc_issue_certificate()', which was added for + * kx509 support in the kdc, then adapted for bx509d. It now has no + * kdc-specific code and very little krb5-specific code, and is named + * `hx509_ca_issue_certificate()'. + */ + +/* From lib/krb5/principal.c */ +#define princ_num_comp(P) ((P)->principalName.name_string.len) +#define princ_type(P) ((P)->principalName.name_type) +#define princ_comp(P) ((P)->principalName.name_string.val) +#define princ_ncomp(P, N) ((P)->principalName.name_string.val[(N)]) +#define princ_realm(P) ((P)->realm) + +static const char * +princ_get_comp_string(KRB5PrincipalName *principal, unsigned int component) +{ + if (component >= princ_num_comp(principal)) + return NULL; + return princ_ncomp(principal, component); +} +/* XXX Add unparse_name() */ + +typedef enum { + CERT_NOTSUP = 0, + CERT_CLIENT = 1, + CERT_SERVER = 2, + CERT_MIXED = 3 +} cert_type; + +static void +frees(char **s) +{ + free(*s); + *s = NULL; +} + +static heim_error_code +count_sans(hx509_request req, size_t *n) +{ + size_t i; + char *s = NULL; + int ret = 0; + + *n = 0; + for (i = 0; ret == 0; i++) { + hx509_san_type san_type; + + ret = hx509_request_get_san(req, i, &san_type, &s); + if (ret) + break; + switch (san_type) { + case HX509_SAN_TYPE_DNSNAME: + case HX509_SAN_TYPE_EMAIL: + case HX509_SAN_TYPE_XMPP: + case HX509_SAN_TYPE_PKINIT: + case HX509_SAN_TYPE_MS_UPN: + (*n)++; + break; + default: + ret = ENOTSUP; + } + frees(&s); + } + free(s); + return ret == HX509_NO_ITEM ? 0 : ret; +} + +static int +has_sans(hx509_request req) +{ + hx509_san_type san_type; + char *s = NULL; + int ret = hx509_request_get_san(req, 0, &san_type, &s); + + frees(&s); + return ret == HX509_NO_ITEM ? 0 : 1; +} + +static cert_type +characterize_cprinc(hx509_context context, + KRB5PrincipalName *cprinc) +{ + unsigned int ncomp = princ_num_comp(cprinc); + const char *comp1 = princ_get_comp_string(cprinc, 1); + + switch (ncomp) { + case 1: + return CERT_CLIENT; + case 2: + if (strchr(comp1, '.') == NULL) + return CERT_CLIENT; + return CERT_SERVER; + case 3: + if (strchr(comp1, '.')) + return CERT_SERVER; + return CERT_NOTSUP; + default: + return CERT_NOTSUP; + } +} + +/* Characterize request as client or server cert req */ +static cert_type +characterize(hx509_context context, + KRB5PrincipalName *cprinc, + hx509_request req) +{ + heim_error_code ret = 0; + cert_type res = CERT_NOTSUP; + size_t i; + char *s = NULL; + int want_ekus = 0; + + if (!has_sans(req)) + return characterize_cprinc(context, cprinc); + + for (i = 0; ret == 0; i++) { + heim_oid oid; + + frees(&s); + ret = hx509_request_get_eku(req, i, &s); + if (ret) + break; + + want_ekus = 1; + ret = der_parse_heim_oid(s, ".", &oid); + if (ret) + break; + /* + * If the client wants only a server certificate, then we'll be + * willing to issue one that may be longer-lived than the client's + * ticket/token. + * + * There may be other server EKUs, but these are the ones we know + * of. + */ + if (der_heim_oid_cmp(&asn1_oid_id_pkix_kp_serverAuth, &oid) && + der_heim_oid_cmp(&asn1_oid_id_pkix_kp_OCSPSigning, &oid) && + der_heim_oid_cmp(&asn1_oid_id_pkix_kp_secureShellServer, &oid)) + res |= CERT_CLIENT; + else + res |= CERT_SERVER; + der_free_oid(&oid); + } + frees(&s); + if (ret == HX509_NO_ITEM) + ret = 0; + + for (i = 0; ret == 0; i++) { + hx509_san_type san_type; + + frees(&s); + ret = hx509_request_get_san(req, i, &san_type, &s); + if (ret) + break; + switch (san_type) { + case HX509_SAN_TYPE_DNSNAME: + if (!want_ekus) + res |= CERT_SERVER; + break; + case HX509_SAN_TYPE_EMAIL: + case HX509_SAN_TYPE_XMPP: + case HX509_SAN_TYPE_PKINIT: + case HX509_SAN_TYPE_MS_UPN: + if (!want_ekus) + res |= CERT_CLIENT; + break; + default: + ret = ENOTSUP; + } + if (ret) + break; + } + frees(&s); + if (ret == HX509_NO_ITEM) + ret = 0; + return ret ? CERT_NOTSUP : res; +} + +/* + * Get a configuration sub-tree for kx509 based on what's being requested and + * by whom. + * + * We have a number of cases: + * + * - default certificate (no CSR used, or no certificate extensions requested) + * - for client principals + * - for service principals + * - client certificate requested (CSR used and client-y SANs/EKUs requested) + * - server certificate requested (CSR used and server-y SANs/EKUs requested) + * - mixed client/server certificate requested (...) + */ +static heim_error_code +get_cf(hx509_context context, + const heim_config_binding *cf, + heim_log_facility *logf, + hx509_request req, + KRB5PrincipalName *cprinc, + const heim_config_binding **out) +{ + heim_error_code ret; + unsigned int ncomp = princ_num_comp(cprinc); + const char *realm = princ_realm(cprinc); + const char *comp0 = princ_get_comp_string(cprinc, 0); + const char *comp1 = princ_get_comp_string(cprinc, 1); + const char *label = NULL; + const char *svc = NULL; + const char *def = NULL; + cert_type certtype = CERT_NOTSUP; + size_t nsans = 0; + + *out = NULL; + if (ncomp == 0) { + heim_log_msg(context->hcontext, logf, 5, NULL, + "Client principal has no components!"); + hx509_set_error_string(context, 0, ret = ENOTSUP, + "Client principal has no components!"); + return ret; + } + + if ((ret = count_sans(req, &nsans)) || + (certtype = characterize(context, cprinc, req)) == CERT_NOTSUP) { + heim_log_msg(context->hcontext, logf, 5, NULL, + "Could not characterize CSR"); + hx509_set_error_string(context, 0, ret, "Could not characterize CSR"); + return ret; + } + + if (nsans) { + def = "custom"; + /* Client requested some certificate extension, a SAN or EKU */ + switch (certtype) { + case CERT_MIXED: label = "mixed"; break; + case CERT_CLIENT: label = "client"; break; + case CERT_SERVER: label = "server"; break; + default: + hx509_set_error_string(context, 0, ret = ENOTSUP, + "Requested SAN/EKU combination not " + "supported"); + return ret; + } + } else { + def = "default"; + /* Default certificate desired */ + if (ncomp == 1) { + label = "user"; + } else if (ncomp == 2 && strcmp(comp1, "root") == 0) { + label = "root_user"; + } else if (ncomp == 2 && strcmp(comp1, "admin") == 0) { + label = "admin_user"; + } else if (strchr(comp1, '.')) { + label = "hostbased_service"; + svc = comp0; + } else { + label = "other"; + } + } + + *out = heim_config_get_list(context->hcontext, cf, label, svc, NULL); + if (*out) { + ret = 0; + } else { + heim_log_msg(context->hcontext, logf, 3, NULL, + "No configuration for %s %s certificate's realm " + "-> %s -> kx509 -> %s%s%s", def, label, realm, label, + svc ? " -> " : "", svc ? svc : ""); + hx509_set_error_string(context, 0, EACCES, + "No configuration for %s %s certificate's realm " + "-> %s -> kx509 -> %s%s%s", def, label, realm, label, + svc ? " -> " : "", svc ? svc : ""); + } + return ret; +} + + +/* + * Find and set a certificate template using a configuration sub-tree + * appropriate to the requesting principal. + * + * This allows for the specification of the following in configuration: + * + * - certificates as templates, with ${var} tokens in subjectName attribute + * values that will be expanded later + * - a plain string with ${var} tokens to use as the subjectName + * - EKUs + * - whether to include a PKINIT SAN + */ +static heim_error_code +set_template(hx509_context context, + heim_log_facility *logf, + const heim_config_binding *cf, + hx509_ca_tbs tbs) +{ + heim_error_code ret = 0; + const char *cert_template = NULL; + const char *subj_name = NULL; + char **ekus = NULL; + + if (cf == NULL) + return EACCES; /* Can't happen */ + + cert_template = heim_config_get_string(context->hcontext, cf, + "template_cert", NULL); + subj_name = heim_config_get_string(context->hcontext, cf, "subject_name", + NULL); + + if (cert_template) { + hx509_certs certs; + hx509_cert template; + + ret = hx509_certs_init(context, cert_template, 0, NULL, &certs); + if (ret == 0) + ret = hx509_get_one_cert(context, certs, &template); + hx509_certs_free(&certs); + if (ret) { + heim_log_msg(context->hcontext, logf, 1, NULL, + "Failed to load certificate template from %s", + cert_template); + hx509_set_error_string(context, 0, EACCES, + "Failed to load certificate template from " + "%s", cert_template); + return ret; + } + + /* + * Only take the subjectName, the keyUsage, and EKUs from the template + * certificate. + */ + ret = hx509_ca_tbs_set_template(context, tbs, + HX509_CA_TEMPLATE_SUBJECT | + HX509_CA_TEMPLATE_KU | + HX509_CA_TEMPLATE_EKU, + template); + hx509_cert_free(template); + if (ret) + return ret; + } + + if (subj_name) { + hx509_name dn = NULL; + + ret = hx509_parse_name(context, subj_name, &dn); + if (ret == 0) + ret = hx509_ca_tbs_set_subject(context, tbs, dn); + hx509_name_free(&dn); + if (ret) + return ret; + } + + if (cert_template == NULL && subj_name == NULL) { + hx509_name dn = NULL; + + ret = hx509_empty_name(context, &dn); + if (ret == 0) + ret = hx509_ca_tbs_set_subject(context, tbs, dn); + hx509_name_free(&dn); + if (ret) + return ret; + } + + ekus = heim_config_get_strings(context->hcontext, cf, "ekus", NULL); + if (ekus) { + size_t i; + + for (i = 0; ret == 0 && ekus[i]; i++) { + heim_oid oid = { 0, NULL }; + + if ((ret = der_find_or_parse_heim_oid(ekus[i], ".", &oid)) == 0) + ret = hx509_ca_tbs_add_eku(context, tbs, &oid); + der_free_oid(&oid); + } + heim_config_free_strings(ekus); + } + + /* + * XXX A KeyUsage template would be nice, but it needs some smarts to + * remove, e.g., encipherOnly, decipherOnly, keyEncipherment, if the SPKI + * algorithm does not support encryption. The same logic should be added + * to hx509_ca_tbs_set_template()'s HX509_CA_TEMPLATE_KU functionality. + */ + return ret; +} + +/* + * Find and set a certificate template, set "variables" in `env', and add add + * default SANs/EKUs as appropriate. + * + * TODO: + * - lookup a template for the client principal in its HDB entry + * - lookup subjectName, SANs for a principal in its HDB entry + * - lookup a host-based client principal's HDB entry and add its canonical + * name / aliases as dNSName SANs + * (this would have to be if requested by the client, perhaps) + */ +static heim_error_code +set_tbs(hx509_context context, + heim_log_facility *logf, + const heim_config_binding *cf, + hx509_request req, + KRB5PrincipalName *cprinc, + hx509_env *env, + hx509_ca_tbs tbs) +{ + KRB5PrincipalName cprinc_no_realm = *cprinc; + heim_error_code ret; + unsigned int ncomp = princ_num_comp(cprinc); + const char *realm = princ_realm(cprinc); + const char *comp0 = princ_get_comp_string(cprinc, 0); + const char *comp1 = princ_get_comp_string(cprinc, 1); + const char *comp2 = princ_get_comp_string(cprinc, 2); + struct rk_strpool *strpool; + char *princ_no_realm = NULL; + char *princ = NULL; + + strpool = _hx509_unparse_kerberos_name(NULL, cprinc); + if (strpool) + princ = rk_strpoolcollect(strpool); + cprinc_no_realm.realm = NULL; + strpool = _hx509_unparse_kerberos_name(NULL, &cprinc_no_realm); + if (strpool) + princ_no_realm = rk_strpoolcollect(strpool); + if (princ == NULL || princ_no_realm == NULL) { + free(princ); + return hx509_enomem(context); + } + strpool = NULL; + ret = hx509_env_add(context, env, "principal-name-without-realm", + princ_no_realm); + if (ret == 0) + ret = hx509_env_add(context, env, "principal-name", princ); + if (ret == 0) + ret = hx509_env_add(context, env, "principal-name-realm", + realm); + + /* Populate requested certificate extensions from CSR/CSRPlus if allowed */ + if (ret == 0) + ret = hx509_ca_tbs_set_from_csr(context, tbs, req); + if (ret == 0) + ret = set_template(context, logf, cf, tbs); + + /* + * Optionally add PKINIT SAN. + * + * Adding an id-pkinit-san means the client can use the certificate to + * initiate PKINIT. That might seem odd, but it enables a sort of PKIX + * credential delegation by allowing forwarded Kerberos tickets to be + * used to acquire PKIX credentials. Thus this can work: + * + * PKIX (w/ HW token) -> Kerberos -> + * PKIX (w/ softtoken) -> Kerberos -> + * PKIX (w/ softtoken) -> Kerberos -> + * ... + * + * Note that we may not have added the PKINIT EKU -- that depends on the + * template, and host-based service templates might well not include it. + */ + if (ret == 0 && !has_sans(req) && + heim_config_get_bool_default(context->hcontext, cf, FALSE, + "include_pkinit_san", NULL)) { + ret = hx509_ca_tbs_add_san_pkinit(context, tbs, princ); + } + + if (ret) + goto out; + + if (ncomp == 1) { + const char *email_domain; + + ret = hx509_env_add(context, env, "principal-component0", + princ_no_realm); + + /* + * If configured, include an rfc822Name that's just the client's + * principal name sans realm @ configured email domain. + */ + if (ret == 0 && !has_sans(req) && + (email_domain = heim_config_get_string(context->hcontext, cf, + "email_domain", NULL))) { + char *email; + + if (asprintf(&email, "%s@%s", princ_no_realm, email_domain) == -1 || + email == NULL) + goto enomem; + ret = hx509_ca_tbs_add_san_rfc822name(context, tbs, email); + free(email); + } + } else if (ncomp == 2 || ncomp == 3) { + /* + * 2- and 3-component principal name. + * + * We do not have a reliable name-type indicator. If the second + * component has a '.' in it then we'll assume that the name is a + * host-based (2-component) or domain-based (3-component) service + * principal name. Else we'll assume it's a two-component admin-style + * username. + */ + + ret = hx509_env_add(context, env, "principal-component0", comp0); + if (ret == 0) + ret = hx509_env_add(context, env, "principal-component1", comp1); + if (ret == 0 && ncomp == 3) + ret = hx509_env_add(context, env, "principal-component2", comp2); + if (ret == 0 && strchr(comp1, '.')) { + /* Looks like host-based or domain-based service */ + ret = hx509_env_add(context, env, "principal-service-name", comp0); + if (ret == 0) + ret = hx509_env_add(context, env, "principal-host-name", + comp1); + if (ret == 0 && ncomp == 3) + ret = hx509_env_add(context, env, "principal-domain-name", + comp2); + if (ret == 0 && !has_sans(req) && + heim_config_get_bool_default(context->hcontext, cf, FALSE, + "include_dnsname_san", NULL)) { + ret = hx509_ca_tbs_add_san_hostname(context, tbs, comp1); + } + } + } else { + heim_log_msg(context->hcontext, logf, 5, NULL, + "kx509/bx509 client %s has too many components!", princ); + hx509_set_error_string(context, 0, ret = EACCES, + "kx509/bx509 client %s has too many " + "components!", princ); + } + +out: + if (ret == ENOMEM) + goto enomem; + free(princ_no_realm); + free(princ); + return ret; + +enomem: + heim_log_msg(context->hcontext, logf, 0, NULL, + "Could not set up TBSCertificate: Out of memory"); + ret = hx509_enomem(context); + goto out; +} + +/* + * Set the notBefore/notAfter for the certificate to be issued. + * + * Here `starttime' is the supplicant's credentials' notBefore equivalent, + * while `endtime' is the supplicant's credentials' notAfter equivalent. + * + * `req_life' is the lifetime requested by the supplicant. + * + * `endtime' must be larger than the current time. + * + * `starttime' can be zero or negative, in which case the notBefore will be the + * current time minus five minutes. + * + * `endtime', `req_life' and configuration parameters will be used to compute + * the actual notAfter. + */ +static heim_error_code +tbs_set_times(hx509_context context, + const heim_config_binding *cf, + heim_log_facility *logf, + time_t starttime, + time_t endtime, + time_t req_life, + hx509_ca_tbs tbs) +{ + time_t now = time(NULL); + time_t force = heim_config_get_time_default(context->hcontext, + cf, 5 * 24 * 3600, + "force_cert_lifetime", NULL); + time_t clamp = heim_config_get_time_default(context->hcontext, cf, 0, + "max_cert_lifetime", NULL); + int allow_more = heim_config_get_bool_default(context->hcontext, cf, FALSE, + "allow_extra_lifetime", + NULL); + starttime = starttime > 0 ? starttime : now - 5 * 60; + + if (endtime < now) { + heim_log_msg(context->hcontext, logf, 3, NULL, + "Endtime is in the past"); + hx509_set_error_string(context, 0, ERANGE, "Endtime is in the past"); + return ERANGE; + } + + /* Apply requested lifetime if shorter or if allowed more */ + if (req_life > 0 && req_life <= endtime - now) + endtime = now + req_life; + else if (req_life > 0 && allow_more) + endtime = now + req_life; + + /* Apply floor */ + if (force > 0 && force > endtime - now) + endtime = now + force; + + /* Apply ceiling */ + if (clamp > 0 && clamp < endtime - now) + endtime = now + clamp; + + hx509_ca_tbs_set_notAfter(context, tbs, endtime); + hx509_ca_tbs_set_notBefore(context, tbs, starttime); + return 0; +} + +/* + * Build a certifate for `principal' and its CSR. + * + * XXX Make `cprinc' a GeneralName! That's why this is private for now. + */ +heim_error_code +_hx509_ca_issue_certificate(hx509_context context, + const heim_config_binding *cf, + heim_log_facility *logf, + hx509_request req, + KRB5PrincipalName *cprinc, + time_t starttime, + time_t endtime, + time_t req_life, + int send_chain, + hx509_certs *out) +{ + heim_error_code ret; + const char *ca; + hx509_ca_tbs tbs = NULL; + hx509_certs chain = NULL; + hx509_cert signer = NULL; + hx509_cert cert = NULL; + hx509_env env = NULL; + KeyUsage ku; + + *out = NULL; + /* Force KU */ + ku = int2KeyUsage(0); + ku.digitalSignature = 1; + hx509_request_authorize_ku(req, ku); + + ret = get_cf(context, cf, logf, req, cprinc, &cf); + if (ret) + return ret; + + if ((ca = heim_config_get_string(context->hcontext, cf, + "ca", NULL)) == NULL) { + heim_log_msg(context->hcontext, logf, 3, NULL, + "No kx509 CA issuer credential specified"); + hx509_set_error_string(context, 0, ret = EACCES, + "No kx509 CA issuer credential specified"); + return ret; + } + + ret = hx509_ca_tbs_init(context, &tbs); + if (ret) { + heim_log_msg(context->hcontext, logf, 0, NULL, + "Failed to create certificate: Out of memory"); + return ret; + } + + /* Lookup a template and set things in `env' and `tbs' as appropriate */ + if (ret == 0) + ret = set_tbs(context, logf, cf, req, cprinc, &env, tbs); + + /* Populate generic template "env" variables */ + + /* + * The `tbs' and `env' are now complete as to naming and EKUs. + * + * We check that the `tbs' is not name-less, after which all remaining + * failures here will not be policy failures. So we also log the intent to + * issue a certificate now. + */ + if (ret == 0 && hx509_name_is_null_p(hx509_ca_tbs_get_name(tbs)) && + !has_sans(req)) { + heim_log_msg(context->hcontext, logf, 3, NULL, + "Not issuing certificate because it would have no names"); + hx509_set_error_string(context, 0, ret = EACCES, + "Not issuing certificate because it " + "would have no names"); + } + if (ret) + goto out; + + /* + * Still to be done below: + * + * - set certificate spki + * - set certificate validity + * - expand variables in certificate subject name template + * - sign certificate + * - encode certificate and chain + */ + + /* Load the issuer certificate and private key */ + { + hx509_certs certs; + hx509_query *q; + + ret = hx509_certs_init(context, ca, 0, NULL, &certs); + if (ret) { + heim_log_msg(context->hcontext, logf, 1, NULL, + "Failed to load CA certificate and private key %s", + ca); + hx509_set_error_string(context, 0, ret, "Failed to load " + "CA certificate and private key %s", ca); + goto out; + } + ret = hx509_query_alloc(context, &q); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_KEYCERTSIGN); + + ret = hx509_certs_find(context, certs, q, &signer); + hx509_query_free(context, q); + hx509_certs_free(&certs); + if (ret) { + heim_log_msg(context->hcontext, logf, 1, NULL, + "Failed to find a CA certificate in %s", ca); + hx509_set_error_string(context, 0, ret, + "Failed to find a CA certificate in %s", + ca); + goto out; + } + } + + /* Populate the subject public key in the TBS context */ + { + SubjectPublicKeyInfo spki; + + ret = hx509_request_get_SubjectPublicKeyInfo(context, + req, &spki); + if (ret == 0) + ret = hx509_ca_tbs_set_spki(context, tbs, &spki); + free_SubjectPublicKeyInfo(&spki); + if (ret) + goto out; + } + + /* Work out cert expiration */ + if (ret == 0) + ret = tbs_set_times(context, cf, logf, starttime, endtime, req_life, + tbs); + + /* Expand the subjectName template in the TBS using the env */ + if (ret == 0) + ret = hx509_ca_tbs_subject_expand(context, tbs, env); + hx509_env_free(&env); + + /* All done with the TBS, sign/issue the certificate */ + if (ret == 0) + ret = hx509_ca_sign(context, tbs, signer, &cert); + + /* + * Gather the certificate and chain into a MEMORY store, being careful not + * to include private keys in the chain. + * + * We could have specified a separate configuration parameter for an hx509 + * store meant to have only the chain and no private keys, but expecting + * the full chain in the issuer credential store and copying only the certs + * (but not the private keys) is safer and easier to configure. + */ + if (ret == 0) + ret = hx509_certs_init(context, "MEMORY:certs", + HX509_CERTS_NO_PRIVATE_KEYS, NULL, out); + if (ret == 0) + ret = hx509_certs_add(context, *out, cert); + if (ret == 0 && send_chain) { + ret = hx509_certs_init(context, ca, + HX509_CERTS_NO_PRIVATE_KEYS, NULL, &chain); + if (ret == 0) + ret = hx509_certs_merge(context, *out, chain); + } + +out: + hx509_certs_free(&chain); + if (env) + hx509_env_free(&env); + if (tbs) + hx509_ca_tbs_free(&tbs); + if (cert) + hx509_cert_free(cert); + if (signer) + hx509_cert_free(signer); + if (ret) + hx509_certs_free(out); + return ret; +} diff --git a/third_party/heimdal/lib/hx509/cert.c b/third_party/heimdal/lib/hx509/cert.c new file mode 100644 index 0000000..4fcb4ba --- /dev/null +++ b/third_party/heimdal/lib/hx509/cert.c @@ -0,0 +1,3951 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include "crypto-headers.h" +#include + +/** + * @page page_cert The basic certificate + * + * The basic hx509 cerificate object in hx509 is hx509_cert. The + * hx509_cert object is representing one X509/PKIX certificate and + * associated attributes; like private key, friendly name, etc. + * + * A hx509_cert object is usully found via the keyset interfaces (@ref + * page_keyset), but its also possible to create a certificate + * directly from a parsed object with hx509_cert_init() and + * hx509_cert_init_data(). + * + * See the library functions here: @ref hx509_cert + */ + +struct hx509_verify_ctx_data { + hx509_certs trust_anchors; + int flags; +#define HX509_VERIFY_CTX_F_TIME_SET 1 +#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2 +#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 +#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 +#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16 +#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32 + time_t time_now; + unsigned int max_depth; +#define HX509_VERIFY_MAX_DEPTH 30 + hx509_revoke_ctx revoke_ctx; +}; + +#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280) +#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS) +#define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0) + +struct _hx509_cert_attrs { + size_t len; + hx509_cert_attribute *val; +}; + +struct hx509_cert_data { + unsigned int ref; + char *friendlyname; + Certificate *data; + hx509_private_key private_key; + struct _hx509_cert_attrs attrs; + hx509_name basename; + _hx509_cert_release_func release; + void *ctx; +}; + +typedef struct hx509_name_constraints { + NameConstraints *val; + size_t len; +} hx509_name_constraints; + +#define GeneralSubtrees_SET(g,var) \ + (g)->len = (var)->len, (g)->val = (var)->val; + +static void +init_context_once(void *ignored) +{ + + ENGINE_add_conf_module(); + OpenSSL_add_all_algorithms(); +} + +/** + * Return a cookie identifying this instance of a library. + * + * Inputs: + * + * @context A krb5_context + * @module Our library name or a library we depend on + * + * Outputs: The instance cookie + * + * @ingroup krb5_support + */ + +HX509_LIB_FUNCTION uintptr_t HX509_LIB_CALL +hx509_get_instance(const char *libname) +{ + static const char *instance = "libhx509"; + + if (strcmp(libname, "hx509") == 0) + return (uintptr_t)instance; + + return 0; +} + +#ifndef PATH_SEP +# define PATH_SEP ":" +#endif +static const char *hx509_config_file = +"~/.hx509/config" PATH_SEP +SYSCONFDIR "/hx509.conf" PATH_SEP +#ifdef _WIN32 +"%{COMMON_APPDATA}/Heimdal/hx509.conf" PATH_SEP +"%{WINDOWS}/hx509.ini" +#else /* _WIN32 */ +"/etc/hx509.conf" +#endif /* _WIN32 */ +; + +/** + * Creates a hx509 context that most functions in the library + * uses. The context is only allowed to be used by one thread at each + * moment. Free the context with hx509_context_free(). + * + * @param context Returns a pointer to new hx509 context. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509 + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_context_init(hx509_context *contextp) +{ + static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; + heim_error_code ret; + hx509_context context; + const char *anchors; + char **files = NULL; + + *contextp = NULL; + context = calloc(1, sizeof(*context)); + if (context == NULL) + return ENOMEM; + + heim_base_once_f(&init_context, NULL, init_context_once); + + if ((context->hcontext = heim_context_init()) == NULL) { + free(context); + return ENOMEM; + } + + if ((ret = heim_get_default_config_files(hx509_config_file, + "HX509_CONFIG", + &files))) { + heim_context_free(&context->hcontext); + free(context); + return ret; + } + + /* If there's no hx509 config, we continue, as we never needed it before */ + if (files) + (void) heim_set_config_files(context->hcontext, files, &context->cf); + heim_free_config_files(files); + + _hx509_ks_null_register(context); + _hx509_ks_mem_register(context); + _hx509_ks_file_register(context); + _hx509_ks_pkcs12_register(context); + _hx509_ks_pkcs11_register(context); + _hx509_ks_dir_register(context); + _hx509_ks_keychain_register(context); + + context->ocsp_time_diff = + heim_config_get_time_default(context->hcontext, context->cf, + HX509_DEFAULT_OCSP_TIME_DIFF, + "libdefaults", "ocsp_time_dif", NULL); + + initialize_hx_error_table_r(&context->et_list); + initialize_asn1_error_table_r(&context->et_list); + +#ifdef HX509_DEFAULT_ANCHORS + anchors = heim_config_get_string_default(context->hcontext, context->cf, + HX509_DEFAULT_ANCHORS, + "libdefaults", "anchors", NULL); +#else + anchors = heim_config_get_string(context->hcontext, context->cf, + "libdefaults", "anchors", NULL); +#endif + if (anchors) + (void)hx509_certs_init(context, anchors, 0, NULL, + &context->default_trust_anchors); + + *contextp = context; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_set_log_dest(hx509_context context, heim_log_facility *fac) +{ + return heim_set_log_dest(context->hcontext, fac); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_set_debug_dest(hx509_context context, heim_log_facility *fac) +{ + return heim_set_debug_dest(context->hcontext, fac); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_set_warn_dest(hx509_context context, heim_log_facility *fac) +{ + return heim_set_warn_dest(context->hcontext, fac); +} + +/** + * Selects if the hx509_revoke_verify() function is going to require + * the existence of a revocation method (OCSP, CRL) or not. Note that + * hx509_verify_path(), hx509_cms_verify_signed(), and other functions + * call hx509_revoke_verify(). + * + * @param context hx509 context to change the flag for. + * @param flag zero, revocation method required, non zero missing + * revocation method ok + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_context_set_missing_revoke(hx509_context context, int flag) +{ + if (flag) + context->flags |= HX509_CTX_VERIFY_MISSING_OK; + else + context->flags &= ~HX509_CTX_VERIFY_MISSING_OK; +} + +/** + * Free the context allocated by hx509_context_init(). + * + * @param context context to be freed. + * + * @ingroup hx509 + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_context_free(hx509_context *context) +{ + if (!*context) + return; + + hx509_clear_error_string(*context); + if ((*context)->ks_ops) { + free((*context)->ks_ops); + (*context)->ks_ops = NULL; + } + (*context)->ks_num_ops = 0; + free_error_table ((*context)->et_list); + if ((*context)->querystat) + free((*context)->querystat); + hx509_certs_free(&(*context)->default_trust_anchors); + heim_config_file_free((*context)->hcontext, (*context)->cf); + heim_context_free(&(*context)->hcontext); + memset(*context, 0, sizeof(**context)); + free(*context); + *context = NULL; +} + +/* + * + */ + +HX509_LIB_FUNCTION Certificate * HX509_LIB_CALL +_hx509_get_cert(hx509_cert cert) +{ + return cert->data; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_get_version(const Certificate *t) +{ + return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; +} + +static hx509_cert +cert_init(hx509_context context, heim_error_t *error) +{ + hx509_cert cert; + + cert = malloc(sizeof(*cert)); + if (cert == NULL) { + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + cert->ref = 1; + cert->friendlyname = NULL; + cert->attrs.len = 0; + cert->attrs.val = NULL; + cert->private_key = NULL; + cert->basename = NULL; + cert->release = NULL; + cert->ctx = NULL; + cert->data= NULL; + return cert; +} + +/** + * Allocate and init an hx509 certificate object from the decoded + * certificate `c´. + * + * @param context A hx509 context. + * @param c + * @param error + * + * @return Returns an hx509 certificate + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error) +{ + hx509_cert cert; + int ret; + + if ((cert = cert_init(context, error)) == NULL) + return NULL; + + cert->data = calloc(1, sizeof(*(cert->data))); + if (cert->data == NULL) { + free(cert); + if (error) + *error = heim_error_create_enomem(); + return NULL; + } + ret = copy_Certificate(c, cert->data); + if (ret) { + free(cert->data); + free(cert); + cert = NULL; + } + return cert; +} + +/** + * Copy a certificate object, but drop any private key assignment. + * + * @param context A hx509 context. + * @param src Certificate object + * @param error + * + * @return Returns an hx509 certificate + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_copy_no_private_key(hx509_context context, + hx509_cert src, + heim_error_t *error) +{ + return hx509_cert_init(context, src->data, error); +} + +/** + * Allocate and init an hx509 certificate object containing only a private key + * (but no Certificate). + * + * @param context A hx509 context. + * @param key + * @param error + * + * @return Returns an hx509 certificate + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_init_private_key(hx509_context context, + hx509_private_key key, + heim_error_t *error) +{ + hx509_cert cert; + + if ((cert = cert_init(context, error))) + (void) _hx509_cert_assign_key(cert, key); + return cert; +} + +/** + * Just like hx509_cert_init(), but instead of a decode certificate + * takes an pointer and length to a memory region that contains a + * DER/BER encoded certificate. + * + * If the memory region doesn't contain just the certificate and + * nothing more the function will fail with + * HX509_EXTRA_DATA_AFTER_STRUCTURE. + * + * @param context A hx509 context. + * @param ptr pointer to memory region containing encoded certificate. + * @param len length of memory region. + * @param error possibly returns an error + * + * @return An hx509 certificate + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_init_data(hx509_context context, + const void *ptr, + size_t len, + heim_error_t *error) +{ + hx509_cert cert; + Certificate t; + size_t size; + int ret; + + ret = decode_Certificate(ptr, len, &t, &size); + if (ret) { + if (error) + *error = heim_error_create(ret, "Failed to decode certificate"); + errno = ret; + return NULL; + } + if (size != len) { + free_Certificate(&t); + if (error) + *error = heim_error_create(HX509_EXTRA_DATA_AFTER_STRUCTURE, + "Extra data after certificate"); + errno = HX509_EXTRA_DATA_AFTER_STRUCTURE; + return NULL; + } + + cert = hx509_cert_init(context, &t, error); + free_Certificate(&t); + return cert; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_cert_set_release(hx509_cert cert, + _hx509_cert_release_func release, + void *ctx) +{ + cert->release = release; + cert->ctx = ctx; +} + + +/* Doesn't make a copy of `private_key'. */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key) +{ + if (cert->private_key) + hx509_private_key_free(&cert->private_key); + cert->private_key = _hx509_private_key_ref(private_key); + return 0; +} + +/** + * Free reference to the hx509 certificate object, if the refcounter + * reaches 0, the object if freed. Its allowed to pass in NULL. + * + * @param cert the cert to free. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_cert_free(hx509_cert cert) +{ + size_t i; + + if (cert == NULL) + return; + + if (cert->ref <= 0) + _hx509_abort("cert refcount <= 0 on free"); + if (--cert->ref > 0) + return; + + if (cert->release) + (cert->release)(cert, cert->ctx); + + if (cert->private_key) + hx509_private_key_free(&cert->private_key); + + if (cert->data) + free_Certificate(cert->data); + free(cert->data); + + for (i = 0; i < cert->attrs.len; i++) { + der_free_octet_string(&cert->attrs.val[i]->data); + der_free_oid(&cert->attrs.val[i]->oid); + free(cert->attrs.val[i]); + } + free(cert->attrs.val); + free(cert->friendlyname); + if (cert->basename) + hx509_name_free(&cert->basename); + memset(cert, 0, sizeof(*cert)); + free(cert); +} + +/** + * Add a reference to a hx509 certificate object. + * + * @param cert a pointer to an hx509 certificate object. + * + * @return the same object as is passed in. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_ref(hx509_cert cert) +{ + if (cert == NULL) + return NULL; + if (cert->ref <= 0) + _hx509_abort("cert refcount <= 0"); + cert->ref++; + if (cert->ref == 0) + _hx509_abort("cert refcount == 0"); + return cert; +} + +/** + * Allocate an verification context that is used to control the + * verification process. + * + * @param context A hx509 context. + * @param ctx returns a pointer to a hx509_verify_ctx object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx) +{ + hx509_verify_ctx c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->max_depth = HX509_VERIFY_MAX_DEPTH; + + *ctx = c; + + return 0; +} + +/** + * Free an hx509 verification context. + * + * @param ctx the context to be freed. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_destroy_ctx(hx509_verify_ctx ctx) +{ + if (ctx) { + hx509_certs_free(&ctx->trust_anchors); + hx509_revoke_free(&ctx->revoke_ctx); + memset(ctx, 0, sizeof(*ctx)); + } + free(ctx); +} + +/** + * Set the trust anchors in the verification context, makes an + * reference to the keyset, so the consumer can free the keyset + * independent of the destruction of the verification context (ctx). + * If there already is a keyset attached, it's released. + * + * @param ctx a verification context + * @param set a keyset containing the trust anchors. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) +{ + if (ctx->trust_anchors) + hx509_certs_free(&ctx->trust_anchors); + ctx->trust_anchors = hx509_certs_ref(set); +} + +/** + * Attach an revocation context to the verfication context, , makes an + * reference to the revoke context, so the consumer can free the + * revoke context independent of the destruction of the verification + * context. If there is no revoke context, the verification process is + * NOT going to check any verification status. + * + * @param ctx a verification context. + * @param revoke_ctx a revoke context. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx) +{ + if (ctx->revoke_ctx) + hx509_revoke_free(&ctx->revoke_ctx); + ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx); +} + +/** + * Set the clock time the the verification process is going to + * use. Used to check certificate in the past and future time. If not + * set the current time will be used. + * + * @param ctx a verification context. + * @param t the time the verifiation is using. + * + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_set_time(hx509_verify_ctx ctx, time_t t) +{ + ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET; + ctx->time_now = t; +} + +HX509_LIB_FUNCTION time_t HX509_LIB_CALL +_hx509_verify_get_time(hx509_verify_ctx ctx) +{ + return ctx->time_now; +} + +/** + * Set the maximum depth of the certificate chain that the path + * builder is going to try. + * + * @param ctx a verification context + * @param max_depth maxium depth of the certificate chain, include + * trust anchor. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth) +{ + ctx->max_depth = max_depth; +} + +/** + * Allow or deny the use of proxy certificates + * + * @param ctx a verification context + * @param boolean if non zero, allow proxy certificates. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; + else + ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; +} + +/** + * Select strict RFC3280 verification of certificiates. This means + * checking key usage on CA certificates, this will make version 1 + * certificiates unuseable. + * + * @param ctx a verification context + * @param boolean if non zero, use strict verification. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280; + else + ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280; +} + +/** + * Allow using the operating system builtin trust anchors if no other + * trust anchors are configured. + * + * @param ctx a verification context + * @param boolean if non zero, useing the operating systems builtin + * trust anchors. + * + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; + else + ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx, + int boolean) +{ + if (boolean) + ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; + else + ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; +} + +static const Extension * +find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx) +{ + const TBSCertificate *c = &cert->tbsCertificate; + + if (c->version == NULL || *c->version < 2 || c->extensions == NULL) + return NULL; + + for (;*idx < c->extensions->len; (*idx)++) { + if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0) + return &c->extensions->val[(*idx)++]; + } + return NULL; +} + +static int +find_extension_auth_key_id(const Certificate *subject, + AuthorityKeyIdentifier *ai) +{ + const Extension *e; + size_t size; + size_t i = 0; + + memset(ai, 0, sizeof(*ai)); + + e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_AuthorityKeyIdentifier(e->extnValue.data, + e->extnValue.length, + ai, &size); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_find_extension_subject_key_id(const Certificate *issuer, + SubjectKeyIdentifier *si) +{ + const Extension *e; + size_t size; + size_t i = 0; + + memset(si, 0, sizeof(*si)); + + e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_SubjectKeyIdentifier(e->extnValue.data, + e->extnValue.length, + si, &size); +} + +static int +find_extension_name_constraints(const Certificate *subject, + NameConstraints *nc) +{ + const Extension *e; + size_t size; + size_t i = 0; + + memset(nc, 0, sizeof(*nc)); + + e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_NameConstraints(e->extnValue.data, + e->extnValue.length, + nc, &size); +} + +static int +find_extension_subject_alt_name(const Certificate *cert, size_t *i, + GeneralNames *sa) +{ + const Extension *e; + size_t size; + + memset(sa, 0, sizeof(*sa)); + + e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_GeneralNames(e->extnValue.data, + e->extnValue.length, + sa, &size); +} + +static int +find_extension_eku(const Certificate *cert, ExtKeyUsage *eku) +{ + const Extension *e; + size_t size; + size_t i = 0; + + memset(eku, 0, sizeof(*eku)); + + e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i); + if (e == NULL) + return HX509_EXTENSION_NOT_FOUND; + + return decode_ExtKeyUsage(e->extnValue.data, + e->extnValue.length, + eku, &size); +} + +static int +add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry) +{ + void *p; + int ret; + + p = realloc(list->val, (list->len + 1) * sizeof(list->val[0])); + if (p == NULL) + return ENOMEM; + list->val = p; + ret = der_copy_octet_string(entry, &list->val[list->len]); + if (ret) + return ret; + list->len++; + return 0; +} + +/** + * Free a list of octet strings returned by another hx509 library + * function. + * + * @param list list to be freed. + * + * @ingroup hx509_misc + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_free_octet_string_list(hx509_octet_string_list *list) +{ + size_t i; + + if (list->val) { + for (i = 0; i < list->len; i++) + der_free_octet_string(&list->val[i]); + free(list->val); + } + list->val = NULL; + list->len = 0; +} + +/** + * Return a list of subjectAltNames specified by oid in the + * certificate. On error the + * + * The returned list of octet string should be freed with + * hx509_free_octet_string_list(). + * + * @param context A hx509 context. + * @param cert a hx509 certificate object. + * @param oid an oid to for SubjectAltName. + * @param list list of matching SubjectAltName. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_find_subjectAltName_otherName(hx509_context context, + hx509_cert cert, + const heim_oid *oid, + hx509_octet_string_list *list) +{ + GeneralNames sa; + int ret; + size_t i, j; + + list->val = NULL; + list->len = 0; + + i = 0; + while (1) { + ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa); + i++; + if (ret == HX509_EXTENSION_NOT_FOUND) { + return 0; + } else if (ret != 0) { + hx509_set_error_string(context, 0, ret, "Error searching for SAN"); + hx509_free_octet_string_list(list); + return ret; + } + + for (j = 0; j < sa.len; j++) { + if (sa.val[j].element == choice_GeneralName_otherName && + der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0) + { + ret = add_to_list(list, &sa.val[j].u.otherName.value); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Error adding an extra SAN to " + "return list"); + hx509_free_octet_string_list(list); + free_GeneralNames(&sa); + return ret; + } + } + } + free_GeneralNames(&sa); + } +} + + +static int +check_key_usage(hx509_context context, const Certificate *cert, + unsigned flags, int req_present) +{ + const Extension *e; + KeyUsage ku; + size_t size; + int ret; + size_t i = 0; + uint64_t ku_flags; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); + if (e == NULL) { + if (req_present) { + hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, + "Required extension key " + "usage missing from certificate"); + return HX509_KU_CERT_MISSING; + } + return 0; + } + + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size); + if (ret) + return ret; + ku_flags = KeyUsage2int(ku); + if ((ku_flags & flags) != flags) { + uint64_t missing = (~ku_flags) & flags; + char buf[256], *name; + + int result = unparse_flags(missing, asn1_KeyUsage_units(), + buf, sizeof(buf)); + _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); + hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, + "Key usage %s required but missing " + "from certificate %s", + (result > 0) ? buf : "", + name ? name : ""); + free(name); + return HX509_KU_CERT_MISSING; + } + return 0; +} + +/* + * Return 0 on matching key usage 'flags' for 'cert', otherwise return + * an error code. If 'req_present' the existence is required of the + * KeyUsage extension. + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_check_key_usage(hx509_context context, hx509_cert cert, + unsigned flags, int req_present) +{ + return check_key_usage(context, _hx509_get_cert(cert), flags, req_present); +} + +enum certtype { PROXY_CERT, EE_CERT, CA_CERT }; + +static int +check_basic_constraints(hx509_context context, const Certificate *cert, + enum certtype type, size_t depth) +{ + BasicConstraints bc; + const Extension *e; + size_t size; + int ret; + size_t i = 0; + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i); + if (e == NULL) { + switch(type) { + case PROXY_CERT: + case EE_CERT: + return 0; + case CA_CERT: { + char *name; + ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); + assert(ret == 0); + hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND, + "basicConstraints missing from " + "CA certifiacte %s", name); + free(name); + return HX509_EXTENSION_NOT_FOUND; + } + } + } + + ret = decode_BasicConstraints(e->extnValue.data, + e->extnValue.length, &bc, + &size); + if (ret) + return ret; + switch(type) { + case PROXY_CERT: + if (bc.cA) + ret = HX509_PARENT_IS_CA; + break; + case EE_CERT: + ret = 0; + break; + case CA_CERT: + if (!bc.cA) + ret = HX509_PARENT_NOT_CA; + else if (bc.pathLenConstraint) + if (depth - 1 > *bc.pathLenConstraint) + ret = HX509_CA_PATH_TOO_DEEP; + break; + } + free_BasicConstraints(&bc); + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_is_parent_cmp(const Certificate *subject, + const Certificate *issuer, + int allow_self_signed) +{ + int diff; + AuthorityKeyIdentifier ai; + SubjectKeyIdentifier si; + int ret_ai, ret_si, ret; + + ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, + &subject->tbsCertificate.issuer, + &diff); + if (ret) + return ret; + if (diff) + return diff; + + memset(&ai, 0, sizeof(ai)); + memset(&si, 0, sizeof(si)); + + /* + * Try to find AuthorityKeyIdentifier, if it's not present in the + * subject certificate nor the parent. + */ + + ret_ai = find_extension_auth_key_id(subject, &ai); + if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND) + return 1; + ret_si = _hx509_find_extension_subject_key_id(issuer, &si); + if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND) + return -1; + + if (ret_si && ret_ai) + goto out; + if (ret_ai) + goto out; + if (ret_si) { + if (allow_self_signed) { + diff = 0; + goto out; + } else if (ai.keyIdentifier) { + diff = -1; + goto out; + } + } + + if (ai.keyIdentifier == NULL) { + Name name; + + if (ai.authorityCertIssuer == NULL) + return -1; + if (ai.authorityCertSerialNumber == NULL) + return -1; + + diff = der_heim_integer_cmp(ai.authorityCertSerialNumber, + &issuer->tbsCertificate.serialNumber); + if (diff) + return diff; + if (ai.authorityCertIssuer->len != 1) + return -1; + if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName) + return -1; + + name.element = (enum Name_enum) + ai.authorityCertIssuer->val[0].u.directoryName.element; + name.u.rdnSequence = + ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence; + + ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, + &name, + &diff); + if (ret) + return ret; + if (diff) + return diff; + diff = 0; + } else + diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si); + if (diff) + goto out; + + out: + free_AuthorityKeyIdentifier(&ai); + free_SubjectKeyIdentifier(&si); + return diff; +} + +static int +certificate_is_anchor(hx509_context context, + hx509_certs trust_anchors, + const hx509_cert cert) +{ + hx509_query q; + hx509_cert c; + int ret; + + if (trust_anchors == NULL) + return 0; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_MATCH_CERTIFICATE; + q.certificate = _hx509_get_cert(cert); + + ret = hx509_certs_find(context, trust_anchors, &q, &c); + if (ret == 0) + hx509_cert_free(c); + return ret == 0; +} + +static int +certificate_is_self_signed(hx509_context context, + const Certificate *cert, + int *self_signed) +{ + int ret, diff; + ret = _hx509_name_cmp(&cert->tbsCertificate.subject, + &cert->tbsCertificate.issuer, &diff); + *self_signed = (diff == 0); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to check if self signed"); + } else if (diff == 0) + ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm); + + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_is_self_signed(hx509_context context, + hx509_cert c, + int *self_signed) +{ + return certificate_is_self_signed(context, c->data, self_signed); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_is_ca(hx509_context context, + hx509_cert c, + int *is_ca) +{ + BasicConstraints bc; + const Extension *e; + size_t size; + size_t i = 0; + int ret = 0; + + *is_ca = 0; + if (_hx509_cert_get_version(c->data) < 3) + return certificate_is_self_signed(context, c->data, is_ca); + + e = find_extension(c->data, &asn1_oid_id_x509_ce_basicConstraints, &i); + if (e == NULL) { + *is_ca = 0; + return 0; + } + + ret = decode_BasicConstraints(e->extnValue.data, + e->extnValue.length, &bc, + &size); + if (ret) + return ret; + + *is_ca = bc.cA; + free_BasicConstraints(&bc); + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_is_root(hx509_context context, + hx509_cert c, + int *is_root) +{ + int ret; + + *is_root = 0; + ret = hx509_cert_is_ca(context, c, is_root); + if (ret) + return ret; + if (*is_root == 0) + /* Not a CA certificate -> not a root certificate */ + return 0; + + /* A CA certificate. If it's self-signed, it's a root certificate. */ + return hx509_cert_is_self_signed(context, c, is_root); +} + +/* + * The subjectName is "null" when it's empty set of relative DBs. + */ + +static int +subject_null_p(const Certificate *c) +{ + return c->tbsCertificate.subject.u.rdnSequence.len == 0; +} + + +static int +find_parent(hx509_context context, + time_t time_now, + hx509_certs trust_anchors, + hx509_path *path, + hx509_certs pool, + hx509_cert current, + hx509_cert *parent) +{ + AuthorityKeyIdentifier ai; + hx509_query q; + int ret; + + *parent = NULL; + memset(&ai, 0, sizeof(ai)); + + _hx509_query_clear(&q); + + if (!subject_null_p(current->data)) { + q.match |= HX509_QUERY_FIND_ISSUER_CERT; + q.subject = _hx509_get_cert(current); + } else { + ret = find_extension_auth_key_id(current->data, &ai); + if (ret) { + hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, + "Subjectless certificate missing AuthKeyID"); + return HX509_CERTIFICATE_MALFORMED; + } + + if (ai.keyIdentifier == NULL) { + free_AuthorityKeyIdentifier(&ai); + hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, + "Subjectless certificate missing keyIdentifier " + "inside AuthKeyID"); + return HX509_CERTIFICATE_MALFORMED; + } + + q.subject_id = ai.keyIdentifier; + q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; + } + + q.path = path; + q.match |= HX509_QUERY_NO_MATCH_PATH; + + if (pool) { + q.timenow = time_now; + q.match |= HX509_QUERY_MATCH_TIME; + + ret = hx509_certs_find(context, pool, &q, parent); + if (ret == 0) { + free_AuthorityKeyIdentifier(&ai); + return 0; + } + q.match &= ~HX509_QUERY_MATCH_TIME; + } + + if (trust_anchors) { + ret = hx509_certs_find(context, trust_anchors, &q, parent); + if (ret == 0) { + free_AuthorityKeyIdentifier(&ai); + return ret; + } + } + free_AuthorityKeyIdentifier(&ai); + + { + hx509_name name; + char *str; + + ret = hx509_cert_get_subject(current, &name); + if (ret) { + hx509_clear_error_string(context); + return HX509_ISSUER_NOT_FOUND; + } + ret = hx509_name_to_string(name, &str); + hx509_name_free(&name); + if (ret) { + hx509_clear_error_string(context); + return HX509_ISSUER_NOT_FOUND; + } + + hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND, + "Failed to find issuer for " + "certificate with subject: '%s'", str); + free(str); + } + return HX509_ISSUER_NOT_FOUND; +} + +/* + * + */ + +static int +is_proxy_cert(hx509_context context, + const Certificate *cert, + ProxyCertInfo *rinfo) +{ + ProxyCertInfo info; + const Extension *e; + size_t size; + int ret; + size_t i = 0; + + if (rinfo) + memset(rinfo, 0, sizeof(*rinfo)); + + e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i); + if (e == NULL) { + hx509_clear_error_string(context); + return HX509_EXTENSION_NOT_FOUND; + } + + ret = decode_ProxyCertInfo(e->extnValue.data, + e->extnValue.length, + &info, + &size); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + if (size != e->extnValue.length) { + free_ProxyCertInfo(&info); + hx509_clear_error_string(context); + return HX509_EXTRA_DATA_AFTER_STRUCTURE; + } + if (rinfo == NULL) + free_ProxyCertInfo(&info); + else + *rinfo = info; + + return 0; +} + +/* + * Path operations are like MEMORY based keyset, but with exposed + * internal so we can do easy searches. + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert) +{ + hx509_cert *val; + val = realloc(path->val, (path->len + 1) * sizeof(path->val[0])); + if (val == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + path->val = val; + path->val[path->len] = hx509_cert_ref(cert); + path->len++; + + return 0; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_path_free(hx509_path *path) +{ + unsigned i; + + for (i = 0; i < path->len; i++) + hx509_cert_free(path->val[i]); + free(path->val); + path->val = NULL; + path->len = 0; +} + +/* + * Find path by looking up issuer for the top certificate and continue + * until an anchor certificate is found or max limit is found. A + * certificate never included twice in the path. + * + * If the trust anchors are not given, calculate optimistic path, just + * follow the chain upward until we no longer find a parent or we hit + * the max path limit. In this case, a failure will always be returned + * depending on what error condition is hit first. + * + * The path includes a path from the top certificate to the anchor + * certificate. + * + * The caller needs to free `path´ both on successful built path and + * failure. + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_calculate_path(hx509_context context, + int flags, + time_t time_now, + hx509_certs anchors, + unsigned int max_depth, + hx509_cert cert, + hx509_certs pool, + hx509_path *path) +{ + hx509_cert parent, current; + int ret; + + if (max_depth == 0) + max_depth = HX509_VERIFY_MAX_DEPTH; + + ret = _hx509_path_append(context, path, cert); + if (ret) + return ret; + + current = hx509_cert_ref(cert); + + while (!certificate_is_anchor(context, anchors, current)) { + + ret = find_parent(context, time_now, anchors, path, + pool, current, &parent); + hx509_cert_free(current); + if (ret) + return ret; + + ret = _hx509_path_append(context, path, parent); + if (ret) + return ret; + current = parent; + + if (path->len > max_depth) { + hx509_cert_free(current); + hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG, + "Path too long while bulding " + "certificate chain"); + return HX509_PATH_TOO_LONG; + } + } + + if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) && + path->len > 0 && + certificate_is_anchor(context, anchors, path->val[path->len - 1])) + { + hx509_cert_free(path->val[path->len - 1]); + path->len--; + } + + hx509_cert_free(current); + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p, + const AlgorithmIdentifier *q) +{ + int diff; + diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm); + if (diff) + return diff; + if (p->parameters) { + if (q->parameters) + return heim_any_cmp(p->parameters, + q->parameters); + else + return 1; + } else { + if (q->parameters) + return -1; + else + return 0; + } +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_Certificate_cmp(const Certificate *p, const Certificate *q) +{ + int diff; + diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue); + if (diff) + return diff; + diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm, + &q->signatureAlgorithm); + if (diff) + return diff; + diff = der_heim_octet_string_cmp(&p->tbsCertificate._save, + &q->tbsCertificate._save); + return diff; +} + +/** + * Compare to hx509 certificate object, useful for sorting. + * + * @param p a hx509 certificate object. + * @param q a hx509 certificate object. + * + * @return 0 the objects are the same, returns > 0 is p is "larger" + * then q, < 0 if p is "smaller" then q. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_cmp(hx509_cert p, hx509_cert q) +{ + return _hx509_Certificate_cmp(p->data, q->data); +} + +/** + * Return the name of the issuer of the hx509 certificate. + * + * @param p a hx509 certificate object. + * @param name a pointer to a hx509 name, should be freed by + * hx509_name_free(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_issuer(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name); +} + +/** + * Return the name of the subject of the hx509 certificate. + * + * @param p a hx509 certificate object. + * @param name a pointer to a hx509 name, should be freed by + * hx509_name_free(). See also hx509_cert_get_base_subject(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_subject(hx509_cert p, hx509_name *name) +{ + return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name); +} + +/** + * Return the name of the base subject of the hx509 certificate. If + * the certiicate is a verified proxy certificate, the this function + * return the base certificate (root of the proxy chain). If the proxy + * certificate is not verified with the base certificate + * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned. + * + * @param context a hx509 context. + * @param c a hx509 certificate object. + * @param name a pointer to a hx509 name, should be freed by + * hx509_name_free(). See also hx509_cert_get_subject(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_base_subject(hx509_context context, hx509_cert c, + hx509_name *name) +{ + if (c->basename) + return hx509_name_copy(context, c->basename, name); + if (is_proxy_cert(context, c->data, NULL) == 0) { + int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED; + hx509_set_error_string(context, 0, ret, + "Proxy certificate has not been " + "canonicalized yet: no base name"); + return ret; + } + return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name); +} + +/** + * Get serial number of the certificate. + * + * @param p a hx509 certificate object. + * @param i serial number, should be freed ith der_free_heim_integer(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i) +{ + return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); +} + +/** + * Get notBefore time of the certificate. + * + * @param p a hx509 certificate object. + * + * @return return not before time + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION time_t HX509_LIB_CALL +hx509_cert_get_notBefore(hx509_cert p) +{ + return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore); +} + +/** + * Get notAfter time of the certificate. + * + * @param p a hx509 certificate object. + * + * @return return not after time. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION time_t HX509_LIB_CALL +hx509_cert_get_notAfter(hx509_cert p) +{ + return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter); +} + +/** + * Get a maximum Kerberos credential lifetime from a Heimdal certificate + * extension. + * + * @param context hx509 context. + * @param cert Certificate. + * @param bound If larger than zero, return no more than this. + * + * @return maximum ticket lifetime. + */ +HX509_LIB_FUNCTION time_t HX509_LIB_CALL +hx509_cert_get_pkinit_max_life(hx509_context context, + hx509_cert cert, + time_t bound) +{ + HeimPkinitPrincMaxLifeSecs r = 0; + size_t sz, i; + time_t b, e; + int ret; + + for (i = 0; i < cert->data->tbsCertificate.extensions->len; i++) { + Extension *ext = &cert->data->tbsCertificate.extensions->val[i]; + + if (ext->_ioschoice_extnValue.element != + choice_Extension_iosnumunknown && + ext->_ioschoice_extnValue.element != + choice_Extension_iosnum_id_heim_ce_pkinit_princ_max_life) + continue; + if (ext->_ioschoice_extnValue.element == choice_Extension_iosnumunknown && + der_heim_oid_cmp(&asn1_oid_id_heim_ce_pkinit_princ_max_life, &ext->extnID)) + continue; + if (ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife) { + r = *ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife; + } else { + ret = decode_HeimPkinitPrincMaxLifeSecs(ext->extnValue.data, + ext->extnValue.length, + &r, &sz); + /* No need to free_HeimPkinitPrincMaxLifeSecs(); it's an int */ + if (ret || r < 1) + return 0; + } + if (bound > 0 && r > bound) + return bound; + return r; + } + if (hx509_cert_check_eku(context, cert, + &asn1_oid_id_heim_eku_pkinit_certlife_is_max_life, 0)) + return 0; + b = hx509_cert_get_notBefore(cert); + e = hx509_cert_get_notAfter(cert); + if (e > b) + r = e - b; + if (bound > 0 && r > bound) + return bound; + return r; +} + +/** + * Get the SubjectPublicKeyInfo structure from the hx509 certificate. + * + * @param context a hx509 context. + * @param p a hx509 certificate object. + * @param spki SubjectPublicKeyInfo, should be freed with + * free_SubjectPublicKeyInfo(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki) +{ + int ret; + + ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki); + if (ret) + hx509_set_error_string(context, 0, ret, "Failed to copy SPKI"); + return ret; +} + +/** + * Get the AlgorithmIdentifier from the hx509 certificate. + * + * @param context a hx509 context. + * @param p a hx509 certificate object. + * @param alg AlgorithmIdentifier, should be freed with + * free_AlgorithmIdentifier(). The algorithmidentifier is + * typicly rsaEncryption, or id-ecPublicKey, or some other + * public key mechanism. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context, + hx509_cert p, + AlgorithmIdentifier *alg) +{ + int ret; + + ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg); + if (ret) + hx509_set_error_string(context, 0, ret, + "Failed to copy SPKI AlgorithmIdentifier"); + return ret; +} + +static int +get_x_unique_id(hx509_context context, const char *name, + const heim_bit_string *cert, heim_bit_string *subject) +{ + int ret; + + if (cert == NULL) { + ret = HX509_EXTENSION_NOT_FOUND; + hx509_set_error_string(context, 0, ret, "%s unique id doesn't exist", name); + return ret; + } + ret = der_copy_bit_string(cert, subject); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc out of memory", name); + return ret; + } + return 0; +} + +/** + * Get a copy of the Issuer Unique ID + * + * @param context a hx509_context + * @param p a hx509 certificate + * @param issuer the issuer id returned, free with der_free_bit_string() + * + * @return An hx509 error code, see hx509_get_error_string(). The + * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate + * doesn't have a issuerUniqueID + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer) +{ + return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer); +} + +/** + * Get a copy of the Subect Unique ID + * + * @param context a hx509_context + * @param p a hx509 certificate + * @param subject the subject id returned, free with der_free_bit_string() + * + * @return An hx509 error code, see hx509_get_error_string(). The + * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate + * doesn't have a subjectUniqueID + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject) +{ + return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject); +} + + +HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL +_hx509_cert_private_key(hx509_cert p) +{ + return p->private_key; +} + +/** + * Indicate whether a hx509_cert has a private key. + * + * @param p a hx509 certificate + * + * @return 1 if p has a private key, 0 otherwise. + * + * @ingroup hx509_cert + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_have_private_key(hx509_cert p) +{ + return p->private_key ? 1 : 0; +} + +/** + * Indicate whether a hx509_cert has a private key only (no certificate). + * + * @param p a hx509 certificate + * + * @return 1 if p has a private key only (no certificate), 0 otherwise. + * + * @ingroup hx509_cert + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_have_private_key_only(hx509_cert p) +{ + return p->private_key && !p->data ? 1 : 0; +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_private_key_exportable(hx509_cert p) +{ + if (p->private_key == NULL) + return 0; + return _hx509_private_key_exportable(p->private_key); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_private_decrypt(hx509_context context, + const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_cert p, + heim_octet_string *cleartext) +{ + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private key missing"); + return HX509_PRIVATE_KEY_MISSING; + } + + return hx509_private_key_private_decrypt(context, + ciphertext, + encryption_oid, + p->private_key, + cleartext); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_public_encrypt(hx509_context context, + const heim_octet_string *cleartext, + const hx509_cert p, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + return _hx509_public_encrypt(context, + cleartext, p->data, + encryption_oid, ciphertext); +} + +/* + * + */ + +HX509_LIB_FUNCTION time_t HX509_LIB_CALL +_hx509_Time2time_t(const Time *t) +{ + switch(t->element) { + case choice_Time_utcTime: + return t->u.utcTime; + case choice_Time_generalTime: + return t->u.generalTime; + } + return 0; +} + +/* + * + */ + +static int +init_name_constraints(hx509_name_constraints *nc) +{ + memset(nc, 0, sizeof(*nc)); + return 0; +} + +static int +add_name_constraints(hx509_context context, const Certificate *c, int not_ca, + hx509_name_constraints *nc) +{ + NameConstraints tnc; + int ret; + + ret = find_extension_name_constraints(c, &tnc); + if (ret == HX509_EXTENSION_NOT_FOUND) + return 0; + else if (ret) { + hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints"); + return ret; + } else if (not_ca) { + ret = HX509_VERIFY_CONSTRAINTS; + hx509_set_error_string(context, 0, ret, "Not a CA and " + "have NameConstraints"); + } else { + NameConstraints *val; + val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1)); + if (val == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + nc->val = val; + ret = copy_NameConstraints(&tnc, &nc->val[nc->len]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + nc->len += 1; + } +out: + free_NameConstraints(&tnc); + return ret; +} + +static int +match_RDN(const RelativeDistinguishedName *c, + const RelativeDistinguishedName *n) +{ + size_t i; + + if (c->len != n->len) + return HX509_NAME_CONSTRAINT_ERROR; + + for (i = 0; i < n->len; i++) { + int diff, ret; + + if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff); + if (ret) + return ret; + if (diff != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } + return 0; +} + +static int +match_X501Name(const Name *c, const Name *n) +{ + size_t i; + int ret; + + if (c->element != choice_Name_rdnSequence + || n->element != choice_Name_rdnSequence) + return 0; + if (c->u.rdnSequence.len > n->u.rdnSequence.len) + return HX509_NAME_CONSTRAINT_ERROR; + for (i = 0; i < c->u.rdnSequence.len; i++) { + ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]); + if (ret) + return ret; + } + return 0; +} + + +static int +match_general_name(const GeneralName *c, const GeneralName *n, int *match) +{ + /* + * Name constraints only apply to the same name type, see RFC3280, + * 4.2.1.11. + */ + assert(c->element == n->element); + + switch(c->element) { + case choice_GeneralName_otherName: + if (der_heim_oid_cmp(&c->u.otherName.type_id, + &n->u.otherName.type_id) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (heim_any_cmp(&c->u.otherName.value, + &n->u.otherName.value) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + *match = 1; + return 0; + case choice_GeneralName_rfc822Name: { + const char *s; + size_t len1, len2; + s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length); + if (s) { + if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + } else { + s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length); + if (s == NULL) + return HX509_NAME_CONSTRAINT_ERROR; + len1 = c->u.rfc822Name.length; + len2 = n->u.rfc822Name.length - + (s - ((char *)n->u.rfc822Name.data)); + if (len1 > len2) + return HX509_NAME_CONSTRAINT_ERROR; + if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (len1 < len2 && s[len2 - len1 + 1] != '.') + return HX509_NAME_CONSTRAINT_ERROR; + } + *match = 1; + return 0; + } + case choice_GeneralName_dNSName: { + size_t lenc, lenn; + char *ptr; + + lenc = c->u.dNSName.length; + lenn = n->u.dNSName.length; + if (lenc > lenn) + return HX509_NAME_CONSTRAINT_ERROR; + ptr = n->u.dNSName.data; + if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (lenn != lenc && ptr[lenn - lenc - 1] != '.') + return HX509_NAME_CONSTRAINT_ERROR; + *match = 1; + return 0; + } + case choice_GeneralName_directoryName: { + Name c_name, n_name; + int ret; + + c_name._save.data = NULL; + c_name._save.length = 0; + c_name.element = (enum Name_enum)c->u.directoryName.element; + c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence; + + n_name._save.data = NULL; + n_name._save.length = 0; + n_name.element = (enum Name_enum)n->u.directoryName.element; + n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence; + + ret = match_X501Name(&c_name, &n_name); + if (ret == 0) + *match = 1; + return ret; + } + case choice_GeneralName_uniformResourceIdentifier: + case choice_GeneralName_iPAddress: + case choice_GeneralName_registeredID: + default: + return HX509_NAME_CONSTRAINT_ERROR; + } +} + +static int +match_alt_name(const GeneralName *n, const Certificate *c, + int *same, int *match) +{ + GeneralNames sa; + int ret = 0; + size_t i, j; + + i = 0; + do { + ret = find_extension_subject_alt_name(c, &i, &sa); + if (ret == HX509_EXTENSION_NOT_FOUND) { + ret = 0; + break; + } else if (ret != 0) + break; + + for (j = 0; j < sa.len; j++) { + if (n->element == sa.val[j].element) { + *same = 1; + match_general_name(n, &sa.val[j], match); + } + } + free_GeneralNames(&sa); + } while (1); + return ret; +} + + +static int +match_tree(const GeneralSubtrees *t, const Certificate *c, int *match) +{ + int name, alt_name, same; + unsigned int i; + int ret = 0; + + name = alt_name = same = *match = 0; + for (i = 0; i < t->len; i++) { + if (t->val[i].minimum && t->val[i].maximum) + return HX509_RANGE; + + /* + * If the constraint apply to directoryNames, test is with + * subjectName of the certificate if the certificate have a + * non-null (empty) subjectName. + */ + + if (t->val[i].base.element == choice_GeneralName_directoryName + && !subject_null_p(c)) + { + GeneralName certname; + + memset(&certname, 0, sizeof(certname)); + certname.element = choice_GeneralName_directoryName; + certname.u.directoryName.element = (enum Name_enum) + c->tbsCertificate.subject.element; + certname.u.directoryName.u.rdnSequence = + c->tbsCertificate.subject.u.rdnSequence; + + match_general_name(&t->val[i].base, &certname, &name); + } + + /* Handle subjectAltNames, this is icky since they + * restrictions only apply if the subjectAltName is of the + * same type. So if there have been a match of type, require + * altname to be set. + */ + match_alt_name(&t->val[i].base, c, &same, &alt_name); + } + if (name && (!same || alt_name)) + *match = 1; + return ret; +} + +static int +check_name_constraints(hx509_context context, + const hx509_name_constraints *nc, + const Certificate *c) +{ + int match, ret; + size_t i; + + for (i = 0 ; i < nc->len; i++) { + GeneralSubtrees gs; + + if (nc->val[i].permittedSubtrees) { + GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees); + ret = match_tree(&gs, c, &match); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + /* allow null subjectNames, they wont matches anything */ + if (match == 0 && !subject_null_p(c)) { + hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, + "Error verifying constraints: " + "certificate didn't match any " + "permitted subtree"); + return HX509_VERIFY_CONSTRAINTS; + } + } + if (nc->val[i].excludedSubtrees) { + GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees); + ret = match_tree(&gs, c, &match); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + if (match) { + hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, + "Error verifying constraints: " + "certificate included in excluded " + "subtree"); + return HX509_VERIFY_CONSTRAINTS; + } + } + } + return 0; +} + +static void +free_name_constraints(hx509_name_constraints *nc) +{ + size_t i; + + for (i = 0 ; i < nc->len; i++) + free_NameConstraints(&nc->val[i]); + free(nc->val); +} + +/** + * Build and verify the path for the certificate to the trust anchor + * specified in the verify context. The path is constructed from the + * certificate, the pool and the trust anchors. + * + * @param context A hx509 context. + * @param ctx A hx509 verification context. + * @param cert the certificate to build the path from. + * @param pool A keyset of certificates to build the chain from. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_verify_path(hx509_context context, + hx509_verify_ctx ctx, + hx509_cert cert, + hx509_certs pool) +{ + hx509_name_constraints nc; + hx509_path path; + int ret, proxy_cert_depth, selfsigned_depth, diff; + size_t i, k; + enum certtype type; + Name proxy_issuer; + hx509_certs anchors = NULL; + + memset(&proxy_issuer, 0, sizeof(proxy_issuer)); + + if ((ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) == 0 && + is_proxy_cert(context, cert->data, NULL) == 0) + { + ret = HX509_PROXY_CERT_INVALID; + hx509_set_error_string(context, 0, ret, + "Proxy certificate is not allowed as an EE " + "certificate if proxy certificate is disabled"); + return ret; + } + + ret = init_name_constraints(&nc); + if (ret) + return ret; + + path.val = NULL; + path.len = 0; + + if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0) + ctx->time_now = time(NULL); + + /* + * + */ + if (ctx->trust_anchors) + anchors = hx509_certs_ref(ctx->trust_anchors); + else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx)) + anchors = hx509_certs_ref(context->default_trust_anchors); + else { + ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors); + if (ret) + goto out; + } + + /* + * Calculate the path from the certificate user presented to the + * to an anchor. + */ + ret = _hx509_calculate_path(context, 0, ctx->time_now, + anchors, ctx->max_depth, + cert, pool, &path); + if (ret) + goto out; + + /* + * Check CA and proxy certificate chain from the top of the + * certificate chain. Also check certificate is valid with respect + * to the current time. + * + */ + + proxy_cert_depth = 0; + selfsigned_depth = 0; + + if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) + type = PROXY_CERT; + else + type = EE_CERT; + + for (i = 0; i < path.len; i++) { + Certificate *c; + time_t t; + + c = _hx509_get_cert(path.val[i]); + + /* + * Lets do some basic check on issuer like + * keyUsage.keyCertSign and basicConstraints.cA bit depending + * on what type of certificate this is. + */ + + switch (type) { + case CA_CERT: + + /* XXX make constants for keyusage */ + ret = check_key_usage(context, c, 1 << 5, + REQUIRE_RFC3280(ctx) ? TRUE : FALSE); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Key usage missing from CA certificate"); + goto out; + } + + /* self signed cert doesn't add to path length */ + if (i + 1 != path.len) { + int selfsigned; + + ret = certificate_is_self_signed(context, c, &selfsigned); + if (ret) + goto out; + if (selfsigned) + selfsigned_depth++; + } + + break; + case PROXY_CERT: { + ProxyCertInfo info; + + if (is_proxy_cert(context, c, &info) == 0) { + size_t j; + + if (info.pCPathLenConstraint != NULL && + *info.pCPathLenConstraint < i) + { + free_ProxyCertInfo(&info); + ret = HX509_PATH_TOO_LONG; + hx509_set_error_string(context, 0, ret, + "Proxy certificate chain " + "longer than allowed"); + goto out; + } + /* XXX MUST check info.proxyPolicy */ + free_ProxyCertInfo(&info); + + j = 0; + if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) { + ret = HX509_PROXY_CERT_INVALID; + hx509_set_error_string(context, 0, ret, + "Proxy certificate has explicitly " + "forbidden subjectAltName"); + goto out; + } + + j = 0; + if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) { + ret = HX509_PROXY_CERT_INVALID; + hx509_set_error_string(context, 0, ret, + "Proxy certificate has explicitly " + "forbidden issuerAltName"); + goto out; + } + + /* + * The subject name of the proxy certificate should be + * CN=XXX,. Prune off CN and check if it's + * the same over the whole chain of proxy certs and + * then check with the EE cert when we get to it. + */ + + if (proxy_cert_depth) { + ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (diff) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Base proxy name not right"); + goto out; + } + } + + free_Name(&proxy_issuer); + + ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + j = proxy_issuer.u.rdnSequence.len; + if (proxy_issuer.u.rdnSequence.len < 2 + || proxy_issuer.u.rdnSequence.val[j - 1].len > 1 + || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type, + &asn1_oid_id_at_commonName)) + { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Proxy name too short or " + "does not have Common name " + "at the top"); + goto out; + } + + free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]); + proxy_issuer.u.rdnSequence.len -= 1; + + ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (diff != 0) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_set_error_string(context, 0, ret, + "Proxy issuer name not as expected"); + goto out; + } + + break; + } else { + /* + * Now we are done with the proxy certificates, this + * cert was an EE cert and we will fall though to + * EE checking below. + */ + type = EE_CERT; + } + } + HEIM_FALLTHROUGH; + case EE_CERT: + /* + * If there were any proxy certificates in the chain + * (proxy_cert_depth > 0), check that the proxy issuer + * matched the proxy certificate's "base" subject. + */ + if (proxy_cert_depth) { + + ret = _hx509_name_cmp(&proxy_issuer, + &c->tbsCertificate.subject, &diff); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + if (diff) { + ret = HX509_PROXY_CERT_NAME_WRONG; + hx509_clear_error_string(context); + goto out; + } + if (cert->basename) + hx509_name_free(&cert->basename); + + ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + break; + } + + ret = check_basic_constraints(context, c, type, + i - proxy_cert_depth - selfsigned_depth); + if (ret) + goto out; + + /* + * Don't check the trust anchors expiration time since they + * are transported out of band, from RFC3820. + */ + if (i + 1 != path.len || CHECK_TA(ctx)) { + + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + if (t > ctx->time_now) { + ret = HX509_CERT_USED_BEFORE_TIME; + hx509_clear_error_string(context); + goto out; + } + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); + if (t < ctx->time_now) { + ret = HX509_CERT_USED_AFTER_TIME; + hx509_clear_error_string(context); + goto out; + } + } + + if (type == EE_CERT) + type = CA_CERT; + else if (type == PROXY_CERT) + proxy_cert_depth++; + } + + /* + * Verify constraints, do this backward so path constraints are + * checked in the right order. + */ + + for (ret = 0, k = path.len; k > 0; k--) { + Certificate *c; + int selfsigned; + i = k - 1; + + c = _hx509_get_cert(path.val[i]); + + ret = certificate_is_self_signed(context, c, &selfsigned); + if (ret) + goto out; + + /* verify name constraints, not for selfsigned and anchor */ + if (!selfsigned || i + 1 != path.len) { + ret = check_name_constraints(context, &nc, c); + if (ret) { + goto out; + } + } + ret = add_name_constraints(context, c, i == 0, &nc); + if (ret) + goto out; + + /* XXX verify all other silly constraints */ + + } + + /* + * Verify that no certificates have been revoked. + */ + + if (ctx->revoke_ctx) { + hx509_certs certs; + + ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0, + NULL, &certs); + if (ret) + goto out; + + for (i = 0; i < path.len; i++) { + ret = hx509_certs_add(context, certs, path.val[i]); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + } + ret = hx509_certs_merge(context, certs, pool); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + + for (i = 0; i < path.len - 1; i++) { + size_t parent = (i < path.len - 1) ? i + 1 : i; + + ret = hx509_revoke_verify(context, + ctx->revoke_ctx, + certs, + ctx->time_now, + path.val[i], + path.val[parent]); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + } + hx509_certs_free(&certs); + } + + /* + * Verify signatures, do this backward so public key working + * parameter is passed up from the anchor up though the chain. + */ + + for (k = path.len; k > 0; k--) { + hx509_cert signer; + Certificate *c; + i = k - 1; + + c = _hx509_get_cert(path.val[i]); + + /* is last in chain (trust anchor) */ + if (i + 1 == path.len) { + int selfsigned; + + signer = path.val[i]; + + ret = certificate_is_self_signed(context, signer->data, &selfsigned); + if (ret) + goto out; + + /* if trust anchor is not self signed, don't check sig */ + if (!selfsigned) + continue; + } else { + /* take next certificate in chain */ + signer = path.val[i + 1]; + } + + /* verify signatureValue */ + ret = _hx509_verify_signature_bitstring(context, + signer, + &c->signatureAlgorithm, + &c->tbsCertificate._save, + &c->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify signature of certificate"); + goto out; + } + /* + * Verify that the signature algorithm is not weak. Ignore + * trust anchors since they are provisioned by the user. + */ + + if (i + 1 != path.len && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) { + ret = _hx509_signature_is_weak(context, &c->signatureAlgorithm); + if (ret) + goto out; + } + } + +out: + hx509_certs_free(&anchors); + free_Name(&proxy_issuer); + free_name_constraints(&nc); + _hx509_path_free(&path); + + return ret; +} + +/** + * Verify a signature made using the private key of an certificate. + * + * @param context A hx509 context. + * @param signer the certificate that made the signature. + * @param alg algorthm that was used to sign the data. + * @param data the data that was signed. + * @param sig the signature to verify. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_crypto + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_verify_signature(hx509_context context, + const hx509_cert signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + return _hx509_verify_signature(context, signer, alg, data, sig); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_verify_signature_bitstring(hx509_context context, + const hx509_cert signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_bit_string *sig) +{ + heim_octet_string os; + + if (sig->length & 7) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "signature not multiple of 8 bits"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + os.data = sig->data; + os.length = sig->length / 8; + + return _hx509_verify_signature(context, signer, alg, data, &os); +} + + + +/** + * Verify that the certificate is allowed to be used for the hostname + * and address. + * + * @param context A hx509 context. + * @param cert the certificate to match with + * @param flags Flags to modify the behavior: + * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok + * @param type type of hostname: + * - HX509_HN_HOSTNAME for plain hostname. + * - HX509_HN_DNSSRV for DNS SRV names. + * @param hostname the hostname to check + * @param sa address of the host + * @param sa_size length of address + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_verify_hostname(hx509_context context, + const hx509_cert cert, + int flags, + hx509_hostname_type type, + const char *hostname, + const struct sockaddr *sa, + /* XXX krb5_socklen_t */ int sa_size) +{ + GeneralNames san; + const Name *name; + int ret; + size_t i, j, k; + + if (sa && sa_size <= 0) + return EINVAL; + + memset(&san, 0, sizeof(san)); + + i = 0; + do { + ret = find_extension_subject_alt_name(cert->data, &i, &san); + if (ret == HX509_EXTENSION_NOT_FOUND) + break; + else if (ret != 0) + return HX509_PARSING_NAME_FAILED; + + for (j = 0; j < san.len; j++) { + switch (san.val[j].element) { + case choice_GeneralName_dNSName: { + heim_printable_string hn; + hn.data = rk_UNCONST(hostname); + hn.length = strlen(hostname); + + if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) { + free_GeneralNames(&san); + return 0; + } + break; + } + default: + break; + } + } + free_GeneralNames(&san); + } while (1); + + name = &cert->data->tbsCertificate.subject; + + /* Find first CN= in the name, and try to match the hostname on that */ + for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) { + i = k - 1; + for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) { + AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j]; + + if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) { + DirectoryString *ds = &n->value; + switch (ds->element) { + case choice_DirectoryString_printableString: { + heim_printable_string hn; + hn.data = rk_UNCONST(hostname); + hn.length = strlen(hostname); + + if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0) + return 0; + break; + } + case choice_DirectoryString_ia5String: { + heim_ia5_string hn; + hn.data = rk_UNCONST(hostname); + hn.length = strlen(hostname); + + if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0) + return 0; + break; + } + case choice_DirectoryString_utf8String: + if (strcasecmp(ds->u.utf8String, hostname) == 0) + return 0; + default: + break; + } + ret = HX509_NAME_CONSTRAINT_ERROR; + } + } + } + + if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0) + ret = HX509_NAME_CONSTRAINT_ERROR; + + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_set_cert_attribute(hx509_context context, + hx509_cert cert, + const heim_oid *oid, + const heim_octet_string *attr) +{ + hx509_cert_attribute a; + void *d; + int ret; + + /* + * TODO: Rewrite this (and hx509_cert_attribute, and _hx509_cert_attrs) to + * use the add_AttributeValues() util generated by asn1_compile. + */ + + if (hx509_cert_get_attribute(cert, oid) != NULL) + return 0; + + d = realloc(cert->attrs.val, + sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1)); + if (d == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + cert->attrs.val = d; + + a = malloc(sizeof(*a)); + if (a == NULL) + return ENOMEM; + + ret = der_copy_octet_string(attr, &a->data); + if (ret == 0) + ret = der_copy_oid(oid, &a->oid); + if (ret == 0) { + cert->attrs.val[cert->attrs.len] = a; + cert->attrs.len++; + } else { + der_free_octet_string(&a->data); + free(a); + } + + return ret; +} + +/** + * Get an external attribute for the certificate, examples are + * friendly name and id. + * + * @param cert hx509 certificate object to search + * @param oid an oid to search for. + * + * @return an hx509_cert_attribute, only valid as long as the + * certificate is referenced. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert_attribute HX509_LIB_CALL +hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid) +{ + size_t i; + for (i = 0; i < cert->attrs.len; i++) + if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0) + return cert->attrs.val[i]; + return NULL; +} + +/** + * Set the friendly name on the certificate. + * + * @param cert The certificate to set the friendly name on + * @param name Friendly name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_set_friendly_name(hx509_cert cert, const char *name) +{ + if (cert->friendlyname) + free(cert->friendlyname); + cert->friendlyname = strdup(name); + if (cert->friendlyname == NULL) + return ENOMEM; + return 0; +} + +/** + * Get friendly name of the certificate. + * + * @param cert cert to get the friendly name from. + * + * @return an friendly name or NULL if there is. The friendly name is + * only valid as long as the certificate is referenced. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +hx509_cert_get_friendly_name(hx509_cert cert) +{ + hx509_cert_attribute a; + PKCS9_friendlyName n; + size_t sz; + int ret; + size_t i; + + if (cert->friendlyname) + return cert->friendlyname; + + a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName); + if (a == NULL) { + hx509_name name; + + ret = hx509_cert_get_subject(cert, &name); + if (ret) + return NULL; + ret = hx509_name_to_string(name, &cert->friendlyname); + hx509_name_free(&name); + if (ret) + return NULL; + return cert->friendlyname; + } + + ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz); + if (ret) + return NULL; + + if (n.len != 1) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + cert->friendlyname = malloc(n.val[0].length + 1); + if (cert->friendlyname == NULL) { + free_PKCS9_friendlyName(&n); + return NULL; + } + + for (i = 0; i < n.val[0].length; i++) { + if (n.val[0].data[i] <= 0xff) + cert->friendlyname[i] = n.val[0].data[i] & 0xff; + else + cert->friendlyname[i] = 'X'; + } + cert->friendlyname[i] = '\0'; + free_PKCS9_friendlyName(&n); + + return cert->friendlyname; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_query_clear(hx509_query *q) +{ + memset(q, 0, sizeof(*q)); +} + +/** + * Allocate an query controller. Free using hx509_query_free(). + * + * @param context A hx509 context. + * @param q return pointer to a hx509_query. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_alloc(hx509_context context, hx509_query **q) +{ + *q = calloc(1, sizeof(**q)); + if (*q == NULL) + return ENOMEM; + return 0; +} + + +/** + * Set match options for the hx509 query controller. + * + * @param q query controller. + * @param option options to control the query controller. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_query_match_option(hx509_query *q, hx509_query_option option) +{ + switch(option) { + case HX509_QUERY_OPTION_PRIVATE_KEY: + q->match |= HX509_QUERY_PRIVATE_KEY; + break; + case HX509_QUERY_OPTION_KU_ENCIPHERMENT: + q->match |= HX509_QUERY_KU_ENCIPHERMENT; + break; + case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE: + q->match |= HX509_QUERY_KU_DIGITALSIGNATURE; + break; + case HX509_QUERY_OPTION_KU_KEYCERTSIGN: + q->match |= HX509_QUERY_KU_KEYCERTSIGN; + break; + case HX509_QUERY_OPTION_END: + default: + break; + } +} + +/** + * Set the issuer and serial number of match in the query + * controller. The function make copies of the isser and serial number. + * + * @param q a hx509 query controller + * @param issuer issuer to search for + * @param serialNumber the serialNumber of the issuer. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_match_issuer_serial(hx509_query *q, + const Name *issuer, + const heim_integer *serialNumber) +{ + int ret; + if (q->serial) { + der_free_heim_integer(q->serial); + free(q->serial); + } + q->serial = malloc(sizeof(*q->serial)); + if (q->serial == NULL) + return ENOMEM; + ret = der_copy_heim_integer(serialNumber, q->serial); + if (ret) { + free(q->serial); + q->serial = NULL; + return ret; + } + if (q->issuer_name) { + free_Name(q->issuer_name); + free(q->issuer_name); + } + q->issuer_name = malloc(sizeof(*q->issuer_name)); + if (q->issuer_name == NULL) + return ENOMEM; + ret = copy_Name(issuer, q->issuer_name); + if (ret) { + free(q->issuer_name); + q->issuer_name = NULL; + return ret; + } + q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; + return 0; +} + +/** + * Set the query controller to match on a friendly name + * + * @param q a hx509 query controller. + * @param name a friendly name to match on + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_match_friendly_name(hx509_query *q, const char *name) +{ + if (q->friendlyname) + free(q->friendlyname); + q->friendlyname = strdup(name); + if (q->friendlyname == NULL) + return ENOMEM; + q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME; + return 0; +} + +/** + * Set the query controller to require an one specific EKU (extended + * key usage). Any previous EKU matching is overwitten. If NULL is + * passed in as the eku, the EKU requirement is reset. + * + * @param q a hx509 query controller. + * @param eku an EKU to match on. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_match_eku(hx509_query *q, const heim_oid *eku) +{ + int ret; + + if (eku == NULL) { + if (q->eku) { + der_free_oid(q->eku); + free(q->eku); + q->eku = NULL; + } + q->match &= ~HX509_QUERY_MATCH_EKU; + } else { + if (q->eku) { + der_free_oid(q->eku); + } else { + q->eku = calloc(1, sizeof(*q->eku)); + if (q->eku == NULL) + return ENOMEM; + } + ret = der_copy_oid(eku, q->eku); + if (ret) { + free(q->eku); + q->eku = NULL; + return ret; + } + q->match |= HX509_QUERY_MATCH_EKU; + } + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr) +{ + if (q->expr) { + _hx509_expr_free(q->expr); + q->expr = NULL; + } + + if (expr == NULL) { + q->match &= ~HX509_QUERY_MATCH_EXPR; + return 0; + } + + q->expr = _hx509_expr_parse(expr); + if (q->expr == NULL) { + const char *reason = _hx509_expr_parse_error(); + + hx509_set_error_string(context, 0, EINVAL, + "Invalid certificate query match expression: " + "%s (%s)", expr, + reason ? reason : "syntax error"); + return EINVAL; + } + + q->match |= HX509_QUERY_MATCH_EXPR; + return 0; +} + +/** + * Set the query controller to match using a specific match function. + * + * @param q a hx509 query controller. + * @param func function to use for matching, if the argument is NULL, + * the match function is removed. + * @param ctx context passed to the function. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_query_match_cmp_func(hx509_query *q, + int (*func)(hx509_context, hx509_cert, void *), + void *ctx) +{ + if (func) + q->match |= HX509_QUERY_MATCH_FUNCTION; + else + q->match &= ~HX509_QUERY_MATCH_FUNCTION; + q->cmp_func = func; + q->cmp_func_ctx = ctx; + return 0; +} + +/** + * Free the query controller. + * + * @param context A hx509 context. + * @param q a pointer to the query controller. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_query_free(hx509_context context, hx509_query *q) +{ + if (q == NULL) + return; + + if (q->serial) { + der_free_heim_integer(q->serial); + free(q->serial); + } + if (q->issuer_name) { + free_Name(q->issuer_name); + free(q->issuer_name); + } + if (q->eku) { + der_free_oid(q->eku); + free(q->eku); + } + if (q->friendlyname) + free(q->friendlyname); + if (q->expr) + _hx509_expr_free(q->expr); + + memset(q, 0, sizeof(*q)); + free(q); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + int ret, diff; + + _hx509_query_statistic(context, 1, q); + + if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && + _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) && + _hx509_Certificate_cmp(q->certificate, c) != 0) + return 0; + + if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER) + && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0) + return 0; + + if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) { + ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff); + if (ret || diff) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) { + ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff); + if (ret || diff) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) { + SubjectKeyIdentifier si; + + ret = _hx509_find_extension_subject_key_id(c, &si); + if (ret == 0) { + if (der_heim_octet_string_cmp(&si, q->subject_id) != 0) + ret = 1; + free_SubjectKeyIdentifier(&si); + } + if (ret) + return 0; + } + if ((q->match & HX509_QUERY_MATCH_ISSUER_ID)) + return 0; + if ((q->match & HX509_QUERY_PRIVATE_KEY) && + _hx509_cert_private_key(cert) == NULL) + return 0; + + { + unsigned ku = 0; + if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE) + ku |= (1 << 0); + if (q->match & HX509_QUERY_KU_NONREPUDIATION) + ku |= (1 << 1); + if (q->match & HX509_QUERY_KU_ENCIPHERMENT) + ku |= (1 << 2); + if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT) + ku |= (1 << 3); + if (q->match & HX509_QUERY_KU_KEYAGREEMENT) + ku |= (1 << 4); + if (q->match & HX509_QUERY_KU_KEYCERTSIGN) + ku |= (1 << 5); + if (q->match & HX509_QUERY_KU_CRLSIGN) + ku |= (1 << 6); + if (ku && check_key_usage(context, c, ku, TRUE)) + return 0; + } + if ((q->match & HX509_QUERY_ANCHOR)) + return 0; + + if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { + hx509_cert_attribute a; + + a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId); + if (a == NULL) + return 0; + if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0) + return 0; + } + + if (q->match & HX509_QUERY_NO_MATCH_PATH) { + size_t i; + + for (i = 0; i < q->path->len; i++) + if (hx509_cert_cmp(q->path->val[i], cert) == 0) + return 0; + } + if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) { + const char *name = hx509_cert_get_friendly_name(cert); + if (name == NULL) + return 0; + if (strcasecmp(q->friendlyname, name) != 0) + return 0; + } + if (q->match & HX509_QUERY_MATCH_FUNCTION) { + ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx); + if (ret != 0) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) { + heim_octet_string os; + + os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_verify_signature(context, + NULL, + hx509_signature_sha1(), + &os, + q->keyhash_sha1); + if (ret != 0) + return 0; + } + + if (q->match & HX509_QUERY_MATCH_TIME) { + time_t t; + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); + if (t > q->timenow) + return 0; + t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); + if (t < q->timenow) + return 0; + } + + /* If an EKU is required, check the cert for it. */ + if ((q->match & HX509_QUERY_MATCH_EKU) && + hx509_cert_check_eku(context, cert, q->eku, 0)) + return 0; + + if ((q->match & HX509_QUERY_MATCH_EXPR)) { + hx509_env env = NULL; + + ret = _hx509_cert_to_env(context, cert, &env); + if (ret) + return 0; + + ret = _hx509_expr_eval(context, env, q->expr); + hx509_env_free(&env); + if (ret == 0) + return 0; + } + + if (q->match & ~HX509_QUERY_MASK) + return 0; + + return 1; +} + +/** + * Set a statistic file for the query statistics. + * + * @param context A hx509 context. + * @param fn statistics file name + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_query_statistic_file(hx509_context context, const char *fn) +{ + if (context->querystat) + free(context->querystat); + context->querystat = strdup(fn); +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_query_statistic(hx509_context context, int type, const hx509_query *q) +{ + FILE *f; + if (context->querystat == NULL) + return; + f = fopen(context->querystat, "a"); + if (f == NULL) + return; + rk_cloexec_file(f); + fprintf(f, "%d %d\n", type, q->match); + fclose(f); +} + +static const char *statname[] = { + "find issuer cert", + "match serialnumber", + "match issuer name", + "match subject name", + "match subject key id", + "match issuer id", + "private key", + "ku encipherment", + "ku digitalsignature", + "ku keycertsign", + "ku crlsign", + "ku nonrepudiation", + "ku keyagreement", + "ku dataencipherment", + "anchor", + "match certificate", + "match local key id", + "no match path", + "match friendly name", + "match function", + "match key hash sha1", + "match time" +}; + +struct stat_el { + unsigned long stats; + unsigned int index; +}; + + +static int +stat_sort(const void *a, const void *b) +{ + const struct stat_el *ae = a; + const struct stat_el *be = b; + return be->stats - ae->stats; +} + +/** + * Unparse the statistics file and print the result on a FILE descriptor. + * + * @param context A hx509 context. + * @param printtype tyep to print + * @param out the FILE to write the data on. + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out) +{ + rtbl_t t; + FILE *f; + int type, mask, num; + size_t i; + unsigned long multiqueries = 0, totalqueries = 0; + struct stat_el stats[32]; + + if (context->querystat == NULL) + return; + f = fopen(context->querystat, "r"); + if (f == NULL) { + fprintf(out, "No statistics file %s: %s.\n", + context->querystat, strerror(errno)); + return; + } + rk_cloexec_file(f); + + for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { + stats[i].index = i; + stats[i].stats = 0; + } + + while (fscanf(f, "%d %d\n", &type, &mask) == 2) { + if (type != printtype) + continue; + num = i = 0; + while (mask && i < sizeof(stats)/sizeof(stats[0])) { + if (mask & 1) { + stats[i].stats++; + num++; + } + mask = mask >>1 ; + i++; + } + if (num > 1) + multiqueries++; + totalqueries++; + } + fclose(f); + + qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort); + + t = rtbl_create(); + if (t == NULL) + errx(1, "out of memory"); + + rtbl_set_separator (t, " "); + + rtbl_add_column_by_id (t, 0, "Name", 0); + rtbl_add_column_by_id (t, 1, "Counter", 0); + + + for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { + char str[10]; + + if (stats[i].index < sizeof(statname)/sizeof(statname[0])) + rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]); + else { + snprintf(str, sizeof(str), "%d", stats[i].index); + rtbl_add_column_entry_by_id (t, 0, str); + } + snprintf(str, sizeof(str), "%lu", stats[i].stats); + rtbl_add_column_entry_by_id (t, 1, str); + } + + rtbl_format(t, out); + rtbl_destroy(t); + + fprintf(out, "\nQueries: multi %lu total %lu\n", + multiqueries, totalqueries); +} + +/** + * Check the extended key usage on the hx509 certificate. + * + * @param context A hx509 context. + * @param cert A hx509 context. + * @param eku the EKU to check for + * @param allow_any_eku if the any EKU is set, allow that to be a + * substitute. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_check_eku(hx509_context context, hx509_cert cert, + const heim_oid *eku, int allow_any_eku) +{ + ExtKeyUsage e; + int ret; + size_t i; + + ret = find_extension_eku(_hx509_get_cert(cert), &e); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + + for (i = 0; i < e.len; i++) { + if (der_heim_oid_cmp(eku, &e.val[i]) == 0) { + free_ExtKeyUsage(&e); + return 0; + } + if (allow_any_eku) { + if (der_heim_oid_cmp(&asn1_oid_id_x509_ce_anyExtendedKeyUsage, + &e.val[i]) == 0) { + free_ExtKeyUsage(&e); + return 0; + } + } + } + free_ExtKeyUsage(&e); + hx509_clear_error_string(context); + return HX509_CERTIFICATE_MISSING_EKU; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_get_keyusage(hx509_context context, + hx509_cert c, + KeyUsage *ku) +{ + Certificate *cert; + const Extension *e; + size_t size; + int ret; + size_t i = 0; + + memset(ku, 0, sizeof(*ku)); + + cert = _hx509_get_cert(c); + + if (_hx509_cert_get_version(cert) < 3) + return 0; + + e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); + if (e == NULL) + return HX509_KU_CERT_MISSING; + + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size); + if (ret) + return ret; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_get_eku(hx509_context context, + hx509_cert cert, + ExtKeyUsage *e) +{ + int ret; + + memset(e, 0, sizeof(*e)); + + ret = find_extension_eku(_hx509_get_cert(cert), e); + if (ret && ret != HX509_EXTENSION_NOT_FOUND) { + hx509_clear_error_string(context); + return ret; + } + return 0; +} + +/** + * Encodes the hx509 certificate as a DER encode binary. + * + * @param context A hx509 context. + * @param c the certificate to encode. + * @param os the encode certificate, set to NULL, 0 on case of + * error. Free the os->data with hx509_xfree(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os) +{ + size_t size; + int ret; + + os->data = NULL; + os->length = 0; + + ASN1_MALLOC_ENCODE(Certificate, os->data, os->length, + _hx509_get_cert(c), &size, ret); + if (ret) { + os->data = NULL; + os->length = 0; + return ret; + } + if (os->length != size) + _hx509_abort("internal ASN.1 encoder error"); + return ret; +} + +/* + * Last to avoid lost __attribute__s due to #undef. + */ + +#undef __attribute__ +#define __attribute__(X) + +HX509_LIB_NORETURN_FUNCTION void HX509_LIB_CALL +_hx509_abort(const char *fmt, ...) + __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2))) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + fflush(stdout); + abort(); +} + +/** + * Free a data element allocated in the library. + * + * @param ptr data to be freed. + * + * @ingroup hx509_misc + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_xfree(void *ptr) +{ + free(ptr); +} + +/** + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) +{ + ExtKeyUsage eku; + hx509_name name; + char *buf; + int ret; + hx509_env envcert = NULL; + + *env = NULL; + + /* version */ + ret = asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert))); + if (ret == -1) + goto out; + ret = hx509_env_add(context, &envcert, "version", buf); + free(buf); + if (ret) + goto out; + + /* subject */ + ret = hx509_cert_get_subject(cert, &name); + if (ret) + goto out; + + ret = hx509_name_to_string(name, &buf); + hx509_name_free(&name); + if (ret) + goto out; + + ret = hx509_env_add(context, &envcert, "subject", buf); + hx509_xfree(buf); + if (ret) + goto out; + + /* issuer */ + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + goto out; + + ret = hx509_name_to_string(name, &buf); + hx509_name_free(&name); + if (ret) + goto out; + + ret = hx509_env_add(context, &envcert, "issuer", buf); + hx509_xfree(buf); + if (ret) + goto out; + + /* eku */ + + ret = _hx509_cert_get_eku(context, cert, &eku); + if (ret == HX509_EXTENSION_NOT_FOUND) + ; + else if (ret != 0) + goto out; + else { + size_t i; + hx509_env enveku = NULL; + + for (i = 0; i < eku.len; i++) { + + ret = der_print_heim_oid(&eku.val[i], '.', &buf); + if (ret) { + free_ExtKeyUsage(&eku); + hx509_env_free(&enveku); + goto out; + } + ret = hx509_env_add(context, &enveku, buf, "oid-name-here"); + free(buf); + if (ret) { + free_ExtKeyUsage(&eku); + hx509_env_free(&enveku); + goto out; + } + } + free_ExtKeyUsage(&eku); + + ret = hx509_env_add_binding(context, &envcert, "eku", enveku); + if (ret) { + hx509_env_free(&enveku); + goto out; + } + } + + { + Certificate *c = _hx509_get_cert(cert); + heim_octet_string os, sig; + hx509_env envhash = NULL; + + os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_create_signature(context, + NULL, + hx509_signature_sha1(), + &os, + NULL, + &sig); + if (ret != 0) + goto out; + + ret = hex_encode(sig.data, sig.length, &buf); + der_free_octet_string(&sig); + if (ret < 0) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Out of memory"); + goto out; + } + + ret = hx509_env_add(context, &envhash, "sha1", buf); + free(buf); + if (ret) + goto out; + + ret = hx509_env_add_binding(context, &envcert, "hash", envhash); + if (ret) { + hx509_env_free(&envhash); + goto out; + } + } + + ret = hx509_env_add_binding(context, env, "certificate", envcert); + if (ret) + goto out; + + return 0; + +out: + hx509_env_free(&envcert); + return ret; +} + +/** + * Print a simple representation of a certificate + * + * @param context A hx509 context, can be NULL + * @param cert certificate to print + * @param out the stdio output stream, if NULL, stdout is used + * + * @return An hx509 error code + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out) +{ + hx509_name name; + char *str; + int ret; + + if (out == NULL) + out = stderr; + + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + return ret; + hx509_name_to_string(name, &str); + hx509_name_free(&name); + fprintf(out, " issuer: \"%s\"\n", str); + free(str); + + ret = hx509_cert_get_subject(cert, &name); + if (ret) + return ret; + hx509_name_to_string(name, &str); + hx509_name_free(&name); + fprintf(out, " subject: \"%s\"\n", str); + free(str); + + { + heim_integer serialNumber; + + ret = hx509_cert_get_serialnumber(cert, &serialNumber); + if (ret) + return ret; + ret = der_print_hex_heim_integer(&serialNumber, &str); + if (ret) + return ret; + der_free_heim_integer(&serialNumber); + fprintf(out, " serial: %s\n", str); + free(str); + } + + fprintf(out, " keyusage: "); + ret = hx509_cert_keyusage_print(context, cert, &str); + if (ret == 0) { + fprintf(out, "%s\n", str); + free(str); + } else + fprintf(out, "no"); + + return 0; +} diff --git a/third_party/heimdal/lib/hx509/char_map.h b/third_party/heimdal/lib/hx509/char_map.h new file mode 100644 index 0000000..8a3026c --- /dev/null +++ b/third_party/heimdal/lib/hx509/char_map.h @@ -0,0 +1,45 @@ +#define Q_CONTROL_CHAR 1 +#define Q_PRINTABLE 2 +#define Q_RFC2253_QUOTE_FIRST 4 +#define Q_RFC2253_QUOTE_LAST 8 +#define Q_RFC2253_QUOTE 16 +#define Q_RFC2253_HEX 32 + +#define Q_RFC2253 (Q_RFC2253_QUOTE_FIRST|Q_RFC2253_QUOTE_LAST|Q_RFC2253_QUOTE|Q_RFC2253_HEX) + + + +unsigned char char_map[] = { + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x06 , 0x00 , 0x00 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , + 0x00 , 0x00 , 0x00 , 0x12 , 0x12 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x10 , 0x10 , 0x12 , 0x10 , 0x02 , + 0x00 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , + 0x00 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , + 0x02 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , + 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 , 0x21 +}; diff --git a/third_party/heimdal/lib/hx509/cms.c b/third_party/heimdal/lib/hx509/cms.c new file mode 100644 index 0000000..1723f3a --- /dev/null +++ b/third_party/heimdal/lib/hx509/cms.c @@ -0,0 +1,1719 @@ +/* + * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_cms CMS/PKCS7 message functions. + * + * CMS is defined in RFC 3369 and is an continuation of the RSA Labs + * standard PKCS7. The basic messages in CMS is + * + * - SignedData + * Data signed with private key (RSA, DSA, ECDSA) or secret + * (symmetric) key + * - EnvelopedData + * Data encrypted with private key (RSA) + * - EncryptedData + * Data encrypted with secret (symmetric) key. + * - ContentInfo + * Wrapper structure including type and data. + * + * + * See the library functions here: @ref hx509_cms + */ + +#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) +#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) + +/** + * Wrap data and oid in a ContentInfo and encode it. + * + * @param oid type of the content. + * @param buf data to be wrapped. If a NULL pointer is passed in, the + * optional content field in the ContentInfo is not going be filled + * in. + * @param res the encoded buffer, the result should be freed with + * der_free_octet_string(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_wrap_ContentInfo(const heim_oid *oid, + const heim_octet_string *buf, + heim_octet_string *res) +{ + ContentInfo ci; + size_t size; + int ret; + + memset(res, 0, sizeof(*res)); + memset(&ci, 0, sizeof(ci)); + + ret = der_copy_oid(oid, &ci.contentType); + if (ret) + return ret; + if (buf) { + ALLOC(ci.content, 1); + if (ci.content == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + ci.content->data = malloc(buf->length); + if (ci.content->data == NULL) { + free_ContentInfo(&ci); + return ENOMEM; + } + memcpy(ci.content->data, buf->data, buf->length); + ci.content->length = buf->length; + } + + ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret); + free_ContentInfo(&ci); + if (ret) + return ret; + if (res->length != size) + _hx509_abort("internal ASN.1 encoder error"); + + return 0; +} + +/** + * Decode an ContentInfo and unwrap data and oid it. + * + * @param in the encoded buffer. + * @param oid type of the content. + * @param out data to be wrapped. + * @param have_data since the data is optional, this flag shows the + * difference between no data and the zero length data. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_unwrap_ContentInfo(const heim_octet_string *in, + heim_oid *oid, + heim_octet_string *out, + int *have_data) +{ + ContentInfo ci; + size_t size; + int ret; + + memset(oid, 0, sizeof(*oid)); + memset(out, 0, sizeof(*out)); + + ret = decode_ContentInfo(in->data, in->length, &ci, &size); + if (ret) + return ret; + + ret = der_copy_oid(&ci.contentType, oid); + if (ret) { + free_ContentInfo(&ci); + return ret; + } + if (ci.content) { + ret = der_copy_octet_string(ci.content, out); + if (ret) { + der_free_oid(oid); + free_ContentInfo(&ci); + return ret; + } + } else + memset(out, 0, sizeof(*out)); + + if (have_data) + *have_data = (ci.content != NULL) ? 1 : 0; + + free_ContentInfo(&ci); + + return 0; +} + +#define CMS_ID_SKI 0 +#define CMS_ID_NAME 1 + +static int +fill_CMSIdentifier(const hx509_cert cert, + int type, + CMSIdentifier *id) +{ + int ret; + + switch (type) { + case CMS_ID_SKI: + id->element = choice_CMSIdentifier_subjectKeyIdentifier; + ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert), + &id->u.subjectKeyIdentifier); + if (ret == 0) + break; + HEIM_FALLTHROUGH; + case CMS_ID_NAME: { + hx509_name name; + + id->element = choice_CMSIdentifier_issuerAndSerialNumber; + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + return ret; + ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer); + hx509_name_free(&name); + if (ret) + return ret; + + ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber); + break; + } + default: + _hx509_abort("CMS fill identifier with unknown type"); + } + return ret; +} + +static int +unparse_CMSIdentifier(hx509_context context, + CMSIdentifier *id, + char **str) +{ + int ret = -1; + + *str = NULL; + switch (id->element) { + case choice_CMSIdentifier_issuerAndSerialNumber: { + IssuerAndSerialNumber *iasn; + char *serial, *name; + + iasn = &id->u.issuerAndSerialNumber; + + ret = _hx509_Name_to_string(&iasn->issuer, &name); + if(ret) + return ret; + ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial); + if (ret) { + free(name); + return ret; + } + ret = asprintf(str, "certificate issued by %s with serial number %s", + name, serial); + free(name); + free(serial); + break; + } + case choice_CMSIdentifier_subjectKeyIdentifier: { + KeyIdentifier *ki = &id->u.subjectKeyIdentifier; + char *keyid; + ssize_t len; + + len = hex_encode(ki->data, ki->length, &keyid); + if (len < 0) + return ENOMEM; + + if (len) + ret = asprintf(str, "certificate with id %s", keyid); + else + ret = asprintf(str, "certificate"); + free(keyid); + break; + } + default: + ret = asprintf(str, "certificate has unknown CMSidentifier type"); + break; + } + /* + * In the following if, we check ret and *str which should be returned/set + * by asprintf(3) in every branch of the switch statement. + */ + if (ret == -1 || *str == NULL) + return ENOMEM; + return 0; +} + +static int +find_CMSIdentifier(hx509_context context, + CMSIdentifier *client, + hx509_certs certs, + time_t time_now, + hx509_cert *signer_cert, + int match) +{ + hx509_query q; + hx509_cert cert; + Certificate c; + int ret; + + memset(&c, 0, sizeof(c)); + _hx509_query_clear(&q); + + *signer_cert = NULL; + + switch (client->element) { + case choice_CMSIdentifier_issuerAndSerialNumber: + q.serial = &client->u.issuerAndSerialNumber.serialNumber; + q.issuer_name = &client->u.issuerAndSerialNumber.issuer; + q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; + break; + case choice_CMSIdentifier_subjectKeyIdentifier: + q.subject_id = &client->u.subjectKeyIdentifier; + q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; + break; + default: + hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "unknown CMS identifier element"); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } + + q.match |= match; + + q.match |= HX509_QUERY_MATCH_TIME; + if (time_now) + q.timenow = time_now; + else + q.timenow = time(NULL); + + ret = hx509_certs_find(context, certs, &q, &cert); + if (ret == HX509_CERT_NOT_FOUND) { + char *str; + + ret = unparse_CMSIdentifier(context, client, &str); + if (ret == 0) { + hx509_set_error_string(context, 0, + HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "Failed to find %s", str); + } else + hx509_clear_error_string(context); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } else if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, + HX509_CMS_NO_RECIPIENT_CERTIFICATE, + "Failed to find CMS id in cert store"); + return HX509_CMS_NO_RECIPIENT_CERTIFICATE; + } + + *signer_cert = cert; + + return 0; +} + +/** + * Decode and unencrypt EnvelopedData. + * + * Extract data and parameters from the EnvelopedData. Also + * supports using detached EnvelopedData. + * + * @param context A hx509 context. + * @param certs Certificate that can decrypt the EnvelopedData + * encryption key. + * @param flags HX509_CMS_UE flags to control the behavior. + * @param data pointer the structure the contains the DER/BER encoded + * EnvelopedData stucture. + * @param length length of the data that data point to. + * @param encryptedContent in case of detached signature, this + * contains the actual encrypted data, otherwise it should be NULL. + * @param time_now set the current time, if zero the library uses now as the date. + * @param contentType output type oid, should be freed with der_free_oid(). + * @param content the data, free with der_free_octet_string(). + * + * @return an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_unenvelope(hx509_context context, + hx509_certs certs, + int flags, + const void *data, + size_t length, + const heim_octet_string *encryptedContent, + time_t time_now, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string key; + EnvelopedData ed; + hx509_cert cert; + AlgorithmIdentifier *ai; + const heim_octet_string *enccontent; + heim_octet_string *params, params_data; + heim_octet_string ivec; + size_t size; + int ret, matched = 0, findflags = 0; + size_t i; + + + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(&ivec, 0, sizeof(ivec)); + memset(content, 0, sizeof(*content)); + memset(contentType, 0, sizeof(*contentType)); + + if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0) + findflags |= HX509_QUERY_KU_ENCIPHERMENT; + + ret = decode_EnvelopedData(data, length, &ed, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EnvelopedData"); + return ret; + } + + if (ed.recipientInfos.len == 0) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, 0, ret, + "No recipient info in enveloped data"); + goto out; + } + + enccontent = ed.encryptedContentInfo.encryptedContent; + if (enccontent == NULL) { + if (encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Content missing from encrypted data"); + goto out; + } + enccontent = encryptedContent; + } else if (encryptedContent != NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Both internal and external encrypted data"); + goto out; + } + + cert = NULL; + for (i = 0; i < ed.recipientInfos.len; i++) { + KeyTransRecipientInfo *ri; + char *str; + int ret2; + + ri = &ed.recipientInfos.val[i]; + + ret = find_CMSIdentifier(context, &ri->rid, certs, + time_now, &cert, + HX509_QUERY_PRIVATE_KEY|findflags); + if (ret) + continue; + + matched = 1; /* found a matching certificate, let decrypt */ + + ret = _hx509_cert_private_decrypt(context, + &ri->encryptedKey, + &ri->keyEncryptionAlgorithm.algorithm, + cert, &key); + + hx509_cert_free(cert); + if (ret == 0) + break; /* successfully decrypted cert */ + cert = NULL; + ret2 = unparse_CMSIdentifier(context, &ri->rid, &str); + if (ret2 == 0) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to decrypt with %s", str); + free(str); + } + } + + if (!matched) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, 0, ret, + "No private key matched any certificate"); + goto out; + } + + if (cert == NULL) { + ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE; + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "No private key decrypted the transfer key"); + goto out; + } + + ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy EnvelopedData content oid"); + goto out; + } + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters) { + params_data.data = ai->parameters->data; + params_data.length = ai->parameters->length; + params = ¶ms_data; + } else + params = NULL; + + { + hx509_crypto crypto; + + ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto); + if (ret) + goto out; + + if (flags & HX509_CMS_UE_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + + if (params) { + ret = hx509_crypto_set_params(context, crypto, params, &ivec); + if (ret) { + hx509_crypto_destroy(crypto); + goto out; + } + } + + ret = hx509_crypto_set_key_data(crypto, key.data, key.length); + if (ret) { + hx509_crypto_destroy(crypto); + hx509_set_error_string(context, 0, ret, + "Failed to set key for decryption " + "of EnvelopedData"); + goto out; + } + + ret = hx509_crypto_decrypt(crypto, + enccontent->data, + enccontent->length, + ivec.length ? &ivec : NULL, + content); + hx509_crypto_destroy(crypto); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decrypt EnvelopedData"); + goto out; + } + } + +out: + + free_EnvelopedData(&ed); + der_free_octet_string(&key); + if (ivec.length) + der_free_octet_string(&ivec); + if (ret) { + der_free_oid(contentType); + der_free_octet_string(content); + } + + return ret; +} + +/** + * Encrypt and encode EnvelopedData. + * + * Encrypt and encode EnvelopedData. The data is encrypted with a + * random key and the the random key is encrypted with the + * certificate's private key. This limits what private key type can be + * used to RSA. + * + * @param context A hx509 context. + * @param flags flags to control the behavior. + * - HX509_CMS_EV_NO_KU_CHECK - Don't check KU on certificate + * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crypto + * - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number + * @param cert Certificate to encrypt the EnvelopedData encryption key + * with. + * @param data pointer the data to encrypt. + * @param length length of the data that data point to. + * @param encryption_type Encryption cipher to use for the bulk data, + * use NULL to get default. + * @param contentType type of the data that is encrypted + * @param content the output of the function, + * free with der_free_octet_string(). + * + * @return an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_envelope_1(hx509_context context, + int flags, + hx509_cert cert, + const void *data, + size_t length, + const heim_oid *encryption_type, + const heim_oid *contentType, + heim_octet_string *content) +{ + KeyTransRecipientInfo *ri; + heim_octet_string ivec; + heim_octet_string key; + hx509_crypto crypto = NULL; + int ret, cmsidflag; + EnvelopedData ed; + size_t size; + + memset(&ivec, 0, sizeof(ivec)); + memset(&key, 0, sizeof(key)); + memset(&ed, 0, sizeof(ed)); + memset(content, 0, sizeof(*content)); + + if (encryption_type == NULL) + encryption_type = &asn1_oid_id_aes_256_cbc; + + if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) { + ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); + if (ret) + goto out; + } + + ret = hx509_crypto_init(context, NULL, encryption_type, &crypto); + if (ret) + goto out; + + if (flags & HX509_CMS_EV_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + + ret = hx509_crypto_set_random_key(crypto, &key); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Create random key for EnvelopedData content"); + goto out; + } + + ret = hx509_crypto_random_iv(crypto, &ivec); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to create a random iv"); + goto out; + } + + ret = hx509_crypto_encrypt(crypto, + data, + length, + &ivec, + &ed.encryptedContentInfo.encryptedContent); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to encrypt EnvelopedData content"); + goto out; + } + + { + AlgorithmIdentifier *enc_alg; + enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + ret = der_copy_oid(encryption_type, &enc_alg->algorithm); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to set crypto oid " + "for EnvelopedData"); + goto out; + } + ALLOC(enc_alg->parameters, 1); + if (enc_alg->parameters == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Failed to allocate crypto parameters " + "for EnvelopedData"); + goto out; + } + + ret = hx509_crypto_get_params(context, + crypto, + &ivec, + enc_alg->parameters); + if (ret) { + goto out; + } + } + + ALLOC_SEQ(&ed.recipientInfos, 1); + if (ed.recipientInfos.val == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, + "Failed to allocate recipients info " + "for EnvelopedData"); + goto out; + } + + ri = &ed.recipientInfos.val[0]; + + if (flags & HX509_CMS_EV_ID_NAME) { + ri->version = 0; + cmsidflag = CMS_ID_NAME; + } else { + ri->version = 2; + cmsidflag = CMS_ID_SKI; + } + + ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to set CMS identifier info " + "for EnvelopedData"); + goto out; + } + + ret = hx509_cert_public_encrypt(context, + &key, cert, + &ri->keyEncryptionAlgorithm.algorithm, + &ri->encryptedKey); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to encrypt transport key for " + "EnvelopedData"); + goto out; + } + + /* + * + */ + + ed.version = 0; + ed.originatorInfo = NULL; + + ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy content oid for " + "EnvelopedData"); + goto out; + } + + ed.unprotectedAttrs = NULL; + + ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length, + &ed, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to encode EnvelopedData"); + goto out; + } + if (size != content->length) + _hx509_abort("internal ASN.1 encoder error"); + +out: + if (crypto) + hx509_crypto_destroy(crypto); + if (ret) + der_free_octet_string(content); + der_free_octet_string(&key); + der_free_octet_string(&ivec); + free_EnvelopedData(&ed); + + return ret; +} + +static int +any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs) +{ + int ret; + size_t i; + + if (sd->certificates == NULL) + return 0; + + for (i = 0; i < sd->certificates->len; i++) { + heim_error_t error; + hx509_cert c; + + c = hx509_cert_init_data(context, + sd->certificates->val[i].data, + sd->certificates->val[i].length, + &error); + if (c == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + return ret; + } + ret = hx509_certs_add(context, certs, c); + hx509_cert_free(c); + if (ret) + return ret; + } + + return 0; +} + +static const Attribute * +find_attribute(const CMSAttributes *attr, const heim_oid *oid) +{ + size_t i; + for (i = 0; i < attr->len; i++) + if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0) + return &attr->val[i]; + return NULL; +} + +/** + * Decode SignedData and verify that the signature is correct. + * + * @param context A hx509 context. + * @param ctx a hx509 verify context. + * @param flags to control the behavior of the function. + * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage + * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch + * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below. + * @param data pointer to CMS SignedData encoded data. + * @param length length of the data that data points to. + * @param signedContent external data used for signature. + * @param pool certificate pool to build certificates paths. + * @param contentType free with der_free_oid(). + * @param content the output of the function, free with + * der_free_octet_string(). + * @param signer_certs list of the cerficates used to sign this + * request, free with hx509_certs_free(). + * + * @return an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_verify_signed(hx509_context context, + hx509_verify_ctx ctx, + unsigned int flags, + const void *data, + size_t length, + const heim_octet_string *signedContent, + hx509_certs pool, + heim_oid *contentType, + heim_octet_string *content, + hx509_certs *signer_certs) +{ + unsigned int verify_flags; + + return hx509_cms_verify_signed_ext(context, + ctx, + flags, + data, + length, + signedContent, + pool, + contentType, + content, + signer_certs, + &verify_flags); +} + +/** + * Decode SignedData and verify that the signature is correct. + * + * @param context A hx509 context. + * @param ctx a hx509 verify context. + * @param flags to control the behaivor of the function. + * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage + * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch + * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below. + * @param data pointer to CMS SignedData encoded data. + * @param length length of the data that data points to. + * @param signedContent external data used for signature. + * @param pool certificate pool to build certificates paths. + * @param contentType free with der_free_oid(). + * @param content the output of the function, free with + * der_free_octet_string(). + * @param signer_certs list of the cerficates used to sign this + * request, free with hx509_certs_free(). + * @param verify_flags flags indicating whether the certificate + * was verified or not + * + * @return an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_verify_signed_ext(hx509_context context, + hx509_verify_ctx ctx, + unsigned int flags, + const void *data, + size_t length, + const heim_octet_string *signedContent, + hx509_certs pool, + heim_oid *contentType, + heim_octet_string *content, + hx509_certs *signer_certs, + unsigned int *verify_flags) +{ + SignerInfo *signer_info; + hx509_cert cert = NULL; + hx509_certs certs = NULL; + SignedData sd; + size_t size; + int ret, found_valid_sig; + size_t i; + + *signer_certs = NULL; + *verify_flags = 0; + + content->data = NULL; + content->length = 0; + contentType->length = 0; + contentType->components = NULL; + + memset(&sd, 0, sizeof(sd)); + + ret = decode_SignedData(data, length, &sd, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode SignedData"); + goto out; + } + + if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "No content data in SignedData"); + goto out; + } + if (sd.encapContentInfo.eContent && signedContent) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Both external and internal SignedData"); + goto out; + } + + if (sd.encapContentInfo.eContent) + ret = der_copy_octet_string(sd.encapContentInfo.eContent, content); + else + ret = der_copy_octet_string(signedContent, content); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } + + ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", + 0, NULL, &certs); + if (ret) + goto out; + + ret = hx509_certs_init(context, "MEMORY:cms-signer-certs", + 0, NULL, signer_certs); + if (ret) + goto out; + + /* XXX Check CMS version */ + + ret = any_to_certs(context, &sd, certs); + if (ret) + goto out; + + if (pool) { + ret = hx509_certs_merge(context, certs, pool); + if (ret) + goto out; + } + + for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { + heim_octet_string signed_data = { 0, NULL }; + const heim_oid *match_oid; + heim_oid decode_oid; + + signer_info = &sd.signerInfos.val[i]; + match_oid = NULL; + + if (signer_info->signature.length == 0) { + ret = HX509_CMS_MISSING_SIGNER_DATA; + hx509_set_error_string(context, 0, ret, + "SignerInfo %zu in SignedData " + "missing signature", i); + continue; + } + + ret = find_CMSIdentifier(context, &signer_info->sid, certs, + _hx509_verify_get_time(ctx), &cert, + HX509_QUERY_KU_DIGITALSIGNATURE); + if (ret) { + /** + * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal + * search for matching certificates by not considering + * KeyUsage bits on the certificates. + */ + if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0) + continue; + + ret = find_CMSIdentifier(context, &signer_info->sid, certs, + _hx509_verify_get_time(ctx), &cert, + 0); + if (ret) + continue; + + } + + if (signer_info->signedAttrs) { + const Attribute *attr; + + CMSAttributes sa; + heim_octet_string os; + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + /* verify that signature exists */ + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest); + if (attr == NULL) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + hx509_set_error_string(context, 0, ret, + "SignerInfo has signed attributes " + "but messageDigest (signature) " + "is missing"); + goto next_signature; + } + if (attr->value.len != 1) { + ret = HX509_CRYPTO_SIGNATURE_MISSING; + hx509_set_error_string(context, 0, ret, + "SignerInfo has more than one " + "messageDigest (signature)"); + goto next_signature; + } + + ret = decode_MessageDigest(attr->value.val[0].data, + attr->value.val[0].length, + &os, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode " + "messageDigest (signature)"); + goto next_signature; + } + + ret = _hx509_verify_signature(context, + NULL, + &signer_info->digestAlgorithm, + content, + &os); + der_free_octet_string(&os); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify messageDigest"); + goto next_signature; + } + + /* + * Fetch content oid inside signedAttrs or set it to + * id-pkcs7-data. + */ + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType); + if (attr == NULL) { + match_oid = &asn1_oid_id_pkcs7_data; + } else { + if (attr->value.len != 1) { + ret = HX509_CMS_DATA_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, + "More than one oid in signedAttrs"); + goto next_signature; + + } + ret = decode_ContentType(attr->value.val[0].data, + attr->value.val[0].length, + &decode_oid, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode " + "oid in signedAttrs"); + goto next_signature; + } + match_oid = &decode_oid; + } + + ASN1_MALLOC_ENCODE(CMSAttributes, + signed_data.data, + signed_data.length, + &sa, + &size, ret); + if (ret) { + if (match_oid == &decode_oid) + der_free_oid(&decode_oid); + hx509_clear_error_string(context); + goto next_signature; + } + if (size != signed_data.length) + _hx509_abort("internal ASN.1 encoder error"); + + } else { + signed_data.data = content->data; + signed_data.length = content->length; + match_oid = &asn1_oid_id_pkcs7_data; + } + + /** + * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow + * encapContentInfo mismatch with the oid in signedAttributes + * (or if no signedAttributes where use, pkcs7-data oid). + * This is only needed to work with broken CMS implementations + * that doesn't follow CMS signedAttributes rules. + */ + + if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) && + (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) { + ret = HX509_CMS_DATA_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, + "Oid in message mismatch from the expected"); + } + if (match_oid == &decode_oid) + der_free_oid(&decode_oid); + + if (ret == 0) { + ret = hx509_verify_signature(context, + cert, + &signer_info->signatureAlgorithm, + &signed_data, + &signer_info->signature); + if (ret) + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify signature in " + "CMS SignedData"); + } + if (signed_data.data != NULL && content->data != signed_data.data) { + free(signed_data.data); + signed_data.data = NULL; + } + if (ret) + goto next_signature; + + /** + * If HX509_CMS_VS_NO_VALIDATE flags is set, return the signer + * certificate unconditionally but do not set HX509_CMS_VSE_VALIDATED. + */ + ret = hx509_verify_path(context, ctx, cert, certs); + if (ret == 0 || (flags & HX509_CMS_VS_NO_VALIDATE)) { + if (ret == 0) + *verify_flags |= HX509_CMS_VSE_VALIDATED; + + ret = hx509_certs_add(context, *signer_certs, cert); + if (ret == 0) + found_valid_sig++; + } + + next_signature: + if (cert) + hx509_cert_free(cert); + cert = NULL; + } + /** + * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty + * SignerInfo (no signatures). If SignedData has no signatures, + * the function will return 0 with signer_certs set to NULL. Zero + * signers is allowed by the standard, but since it's only useful + * in corner cases, it's made into a flag that the caller has to + * turn on. + */ + if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) { + if (*signer_certs) + hx509_certs_free(signer_certs); + } else if (found_valid_sig == 0) { + if (ret == 0) { + ret = HX509_CMS_SIGNER_NOT_FOUND; + hx509_set_error_string(context, 0, ret, + "No signers were found"); + } + goto out; + } + + ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + +out: + free_SignedData(&sd); + if (certs) + hx509_certs_free(&certs); + if (ret) { + if (content->data) + der_free_octet_string(content); + if (*signer_certs) + hx509_certs_free(signer_certs); + der_free_oid(contentType); + der_free_octet_string(content); + } + + return ret; +} + +static int +add_one_attribute(Attribute **attr, + unsigned int *len, + const heim_oid *oid, + heim_octet_string *data) +{ + void *d; + int ret; + + d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1)); + if (d == NULL) + return ENOMEM; + (*attr) = d; + + ret = der_copy_oid(oid, &(*attr)[*len].type); + if (ret) + return ret; + + ALLOC_SEQ(&(*attr)[*len].value, 1); + if ((*attr)[*len].value.val == NULL) { + der_free_oid(&(*attr)[*len].type); + return ENOMEM; + } + + (*attr)[*len].value.val[0].data = data->data; + (*attr)[*len].value.val[0].length = data->length; + + *len += 1; + + return 0; +} + +/** + * Sign and encode a SignedData structure. + * + * @param context A hx509 context. + * @param flags + * @param eContentType the type of the data. + * @param data data to sign + * @param length length of the data that data points to. + * @param digest_alg digest algorithm to use, use NULL to get the + * default or the peer determined algorithm. + * @param cert certificate to use for signing the data. + * @param peer info about the peer the message to send the message to, + * like what digest algorithm to use. + * @param anchors trust anchors that the client will use, used to + * polulate the certificates included in the message + * @param pool certificates to use in try to build the path to the + * trust anchors. + * @param signed_data the output of the function, free with + * der_free_octet_string(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_cms + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_create_signed_1(hx509_context context, + int flags, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_cert cert, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + hx509_certs certs; + int ret = 0; + + signed_data->data = NULL; + signed_data->length = 0; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); + if (ret) + return ret; + ret = hx509_certs_add(context, certs, cert); + if (ret) + goto out; + + ret = hx509_cms_create_signed(context, flags, eContentType, data, length, + digest_alg, certs, peer, anchors, pool, + signed_data); + + out: + hx509_certs_free(&certs); + return ret; +} + +struct sigctx { + SignedData sd; + const AlgorithmIdentifier *digest_alg; + const heim_oid *eContentType; + heim_octet_string content; + hx509_peer_info peer; + int cmsidflag; + int leafonly; + hx509_certs certs; + hx509_certs anchors; + hx509_certs pool; +}; + +static int HX509_LIB_CALL +sig_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + heim_octet_string buf, sigdata = { 0, NULL }; + SignerInfo *signer_info = NULL; + AlgorithmIdentifier digest; + size_t size; + void *ptr; + int ret; + SignedData *sd = &sigctx->sd; + hx509_path path; + + memset(&digest, 0, sizeof(digest)); + memset(&path, 0, sizeof(path)); + + if (_hx509_cert_private_key(cert) == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private key missing for signing"); + return HX509_PRIVATE_KEY_MISSING; + } + + if (sigctx->digest_alg) { + ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); + if (ret) + hx509_clear_error_string(context); + } else { + ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, + _hx509_cert_private_key(cert), + sigctx->peer, &digest); + } + if (ret) + goto out; + + /* + * Allocate on more signerInfo and do the signature processing + */ + + ptr = realloc(sd->signerInfos.val, + (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); + if (ptr == NULL) { + ret = ENOMEM; + goto out; + } + sd->signerInfos.val = ptr; + + signer_info = &sd->signerInfos.val[sd->signerInfos.len]; + + memset(signer_info, 0, sizeof(*signer_info)); + + signer_info->version = 1; + + ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + signer_info->signedAttrs = NULL; + signer_info->unsignedAttrs = NULL; + + ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + /* + * If it isn't pkcs7-data send signedAttributes + */ + + if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) { + CMSAttributes sa; + heim_octet_string sig; + + ALLOC(signer_info->signedAttrs, 1); + if (signer_info->signedAttrs == NULL) { + ret = ENOMEM; + goto out; + } + + ret = _hx509_create_signature(context, + NULL, + &digest, + &sigctx->content, + NULL, + &sig); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(MessageDigest, + buf.data, + buf.length, + &sig, + &size, + ret); + der_free_octet_string(&sig); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (size != buf.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + &asn1_oid_id_pkcs9_messageDigest, + &buf); + if (ret) { + free(buf.data); + hx509_clear_error_string(context); + goto out; + } + + + ASN1_MALLOC_ENCODE(ContentType, + buf.data, + buf.length, + sigctx->eContentType, + &size, + ret); + if (ret) + goto out; + if (size != buf.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = add_one_attribute(&signer_info->signedAttrs->val, + &signer_info->signedAttrs->len, + &asn1_oid_id_pkcs9_contentType, + &buf); + if (ret) { + free(buf.data); + hx509_clear_error_string(context); + goto out; + } + + sa.val = signer_info->signedAttrs->val; + sa.len = signer_info->signedAttrs->len; + + ASN1_MALLOC_ENCODE(CMSAttributes, + sigdata.data, + sigdata.length, + &sa, + &size, + ret); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (size != sigdata.length) + _hx509_abort("internal ASN.1 encoder error"); + } else { + sigdata.data = sigctx->content.data; + sigdata.length = sigctx->content.length; + } + + { + AlgorithmIdentifier sigalg; + + ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, + _hx509_cert_private_key(cert), sigctx->peer, + &sigalg); + if (ret) + goto out; + + ret = _hx509_create_signature(context, + _hx509_cert_private_key(cert), + &sigalg, + &sigdata, + &signer_info->signatureAlgorithm, + &signer_info->signature); + free_AlgorithmIdentifier(&sigalg); + if (ret) + goto out; + } + + sigctx->sd.signerInfos.len++; + signer_info = NULL; + + /* + * Provide best effort path + */ + if (sigctx->certs) { + unsigned int i; + + if (sigctx->pool && sigctx->leafonly == 0) { + _hx509_calculate_path(context, + HX509_CALCULATE_PATH_NO_ANCHOR, + time(NULL), + sigctx->anchors, + 0, + cert, + sigctx->pool, + &path); + } else + _hx509_path_append(context, &path, cert); + + for (i = 0; i < path.len; i++) { + /* XXX remove dups */ + ret = hx509_certs_add(context, sigctx->certs, path.val[i]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + + out: + if (signer_info) + free_SignerInfo(signer_info); + if (sigdata.data != sigctx->content.data) + der_free_octet_string(&sigdata); + _hx509_path_free(&path); + free_AlgorithmIdentifier(&digest); + + return ret; +} + +static int HX509_LIB_CALL +cert_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + const unsigned int i = sigctx->sd.certificates->len; + void *ptr; + int ret; + + ptr = realloc(sigctx->sd.certificates->val, + (i + 1) * sizeof(sigctx->sd.certificates->val[0])); + if (ptr == NULL) + return ENOMEM; + sigctx->sd.certificates->val = ptr; + + ret = hx509_cert_binary(context, cert, + &sigctx->sd.certificates->val[i]); + if (ret == 0) + sigctx->sd.certificates->len++; + + return ret; +} + +static int +cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q) +{ + return der_heim_oid_cmp(&p->algorithm, &q->algorithm); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_create_signed(hx509_context context, + int flags, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_certs certs, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + unsigned int i, j; + int ret; + size_t size; + struct sigctx sigctx; + + memset(&sigctx, 0, sizeof(sigctx)); + + if (eContentType == NULL) + eContentType = &asn1_oid_id_pkcs7_data; + + sigctx.digest_alg = digest_alg; + sigctx.content.data = rk_UNCONST(data); + sigctx.content.length = length; + sigctx.eContentType = eContentType; + sigctx.peer = peer; + /** + * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name + * and serial number if possible. Otherwise subject key identifier + * will preferred. + */ + if (flags & HX509_CMS_SIGNATURE_ID_NAME) + sigctx.cmsidflag = CMS_ID_NAME; + else + sigctx.cmsidflag = CMS_ID_SKI; + + /** + * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf + * certificates to be added to the SignedData. + */ + sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0; + + /** + * Use HX509_CMS_NO_CERTS to make the SignedData contain no + * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY. + */ + + if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) { + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); + if (ret) + return ret; + } + + sigctx.anchors = anchors; + sigctx.pool = pool; + + sigctx.sd.version = cMSVersion_v3; + + ret = der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); + if (ret) + goto out; + + /** + * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. + */ + if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) { + ALLOC(sigctx.sd.encapContentInfo.eContent, 1); + if (sigctx.sd.encapContentInfo.eContent == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + sigctx.sd.encapContentInfo.eContent->data = malloc(length); + if (sigctx.sd.encapContentInfo.eContent->data == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); + sigctx.sd.encapContentInfo.eContent->length = length; + } + + /** + * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no + * signatures). + */ + if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) { + ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx); + if (ret) + goto out; + } + + if (sigctx.sd.signerInfos.len) { + + /* + * For each signerInfo, collect all different digest types. + */ + for (i = 0; i < sigctx.sd.signerInfos.len; i++) { + AlgorithmIdentifier *di = + &sigctx.sd.signerInfos.val[i].digestAlgorithm; + + for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++) + if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0) + break; + if (j == sigctx.sd.digestAlgorithms.len) { + ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + } + + /* + * Add certs we think are needed, build as part of sig_process + */ + if (sigctx.certs) { + ALLOC(sigctx.sd.certificates, 1); + if (sigctx.sd.certificates == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx); + if (ret) + goto out; + } + + ASN1_MALLOC_ENCODE(SignedData, + signed_data->data, signed_data->length, + &sigctx.sd, &size, ret); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + if (signed_data->length != size) + _hx509_abort("internal ASN.1 encoder error"); + +out: + hx509_certs_free(&sigctx.certs); + free_SignedData(&sigctx.sd); + + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cms_decrypt_encrypted(hx509_context context, + hx509_lock lock, + const void *data, + size_t length, + heim_oid *contentType, + heim_octet_string *content) +{ + heim_octet_string cont; + CMSEncryptedData ed; + AlgorithmIdentifier *ai; + int ret; + + memset(content, 0, sizeof(*content)); + memset(&cont, 0, sizeof(cont)); + + ret = decode_CMSEncryptedData(data, length, &ed, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode CMSEncryptedData"); + return ret; + } + + if (ed.encryptedContentInfo.encryptedContent == NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "No content in EncryptedData"); + goto out; + } + + ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm; + if (ai->parameters == NULL) { + ret = HX509_ALG_NOT_SUPP; + hx509_clear_error_string(context); + goto out; + } + + ret = _hx509_pbe_decrypt(context, + lock, + ai, + ed.encryptedContentInfo.encryptedContent, + &cont); + if (ret) + goto out; + + *content = cont; + +out: + if (ret) { + if (cont.data) + free(cont.data); + } + free_CMSEncryptedData(&ed); + return ret; +} diff --git a/third_party/heimdal/lib/hx509/collector.c b/third_party/heimdal/lib/hx509/collector.c new file mode 100644 index 0000000..f1423ac --- /dev/null +++ b/third_party/heimdal/lib/hx509/collector.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +struct private_key { + AlgorithmIdentifier alg; + hx509_private_key private_key; + heim_octet_string localKeyId; +}; + +struct hx509_collector { + hx509_lock lock; + hx509_certs unenvelop_certs; + hx509_certs certs; + struct { + struct private_key **data; + size_t len; + } val; +}; + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector) +{ + struct hx509_collector *c; + int ret; + + *collector = NULL; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + c->lock = lock; + + ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert", + 0,NULL, &c->unenvelop_certs); + if (ret) { + free(c); + return ret; + } + c->val.data = NULL; + c->val.len = 0; + ret = hx509_certs_init(context, "MEMORY:collector-tmp-store", + 0, NULL, &c->certs); + if (ret) { + hx509_certs_free(&c->unenvelop_certs); + free(c); + return ret; + } + + *collector = c; + return 0; +} + +HX509_LIB_FUNCTION hx509_lock HX509_LIB_CALL +_hx509_collector_get_lock(struct hx509_collector *c) +{ + return c->lock; +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_collector_certs_add(hx509_context context, + struct hx509_collector *c, + hx509_cert cert) +{ + return hx509_certs_add(context, c->certs, cert); +} + +static void +free_private_key(struct private_key *key) +{ + free_AlgorithmIdentifier(&key->alg); + if (key->private_key) + hx509_private_key_free(&key->private_key); + der_free_octet_string(&key->localKeyId); + free(key); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_collector_private_key_add(hx509_context context, + struct hx509_collector *c, + const AlgorithmIdentifier *alg, + hx509_private_key private_key, + const heim_octet_string *key_data, + const heim_octet_string *localKeyId) +{ + struct private_key *key; + void *d; + int ret; + + key = calloc(1, sizeof(*key)); + if (key == NULL) + return ENOMEM; + + d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0])); + if (d == NULL) { + free(key); + hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); + return ENOMEM; + } + c->val.data = d; + + ret = copy_AlgorithmIdentifier(alg, &key->alg); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy " + "AlgorithmIdentifier"); + goto out; + } + if (private_key) { + key->private_key = private_key; + } else { + ret = hx509_parse_private_key(context, alg, + key_data->data, key_data->length, + HX509_KEY_FORMAT_DER, + &key->private_key); + if (ret && localKeyId) { + int ret2; + + ret2 = hx509_parse_private_key(context, alg, + localKeyId->data, localKeyId->length, + HX509_KEY_FORMAT_PKCS8, + &key->private_key); + if (ret2 == 0) + ret = 0; + } + if (ret) + goto out; + } + if (localKeyId) { + ret = der_copy_octet_string(localKeyId, &key->localKeyId); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy localKeyId"); + goto out; + } + } else + memset(&key->localKeyId, 0, sizeof(key->localKeyId)); + + c->val.data[c->val.len] = key; + c->val.len++; + +out: + if (ret) + free_private_key(key); + + return ret; +} + +static int +match_localkeyid(hx509_context context, + struct private_key *value, + hx509_certs certs) +{ + hx509_cert cert; + hx509_query q; + int ret; + + if (value->localKeyId.length == 0) { + hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING, + "No local key attribute on private key"); + return HX509_LOCAL_ATTRIBUTE_MISSING; + } + + _hx509_query_clear(&q); + q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID; + + q.local_key_id = &value->localKeyId; + + ret = hx509_certs_find(context, certs, &q, &cert); + if (ret == 0 && cert == NULL) + ret = HX509_CERT_NOT_FOUND; + if (ret == 0) { + if (value->private_key) + _hx509_cert_assign_key(cert, value->private_key); + hx509_cert_free(cert); + } + return ret; +} + +static int +match_keys(hx509_context context, struct private_key *value, hx509_certs certs) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = HX509_CERT_NOT_FOUND; + + if (value->private_key == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "No private key to compare with"); + return HX509_PRIVATE_KEY_MISSING; + } + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_cert_private_key(c)) { + hx509_cert_free(c); + continue; + } + + ret = _hx509_match_keys(c, value->private_key); + if (ret) { + _hx509_cert_assign_key(c, value->private_key); + hx509_cert_free(c); + found = 0; + break; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + + if (found) + hx509_clear_error_string(context); + + return found; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_collector_collect_certs(hx509_context context, + struct hx509_collector *c, + hx509_certs *ret_certs) +{ + hx509_certs certs; + int ret; + size_t i; + + *ret_certs = NULL; + + ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs); + if (ret) + return ret; + + ret = hx509_certs_merge(context, certs, c->certs); + if (ret) { + hx509_certs_free(&certs); + return ret; + } + + for (i = 0; i < c->val.len; i++) { + ret = match_localkeyid(context, c->val.data[i], certs); + if (ret == 0) + continue; + ret = match_keys(context, c->val.data[i], certs); + if (ret == 0) + continue; + } + + *ret_certs = certs; + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_collector_collect_private_keys(hx509_context context, + struct hx509_collector *c, + hx509_private_key **keys) +{ + size_t i, nkeys; + + *keys = NULL; + + for (i = 0, nkeys = 0; i < c->val.len; i++) + if (c->val.data[i]->private_key) + nkeys++; + + *keys = calloc(nkeys + 1, sizeof(**keys)); + if (*keys == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory"); + return ENOMEM; + } + + for (i = 0, nkeys = 0; i < c->val.len; i++) { + if (c->val.data[i]->private_key) { + (*keys)[nkeys++] = c->val.data[i]->private_key; + c->val.data[i]->private_key = NULL; + } + } + (*keys)[nkeys] = NULL; + + return 0; +} + + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_collector_free(struct hx509_collector *c) +{ + size_t i; + + if (c->unenvelop_certs) + hx509_certs_free(&c->unenvelop_certs); + if (c->certs) + hx509_certs_free(&c->certs); + for (i = 0; i < c->val.len; i++) + free_private_key(c->val.data[i]); + if (c->val.data) + free(c->val.data); + free(c); +} diff --git a/third_party/heimdal/lib/hx509/crypto-ec.c b/third_party/heimdal/lib/hx509/crypto-ec.c new file mode 100644 index 0000000..b7435c9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/crypto-ec.c @@ -0,0 +1,838 @@ +/* + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#ifdef HAVE_HCRYPTO_W_OPENSSL +#include +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_30 +#include +#include +#endif +#define HEIM_NO_CRYPTO_HDRS +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +#include "hx_locl.h" + +extern const AlgorithmIdentifier _hx509_signature_sha512_data; +extern const AlgorithmIdentifier _hx509_signature_sha384_data; +extern const AlgorithmIdentifier _hx509_signature_sha256_data; +extern const AlgorithmIdentifier _hx509_signature_sha1_data; + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_private_eckey_free(void *eckey) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL +#ifdef HAVE_OPENSSL_30 + EVP_PKEY_free(eckey); +#else + EC_KEY_free(eckey); +#endif +#endif +} + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static struct oid2nid_st { + const heim_oid *oid; + int nid; +} oid2nid[] = { + { ASN1_OID_ID_EC_GROUP_SECP256R1, NID_X9_62_prime256v1 }, +#ifdef NID_secp521r1 + { ASN1_OID_ID_EC_GROUP_SECP521R1, NID_secp521r1 }, +#endif +#ifdef NID_secp384r1 + { ASN1_OID_ID_EC_GROUP_SECP384R1, NID_secp384r1 }, +#endif +#ifdef NID_secp160r1 + { ASN1_OID_ID_EC_GROUP_SECP160R1, NID_secp160r1 }, +#endif +#ifdef NID_secp160r2 + { ASN1_OID_ID_EC_GROUP_SECP160R2, NID_secp160r2 }, +#endif + /* XXX Add more! Add X25519! */ +}; + +int +_hx509_ossl_oid2nid(heim_oid *oid) +{ + size_t i; + + for (i = 0; i < sizeof(oid2nid)/sizeof(oid2nid[0]); i++) + if (der_heim_oid_cmp(oid, oid2nid[i].oid) == 0) + return oid2nid[i].nid; + return NID_undef; +} + +static int +ECParameters2nid(hx509_context context, + heim_octet_string *parameters, + int *nid) +{ + ECParameters ecparam; + size_t size; + int ret; + + if (parameters == NULL) { + ret = HX509_PARSING_KEY_FAILED; + hx509_set_error_string(context, 0, ret, + "EC parameters missing"); + return ret; + } + + ret = decode_ECParameters(parameters->data, parameters->length, + &ecparam, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EC parameters"); + return ret; + } + + if (ecparam.element != choice_ECParameters_namedCurve) { + free_ECParameters(&ecparam); + hx509_set_error_string(context, 0, ret, + "EC parameters is not a named curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + *nid = _hx509_ossl_oid2nid(&ecparam.u.namedCurve); + free_ECParameters(&ecparam); + if (*nid == NID_undef) { + hx509_set_error_string(context, 0, ret, + "Failed to find matcing NID for EC curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + return 0; +} + +#ifdef HAVE_OPENSSL_30 +static const EVP_MD * +signature_alg2digest_evp_md(hx509_context context, + const AlgorithmIdentifier *digest_alg) +{ + if ((&digest_alg->algorithm == &asn1_oid_id_sha512 || + der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha512) == 0)) + return EVP_sha512(); + if ((&digest_alg->algorithm == &asn1_oid_id_sha384 || + der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha384) == 0)) + return EVP_sha384(); + if ((&digest_alg->algorithm == &asn1_oid_id_sha256 || + der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha256) == 0)) + return EVP_sha256(); + if ((&digest_alg->algorithm == &asn1_oid_id_secsig_sha_1 || + der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_secsig_sha_1) == 0)) + return EVP_sha1(); + if ((&digest_alg->algorithm == &asn1_oid_id_rsa_digest_md5 || + der_heim_oid_cmp(&digest_alg->algorithm, + &asn1_oid_id_rsa_digest_md5) == 0)) + return EVP_md5(); + + /* + * XXX Decode the `digest_alg->algorithm' OID and include it in the error + * message. + */ + hx509_set_error_string(context, 0, EINVAL, + "Digest algorithm not found"); + return NULL; +} +#endif + + + +/* + * + */ + +static int +ecdsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ +#ifdef HAVE_OPENSSL_30 + const AlgorithmIdentifier *digest_alg = sig_alg->digest_alg; + const EVP_MD *md = signature_alg2digest_evp_md(context, digest_alg); + const SubjectPublicKeyInfo *spi; + const char *curve_sn = NULL; /* sn == short name in OpenSSL parlance */ + OSSL_PARAM params[2]; + EVP_PKEY_CTX *pctx = NULL; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY *template = NULL; + EVP_PKEY *public = NULL; + const unsigned char *p; + size_t len; + char *curve_sn_dup = NULL; + int groupnid; + int ret = 0; + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + if (der_heim_oid_cmp(&spi->algorithm.algorithm, + ASN1_OID_ID_ECPUBLICKEY) != 0) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + /* XXX Include the OID in the message */ + "Unsupported subjectPublicKey algorithm"); + if (ret == 0) + ret = ECParameters2nid(context, spi->algorithm.parameters, &groupnid); + if (ret == 0 && (curve_sn = OBJ_nid2sn(groupnid)) == NULL) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + "Could not resolve curve NID %d to its short name", + groupnid); + if (ret == 0 && (curve_sn_dup = strdup(curve_sn)) == NULL) + ret = hx509_enomem(context); + if (ret == 0 && (mdctx = EVP_MD_CTX_new()) == NULL) + ret = hx509_enomem(context); + + /* + * In order for d2i_PublicKey() to work we need to create a template key + * that has the curve parameters for the subjectPublicKey. + * + * Or maybe we could learn to use the OSSL_DECODER(3) API. But this works, + * at least until OpenSSL deprecates d2i_PublicKey() and forces us to use + * OSSL_DECODER(3). + */ + if (ret == 0) { + /* + * Apparently there's no error checking to be done here? Why does + * OSSL_PARAM_construct_utf8_string() want a non-const for the value? + * Is that a bug in OpenSSL? + */ + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + curve_sn_dup, 0); + params[1] = OSSL_PARAM_construct_end(); + + if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) + ret = hx509_enomem(context); + } + if (ret == 0 && EVP_PKEY_fromdata_init(pctx) != 1) + ret = hx509_enomem(context); + if (ret == 0 && + EVP_PKEY_fromdata(pctx, &template, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, params) != 1) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + "Could not set up to parse key for curve %s", + curve_sn); + + /* Finally we can decode the subjectPublicKey */ + p = spi->subjectPublicKey.data; + len = spi->subjectPublicKey.length / 8; + if (ret == 0 && + (public = d2i_PublicKey(EVP_PKEY_EC, &template, &p, len)) == NULL) + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + + /* EVP_DigestVerifyInit() will allocate a new pctx */ + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + + if (ret == 0 && + EVP_DigestVerifyInit(mdctx, &pctx, md, NULL, public) != 1) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + "Could not initialize " + "OpenSSL signature verification"); + if (ret == 0 && + EVP_DigestVerifyUpdate(mdctx, data->data, data->length) != 1) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + "Could not initialize " + "OpenSSL signature verification"); + if (ret == 0 && + EVP_DigestVerifyFinal(mdctx, sig->data, sig->length) != 1) + hx509_set_error_string(context, 0, + ret = HX509_CRYPTO_SIG_INVALID_FORMAT, + "Signature verification failed"); + + EVP_MD_CTX_free(mdctx); + EVP_PKEY_free(template); + free(curve_sn_dup); + return ret; +#else + const AlgorithmIdentifier *digest_alg; + const SubjectPublicKeyInfo *spi; + heim_octet_string digest; + int ret; + EC_KEY *key = NULL; + int groupnid; + EC_GROUP *group; + const unsigned char *p; + long len; + + digest_alg = sig_alg->digest_alg; + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &digest); + if (ret) + return ret; + + /* set up EC KEY */ + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, ASN1_OID_ID_ECPUBLICKEY) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + /* + * Find the group id + */ + + ret = ECParameters2nid(context, spi->algorithm.parameters, &groupnid); + if (ret) { + der_free_octet_string(&digest); + return ret; + } + + /* + * Create group, key, parse key + */ + + key = EC_KEY_new(); + group = EC_GROUP_new_by_curve_name(groupnid); + EC_KEY_set_group(key, group); + EC_GROUP_free(group); + + p = spi->subjectPublicKey.data; + len = spi->subjectPublicKey.length / 8; + + if (o2i_ECPublicKey(&key, &p, len) == NULL) { + EC_KEY_free(key); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + ret = ECDSA_verify(-1, digest.data, digest.length, + sig->data, sig->length, key); + der_free_octet_string(&digest); + EC_KEY_free(key); + if (ret != 1) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + return ret; + } + + return 0; +#endif +} + +static int +ecdsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ +#ifdef HAVE_OPENSSL_30 + const AlgorithmIdentifier *digest_alg = sig_alg->digest_alg; + const EVP_MD *md = signature_alg2digest_evp_md(context, digest_alg); + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + const heim_oid *sig_oid; + int ret = 0; + + sig->data = NULL; + sig->length = 0; + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig_oid = sig_alg->sig_oid; + digest_alg = sig_alg->digest_alg; + + if (signatureAlgorithm) + ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, + "\x05\x00", 2); + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) + ret = hx509_enomem(context); + if (ret == 0 && EVP_DigestSignInit(mdctx, &pctx, md, NULL, + signer->private_key.ecdsa) != 1) + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + if (ret == 0 && EVP_DigestSignUpdate(mdctx, data->data, data->length) != 1) + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + if (ret == 0 && EVP_DigestSignFinal(mdctx, NULL, &sig->length) != 1) + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + if (ret == 0 && (sig->data = malloc(sig->length)) == NULL) + ret = hx509_enomem(context); + if (ret == 0 && EVP_DigestSignFinal(mdctx, sig->data, &sig->length) != 1) + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + + if (ret == HX509_CMS_FAILED_CREATE_SIGATURE) { + /* XXX Extract error detail from OpenSSL */ + hx509_set_error_string(context, 0, ret, + "ECDSA sign failed"); + } + + if (ret) { + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + free(sig->data); + sig->data = NULL; + sig->length = 0; + } + EVP_MD_CTX_free(mdctx); + return ret; +#else + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + unsigned int siglen; + int ret; + + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig_oid = sig_alg->sig_oid; + digest_alg = sig_alg->digest_alg; + + if (signatureAlgorithm) { + ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, + "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + } + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &indata); + if (ret) + goto error; + + sig->length = ECDSA_size(signer->private_key.ecdsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + der_free_octet_string(&indata); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto error; + } + + siglen = sig->length; + + ret = ECDSA_sign(-1, indata.data, indata.length, + sig->data, &siglen, signer->private_key.ecdsa); + der_free_octet_string(&indata); + if (ret != 1) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "ECDSA sign failed: %d", ret); + goto error; + } + if (siglen > sig->length) + _hx509_abort("ECDSA signature prelen longer than output len"); + + sig->length = siglen; + + return 0; +error: + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + return ret; +#endif +} + +static int +ecdsa_available(const hx509_private_key signer, + const AlgorithmIdentifier *sig_alg) +{ +#ifdef HAVE_OPENSSL_30 + const struct signature_alg *sig; + size_t group_name_len = 0; + char group_name_buf[96]; + EC_GROUP *group = NULL; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + int ret = 0; + + if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig = _hx509_find_sig_alg(&sig_alg->algorithm); + if (sig == NULL || sig->digest_size == 0) + return 0; + + if (EVP_PKEY_get_group_name(signer->private_key.ecdsa, group_name_buf, + sizeof(group_name_buf), + &group_name_len) != 1 || + group_name_len >= sizeof(group_name_buf)) { + return 0; + } + group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(group_name_buf)); + bnctx = BN_CTX_new(); + order = BN_new(); + if (group && bnctx && order && + EC_GROUP_get_order(group, order, bnctx) == 1) + ret = 1; + +#if 0 + /* + * If anything, require a digest at least as wide as the EC key size + * + * if (BN_num_bytes(order) > sig->digest_size) + * ret = 0; + */ +#endif + + BN_CTX_free(bnctx); + BN_clear_free(order); + EC_GROUP_free(group); + return ret; +#else + const struct signature_alg *sig; + const EC_GROUP *group; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + int ret = 0; + + if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig = _hx509_find_sig_alg(&sig_alg->algorithm); + + if (sig == NULL || sig->digest_size == 0) + return 0; + + group = EC_KEY_get0_group(signer->private_key.ecdsa); + if (group == NULL) + return 0; + + bnctx = BN_CTX_new(); + order = BN_new(); + if (order == NULL) + goto err; + + if (EC_GROUP_get_order(group, order, bnctx) != 1) + goto err; + +#if 0 + /* If anything, require a digest at least as wide as the EC key size */ + if (BN_num_bytes(order) > sig->digest_size) +#endif + ret = 1; + err: + if (bnctx) + BN_CTX_free(bnctx); + if (order) + BN_clear_free(order); + + return ret; +#endif +} + +static int +ecdsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + memset(spki, 0, sizeof(*spki)); + return ENOMEM; +} + +static int +ecdsa_private_key_export(hx509_context context, + const hx509_private_key key, + hx509_key_format_t format, + heim_octet_string *data) +{ + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; +} + +static int +ecdsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_key_format_t format, + hx509_private_key private_key) +{ +#ifdef HAVE_OPENSSL_30 + const unsigned char *p = data; + EVP_PKEY *key = NULL; + int ret = 0; + + switch (format) { + case HX509_KEY_FORMAT_PKCS8: + key = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p, len); + if (key == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + break; + + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } + + /* + * We used to have to call EC_KEY_new(), then EC_KEY_set_group() the group + * (curve) on the resulting EC_KEY _before_ we could d2i_ECPrivateKey() the + * key, but that's all deprecated in OpenSSL 3.0. + * + * In fact, it's not clear how ever to assign a group to a private key, + * but that's what the documentation for d2i_PrivateKey() says: that + * its `EVP_PKEY **' argument must be non-NULL pointing to a key that + * has had the group set. + * + * However, from code inspection it's clear that when the ECParameters + * are present in the private key payload passed to d2i_PrivateKey(), + * the group will be taken from that. + * + * What we'll do is that if we have `keyai->parameters' we'll check if the + * key we got is for the same group. + */ + if (keyai->parameters) { + size_t gname_len = 0; + char buf[96]; + int got_group_nid = NID_undef; + int want_groupnid = NID_undef; + + ret = ECParameters2nid(context, keyai->parameters, &want_groupnid); + if (ret == 0 && + (EVP_PKEY_get_group_name(key, buf, sizeof(buf), &gname_len) != 1 || + gname_len >= sizeof(buf))) + ret = HX509_ALG_NOT_SUPP; + if (ret == 0) + got_group_nid = OBJ_txt2nid(buf); + if (ret == 0 && + (got_group_nid == NID_undef || want_groupnid != got_group_nid)) + ret = HX509_ALG_NOT_SUPP; + } + + if (ret == 0) { + private_key->private_key.ecdsa = key; + private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; + key = NULL; + } + + EVP_PKEY_free(key); + return ret; +#else + const unsigned char *p = data; + EC_KEY **pkey = NULL; + EC_KEY *key; + + if (keyai->parameters) { + EC_GROUP *group; + int groupnid; + int ret; + + ret = ECParameters2nid(context, keyai->parameters, &groupnid); + if (ret) + return ret; + + key = EC_KEY_new(); + if (key == NULL) + return ENOMEM; + + group = EC_GROUP_new_by_curve_name(groupnid); + if (group == NULL) { + EC_KEY_free(key); + return ENOMEM; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_group(key, group) != 1) { + EC_KEY_free(key); + EC_GROUP_free(group); + return ENOMEM; + } + EC_GROUP_free(group); + pkey = &key; + } + + switch (format) { + case HX509_KEY_FORMAT_DER: + + private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); + if (private_key->private_key.ecdsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; + break; + + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } + + return 0; +#endif +} + +static int +ecdsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) +{ + return ENOMEM; +} + +static BIGNUM * +ecdsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + return NULL; +} + +static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_ecPublicKey = { + { 6, rk_UNCONST(ecPublicKey) }, NULL +}; + +static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { + { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha384_oid[] ={ 1, 2, 840, 10045, 4, 3, 3 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha384_data = { + { 7, rk_UNCONST(ecdsa_with_sha384_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha512_oid[] ={ 1, 2, 840, 10045, 4, 3, 4 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha512_data = { + { 7, rk_UNCONST(ecdsa_with_sha512_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { + { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL +}; + +hx509_private_key_ops ecdsa_private_key_ops = { + "EC PRIVATE KEY", + ASN1_OID_ID_ECPUBLICKEY, + ecdsa_available, + ecdsa_private_key2SPKI, + ecdsa_private_key_export, + ecdsa_private_key_import, + ecdsa_generate_private_key, + ecdsa_get_internal +}; + +const struct signature_alg ecdsa_with_sha512_alg = { + "ecdsa-with-sha512", + ASN1_OID_ID_ECDSA_WITH_SHA512, + &_hx509_signature_ecdsa_with_sha512_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha512_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 64 +}; + +const struct signature_alg ecdsa_with_sha384_alg = { + "ecdsa-with-sha384", + ASN1_OID_ID_ECDSA_WITH_SHA384, + &_hx509_signature_ecdsa_with_sha384_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha384_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 48 +}; + +const struct signature_alg ecdsa_with_sha256_alg = { + "ecdsa-with-sha256", + ASN1_OID_ID_ECDSA_WITH_SHA256, + &_hx509_signature_ecdsa_with_sha256_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha256_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 32 +}; + +const struct signature_alg ecdsa_with_sha1_alg = { + "ecdsa-with-sha1", + ASN1_OID_ID_ECDSA_WITH_SHA1, + &_hx509_signature_ecdsa_with_sha1_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 20 +}; + +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +HX509_LIB_FUNCTION const AlgorithmIdentifier * HX509_LIB_CALL +hx509_signature_ecPublicKey(void) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return &_hx509_signature_ecPublicKey; +#else + return NULL; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} + +HX509_LIB_FUNCTION const AlgorithmIdentifier * HX509_LIB_CALL +hx509_signature_ecdsa_with_sha256(void) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return &_hx509_signature_ecdsa_with_sha256_data; +#else + return NULL; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} diff --git a/third_party/heimdal/lib/hx509/crypto.c b/third_party/heimdal/lib/hx509/crypto.c new file mode 100644 index 0000000..ba9db64 --- /dev/null +++ b/third_party/heimdal/lib/hx509/crypto.c @@ -0,0 +1,2800 @@ +/* + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/*- + * RFC5758 specifies no parameters for ecdsa-with-SHA signatures + * RFC5754 specifies NULL parameters for shaWithRSAEncryption signatures + * + * XXX: Make sure that the parameters are either NULL in both the tbs and the + * signature, or absent from both the tbs and the signature. + */ + +static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; + +static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; +const AlgorithmIdentifier _hx509_signature_sha512_data = { + { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_sha384_data = { + { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_sha256_data = { + { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +const AlgorithmIdentifier _hx509_signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +const AlgorithmIdentifier _hx509_signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { + { 7, rk_UNCONST(rsa_with_sha512_oid) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { + { 7, rk_UNCONST(rsa_with_sha384_oid) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { + { 7, rk_UNCONST(rsa_with_sha256_oid) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { + { 7, rk_UNCONST(rsa_with_sha1_oid) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { + { 7, rk_UNCONST(rsa_with_md5_oid) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_data = { + { 7, rk_UNCONST(rsa_oid) }, NULL +}; + +static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = { + { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL +}; + +static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 }; +const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = { + { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL +}; + +static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 }; +const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = { + { 9, rk_UNCONST(aes128_cbc_oid) }, NULL +}; + +static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 }; +const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = { + { 9, rk_UNCONST(aes256_cbc_oid) }, NULL +}; + +/* + * + */ + +static BIGNUM * +heim_int2BN(const heim_integer *i) +{ + BIGNUM *bn; + + bn = BN_bin2bn(i->data, i->length, NULL); + BN_set_negative(bn, i->negative); + return bn; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_set_digest_alg(DigestAlgorithmIdentifier *id, + const heim_oid *oid, + const void *param, size_t length) +{ + int ret; + if (param) { + id->parameters = malloc(sizeof(*id->parameters)); + if (id->parameters == NULL) + return ENOMEM; + id->parameters->data = malloc(length); + if (id->parameters->data == NULL) { + free(id->parameters); + id->parameters = NULL; + return ENOMEM; + } + memcpy(id->parameters->data, param, length); + id->parameters->length = length; + } else + id->parameters = NULL; + ret = der_copy_oid(oid, &id->algorithm); + if (ret) { + if (id->parameters) { + free(id->parameters->data); + free(id->parameters); + id->parameters = NULL; + } + return ret; + } + return 0; +} + +/* + * + */ + +static int +rsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DigestInfo di; + unsigned char *to; + int tosize, retsize; + int ret; + RSA *rsa; + size_t size; + const unsigned char *p; + + memset(&di, 0, sizeof(di)); + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + p = spi->subjectPublicKey.data; + size = spi->subjectPublicKey.length / 8; + + rsa = d2i_RSAPublicKey(NULL, &p, size); + if (rsa == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + retsize = RSA_public_decrypt(sig->length, (unsigned char *)sig->data, + to, rsa, RSA_PKCS1_PADDING); + if (retsize <= 0) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, + "RSA public decrypt failed: %d", retsize); + free(to); + goto out; + } + if (retsize > tosize) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + + if (sig_alg->flags & RA_RSA_USES_DIGEST_INFO) { + + ret = decode_DigestInfo(to, retsize, &di, &size); + free(to); + if (ret) { + goto out; + } + + /* Check for extra data inside the sigature */ + if (size != (size_t)retsize) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "size from decryption mismatch"); + goto out; + } + + if (sig_alg->digest_alg && + der_heim_oid_cmp(&di.digestAlgorithm.algorithm, + &sig_alg->digest_alg->algorithm) != 0) + { + ret = HX509_CRYPTO_OID_MISMATCH; + hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch"); + goto out; + } + + /* verify that the parameters are NULL or the NULL-type */ + if (di.digestAlgorithm.parameters != NULL && + (di.digestAlgorithm.parameters->length != 2 || + memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0)) + { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature"); + goto out; + } + + ret = _hx509_verify_signature(context, + NULL, + &di.digestAlgorithm, + data, + &di.digest); + if (ret) + goto out; + + } else { + if ((size_t)retsize != data->length || + ct_memcmp(to, data->data, retsize) != 0) + { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "RSA Signature incorrect"); + goto out; + } + free(to); + ret = 0; + } + + out: + free_DigestInfo(&di); + if (rsa) + RSA_free(rsa); + return ret; +} + +static int +rsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + size_t size; + int ret; + + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) != 0) + return HX509_ALG_NOT_SUPP; + + if (alg) + sig_oid = &alg->algorithm; + else + sig_oid = signer->signature_alg; + + if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA512WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_sha512(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA384WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_sha384(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA256WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_sha256(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_sha1(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_md5(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION) == 0) { + digest_alg = hx509_signature_md5(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_DSA_WITH_SHA1) == 0) { + digest_alg = hx509_signature_sha1(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) { + digest_alg = hx509_signature_sha1(); + } else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_HEIM_RSA_PKCS1_X509) == 0) { + digest_alg = NULL; + } else + return HX509_ALG_NOT_SUPP; + + if (signatureAlgorithm) { + ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, + "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + } + + if (digest_alg) { + DigestInfo di; + memset(&di, 0, sizeof(di)); + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + &di.digestAlgorithm, + &di.digest); + if (ret) + return ret; + ASN1_MALLOC_ENCODE(DigestInfo, + indata.data, + indata.length, + &di, + &size, + ret); + free_DigestInfo(&di); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + if (indata.length != size) + _hx509_abort("internal ASN.1 encoder error"); + } else { + indata = *data; + } + + sig->length = RSA_size(signer->private_key.rsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + der_free_octet_string(&indata); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = RSA_private_encrypt(indata.length, indata.data, + sig->data, + signer->private_key.rsa, + RSA_PKCS1_PADDING); + if (indata.data != data->data) + der_free_octet_string(&indata); + if (ret <= 0) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "RSA private encrypt failed: %d", ret); + return ret; + } + if (sig->length > (size_t)ret) { + size = sig->length - ret; + memmove((uint8_t *)sig->data + size, sig->data, ret); + memset(sig->data, 0, size); + } else if (sig->length < (size_t)ret) + _hx509_abort("RSA signature prelen longer than output len"); + + return 0; +} + +static int +rsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_key_format_t format, + hx509_private_key private_key) +{ + switch (format) { + case HX509_KEY_FORMAT_DER: { + const unsigned char *p = data; + + private_key->private_key.rsa = + d2i_RSAPrivateKey(NULL, &p, len); + if (private_key->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse RSA key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION; + break; + + } + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } + + return 0; +} + +static int +rsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + int len, ret; + + memset(spki, 0, sizeof(*spki)); + + len = i2d_RSAPublicKey(private_key->private_key.rsa, NULL); + if (len < 0) + return -1; + + spki->subjectPublicKey.data = malloc(len); + if (spki->subjectPublicKey.data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory"); + return ENOMEM; + } + spki->subjectPublicKey.length = len * 8; + + ret = _hx509_set_digest_alg(&spki->algorithm, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + "\x05\x00", 2); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc - out of memory"); + free(spki->subjectPublicKey.data); + spki->subjectPublicKey.data = NULL; + spki->subjectPublicKey.length = 0; + return ret; + } + + { + unsigned char *pp = spki->subjectPublicKey.data; + i2d_RSAPublicKey(private_key->private_key.rsa, &pp); + } + + return 0; +} + +static int +rsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) +{ + BIGNUM *e; + int ret; + unsigned long bits; + + static const int default_rsa_e = 65537; + static const int default_rsa_bits = 2048; + + private_key->private_key.rsa = RSA_new(); + if (private_key->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to generate RSA key"); + return HX509_PARSING_KEY_FAILED; + } + + e = BN_new(); + BN_set_word(e, default_rsa_e); + + bits = default_rsa_bits; + + if (ctx->num_bits) + bits = ctx->num_bits; + + ret = RSA_generate_key_ex(private_key->private_key.rsa, bits, e, NULL); + BN_free(e); + if (ret != 1) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to generate RSA key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION; + + return 0; +} + +static int +rsa_private_key_export(hx509_context context, + const hx509_private_key key, + hx509_key_format_t format, + heim_octet_string *data) +{ + int ret; + + data->data = NULL; + data->length = 0; + + switch (format) { + case HX509_KEY_FORMAT_DER: + + ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL); + if (ret <= 0) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "Private key is not exportable"); + return ret; + } + + data->data = malloc(ret); + if (data->data == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; + } + data->length = ret; + + { + unsigned char *p = data->data; + i2d_RSAPrivateKey(key->private_key.rsa, &p); + } + break; + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } + + return 0; +} + +static BIGNUM * +rsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + if (strcasecmp(type, "rsa-modulus") == 0) { + return BN_dup(key->private_key.rsa->n); + } else if (strcasecmp(type, "rsa-exponent") == 0) { + return BN_dup(key->private_key.rsa->e); + } else + return NULL; +} + + + +static hx509_private_key_ops rsa_private_key_ops = { + "RSA PRIVATE KEY", + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + NULL, + rsa_private_key2SPKI, + rsa_private_key_export, + rsa_private_key_import, + rsa_generate_private_key, + rsa_get_internal +}; + +/* + * + */ + +static int +dsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const SubjectPublicKeyInfo *spi; + DSAPublicKey pk; + DSAParams param; + size_t size; + DSA *dsa; + int ret; + + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + dsa = DSA_new(); + if (dsa == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = decode_DSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) + goto out; + + dsa->pub_key = heim_int2BN(&pk); + + free_DSAPublicKey(&pk); + + if (dsa->pub_key == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + if (spi->algorithm.parameters == NULL) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "DSA parameters missing"); + goto out; + } + + ret = decode_DSAParams(spi->algorithm.parameters->data, + spi->algorithm.parameters->length, + ¶m, + &size); + if (ret) { + hx509_set_error_string(context, 0, ret, "DSA parameters failed to decode"); + goto out; + } + + dsa->p = heim_int2BN(¶m.p); + dsa->q = heim_int2BN(¶m.q); + dsa->g = heim_int2BN(¶m.g); + + free_DSAParams(¶m); + + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + ret = DSA_verify(-1, data->data, data->length, + (unsigned char*)sig->data, sig->length, + dsa); + if (ret == 1) + ret = 0; + else if (ret == 0 || ret == -1) { + ret = HX509_CRYPTO_BAD_SIGNATURE; + hx509_set_error_string(context, 0, ret, "BAD DSA sigature"); + } else { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + hx509_set_error_string(context, 0, ret, "Invalid format of DSA sigature"); + } + + out: + DSA_free(dsa); + + return ret; +} + +#if 0 +static int +dsa_parse_private_key(hx509_context context, + const void *data, + size_t len, + hx509_private_key private_key) +{ + const unsigned char *p = data; + + private_key->private_key.dsa = + d2i_DSAPrivateKey(NULL, &p, len); + if (private_key->private_key.dsa == NULL) + return EINVAL; + private_key->signature_alg = ASN1_OID_ID_DSA_WITH_SHA1; + + return 0; +/* else */ + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "No support to parse DSA keys"); + return HX509_PARSING_KEY_FAILED; +} +#endif + +static int +evp_md_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + size_t sigsize = EVP_MD_size(sig_alg->evp_md()); + EVP_MD_CTX *ctx; + + memset(sig, 0, sizeof(*sig)); + + if (signatureAlgorithm) { + int ret; + ret = _hx509_set_digest_alg(signatureAlgorithm, + sig_alg->sig_oid, "\x05\x00", 2); + if (ret) + return ret; + } + + + sig->data = malloc(sigsize); + if (sig->data == NULL) { + sig->length = 0; + return ENOMEM; + } + sig->length = sigsize; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, sig_alg->evp_md(), NULL); + EVP_DigestUpdate(ctx, data->data, data->length); + EVP_DigestFinal_ex(ctx, sig->data, NULL); + EVP_MD_CTX_destroy(ctx); + + + return 0; +} + +static int +evp_md_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *ctx; + size_t sigsize = EVP_MD_size(sig_alg->evp_md()); + + if (sig->length != sigsize || sigsize > sizeof(digest)) { + hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, + "SHA256 sigature has wrong length"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, sig_alg->evp_md(), NULL); + EVP_DigestUpdate(ctx, data->data, data->length); + EVP_DigestFinal_ex(ctx, digest, NULL); + EVP_MD_CTX_destroy(ctx); + + if (ct_memcmp(digest, sig->data, sigsize) != 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE, + "Bad %s sigature", sig_alg->name); + return HX509_CRYPTO_BAD_SIGNATURE; + } + + return 0; +} + +#ifdef HAVE_HCRYPTO_W_OPENSSL +extern const struct signature_alg ecdsa_with_sha512_alg; +extern const struct signature_alg ecdsa_with_sha384_alg; +extern const struct signature_alg ecdsa_with_sha256_alg; +extern const struct signature_alg ecdsa_with_sha1_alg; +#endif + +static const struct signature_alg heim_rsa_pkcs1_x509 = { + "rsa-pkcs1-x509", + ASN1_OID_ID_HEIM_RSA_PKCS1_X509, + &_hx509_signature_rsa_pkcs1_x509_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + NULL, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg pkcs1_rsa_sha1_alg = { + "rsa", + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_rsa_with_sha1_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + NULL, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_sha512_alg = { + "rsa-with-sha512", + ASN1_OID_ID_PKCS1_SHA512WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_sha512_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_sha512_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_sha384_alg = { + "rsa-with-sha384", + ASN1_OID_ID_PKCS1_SHA384WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_sha384_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_sha384_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_sha256_alg = { + "rsa-with-sha256", + ASN1_OID_ID_PKCS1_SHA256WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_sha256_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_sha256_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_sha1_alg = { + "rsa-with-sha1", + ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_sha1_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_sha1_alg_secsig = { + "rsa-with-sha1", + ASN1_OID_ID_SECSIG_SHA_1WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_sha1_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg rsa_with_md5_alg = { + "rsa-with-md5", + ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION, + &_hx509_signature_rsa_with_md5_data, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &_hx509_signature_md5_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|WEAK_SIG_ALG, + 1230739889, + NULL, + rsa_verify_signature, + rsa_create_signature, + 0 +}; + +static const struct signature_alg dsa_sha1_alg = { + "dsa-with-sha1", + ASN1_OID_ID_DSA_WITH_SHA1, + NULL, + ASN1_OID_ID_DSA, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, + NULL, + dsa_verify_signature, + /* create_signature */ NULL, + 0 +}; + +static const struct signature_alg sha512_alg = { + "sha-512", + ASN1_OID_ID_SHA512, + &_hx509_signature_sha512_data, + NULL, + NULL, + SIG_DIGEST, + 0, + EVP_sha512, + evp_md_verify_signature, + evp_md_create_signature, + 0 +}; + +static const struct signature_alg sha384_alg = { + "sha-384", + ASN1_OID_ID_SHA384, + &_hx509_signature_sha384_data, + NULL, + NULL, + SIG_DIGEST, + 0, + EVP_sha384, + evp_md_verify_signature, + evp_md_create_signature, + 0 +}; + +static const struct signature_alg sha256_alg = { + "sha-256", + ASN1_OID_ID_SHA256, + &_hx509_signature_sha256_data, + NULL, + NULL, + SIG_DIGEST, + 0, + EVP_sha256, + evp_md_verify_signature, + evp_md_create_signature, + 0 +}; + +static const struct signature_alg sha1_alg = { + "sha1", + ASN1_OID_ID_SECSIG_SHA_1, + &_hx509_signature_sha1_data, + NULL, + NULL, + SIG_DIGEST, + 0, + EVP_sha1, + evp_md_verify_signature, + evp_md_create_signature, + 0 +}; + +static const struct signature_alg md5_alg = { + "rsa-md5", + ASN1_OID_ID_RSA_DIGEST_MD5, + &_hx509_signature_md5_data, + NULL, + NULL, + SIG_DIGEST|WEAK_SIG_ALG, + 0, + EVP_md5, + evp_md_verify_signature, + NULL, + 0 +}; + +/* + * Order matter in this structure, "best" first for each "key + * compatible" type (type is ECDSA, RSA, DSA, none, etc) + */ + +static const struct signature_alg *sig_algs[] = { +#ifdef HAVE_HCRYPTO_W_OPENSSL + &ecdsa_with_sha512_alg, + &ecdsa_with_sha384_alg, + &ecdsa_with_sha256_alg, + &ecdsa_with_sha1_alg, +#endif + &rsa_with_sha512_alg, + &rsa_with_sha384_alg, + &rsa_with_sha256_alg, + &rsa_with_sha1_alg, + &rsa_with_sha1_alg_secsig, + &pkcs1_rsa_sha1_alg, + &rsa_with_md5_alg, + &heim_rsa_pkcs1_x509, + &dsa_sha1_alg, + &sha512_alg, + &sha384_alg, + &sha256_alg, + &sha1_alg, + &md5_alg, + NULL +}; + +const struct signature_alg * +_hx509_find_sig_alg(const heim_oid *oid) +{ + unsigned int i; + for (i = 0; sig_algs[i]; i++) + if (der_heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0) + return sig_algs[i]; + return NULL; +} + +static const AlgorithmIdentifier * +alg_for_privatekey(const hx509_private_key pk, int type) +{ + const heim_oid *keytype; + unsigned int i; + + if (pk->ops == NULL) + return NULL; + + keytype = pk->ops->key_oid; + + for (i = 0; sig_algs[i]; i++) { + if (sig_algs[i]->key_oid == NULL) + continue; + if (der_heim_oid_cmp(sig_algs[i]->key_oid, keytype) != 0) + continue; + if (pk->ops->available && + pk->ops->available(pk, sig_algs[i]->sig_alg) == 0) + continue; + if (type == HX509_SELECT_PUBLIC_SIG) + return sig_algs[i]->sig_alg; + if (type == HX509_SELECT_DIGEST) + return sig_algs[i]->digest_alg; + + return NULL; + } + return NULL; +} + +/* + * + */ +#ifdef HAVE_HCRYPTO_W_OPENSSL +extern hx509_private_key_ops ecdsa_private_key_ops; +#endif + +static struct hx509_private_key_ops *private_algs[] = { + &rsa_private_key_ops, +#ifdef HAVE_HCRYPTO_W_OPENSSL + &ecdsa_private_key_ops, +#endif + NULL +}; + +HX509_LIB_FUNCTION hx509_private_key_ops * HX509_LIB_CALL +hx509_find_private_alg(const heim_oid *oid) +{ + int i; + for (i = 0; private_algs[i]; i++) { + if (private_algs[i]->key_oid == NULL) + continue; + if (der_heim_oid_cmp(private_algs[i]->key_oid, oid) == 0) + return private_algs[i]; + } + return NULL; +} + +/* + * Check if the algorithm `alg' have a best before date, and if it + * des, make sure the its before the time `t'. + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_signature_is_weak(hx509_context context, const AlgorithmIdentifier *alg) +{ + const struct signature_alg *md; + + md = _hx509_find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (md->flags & WEAK_SIG_ALG) { + hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE, + "Algorithm %s is weak", md->name); + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + } + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_self_signed_valid(hx509_context context, + const AlgorithmIdentifier *alg) +{ + const struct signature_alg *md; + + md = _hx509_find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if ((md->flags & SELF_SIGNED_OK) == 0) { + hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE, + "Algorithm %s not trusted for self signatures", + md->name); + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + } + return 0; +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_verify_signature(hx509_context context, + const hx509_cert cert, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const struct signature_alg *md; + const Certificate *signer = NULL; + + if (cert) + signer = _hx509_get_cert(cert); + + md = _hx509_find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (signer && (md->flags & PROVIDE_CONF) == 0) { + hx509_clear_error_string(context); + return HX509_CRYPTO_SIG_NO_CONF; + } + if (signer == NULL && (md->flags & REQUIRE_SIGNER)) { + hx509_clear_error_string(context); + return HX509_CRYPTO_SIGNATURE_WITHOUT_SIGNER; + } + if (md->key_oid && signer) { + const SubjectPublicKeyInfo *spi; + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_DONT_MATCH_KEY_ALG; + } + } + return (*md->verify_signature)(context, md, signer, alg, data, sig); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_create_signature(hx509_context context, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const struct signature_alg *md; + + md = _hx509_find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, + "algorithm no supported"); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + if (signer && (md->flags & PROVIDE_CONF) == 0) { + hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, + "algorithm provides no conf"); + return HX509_CRYPTO_SIG_NO_CONF; + } + + return (*md->create_signature)(context, md, signer, alg, data, + signatureAlgorithm, sig); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_create_signature_bitstring(hx509_context context, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_bit_string *sig) +{ + heim_octet_string os; + int ret; + + ret = _hx509_create_signature(context, signer, alg, + data, signatureAlgorithm, &os); + if (ret) + return ret; + sig->data = os.data; + sig->length = os.length * 8; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_public_encrypt(hx509_context context, + const heim_octet_string *cleartext, + const Certificate *cert, + heim_oid *encryption_oid, + heim_octet_string *ciphertext) +{ + const SubjectPublicKeyInfo *spi; + unsigned char *to; + int tosize; + int ret; + RSA *rsa; + size_t size; + const unsigned char *p; + + ciphertext->data = NULL; + ciphertext->length = 0; + + spi = &cert->tbsCertificate.subjectPublicKeyInfo; + + p = spi->subjectPublicKey.data; + size = spi->subjectPublicKey.length / 8; + + rsa = d2i_RSAPublicKey(NULL, &p, size); + if (rsa == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + tosize = RSA_size(rsa); + to = malloc(tosize); + if (to == NULL) { + RSA_free(rsa); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = RSA_public_encrypt(cleartext->length, + (unsigned char *)cleartext->data, + to, rsa, RSA_PKCS1_PADDING); + RSA_free(rsa); + if (ret <= 0) { + free(to); + hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PUBLIC_ENCRYPT, + "RSA public encrypt failed with %d", ret); + return HX509_CRYPTO_RSA_PUBLIC_ENCRYPT; + } + if (ret > tosize) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + + ciphertext->length = ret; + ciphertext->data = to; + + ret = der_copy_oid(ASN1_OID_ID_PKCS1_RSAENCRYPTION, encryption_oid); + if (ret) { + der_free_octet_string(ciphertext); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_private_key_private_decrypt(hx509_context context, + const heim_octet_string *ciphertext, + const heim_oid *encryption_oid, + hx509_private_key p, + heim_octet_string *cleartext) +{ + int ret; + + cleartext->data = NULL; + cleartext->length = 0; + + if (p->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, + "Private RSA key missing"); + return HX509_PRIVATE_KEY_MISSING; + } + + cleartext->length = RSA_size(p->private_key.rsa); + cleartext->data = malloc(cleartext->length); + if (cleartext->data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + ret = RSA_private_decrypt(ciphertext->length, ciphertext->data, + cleartext->data, + p->private_key.rsa, + RSA_PKCS1_PADDING); + if (ret <= 0) { + der_free_octet_string(cleartext); + hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PRIVATE_DECRYPT, + "Failed to decrypt using private key: %d", ret); + return HX509_CRYPTO_RSA_PRIVATE_DECRYPT; + } + if (cleartext->length < (size_t)ret) + _hx509_abort("internal rsa decryption failure: ret > tosize"); + + cleartext->length = ret; + + return 0; +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_parse_private_key(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_key_format_t format, + hx509_private_key *private_key) +{ + struct hx509_private_key_ops *ops; + int ret; + + *private_key = NULL; + + ops = hx509_find_private_alg(&keyai->algorithm); + if (ops == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + ret = hx509_private_key_init(private_key, ops, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + + ret = (*ops->import)(context, keyai, data, len, format, *private_key); + if (ret) + hx509_private_key_free(private_key); + + if (ret && format == HX509_KEY_FORMAT_PKCS8) { + PKCS8PrivateKeyInfo ki; + hx509_private_key key; + + /* Re-enter to try parsing the DER-encoded key from PKCS#8 envelope */ + ret = decode_PKCS8PrivateKeyInfo(data, len, &ki, NULL); + if (ret) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse PKCS#8-encoded private " + "key"); + return HX509_PARSING_KEY_FAILED; + } + ret = hx509_parse_private_key(context, &ki.privateKeyAlgorithm, + ki.privateKey.data, ki.privateKey.length, + HX509_KEY_FORMAT_DER, &key); + free_PKCS8PrivateKeyInfo(&ki); + if (ret) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse RSA key from PKCS#8 " + "envelope"); + return HX509_PARSING_KEY_FAILED; + } + *private_key = key; + } + return ret; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + const struct hx509_private_key_ops *ops = private_key->ops; + if (ops == NULL || ops->get_spki == NULL) { + hx509_set_error_string(context, 0, HX509_UNIMPLEMENTED_OPERATION, + "Private key have no key2SPKI function"); + return HX509_UNIMPLEMENTED_OPERATION; + } + return (*ops->get_spki)(context, private_key, spki); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_generate_private_key_init(hx509_context context, + const heim_oid *oid, + struct hx509_generate_private_context **ctx) +{ + *ctx = NULL; + + if (der_heim_oid_cmp(oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) != 0) { + hx509_set_error_string(context, 0, EINVAL, + "private key not an RSA key"); + return EINVAL; + } + + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + (*ctx)->key_oid = oid; + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_generate_private_key_is_ca(hx509_context context, + struct hx509_generate_private_context *ctx) +{ + ctx->isCA = 1; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_generate_private_key_bits(hx509_context context, + struct hx509_generate_private_context *ctx, + unsigned long bits) +{ + ctx->num_bits = bits; + return 0; +} + + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_generate_private_key_free(struct hx509_generate_private_context **ctx) +{ + free(*ctx); + *ctx = NULL; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key *private_key) +{ + struct hx509_private_key_ops *ops; + int ret; + + *private_key = NULL; + + ops = hx509_find_private_alg(ctx->key_oid); + if (ops == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + + ret = hx509_private_key_init(private_key, ops, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + + ret = (*ops->generate_private_key)(context, ctx, *private_key); + if (ret) + hx509_private_key_free(private_key); + + return ret; +} + +/* + * + */ + +const AlgorithmIdentifier * +hx509_signature_sha512(void) +{ return &_hx509_signature_sha512_data; } + +const AlgorithmIdentifier * +hx509_signature_sha384(void) +{ return &_hx509_signature_sha384_data; } + +const AlgorithmIdentifier * +hx509_signature_sha256(void) +{ return &_hx509_signature_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_sha1(void) +{ return &_hx509_signature_sha1_data; } + +const AlgorithmIdentifier * +hx509_signature_md5(void) +{ return &_hx509_signature_md5_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha512(void) +{ return &_hx509_signature_rsa_with_sha512_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha384(void) +{ return &_hx509_signature_rsa_with_sha384_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha256(void) +{ return &_hx509_signature_rsa_with_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_sha1(void) +{ return &_hx509_signature_rsa_with_sha1_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_with_md5(void) +{ return &_hx509_signature_rsa_with_md5_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa(void) +{ return &_hx509_signature_rsa_data; } + +const AlgorithmIdentifier * +hx509_signature_rsa_pkcs1_x509(void) +{ return &_hx509_signature_rsa_pkcs1_x509_data; } + +const AlgorithmIdentifier * +hx509_crypto_des_rsdi_ede3_cbc(void) +{ return &_hx509_des_rsdi_ede3_cbc_oid; } + +const AlgorithmIdentifier * +hx509_crypto_aes128_cbc(void) +{ return &_hx509_crypto_aes128_cbc_data; } + +const AlgorithmIdentifier * +hx509_crypto_aes256_cbc(void) +{ return &_hx509_crypto_aes256_cbc_data; } + +/* + * + */ + +const AlgorithmIdentifier * _hx509_crypto_default_sig_alg = + &_hx509_signature_rsa_with_sha256_data; +const AlgorithmIdentifier * _hx509_crypto_default_digest_alg = + &_hx509_signature_sha256_data; +const AlgorithmIdentifier * _hx509_crypto_default_secret_alg = + &_hx509_crypto_aes128_cbc_data; + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_private_key_init(hx509_private_key *key, + hx509_private_key_ops *ops, + void *keydata) +{ + *key = calloc(1, sizeof(**key)); + if (*key == NULL) + return ENOMEM; + (*key)->ref = 1; + (*key)->ops = ops; + (*key)->private_key.keydata = keydata; + return 0; +} + +HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL +_hx509_private_key_ref(hx509_private_key key) +{ + if (key->ref == 0) + _hx509_abort("key refcount <= 0 on ref"); + key->ref++; + if (key->ref == UINT_MAX) + _hx509_abort("key refcount == UINT_MAX on ref"); + return key; +} + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +_hx509_private_pem_name(hx509_private_key key) +{ + return key->ops->pemtype; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_private_key_free(hx509_private_key *key) +{ + if (key == NULL || *key == NULL) + return 0; + + if ((*key)->ref == 0) + _hx509_abort("key refcount == 0 on free"); + if (--(*key)->ref > 0) + return 0; + + if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) { + if ((*key)->private_key.rsa) + RSA_free((*key)->private_key.rsa); + } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, + ASN1_OID_ID_ECPUBLICKEY) == 0 && + (*key)->private_key.ecdsa != NULL) { + _hx509_private_eckey_free((*key)->private_key.ecdsa); + } + (*key)->private_key.rsa = NULL; + free(*key); + *key = NULL; + return 0; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_private_key_assign_rsa(hx509_private_key key, void *ptr) +{ + if (key->private_key.rsa) + RSA_free(key->private_key.rsa); + key->private_key.rsa = ptr; + key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION; + key->md = &pkcs1_rsa_sha1_alg; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_private_key_oid(hx509_context context, + const hx509_private_key key, + heim_oid *data) +{ + int ret; + ret = der_copy_oid(key->ops->key_oid, data); + if (ret) + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_private_key_exportable(hx509_private_key key) +{ + if (key->ops->export == NULL) + return 0; + return 1; +} + +HX509_LIB_FUNCTION BIGNUM * HX509_LIB_CALL +_hx509_private_key_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + if (key->ops->get_internal == NULL) + return NULL; + return (*key->ops->get_internal)(context, key, type); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_private_key_export(hx509_context context, + const hx509_private_key key, + hx509_key_format_t format, + heim_octet_string *data) +{ + data->length = 0; + data->data = NULL; + if (key->ops->export == NULL) { + hx509_clear_error_string(context); + return HX509_UNIMPLEMENTED_OPERATION; + } + if (format == HX509_KEY_FORMAT_PKCS8) { + PKCS8PrivateKeyInfo ki; + size_t size; + int ret; + + memset(&ki, 0, sizeof(ki)); + ki.attributes = NULL; /* No localKeyId needed */ + ki.privateKey.data = NULL; + ki.privateKeyAlgorithm.algorithm.components = NULL; + ret = der_parse_hex_heim_integer("00", &ki.version); + if (ret == 0) + ret = _hx509_private_key_oid(context, key, + &ki.privateKeyAlgorithm.algorithm); + if (ret == 0) + /* Re-enter */ + ret = _hx509_private_key_export(context, key, HX509_KEY_FORMAT_DER, + &ki.privateKey); + + /* + * XXX To set ki.privateKeyAlgorithm.parameters we'll need to either + * move this code into the *key->ops->export() functions, or expand + * their signature to allow them to set it for us, or add a method to + * hx509_private_key_ops that allows us to get the parameters from the + * backend. + */ + ki.privateKeyAlgorithm.parameters = NULL; + + if (ret == 0) + ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, data->data, data->length, + &ki, &size, ret); + free_PKCS8PrivateKeyInfo(&ki); + if (ret == 0 && size != data->length) + ret = EINVAL; + if (ret) + hx509_set_error_string(context, 0, ret, + "Private key PKCS#8 encoding failed"); + return ret; + } + return (*key->ops->export)(context, key, format, data); +} + +/* + * + */ + +struct hx509cipher { + const char *name; + int flags; +#define CIPHER_WEAK 1 + const heim_oid *oid; + const AlgorithmIdentifier *(*ai_func)(void); + const EVP_CIPHER *(*evp_func)(void); + int (*get_params)(hx509_context, const hx509_crypto, + const heim_octet_string *, heim_octet_string *); + int (*set_params)(hx509_context, const heim_octet_string *, + hx509_crypto, heim_octet_string *); +}; + +struct hx509_crypto_data { + char *name; + int flags; +#define ALLOW_WEAK 1 + +#define PADDING_NONE 2 +#define PADDING_PKCS7 4 +#define PADDING_FLAGS (2|4) + const struct hx509cipher *cipher; + const EVP_CIPHER *c; + heim_octet_string key; + heim_oid oid; + void *param; +}; + +/* + * + */ + +static unsigned private_rc2_40_oid_data[] = { 127, 1 }; + +static heim_oid asn1_oid_private_rc2_40 = + { 2, private_rc2_40_oid_data }; + +/* + * + */ + +static int +CMSCBCParam_get(hx509_context context, const hx509_crypto crypto, + const heim_octet_string *ivec, heim_octet_string *param) +{ + size_t size; + int ret; + + assert(crypto->param == NULL); + if (ivec == NULL) + return 0; + + ASN1_MALLOC_ENCODE(CMSCBCParameter, param->data, param->length, + ivec, &size, ret); + if (ret == 0 && size != param->length) + _hx509_abort("Internal asn1 encoder failure"); + if (ret) + hx509_clear_error_string(context); + return ret; +} + +static int +CMSCBCParam_set(hx509_context context, const heim_octet_string *param, + hx509_crypto crypto, heim_octet_string *ivec) +{ + int ret; + if (ivec == NULL) + return 0; + + ret = decode_CMSCBCParameter(param->data, param->length, ivec, NULL); + if (ret) + hx509_clear_error_string(context); + + return ret; +} + +struct _RC2_params { + int maximum_effective_key; +}; + +static int +CMSRC2CBCParam_get(hx509_context context, const hx509_crypto crypto, + const heim_octet_string *ivec, heim_octet_string *param) +{ + CMSRC2CBCParameter rc2params; + const struct _RC2_params *p = crypto->param; + int maximum_effective_key = 128; + size_t size; + int ret; + + memset(&rc2params, 0, sizeof(rc2params)); + + if (p) + maximum_effective_key = p->maximum_effective_key; + + switch(maximum_effective_key) { + case 40: + rc2params.rc2ParameterVersion = 160; + break; + case 64: + rc2params.rc2ParameterVersion = 120; + break; + case 128: + rc2params.rc2ParameterVersion = 58; + break; + } + rc2params.iv = *ivec; + + ASN1_MALLOC_ENCODE(CMSRC2CBCParameter, param->data, param->length, + &rc2params, &size, ret); + if (ret == 0 && size != param->length) + _hx509_abort("Internal asn1 encoder failure"); + + return ret; +} + +static int +CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param, + hx509_crypto crypto, heim_octet_string *ivec) +{ + CMSRC2CBCParameter rc2param; + struct _RC2_params *p; + size_t size; + int ret; + + ret = decode_CMSRC2CBCParameter(param->data, param->length, + &rc2param, &size); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + free_CMSRC2CBCParameter(&rc2param); + hx509_clear_error_string(context); + return ENOMEM; + } + switch(rc2param.rc2ParameterVersion) { + case 160: + crypto->c = EVP_rc2_40_cbc(); + p->maximum_effective_key = 40; + break; + case 120: + crypto->c = EVP_rc2_64_cbc(); + p->maximum_effective_key = 64; + break; + case 58: + crypto->c = EVP_rc2_cbc(); + p->maximum_effective_key = 128; + break; + default: + free(p); + free_CMSRC2CBCParameter(&rc2param); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + if (ivec) + ret = der_copy_octet_string(&rc2param.iv, ivec); + free_CMSRC2CBCParameter(&rc2param); + if (ret) { + free(p); + hx509_clear_error_string(context); + } else + crypto->param = p; + + return ret; +} + +/* + * + */ + +static const struct hx509cipher ciphers[] = { + { + "rc2-cbc", + CIPHER_WEAK, + ASN1_OID_ID_PKCS3_RC2_CBC, + NULL, + EVP_rc2_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "rc2-cbc", + CIPHER_WEAK, + ASN1_OID_ID_RSADSI_RC2_CBC, + NULL, + EVP_rc2_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "rc2-40-cbc", + CIPHER_WEAK, + &asn1_oid_private_rc2_40, + NULL, + EVP_rc2_40_cbc, + CMSRC2CBCParam_get, + CMSRC2CBCParam_set + }, + { + "des-ede3-cbc", + 0, + ASN1_OID_ID_PKCS3_DES_EDE3_CBC, + NULL, + EVP_des_ede3_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "des-ede3-cbc", + 0, + ASN1_OID_ID_RSADSI_DES_EDE3_CBC, + hx509_crypto_des_rsdi_ede3_cbc, + EVP_des_ede3_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-128-cbc", + 0, + ASN1_OID_ID_AES_128_CBC, + hx509_crypto_aes128_cbc, + EVP_aes_128_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-192-cbc", + 0, + ASN1_OID_ID_AES_192_CBC, + NULL, + EVP_aes_192_cbc, + CMSCBCParam_get, + CMSCBCParam_set + }, + { + "aes-256-cbc", + 0, + ASN1_OID_ID_AES_256_CBC, + hx509_crypto_aes256_cbc, + EVP_aes_256_cbc, + CMSCBCParam_get, + CMSCBCParam_set + } +}; + +static const struct hx509cipher * +find_cipher_by_oid(const heim_oid *oid) +{ + size_t i; + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) + if (der_heim_oid_cmp(oid, ciphers[i].oid) == 0) + return &ciphers[i]; + + return NULL; +} + +static const struct hx509cipher * +find_cipher_by_name(const char *name) +{ + size_t i; + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) + if (strcasecmp(name, ciphers[i].name) == 0) + return &ciphers[i]; + + return NULL; +} + + +HX509_LIB_FUNCTION const heim_oid * HX509_LIB_CALL +hx509_crypto_enctype_by_name(const char *name) +{ + const struct hx509cipher *cipher; + + cipher = find_cipher_by_name(name); + if (cipher == NULL) + return NULL; + return cipher->oid; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_init(hx509_context context, + const char *provider, + const heim_oid *enctype, + hx509_crypto *crypto) +{ + const struct hx509cipher *cipher; + + *crypto = NULL; + + cipher = find_cipher_by_oid(enctype); + if (cipher == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "Algorithm not supported"); + return HX509_ALG_NOT_SUPP; + } + + *crypto = calloc(1, sizeof(**crypto)); + if (*crypto == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + (*crypto)->flags = PADDING_PKCS7; + (*crypto)->cipher = cipher; + (*crypto)->c = (*cipher->evp_func)(); + + if (der_copy_oid(enctype, &(*crypto)->oid)) { + hx509_crypto_destroy(*crypto); + *crypto = NULL; + hx509_clear_error_string(context); + return ENOMEM; + } + + return 0; +} + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +hx509_crypto_provider(hx509_crypto crypto) +{ + return "unknown"; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_crypto_destroy(hx509_crypto crypto) +{ + if (crypto->name) + free(crypto->name); + if (crypto->key.data) + free(crypto->key.data); + if (crypto->param) + free(crypto->param); + der_free_oid(&crypto->oid); + memset(crypto, 0, sizeof(*crypto)); + free(crypto); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_set_key_name(hx509_crypto crypto, const char *name) +{ + return 0; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_crypto_allow_weak(hx509_crypto crypto) +{ + crypto->flags |= ALLOW_WEAK; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_crypto_set_padding(hx509_crypto crypto, int padding_type) +{ + switch (padding_type) { + case HX509_CRYPTO_PADDING_PKCS7: + crypto->flags &= ~PADDING_FLAGS; + crypto->flags |= PADDING_PKCS7; + break; + case HX509_CRYPTO_PADDING_NONE: + crypto->flags &= ~PADDING_FLAGS; + crypto->flags |= PADDING_NONE; + break; + default: + _hx509_abort("Invalid padding"); + } +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length) +{ + if (EVP_CIPHER_key_length(crypto->c) > (int)length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.data = NULL; + crypto->key.length = 0; + } + crypto->key.data = malloc(length); + if (crypto->key.data == NULL) + return ENOMEM; + memcpy(crypto->key.data, data, length); + crypto->key.length = length; + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_set_random_key(hx509_crypto crypto, heim_octet_string *key) +{ + if (crypto->key.data) { + free(crypto->key.data); + crypto->key.length = 0; + } + + crypto->key.length = EVP_CIPHER_key_length(crypto->c); + crypto->key.data = malloc(crypto->key.length); + if (crypto->key.data == NULL) { + crypto->key.length = 0; + return ENOMEM; + } + if (RAND_bytes(crypto->key.data, crypto->key.length) <= 0) { + free(crypto->key.data); + crypto->key.data = NULL; + crypto->key.length = 0; + return HX509_CRYPTO_INTERNAL_ERROR; + } + if (key) + return der_copy_octet_string(&crypto->key, key); + else + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_set_params(hx509_context context, + hx509_crypto crypto, + const heim_octet_string *param, + heim_octet_string *ivec) +{ + return (*crypto->cipher->set_params)(context, param, crypto, ivec); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_get_params(hx509_context context, + hx509_crypto crypto, + const heim_octet_string *ivec, + heim_octet_string *param) +{ + return (*crypto->cipher->get_params)(context, crypto, ivec, param); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_random_iv(hx509_crypto crypto, heim_octet_string *ivec) +{ + ivec->length = EVP_CIPHER_iv_length(crypto->c); + ivec->data = malloc(ivec->length); + if (ivec->data == NULL) { + ivec->length = 0; + return ENOMEM; + } + + if (RAND_bytes(ivec->data, ivec->length) <= 0) { + free(ivec->data); + ivec->data = NULL; + ivec->length = 0; + return HX509_CRYPTO_INTERNAL_ERROR; + } + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_encrypt(hx509_crypto crypto, + const void *data, + const size_t length, + const heim_octet_string *ivec, + heim_octet_string **ciphertext) +{ + EVP_CIPHER_CTX evp; + size_t padsize, bsize; + int ret; + + *ciphertext = NULL; + + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + + assert(EVP_CIPHER_iv_length(crypto->c) == (int)ivec->length); + + EVP_CIPHER_CTX_init(&evp); + + ret = EVP_CipherInit_ex(&evp, crypto->c, NULL, + crypto->key.data, ivec->data, 1); + if (ret != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + *ciphertext = calloc(1, sizeof(**ciphertext)); + if (*ciphertext == NULL) { + ret = ENOMEM; + goto out; + } + + assert(crypto->flags & PADDING_FLAGS); + + bsize = EVP_CIPHER_block_size(crypto->c); + padsize = 0; + + if (crypto->flags & PADDING_NONE) { + if (bsize != 1 && (length % bsize) != 0) + return HX509_CMS_PADDING_ERROR; + } else if (crypto->flags & PADDING_PKCS7) { + if (bsize != 1) + padsize = bsize - (length % bsize); + } + + (*ciphertext)->length = length + padsize; + (*ciphertext)->data = malloc(length + padsize); + if ((*ciphertext)->data == NULL) { + ret = ENOMEM; + goto out; + } + + memcpy((*ciphertext)->data, data, length); + if (padsize) { + size_t i; + unsigned char *p = (*ciphertext)->data; + p += length; + for (i = 0; i < padsize; i++) + *p++ = padsize; + } + + ret = EVP_Cipher(&evp, (*ciphertext)->data, + (*ciphertext)->data, + length + padsize); + if (ret != 1) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + ret = 0; + + out: + if (ret) { + if (*ciphertext) { + if ((*ciphertext)->data) { + free((*ciphertext)->data); + } + free(*ciphertext); + *ciphertext = NULL; + } + } + EVP_CIPHER_CTX_cleanup(&evp); + + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_decrypt(hx509_crypto crypto, + const void *data, + const size_t length, + heim_octet_string *ivec, + heim_octet_string *clear) +{ + EVP_CIPHER_CTX evp; + void *idata = NULL; + int ret; + + clear->data = NULL; + clear->length = 0; + + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + + if (ivec && EVP_CIPHER_iv_length(crypto->c) < (int)ivec->length) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (crypto->key.data == NULL) + return HX509_CRYPTO_INTERNAL_ERROR; + + if (ivec) + idata = ivec->data; + + EVP_CIPHER_CTX_init(&evp); + + ret = EVP_CipherInit_ex(&evp, crypto->c, NULL, + crypto->key.data, idata, 0); + if (ret != 1) { + EVP_CIPHER_CTX_cleanup(&evp); + return HX509_CRYPTO_INTERNAL_ERROR; + } + + clear->length = length; + clear->data = malloc(length); + if (clear->data == NULL) { + EVP_CIPHER_CTX_cleanup(&evp); + clear->length = 0; + return ENOMEM; + } + + if (EVP_Cipher(&evp, clear->data, data, length) != 1) { + return HX509_CRYPTO_INTERNAL_ERROR; + } + EVP_CIPHER_CTX_cleanup(&evp); + + if ((crypto->flags & PADDING_PKCS7) && EVP_CIPHER_block_size(crypto->c) > 1) { + int padsize; + unsigned char *p; + int j, bsize = EVP_CIPHER_block_size(crypto->c); + + if ((int)clear->length < bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + + p = clear->data; + p += clear->length - 1; + padsize = *p; + if (padsize > bsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + clear->length -= padsize; + for (j = 0; j < padsize; j++) { + if (*p-- != padsize) { + ret = HX509_CMS_PADDING_ERROR; + goto out; + } + } + } + + return 0; + + out: + if (clear->data) + free(clear->data); + clear->data = NULL; + clear->length = 0; + return ret; +} + +typedef int (*PBE_string2key_func)(hx509_context, + const char *, + const heim_octet_string *, + hx509_crypto *, heim_octet_string *, + heim_octet_string *, + const heim_oid *, const EVP_MD *); + +static int +PBE_string2key(hx509_context context, + const char *password, + const heim_octet_string *parameters, + hx509_crypto *crypto, + heim_octet_string *key, heim_octet_string *iv, + const heim_oid *enc_oid, + const EVP_MD *md) +{ + PKCS12_PBEParams p12params; + int passwordlen; + hx509_crypto c; + int iter, saltlen, ret; + unsigned char *salt; + + passwordlen = password ? strlen(password) : 0; + + if (parameters == NULL) + return HX509_ALG_NOT_SUPP; + + ret = decode_PKCS12_PBEParams(parameters->data, + parameters->length, + &p12params, NULL); + if (ret) + goto out; + + if (p12params.iterations) + iter = *p12params.iterations; + else + iter = 1; + salt = p12params.salt.data; + saltlen = p12params.salt.length; + + if (!PKCS12_key_gen (password, passwordlen, salt, saltlen, + PKCS12_KEY_ID, iter, key->length, key->data, md)) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + if (!PKCS12_key_gen (password, passwordlen, salt, saltlen, + PKCS12_IV_ID, iter, iv->length, iv->data, md)) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + + ret = hx509_crypto_init(context, NULL, enc_oid, &c); + if (ret) + goto out; + + hx509_crypto_allow_weak(c); + + ret = hx509_crypto_set_key_data(c, key->data, key->length); + if (ret) { + hx509_crypto_destroy(c); + goto out; + } + + *crypto = c; +out: + free_PKCS12_PBEParams(&p12params); + return ret; +} + +static const heim_oid * +find_string2key(const heim_oid *oid, + const EVP_CIPHER **c, + const EVP_MD **md, + PBE_string2key_func *s2k) +{ + if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC2_CBC) == 0) { + *c = EVP_rc2_40_cbc(); + if (*c == NULL) + return NULL; + *md = EVP_sha1(); + if (*md == NULL) + return NULL; + *s2k = PBE_string2key; + return &asn1_oid_private_rc2_40; + } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC2_CBC) == 0) { + *c = EVP_rc2_cbc(); + if (*c == NULL) + return NULL; + *md = EVP_sha1(); + if (*md == NULL) + return NULL; + *s2k = PBE_string2key; + return ASN1_OID_ID_PKCS3_RC2_CBC; +#if 0 + } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC4) == 0) { + *c = EVP_rc4_40(); + if (*c == NULL) + return NULL; + *md = EVP_sha1(); + if (*md == NULL) + return NULL; + *s2k = PBE_string2key; + return NULL; + } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC4) == 0) { + *c = EVP_rc4(); + if (*c == NULL) + return NULL; + *md = EVP_sha1(); + if (*md == NULL) + return NULL; + *s2k = PBE_string2key; + return ASN1_OID_ID_PKCS3_RC4; +#endif + } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND3_KEYTRIPLEDES_CBC) == 0) { + *c = EVP_des_ede3_cbc(); + if (*c == NULL) + return NULL; + *md = EVP_sha1(); + if (*md == NULL) + return NULL; + *s2k = PBE_string2key; + return ASN1_OID_ID_PKCS3_DES_EDE3_CBC; + } + + return NULL; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_pbe_encrypt(hx509_context context, + hx509_lock lock, + const AlgorithmIdentifier *ai, + const heim_octet_string *content, + heim_octet_string *econtent) +{ + hx509_clear_error_string(context); + return EINVAL; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_pbe_decrypt(hx509_context context, + hx509_lock lock, + const AlgorithmIdentifier *ai, + const heim_octet_string *econtent, + heim_octet_string *content) +{ + const struct _hx509_password *pw; + heim_octet_string key, iv; + const heim_oid *enc_oid; + const EVP_CIPHER *c; + const EVP_MD *md; + PBE_string2key_func s2k; + int ret = 0; + size_t i; + + memset(&key, 0, sizeof(key)); + memset(&iv, 0, sizeof(iv)); + + memset(content, 0, sizeof(*content)); + + enc_oid = find_string2key(&ai->algorithm, &c, &md, &s2k); + if (enc_oid == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "String to key algorithm not supported"); + ret = HX509_ALG_NOT_SUPP; + goto out; + } + + key.length = EVP_CIPHER_key_length(c); + key.data = malloc(key.length); + if (key.data == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + iv.length = EVP_CIPHER_iv_length(c); + iv.data = malloc(iv.length); + if (iv.data == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + pw = _hx509_lock_get_passwords(lock); + + ret = HX509_CRYPTO_INTERNAL_ERROR; + for (i = 0; i < pw->len + 1; i++) { + hx509_crypto crypto; + const char *password; + + if (i < pw->len) + password = pw->val[i]; + else if (i < pw->len + 1) + password = ""; + else + password = NULL; + + ret = (*s2k)(context, password, ai->parameters, &crypto, + &key, &iv, enc_oid, md); + if (ret) + goto out; + + ret = hx509_crypto_decrypt(crypto, + econtent->data, + econtent->length, + &iv, + content); + hx509_crypto_destroy(crypto); + if (ret == 0) + goto out; + + } +out: + if (key.data) + der_free_octet_string(&key); + if (iv.data) + der_free_octet_string(&iv); + return ret; +} + +/* + * + */ + + +static int +match_keys_rsa(hx509_cert c, hx509_private_key private_key) +{ + const Certificate *cert; + const SubjectPublicKeyInfo *spi; + RSAPublicKey pk; + RSA *rsa; + size_t size; + int ret; + + if (private_key->private_key.rsa == NULL) + return 0; + + rsa = private_key->private_key.rsa; + if (rsa->d == NULL || rsa->p == NULL || rsa->q == NULL) + return 0; + + cert = _hx509_get_cert(c); + spi = &cert->tbsCertificate.subjectPublicKeyInfo; + + rsa = RSA_new(); + if (rsa == NULL) + return 0; + + ret = decode_RSAPublicKey(spi->subjectPublicKey.data, + spi->subjectPublicKey.length / 8, + &pk, &size); + if (ret) { + RSA_free(rsa); + return 0; + } + rsa->n = heim_int2BN(&pk.modulus); + rsa->e = heim_int2BN(&pk.publicExponent); + + free_RSAPublicKey(&pk); + + rsa->d = BN_dup(private_key->private_key.rsa->d); + rsa->p = BN_dup(private_key->private_key.rsa->p); + rsa->q = BN_dup(private_key->private_key.rsa->q); + rsa->dmp1 = BN_dup(private_key->private_key.rsa->dmp1); + rsa->dmq1 = BN_dup(private_key->private_key.rsa->dmq1); + rsa->iqmp = BN_dup(private_key->private_key.rsa->iqmp); + + if (rsa->n == NULL || rsa->e == NULL || + rsa->d == NULL || rsa->p == NULL|| rsa->q == NULL || + rsa->dmp1 == NULL || rsa->dmq1 == NULL) { + RSA_free(rsa); + return 0; + } + + ret = RSA_check_key(rsa); + RSA_free(rsa); + + return ret == 1; +} + +static int +match_keys_ec(hx509_cert c, hx509_private_key private_key) +{ + return 1; /* XXX use EC_KEY_check_key */ +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_match_keys(hx509_cert c, hx509_private_key key) +{ + if (!key->ops) + return 0; + if (der_heim_oid_cmp(key->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) + return match_keys_rsa(c, key); + if (der_heim_oid_cmp(key->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) == 0) + return match_keys_ec(c, key); + return 0; + +} + + +static const heim_oid * +find_keytype(const hx509_private_key key) +{ + const struct signature_alg *md; + + if (key == NULL) + return NULL; + + md = _hx509_find_sig_alg(key->signature_alg); + if (md == NULL) + return NULL; + return md->key_oid; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_select(const hx509_context context, + int type, + const hx509_private_key source, + hx509_peer_info peer, + AlgorithmIdentifier *selected) +{ + const AlgorithmIdentifier *def = NULL; + size_t i, j; + int ret, bits; + + memset(selected, 0, sizeof(*selected)); + + if (type == HX509_SELECT_DIGEST) { + bits = SIG_DIGEST; + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_digest_alg; + } else if (type == HX509_SELECT_PUBLIC_SIG) { + bits = SIG_PUBLIC_SIG; + /* XXX depend on `source´ and `peer´ */ + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_sig_alg; + } else if (type == HX509_SELECT_SECRET_ENC) { + bits = SIG_SECRET; + def = _hx509_crypto_default_secret_alg; + } else { + hx509_set_error_string(context, 0, EINVAL, + "Unknown type %d of selection", type); + return EINVAL; + } + + if (peer) { + const heim_oid *keytype = NULL; + + keytype = find_keytype(source); + + for (i = 0; i < peer->len; i++) { + for (j = 0; sig_algs[j]; j++) { + if ((sig_algs[j]->flags & bits) != bits) + continue; + if (der_heim_oid_cmp(sig_algs[j]->sig_oid, + &peer->val[i].algorithm) != 0) + continue; + if (keytype && sig_algs[j]->key_oid && + der_heim_oid_cmp(keytype, sig_algs[j]->key_oid)) + continue; + + /* found one, use that */ + ret = copy_AlgorithmIdentifier(&peer->val[i], selected); + if (ret) + hx509_clear_error_string(context); + return ret; + } + if (bits & SIG_SECRET) { + const struct hx509cipher *cipher; + + cipher = find_cipher_by_oid(&peer->val[i].algorithm); + if (cipher == NULL) + continue; + if (cipher->ai_func == NULL) + continue; + ret = copy_AlgorithmIdentifier(cipher->ai_func(), selected); + if (ret) + hx509_clear_error_string(context); + return ret; + } + } + } + + /* use default */ + ret = copy_AlgorithmIdentifier(def, selected); + if (ret) + hx509_clear_error_string(context); + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crypto_available(hx509_context context, + int type, + hx509_cert source, + AlgorithmIdentifier **val, + unsigned int *plen) +{ + const heim_oid *keytype = NULL; + unsigned int len, i; + void *ptr; + int bits, ret; + + *val = NULL; + + if (type == HX509_SELECT_ALL) { + bits = SIG_DIGEST | SIG_PUBLIC_SIG | SIG_SECRET; + } else if (type == HX509_SELECT_DIGEST) { + bits = SIG_DIGEST; + } else if (type == HX509_SELECT_PUBLIC_SIG) { + bits = SIG_PUBLIC_SIG; + } else { + hx509_set_error_string(context, 0, EINVAL, + "Unknown type %d of available", type); + return EINVAL; + } + + if (source) + keytype = find_keytype(_hx509_cert_private_key(source)); + + len = 0; + for (i = 0; sig_algs[i]; i++) { + if ((sig_algs[i]->flags & bits) == 0) + continue; + if (sig_algs[i]->sig_alg == NULL) + continue; + if (keytype && sig_algs[i]->key_oid && + der_heim_oid_cmp(sig_algs[i]->key_oid, keytype)) + continue; + + /* found one, add that to the list */ + ptr = realloc(*val, sizeof(**val) * (len + 1)); + if (ptr == NULL) + goto out; + *val = ptr; + + ret = copy_AlgorithmIdentifier(sig_algs[i]->sig_alg, &(*val)[len]); + if (ret) + goto out; + len++; + } + + /* Add AES */ + if (bits & SIG_SECRET) { + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) { + + if (ciphers[i].flags & CIPHER_WEAK) + continue; + if (ciphers[i].ai_func == NULL) + continue; + + ptr = realloc(*val, sizeof(**val) * (len + 1)); + if (ptr == NULL) + goto out; + *val = ptr; + + ret = copy_AlgorithmIdentifier((ciphers[i].ai_func)(), &(*val)[len]); + if (ret) + goto out; + len++; + } + } + + *plen = len; + return 0; + +out: + for (i = 0; i < len; i++) + free_AlgorithmIdentifier(&(*val)[i]); + free(*val); + *val = NULL; + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_crypto_free_algs(AlgorithmIdentifier *val, + unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + free_AlgorithmIdentifier(&val[i]); + free(val); +} diff --git a/third_party/heimdal/lib/hx509/data/PKITS.pdf b/third_party/heimdal/lib/hx509/data/PKITS.pdf new file mode 100644 index 0000000..3a56862 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/PKITS.pdf differ diff --git a/third_party/heimdal/lib/hx509/data/PKITS_data.zip b/third_party/heimdal/lib/hx509/data/PKITS_data.zip new file mode 100644 index 0000000..50d6fbb Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/PKITS_data.zip differ diff --git a/third_party/heimdal/lib/hx509/data/bleichenbacher-bad.pem b/third_party/heimdal/lib/hx509/data/bleichenbacher-bad.pem new file mode 100644 index 0000000..2c71932 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/bleichenbacher-bad.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV +BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD +VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa +Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs +YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy +IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD +hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u +12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU +DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ +e20sRA== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/bleichenbacher-good.pem b/third_party/heimdal/lib/hx509/data/bleichenbacher-good.pem new file mode 100644 index 0000000..409147b --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/bleichenbacher-good.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV +BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD +VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU5MDJa +Fw0wNjEwMTEyMzU5MDJaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs +YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy +IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD +hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u +12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAc+fnj0rB2CYautG2 +4itiMOU4SN6JFTFDCTU/Gb5aR/Fiu7HJkuE5yGEnTdnwcId/T9sTW251yzCc1e2z +rHX/kw== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/bleichenbacher-sf-pad-correct.pem b/third_party/heimdal/lib/hx509/data/bleichenbacher-sf-pad-correct.pem new file mode 100644 index 0000000..3e73f5d --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/bleichenbacher-sf-pad-correct.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICgzCCAWugAwIBAgIBFzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYw +ODE5MTY1MTMwWhcNMDYxMDE4MTY1MTMwWjARMQ8wDQYDVQQDEwZIYWNrZXIwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKSu6ChWttBsOpaBrYf4PzyCGNe6DuE7 +rmq4CMskdz8uiAJ3wVd8jGsjdeY4YzoXSVp+9mEF6XqNgyDf8Ub3kNgPYxvJ28lg +QVpd5RdGWXHo14LWBTD1mtFkCiAhVlATsVNI/tjv2tv7Jp8EsylbDHe7hslA0rns +Rr2cS9bvpM03AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF +BQADggEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLL/Up63HkFWD15INcW +Xd1nZGI+gO/whm58ICyJ1Js7ON6N4NyBTwe8513CvdOlOdG/Ctmy2gxEE47HhEed +ST8AUooI0ey599t84P20gGRuOYIjr7c= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/ca.crt b/third_party/heimdal/lib/hx509/data/ca.crt new file mode 100644 index 0000000..7aa8bcf --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/ca.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFczCCA1ugAwIBAgIJAI34CtjBcJHEMA0GCSqGSIb3DQEBCwUAMCoxGzAZBgNV +BAMMEmh4NTA5IFRlc3QgUm9vdCBDQTELMAkGA1UEBhMCU0UwIBcNMTkwMzIyMjIy +NTAxWhgPMjUxODExMjEyMjI1MDFaMCoxGzAZBgNVBAMMEmh4NTA5IFRlc3QgUm9v +dCBDQTELMAkGA1UEBhMCU0UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDE4gbVQ/vlPFU2W62rukqiUkJ/EIDo1HE4r+xpxO12Ke45NtqSep0d2FfSvEu8 +dhot1jWIkijF7B/bFuB0LyFryCAV/zlU9rLoadCmur5ONIgXRm7eW19wxo5YRD4C +A1IRwvT+Axz0TC3eyquUN1C0r7ZWbiOY8uQy3Sjfar16Z3TtqlKgo4R/yF7dIPJO +OVHaznC+xsfLsYE2r9PqbTjBF3O1pIhwV9oA3tfs23EtvcZBP3y3LSsjnKaF0b/N +XmjLNW9hbmAfN+16TEMOlVZvBjUPO3CC/GU0PJzm1/FqyzXWeRx5FZNi7fCPKg8J +9QDAgK5mMn+ZPazuUt70uxUFrnRLCjCia/TgC+t2d+3AqsnRlYnLYDv/MeP/QwqH +GK3+WuAS6uqXZMtilDhY+oiMTZ4vDHvwzJ5q3UhIpWXj5cSGWAxQurKgUsjT9sta +gGmXlBauMYSzFM5T+TXica1qE7dNXjXr2sTy9BHIp+aWJuGkX9rSx8tHwbkIkVTp +4UCZ+QoxBRaSmiuyFPM77yg6wZBuSuRRN/BNKvAhuJaE1MdA+vobbyyNbv56MU0+ +WI4ucD+b08JmJp3k+fgM0fKXBQlEL4mp7zeUoLmC1yCy48Zk1foPZTRH9pIGB/zU +z4B8o20NmereB9bX0IjJ6eqMDqvAZWZ99Nf16Q3X88T88wIDAQABo4GZMIGWMB0G +A1UdDgQWBBRTuMwJxp9C6tXkdCC0Ze1o+J21BTBaBgNVHSMEUzBRgBRTuMwJxp9C +6tXkdCC0Ze1o+J21BaEupCwwKjEbMBkGA1UEAwwSaHg1MDkgVGVzdCBSb290IENB +MQswCQYDVQQGEwJTRYIJAI34CtjBcJHEMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQD +AgHmMA0GCSqGSIb3DQEBCwUAA4ICAQCdea8Tx/1vuQCqn2AOmIzEO9xgmaY3opl9 +0Px82DafNuFFJu9WlPrsKeADtSqpA/MwBjL8K+T3dhL4Bxhq8jed0gGsS3C3xFTl +/RJbnFiLuveMErPTEtxaRYpa3oibQ15eJbDq533Is1x8oeK6NnHB6St3nboST0f3 +6SeAsoeHrI16eUEJQ3UKJYJlxATEqOpeaWwdlT6jF9u0WyENz0ijD0b9FPY/zq6D +zx47Zd5F6aisrtKNXFjB9/oHV6jOh9OGxz6WfT1z2AZ+69jEm+xE8coq4nyWcJrS +cf7ENBIw1Rknpxk3/H1p0q+Zze5/JBYlKOtEML1dwRIRquVgfhcI/tOq7m5jUxTl +/6dW8FCnuEFBnUvUrZ0Hv3g2jvHElpPjYkLwZyKFYyvY/G+xCZAiqaYZ2kQqRmti +KvSfh8fJlV2Jj2aDI1I4JjACG7LYBe7WXCs7TccRrhnx/RUY7cpJwEQrIOKBq8wx +DD58oPgvkmNPP5lZcFARjnWcY8xS9KzT+KaZWM3ZPefg3Vk//3HfwZfDE3Y7IMgu +quuLcpeGtMDyurnm6piUdPITt8yW+MMJR8V+PeF0zLdN4dA0nuJpZWZ3fvnevmAL +jh/ia0LuzkhVSj1R1dXXopZevazh/tmAuKU9BbeYGvwI1RFXVvyzpGRfMbgaze3Q +tIrreKeFxg== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/ca.key b/third_party/heimdal/lib/hx509/data/ca.key new file mode 100644 index 0000000..83cff75 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDE4gbVQ/vlPFU2 +W62rukqiUkJ/EIDo1HE4r+xpxO12Ke45NtqSep0d2FfSvEu8dhot1jWIkijF7B/b +FuB0LyFryCAV/zlU9rLoadCmur5ONIgXRm7eW19wxo5YRD4CA1IRwvT+Axz0TC3e +yquUN1C0r7ZWbiOY8uQy3Sjfar16Z3TtqlKgo4R/yF7dIPJOOVHaznC+xsfLsYE2 +r9PqbTjBF3O1pIhwV9oA3tfs23EtvcZBP3y3LSsjnKaF0b/NXmjLNW9hbmAfN+16 +TEMOlVZvBjUPO3CC/GU0PJzm1/FqyzXWeRx5FZNi7fCPKg8J9QDAgK5mMn+ZPazu +Ut70uxUFrnRLCjCia/TgC+t2d+3AqsnRlYnLYDv/MeP/QwqHGK3+WuAS6uqXZMti +lDhY+oiMTZ4vDHvwzJ5q3UhIpWXj5cSGWAxQurKgUsjT9stagGmXlBauMYSzFM5T ++TXica1qE7dNXjXr2sTy9BHIp+aWJuGkX9rSx8tHwbkIkVTp4UCZ+QoxBRaSmiuy +FPM77yg6wZBuSuRRN/BNKvAhuJaE1MdA+vobbyyNbv56MU0+WI4ucD+b08JmJp3k ++fgM0fKXBQlEL4mp7zeUoLmC1yCy48Zk1foPZTRH9pIGB/zUz4B8o20NmereB9bX +0IjJ6eqMDqvAZWZ99Nf16Q3X88T88wIDAQABAoICAQCD8TXDFpxpM9WnaCkrPN1n +itklbln1rulxo/Q7rc21ssQDc89m+uTwa1vvzmCzHDLPJQ8bR1gry+JNYTdqpWsw +YB2goDo7xlh/iOpb0ipXHr1VW85RFcsQOQCMBq/HiZImdRDaahutXKAg/pGd8rQT +Yu4/XfBdP+nObIhHsbDppwules+E+BCD0jRA3SOFaMSCbncAYxbiW0LM82iBYlD2 +llDlGi6Vm0pt6umpwiZHETcb4wAhghO2+fRfGgIAD5ULGfRaxy2DvmdX3mPSEiKq +pO5KFvt/zMXGDBjaWz1e5HBgGyoJu3vagLsGNpl9gsPOPm6h7pW0jLCnxsHEINwk +lGbhCR9ubaZMCNuwEppPNeusURG35XiSEHC4fBPhlG6pB737a6ih/w9dwOkLuijJ +X3vOaVj2K5waExi72uij+GnZBylemOTAy9lE3xlUzhO74h9F8DuoJHMxXKU5a24L +/hmnnIYHOJpHQIfcfkMIx9VuG/qsug+DdOxlgByT6hbkRbX2gGSP3iqy7XUnb2g0 +3QQdyQpz8wJ2x568EAAC0HKhQj2fcL1L5lpM5xpbg6s87o50reMhcAogb2mGjx3Q +r8u9PJeYgJ5FOqu0zLbenWkb4OLtLz6kHhOdimkCrybL+bLQFdl9lNAOqgVuJxyT +NaClP+v9lAACBkONihU8AQKCAQEA9hxExY0NXFDZHiLq4M4DG79BthLWLi4QFZI5 +2vpzrS5kT90rptAzBenTBWdUifAI8JPkq2R8VKB8j7F5YELQ9UTmoT+qMGEslQ1p +RTE8fZln6UhLUIv5tTwhL6Afbs2Faz7Vd7rUq9eUkyxsjxtZe5cPH1dGplx0iPQI +QQ1OasSWc8TmZWXRvcRWe5vWiJLFZKt6fJZWYyBBvu8L7PZ6QR5Oa2EO1UTPPX+W +7+BwsoH9Bguv+hYliKEReN8SIfOF9E/OElrNooy7eANFTQ3pNEou68rqpzX4jgdW +G4Nnsu9rkO8K+bb+/MLBvdxrEiKrNb+xwcVOFaJNqz6aNMC14QKCAQEAzMtbIpig +dLUha3QXrXIsEjH/hlGx0c6Q9VH/toQbBNE4LOrS4QlurX3iRz79tNYLYdwLrZ2Q ++tK31/ilX/hGIiA1w6fHcrQokddMJhhGoR6nSUiybs+75Ac01xHDSYXCo/YOkr8m +HOtRWi+0qJqzU4sticPwi2YStM6L2gNpEDU9FQTG/wgLLHPxDEjRpkhmgQbt8nEQ +M+amXK1othrZVSTJl1hREF11DkzhkZYyGgY4ifAyAOPW7z5K0nS2drV8PExFSkr+ +2eriVvavu/40WbvadhTy1cyVL7N3svzY34TgwqsXX1Stz8dQBa+uImt9gxmZIK9I +reONiErKBhClUwKCAQEAjY1IyM8OBjDCECFJMq+K/iSM6OoAomMAAUgvWpF+gvcR +3xV4i+Nn1VjddFgwOX4Dxktp1GJhWFNOEV+kTgdgJBHTDJ+PhW/+smQaTh+5iQv4 +xiY8m0FHCERjWf8g1RwERuDG6qxcsdG2tMdyUQUL/JevrPkHu5ulszeYn8HFfoc/ +eaqgUWW0sw8AJuxFAhxYyEQQmSPm3/Cnn+fh1hMV0epadExIucVv5RFDgQh4CVPW +cem6935RbDon0HuM9FYaj6BvCAOODpYfJTHMZDtCDD82qYv2VuIl6ZqynfSAalxm +Y9/5UhM8qahiwo7KTo3+J1XwKWEQPkUxovLIwtqsQQKCAQEAgMgwWyUXYcy1Y1jx +usRdKmP+h3zAEWuQhHQ4FZIlW3YlmTlhutmvm7HZpWvbJuii57r0LQ00qkXwDgPy +GtOJZtRSeuL67QqVqIB3Bk2lvJQGJnNsoXpIcTCG7efhok5XA7wrleRWF0FzOv9c +39nIgvS2gjeRAFgD02c/Uq1qWCLicmE6sg1g2WdfYZY5IBPPQbwVzauDwN9+JjF1 +824W1Q/5JQ8Iiv36Ki/2eRK2Ft9qlnNRPnYIJxJJAucaBrRBl7luqTVX5blq87zU +7acBTJxw2Gh7/C5WclStJQUTbBunK0NjwzMAyfRQQgMjwclOeC6UuJUBYzgBPH+r +Yvz8uQKCAQA8WchJ0UQmOP98voo0cnIX0lcZcddwzdsZm78p1PrXqmsrxnlmRILA +wZ5okzIzEqu1Xltu5DS/CAAWdRkY/2LFGty1dW5UR47xsWE7fMf4dbPeOcBxgfh4 +sQgG7KcWY9mw3PZ4PmPP63nRC/1Ws/+dlvpNA77BjyHH7laTVZbUadS/0bCzhJG0 +RW27r5UcPV8IhKTNU8iOxvaN2U0N2RaaxZ8AaYj8UEeMlFp91DXYa5SCWY1yM0c7 +QYpO3EtSLj+ECk09lDzQBPUo4jzb5CoTFYDEdXr8Rt4I/r03fkOwHslWUzXVyqRe +xC/DrYbFBHh4yQWuQPsmCbi6OkGKDvwA +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/crl1.crl b/third_party/heimdal/lib/hx509/data/crl1.crl new file mode 100644 index 0000000..575f80e --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/crl1.crl @@ -0,0 +1,16 @@ +-----BEGIN X509 CRL----- +MIIChTBvMA0GCSqGSIb3DQEBBQUAMCoxGzAZBgNVBAMMEmh4NTA5IFRlc3QgUm9v +dCBDQTELMAkGA1UEBhMCU0UXDTE5MDMyMjIyMjUxNloXDTI5MDEyODIyMjUxNlow +FDASAgEDFw0xOTAzMjIyMjI1MTZaMA0GCSqGSIb3DQEBBQUAA4ICAQBCM4u2dByD +hPsQUpPAPsZ/a7tPdvkgmcLtk2CFhtJqtDBT96SAr0tVpcpIbZoB0tH/MvJfhAaR +AOLrgdmrwlKaIbq3uyEDIghRlRiG2WXX+gsP9yK1xS6AuQnXS8Pnyng0xo2V8fMy +UCN+gKvO70O6dqcDApU1Tt5jxkPFACBYSSMsuunrjWGuttKGebJJGeBzU+PYt7bZ +7CT2BgsLgl5J2DL6KO9tGjDmlGKKC2joF1PDkjzbIfs389eyOZqJu/3Q4EtBFzad +Yz0DAEDzDrn7dj53NJp6dxbqOM86woak37dtDG5Mwu8KTQEGpfsqdofQf39nluJu +70NHJrXP+9IQ7Tvb3bakZbyigw7J9PBXaHyImXN/gejYD/FQjghnmS2QU72JsSKT +3nAN3I6MRAEIhoaxForCl3f+uHgtvQBBITSIUdnGaTZnI0mXrkHS9H4eWWJREZbc +wBqKGZxbfy8ZbPaKv75Zzj0ZMns7vNybUqLEE/OcwrEjd/pCLwWZ6KzgtS1t22TU +o3H26GNLzMQvg/1dVsRZWrkWxAjVNHtUIXXbmBOvSii3BX7jPIfH1bCZrfsl0xrS +BsqhtIZj74hyTV1FX79CdFu0Ag/ugtzY4K8rdIu9kaPe2Ju6ulQBtpmCK++H7szP +48fJOwV1aKzJGVCH61kSGc8ljyGjDEDn4Q== +-----END X509 CRL----- diff --git a/third_party/heimdal/lib/hx509/data/crl1.der b/third_party/heimdal/lib/hx509/data/crl1.der new file mode 100644 index 0000000..a667423 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/crl1.der differ diff --git a/third_party/heimdal/lib/hx509/data/eccurve.pem b/third_party/heimdal/lib/hx509/data/eccurve.pem new file mode 100644 index 0000000..a76e47d --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/eccurve.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- diff --git a/third_party/heimdal/lib/hx509/data/gen-req.sh b/third_party/heimdal/lib/hx509/data/gen-req.sh new file mode 100755 index 0000000..09f0dfb --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/gen-req.sh @@ -0,0 +1,360 @@ +#!/bin/sh +# $Id$ +# +# This script need openssl 0.9.8a or newer, so it can parse the +# otherName section for pkinit certificates. +# + +openssl=openssl + +# workaround until openssl -objects lands +if ${openssl} version | grep '^OpenSSL 1\.[1-9]' >/dev/null ; then + config=openssl.1.1.cnf +else + config=openssl.1.0.cnf +fi + +gen_cert() +{ + keytype=${6:-rsa:4096} + ${openssl} req \ + -new \ + -subj "$1" \ + -config ${config} \ + -newkey $keytype \ + -sha1 \ + -nodes \ + -keyout out.key \ + -out cert.req > /dev/null 2>/dev/null + + if [ "$3" = "ca" ] ; then + ${openssl} x509 \ + -req \ + -days 182500 \ + -in cert.req \ + -extfile ${config} \ + -extensions $4 \ + -signkey out.key \ + -out cert.crt + + ln -s ca.crt `${openssl} x509 -hash -noout -in cert.crt`.0 + + name=$3 + + elif [ "$3" = "proxy" ] ; then + + ${openssl} x509 \ + -req \ + -in cert.req \ + -days 182500 \ + -out cert.crt \ + -CA $2.crt \ + -CAkey $2.key \ + -CAcreateserial \ + -extfile ${config} \ + -extensions $4 + + name=$5 + else + + ${openssl} ca \ + -name $4 \ + -days 182500 \ + -cert $2.crt \ + -keyfile $2.key \ + -in cert.req \ + -out cert.crt \ + -outdir . \ + -batch \ + -config ${config} + + name=$3 + fi + + mv cert.crt $name.crt + mv out.key $name.key +} + +echo "01" > serial +> index.txt +rm -f *.0 + +gen_cert "/CN=hx509 Test Root CA/C=SE" "root" "ca" "v3_ca" +gen_cert "/CN=OCSP responder/C=SE" "ca" "ocsp-responder" "ocsp" +gen_cert "/CN=Test cert/C=SE" "ca" "test" "usr" +gen_cert "/CN=Revoke cert/C=SE" "ca" "revoke" "usr" +gen_cert "/CN=Test cert KeyEncipherment/C=SE" "ca" "test-ke-only" "usr_ke" +gen_cert "/CN=Test cert DigitalSignature/C=SE" "ca" "test-ds-only" "usr_ds" +gen_cert "/CN=pkinit/C=SE" "ca" "pkinit" "pkinit_client" +$openssl ecparam -name secp256r1 -out eccurve.pem +gen_cert "/CN=pkinit-ec/C=SE" "ca" "pkinit-ec" "pkinit_client" "XXX" ec:eccurve.pem +gen_cert "/C=SE/CN=pkinit/CN=pkinit-proxy" "pkinit" "proxy" "proxy_cert" pkinit-proxy +gen_cert "/CN=kdc/C=SE" "ca" "kdc" "pkinit_kdc" +gen_cert "/CN=www.test.h5l.se/C=SE" "ca" "https" "https" +gen_cert "/CN=Sub CA/C=SE" "ca" "sub-ca" "subca" +gen_cert "/CN=Test sub cert/C=SE" "sub-ca" "sub-cert" "usr" +gen_cert "/C=SE/CN=Test cert/CN=proxy" "test" "proxy" "proxy_cert" proxy-test +gen_cert "/C=SE/CN=Test cert/CN=proxy/CN=child" "proxy-test" "proxy" "proxy_cert" proxy-level-test +gen_cert "/C=SE/CN=Test cert/CN=no-proxy" "test" "proxy" "usr_cert" no-proxy-test +gen_cert "/C=SE/CN=Test cert/CN=proxy10" "test" "proxy" "proxy10_cert" proxy10-test +gen_cert "/C=SE/CN=Test cert/CN=proxy10/CN=child" "proxy10-test" "proxy" "proxy10_cert" proxy10-child-test +gen_cert "/C=SE/CN=Test cert/CN=proxy10/CN=child/CN=child" "proxy10-child-test" "proxy" "proxy10_cert" proxy10-child-child-test + + +# combine +cat sub-ca.crt ca.crt > sub-ca-combined.crt +cat test.crt test.key > test.combined.crt +cat pkinit-proxy.crt pkinit.crt > pkinit-proxy-chain.crt + +# password protected key +${openssl} rsa -in test.key -aes256 -passout pass:foobar -out test-pw.key +${openssl} rsa -in pkinit.key -aes256 -passout pass:foo -out pkinit-pw.key + + +${openssl} ca \ + -name usr \ + -cert ca.crt \ + -keyfile ca.key \ + -revoke revoke.crt \ + -config ${config} + +${openssl} pkcs12 \ + -export \ + -in test.crt \ + -inkey test.key \ + -passout pass:foobar \ + -out test.p12 \ + -name "friendlyname-test" \ + -certfile ca.crt \ + -caname ca + +${openssl} pkcs12 \ + -export \ + -in sub-cert.crt \ + -inkey sub-cert.key \ + -passout pass:foobar \ + -out sub-cert.p12 \ + -name "friendlyname-sub-cert" \ + -certfile sub-ca-combined.crt \ + -caname sub-ca \ + -caname ca + +${openssl} pkcs12 \ + -keypbe NONE \ + -certpbe NONE \ + -export \ + -in test.crt \ + -inkey test.key \ + -passout pass:foobar \ + -out test-nopw.p12 \ + -name "friendlyname-cert" \ + -certfile ca.crt \ + -caname ca + +${openssl} smime \ + -sign \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -outform DER \ + -out test-signed-data + +${openssl} smime \ + -sign \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -noattr \ + -outform DER \ + -out test-signed-data-noattr + +${openssl} smime \ + -sign \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -noattr \ + -nocerts \ + -outform DER \ + -out test-signed-data-noattr-nocerts + +${openssl} smime \ + -sign \ + -md sha1 \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -outform DER \ + -out test-signed-sha-1 + +${openssl} smime \ + -sign \ + -md sha256 \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -outform DER \ + -out test-signed-sha-256 + +${openssl} smime \ + -sign \ + -md sha512 \ + -nodetach \ + -binary \ + -in static-file \ + -signer test.crt \ + -inkey test.key \ + -outform DER \ + -out test-signed-sha-512 + + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-rc2-40 \ + -rc2-40 \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-rc2-64 \ + -rc2-64 \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-rc2-128 \ + -rc2-128 \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-des \ + -des \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-des-ede3 \ + -des3 \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-aes-128 \ + -aes128 \ + test.crt + +${openssl} smime \ + -encrypt \ + -nodetach \ + -binary \ + -in static-file \ + -outform DER \ + -out test-enveloped-aes-256 \ + -aes256 \ + test.crt + +echo ocsp requests + +${openssl} ocsp \ + -issuer ca.crt \ + -cert test.crt \ + -reqout ocsp-req1.der + +${openssl} ocsp \ + -index index.txt \ + -rsigner ocsp-responder.crt \ + -rkey ocsp-responder.key \ + -CA ca.crt \ + -reqin ocsp-req1.der \ + -noverify \ + -respout ocsp-resp1-ocsp.der + +${openssl} ocsp \ + -index index.txt \ + -rsigner ca.crt \ + -rkey ca.key \ + -CA ca.crt \ + -reqin ocsp-req1.der \ + -noverify \ + -respout ocsp-resp1-ca.der + +${openssl} ocsp \ + -index index.txt \ + -rsigner ocsp-responder.crt \ + -rkey ocsp-responder.key \ + -CA ca.crt \ + -resp_no_certs \ + -reqin ocsp-req1.der \ + -noverify \ + -respout ocsp-resp1-ocsp-no-cert.der + +${openssl} ocsp \ + -index index.txt \ + -rsigner ocsp-responder.crt \ + -rkey ocsp-responder.key \ + -CA ca.crt \ + -reqin ocsp-req1.der \ + -resp_key_id \ + -noverify \ + -respout ocsp-resp1-keyhash.der + +${openssl} ocsp \ + -issuer ca.crt \ + -cert revoke.crt \ + -reqout ocsp-req2.der + +${openssl} ocsp \ + -index index.txt \ + -rsigner ocsp-responder.crt \ + -rkey ocsp-responder.key \ + -CA ca.crt \ + -reqin ocsp-req2.der \ + -noverify \ + -respout ocsp-resp2.der + +${openssl} ca \ + -gencrl \ + -name usr \ + -crldays 3600 \ + -keyfile ca.key \ + -cert ca.crt \ + -crl_reason superseded \ + -out crl1.crl \ + -config ${config} + +${openssl} crl -in crl1.crl -outform der -out crl1.der diff --git a/third_party/heimdal/lib/hx509/data/https.crt b/third_party/heimdal/lib/hx509/data/https.crt new file mode 100644 index 0000000..54d5df1 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/https.crt @@ -0,0 +1,116 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 9 (0x9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:10 2019 GMT + Not After : Nov 21 22:25:10 2518 GMT + Subject: C=SE, CN=www.test.h5l.se + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bb:ca:85:9c:3d:6b:5a:21:1b:2c:84:35:48:37: + bc:13:62:93:ff:7b:be:49:40:e2:36:b5:7a:54:a4: + e3:0f:b1:87:29:de:6b:7d:86:ec:b6:25:c5:9c:dc: + 13:06:57:4c:80:1b:86:f0:ac:e6:64:8f:aa:63:cc: + 28:49:5c:84:09:b8:0f:31:99:dd:36:d2:42:b5:aa: + df:31:f6:27:ca:c2:4c:50:11:5b:01:94:17:da:2a: + 5c:21:e5:b5:81:23:69:3e:4f:1d:08:48:95:57:30: + 77:96:ae:9b:78:87:10:e4:6d:90:e8:78:ad:19:41: + 3d:b8:91:1c:b6:04:78:52:e5:e4:3f:28:df:01:13: + da:aa:cb:24:cf:f5:93:f9:02:b8:c5:dc:47:fb:79: + e5:de:9e:19:b3:28:ab:2d:bd:73:48:0f:71:0a:b6: + 81:5a:6d:02:6d:9c:c8:c3:14:d5:82:bf:19:b8:d0: + 6f:58:32:6c:76:91:f3:07:6b:25:4a:59:f4:2d:c9: + 8d:da:ee:cc:30:5b:5b:d8:f3:0d:63:28:8d:9c:df: + 21:b5:3a:41:e0:55:d0:5f:f1:32:45:0b:6b:40:b6: + d8:43:0c:7b:28:3d:2d:7c:40:19:a2:e0:d6:a2:0b: + 32:65:a3:81:e9:1c:e5:6a:f6:61:7c:66:fa:c6:10: + bf:5d:1d:d9:c1:1a:67:fb:a0:43:15:ff:f5:40:5a: + 0c:8a:4b:48:38:d5:c7:77:48:19:f7:21:de:73:17: + 97:cf:03:d7:c3:84:22:38:ae:f2:be:d2:61:af:37: + 38:31:41:01:97:58:93:ba:80:da:bb:00:33:a8:2b: + 98:34:80:8b:00:1e:83:02:c4:26:3f:5c:51:a9:29: + e3:ac:b1:36:31:57:87:43:94:57:3a:17:f4:6d:34: + bf:23:b6:a2:56:d2:b7:72:7e:35:34:d9:58:46:c1: + 64:2d:3f:e7:ff:e4:fd:42:11:d9:04:98:ba:9d:88: + ec:e7:ae:bb:11:42:fd:00:cb:24:17:27:94:2c:a0: + 34:df:18:8b:7a:bc:39:55:6c:02:3b:44:cf:a4:42: + f3:e3:81:5b:d6:90:8e:78:d7:3f:4c:ef:6c:de:4d: + 7e:41:ce:87:8f:c0:38:a4:57:05:63:32:85:c3:de: + 88:aa:8c:0b:04:df:c3:86:64:4c:19:91:e1:e4:b2: + f8:f6:f3:fe:93:c3:3e:c1:b1:74:b4:72:ff:88:94: + 8d:34:a3:b0:9d:55:aa:fe:bc:bc:41:55:49:8a:f1: + ee:dd:fa:0e:a1:fa:b9:71:a7:d5:fc:b7:fc:ab:c2: + af:8f:bd:6e:48:ec:54:f0:f8:a8:b4:d7:6c:11:0e: + f9:16:ab + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + AA:3C:0D:95:CD:14:0A:9C:A5:2D:09:6E:EE:5B:43:A9:AF:3F:6E:54 + Signature Algorithm: sha1WithRSAEncryption + a3:ec:06:1b:66:b3:cb:a3:12:38:ef:30:dc:a6:a1:fc:d3:52: + d0:73:c8:a9:4d:0b:8e:02:2a:08:a6:4f:55:41:2f:46:2b:cf: + e9:04:07:9d:42:47:0d:88:64:1f:39:ae:d7:9b:30:43:47:f9: + ba:96:a8:2f:7a:6e:4b:22:9c:65:c7:9c:8c:c6:d2:f2:5f:a9: + fd:de:eb:9e:7a:13:b8:22:0c:59:15:90:ba:65:b7:08:3d:dd: + 2e:e2:09:be:47:53:25:0a:8c:d3:e0:78:e9:1a:15:8e:32:b2: + 5f:76:e1:68:3c:2f:33:3f:38:17:ff:3b:ad:43:b7:0e:87:08: + 97:6b:8d:a7:6c:3b:de:1a:18:3d:5b:74:0b:87:03:8a:49:b0: + 22:84:2a:72:f1:01:c3:b5:55:9e:4a:56:c1:96:6c:ba:9c:eb: + 58:ce:4e:53:fd:b8:99:02:c1:d5:62:ef:b5:44:73:1c:c6:4f: + 26:f9:8d:6b:e9:58:be:3c:4a:56:ef:65:6a:f5:71:1c:3b:8e: + f4:ae:43:44:ab:26:80:41:da:a9:6b:9b:63:49:bc:39:76:3b: + 1e:fe:a5:24:0e:4c:59:51:9d:47:c4:ce:2b:90:65:e8:f8:ae: + ab:aa:14:cc:d2:4a:cf:85:20:40:dd:80:49:ea:7c:98:04:ee: + 57:41:e6:bc:13:fc:28:5e:08:5c:ee:fa:1b:72:ea:80:e8:ba: + 7e:d6:34:eb:fc:88:f1:16:42:b2:bb:22:9c:e0:36:84:23:f5: + 20:86:dc:38:55:89:dc:0e:67:7c:c7:bb:2f:36:25:bc:ca:be: + 2b:1c:79:26:79:2b:49:17:3c:76:02:cf:f9:e3:8a:3f:15:69: + 2c:12:5c:99:93:85:11:c8:90:68:d6:f1:8d:87:30:bf:0d:ec: + 89:9a:f4:48:cc:26:95:c7:65:cd:30:cc:d0:93:c3:80:3f:ad: + a6:fa:7c:88:82:53:0e:9b:16:c3:dd:27:9a:d0:99:05:fb:2d: + d0:e6:fa:08:92:46:ee:dd:44:9d:56:b2:95:52:99:db:5a:20: + 16:c9:a7:a3:0b:a3:c5:d8:0a:b7:c2:cf:f7:95:a4:df:4c:f9: + 2f:69:a0:27:6e:0f:85:3e:76:b4:3d:6b:f7:4a:de:1a:de:a4: + d3:01:91:f1:44:59:44:2c:93:15:52:99:da:6e:93:b8:da:54: + b5:06:ff:82:9b:cf:57:0c:7d:06:6b:ff:ce:b9:c9:47:62:c9: + 15:f4:67:4e:57:12:74:d7:b5:31:53:cc:eb:d7:05:4d:34:58: + a9:5d:33:85:2d:72:6f:12:99:7e:60:63:27:05:74:8b:85:0c: + 0b:f9:b3:b4:e7:f6:4e:4b +-----BEGIN CERTIFICATE----- +MIIFBzCCAu+gAwIBAgIBCTANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUxMFoYDzI1 +MTgxMTIxMjIyNTEwWjAnMQswCQYDVQQGEwJTRTEYMBYGA1UEAwwPd3d3LnRlc3Qu +aDVsLnNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu8qFnD1rWiEb +LIQ1SDe8E2KT/3u+SUDiNrV6VKTjD7GHKd5rfYbstiXFnNwTBldMgBuG8KzmZI+q +Y8woSVyECbgPMZndNtJCtarfMfYnysJMUBFbAZQX2ipcIeW1gSNpPk8dCEiVVzB3 +lq6beIcQ5G2Q6HitGUE9uJEctgR4UuXkPyjfARPaqsskz/WT+QK4xdxH+3nl3p4Z +syirLb1zSA9xCraBWm0CbZzIwxTVgr8ZuNBvWDJsdpHzB2slSln0LcmN2u7MMFtb +2PMNYyiNnN8htTpB4FXQX/EyRQtrQLbYQwx7KD0tfEAZouDWogsyZaOB6RzlavZh +fGb6xhC/XR3ZwRpn+6BDFf/1QFoMiktIONXHd0gZ9yHecxeXzwPXw4QiOK7yvtJh +rzc4MUEBl1iTuoDauwAzqCuYNICLAB6DAsQmP1xRqSnjrLE2MVeHQ5RXOhf0bTS/ +I7aiVtK3cn41NNlYRsFkLT/n/+T9QhHZBJi6nYjs5667EUL9AMskFyeULKA03xiL +erw5VWwCO0TPpELz44Fb1pCOeNc/TO9s3k1+Qc6Hj8A4pFcFYzKFw96IqowLBN/D +hmRMGZHh5LL49vP+k8M+wbF0tHL/iJSNNKOwnVWq/ry8QVVJivHu3foOofq5cafV +/Lf8q8Kvj71uSOxU8PiotNdsEQ75FqsCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNV +HQ8EBAMCBeAwHQYDVR0OBBYEFKo8DZXNFAqcpS0Jbu5bQ6mvP25UMA0GCSqGSIb3 +DQEBBQUAA4ICAQCj7AYbZrPLoxI47zDcpqH801LQc8ipTQuOAioIpk9VQS9GK8/p +BAedQkcNiGQfOa7XmzBDR/m6lqgvem5LIpxlx5yMxtLyX6n93uueehO4IgxZFZC6 +ZbcIPd0u4gm+R1MlCozT4HjpGhWOMrJfduFoPC8zPzgX/zutQ7cOhwiXa42nbDve +Ghg9W3QLhwOKSbAihCpy8QHDtVWeSlbBlmy6nOtYzk5T/biZAsHVYu+1RHMcxk8m ++Y1r6Vi+PEpW72Vq9XEcO470rkNEqyaAQdqpa5tjSbw5djse/qUkDkxZUZ1HxM4r +kGXo+K6rqhTM0krPhSBA3YBJ6nyYBO5XQea8E/woXghc7vobcuqA6Lp+1jTr/Ijx +FkKyuyKc4DaEI/Ughtw4VYncDmd8x7svNiW8yr4rHHkmeStJFzx2As/544o/FWks +ElyZk4URyJBo1vGNhzC/DeyJmvRIzCaVx2XNMMzQk8OAP62m+nyIglMOmxbD3Sea +0JkF+y3Q5voIkkbu3USdVrKVUpnbWiAWyaejC6PF2Aq3ws/3laTfTPkvaaAnbg+F +Pna0PWv3St4a3qTTAZHxRFlELJMVUpnabpO42lS1Bv+Cm89XDH0Ga//OuclHYskV +9GdOVxJ017UxU8zr1wVNNFipXTOFLXJvEpl+YGMnBXSLhQwL+bO05/ZOSw== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/https.key b/third_party/heimdal/lib/hx509/data/https.key new file mode 100644 index 0000000..59d7bfd --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/https.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQC7yoWcPWtaIRss +hDVIN7wTYpP/e75JQOI2tXpUpOMPsYcp3mt9huy2JcWc3BMGV0yAG4bwrOZkj6pj +zChJXIQJuA8xmd020kK1qt8x9ifKwkxQEVsBlBfaKlwh5bWBI2k+Tx0ISJVXMHeW +rpt4hxDkbZDoeK0ZQT24kRy2BHhS5eQ/KN8BE9qqyyTP9ZP5ArjF3Ef7eeXenhmz +KKstvXNID3EKtoFabQJtnMjDFNWCvxm40G9YMmx2kfMHayVKWfQtyY3a7swwW1vY +8w1jKI2c3yG1OkHgVdBf8TJFC2tAtthDDHsoPS18QBmi4NaiCzJlo4HpHOVq9mF8 +ZvrGEL9dHdnBGmf7oEMV//VAWgyKS0g41cd3SBn3Id5zF5fPA9fDhCI4rvK+0mGv +NzgxQQGXWJO6gNq7ADOoK5g0gIsAHoMCxCY/XFGpKeOssTYxV4dDlFc6F/RtNL8j +tqJW0rdyfjU02VhGwWQtP+f/5P1CEdkEmLqdiOznrrsRQv0AyyQXJ5QsoDTfGIt6 +vDlVbAI7RM+kQvPjgVvWkI541z9M72zeTX5BzoePwDikVwVjMoXD3oiqjAsE38OG +ZEwZkeHksvj28/6Twz7BsXS0cv+IlI00o7CdVar+vLxBVUmK8e7d+g6h+rlxp9X8 +t/yrwq+PvW5I7FTw+Ki012wRDvkWqwIDAQABAoICAQCUxRFqQGIeieGsN6S6bKUL +umnC2XZbNBLCAq1CB0p2sU6CBdmkHVLDzlKqPNK5kEljp+sUGfV/ryzuWNuFmsxj +orQuuFU+y/3bS938B6VohNrOB6HQM1FeHXbVx9Qt1S7YFPbMDCx7YUMsVXGHX4Er +Zf2JnaiMPFo4MIXNUOc9zTAwNSHOCbuO2NZ2BXhPqi9VWHiSKfTIkvmLLGnIF7EP +YmRMd18skvV8ftuxaHzpUpl/B2leNrwkhuVAeEqXh4HhEC7YRZvvp0CxM4PkjUj7 +AO4EU33CylkE2ODZP/2cy/2xyF5891Jkf6ePmI2Q3Ev1pz4QvjqlrUB3vGForfXa +4fLUY+UjmIUPrfF81qryfVbie96wcXIKLEa9osnd/vSJLvs5jrKtpuN1z2lsonz+ +kwwV3lBVeL+DtBJnpGV0qHGaa0GFxjtQKtVPm2HMjPpk0oUh1lAnv4rfdxR0QQIP +JWhYTt6TfqvClmvKKNuu1O8WGw7ngpUniqenWvHXmgnZtfuVMUvjn55nPWSyV2gf +r1qRSYZQKlgzCOrCvX1+tXpRfsYqdQccxgBnxrnXTBknwvIEbFbK/QrLnfUnskuQ +GHbTJUsM3wXChFsx3l4HsxuJG8hbvk5ayX64R8WKzw4tcE78b+vII489GjjuSqdp +L5uniS8kOO99OqZydUiYeQKCAQEA+ALfEEa70OzH5rJxGEbQu34LB3rQTMGONKrc +dbdO2MWfsnIJsmybSYOH1YHT2DdUe9aQUNvlu8CVQKEElyG3YPHDR2a0/9roMmy+ +89vw0OScpqjdhl6ULiyzJGM0f23HfbpugBNRhAdrSK02aPDQrenw8Yuk9abhFi+k +V3VOd+q3Vx9QZ+5BIugqBnWr+2P7tCUxr5sjp5Srj3iyEzH24Yt5OEGPq5GuM2T1 +xYWmjJ5DkJEh5lG1/aeYjZAj4vHFkUZMnIH/A9EYcZG7cHXifwT1/o/SCRazLK1u +yTV5fJ2Cj5Fc4AtbNzR6nt8nQ3yYOpU/jiNRZZ3rz/PIMksTFwKCAQEAwdcRlA9u +mDkKQF2xcyFbdjE+FBz4ZdenpjBtoCOLlDJpOhC+rc7meCbnWfwV52dmMOEJVjj8 +y/8Aa2+ZAIGm1GfFaYxR0kdqoiAmbNdUtqqIS0gqOngAZ3kgDBxWCW7vEtggE9wS +84Nb+2OrhuqxhEo4vJAtlqDLo8ajjgg1iwIrtjfuFGJsBfLiM/AR0E1ZUi6X+FDW +StGZfzwM9/3VNrJ2yzVXy1VKzS6nzX5OjzDlbdDXHl0XbEKXwkSMXrkfPCvqJmy1 +R9Hiz4ajYnEBJ47SPuV6vfivV591HKEdVWGgS9ezh2wAG1yHUATlUHjFuaTjYJO1 +efc5YXe3kFTljQKCAQEAz//4fHoWQp6S+NRnLWkW3mhTb658zCL41QsHYmKeagc0 +bEBgCZg0lG8PmO0NcqTU4heNaYNDJTfa9R0V8HqChXe9w0BMRNifLMsvSu4HBer1 +xoCRaYQg2qj6hWX+PXEggj29NwT8tLJUM9uxakmtem5dePcZHj0bQbQrLH5hlQjx +Qswsbz3OuyvjMw+1cVzlWKxpA1IlkQKK8ATVtGuPFpIW1CuIBuhjJQ9jYIk6qWyC +Vdiiibu12kqZEwD0V/1VKQXAcvJDojvXOEh031i+4LCUby7HhH/ZPXsnEvEaNn0T +Zr0PG4fqtF37CQs2rs7sDRXm+5p7RbIwd3OJT0TPeQKCAQBObUn7cdL5W/q92Cq3 +vkNXKs1HLgGCkyKNpwJzzG3o5AyXJbdAc3nkGzl3uvrRyZAbLrGsZRpDH0V4Morh +HZP2VJYXAmMIhUSrm/5wAx+PWKgUbXpIdc0UEHna7IwS/QNVyIQSBPTV+cv5hnYb +/FEeiTkzcdJAI4bBGNmL2d5wA8zTyQVW0guKzJ6hDPzoHqOJELkECxDo7K0CQbWt +kNH3c3WE+mwvJK9DHSFfjz8RyGLLb7fZ3Shg8QCd5UY1/QiaO9pc+ZbPHCh8dqkc +Z0RkUPDX6dkji77F4QptLvLDXOCSTw+gNx5D88f7pD9zs6msVv54UMsYMeLRgLKQ +fwjxAoIBAQD3C6bhnfTvlphLX+Fq9ObNJNNIYm5+k5cWjgAYJG9ZbC/hbVE3ZUuL +kYynfu56rA73yb1TBJswpem1tEwDRCUfuEcgIWmjlKdQOMqVaW3EtZDDZpJyZJpQ +Vf4P46WCsM8pzDK2eYsy3IHRhJgrDMu+cLNOtq/7e1zeOtmPzutuZm5eo9KP7jJ2 +bse1S5e5j2VwOeyHW5wUGer99JizbbcoSn4GkejRTj8I+SHsOu1kQzAV3pQCcvJe +4Kk7itN65RsZOxh5BShk+X3TIna8QholzxuqSi9aZdBUouUWXYHpM8ch8UDEXCy+ +PJKGZjLpgXkldTcRw00N0NRePp73WR86 +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/j.pem b/third_party/heimdal/lib/hx509/data/j.pem new file mode 100644 index 0000000..45ae8e8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/j.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN +MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g +Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz +MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV +BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC +cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 +52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL +yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 +agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi +MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA +UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR +/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE +CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ +S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC +SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG +A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj +grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG +SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg +HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R +8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M +Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 +IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih +bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/kdc.crt b/third_party/heimdal/lib/hx509/data/kdc.crt new file mode 100644 index 0000000..a92fcc0 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/kdc.crt @@ -0,0 +1,122 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8 (0x8) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:09 2019 GMT + Not After : Nov 21 22:25:09 2518 GMT + Subject: C=SE, CN=kdc + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:73:ec:58:67:7a:65:30:ab:19:15:a1:bf:1e: + de:db:e5:4a:92:f0:99:8a:eb:02:6d:e4:31:1a:c7: + 4d:07:57:b1:82:9e:d2:d2:c7:f3:0b:b2:82:61:5c: + ba:38:c3:54:e9:e1:be:6b:5f:0d:22:62:2b:cb:d5: + 34:0e:63:0b:50:8a:8b:b3:be:6a:e1:85:dc:b1:28: + 13:ee:dd:6e:40:d5:48:1d:eb:aa:04:0b:e7:c8:1c: + 6d:60:54:b6:cc:be:52:5a:88:22:ce:07:2d:3f:cb: + fc:00:ab:8b:a5:e7:32:8e:b1:8b:03:d8:81:a2:69: + d4:9f:3a:ff:da:b5:e3:0d:e3:21:54:29:cb:61:ba: + 16:13:94:97:1b:72:24:6d:da:d7:d9:35:b1:57:f1: + 3b:9d:ee:90:76:4e:58:1f:4e:76:12:c6:89:2a:54: + bf:e8:53:5a:de:05:79:93:0b:41:2c:03:c5:30:58: + a8:e6:57:08:f9:47:7c:c0:3a:5c:eb:1b:33:68:52: + 02:19:08:e6:35:48:05:a7:51:22:89:1c:1e:c8:0b: + 55:73:b2:c9:75:f9:74:aa:de:5e:3a:54:f8:96:47: + cf:25:2d:75:e7:71:74:31:91:17:85:44:89:8a:16: + 88:ca:12:dd:0e:36:4d:e5:af:b3:db:d3:7c:53:8d: + 7a:08:69:92:72:81:c8:13:c7:71:96:8f:2d:54:98: + c9:63:10:26:be:59:8f:db:82:47:c1:29:c6:28:7f: + a0:16:bf:85:a2:eb:2f:2f:46:86:6b:77:1f:31:30: + d4:52:35:32:09:16:cd:48:ec:3c:4c:2c:03:e5:b9: + 90:e9:f7:b4:7d:97:91:31:27:4e:df:b6:bd:b6:ec: + ca:47:16:00:58:e9:87:4f:20:af:ef:4c:34:42:5b: + 3e:28:aa:cd:39:75:3b:6f:7c:b9:7b:50:76:67:25: + 31:46:f5:34:aa:c6:5a:22:77:b5:9d:6d:88:4d:f1: + e6:e7:ca:d2:d8:70:10:58:39:58:0f:ce:8d:b3:4d: + e4:f4:80:ca:31:75:3c:38:61:6c:d9:17:d2:aa:72: + f9:e0:ac:86:ab:33:16:84:e8:c8:de:58:9d:78:ac: + f1:2a:64:b8:e3:f2:cb:20:42:dd:f9:bd:2e:c2:84: + 6e:11:34:76:a5:c5:54:c5:51:9b:cb:85:d1:05:82: + 1c:33:d5:95:18:ad:4c:94:d2:7b:4f:72:23:ff:c1: + 4b:a2:ea:1a:3a:18:c2:f5:c8:08:76:00:12:25:e5: + ee:30:b9:8d:2f:0f:95:3d:70:ac:6a:eb:d8:c5:71: + 9a:cf:a9:a6:6a:ce:45:07:a4:41:de:85:fb:ad:e0: + 39:0b:6f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + Signing KDC Response + X509v3 Subject Key Identifier: + 62:AF:D5:17:E4:9F:2A:8D:8A:CA:2B:05:E1:25:66:BB:61:03:77:EA + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: sha1WithRSAEncryption + 41:29:9f:70:6b:36:28:cc:86:e1:4d:ae:25:34:b1:24:ab:f8: + 03:de:28:da:d1:13:8e:03:d3:5a:57:72:69:f9:04:1c:e0:1d: + 14:91:c7:a0:8b:ab:c7:61:6e:4e:86:2a:2a:40:22:10:10:58: + 0c:18:95:eb:d2:15:18:35:3c:fc:42:25:1a:dc:03:cb:ba:f3: + 81:80:d2:45:4e:c6:90:11:2f:e9:db:76:9a:e3:1d:0c:04:dc: + fb:d9:ec:bd:48:38:66:78:d6:52:c2:bc:ae:20:9b:1d:87:28: + 9f:38:fa:db:8f:17:1f:3e:29:85:17:a0:95:bd:72:88:0c:93: + 88:ba:8e:31:67:2b:03:b0:bf:3a:7e:e4:e2:82:f7:6c:36:1a: + d1:8e:7c:87:63:17:e4:68:7f:4b:e7:dc:40:b5:02:5a:62:be: + 54:ee:11:30:39:80:2a:c0:3e:8f:3b:67:cb:9d:9f:ee:c1:ea: + f1:4c:e8:55:24:6a:73:84:ef:82:ca:99:ec:84:05:5e:82:a1: + 52:40:5e:71:10:c9:c3:9b:18:ce:7f:50:db:8a:49:d4:b6:b9: + 5e:ef:13:4c:e8:be:76:2b:cc:f9:eb:9e:9b:4b:29:8e:ee:1c: + e5:bd:08:f0:50:63:e2:c3:94:20:2f:fe:cb:6a:ed:2b:2a:e2: + 51:44:3d:06:d1:b4:43:26:43:07:4d:c9:e1:4f:9d:3d:0f:a6: + 74:93:ff:51:74:c8:aa:2d:76:ab:93:6f:84:47:2d:70:37:d2: + 21:f0:cb:4d:a5:8b:df:91:4b:95:f0:ba:fe:d9:fc:f2:ed:b5: + e7:91:03:5a:ad:12:43:f3:ba:c8:a7:51:34:9b:40:bd:71:39: + af:b1:9f:e4:9f:3f:1b:27:a5:84:43:a2:c3:3f:52:63:a8:bf: + 8b:59:82:53:b5:26:64:16:73:90:f8:7b:7d:ce:f6:41:b6:8b: + 81:56:90:c2:ff:46:46:8f:63:3d:95:d9:f0:49:73:37:d9:14: + 2b:26:95:ac:19:29:1d:cb:c2:03:d7:36:4e:4a:39:3e:51:02: + de:aa:dc:6b:77:a8:57:ba:50:21:0e:8e:b7:48:bc:44:fa:45: + db:c9:bb:72:ea:e4:2a:7a:35:75:3c:68:29:5d:b9:57:0b:d3: + 2e:2c:4f:01:1b:f0:21:0c:fc:95:17:b7:40:be:aa:0c:f9:04: + 60:6a:d1:54:0d:b9:68:d7:e9:7a:f4:96:ad:f1:a0:15:15:c2: + 51:61:44:5f:0e:bb:98:d1:81:9f:c1:81:d6:e2:26:d5:11:56: + d2:cd:0f:9c:6b:69:f0:78:24:ff:bf:df:02:2b:0d:d1:83:5b: + 14:4d:c0:e2:80:47:65:2b +-----BEGIN CERTIFICATE----- +MIIFWzCCA0OgAwIBAgIBCDANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwOVoYDzI1 +MTgxMTIxMjIyNTA5WjAbMQswCQYDVQQGEwJTRTEMMAoGA1UEAwwDa2RjMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0XPsWGd6ZTCrGRWhvx7e2+VKkvCZ +iusCbeQxGsdNB1exgp7S0sfzC7KCYVy6OMNU6eG+a18NImIry9U0DmMLUIqLs75q +4YXcsSgT7t1uQNVIHeuqBAvnyBxtYFS2zL5SWogizgctP8v8AKuLpecyjrGLA9iB +omnUnzr/2rXjDeMhVCnLYboWE5SXG3IkbdrX2TWxV/E7ne6Qdk5YH052EsaJKlS/ +6FNa3gV5kwtBLAPFMFio5lcI+Ud8wDpc6xszaFICGQjmNUgFp1EiiRweyAtVc7LJ +dfl0qt5eOlT4lkfPJS1153F0MZEXhUSJihaIyhLdDjZN5a+z29N8U416CGmScoHI +E8dxlo8tVJjJYxAmvlmP24JHwSnGKH+gFr+FousvL0aGa3cfMTDUUjUyCRbNSOw8 +TCwD5bmQ6fe0fZeRMSdO37a9tuzKRxYAWOmHTyCv70w0Qls+KKrNOXU7b3y5e1B2 +ZyUxRvU0qsZaIne1nW2ITfHm58rS2HAQWDlYD86Ns03k9IDKMXU8OGFs2RfSqnL5 +4KyGqzMWhOjI3lideKzxKmS44/LLIELd+b0uwoRuETR2pcVUxVGby4XRBYIcM9WV +GK1MlNJ7T3Ij/8FLouoaOhjC9cgIdgASJeXuMLmNLw+VPXCsauvYxXGaz6mmas5F +B6RB3oX7reA5C28CAwEAAaOBmDCBlTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAS +BgNVHSUECzAJBgcrBgEFAgMFMB0GA1UdDgQWBBRir9UX5J8qjYrKKwXhJWa7YQN3 +6jBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgDRsLVEVTVC5INUwuU0WhIDAeoAMC +AQGhFzAVGwZrcmJ0Z3QbC1RFU1QuSDVMLlNFMA0GCSqGSIb3DQEBBQUAA4ICAQBB +KZ9wazYozIbhTa4lNLEkq/gD3ija0ROOA9NaV3Jp+QQc4B0Ukcegi6vHYW5Ohioq +QCIQEFgMGJXr0hUYNTz8QiUa3APLuvOBgNJFTsaQES/p23aa4x0MBNz72ey9SDhm +eNZSwryuIJsdhyifOPrbjxcfPimFF6CVvXKIDJOIuo4xZysDsL86fuTigvdsNhrR +jnyHYxfkaH9L59xAtQJaYr5U7hEwOYAqwD6PO2fLnZ/uwerxTOhVJGpzhO+Cypns +hAVegqFSQF5xEMnDmxjOf1DbiknUtrle7xNM6L52K8z5656bSymO7hzlvQjwUGPi +w5QgL/7Lau0rKuJRRD0G0bRDJkMHTcnhT509D6Z0k/9RdMiqLXark2+ERy1wN9Ih +8MtNpYvfkUuV8Lr+2fzy7bXnkQNarRJD87rIp1E0m0C9cTmvsZ/knz8bJ6WEQ6LD +P1JjqL+LWYJTtSZkFnOQ+Ht9zvZBtouBVpDC/0ZGj2M9ldnwSXM32RQrJpWsGSkd +y8ID1zZOSjk+UQLeqtxrd6hXulAhDo63SLxE+kXbybty6uQqejV1PGgpXblXC9Mu +LE8BG/AhDPyVF7dAvqoM+QRgatFUDblo1+l69Jat8aAVFcJRYURfDruY0YGfwYHW +4ibVEVbSzQ+ca2nweCT/v98CKw3Rg1sUTcDigEdlKw== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/kdc.key b/third_party/heimdal/lib/hx509/data/kdc.key new file mode 100644 index 0000000..1984f20 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/kdc.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDRc+xYZ3plMKsZ +FaG/Ht7b5UqS8JmK6wJt5DEax00HV7GCntLSx/MLsoJhXLo4w1Tp4b5rXw0iYivL +1TQOYwtQiouzvmrhhdyxKBPu3W5A1Ugd66oEC+fIHG1gVLbMvlJaiCLOBy0/y/wA +q4ul5zKOsYsD2IGiadSfOv/ateMN4yFUKcthuhYTlJcbciRt2tfZNbFX8Tud7pB2 +TlgfTnYSxokqVL/oU1reBXmTC0EsA8UwWKjmVwj5R3zAOlzrGzNoUgIZCOY1SAWn +USKJHB7IC1Vzssl1+XSq3l46VPiWR88lLXXncXQxkReFRImKFojKEt0ONk3lr7Pb +03xTjXoIaZJygcgTx3GWjy1UmMljECa+WY/bgkfBKcYof6AWv4Wi6y8vRoZrdx8x +MNRSNTIJFs1I7DxMLAPluZDp97R9l5ExJ07ftr227MpHFgBY6YdPIK/vTDRCWz4o +qs05dTtvfLl7UHZnJTFG9TSqxloid7WdbYhN8ebnytLYcBBYOVgPzo2zTeT0gMox +dTw4YWzZF9KqcvngrIarMxaE6MjeWJ14rPEqZLjj8ssgQt35vS7ChG4RNHalxVTF +UZvLhdEFghwz1ZUYrUyU0ntPciP/wUui6ho6GML1yAh2ABIl5e4wuY0vD5U9cKxq +69jFcZrPqaZqzkUHpEHehfut4DkLbwIDAQABAoICAH37+GGEfH55M7E27b+D1hD2 +blDMH88LZL6sz0yILLEJ8l/bIHxggLS8fugJWoniFCVJ/7udxMy1uBo298TflmKv +szA+jRNx7TkyHitDTZn5sBMvOWiNsLERSEj1K68jm22RDT5X2sPQ8peEl88GrcZe +zHtXs0H53kaYumTXmuczg0yYhxkVUUodynZbxcW+KK8iOLXpCC8K3CINJbxO+X55 +pO+tYnFgEfwR1vq3fk/3RJi7+3vxRhiLA2KsuE9CYT2SdmiQjcfmtl/Z0agfHfS9 +vHyHQd6QWbidYJg9m/jo4JRAL/cyqu1VlIw4mXJR8514kzaFO324nbrQDqxDIO7v +jvFL9SjnReVxUjfnQ7W5BackMn7rxaa4gGm3P1ZAYY0DrSBThlleKkuGhuOHaRFG +P3uPjfar4ybGnozqCrVpuFJLOtQocdJpPBdQtS0WuE3sMOUkOV9HfqxusnS074on +2qn3Yy7PhKBfqBYKVqd0l99QHjwr3/0VLjDpnVvvFZFDcH9uL9daD+JfZj3aaGdv +bmPGwO4svlVEDzfScoI3NnReGEH/bgmdbaPBcSiX42NX12XHWZ55d9grQlJWdSw5 +W8+Dqy86/gCA0VJ4fKaJM5ZGbngOwjgCYZkNHyFo42/zTFSI1S9PiWTNAHPGqZyD +nOjpXLR1N+dk0yBwpOQhAoIBAQDy5BeFO+mqp3NWHZXVoy+THqumajCR5AjEsbFl +aWosL99Zk/avfA7G8orHXrAj1XEsGxkFtCnRUlg35LqMYK1tYYIk5NqdFCAeQUOe +7NgNlicjiKG+a69bQ5TOtgmtdhIh+Uu1yNgbNelWJFizyxoFFFX7jp52utNWix3r +x6LfTZmNUQqbFetuMKln0WzVwa0uqezzvxZ7oPLVeEc4LT7wtKTPDf6/VTfoeLoO +JvvMb5cnKZGQmpC8Jub5mRkEFcUIGmbKM2G9sRFPNt2Lh08xVCDXEJSFZPiBpLGP +6TvJ9DkKEd0Shj0VdnV9304XkcFdfjWIDHlfLJnzwn++Wx9rAoIBAQDcwdUVfsFE +kVJtdWjtAAj1uSEAPDiggfDhTlOsJMQ3U7PlmdgiafNMKpzmLwqH8Pe5IK4Z9KZ1 +pT+d89udXGOUXhqU6kvxfVu3S7skE9r5DYS/kg7xXJerir+fGsZ5lGDqz90xYxhp +ect5jOtsRxDlI7Vg5guUp30h8FsAdrP42jiUZxy4AkBdVuyqKAbl5ZtnV4eCk3fV +iLyVmD27I6h8jnvGvPVODjpesuu7XzQe9ZhyAU/7JSsshLKoKIjwZSx77dhfqI9i +pm1cwhKbT7opZa2zuXd1h/nDo4SLOfBRTQ+424NPhfk754HKup+lskXuedlumqhj +z6V8QbfjVRkNAoIBAG+WxQuMC/1AMyfkLbtZ3niLxbaN4MSV7EVZkbOSq5mjYMyJ +wvK6XxudwI55/RhpbjYiOOu66t9lImyDZAUsQWEYRC9pCNrTrTHZMBTqoRQU4ORd +WFngpU6bjNkvHuEXdpsvKk5Y+Jf/u7S8vBfV/p1Iy3vn+Pt5N7Dx9wwkyromr54S +FnpLpr8YEixFNeg6s7LVlKwjJVQlDItwV+ACQYFarMEHn/sNTsM5+9iWpmY0+k+e +tGan7EjU4pbXdHvA+KWRY5oP4x7AI8Ct5zi8MHDsQq4ryuBCFD2TiZQhRjuxPSdY +L6XcEGI06yOqHPmNGDY4zqUzfetw1UX9HK06tgMCggEAF5UZRz+QM9v2Wz0UpWTA +kEdjkBvezL601czBQX13/JUTfa6OmTaKSBOxSSGzVUxXmk40aw9ojN7HSf9X8ZqC +BMJ8wnW5ASYsGwubBUKdvMdF7BUVRZFnnmqnB78bfrdsFwl3jqQQYowhQW3dZGa/ +FktXP++zQwEVa/+6KPWFSks9ihTty3ZqG86CX7cA7aQ2kraWAkvwnD4ML0rhJVGs +2Ql7jYJ4DguVDrK8XfrQnZIM4/jh62lQEGRolXAnGM8mDmMdHzLphldTDXqp9C9z +KqLzCGUCruqEsvKP4TOiSX0a9dt1TpR4SH71rYt8LH473DrmEFuzK15uRjTbCQz5 +LQKCAQEA0hy4cQ07D32jcaN0xQ40Av8fO3dDwgcrSrTfBIk2naa7w9ssshhIFCWT +pXC68HjbXJAm+FUmzp1wyj1ss+1CWSHD9sWPUwJj/T0fGSfpPKC5UpuvSMXRsych +DX2WwGIExAHDF1vHlhc9mn26IZo+oZPA1X2SqurKz7RYuDXpiAdMQx1azjMuzQF0 +xBPoILyT4ZgDW1YCs87QF+Rk7x6S1HePF0dCDo6vke34ydZe+by/UnLhiGtbTtI7 +uBLJkF39dTie3vP+2I6eQbV+RUhhf1MGHSf8tVw7sIdtTbB3b7pEemMQhpyGJ02P +RCBsiAswkZ1vTsDII1BKYPknuvgH9g== +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/key.der b/third_party/heimdal/lib/hx509/data/key.der new file mode 100644 index 0000000..e7c665e Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/key.der differ diff --git a/third_party/heimdal/lib/hx509/data/key2.der b/third_party/heimdal/lib/hx509/data/key2.der new file mode 100644 index 0000000..fe3f413 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/key2.der differ diff --git a/third_party/heimdal/lib/hx509/data/mkcert.sh b/third_party/heimdal/lib/hx509/data/mkcert.sh new file mode 100755 index 0000000..c06528d --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/mkcert.sh @@ -0,0 +1,83 @@ +#! /bin/bash + +set -e + +DAYS=182500 + +key() { + local key=$1; shift + + if [ ! -f "${key}.pem" ]; then + openssl genpkey \ + -paramfile <(openssl ecparam -name prime256v1) \ + -out "${key}.pem" + fi +} + +req() { + local key=$1; shift + local dn=$1; shift + + openssl req -new -sha256 -key "${key}.pem" \ + -config <(printf "[req]\n%s\n%s\n[dn]\nCN_default=foo\n" \ + "prompt = yes" "distinguished_name = dn") \ + -subj "${dn}" +} + +cert() { + local cert=$1; shift + local exts=$1; shift + + openssl x509 -req -sha256 -out "${cert}.pem" \ + -extfile <(printf "%s\n" "$exts") "$@" +} + +genroot() { + local dn=$1; shift + local key=$1; shift + local cert=$1; shift + + exts=$(printf "%s\n%s\n%s\n%s\n" \ + "subjectKeyIdentifier = hash" \ + "authorityKeyIdentifier = keyid" \ + "basicConstraints = CA:true" \ + "keyUsage = keyCertSign, cRLSign" ) + key "$key"; req "$key" "$dn" | + cert "$cert" "$exts" -signkey "${key}.pem" \ + -set_serial 1 -days "${DAYS}" +} + +genee() { + local dn=$1; shift + local key=$1; shift + local cert=$1; shift + local cakey=$1; shift + local cacert=$1; shift + + exts=$(printf "%s\n%s\n%s\n%s\n" \ + "subjectKeyIdentifier = hash" \ + "authorityKeyIdentifier = keyid, issuer" \ + "basicConstraints = CA:false" \ + "keyUsage = digitalSignature, keyEncipherment, dataEncipherment" \ + ) + key "$key"; req "$key" "$dn" | + cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \ + -set_serial 2 -days "${DAYS}" "$@" +} + + +genroot "/C=SE/O=Heimdal/CN=CA secp256r1" \ + secp256r1TestCA.key secp256r1TestCA.cert +genee "/C=SE/O=Heimdal/CN=Server" \ + secp256r2TestServer.key secp256r2TestServer.cert \ + secp256r1TestCA.key secp256r1TestCA.cert +genee "/C=SE/O=Heimdal/CN=Client" \ + secp256r2TestClient.key secp256r2TestClient.cert \ + secp256r1TestCA.key secp256r1TestCA.cert + +cat secp256r1TestCA.key.pem secp256r1TestCA.cert.pem > \ + secp256r1TestCA.pem +cat secp256r2TestClient.cert.pem secp256r2TestClient.key.pem > \ + secp256r2TestClient.pem +cat secp256r2TestServer.cert.pem secp256r2TestServer.key.pem > \ + secp256r2TestServer.pem diff --git a/third_party/heimdal/lib/hx509/data/n0ll.pem b/third_party/heimdal/lib/hx509/data/n0ll.pem new file mode 100644 index 0000000..4b17377 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/n0ll.pem @@ -0,0 +1,47 @@ +https://www.noisebridge.net/pipermail/noisebridge-discuss/2009-September/008400.html + +Jacob Appelbaum jacob at appelbaum.net +Tue Sep 29 22:51:33 PDT 2009 + + +I hope this release will help with confirmation of the bug and with +regression testing. Feel free to use this certificate for anything +relating to free software too. Consider it released into the public +domain of interesting integers. + +-----BEGIN CERTIFICATE----- +MIIGTjCCBbegAwIBAgIDExefMA0GCSqGSIb3DQEBBQUAMIIBEjELMAkGA1UEBhMC +RVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMSkwJwYD +VQQKEyBJUFMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgcy5sLjEuMCwGA1UEChQl +Z2VuZXJhbEBpcHNjYS5jb20gQy5JLkYuICBCLUI2MjIxMDY5NTEuMCwGA1UECxMl +aXBzQ0EgQ0xBU0VBMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl +aXBzQ0EgQ0xBU0VBMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEgMB4GCSqGSIb3 +DQEJARYRZ2VuZXJhbEBpcHNjYS5jb20wHhcNMDkwNzMwMDcxNDQyWhcNMTEwNzMw +MDcxNDQyWjCBnjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAU +BgNVBAcTDVNhbiBGcmFuY2lzY28xFDASBgNVBAoTC05vaXNlYnJpZGdlMSMwIQYD +VQQLExpNb3hpZSBNYXJsaW5zcGlrZSBGYW4gQ2x1YjEnMCUGA1UEAxQeKgB0aG91 +Z2h0Y3JpbWUubm9pc2VicmlkZ2UubmV0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQDPTRdCAI0MQZUxjEAwvF5CtigJdS8ZYdmrTezzRMQcAZVvJ+twB5hPHgXQ +82xJRebeSHpZ8MKTajecAnJPvRQ2JqFwl9T+SyTozSkeYRqFsG+WBoMQE9aJn70H +Z/FC3ptjZ4uW+QbvfJNLavk5MTJ/mFnvzpG+Bc7wgjPYdgZMnwIDAQABo4IDITCC +Ax0wCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgP4MBMG +A1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBStfpIwBXE+eXWUWtE3s5JqXon2 +TzAfBgNVHSMEGDAWgBQOB2DUOckbW12QeyPI0jSdSppGOTAJBgNVHREEAjAAMBwG +A1UdEgQVMBOBEWdlbmVyYWxAaXBzY2EuY29tMHIGCWCGSAGG+EIBDQRlFmNPcmdh +bml6YXRpb24gSW5mb3JtYXRpb24gTk9UIFZBTElEQVRFRC4gQ0xBU0VBMSBTZXJ2 +ZXIgQ2VydGlmaWNhdGUgaXNzdWVkIGJ5IGh0dHBzOi8vd3d3Lmlwc2NhLmNvbS8w +LwYJYIZIAYb4QgECBCIWIGh0dHBzOi8vd3d3Lmlwc2NhLmNvbS9pcHNjYTIwMDIv +MEMGCWCGSAGG+EIBBAQ2FjRodHRwczovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAy +L2lwc2NhMjAwMkNMQVNFQTEuY3JsMEYGCWCGSAGG+EIBAwQ5FjdodHRwczovL3d3 +dy5pcHNjYS5jb20vaXBzY2EyMDAyL3Jldm9jYXRpb25DTEFTRUExLmh0bWw/MEMG +CWCGSAGG+EIBBwQ2FjRodHRwczovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAyL3Jl +bmV3YWxDTEFTRUExLmh0bWw/MEEGCWCGSAGG+EIBCAQ0FjJodHRwczovL3d3dy5p +cHNjYS5jb20vaXBzY2EyMDAyL3BvbGljeUNMQVNFQTEuaHRtbDCBgwYDVR0fBHww +ejA5oDegNYYzaHR0cDovL3d3dy5pcHNjYS5jb20vaXBzY2EyMDAyL2lwc2NhMjAw +MkNMQVNFQTEuY3JsMD2gO6A5hjdodHRwOi8vd3d3YmFjay5pcHNjYS5jb20vaXBz +Y2EyMDAyL2lwc2NhMjAwMkNMQVNFQTEuY3JsMDIGCCsGAQUFBwEBBCYwJDAiBggr +BgEFBQcwAYYWaHR0cDovL29jc3AuaXBzY2EuY29tLzANBgkqhkiG9w0BAQUFAAOB +gQAjzXaLBu+/+RP0vQ6WjW/Pxgm4WQYhecqZ2+7ZFbsUCMJPQ8XE2uv+rIteGnRF +Zr3hYb+dVlfUnethjPhazZW+/hU4FePqmlbTtmMe+zMLThiScyC8y3EW4L4BZYcp +p1drPlZIj2RmSgPQ99oToUk5O6t+LMg1N14ajr9TpM8yNQ== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/nist-data b/third_party/heimdal/lib/hx509/data/nist-data new file mode 100644 index 0000000..7407b80 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/nist-data @@ -0,0 +1,91 @@ +# $Id$ +# id verify cert hxtool-verify-arguments... +# p(ass) f(ail) +# Those id's that end with i are invariants of the orignal test +# +# 4.1 Signature Verification +# +4.1.1 p ValidCertificatePathTest1EE.crt GoodCACert.crt GoodCACRL.crl +4.1.2 f InvalidCASignatureTest2EE.crt BadSignedCACert.crt BadSignedCACRL.crl +4.1.3 f InvalidEESignatureTest3EE.crt GoodCACert.crt GoodCACRL.crl +#4.1.4 p ValidDSASignaturesTest4EE.crt DSACACert.crt DSACACRL.crl +#4.1.5 p ValidDSAParameterInheritanceTest5EE.crl DSAParametersInheritedCACert.crt DSAParametersInheritedCACRL.crl DSACACert.crt DSACACRL.crl +#4.1.6 f InvalidDSASignaturesTest6EE.crt DSACACert.crt DSACACRL.crl +# +# 4.2 Validity Periods +# +4.2.1 f InvalidCAnotBeforeDateTest1EE.crt BadnotBeforeDateCACert.crt BadnotBeforeDateCACRL.crl +4.2.2 f InvalidEEnotBeforeDateTest2EE.crt GoodCACert.crt GoodCACRL.crl +4.2.3 p Validpre2000UTCnotBeforeDateTest3EE.crt GoodCACert.crt GoodCACRL.crl +4.2.4 p ValidGeneralizedTimenotBeforeDateTest4EE.crt GoodCACert.crt GoodCACRL.crl +4.2.5 f InvalidCAnotAfterDateTest5EE.crt BadnotAfterDateCACert.crt BadnotAfterDateCACRL.crl +4.2.6 f InvalidEEnotAfterDateTest6EE.crt GoodCACert.crt GoodCACRL.crl +4.2.7 f Invalidpre2000UTCEEnotAfterDateTest7EE.crt GoodCACert.crt GoodCACRL.crl +#4.2.8 p ValidGeneralizedTimenotAfterDateTest8EE.crt GoodCACert.crt GoodCACRL.crl +# +# 4.4 CRtests +# +4.4.1 f InvalidMissingCRLTest1EE.crt NoCRLCACert.crt +4.4.1i p InvalidMissingCRLTest1EE.crt --missing-revoke NoCRLCACert.crt +4.4.2 f InvalidRevokedEETest3EE.crt GoodCACert.crt InvalidRevokedCATest2EE.crt GoodCACRL.crl RevokedsubCACRL.crl +4.4.2i p InvalidRevokedEETest3EE.crt --missing-revoke GoodCACert.crt InvalidRevokedCATest2EE.crt +4.4.3 f InvalidRevokedEETest3EE.crt GoodCACert.crt GoodCACRL.crl +4.4.3i p InvalidRevokedEETest3EE.crt --missing-revoke GoodCACert.crt +4.4.4 f InvalidBadCRLSignatureTest4EE.crt BadCRLSignatureCACert.crt BadCRLSignatureCACRL.crl +4.4.4i p InvalidBadCRLSignatureTest4EE.crt --missing-revoke BadCRLSignatureCACert.crt +4.4.5 f InvalidBadCRLIssuerNameTest5EE.crt BadCRLIssuerNameCACert.crt BadCRLIssuerNameCACRL.crl +4.4.5i p InvalidBadCRLIssuerNameTest5EE.crt --missing-revoke BadCRLIssuerNameCACert.crt +4.4.6 f InvalidWrongCRLTest6EE.crt WrongCRLCACert.crt WrongCRLCACRL.crl +4.4.7 p ValidTwoCRLsTest7EE.crt TwoCRLsCACert.crt TwoCRLsCAGoodCRL.crl TwoCRLsCABadCRL.crl +4.4.8 f InvalidUnknownCRLEntryExtensionTest8EE.crt UnknownCRLEntryExtensionCACert.crt UnknownCRLEntryExtensionCACRL.crl +4.4.9 f InvalidUnknownCRLExtensionTest9EE.crt UnknownCRLExtensionCACert.crt UnknownCRLExtensionCACRL.crl +4.4.10 f InvalidUnknownCRLExtensionTest10EE.crt UnknownCRLExtensionCACert.crt UnknownCRLExtensionCACRL.crl +4.4.11 f InvalidOldCRLnextUpdateTest11EE.crt OldCRLnextUpdateCACert.crt OldCRLnextUpdateCACRL.crl +4.4.12 f Invalidpre2000CRLnextUpdateTest12EE.crt pre2000CRLnextUpdateCACert.crt pre2000CRLnextUpdateCACRL.crl +#4.4.13-xxx s ValidGeneralizedTimeCRLnextUpdateTest13EE.crt GeneralizedTimeCRLnextUpdateCACert.crt GeneralizedTimeCRLnextUpdateCACRL.crl +4.4.14 p ValidNegativeSerialNumberTest14EE.crt NegativeSerialNumberCACert.crt NegativeSerialNumberCACRL.crl +4.4.15 f InvalidNegativeSerialNumberTest15EE.crt NegativeSerialNumberCACert.crt NegativeSerialNumberCACRL.crl +4.4.16 p ValidLongSerialNumberTest16EE.crt LongSerialNumberCACert.crt LongSerialNumberCACRL.crl +4.4.17 p ValidLongSerialNumberTest17EE.crt LongSerialNumberCACert.crt LongSerialNumberCACRL.crl +4.4.18 f InvalidLongSerialNumberTest18EE.crt LongSerialNumberCACert.crt LongSerialNumberCACRL.crl +# +# +# 4.8 Ceificate Policies +incomplete4.8.2 p AllCertificatesNoPoliciesTest2EE.crt NoPoliciesCACert.crt NoPoliciesCACRL.crl +incomplete4.8.10 p AllCertificatesSamePoliciesTest10EE.crt PoliciesP12CACert.crt PoliciesP12CACRL.crl +incomplete4.8.13 p AllCertificatesSamePoliciesTest13EE.crt PoliciesP123CACert.crt PoliciesP123CACRL.crl +incomplete4.8.11 p AllCertificatesanyPolicyTest11EE.crt anyPolicyCACert.crt anyPolicyCACRL.crl +unknown p AnyPolicyTest14EE.crt anyPolicyCACert.crt anyPolicyCACRL.crl +unknown f BadSignedCACert.crt +unknown f BadnotAfterDateCACert.crt +unknown f BadnotBeforeDateCACert.crt +# +# 4.13 Name Constraints +# +4.13.1 p ValidDNnameConstraintsTest1EE.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.2 f InvalidDNnameConstraintsTest2EE.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.3 f InvalidDNnameConstraintsTest3EE.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.4 p ValidDNnameConstraintsTest4EE.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.5 p ValidDNnameConstraintsTest5EE.crt nameConstraintsDN2CACert.crt nameConstraintsDN2CACRL.crl +4.13.6 p ValidDNnameConstraintsTest6EE.crt nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +4.13.7 f InvalidDNnameConstraintsTest7EE.crt nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +4.13.8 f InvalidDNnameConstraintsTest8EE.crt nameConstraintsDN4CACert.crt nameConstraintsDN4CACRL.crl +4.13.9 f InvalidDNnameConstraintsTest9EE.crt nameConstraintsDN4CACert.crt nameConstraintsDN4CACRL.crl +4.13.10 f InvalidDNnameConstraintsTest10EE.crt nameConstraintsDN5CACert.crt nameConstraintsDN5CACRL.crl +4.13.11 p ValidDNnameConstraintsTest11EE.crt nameConstraintsDN5CACert.crt nameConstraintsDN5CACRL.crl +4.13.12 f InvalidDNnameConstraintsTest12EE.crt nameConstraintsDN1subCA1Cert.crt nameConstraintsDN1subCA1CRL.crl nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.13 f InvalidDNnameConstraintsTest13EE.crt nameConstraintsDN1subCA1Cert.crt nameConstraintsDN1subCA1CRL.crl nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.14 p ValidDNnameConstraintsTest14EE.crt nameConstraintsDN1subCA2Cert.crt nameConstraintsDN1subCA2CRL.crl nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +4.13.15 f InvalidDNnameConstraintsTest15EE.crt nameConstraintsDN3subCA1Cert.crt nameConstraintsDN3subCA1CRL.crl nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +4.13.16 f InvalidDNnameConstraintsTest16EE.crt nameConstraintsDN3subCA1Cert.crt nameConstraintsDN3subCA1CRL.crl nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +4.13.17 f InvalidDNnameConstraintsTest17EE.crt nameConstraintsDN3subCA2Cert.crt nameConstraintsDN3subCA2CRL.crl nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +4.13.18 p ValidDNnameConstraintsTest18EE.crt nameConstraintsDN3subCA2Cert.crt nameConstraintsDN3subCA2CRL.crl nameConstraintsDN3CACert.crt nameConstraintsDN3CACRL.crl +# +# no crl for self issued cert +# +#4.13.19 p ValidDNnameConstraintsTest19EE.crt nameConstraintsDN1SelfIssuedCACert.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +# ?? +4.13.20 f InvalidDNnameConstraintsTest20EE.crt nameConstraintsDN1CACert.crt nameConstraintsDN1CACRL.crl +#4.13.21 p ValidRFC822nameConstraintsTest21EE.crt nameConstraintsRFC822CA1Cert.crt nameConstraintsRFC822CA1CRL.crl +#page 74 +end diff --git a/third_party/heimdal/lib/hx509/data/nist-data2 b/third_party/heimdal/lib/hx509/data/nist-data2 new file mode 100644 index 0000000..491beac --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/nist-data2 @@ -0,0 +1,291 @@ +# 4.1.1 Valid Signatures Test1 - Validate Successfully +0 ValidCertificatePathTest1EE.crt +# 4.1.2 Invalid CA Signature Test2 - Reject - Invalid signature on intermediate certificate +1 InvalidCASignatureTest2EE.crt +# 4.1.3 Invalid EE Signature Test3 - Reject - Invalid signature on end entity certificate +1 InvalidEESignatureTest3EE.crt +# 4.1.4 Valid DSA Signatures Test4 - Reject - Application can not process DSA signatures +1 ValidDSASignaturesTest4EE.crt +# 4.2.1 Invalid CA notBefore Date Test1 - Reject - notBefore date in intermediate certificate is after the current date +1 InvalidCAnotBeforeDateTest1EE.crt +# 4.2.2 Invalid EE notBefore Date Test2 - Reject - notBefore date in end entity certificate is after the current date +1 InvalidEEnotBeforeDateTest2EE.crt +# 4.2.3 Valid pre2000 UTC notBefore Date Test3 - Validate Successfully +0 Validpre2000UTCnotBeforeDateTest3EE.crt +# 4.2.4 Valid GeneralizedTime notBefore Date Test4 - Validate Successfully +0 ValidGeneralizedTimenotBeforeDateTest4EE.crt +# 4.2.5 Invalid CA notAfter Date Test5 - Reject - notAfter date in intermediate certificate is before the current date +1 InvalidCAnotAfterDateTest5EE.crt +# 4.2.6 Invalid EE notAfter Date Test6 - Reject - notAfter date in end entity certificate is before the current date +1 InvalidEEnotAfterDateTest6EE.crt +# 4.2.7 Invalid pre2000 UTC EE notAfter Date Test7 - Reject - notAfter date in end entity certificate is before the current date +1 Invalidpre2000UTCEEnotAfterDateTest7EE.crt +# 4.2.8 Valid GeneralizedTime notAfter Date Test8 - Validate Successfully +0 ValidGeneralizedTimenotAfterDateTest8EE.crt +# 4.3.1 Invalid Name Chaining EE Test1 - Reject - names do not chain +1 InvalidNameChainingTest1EE.crt +# 4.3.2 Invalid Name Chaining Order Test2 - Reject - names do not chain +1 InvalidNameChainingOrderTest2EE.crt +# 4.3.3 Valid Name Chaining Whitespace Test3 - Validate Successfully +0 ValidNameChainingWhitespaceTest3EE.crt +# 4.3.4 Valid Name Chaining Whitespace Test4 - Validate Successfully +0 ValidNameChainingWhitespaceTest4EE.crt +# 4.3.5 Valid Name Chaining Capitalization Test5 - Validate Successfully +0 ValidNameChainingCapitalizationTest5EE.crt +# 4.3.6 Valid Name Chaining UIDs Test6 - Validate Successfully +0 ValidNameUIDsTest6EE.crt +# 4.3.9 Valid UTF8String Encoded Names Test9 - Validate Successfully +0 ValidUTF8StringEncodedNamesTest9EE.crt +# 4.4.1 Missing CRL Test1 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidMissingCRLTest1EE.crt +# 4.4.2 Invalid Revoked CA Test2 - Reject - an intermediate certificate has been revoked. +2 InvalidRevokedCATest2EE.crt +# 4.4.3 Invalid Revoked EE Test3 - Reject - the end entity certificate has been revoked +2 InvalidRevokedEETest3EE.crt +# 4.4.4. Invalid Bad CRL Signature Test4 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidBadCRLSignatureTest4EE.crt +# 4.4.5 Invalid Bad CRL Issuer Name Test5 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidBadCRLIssuerNameTest5EE.crt +# 4.4.6 Invalid Wrong CRL Test6 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidWrongCRLTest6EE.crt +# 4.4.7 Valid Two CRLs Test7 - Validate Successfully +0 ValidTwoCRLsTest7EE.crt +# 4.4.8 Invalid Unknown CRL Entry Extension Test8 - Reject - the end entity certificate has been revoked +2 InvalidUnknownCRLEntryExtensionTest8EE.crt +# 4.4.9 Invalid Unknown CRL Extension Test9 - Reject - the end entity certificate has been revoked +2 InvalidUnknownCRLExtensionTest9EE.crt +# 4.4.10 Invalid Unknown CRL Extension Test10 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidUnknownCRLExtensionTest10EE.crt +# 4.4.11 Invalid Old CRL nextUpdate Test11 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidOldCRLnextUpdateTest11EE.crt +# 4.4.12 Invalid pre2000 CRL nextUpdate Tesst12 - Reject or Warn - status of end entity certificate can not be determined +3 Invalidpre2000CRLnextUpdateTest12EE.crt +# 4.4.13 Valid GeneralizedTime CRL nextUpdate Test13 - Validate Successfully +0 ValidGeneralizedTimeCRLnextUpdateTest13EE.crt +# 4.4.14 Valid Negative Serial Number Test14 - Validate Successfully +0 ValidNegativeSerialNumberTest14EE.crt +# 4.4.15 Invalid Negative Serial Number Test15 - Reject - the end entity certificate has been revoked +2 InvalidNegativeSerialNumberTest15EE.crt +# 4.4.16 Valid Long Serial Number Test16 - Validate Successfully +0 ValidLongSerialNumberTest16EE.crt +# 4.4.17 Valid Long Serial Number Test17 - Validate Successfully +0 ValidLongSerialNumberTest17EE.crt +# 4.4.18 Invalid Long Serial Number Test18 - Reject - the end entity certificate has been revoked +2 InvalidLongSerialNumberTest18EE.crt +# 4.4.19 Valid Separate Certificate and CRL Keys Test19 - Validate Successfully +0 ValidSeparateCertificateandCRLKeysTest19EE.crt +# 4.4.20 Invalid Separate Certificate and CRL Keys Test20 - Reject - the end entity certificate has been revoked +2 InvalidSeparateCertificateandCRLKeysTest20EE.crt +# 4.4.21 Invalid Separate Certificate and CRL Keys Test21 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidSeparateCertificateandCRLKeysTest21EE.crt +# 4.5.1 Valid Basic Self-Issued Old With New Test1 - Validate Successfully +0 ValidBasicSelfIssuedOldWithNewTest1EE.crt +# 4.5.2 Invalid Basic Self-Issued Old With New Test2 - Reject - the end entity certificate has been revoked +2 InvalidBasicSelfIssuedOldWithNewTest2EE.crt +# 4.5.3 Valid Basic Self-Issued New With Old Test3 - Validate Successfully +0 ValidBasicSelfIssuedNewWithOldTest3EE.crt +# 4.5.4 Valid Basic Self-Issued New With Old Test4 - Validate Successfully +0 ValidBasicSelfIssuedNewWithOldTest4EE.crt +# 4.5.5 Invalid Basic Self-Issued New With Old Test5 - Reject - the end entity certificate has been revoked +2 InvalidBasicSelfIssuedNewWithOldTest5EE.crt +# 4.5.6 Valid Basic Self-Issued CRL Signing Key Test6 - Validate Successfully +0 ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt +# 4.5.7 Invalid Basic Self-Issued CRL Signing Key Test7 - Reject - the end entity certificate has been revoked +2 InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt +# 4.5.8 Invalid Basic Self-Issued CRL Signing Key Test8 - Reject - invalid certification path +1 InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt +# 4.6.1 Invalid Missing basicConstraints Test1 - Reject - invalid certification path +1 InvalidMissingbasicConstraintsTest1EE.crt +# 4.6.2 Invalid cA False Test2 - Reject - invalid certification path +1 InvalidcAFalseTest2EE.crt +# 4.6.3 Invalid cA False Test3 - Reject - invalid certification path +1 InvalidcAFalseTest3EE.crt +# 4.6.4 Valid basicConstraints Not Critical Test4 - Validate Successfully +0 ValidbasicConstraintsNotCriticalTest4EE.crt +# 4.6.5 Invalid pathLenConstraint Test5 - Reject - invalid certification path +1 InvalidpathLenConstraintTest5EE.crt +# 4.6.6 Invalid pathLenConstraint Test6 - Reject - invalid certification path +1 InvalidpathLenConstraintTest6EE.crt +# 4.6.7 Valid pathLenConstraint Test7 - Validate Successfully +0 ValidpathLenConstraintTest7EE.crt +# 4.6.8 Valid pathLenConstraint Test8 - Validate Successfully +0 ValidpathLenConstraintTest8EE.crt +# 4.6.9 Invalid pathLenConstraint Test9 - Reject - invalid certification path +1 InvalidpathLenConstraintTest9EE.crt +# 4.6.10 Invalid pathLenConstraint Test10 - Reject - invalid certification path +1 InvalidpathLenConstraintTest10EE.crt +# 4.6.11 Invalid pathLenConstraint Test11 - Reject - invalid certification path +1 InvalidpathLenConstraintTest11EE.crt +# 4.6.12 Invalid pathLenConstraint Test12 - Reject - invalid certification path +1 InvalidpathLenConstraintTest12EE.crt +# 4.6.13 Valid pathLenConstraint Test13 - Validate Successfully +0 ValidpathLenConstraintTest13EE.crt +# 4.6.14 Valid pathLenConstraint Test14 - Validate Successfully +0 ValidpathLenConstraintTest14EE.crt +# 4.6.15 Valid Self-Issued pathLenConstraint Test15 - Validate Successfully +0 ValidSelfIssuedpathLenConstraintTest15EE.crt +# 4.6.16 Invalid Self-Issued pathLenConstraint Test16 - Reject - invalid certification path +1 InvalidSelfIssuedpathLenConstraintTest16EE.crt +# 4.6.17 Valid Self-Issued pathLenConstraint Test17 - Validate Successfully +0 ValidSelfIssuedpathLenConstraintTest17EE.crt +# 4.7.1 Invalid keyUsage Critical keyCertSign False Test1 - Reject - invalid certification path +1 InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt +# 4.7.2 Invalid keyUsage Not Critical keyCertSign False Test2 - Reject - invalid certification path +1 InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt +# 4.7.3 Valid keyUsage Not Critical Test3 - Validate Successfully +0 ValidkeyUsageNotCriticalTest3EE.crt +# 4.7.4 Invalid keyUsage Critical cRLSign False Test4 - Reject - invalid certification path +1 InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt +# 4.7.5 Invalid keyUsage Not Critical cRLSign False Test5 - Reject - invalid certification path +1 InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt +0 UserNoticeQualifierTest19EE.crt +# 4.10.1 Valid Policy Mapping Test1, subtest 1 - Reject - unrecognized critical extension [Test using the default settings (i.e., initial-policy-set = any-policy) +1 InvalidSelfIssuedrequireExplicitPolicyTest8EE.crt +# 4.11.2 Valid inhibitPolicyMapping Test2 - Reject - unrecognized critical extension +1 ValidinhibitPolicyMappingTest2EE.crt +# 4.12.2 Valid inhibitAnyPolicy Test2 - Reject - unrecognized critical extension +1 ValidinhibitAnyPolicyTest2EE.crt +# 4.13.1 Valid DN nameConstraints Test1 - Validate Successfully +0 ValidDNnameConstraintsTest1EE.crt +# 4.13.2 Invalid DN nameConstraints Test2 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest2EE.crt +# 4.13.3 Invalid DN nameConstraints Test3 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest3EE.crt +# 4.13.4 Valid DN nameConstraints Test4 - Validate Successfully +0 ValidDNnameConstraintsTest4EE.crt +# 4.13.5 Valid DN nameConstraints Test5 - Validate Successfully +0 ValidDNnameConstraintsTest5EE.crt +# 4.13.6 Valid DN nameConstraints Test6 - Validate Successfully +0 ValidDNnameConstraintsTest6EE.crt +# 4.13.7 Invalid DN nameConstraints Test7 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest7EE.crt +# 4.13.8 Invalid DN nameConstraints Test8 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest8EE.crt +# 4.13.9 Invalid DN nameConstraints Test9 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest9EE.crt +# 4.13.10 Invalid DN nameConstraints Test10 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest10EE.crt +# 4.13.11 Valid DN nameConstraints Test11 - Validate Successfully +0 ValidDNnameConstraintsTest11EE.crt +# 4.13.12 Invalid DN nameConstraints Test12 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest12EE.crt +# 4.13.13 Invalid DN nameConstraints Test13 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest13EE.crt +# 4.13.14 Valid DN nameConstraints Test14 - Validate Successfully +0 ValidDNnameConstraintsTest14EE.crt +# 4.13.15 Invalid DN nameConstraints Test15 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest15EE.crt +# 4.13.16 Invalid DN nameConstraints Test16 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest16EE.crt +# 4.13.17 Invalid DN nameConstraints Test17 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest17EE.crt +# 4.13.18 Valid DN nameConstraints Test18 - Validate Successfully +0 ValidDNnameConstraintsTest18EE.crt +# 4.13.19 Valid Self-Issued DN nameConstraints Test19 - Validate Successfully +0 ValidDNnameConstraintsTest19EE.crt +# 4.13.20 Invalid Self-Issued DN nameConstraints Test20 - Reject - name constraints violation +1 InvalidDNnameConstraintsTest20EE.crt +# 4.13.21 Valid RFC822 nameConstraints Test21 - Validate Successfully +0 ValidRFC822nameConstraintsTest21EE.crt +# 4.13.22 Invalid RFC822 nameConstraints Test22 - Reject - name constraints violation +1 InvalidRFC822nameConstraintsTest22EE.crt +# 4.13.23 Valid RFC822 nameConstraints Test23 - Validate Successfully +0 ValidRFC822nameConstraintsTest23EE.crt +# 4.13.24 Invalid RFC822 nameConstraints Test24 - Reject - name constraints violation +1 InvalidRFC822nameConstraintsTest24EE.crt +# 4.13.25 Valid RFC822 nameConstraints Test25 - Validate Successfully +0 ValidRFC822nameConstraintsTest25EE.crt +# 4.13.26 Invalid RFC822 nameConstraints Test26 - Reject - name constraints violation +1 InvalidRFC822nameConstraintsTest26EE.crt +# 4.13.27 Valid DN and RFC822 nameConstraints Test27 - Validate Successfully +0 ValidDNandRFC822nameConstraintsTest27EE.crt +# 4.13.28 Invalid DN and RFC822 nameConstraints Test28 - Reject - name constraints violation +1 InvalidDNandRFC822nameConstraintsTest28EE.crt +# 4.13.29 Invalid DN and RFC822 nameConstraints Test29 - Reject - name constraints violation +1 InvalidDNandRFC822nameConstraintsTest29EE.crt +# 4.13.30 Valid DNS nameConstraints Test30 - Validate Successfully +0 ValidDNSnameConstraintsTest30EE.crt +# 4.13.31 Invalid DNS nameConstraints Test31 - Reject - name constraints violation +1 InvalidDNSnameConstraintsTest31EE.crt +# 4.13.32 Valid DNS nameConstraints Test32 - Validate Successfully +0 ValidDNSnameConstraintsTest32EE.crt +# 4.13.33 Invalid DNS nameConstraints Test33 - Reject - name constraints violation +1 InvalidDNSnameConstraintsTest33EE.crt +# 4.13.34 Valid URI nameConstraints Test34 - Validate Successfully +0 ValidURInameConstraintsTest34EE.crt +# 4.13.35 Invalid URI nameConstraints Test35 - Reject - name constraints violation +1 InvalidURInameConstraintsTest35EE.crt +# 4.13.36 Valid URI nameConstraints Test36 - Validate Successfully +0 ValidURInameConstraintsTest36EE.crt +# 4.13.37 Invalid URI nameConstraints Test37 - Reject - name constraints violation +1 InvalidURInameConstraintsTest37EE.crt +# 4.13.38 Invalid DNS nameConstraints Test38 - Reject - name constraints violation +1 InvalidDNSnameConstraintsTest38EE.crt +# 4.14.1 Valid distributionPoint Test1 - Validate Successfully +0 ValiddistributionPointTest1EE.crt +# 4.14.2 Invalid distributionPoint Test2 - Reject - end entity certificate has been revoked +2 InvaliddistributionPointTest2EE.crt +# 4.14.3 Invalid distributionPoint Test3 - Reject or Warn - status of end entity certificate can not be determined +3 InvaliddistributionPointTest3EE.crt +# 4.14.4 Valid distributionPoint Test4 - Validate Successfully +0 ValiddistributionPointTest4EE.crt +# 4.14.5 Valid distributionPoint Test5 - Validate Successfully +0 ValiddistributionPointTest5EE.crt +# 4.14.6 Invalid distributionPoint Test6 - Reject - end entity certificate has been revoked +2 InvaliddistributionPointTest6EE.crt +# 4.14.7 Valid distributionPoint Test7 - Validate Successfully +0 ValiddistributionPointTest7EE.crt +# 4.14.8 Invalid distributionPoint Test8 - Reject or Warn - status of end entity certificate can not be determined +3 InvaliddistributionPointTest8EE.crt +# 4.14.9 Invalid distributionPoint Test9 - Reject or Warn - status of end entity certificate can not be determined +3 InvaliddistributionPointTest9EE.crt +# 4.14.10 Valid No issuingDistributionPoint Test10 - Validate Successfully +0 ValidNoissuingDistributionPointTest10EE.crt +# 4.14.11 Invalid onlyContainsUserCerts CRL Test11 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidonlyContainsUserCertsTest11EE.crt +# 4.14.12 Invalid onlyContainsCACerts CRL Test12 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidonlyContainsCACertsTest12EE.crt +# 4.14.13 Valid onlyContainsCACerts CRL Test13 - Validate Successfully +0 ValidonlyContainsCACertsTest13EE.crt +# 4.14.14 Invalid onlyContainsAttributeCerts Test14 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidonlyContainsAttributeCertsTest14EE.crt +# 4.14.15 Invalid onlySomeReasons Test15 - Reject - end entity certificate has been revoked +2 InvalidonlySomeReasonsTest15EE.crt +# 4.14.16 Invalid onlySomeReasons Test16 - Reject - end entity certificate is on hold +2 InvalidonlySomeReasonsTest16EE.crt +# 4.14.17 Invalid onlySomeReasons Test17 - Reject or Warn - status of end entity certificate can not be determined +3 InvalidonlySomeReasonsTest17EE.crt +# 4.14.18 Valid onlySomeReasons Test18 - Validate Successfully +0 ValidonlySomeReasonsTest18EE.crt +# 4.14.19 Valid onlySomeReasons Test19 - Validate Successfully +0 ValidonlySomeReasonsTest19EE.crt +# 4.14.20 Invalid onlySomeReasons Test20 - Reject - end entity certificate has been revoked +2 InvalidonlySomeReasonsTest20EE.crt +# 4.14.21 Invalid onlySomeReasons Test21 - Reject - end entity certificate has been revoked +2 InvalidonlySomeReasonsTest21EE.crt +# 4.14.24 Valid IDP with indirectCRL Test24 - Reject or Warn - status of end entity certificate can not be determined +3 ValidIDPwithindirectCRLTest24EE.crt +# 4.15.1 Invalid deltaCRLIndicator No Base Test1 - Reject or Warn - status of end entity certificate can not be determined +3 InvaliddeltaCRLIndicatorNoBaseTest1EE.crt +# 4.15.2 Valid delta-CRL Test2 - Validate Successfully +0 ValiddeltaCRLTest2EE.crt +# 4.15.3 Invalid delta-CRL Test3 - Reject - end entity certificate has been revoked +2 InvaliddeltaCRLTest3EE.crt +# 4.15.4 Invalid delta-CRL Test4 - Reject - end entity certificate has been revoked +2 InvaliddeltaCRLTest4EE.crt +# 4.15.5 Valid delta-CRL Test5 - Validate Successfully +0 ValiddeltaCRLTest5EE.crt +# 4.15.6 Invalid delta-CRL Test6 - Reject - end entity certificate has been revoked +2 InvaliddeltaCRLTest6EE.crt +# 4.15.7 Valid delta-CRL Test7 - Validate Successfully +0 ValiddeltaCRLTest7EE.crt +# 4.15.8 Valid delta-CRL Test8 - Validate Successfully +0 ValiddeltaCRLTest8EE.crt +# 4.15.9 Invalid delta-CRL Test9 - Reject - end entity certificate has been revoked +2 InvaliddeltaCRLTest9EE.crt +# 4.15.10 Invalid delta-CRL Test10 - Reject or Warn - status of end entity certificate can not be determined +3 InvaliddeltaCRLTest10EE.crt +# 4.16.1 Valid Unknown Not Critical Certificate Extension Test1 - Validate Successfully +0 ValidUnknownNotCriticalCertificateExtensionTest1EE.crt +# 4.16.2 Invalid Unknown Critical Certificate Extension Test2 - Reject - unrecognized critical extension +1 InvalidUnknownCriticalCertificateExtensionTest2EE.crt diff --git a/third_party/heimdal/lib/hx509/data/nist-result2 b/third_party/heimdal/lib/hx509/data/nist-result2 new file mode 100644 index 0000000..93a22e7 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/nist-result2 @@ -0,0 +1,31 @@ +# $Id$ +# id FAIL +4.2.8 EITHER depeneds on if time_t is 64 bit or not +4.3.5 FAIL +4.4.13 EITHER depeneds on if time_t is 64 bit or not +4.5.1 FAIL +4.5.4 FAIL +4.5.6 FAIL +4.6.15 FAIL +4.6.17 FAIL +4.11.2 FAIL +4.12.2 FAIL +4.13.19 FAIL +4.13.21 FAIL +4.13.23 FAIL +4.13.26 FAIL +4.13.27 FAIL +4.13.30 FAIL +4.13.33 FAIL +4.13.34 FAIL +4.13.37 FAIL +4.14.1 FAIL +4.14.4 FAIL +4.14.5 FAIL +4.14.7 FAIL +4.14.13 FAIL +4.14.18 FAIL +4.14.19 FAIL +4.15.4 FAIL +4.15.5 FAIL +4.16.2 FAIL diff --git a/third_party/heimdal/lib/hx509/data/no-proxy-test.crt b/third_party/heimdal/lib/hx509/data/no-proxy-test.crt new file mode 100644 index 0000000..5f27bcd --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/no-proxy-test.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFEzCCAvugAwIBAgIJAKQmPUkmhyKiMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQwIBcNMTkwMzIyMjIyNTEzWhgPMjUx +ODExMjEyMjI1MTNaMDQxCzAJBgNVBAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQx +ETAPBgNVBAMMCG5vLXByb3h5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEA1wY5NrUAYbdIiJyOwEG5zo6892LuPxYrJ39qy0868pQMPuViT3IjP8fOockf +IHFqM1M/rYEKBCaHm3W5d0+QET1T3pJq7eOTuG8Ep4BiMDm2mD0VeWOCeLJjfnuR +8WPG3Fz//55NBCByMc4as5+Gw9b6z6Mh8pFMyz4zyMQI420Gss9hHoTiD9o4fhM4 +U5M+l+gvVYmvLhZ0Z8hIJAqnlRJoIKeEbcHS1qIqkN0vkdRZc5usJmxhpJi8SjTS +pGiP53QDmGDJMHd5Fsfyv98n6T6fIkf+O2sAVnxdgOBIyYibdMH021/UzbXZHoDK +Nx5HH9lr1R9vE5fy969yCQ10lgaNmlp68j8/5B8QPeRbe29DQ1rRBzheji1kkxbg +8FU7GKu92GHrDhK5dasl7tH3qx4WKOAD4ENJI4vSDWo/IxkKYLLuNIMcVhmGORGl +IvxaDVxr5wHdGgpBJwc2BxcHU6/8cuYGDewR2h/TWb6jTVmfq7lx+fefEkTDmOxI +WbXwGtbZqqX5EzWp3VTBakONdRjJwxg3MShWJ1ZhYawzeTwZg3FOIn9W2tLkPNU7 +Ly/fZMBD6qJ5X/0gJGkx9QRlANMJnj0POaBvIyzkGz95QlyIoiAJyuzCKbX5WQdd +jy1drnB2VdAjWyAjUP+9JsMJJKyLYOWxvemE1yAIIL9yjVMCAwEAAaM5MDcwCQYD +VR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFN8mmgQlHmnWopRs35laOYZ9 +/02LMA0GCSqGSIb3DQEBCwUAA4ICAQB6dmCcY2XRzeZz2CQ2DdGJRyBDdHFf7W3O +4Tk/w2ZQLFx6BwttOB94LcaVFRUHp9arkNDH6ne9ntQ1LZ3fPoRR4RXwQO8c+pIf +ZDWPEr7Exv1F1zrjAEHx2UcP1pu4PU9PDqmGs2BarnHgKotfY8AXdJkl1g128LIQ +WOmQFyI6Ny//4MT/5YB6OSr2zzrKz5FyGxKSG49xfPSSAf3mHAUxHzBJ1orpHIpo +zQcrt6oRbi9G9cKVYTEVRVM2CgqMJwBUH7d9BRIab4hp7lqynFJKg3uOH90cmms1 +dY5NRmy+jmAqveEGvCw2+vmHtbj5NikwUBnRqZGW/XHLSj8niCtO2PT30xzpDiEa +iYBGyuETV5vwFIbucdbenaBrrbvumr4lWqhjadQVwjhNcqdmhIxuGGXF/XGG5+do +hFaYD5fguyfQDGaeFQIipPEyZcx0QcGA77g7eKYgPyBFZxGHS7P1x1GrchZIOH1q +W59AuSwxKWGEAM2tlp2+Esp3Zj8UBy2nL9fXRyDEMerCuJUcbCLODGYDc0/s/7Cs +G8ZNK+GXs68CgxJCbxY5uUcYQyVpRFi62jvghuPGQkxytQ/GWM+q94ncr8I2+lsO +kTcdzYbAapst+XoPL9enQwAkw4yksJ8Rx2P2TDRAZl58+utRrdQyL0oD9cJy57LE +cpMYhZWsyQ== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/no-proxy-test.key b/third_party/heimdal/lib/hx509/data/no-proxy-test.key new file mode 100644 index 0000000..9f30400 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/no-proxy-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDXBjk2tQBht0iI +nI7AQbnOjrz3Yu4/Fisnf2rLTzrylAw+5WJPciM/x86hyR8gcWozUz+tgQoEJoeb +dbl3T5ARPVPekmrt45O4bwSngGIwObaYPRV5Y4J4smN+e5HxY8bcXP//nk0EIHIx +zhqzn4bD1vrPoyHykUzLPjPIxAjjbQayz2EehOIP2jh+EzhTkz6X6C9Via8uFnRn +yEgkCqeVEmggp4RtwdLWoiqQ3S+R1Flzm6wmbGGkmLxKNNKkaI/ndAOYYMkwd3kW +x/K/3yfpPp8iR/47awBWfF2A4EjJiJt0wfTbX9TNtdkegMo3Hkcf2WvVH28Tl/L3 +r3IJDXSWBo2aWnryPz/kHxA95Ft7b0NDWtEHOF6OLWSTFuDwVTsYq73YYesOErl1 +qyXu0ferHhYo4APgQ0kji9INaj8jGQpgsu40gxxWGYY5EaUi/FoNXGvnAd0aCkEn +BzYHFwdTr/xy5gYN7BHaH9NZvqNNWZ+ruXH5958SRMOY7EhZtfAa1tmqpfkTNand +VMFqQ411GMnDGDcxKFYnVmFhrDN5PBmDcU4if1ba0uQ81TsvL99kwEPqonlf/SAk +aTH1BGUA0wmePQ85oG8jLOQbP3lCXIiiIAnK7MIptflZB12PLV2ucHZV0CNbICNQ +/70mwwkkrItg5bG96YTXIAggv3KNUwIDAQABAoICAQDKOoMyzZbXUC66tSuY6/fZ +qetVa8kQskPR+QcywYh6Pv0pZklI2NsIEF5pUKOiuqgcL26TOup1rtsZPeY5rS2c +2SX5DZHdvIzhCCDDfH5cRttRYRnCOfGqnHPwsD05XxLXi+wEuBhNCkr8RpBcYWu4 +4oavJAk4fqlP+WdwqdaGNrL3Fw2LS4TlTeKVyHPQPoq/CdMCyuRkHyBJv1cB9rdX +/6DJHWPyajlmPcx0xGIJ8EJU9ZM56/MFf9SOohF+KQ02rKj49gYiPCs5XsIS7Mk3 +l/rInhcgQOlnbb3vCIHMcVtru0MT05RsCFx0UMJehm50KOM+5TptnhoYEvzYQLxk +578RDQUNiQxdonmcF8QXvCBHArP20SLyfwavNsFtvfNe26i+9ti/+GaLsKHRC/ZI +NsaIsO3wGT2E2/qoyFt+aOxrlNeT4zq+tHX01U8UzK3qhp6/RuSrQeCdmE7e/Mjb +GVDpBYBbscfcApSCVyrpJ51Fs2VKt9QBliocrxG0Voa4xpdwC9XCI3AfTyzzG5le +fSqhl4kB0iDboWJQgiH7hJKhFtBnrBVhPQ+bcl/G4+OZYV9HNZ98gNurCW9qO7Bf +8jP3/A1YWYY4GI7LVqsjOZdFk3EXz1g0PR8UH4+4RRrmVAe6QD4zzQmk7ecGu5k7 +nZXuAluURI6ExdBoGGxU8QKCAQEA8GYwOHkZjNNWVDBkhjVliUHtwHof+8MoJp/L +pHR2dwIH3UXU9RrFfzfz2sQ07Vi7aiyyebVXAA1q8ENHfeHvlWbT0SPBZOKbujVJ +S+cNYZJvlWrvS/1ZgNld5SDSaV6R5tMIdAOyWvYm3ijgVGOmEccZVdby0MagTvJx +fwxcNe5H86KGbZrEFieaCjz69Mg9jQh9QhfRxom1H38EcXd5O9wRSpLoXBH4c8Ha +WBiFGaNZJrvOtCZz5YYsWVoaW9GHa4fTs9aQEirDoIR1GD+b6srD/bWX+CfM/SwG +7bDNh2NZuH/24R+55/SUxBdhttImtiE1TmJ8XkhnocuZc03SuQKCAQEA5Pp55xqe +cAELtdHv6iyM25e8Iv9KVMJ9y9HGH9cLdk9OwOwWroIhdIYe/yvYmHSSSiCQI+JB +DC+2n9qxda1DHMpJWPIS4bEkKEPRsVmUyQp68OSxKcPh60m1lWk+UMhcPFWJEggz +XKDacyjC596r4FBMk6n84lhu3HII3Zfho25IeMOgOcGlFHn5TETaqUQG1D0dParO +rtP151TKFjyihOn8WibkcZ8uT0PXjREVCXgiha4Z/eNFeIknC007uus8bCWKUz0n +krNTz9hiGDJHRoyGdUS9PlusW1rA8kXMvQ+8SWzHCqgwfx6zB/Nzii+glFOzzIhG +Vydp/zFrLhJKawKCAQBAddY2PlqYhU6fsn4x8n1waYo700NiObk5ah2r0kK1tIix +T3lD49LTQwiTP4tFnUZbuPJ+ah6S+AYVuKSh34Rjljfz21ePGqhRLNqjjKfs4twi +v5K82Ik4YJCp0Lw63s3Wi/23Rgp8E4bmiSVl23Z7S9zCRKnFS41Ovfmq7ICJQYRv +ksPi/d3YZvQKDMHqAwtmFsGniEWKrAAyGtfxKO0MHP1R9sRxc6wgNfm7J5ABCOjt +1uwdKDZpdCnOJ7frqOpb7gbZMQ5eoLLmBr5zKxM+yPH2xMukEeAIfta4w3DI/d3f ++AgV43Dw/ocpcW+VGxKgQZVOmF/q1BVdr/9MiLCZAoIBAEEFZ2xawLbpdRvSW6BR +ukX5FnGRsNfUysf/75THCfg0mRZrdB1l0n42P8MR/lV8dLYb/RJTg0kkm2VVQqM5 +6h7Yym85fmccWDoe2ALWf0t/cF3Lcwt7FkIsEiY1Vn62BosTdvLp5TveaWneH0qc +jo4J/1THJopXtlNfBml2YZp5DJdOZcdA19GyuToRK055hL7sA8upHzvB8MgZ6bDa +0wOPNhubg69IFmxnxWPHgAPKW3M+dx8DVIzf1Xh+HAH+HpBPMLJmYUBlL92Lgn+A +d4DvEpdmR57XhWADq1qgu3zMZRksjHDYRb0zSH9vgFWzJJQ6GIpyABdrl8vhip/w +jbUCggEBAMelGQB2zBBbo1F+InIPkCZH/r0Z/VrB6bQG2UY5c5Em5dTliKjE9r7U +EGJBgLxPiHQomxG6Z/AWVzbUiv650sjfTu/W9qZ4iCEAQvGtR5FxhgtBTspMURxR +W+QiMmkKrkkQgVBXslXgOGerj1RUe+gjaaO6qEdH5famYBXOYAG1gnq3hYa8DWMg +OOQPoWBv2bCrtFNmuMFuHI4dTACvzbEipBTsTs0AbAQbvcSuo+KQqCcXhFfENJ/d +7F9XN3fxSG7g4YAiIVOUjNZYz36bcpV0zpHUde+mbOvE9uXny5CFRkMHkio0Kj8h +vMvFV9XqcWhoGHKX/S/Hmjljr7ln1Dc= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/ocsp-req1.der b/third_party/heimdal/lib/hx509/data/ocsp-req1.der new file mode 100644 index 0000000..e536ebb Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-req1.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-req2.der b/third_party/heimdal/lib/hx509/data/ocsp-req2.der new file mode 100644 index 0000000..e224fa6 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-req2.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-2.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-2.der new file mode 100644 index 0000000..98d88e4 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-2.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-3.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-3.der new file mode 100644 index 0000000..4c65016 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-3.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-ca.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ca.der new file mode 100644 index 0000000..228918c Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ca.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-keyhash.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-keyhash.der new file mode 100644 index 0000000..250a1f1 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-keyhash.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp-no-cert.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp-no-cert.der new file mode 100644 index 0000000..6ebbd84 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp-no-cert.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp.der new file mode 100644 index 0000000..c97654a Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1-ocsp.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp1.der b/third_party/heimdal/lib/hx509/data/ocsp-resp1.der new file mode 100644 index 0000000..8546eba Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp1.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-resp2.der b/third_party/heimdal/lib/hx509/data/ocsp-resp2.der new file mode 100644 index 0000000..d731f38 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/ocsp-resp2.der differ diff --git a/third_party/heimdal/lib/hx509/data/ocsp-responder.crt b/third_party/heimdal/lib/hx509/data/ocsp-responder.crt new file mode 100644 index 0000000..753ca56 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/ocsp-responder.crt @@ -0,0 +1,119 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:01 2019 GMT + Not After : Nov 21 22:25:01 2518 GMT + Subject: C=SE, CN=OCSP responder + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b1:21:1d:c9:2b:44:9e:62:fe:13:94:ea:a1:e1: + cd:17:0e:bb:4d:1c:62:27:ee:d3:f7:61:c8:26:c1: + 0f:45:fc:10:d8:39:c3:da:86:a0:00:30:d7:ad:86: + ff:c6:36:6c:f5:e2:26:8c:f6:76:1b:d0:09:b6:a5: + f8:cb:d5:88:fc:ca:ca:28:49:ed:64:2b:f3:88:4e: + 8e:ec:7c:63:b8:75:6a:cc:73:b6:66:6c:c3:7c:e4: + d7:50:95:88:12:84:e7:5c:50:87:db:4c:bf:91:98: + b1:3a:44:57:0b:1a:7a:f1:93:e3:4c:69:8b:9f:d7: + b9:20:8d:0e:cb:ff:de:38:6f:6a:91:55:1a:6f:a6: + 82:1d:05:f6:fc:46:8c:83:8b:ab:6e:3f:6a:6f:c5: + 0c:cc:ff:3c:78:74:d4:f8:56:be:59:60:d5:3f:4d: + 3e:e4:e1:4b:2d:c5:2a:d1:6a:7a:21:b9:6e:61:10: + 03:79:88:5b:74:f4:29:0d:56:d3:6b:d5:7d:8c:59: + 5d:4e:89:0d:a3:a6:8b:43:28:e8:e2:f1:bb:d5:eb: + 65:9b:c2:d6:62:aa:df:66:d5:92:dd:84:6c:29:28: + 1a:e8:29:b3:09:d1:45:14:44:cb:30:03:73:3a:94: + a3:a3:24:89:15:fb:ca:e0:a6:62:35:48:f8:92:50: + 3a:ff:17:d8:4a:1e:a0:9c:d9:68:cc:21:e1:c9:36: + d1:47:bc:f1:56:3e:87:18:10:0d:f5:56:9a:c9:79: + 16:c0:08:a0:59:65:b2:00:dd:9a:e9:97:e7:8f:85: + ee:cd:0d:20:5e:2d:58:ff:8e:e3:ce:4f:36:65:c3: + f1:88:39:dd:34:29:db:8c:ed:6e:c8:7b:30:ad:49: + 58:e6:f9:5b:85:46:0a:04:0f:9e:ea:ca:a8:2a:35: + 0d:66:f3:48:b6:e3:c7:e0:e8:a3:ed:6c:f3:e4:cd: + 1d:45:f3:e2:2c:6c:5b:91:b8:26:dd:49:d4:78:d3: + 4e:57:3a:b5:af:cd:3a:05:d5:89:63:f5:bc:73:1f: + 26:cc:2c:4b:2d:81:b3:5d:49:28:04:46:f8:24:5a: + 68:1d:06:1b:2d:be:56:f9:b3:f4:d1:50:2f:95:9b: + 9f:45:c7:62:35:bc:46:a9:df:c6:45:21:e9:1c:7d: + a8:2e:b1:87:91:0b:7c:fb:97:52:31:f9:41:73:ba: + 83:22:4a:80:f9:ff:f1:95:74:79:f7:20:95:f0:17: + 20:7d:ac:55:e8:b0:c6:b2:a6:56:c6:c0:cf:3d:78: + d5:9e:37:41:b4:78:aa:30:f0:2d:59:7c:6a:c8:68: + cc:91:09:13:f8:9f:04:e3:a9:86:c2:74:ba:f6:32: + 44:0d:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + OCSP No Check, OCSP Signing + X509v3 Subject Key Identifier: + D0:3C:E8:05:07:BB:9A:96:36:88:44:AA:9A:4F:62:9E:9F:33:5B:03 + Signature Algorithm: sha1WithRSAEncryption + c0:72:d2:af:26:74:de:f8:7c:96:bf:ab:d2:ed:95:d9:bb:0b: + 07:31:8a:4b:21:f0:b5:7e:ab:b4:50:b0:af:bf:96:64:ce:38: + 99:3d:f3:26:02:4d:5a:da:71:ad:6d:a6:f7:fc:5e:46:16:3d: + 9e:cf:95:a3:5d:0c:4a:64:a1:84:88:b0:31:0e:eb:54:cb:99: + 42:45:09:92:ea:b7:74:f5:fb:ff:c6:91:31:27:bd:54:55:9f: + 6c:bb:e2:45:4a:33:ed:00:a5:4e:e2:7b:2c:98:f1:3b:bc:f2: + 87:33:e5:22:d8:fc:a8:4c:90:e2:df:ce:48:c8:3c:56:43:6c: + ac:f1:f6:e0:75:c2:a7:f9:33:87:4e:75:a6:22:17:78:32:88: + aa:f9:2a:40:4c:e0:25:6c:4c:0c:cb:6f:1a:7b:13:0d:35:a6: + 23:86:42:75:3c:c1:69:c1:c5:79:77:51:4b:19:14:e7:4b:f9: + df:0b:30:aa:c4:97:84:6e:57:7b:00:b3:a5:31:c6:9f:17:f1: + b0:4c:81:f7:e6:df:e8:c0:d2:91:03:c2:e3:dd:94:c4:f0:ee: + 1c:73:1c:33:ae:91:60:fe:cf:48:08:0a:95:c1:95:28:af:31: + 23:a6:2a:1c:d1:6c:7f:68:e8:a9:a4:27:8f:6f:29:33:a9:48: + 0c:03:8f:fa:b5:ef:2a:9a:ce:ed:ba:74:39:88:ef:3b:d9:93: + 77:34:30:d1:a3:5c:9d:f1:3c:30:19:c2:ca:2e:41:5b:23:bb: + 6a:67:35:e3:e2:c6:6e:a0:3e:76:50:db:6b:ee:02:98:81:bf: + 75:ac:3a:78:4f:f4:fb:d1:7a:1f:85:1a:24:cd:b8:06:7e:95: + 28:85:2a:c6:41:23:35:08:31:59:ce:ad:a3:23:1a:7a:11:26: + d9:45:57:bf:ea:e0:72:3a:f8:48:e0:c1:5c:b3:20:93:b5:1a: + 93:75:ef:f3:19:9d:ed:5d:9f:81:73:21:02:96:fa:ee:c9:4c: + c7:95:1b:aa:65:b9:69:15:3c:ef:b3:f6:e1:f5:89:78:05:50: + d3:54:c4:c9:40:e5:5f:3e:bd:36:d2:0e:27:99:5e:83:e5:4b: + bf:72:84:13:64:8d:d9:db:69:8b:04:37:e8:db:22:46:29:84: + 08:83:40:34:d8:e0:bf:cc:5c:7c:b2:bd:c5:38:7d:59:e6:9d: + 8a:78:87:08:13:6f:a5:7d:2f:88:80:ce:e5:86:38:6f:53:b8: + 99:ba:f5:21:9e:8f:5f:aa:3a:07:73:9b:02:f1:97:1f:8b:52: + 53:5e:24:af:d7:b9:a4:3f:4e:64:c8:62:26:b3:c0:44:dd:bb: + 29:8c:b5:66:05:5d:fd:f7 +-----BEGIN CERTIFICATE----- +MIIFJjCCAw6gAwIBAgIBATANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwMVoYDzI1 +MTgxMTIxMjIyNTAxWjAmMQswCQYDVQQGEwJTRTEXMBUGA1UEAwwOT0NTUCByZXNw +b25kZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCxIR3JK0SeYv4T +lOqh4c0XDrtNHGIn7tP3YcgmwQ9F/BDYOcPahqAAMNethv/GNmz14iaM9nYb0Am2 +pfjL1Yj8ysooSe1kK/OITo7sfGO4dWrMc7ZmbMN85NdQlYgShOdcUIfbTL+RmLE6 +RFcLGnrxk+NMaYuf17kgjQ7L/944b2qRVRpvpoIdBfb8RoyDi6tuP2pvxQzM/zx4 +dNT4Vr5ZYNU/TT7k4UstxSrRanohuW5hEAN5iFt09CkNVtNr1X2MWV1OiQ2jpotD +KOji8bvV62WbwtZiqt9m1ZLdhGwpKBroKbMJ0UUURMswA3M6lKOjJIkV+8rgpmI1 +SPiSUDr/F9hKHqCc2WjMIeHJNtFHvPFWPocYEA31VprJeRbACKBZZbIA3Zrpl+eP +he7NDSBeLVj/juPOTzZlw/GIOd00KduM7W7IezCtSVjm+VuFRgoED57qyqgqNQ1m +80i248fg6KPtbPPkzR1F8+IsbFuRuCbdSdR4005XOrWvzToF1Ylj9bxzHybMLEst +gbNdSSgERvgkWmgdBhstvlb5s/TRUC+Vm59Fx2I1vEap38ZFIekcfagusYeRC3z7 +l1Ix+UFzuoMiSoD5//GVdHn3IJXwFyB9rFXosMayplbGwM89eNWeN0G0eKow8C1Z +fGrIaMyRCRP4nwTjqYbCdLr2MkQNvQIDAQABo1kwVzAJBgNVHRMEAjAAMAsGA1Ud +DwQEAwIF4DAeBgNVHSUEFzAVBgkrBgEFBQcwAQUGCCsGAQUFBwMJMB0GA1UdDgQW +BBTQPOgFB7ualjaIRKqaT2KenzNbAzANBgkqhkiG9w0BAQUFAAOCAgEAwHLSryZ0 +3vh8lr+r0u2V2bsLBzGKSyHwtX6rtFCwr7+WZM44mT3zJgJNWtpxrW2m9/xeRhY9 +ns+Vo10MSmShhIiwMQ7rVMuZQkUJkuq3dPX7/8aRMSe9VFWfbLviRUoz7QClTuJ7 +LJjxO7zyhzPlItj8qEyQ4t/OSMg8VkNsrPH24HXCp/kzh051piIXeDKIqvkqQEzg +JWxMDMtvGnsTDTWmI4ZCdTzBacHFeXdRSxkU50v53wswqsSXhG5XewCzpTHGnxfx +sEyB9+bf6MDSkQPC492UxPDuHHMcM66RYP7PSAgKlcGVKK8xI6YqHNFsf2joqaQn +j28pM6lIDAOP+rXvKprO7bp0OYjvO9mTdzQw0aNcnfE8MBnCyi5BWyO7amc14+LG +bqA+dlDba+4CmIG/daw6eE/0+9F6H4UaJM24Bn6VKIUqxkEjNQgxWc6toyMaehEm +2UVXv+rgcjr4SODBXLMgk7Uak3Xv8xmd7V2fgXMhApb67slMx5UbqmW5aRU877P2 +4fWJeAVQ01TEyUDlXz69NtIOJ5leg+VLv3KEE2SN2dtpiwQ36NsiRimECINANNjg +v8xcfLK9xTh9WeadiniHCBNvpX0viIDO5YY4b1O4mbr1IZ6PX6o6B3ObAvGXH4tS +U14kr9e5pD9OZMhiJrPARN27KYy1ZgVd/fc= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/ocsp-responder.key b/third_party/heimdal/lib/hx509/data/ocsp-responder.key new file mode 100644 index 0000000..140aaf8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/ocsp-responder.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCxIR3JK0SeYv4T +lOqh4c0XDrtNHGIn7tP3YcgmwQ9F/BDYOcPahqAAMNethv/GNmz14iaM9nYb0Am2 +pfjL1Yj8ysooSe1kK/OITo7sfGO4dWrMc7ZmbMN85NdQlYgShOdcUIfbTL+RmLE6 +RFcLGnrxk+NMaYuf17kgjQ7L/944b2qRVRpvpoIdBfb8RoyDi6tuP2pvxQzM/zx4 +dNT4Vr5ZYNU/TT7k4UstxSrRanohuW5hEAN5iFt09CkNVtNr1X2MWV1OiQ2jpotD +KOji8bvV62WbwtZiqt9m1ZLdhGwpKBroKbMJ0UUURMswA3M6lKOjJIkV+8rgpmI1 +SPiSUDr/F9hKHqCc2WjMIeHJNtFHvPFWPocYEA31VprJeRbACKBZZbIA3Zrpl+eP +he7NDSBeLVj/juPOTzZlw/GIOd00KduM7W7IezCtSVjm+VuFRgoED57qyqgqNQ1m +80i248fg6KPtbPPkzR1F8+IsbFuRuCbdSdR4005XOrWvzToF1Ylj9bxzHybMLEst +gbNdSSgERvgkWmgdBhstvlb5s/TRUC+Vm59Fx2I1vEap38ZFIekcfagusYeRC3z7 +l1Ix+UFzuoMiSoD5//GVdHn3IJXwFyB9rFXosMayplbGwM89eNWeN0G0eKow8C1Z +fGrIaMyRCRP4nwTjqYbCdLr2MkQNvQIDAQABAoICAF7zLJ9Y5ViuIhrnGfubKjBx +AjBsxaU4XkHfFcbIeOKAI5t1I6rxvbU8eXEYy+U56aDJEPdBasCv/XT+dWb22Y8B +Oers7idjdBGeYvkcGOyZbJ2aba1sIkLB/TXCYoXi3o7a0GjbNFnc6ywb1Dksgbkc +GJ0uet09a4yqcMMkLsA74Xl0kE5HiLn8J5DGVK5zYXsg3XJ6w8jkDUtY/Yz+Gt2Y +jdd4Ff3lU0J+zdwiYsPPPf8j8WjlknkYJSV0ZLMKZ1mj0eO2jiwqq75doLF++bzL +idU8VWXgyQ678BV01fIeAIZxS/s4Rfp+ghkD0HIXmbxralzxc6iHKF/99Nmhzm1o +/1PxIqTkso1G1MvizXgr54Uxdv7N01nuL+nDp4q1kBieCqAfkDbbbk9NQb/BUntx +ZZH2VJxFk8iit8O9BLPM5xiwsdx0QNeYEYQ+fXl75QCLN2zEMaPeOXpV6zWy2NR4 +P+eUEmOC+8Uj44/k21R/Zf46SAEB9YZPmAmq7rW9ACj17sj6e2F1hsVStMy3aG3h +59GG+sxMSIHwMJ/xB9r+xfaoX4iUapogy1N8pKyYL2CT6c2VB+wBW0gJsuxEGIt3 +x5LugOkCiArTOxTO54tTNeO/5+G+PkYrZwQazCuj9PQPTymHd4ieh61t/8CpasxT +faIJQt+GxtrBWI8Pc2h1AoIBAQDn22N6+XkouiQcg+sunLFwT5jxQsUZIOVAjx8r +WFoCW6onzltldxrpP+dx0nOaeBbwHTCRDYrHJhA3bmpaXjBYI8MunfYzHTxmCS1p +0/cGCMhcZc4dokOh60c1C9/UTG5hAEUAB9kP5C3H1OoL63OM24XQl7hwwX7WFOdL +VzzADDssLlfhsWRuXa9H5uD2ziqmWE6EZE9Jx5UlolgGpAGcS4YoJi5PaMnYdIJF +Cpf4gqhtuuUWD7brF9QCKF+e2lLqt4FHSrInqUIYD8HL4xToDPdKfxzUrI3S9dDh +g7yWWIRKR1W2IFSxBCwedLHl7VGpmgJ+RVovsTbnU+DLplGnAoIBAQDDktp+6FJP +WorkWUOUWLz4Ao3R3Cd/s7zZlhyNd2fjonH4uBry+X0Vunz2525YtOEVXcVM8Mqa +KDRyluAwp9pHYc3mhqGafWjoyH1+aDbkALSRcrGw1MkodqgSqxSt1RjgjXwbJb9Y +wUQSTxd7eJym2WtWAp0WQjH20ygMLu4Lt79HK6M+L0hi9lcxbNNxlQEC5FKgplLn +urpACHtzrUiIBfpu0LJL0E3dUytQUSVXE02R8j8STRO4lu3n90lZktEl0XuHEHqr +JXn+p1EhgxpMaYbKr+/v1dFc1RFnaDJO1b2IIaX4psKPPjF408EGqzwXeUen4RLJ +oaaDSTftN+n7AoIBACBe8w6yUgYrpusMSAOkAOoLUvEsP1R40UkoMlPc7AQ0RBd2 +qjAKZwl10JyFo3pHlfxENwmpeFzBpbX3hoXDbMCBjbiueTc9t7cPRPXnkC+Zfk/Y +LuTYSNUMgk6Xr9J2MVr9rKSKc/XSB8pEocC0SNe7tn0fEbM8cLb3CCvurB6sFn7e +oYpzN/BoyBYj1/jdY/sBjUTStHc6lEpC1kNnFop5yOtGGWUg3j2IVr/I8NrTcyyO +0Xk5DHLaStFaTa9iD/2RTU1k0mbTLNUrLgWHWN3lIYmXIbFXvh1cEKPLvsLG7QFp +4D+jV++3A2nlJQlTDvm89OgoSqUp+t5lSZdlSzUCggEBAJ+BA+aA/7Bsfd6i1rUE +coorOxMvZJ+ILbuf7AWMnxROhnl9Xa1QwS2ZfRW5xoteajyMz79imzqDE9NpLctA ++otBPzaGEwL2yTshWQhhYnMuCBaf3kAEK1NvAsDG+wSTScjKW6+gZ6Cxbx0nmFVB +FzIVHK93Tjq7HhjaOk1FcSvpXn1jH641zem4U4Ch6wk1py9+m80eGXuZFRHoWRcM ++pzFk2wRlXizmO2rSSYmKDgOLDOdyMbaSf1ASyPm0NHXJfCcGw0a6ZDv7cE9ILQe +QrKTVjW0rBGE5025EIqvtmgJdpyyJLTY/NDqvlp3CXSw7z+N0F0g+bustStZ6dz0 +v0UCggEAXsErHCyXn4LGb77CKdqLPC+VzXUtpY7ydBBOZ/4jemRdGn1YjgDPBrOl +tESL90Ir1F36zAQOenEOn2VIfCX0DWFLKA5FE2dRM/7X79yTOFwZ2n9Ubz0ulNVH +zHB2eSHsUhhVszRgqXFwWWwDnkqB7V8HkEXGodl77qf79KL6BQdBj9HbX/4Es1KS +C4OedUoFIgkvDppiG3mS9JftlHpKM60ckDpkTREdbsRxy2UEjXSdaW/ycJne+xYs +KKwq1IWDGJYoAfcH6f/9ipG/tC7e5ckUXIQO2bQdtVwqpL0b2VneiWdK4F8EmdiZ +SSGDNVUC8knNaz9M5HYwvqUl1if8yg== +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/openssl.1.0.cnf b/third_party/heimdal/lib/hx509/data/openssl.1.0.cnf new file mode 100644 index 0000000..b014656 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/openssl.1.0.cnf @@ -0,0 +1,190 @@ +oid_section = new_oids + +[new_oids] +pkkdcekuoid = 1.3.6.1.5.2.3.5 + +[ca] + +default_ca = user + +[usr] +database = index.txt +serial = serial +x509_extensions = usr_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[ocsp] +database = index.txt +serial = serial +x509_extensions = ocsp_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[usr_ke] +database = index.txt +serial = serial +x509_extensions = usr_cert_ke +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[usr_ds] +database = index.txt +serial = serial +x509_extensions = usr_cert_ds +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[pkinit_client] +database = index.txt +serial = serial +x509_extensions = pkinit_client_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[pkinit_kdc] +database = index.txt +serial = serial +x509_extensions = pkinit_kdc_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[https] +database = index.txt +serial = serial +x509_extensions = https_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[subca] +database = index.txt +serial = serial +x509_extensions = v3_ca +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + + +[req] +distinguished_name = req_distinguished_name +x509_extensions = v3_ca # The extensions to add to the self signed cert + +string_mask = utf8only + +[v3_ca] + +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints = CA:true +keyUsage = cRLSign, keyCertSign, keyEncipherment, nonRepudiation, digitalSignature + +[usr_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash + +[usr_cert_ke] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, keyEncipherment +subjectKeyIdentifier = hash + +[proxy_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:0,policy:text:foo + +[pkinitc_principals] +princ1 = GeneralString:bar + +[pkinitc_principal_seq] +name_type = EXP:0,INTEGER:1 +name_string = EXP:1,SEQUENCE:pkinitc_principals + +[pkinitc_princ_name] +realm = EXP:0,GeneralString:TEST.H5L.SE +principal_name = EXP:1,SEQUENCE:pkinitc_principal_seq + +[pkinit_client_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:pkinitc_princ_name + +[https_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +#extendedKeyUsage = https-server XXX +subjectKeyIdentifier = hash + +[pkinit_kdc_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = pkkdcekuoid +subjectKeyIdentifier = hash +subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:pkinitkdc_princ_name + +[pkinitkdc_princ_name] +realm = EXP:0,GeneralString:TEST.H5L.SE +principal_name = EXP:1,SEQUENCE:pkinitkdc_principal_seq + +[pkinitkdc_principal_seq] +name_type = EXP:0,INTEGER:1 +name_string = EXP:1,SEQUENCE:pkinitkdc_principals + +[pkinitkdc_principals] +princ1 = GeneralString:krbtgt +princ2 = GeneralString:TEST.H5L.SE + +[proxy10_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:10,policy:text:foo + +[usr_cert_ds] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature +subjectKeyIdentifier = hash + +[ocsp_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +# ocsp-nocheck and kp-OCSPSigning +extendedKeyUsage = 1.3.6.1.5.5.7.48.1.5, 1.3.6.1.5.5.7.3.9 +subjectKeyIdentifier = hash + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = SE +countryName_min = 2 +countryName_max = 2 + +organizationalName = Organizational Unit Name (eg, section) + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +#[req_attributes] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 + +[policy_match] +countryName = match +commonName = supplied diff --git a/third_party/heimdal/lib/hx509/data/openssl.1.1.cnf b/third_party/heimdal/lib/hx509/data/openssl.1.1.cnf new file mode 100644 index 0000000..110073f --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/openssl.1.1.cnf @@ -0,0 +1,185 @@ +[ca] + +default_ca = user + +[usr] +database = index.txt +serial = serial +x509_extensions = usr_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[ocsp] +database = index.txt +serial = serial +x509_extensions = ocsp_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[usr_ke] +database = index.txt +serial = serial +x509_extensions = usr_cert_ke +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[usr_ds] +database = index.txt +serial = serial +x509_extensions = usr_cert_ds +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[pkinit_client] +database = index.txt +serial = serial +x509_extensions = pkinit_client_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[pkinit_kdc] +database = index.txt +serial = serial +x509_extensions = pkinit_kdc_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[https] +database = index.txt +serial = serial +x509_extensions = https_cert +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + +[subca] +database = index.txt +serial = serial +x509_extensions = v3_ca +default_md=sha1 +policy = policy_match +email_in_dn = no +certs = . + + +[req] +distinguished_name = req_distinguished_name +x509_extensions = v3_ca # The extensions to add to the self signed cert + +string_mask = utf8only + +[v3_ca] + +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints = CA:true +keyUsage = cRLSign, keyCertSign, keyEncipherment, nonRepudiation, digitalSignature + +[usr_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash + +[usr_cert_ke] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, keyEncipherment +subjectKeyIdentifier = hash + +[proxy_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:0,policy:text:foo + +[pkinitc_principals] +princ1 = GeneralString:bar + +[pkinitc_principal_seq] +name_type = EXP:0,INTEGER:1 +name_string = EXP:1,SEQUENCE:pkinitc_principals + +[pkinitc_princ_name] +realm = EXP:0,GeneralString:TEST.H5L.SE +principal_name = EXP:1,SEQUENCE:pkinitc_principal_seq + +[pkinit_client_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:pkinitc_princ_name + +[https_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +#extendedKeyUsage = https-server XXX +subjectKeyIdentifier = hash + +[pkinit_kdc_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = 1.3.6.1.5.2.3.5 +subjectKeyIdentifier = hash +subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:pkinitkdc_princ_name + +[pkinitkdc_princ_name] +realm = EXP:0,GeneralString:TEST.H5L.SE +principal_name = EXP:1,SEQUENCE:pkinitkdc_principal_seq + +[pkinitkdc_principal_seq] +name_type = EXP:0,INTEGER:1 +name_string = EXP:1,SEQUENCE:pkinitkdc_principals + +[pkinitkdc_principals] +princ1 = GeneralString:krbtgt +princ2 = GeneralString:TEST.H5L.SE + +[proxy10_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectKeyIdentifier = hash +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:10,policy:text:foo + +[usr_cert_ds] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature +subjectKeyIdentifier = hash + +[ocsp_cert] +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +# ocsp-nocheck and kp-OCSPSigning +extendedKeyUsage = 1.3.6.1.5.5.7.48.1.5, 1.3.6.1.5.5.7.3.9 +subjectKeyIdentifier = hash + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = SE +countryName_min = 2 +countryName_max = 2 + +organizationalName = Organizational Unit Name (eg, section) + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +#[req_attributes] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 + +[policy_match] +countryName = match +commonName = supplied diff --git a/third_party/heimdal/lib/hx509/data/pkinit-ec.crt b/third_party/heimdal/lib/hx509/data/pkinit-ec.crt new file mode 100644 index 0000000..54435d3 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-ec.crt @@ -0,0 +1,81 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:06 2019 GMT + Not After : Nov 21 22:25:06 2518 GMT + Subject: C=SE, CN=pkinit-ec + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:c0:2b:8e:f3:0c:c3:1b:88:94:eb:4e:6a:12:f2: + fb:63:99:77:a2:13:7a:16:ce:48:dc:48:9a:83:91: + 5e:a9:b8:ab:17:77:94:ae:55:09:8d:69:4a:a4:a8: + 6b:77:12:01:fb:3c:6f:cd:b1:e3:02:be:63:b1:43: + 8d:8f:df:8c:75 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 77:9B:74:4B:75:90:50:CE:20:C3:00:9B:A5:23:F7:69:A8:C7:CC:34 + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: sha1WithRSAEncryption + 70:02:b8:13:0f:d9:2b:7a:e9:42:5c:82:6a:9d:ea:f8:51:dc: + a9:2e:67:ec:c3:cb:67:48:fe:6a:bd:58:86:67:c2:1f:d4:a0: + dc:7d:17:41:93:8d:e0:67:60:01:60:cc:34:1f:0e:b0:fc:9b: + 5f:f6:cf:91:2b:a3:ec:28:5b:80:ff:31:21:14:5b:3c:a2:5c: + 6b:3b:32:94:de:ab:03:d9:41:70:c1:4f:4e:49:4d:63:8f:9a: + 8b:be:14:87:b0:df:bc:64:83:e1:99:ce:e6:77:12:5a:43:e3: + 3b:d7:e9:10:5e:68:36:38:de:88:c2:78:af:97:a3:a2:4e:bf: + a9:2d:e1:98:f4:9a:35:ec:b4:2a:70:18:09:99:ff:80:fb:73: + 49:75:47:54:31:7a:e1:43:28:4b:53:71:81:92:4c:42:db:9b: + 52:38:ad:90:47:db:4e:da:75:6f:37:14:ce:56:6e:06:d0:40: + 8e:df:f1:71:23:98:ee:b4:43:b7:77:3a:1c:a5:a3:6f:3e:d3: + 5f:86:0b:6d:d4:b8:4a:2e:8a:e0:d7:d2:75:5f:ca:bc:9c:e2: + d8:b9:04:bf:ec:8a:1e:78:28:f5:13:73:9c:dd:2c:10:73:55: + cf:40:96:8d:8a:b4:1c:79:bd:aa:01:de:b2:de:c4:30:04:11: + af:d5:fb:cb:28:44:25:02:ab:b3:68:22:02:1b:99:b1:96:eb: + f7:f3:ad:6e:32:76:67:be:bb:78:bc:46:9a:1c:b3:8e:66:39: + eb:cb:d8:76:c8:06:e5:79:1e:f0:fa:54:3f:a1:ea:ff:60:e8: + fb:55:d9:1c:47:3a:e7:67:df:c8:69:1d:d1:9a:56:96:2b:01: + 79:ad:22:f2:7a:3b:e6:be:32:84:9a:e3:50:db:89:69:c1:3e: + 19:09:d5:b3:3c:2c:08:90:8b:93:aa:39:ae:48:90:ec:cf:79: + 3d:15:91:86:3e:38:0e:0a:99:b1:d9:78:14:59:17:44:c0:76: + 70:a0:7a:92:64:2a:60:04:aa:ce:6b:b1:d5:c1:3b:e8:1b:58: + 6f:7d:dd:dc:90:49:55:e1:37:5a:7b:75:89:da:08:c1:a5:33: + c9:f9:0d:4a:1d:08:e0:a8:be:3f:0e:a2:e0:10:71:92:50:f8: + 75:33:98:7c:be:c9:2f:c8:7c:b2:19:94:14:59:0b:1c:ca:bc: + 34:ff:03:a4:3c:f0:bd:ac:c8:f6:63:8f:59:d3:eb:65:e9:96: + 9b:21:a9:94:a7:7d:fe:dd:62:cd:77:62:6a:58:38:de:63:4c: + 0c:c3:ea:09:4f:6a:80:76:07:59:ba:15:d2:b4:c1:46:1e:11: + 50:5b:be:8d:8e:21:4e:78 +-----BEGIN CERTIFICATE----- +MIIDcDCCAVigAwIBAgIBBzANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwNloYDzI1 +MTgxMTIxMjIyNTA2WjAhMQswCQYDVQQGEwJTRTESMBAGA1UEAwwJcGtpbml0LWVj +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwCuO8wzDG4iU605qEvL7Y5l3ohN6 +Fs5I3Eiag5FeqbirF3eUrlUJjWlKpKhrdxIB+zxvzbHjAr5jsUONj9+MdaNzMHEw +CQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFHebdEt1kFDOIMMAm6Uj +92mox8w0MDgGA1UdEQQxMC+gLQYGKwYBBQICoCMwIaANGwtURVNULkg1TC5TRaEQ +MA6gAwIBAaEHMAUbA2JhcjANBgkqhkiG9w0BAQUFAAOCAgEAcAK4Ew/ZK3rpQlyC +ap3q+FHcqS5n7MPLZ0j+ar1YhmfCH9Sg3H0XQZON4GdgAWDMNB8OsPybX/bPkSuj +7ChbgP8xIRRbPKJcazsylN6rA9lBcMFPTklNY4+ai74Uh7DfvGSD4ZnO5ncSWkPj +O9fpEF5oNjjeiMJ4r5ejok6/qS3hmPSaNey0KnAYCZn/gPtzSXVHVDF64UMoS1Nx +gZJMQtubUjitkEfbTtp1bzcUzlZuBtBAjt/xcSOY7rRDt3c6HKWjbz7TX4YLbdS4 +Si6K4NfSdV/KvJzi2LkEv+yKHngo9RNznN0sEHNVz0CWjYq0HHm9qgHest7EMAQR +r9X7yyhEJQKrs2giAhuZsZbr9/OtbjJ2Z767eLxGmhyzjmY568vYdsgG5Xke8PpU +P6Hq/2Do+1XZHEc652ffyGkd0ZpWlisBea0i8no75r4yhJrjUNuJacE+GQnVszws +CJCLk6o5rkiQ7M95PRWRhj44DgqZsdl4FFkXRMB2cKB6kmQqYASqzmux1cE76BtY +b33d3JBJVeE3Wnt1idoIwaUzyfkNSh0I4Ki+Pw6i4BBxklD4dTOYfL7JL8h8shmU +FFkLHMq8NP8DpDzwvazI9mOPWdPrZemWmyGplKd9/t1izXdialg43mNMDMPqCU9q +gHYHWboV0rTBRh4RUFu+jY4hTng= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit-ec.key b/third_party/heimdal/lib/hx509/data/pkinit-ec.key new file mode 100644 index 0000000..0ac3fe4 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-ec.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg38AlgS7f0d6rvR6u +mLJVGl/UF04RYiIeWsVJYUNS7RKhRANCAATAK47zDMMbiJTrTmoS8vtjmXeiE3oW +zkjcSJqDkV6puKsXd5SuVQmNaUqkqGt3EgH7PG/NseMCvmOxQ42P34x1 +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit-proxy-chain.crt b/third_party/heimdal/lib/hx509/data/pkinit-proxy-chain.crt new file mode 100644 index 0000000..2b425bc --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-proxy-chain.crt @@ -0,0 +1,149 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIJAJd7zCsMMPvAMA0GCSqGSIb3DQEBCwUAMB4xCzAJBgNV +BAYTAlNFMQ8wDQYDVQQDDAZwa2luaXQwIBcNMTkwMzIyMjIyNTA3WhgPMjUxODEx +MjEyMjI1MDdaMDUxCzAJBgNVBAYTAlNFMQ8wDQYDVQQDDAZwa2luaXQxFTATBgNV +BAMMDHBraW5pdC1wcm94eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AM1Z218qhKJXqYoQ/5DZgDYNtgJ9QLkPF0vsu6cScVhykomP1H2Qjj3+u6ZFB9oj +YS/ynPgkCjwexA7nDGVxfrR0OksDNFGHwCu/O1wagzyeImgvYYzPlKyFqT+0IN0U +TgEoMdtXUduxmJGr0wEr2aMeiETUGZmRc02icTPZIznhf9elXmAp7EQspjtN9P04 +OCkVygr/FKkeI7XsZR8Ekzqdaf400g1Cy+X2kMvnRs/Tyf3qp/xv1RG7cDz+vfiB +8S/Vd2zSyBFboOZZi0xVo2vEs9nzBbmTQFAFINSEtIjJWb9Tupz4YwU/xK9bq2G7 +/eOrt4e9pXry1gUKNN/qZIEkbaebhWxW6twMVO/nyXlnklpF1PvPKHsWP2JqhJK7 +9SZcqZkeRit1wlwXsWhb+Zzl27K74P1WgNQF9lbPwhQ6bPmadirCs0kkMBDjmh4U +SJe/5wIOLVPY0KrhQeC7Vn+hkCxqRTwZQuLKDWUKgd4jmvsjfLYAZVQfGUBX1x7D +Wng44pW7ytOSbn/4pAu38FGGLbPcKNw+cRRtHtBpWiCthDIJ6gOmJo8JngaU2Iss +ozmxfGZsdQscUEFVwL5X9YaBpWcGKKxZH7UXq3S3wOEm2yQ6/UrdJnuP+xIYFEiA +c7tQIFBYoX11+/cZGyVZmn8ESM4ytw9QqmxxaDAEdaJjAgMBAAGjYDBeMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBSU/W8lX964Gjrb5YqSo3zg3XLl +vzAlBggrBgEFBQcBDgEB/wQWMBQCAQAwDwYIKwYBBQUHFQAEA2ZvbzANBgkqhkiG +9w0BAQsFAAOCAgEA2bcpIO8UZ7eDFPtIZd6BWVrQZ5Dj+LZA0KV2v+FjoZQN0/w6 +gzloDy0x3yym6lOtCNPnjxcYP2yfGl5WZet1VXCR+KXXHGID2MkOXhXTCH7eSCGC +GZpOsSEWs+CXyP/X5B85nkweK8MzLRdJc4Ilxf1UMMOdobgQnRq41NgWyQxA8xLR +jEeGV+CD5dvteyqBeXvq4IBBUTqAiyoH57XXZRPwWH7z3h9f7B4GdoQuRBQK+idM +hLgtQ9nkT+DDyoMC6iAtIVwntxsAIg5rUSkQ6RgS3ap6SC94+v3q5V2BJaJl/R+0 +X5ybK2hRKWsUAvU280UX/xT5EGeokHwegI+F7yQflTGI1p090uhBYZvWYj2G8wf5 +nlE7a2h8IG3SmS7qUlKe+RyPwHce+jgHU0aS3ROxreLGf/VX1k3yR2Vk0wpVWFis +WeC7U5g+iqv/UomqxpFwP3iH8RJhL3eGYVmatHIXjm838wepofexqUL4UKoY/t+h +FmMusCz2SFZFbgOHF1Vd9C3c/mr6J4HbYju1hO09iOFuQmoo4CjNjdKyLvP1HSap +g7IPdLP0f++1gGcRq8AkFC9U/vZx5OPwjIku645WeOBoLhFcSoLxyhMeekSNXpwS +WHArnvVC7cmuvuzmzf5+XqmBzSD0RWGK09drTZdryXuzv8djbeqldeRr1Zg= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:06 2019 GMT + Not After : Nov 21 22:25:06 2518 GMT + Subject: C=SE, CN=pkinit + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e4:e6:1a:b1:de:91:30:34:8a:c7:f2:d9:0a:09: + 82:13:46:e9:db:c8:54:1e:0e:b0:b0:0a:e3:a3:b5: + 55:3c:6f:f8:45:8f:24:ed:56:c5:16:23:aa:ad:86: + 5a:5a:e0:8f:a2:f5:82:59:cc:70:b7:45:cc:1b:44: + a7:49:4b:ff:63:28:9d:01:22:79:ca:1a:6a:2b:75: + f8:40:c0:f0:93:b1:ab:85:cd:af:88:ac:30:f3:cb: + 42:87:fc:be:76:bb:fd:1c:a4:45:7a:66:37:47:ea: + aa:bf:c4:4b:47:fb:5b:ab:3f:c1:22:a9:06:f2:61: + 3d:5b:20:51:fc:ce:a7:82:74:6f:3d:ac:68:d6:78: + a2:77:83:26:af:23:63:20:3f:21:6e:29:1f:55:4c: + a6:d0:5a:51:e5:96:c1:cd:22:03:22:ee:de:42:3c: + 82:4d:29:20:c6:be:85:5b:04:3a:5f:8b:c7:e8:4e: + aa:3c:8e:dd:0d:d8:e5:d0:ff:0b:52:37:40:51:0d: + 33:f7:a8:05:07:76:dc:48:20:cd:52:38:a4:1f:44: + 11:cf:6d:58:a9:5a:9a:34:cb:93:07:30:e3:66:7b: + dc:d3:0b:6b:a2:1c:3f:19:ec:0b:0c:ea:29:6c:75: + 4d:7a:86:cf:35:87:9e:50:15:f3:34:73:0e:ac:4b: + a5:aa:1f:a2:f9:d5:8f:34:bd:5f:19:ae:22:8c:7f: + f7:ca:64:e6:ed:42:75:e5:92:9c:53:53:b7:66:68: + e5:07:eb:08:40:ec:bd:7c:ae:b0:c4:a5:4b:d7:4b: + 58:86:05:a8:91:db:ee:7a:3f:c4:fd:83:e5:7b:cb: + d0:8c:87:68:3b:83:67:e5:6a:5e:fa:28:b5:ee:07: + b1:0d:6a:93:1e:b0:c7:5c:57:fd:ce:e2:9c:0f:5e: + fe:41:cf:20:f2:1d:88:52:00:d4:83:fe:5b:d7:87: + 49:b0:78:2b:a7:60:c2:55:c6:c3:a2:6d:16:04:7f: + 8b:12:f7:65:c6:91:41:53:d8:ac:70:c0:3d:83:d8: + e0:6c:bb:3e:48:b8:c2:72:be:c0:35:61:40:ff:9f: + 97:18:9e:c7:39:0f:93:36:8f:0e:a6:3c:6d:5b:fd: + 89:6a:bb:ee:5e:43:f8:0d:29:7a:cf:23:bf:0b:c1: + 29:76:ae:a2:9a:73:b2:d0:b9:bd:48:51:25:8a:6b: + a9:c5:07:94:26:03:10:74:7b:fc:b7:5d:8f:2d:97: + 55:11:3e:7c:04:89:0e:b9:b9:73:2a:6c:5b:12:19: + 65:92:48:64:d5:4f:2c:79:3f:16:ad:65:97:21:db: + 3c:30:68:67:aa:42:14:86:59:57:b0:79:15:9e:a3: + 05:4f:33 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 7A:C6:DB:B8:D2:75:D1:8D:BB:72:AE:B5:25:6E:6F:8C:AF:63:3A:4D + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: sha1WithRSAEncryption + 7f:5c:76:fd:3d:ef:0c:7f:70:c7:09:d3:5c:c1:b6:40:25:47: + a3:6a:bf:4e:ad:d1:e6:cc:92:86:b6:6a:42:3d:4f:bc:f1:6f: + fd:7e:22:52:9c:dc:a6:0b:71:98:80:44:cf:f1:91:bb:50:c8: + 15:cd:8c:d8:9c:7d:8d:69:61:1b:4c:66:40:77:44:45:33:9c: + 9a:04:01:a1:4b:82:3a:d7:39:97:27:90:a6:71:9a:b1:9c:ce: + 60:01:8b:a5:6f:39:a3:e1:75:de:3c:5c:61:66:a5:50:db:0f: + 4a:03:32:8d:dd:e5:b6:ab:6a:b2:53:6a:4c:c9:99:74:f7:f5: + 1e:a5:06:1a:d3:64:26:c5:77:f4:a6:40:1a:c4:7e:22:05:a6: + a5:25:f7:5d:74:a5:c9:86:c0:3a:88:2e:6e:0e:58:4f:e5:6e: + e9:2a:34:2a:1d:1d:a4:e4:74:f3:a5:e5:56:5d:5f:02:c4:eb: + c7:12:f2:55:6a:f1:6c:ec:6e:b8:c1:2d:aa:4a:7d:ed:91:c8: + 78:1b:b7:b9:37:17:32:ee:1b:b5:d9:5c:98:d2:cf:d8:c6:90: + a5:c9:f1:eb:8d:2c:d4:90:b2:8c:e5:53:9a:66:20:92:8b:a2: + 0c:8b:76:9b:5f:5b:39:77:69:67:a7:8c:de:10:57:85:45:a4: + 8f:85:3a:59:5f:fc:0c:70:de:1c:67:33:5e:9b:a5:21:3d:bd: + 2e:de:3e:c2:0d:cf:8f:52:43:92:01:cc:47:da:af:47:85:69: + 94:d3:9f:c9:d5:5d:50:ca:27:a5:bb:c0:53:12:e0:e8:3c:ed: + 0d:bd:47:97:af:be:b8:f9:0c:10:2a:79:21:3c:15:ef:c0:a5: + eb:33:38:93:5b:a3:de:1a:97:eb:c3:db:04:1f:e8:f4:23:10: + ff:2d:1e:9b:4e:1f:8e:27:7d:71:34:e2:be:74:a2:62:69:9a: + 83:7b:6e:9e:e4:a2:7c:84:82:ff:83:b3:cd:d2:0f:74:05:72: + b8:b0:45:23:b6:cd:04:25:2d:58:7f:92:ce:68:f9:ba:d0:9e: + a8:e1:f8:c0:86:0e:aa:ee:f9:af:ff:5c:bf:46:76:08:b1:83: + e7:66:8b:ca:1b:8f:f4:9f:6a:ac:71:4e:3a:d1:77:fd:97:81: + ff:0e:d0:d1:4a:7e:6d:94:e6:8c:e1:28:92:b1:68:83:5a:62: + 48:0d:26:ee:28:60:57:ff:52:b8:1e:8c:03:d8:fb:c1:6e:4f: + fd:7a:46:0b:0f:c8:05:ad:3a:a4:68:be:fd:30:62:ce:f2:0a: + b1:34:2c:95:e7:e2:91:ec:a3:c6:4e:2d:a5:fe:09:45:84:38: + 9c:d7:f4:0b:18:22:9d:df +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIBBjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwNloYDzI1 +MTgxMTIxMjIyNTA2WjAeMQswCQYDVQQGEwJTRTEPMA0GA1UEAwwGcGtpbml0MIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OYasd6RMDSKx/LZCgmCE0bp +28hUHg6wsArjo7VVPG/4RY8k7VbFFiOqrYZaWuCPovWCWcxwt0XMG0SnSUv/Yyid +ASJ5yhpqK3X4QMDwk7Grhc2viKww88tCh/y+drv9HKRFemY3R+qqv8RLR/tbqz/B +IqkG8mE9WyBR/M6ngnRvPaxo1niid4MmryNjID8hbikfVUym0FpR5ZbBzSIDIu7e +QjyCTSkgxr6FWwQ6X4vH6E6qPI7dDdjl0P8LUjdAUQ0z96gFB3bcSCDNUjikH0QR +z21YqVqaNMuTBzDjZnvc0wtrohw/GewLDOopbHVNeobPNYeeUBXzNHMOrEulqh+i ++dWPNL1fGa4ijH/3ymTm7UJ15ZKcU1O3ZmjlB+sIQOy9fK6wxKVL10tYhgWokdvu +ej/E/YPle8vQjIdoO4Nn5Wpe+ii17gexDWqTHrDHXFf9zuKcD17+Qc8g8h2IUgDU +g/5b14dJsHgrp2DCVcbDom0WBH+LEvdlxpFBU9iscMA9g9jgbLs+SLjCcr7ANWFA +/5+XGJ7HOQ+TNo8OpjxtW/2JarvuXkP4DSl6zyO/C8Epdq6imnOy0Lm9SFElimup +xQeUJgMQdHv8t12PLZdVET58BIkOublzKmxbEhllkkhk1U8seT8WrWWXIds8MGhn +qkIUhllXsHkVnqMFTzMCAwEAAaNzMHEwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAw +HQYDVR0OBBYEFHrG27jSddGNu3KutSVub4yvYzpNMDgGA1UdEQQxMC+gLQYGKwYB +BQICoCMwIaANGwtURVNULkg1TC5TRaEQMA6gAwIBAaEHMAUbA2JhcjANBgkqhkiG +9w0BAQUFAAOCAgEAf1x2/T3vDH9wxwnTXMG2QCVHo2q/Tq3R5syShrZqQj1PvPFv +/X4iUpzcpgtxmIBEz/GRu1DIFc2M2Jx9jWlhG0xmQHdERTOcmgQBoUuCOtc5lyeQ +pnGasZzOYAGLpW85o+F13jxcYWalUNsPSgMyjd3ltqtqslNqTMmZdPf1HqUGGtNk +JsV39KZAGsR+IgWmpSX3XXSlyYbAOogubg5YT+Vu6So0Kh0dpOR086XlVl1fAsTr +xxLyVWrxbOxuuMEtqkp97ZHIeBu3uTcXMu4btdlcmNLP2MaQpcnx640s1JCyjOVT +mmYgkouiDIt2m19bOXdpZ6eM3hBXhUWkj4U6WV/8DHDeHGczXpulIT29Lt4+wg3P +j1JDkgHMR9qvR4VplNOfydVdUMonpbvAUxLg6DztDb1Hl6++uPkMECp5ITwV78Cl +6zM4k1uj3hqX68PbBB/o9CMQ/y0em04fjid9cTTivnSiYmmag3tunuSifISC/4Oz +zdIPdAVyuLBFI7bNBCUtWH+Szmj5utCeqOH4wIYOqu75r/9cv0Z2CLGD52aLyhuP +9J9qrHFOOtF3/ZeB/w7Q0Up+bZTmjOEokrFog1piSA0m7ihgV/9SuB6MA9j7wW5P +/XpGCw/IBa06pGi+/TBizvIKsTQslefikeyjxk4tpf4JRYQ4nNf0Cxgind8= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit-proxy.crt b/third_party/heimdal/lib/hx509/data/pkinit-proxy.crt new file mode 100644 index 0000000..d92acdf --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-proxy.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIJAJd7zCsMMPvAMA0GCSqGSIb3DQEBCwUAMB4xCzAJBgNV +BAYTAlNFMQ8wDQYDVQQDDAZwa2luaXQwIBcNMTkwMzIyMjIyNTA3WhgPMjUxODEx +MjEyMjI1MDdaMDUxCzAJBgNVBAYTAlNFMQ8wDQYDVQQDDAZwa2luaXQxFTATBgNV +BAMMDHBraW5pdC1wcm94eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AM1Z218qhKJXqYoQ/5DZgDYNtgJ9QLkPF0vsu6cScVhykomP1H2Qjj3+u6ZFB9oj +YS/ynPgkCjwexA7nDGVxfrR0OksDNFGHwCu/O1wagzyeImgvYYzPlKyFqT+0IN0U +TgEoMdtXUduxmJGr0wEr2aMeiETUGZmRc02icTPZIznhf9elXmAp7EQspjtN9P04 +OCkVygr/FKkeI7XsZR8Ekzqdaf400g1Cy+X2kMvnRs/Tyf3qp/xv1RG7cDz+vfiB +8S/Vd2zSyBFboOZZi0xVo2vEs9nzBbmTQFAFINSEtIjJWb9Tupz4YwU/xK9bq2G7 +/eOrt4e9pXry1gUKNN/qZIEkbaebhWxW6twMVO/nyXlnklpF1PvPKHsWP2JqhJK7 +9SZcqZkeRit1wlwXsWhb+Zzl27K74P1WgNQF9lbPwhQ6bPmadirCs0kkMBDjmh4U +SJe/5wIOLVPY0KrhQeC7Vn+hkCxqRTwZQuLKDWUKgd4jmvsjfLYAZVQfGUBX1x7D +Wng44pW7ytOSbn/4pAu38FGGLbPcKNw+cRRtHtBpWiCthDIJ6gOmJo8JngaU2Iss +ozmxfGZsdQscUEFVwL5X9YaBpWcGKKxZH7UXq3S3wOEm2yQ6/UrdJnuP+xIYFEiA +c7tQIFBYoX11+/cZGyVZmn8ESM4ytw9QqmxxaDAEdaJjAgMBAAGjYDBeMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBSU/W8lX964Gjrb5YqSo3zg3XLl +vzAlBggrBgEFBQcBDgEB/wQWMBQCAQAwDwYIKwYBBQUHFQAEA2ZvbzANBgkqhkiG +9w0BAQsFAAOCAgEA2bcpIO8UZ7eDFPtIZd6BWVrQZ5Dj+LZA0KV2v+FjoZQN0/w6 +gzloDy0x3yym6lOtCNPnjxcYP2yfGl5WZet1VXCR+KXXHGID2MkOXhXTCH7eSCGC +GZpOsSEWs+CXyP/X5B85nkweK8MzLRdJc4Ilxf1UMMOdobgQnRq41NgWyQxA8xLR +jEeGV+CD5dvteyqBeXvq4IBBUTqAiyoH57XXZRPwWH7z3h9f7B4GdoQuRBQK+idM +hLgtQ9nkT+DDyoMC6iAtIVwntxsAIg5rUSkQ6RgS3ap6SC94+v3q5V2BJaJl/R+0 +X5ybK2hRKWsUAvU280UX/xT5EGeokHwegI+F7yQflTGI1p090uhBYZvWYj2G8wf5 +nlE7a2h8IG3SmS7qUlKe+RyPwHce+jgHU0aS3ROxreLGf/VX1k3yR2Vk0wpVWFis +WeC7U5g+iqv/UomqxpFwP3iH8RJhL3eGYVmatHIXjm838wepofexqUL4UKoY/t+h +FmMusCz2SFZFbgOHF1Vd9C3c/mr6J4HbYju1hO09iOFuQmoo4CjNjdKyLvP1HSap +g7IPdLP0f++1gGcRq8AkFC9U/vZx5OPwjIku645WeOBoLhFcSoLxyhMeekSNXpwS +WHArnvVC7cmuvuzmzf5+XqmBzSD0RWGK09drTZdryXuzv8djbeqldeRr1Zg= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit-proxy.key b/third_party/heimdal/lib/hx509/data/pkinit-proxy.key new file mode 100644 index 0000000..6ef1f81 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-proxy.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDNWdtfKoSiV6mK +EP+Q2YA2DbYCfUC5DxdL7LunEnFYcpKJj9R9kI49/rumRQfaI2Ev8pz4JAo8HsQO +5wxlcX60dDpLAzRRh8ArvztcGoM8niJoL2GMz5Sshak/tCDdFE4BKDHbV1HbsZiR +q9MBK9mjHohE1BmZkXNNonEz2SM54X/XpV5gKexELKY7TfT9ODgpFcoK/xSpHiO1 +7GUfBJM6nWn+NNINQsvl9pDL50bP08n96qf8b9URu3A8/r34gfEv1Xds0sgRW6Dm +WYtMVaNrxLPZ8wW5k0BQBSDUhLSIyVm/U7qc+GMFP8SvW6thu/3jq7eHvaV68tYF +CjTf6mSBJG2nm4VsVurcDFTv58l5Z5JaRdT7zyh7Fj9iaoSSu/UmXKmZHkYrdcJc +F7FoW/mc5duyu+D9VoDUBfZWz8IUOmz5mnYqwrNJJDAQ45oeFEiXv+cCDi1T2NCq +4UHgu1Z/oZAsakU8GULiyg1lCoHeI5r7I3y2AGVUHxlAV9cew1p4OOKVu8rTkm5/ ++KQLt/BRhi2z3CjcPnEUbR7QaVogrYQyCeoDpiaPCZ4GlNiLLKM5sXxmbHULHFBB +VcC+V/WGgaVnBiisWR+1F6t0t8DhJtskOv1K3SZ7j/sSGBRIgHO7UCBQWKF9dfv3 +GRslWZp/BEjOMrcPUKpscWgwBHWiYwIDAQABAoICAQCIK2e+qXEePccc2Ly/jpro +PRtOd0Qt8wXdwPOGjEJBBmiJc6jSQsMv9PT2Apx8WC2gH99a5Hss9rHHuAqOUj5U +5yWojE1rKvuRhtOT9bjEv4/NSm4Dc7sA0/kxVv7b2xUGy2KUMkkDx7aGEkxvYGaH +Nj3idksrfDnbZzZtzTUAsrmVhAEa/3G+m2T3unAUYe1LwTkjJZbLtkKz5jf/44bF +vZCFkv0e8gZHTcMikxBvy98L00jlqjq98W8x4zKR0Yjf0UvKC9PDPuFpHkOysK8X +TW59vhszvaNN7LiidAVLF0m+B4WdhVAUMP750W3J92EaUcn35xgOeWzWFriNKt7N +W9P288jWeNazQoNS6ygi9zJERX869UWxw+SAiWlymhmFC9tQgMEH1RJy3TtrFQpa +krDv8mnkYBLU7BUI//jEbWLSfrXndHKgsLEO+bXViVV80PqX3d6xxTRItuANcZKy +Yz4kA4aKDg1lrDcDMUTG4BZJthHD1xlCg7d+xnxVmamsoQ89AyErsYmVMxd5C2IA +TbCKseKyPd7nztHc1ktEdpM6DhXqrZw0o1pCVSQeXkPpFqG3b0vwtZFYiyNwJGpW +Wzn3w7f6ZRwZYAbj3t1Esxjw+ej++6DTbUBZWRllhgpMoryCbtCfWRsL7S4u6I7E +1dzmF8pdJ+vvOaeC5BZxoQKCAQEA7dPAX7ZCOp6Mgp88VIBw4Rb6duSBPWqiL3mn +4BtV2UFbU+So4Ro5SRUF1O6KJ8tZsyRfGZn+B+wSjPUsgp4dFfpP1GSQvIk3HkEU +Zg6VNvxPRd/oloRjvG119BBXr7mpkCDEmGxLqXAvxvafFc4gGajFBRISPWLsDAYu +0yDMkCmPWMWMLx/sYLv2lE/0GLa7oOO/5flHFM/Mom4HOactq6nghHT8Rn77b9zg +WOyNsX0nZTtjLlWGjH/R2mRLYwI1mq3cUTCnwRNPYhgbgIQS7666jtfUP17H1W2H ++hZrggrmVVHzYSW1Z2fLUTAMXuPUE98bnF5LytoZ1huMQU6ESwKCAQEA3QrTAZwj +KU9Kc/Ur9K047Xfs56XpOtlo67sWY8GQRxFv+pIKT5zJIJBm6O/9Ps+ZuhykzOdZ +uuee8pDzszFw6jprRpEutFRh//xBE+VKW1SQipKKS8hHYIH+BJlLBJ0VdvQCtoLX +sTOmmL7E3szuKUEmCPQqYj3VrAWQXqzNF7uQdns62lSBLI2b8ZuwBbS6Pk4J9Ic8 +d902+y9kTO2j4jipMQHxVVEoaksZxdVTUZgAlku+xkMM/oxQclMoXnx4uemiQoxq +u6k0waZpW5yvlNys23YCFPl8A3tMWZ0HC5UOQVXL2KgsVLAoYvNJAhQxWbSj0i6m +sRSsEN/SmJobSQKCAQBJkZRTxzyLh5otmfZ+qVDBwGrwNlVoW0EacIamw631y8rl +k7lOEN+hpNgt+zBPiQ8RZHHqqIE1kChY5ErFiQW0U784E3fWapfbSwR1YZN08+3N +zqrTTNbRZgbz3c5SNJuoUwqdn/pzypls8cNaam3xogx4OhPcW2precooU2AURFbs +fgeUWEq1zc9EJ8t5jaVS6sDk8gyz+mfx4xlnEzkEfkNOliWn5QYAn5Hi0CIwwmda +YFmY7qn1cmDHLvlHAlr0o02g6+0ow8FttclkIvb8n89j+o3UoIwukHhcu2y8SITh +5bzk01ZfS3NQhQ1+mPl0wDJ5V44YjQkq+1CSrygrAoIBAQDN9K/26Ay7CO5ObTqv +mFdarEtI7AYMl1Zzjral7E0Kauzzg++njma4uNOqZzKHu9d42geUBFxPElG/od/w +LzkOhbA+6DekPpuxcNESQKqvvnOPKktBoTMgcP7GOi7z9YlydJmyhOeEbKPl3pqB +HmEqf1F5NkfnkcXtqqGCFXBjlJheTSPhGqvhX3DWBkJUjriaJQyRkxB8ftoj4VyL +cUEqH7FFwJGk9SG7KI6zDrm7ZO3nHFx9TyxkYUjzvRf4MfIrB83wQ/WPNXG6ndu9 +SJkxEwzcz2/RK0Sp2dCiDvXpjNDjf5WYIdpsblazHAwCq93vv6iExoL6rFBGyMXo ++m5BAoIBAEEH9DWpYZRLw2SQbsdSgMRRFo2Kvu7jpmCbQVWlBA2WjAUIPhie4hkt +DUUKVROwzPXinMCkZuZ1YL/A1R9gJ30Qo+c4Cj6tKlZ8Ux5cmEOjLfQuREMsJ9Tv +wYyFodqKW4wRvtNn2Ij+C/VV4dDncIMM0mw8EoQ4/DP2aseqzG49rOrYGl43gs1l +RTMyyPiWyweJZ2e0IRSnqrcSEcvPfw9ViZWNVAHMycA6ttt3gSi0+57OjPmxeEPC +9z9x5N+7zKOfpUo6/jguC1TRFzmKJYpMlRhM/0Ruz2imghKMn86PUKI/GBrOXhx4 +k2odOmvIh8CJ2ZSNtza8KPoCHxzIOQU= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit-pw.key b/third_party/heimdal/lib/hx509/data/pkinit-pw.key new file mode 100644 index 0000000..3fef51f --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit-pw.key @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,0D7945ED368F10EDD0E5FB517DA6CEDD + +U4MlgA6Abbuv+8v7XUYDCxGw8Sd4xWCuxFWu3+twUWfpN3MG95RPuCf21m1rXb0q +BmmyRECQg6Kk+wuFKVeKEVsBT5pJ/CmutPeE3Y1Oxkn0G09RygO3+mrZInnMdACM +9TYYUA6AGp67hF4G5pJUk7T+Zdfu5+pxhzsRC24UussXFlUtnPCS1QlRWUraVpzs +Ei7whYsfz3Fcw5ZEo5b9z+NHqU3OIMfLH2Q0dPJ7Y2gHtteaftmOcRALcz7l4Jug ++9YCAOChw110BII76z6fwPDKbJuMAlZuzhB4XFfYbwVqvMbddQslANb2PiaReIRk +g52kJY/cMb/nSbGwf0ZG9rGhcuw6xdvMoTFPtqqy7NXEPxfwlxoAxsJVg3Rp/4d9 +M8h4mOyvDjuluIK1GpPfoHGCOYFyduaQQM+KZ00D08j/d8y8RkaD07eXOLQE3CHY +qXO8fE91lpcnxVRVCv1s4v63/FgqYrrU7rqSgGaQwKrcZK4hZEbL8yMcJFe4KOoJ +m2k7pqi6hL9JILz7G9+oMnrObOZ9aK+ZiXz09+CxWYhwCcQrFXaK9XKDUWLqoSZn +ZBj1xYqwW1kvhybdUENHXUVh3G4lA2+sWbEKvSLwcAsiIVkYxuiWwb9Ix5MPCKDK +ZuzIQaQ5Ji5PWPqCR4iYdt8BOq/r2iMEUwJ2KZtxRcPknbH94rt31dz0cXr/fFO7 +OPxGTuJILIvf+wRZ88x8hmYA6JjRvEHZDrlwmk+uoUBsOYEcVOg7hd/AQYd1BZWQ +HvlELIHaGgLxmq/C1InRbU/mtnIElBHAI3NLKpSgGyFH4/Mis/M/VnHJaC3sWKFR +bJ5SobVa8HYgRy6y3mA/DsssGVj/dz2riTzjCXpNmju83D8wGJ8iDjJP0183R6Zh +Rb83W3EAjkHHLIkli40E7H6cq1RjXTrzUpvE21Yq5vbk6rBnLRO/lDX4lpFq0S09 +Rd8UQUhXqTxtOGXIFv/4sS2P4oIAx+mk4pf+iJMltjvCLCNkPQRL+NewVHMm4zhK +25Yo9SNObY/zk3MBKH0FnI9xAmS7xUdzjRTQvP8yqBu0lQfJo2np3FsjtGyvjYWO +b11L4mc+n19LCA2PpU4VaWxzPfZraBBHJy75Cqk0xXx/9obtrgZ89qXgv6H6PZod +8W64PUK+895+07plpOAmrS0WZL0muh5m9qarabmY0dcoiG16Ln2iAEJTvepKn/7f +H7rC8OoFr6AWYRx3hj0dLCSs6VPVFLAyQvEPIQlPFndT8rhuP9z8W1W6OkLpe8wE +fVFL3jNMwRTYTB9aAwFFeyrf1CbaTs8iRmp0eZgTteNbhshx1UdAasj7sLLUhPFe +cU9evtCKFqoRfSiuR0uzetWMJ7vODxGDzGkbDhIqVRpcUaBz6cQs4NlslT/ebXe9 +5xL6KWI3vUIJeWcTEJbl0sUTBbmRUxPB636XdQ4l3OIYI32NK29fX2+2pHXqaWql +L8iVwsLJM422pxHdixGmO0eLEJ1Y62tvmTWQ3Nr+/ZJP8h9yk61gj2QTHOVAyz7o +UxZie77035ni7vZG0AjJDz80hj9rnMpznTUZCiEzArJ65RTrUmiiedSyatHYEREK +pC3+2aqvrOaGCikIfFTAEOKlE2ZjDVZ1jYCFCVFmJE6sqtpIigMeiChsFlxg4FCo +zIvfFEY6QdnqHPvUMsXNr/p5xcVQjZhitk8Av/Lr1gSsHapiRthbty2Yry1r2QYb +T79qdouzk0sGdIORM5SmEvPAp/459cy91nIEav4eC5JB/owPyPB5KNuz6wL1Guo1 +TUDoOyR/vkB4Ybm9A4se6ldYftK3nxiFCL96SgqFP5WC6JAwZROBKFn5HWLdVPOD +/lXB3SxGe48PjcAX2ugo8KySpDC41uUIHOdxPeRBUPWB9bRpAmLfV7lsBC0X7fPn +ghdnQav0TcQTOwChNaCLpUSzRzk71y7IR/4LASgm7WZUoV3YF8SarsA+wOvKCuKf +GJJThmSRzhSU8xbyU8hdVAd0XT8d2tSNJLuJ8PT//dqbh4Ft6U+DjpNX2XUtAINe +9L61Wpj5HduTqcXSTeHnhdDqjuAEGrFkR3P/SmA/r+uaaVvi/sbbh8cBqvjC3O40 +Z+e4JDd2XvjCgChdJIOUJfHfvLGjkaGJIecizT8YYGO0FyebnPPah/Jj1R4XPaWZ ++Wu2ro1/GKKnHCsIMbEz4BbGrapi63RWGRufNhVE518CX7vMsqgbMFgspfbUinrq +N6+5MD/VLrMkbCrYxVFRP8Lcug4IJhRjV9olI9GEN7/ulMV8A4UQXh0K9zPox21H +qPf9kgPpd8GNWXZ+/kQkuLL74BjWCiiUxqDLFY6xKN+5yPwe9l0TNymuSNAxJCMZ +2Jyfhaq3R7AlqNisoNFO99g3HVXXowi1dK9hc2AqXdqyN5w6LrO8eAy3FQsBv8iD +pFruJeMve+Fohzrnb8L9B+Wm5nNUH9Z1/jsR+/rnaoqOYl1qza88URqlcy8ovPXh +1y3d0YGZi877nzLPTe0WPSy0ueJkolqx27hrwvLA6SLBFwzg174pS/vmH1cmEKep +ZekUuAUxp3pJ70Dzu+lsSnye66mUxx56JHGcCD1uiUkB8qWXTGrnTGkxUJYfZoip +0nX6YWChnuXkQ46B/tYIaP0+d94LkqjB2VzEDv71oXU4uTD2hqK2i2oTRlXQUBV6 +iNutj1sawU7WUXBRUf0ls8GRIHb6xvNVwnus0/P0VnUkTMCVE3ohQCw2SLkCiPtX +o24G7A6jNCsM3XTfK68P0TqkMKg5wYJM7Pbt4FLBRxy0uzeR6GarMneLP173rH+Z +LX5zVvEveL6yHnmKHZm9OoXj+NNn9HkUdCWqxmOvYNl8TTRh58ZCIUDJn4ZQcMkw +jjOSPfaPWkNrLXm/PxW55JmLuewgHGWo/1gfJCrewrvkuXWJffL09An1/rJoqb0B +TSFAKj6c/WhJvG7qFYLd7+tMfoet2exw34uP6tvi8Lq/u6cG63wXKbzhpXtvyqOs +wOOVZDnTskF5syX20FojeKCLCUQWIMv/vYKlrCeA0zpxL4qQFxpHlHAI2cw8MtVa +Cd8XFmQihZRm+7A8dDsL0AU5ai0kh7yIAhZZ/bR4sUscnbO2y/w+AItcBbfcCK8T +-----END RSA PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit.crt b/third_party/heimdal/lib/hx509/data/pkinit.crt new file mode 100644 index 0000000..3f20629 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit.crt @@ -0,0 +1,119 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:06 2019 GMT + Not After : Nov 21 22:25:06 2518 GMT + Subject: C=SE, CN=pkinit + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e4:e6:1a:b1:de:91:30:34:8a:c7:f2:d9:0a:09: + 82:13:46:e9:db:c8:54:1e:0e:b0:b0:0a:e3:a3:b5: + 55:3c:6f:f8:45:8f:24:ed:56:c5:16:23:aa:ad:86: + 5a:5a:e0:8f:a2:f5:82:59:cc:70:b7:45:cc:1b:44: + a7:49:4b:ff:63:28:9d:01:22:79:ca:1a:6a:2b:75: + f8:40:c0:f0:93:b1:ab:85:cd:af:88:ac:30:f3:cb: + 42:87:fc:be:76:bb:fd:1c:a4:45:7a:66:37:47:ea: + aa:bf:c4:4b:47:fb:5b:ab:3f:c1:22:a9:06:f2:61: + 3d:5b:20:51:fc:ce:a7:82:74:6f:3d:ac:68:d6:78: + a2:77:83:26:af:23:63:20:3f:21:6e:29:1f:55:4c: + a6:d0:5a:51:e5:96:c1:cd:22:03:22:ee:de:42:3c: + 82:4d:29:20:c6:be:85:5b:04:3a:5f:8b:c7:e8:4e: + aa:3c:8e:dd:0d:d8:e5:d0:ff:0b:52:37:40:51:0d: + 33:f7:a8:05:07:76:dc:48:20:cd:52:38:a4:1f:44: + 11:cf:6d:58:a9:5a:9a:34:cb:93:07:30:e3:66:7b: + dc:d3:0b:6b:a2:1c:3f:19:ec:0b:0c:ea:29:6c:75: + 4d:7a:86:cf:35:87:9e:50:15:f3:34:73:0e:ac:4b: + a5:aa:1f:a2:f9:d5:8f:34:bd:5f:19:ae:22:8c:7f: + f7:ca:64:e6:ed:42:75:e5:92:9c:53:53:b7:66:68: + e5:07:eb:08:40:ec:bd:7c:ae:b0:c4:a5:4b:d7:4b: + 58:86:05:a8:91:db:ee:7a:3f:c4:fd:83:e5:7b:cb: + d0:8c:87:68:3b:83:67:e5:6a:5e:fa:28:b5:ee:07: + b1:0d:6a:93:1e:b0:c7:5c:57:fd:ce:e2:9c:0f:5e: + fe:41:cf:20:f2:1d:88:52:00:d4:83:fe:5b:d7:87: + 49:b0:78:2b:a7:60:c2:55:c6:c3:a2:6d:16:04:7f: + 8b:12:f7:65:c6:91:41:53:d8:ac:70:c0:3d:83:d8: + e0:6c:bb:3e:48:b8:c2:72:be:c0:35:61:40:ff:9f: + 97:18:9e:c7:39:0f:93:36:8f:0e:a6:3c:6d:5b:fd: + 89:6a:bb:ee:5e:43:f8:0d:29:7a:cf:23:bf:0b:c1: + 29:76:ae:a2:9a:73:b2:d0:b9:bd:48:51:25:8a:6b: + a9:c5:07:94:26:03:10:74:7b:fc:b7:5d:8f:2d:97: + 55:11:3e:7c:04:89:0e:b9:b9:73:2a:6c:5b:12:19: + 65:92:48:64:d5:4f:2c:79:3f:16:ad:65:97:21:db: + 3c:30:68:67:aa:42:14:86:59:57:b0:79:15:9e:a3: + 05:4f:33 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 7A:C6:DB:B8:D2:75:D1:8D:BB:72:AE:B5:25:6E:6F:8C:AF:63:3A:4D + X509v3 Subject Alternative Name: + othername: + Signature Algorithm: sha1WithRSAEncryption + 7f:5c:76:fd:3d:ef:0c:7f:70:c7:09:d3:5c:c1:b6:40:25:47: + a3:6a:bf:4e:ad:d1:e6:cc:92:86:b6:6a:42:3d:4f:bc:f1:6f: + fd:7e:22:52:9c:dc:a6:0b:71:98:80:44:cf:f1:91:bb:50:c8: + 15:cd:8c:d8:9c:7d:8d:69:61:1b:4c:66:40:77:44:45:33:9c: + 9a:04:01:a1:4b:82:3a:d7:39:97:27:90:a6:71:9a:b1:9c:ce: + 60:01:8b:a5:6f:39:a3:e1:75:de:3c:5c:61:66:a5:50:db:0f: + 4a:03:32:8d:dd:e5:b6:ab:6a:b2:53:6a:4c:c9:99:74:f7:f5: + 1e:a5:06:1a:d3:64:26:c5:77:f4:a6:40:1a:c4:7e:22:05:a6: + a5:25:f7:5d:74:a5:c9:86:c0:3a:88:2e:6e:0e:58:4f:e5:6e: + e9:2a:34:2a:1d:1d:a4:e4:74:f3:a5:e5:56:5d:5f:02:c4:eb: + c7:12:f2:55:6a:f1:6c:ec:6e:b8:c1:2d:aa:4a:7d:ed:91:c8: + 78:1b:b7:b9:37:17:32:ee:1b:b5:d9:5c:98:d2:cf:d8:c6:90: + a5:c9:f1:eb:8d:2c:d4:90:b2:8c:e5:53:9a:66:20:92:8b:a2: + 0c:8b:76:9b:5f:5b:39:77:69:67:a7:8c:de:10:57:85:45:a4: + 8f:85:3a:59:5f:fc:0c:70:de:1c:67:33:5e:9b:a5:21:3d:bd: + 2e:de:3e:c2:0d:cf:8f:52:43:92:01:cc:47:da:af:47:85:69: + 94:d3:9f:c9:d5:5d:50:ca:27:a5:bb:c0:53:12:e0:e8:3c:ed: + 0d:bd:47:97:af:be:b8:f9:0c:10:2a:79:21:3c:15:ef:c0:a5: + eb:33:38:93:5b:a3:de:1a:97:eb:c3:db:04:1f:e8:f4:23:10: + ff:2d:1e:9b:4e:1f:8e:27:7d:71:34:e2:be:74:a2:62:69:9a: + 83:7b:6e:9e:e4:a2:7c:84:82:ff:83:b3:cd:d2:0f:74:05:72: + b8:b0:45:23:b6:cd:04:25:2d:58:7f:92:ce:68:f9:ba:d0:9e: + a8:e1:f8:c0:86:0e:aa:ee:f9:af:ff:5c:bf:46:76:08:b1:83: + e7:66:8b:ca:1b:8f:f4:9f:6a:ac:71:4e:3a:d1:77:fd:97:81: + ff:0e:d0:d1:4a:7e:6d:94:e6:8c:e1:28:92:b1:68:83:5a:62: + 48:0d:26:ee:28:60:57:ff:52:b8:1e:8c:03:d8:fb:c1:6e:4f: + fd:7a:46:0b:0f:c8:05:ad:3a:a4:68:be:fd:30:62:ce:f2:0a: + b1:34:2c:95:e7:e2:91:ec:a3:c6:4e:2d:a5:fe:09:45:84:38: + 9c:d7:f4:0b:18:22:9d:df +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIBBjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwNloYDzI1 +MTgxMTIxMjIyNTA2WjAeMQswCQYDVQQGEwJTRTEPMA0GA1UEAwwGcGtpbml0MIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OYasd6RMDSKx/LZCgmCE0bp +28hUHg6wsArjo7VVPG/4RY8k7VbFFiOqrYZaWuCPovWCWcxwt0XMG0SnSUv/Yyid +ASJ5yhpqK3X4QMDwk7Grhc2viKww88tCh/y+drv9HKRFemY3R+qqv8RLR/tbqz/B +IqkG8mE9WyBR/M6ngnRvPaxo1niid4MmryNjID8hbikfVUym0FpR5ZbBzSIDIu7e +QjyCTSkgxr6FWwQ6X4vH6E6qPI7dDdjl0P8LUjdAUQ0z96gFB3bcSCDNUjikH0QR +z21YqVqaNMuTBzDjZnvc0wtrohw/GewLDOopbHVNeobPNYeeUBXzNHMOrEulqh+i ++dWPNL1fGa4ijH/3ymTm7UJ15ZKcU1O3ZmjlB+sIQOy9fK6wxKVL10tYhgWokdvu +ej/E/YPle8vQjIdoO4Nn5Wpe+ii17gexDWqTHrDHXFf9zuKcD17+Qc8g8h2IUgDU +g/5b14dJsHgrp2DCVcbDom0WBH+LEvdlxpFBU9iscMA9g9jgbLs+SLjCcr7ANWFA +/5+XGJ7HOQ+TNo8OpjxtW/2JarvuXkP4DSl6zyO/C8Epdq6imnOy0Lm9SFElimup +xQeUJgMQdHv8t12PLZdVET58BIkOublzKmxbEhllkkhk1U8seT8WrWWXIds8MGhn +qkIUhllXsHkVnqMFTzMCAwEAAaNzMHEwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAw +HQYDVR0OBBYEFHrG27jSddGNu3KutSVub4yvYzpNMDgGA1UdEQQxMC+gLQYGKwYB +BQICoCMwIaANGwtURVNULkg1TC5TRaEQMA6gAwIBAaEHMAUbA2JhcjANBgkqhkiG +9w0BAQUFAAOCAgEAf1x2/T3vDH9wxwnTXMG2QCVHo2q/Tq3R5syShrZqQj1PvPFv +/X4iUpzcpgtxmIBEz/GRu1DIFc2M2Jx9jWlhG0xmQHdERTOcmgQBoUuCOtc5lyeQ +pnGasZzOYAGLpW85o+F13jxcYWalUNsPSgMyjd3ltqtqslNqTMmZdPf1HqUGGtNk +JsV39KZAGsR+IgWmpSX3XXSlyYbAOogubg5YT+Vu6So0Kh0dpOR086XlVl1fAsTr +xxLyVWrxbOxuuMEtqkp97ZHIeBu3uTcXMu4btdlcmNLP2MaQpcnx640s1JCyjOVT +mmYgkouiDIt2m19bOXdpZ6eM3hBXhUWkj4U6WV/8DHDeHGczXpulIT29Lt4+wg3P +j1JDkgHMR9qvR4VplNOfydVdUMonpbvAUxLg6DztDb1Hl6++uPkMECp5ITwV78Cl +6zM4k1uj3hqX68PbBB/o9CMQ/y0em04fjid9cTTivnSiYmmag3tunuSifISC/4Oz +zdIPdAVyuLBFI7bNBCUtWH+Szmj5utCeqOH4wIYOqu75r/9cv0Z2CLGD52aLyhuP +9J9qrHFOOtF3/ZeB/w7Q0Up+bZTmjOEokrFog1piSA0m7ihgV/9SuB6MA9j7wW5P +/XpGCw/IBa06pGi+/TBizvIKsTQslefikeyjxk4tpf4JRYQ4nNf0Cxgind8= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/pkinit.key b/third_party/heimdal/lib/hx509/data/pkinit.key new file mode 100644 index 0000000..ee1c842 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/pkinit.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDk5hqx3pEwNIrH +8tkKCYITRunbyFQeDrCwCuOjtVU8b/hFjyTtVsUWI6qthlpa4I+i9YJZzHC3Rcwb +RKdJS/9jKJ0BInnKGmordfhAwPCTsauFza+IrDDzy0KH/L52u/0cpEV6ZjdH6qq/ +xEtH+1urP8EiqQbyYT1bIFH8zqeCdG89rGjWeKJ3gyavI2MgPyFuKR9VTKbQWlHl +lsHNIgMi7t5CPIJNKSDGvoVbBDpfi8foTqo8jt0N2OXQ/wtSN0BRDTP3qAUHdtxI +IM1SOKQfRBHPbVipWpo0y5MHMONme9zTC2uiHD8Z7AsM6ilsdU16hs81h55QFfM0 +cw6sS6WqH6L51Y80vV8ZriKMf/fKZObtQnXlkpxTU7dmaOUH6whA7L18rrDEpUvX +S1iGBaiR2+56P8T9g+V7y9CMh2g7g2flal76KLXuB7ENapMesMdcV/3O4pwPXv5B +zyDyHYhSANSD/lvXh0mweCunYMJVxsOibRYEf4sS92XGkUFT2KxwwD2D2OBsuz5I +uMJyvsA1YUD/n5cYnsc5D5M2jw6mPG1b/Ylqu+5eQ/gNKXrPI78LwSl2rqKac7LQ +ub1IUSWKa6nFB5QmAxB0e/y3XY8tl1URPnwEiQ65uXMqbFsSGWWSSGTVTyx5Pxat +ZZch2zwwaGeqQhSGWVeweRWeowVPMwIDAQABAoICABdRKV79ISUb9RcxMdLH7Swx +iRkOayM0s+L6+P1wN2KUtWHAly5mLGV49KYAjau8PGWJROII5WKGBaixcakRyM49 +EOFQtb9UuYP73HIcNWWWL7bNoRf3EnWDOx/HK0/FDp+gTEOPrgnxabtnL5QBkvD6 +6Z2yQjbmmO1zeWabVoz/d2V87qEKYOJzxbkJjct3Ityp67swt715teYBWXSgBlnE +o3dz2oIpsmEMf2EqKRgakR6lBMpucy457g9AK9MQNckL40NTJlAAV6gxTzkU9AML +WBUdOm7l/9do9W1CGagS7gfBnhFBd1wYo3eJUvbtbBsTKIB3dDUMR14Mam46toFQ +pxRjTOpywwePQSJAxR3M1QbnOup3w8Mw9+Vw++mVS0woXhCz2zwmPTuC6/YN1WCM +Zs4jRFQrc1fw3o6BBNmoMb9TL2aDOLbAtMSvFlH4FQQTy4RLzOoZnNAvy5f4qmzp +VvEqiZzgXhg+VjPlQpGEoBptt3Jru9vOBCdPTd1L7jMUjC3lf+MR1QrJxFNdK0cH +0YeSehTFOtZ4fTPwXlKJsPXSGyu3ZvN3ukt15X/qQypeqqlnln7BjKuUyltkAl8z +727G1tgiObFDUL/oPbeqkmGoN+z8mn6PlyN3pe/mYwZES6F5RoEy/AAOrhp0HINz +lzt7bZVoFY+tVkZU6AyBAoIBAQD6Wc6rzhwa2klX1BjOJXbgsh8tA5zvYM44fcZz +JSanqwMfiu60nvVW0nF0jVfHKGckJ2KQYbNKucTBJRgAY4a2eXrcEIkOPY50b9Dv +BtCNhiwfQ31VQct+qoS2693d9N3Q17d0sqUwvSAN33YcePTb/uC8L3Ys6pFrsrn/ +RRTdlcF3077jaYjKFAGRRWhHDaJNsm3XZm1jgHWRktRgiJe+EN6NjW2ScC1UqN1l +5To2AFbxg/87T89rLcKi47CNF1akFV5o0csQX3KUZtLse5VM5R4j7NGtd8deHgJv +c+/xC6RblmX6AgXTXUICNBjgIF/QV5XyKTvA3QEvG3eErfBDAoIBAQDqEGBL6MGG +PT9M7GGFq7pc/BAHkm31+Zq0pTV6EbBwu4SGZtFkhXZJXAi6cAhKBr9u8colZmEW +EG+OVPhNN4cNOPrbDESFaM5D0dNED5AAUlyE0ozI+Rlx7m91UhPufyWCg66SJNj9 +7o3Kh57N7p8RqpBicuXv6bBBna1+AA6/v3JImE4FWRyg8LwUWWmCVU8CDKzuUdQ2 +Os+irE/eXq20/FYNoFkYNiS28wh9c06v90f9n1QV6ma3tSy11g7a/uTZ4oX6HVoj +26sMx+z+SDWnKCgTSiELdzpeLooMMAI9toyNLLLw2knzHhOz1M2wcxuYa4hSo6Dj +N6odujQwCu5RAoIBAQD2ymNG0Aa6nebhMs9FIH+A33aGLGKfQ6Hm5G4mAkCJ1rZc +eNv5qB2Yehmn2NHoHTcX1899HyLcjiacdBGmCHa7GSP5Hj/NjvcIZ1Xi26fpa5PB +OgmqaxLMihIMNJXhgMrNXmmWG6lmU3nu0xOe28oduLMYL/1iJ9Y1AdoC/7mi+kbe +9hjeG6Hh+zjUWUSDjrgpubQ4O9un0/GSENlVVDGqBv0tM3cJfZXiOBkQopjwtQMA +UKvhbzq8oD6XzrazT4d0dzA7SlzQhhbwnjBdOTKju9Urev/z7fjWGeUys2qcB2r9 +clSS0T2m7+7rNyoyfxeUzVKehvFFnVfWdVArtj/7AoIBAQDE66wokRUn/CVicUkG +7din3EUcKbyrgij/LDNWlMVNwuWXMa+fE43V4EFToWfH5+9sxq2cU4sAxikkpSYV +yM6teC/M1IBdgTRv6HsGutUbAC/oaz+Y4cHfkYtiOACe2YfUSzc2qxuIYAgYyYr4 +lHZtpYM94I7FDmWEfsT0ydWeytG6c7DIXRVx7bc+o47Z4S3Mep+PDXctfMMtiCzV +1+/q4ZUAd9QdQ4gWB1gwOy+Lac6+eSqEGaX7jsij3wi2hFZDXYn8SG+K1YgOA7HG +qTfCf01gFTDB9bg8fokUAdwQ0aFkMKQHcI9gpABNfo7ikaU40ddqN1Hnd/B+fCbl ++HxRAoIBAQCA98OxfQECOxve0RMTAslR1mq7MqHMcmk/ukENJsErxWYp2r4Ghgmu +wWeweGBFwTPJ1lqm0+mpyUphE20m8A6QxN4dR7ckAQfGjuc6ZRBJDhSY/rPv+3j0 +fBhKyJl+DL4RiNCXncQFD4sa8YH6UcsGDo8OkWr1ZzOQp0jTSa8yOmswDlt7boch +5DGHb5xtngPe5lpVg+t2VZeXF7sTy7BZwwTLLZWtI5wHuUAnOeLvwCMHmZTrpwe+ +cN0oo2nQTI/EgYf5ZyVj+zfiaxvST5AN6BKj8QApwC0q/TipqoLghxD3YNzUokFI +RGobyk3036+cucUBlLFJBboNBbUzUX7l +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/proxy-level-test.crt b/third_party/heimdal/lib/hx509/data/proxy-level-test.crt new file mode 100644 index 0000000..51422e9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy-level-test.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgIJAOXO+qv/iXxCMA0GCSqGSIb3DQEBCwUAMDExCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQxDjAMBgNVBAMMBXByb3h5MCAXDTE5 +MDMyMjIyMjUxM1oYDzI1MTgxMTIxMjIyNTEzWjBBMQswCQYDVQQGEwJTRTESMBAG +A1UEAwwJVGVzdCBjZXJ0MQ4wDAYDVQQDDAVwcm94eTEOMAwGA1UEAwwFY2hpbGQw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPMfDYnc56LmPFqSovq3KU +JcBypPhCtrOiJ3vwLIumg+NDlsWdhG0EP8xwGnbikR5RNAi/PtCV8cGsbQ3+Fio8 +AFVQs956itoNEvzoL+mbyNpyRVr1ph9qJ/lO5mzdNfCQb++b73bkygUaNKJPpdL5 +VNEwdG6bEEw59+WWqATO1geUv//AeNPqLrKFDMg5HQzCjGXhwE99J156AQ4fw6lB +0Yubssk6AfHLKd+UKh8qRPdO1EYzgHRuSGW7olXUbiS3wmPe1/JYMEiILjGmvAaA +Y55qsxFxZlTEehO99WF6rOrP1lC3ddcBd0fXBvJTiQeQsHT29tiVlPMFolmnQMbO ++bzLUPSx9ukW2deirFViXnC7pb5Cv8ZIJ2jsZEG3D4JM5WqZ1ycrKAq49r284LbX +LZH0ZnKZyGJmOjsXqIwWJJthMSlb7l/TA4IdRePYlaYQNQqIYwsPv9o+wv3owUaV +1PePDbn3PY/LENshooIV1yqhbA/Kr4ayiYuTFLtugPcWwi8sAXFNC3t6x4+xTK3n +S0n30hvIWZGKes8Zz46E6ANAf+stiKWxhTROrfLNKvenKXc4iVETOzZkBhQPyhk5 +dM1aC9rylQnm30o8oVnNpn/z9rePdCDbBluHKcJE4xcX5QpU3qybO5W5A7dhxsjw +0iVfuheSt5AkE4ixHAy/6wIDAQABo2AwXjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF +4DAdBgNVHQ4EFgQUcMWBbIV1HXTcW9hfIFew2urXq5QwJQYIKwYBBQUHAQ4BAf8E +FjAUAgEAMA8GCCsGAQUFBxUABANmb28wDQYJKoZIhvcNAQELBQADggIBAGygvoGy +/aUbaxSh8v1ug6qHHDMuKAddD4qnTx/JKFyUbVDKOUsiu4kuwH5uoIMhhPd5XYBw +2gNjptKIK/o5CMGXQpAFV9cfd7h57bhBTBU5xPvdsTsXSRObkmESE07XF81Vmqbz +3+YvbhYy98mHszMnsBzG24pJYn+Xhv0KfUINV+BzZZPZmwTkZki8gnAYpSfA85d2 +o1SO2iP0kZPUOoTRDrvN6v7EHFxar8Prka2jpHBPRXUMANbGl/Iu8SvzukVDc6g2 +pEBa9vDPl2Tf44kct+hB7Q735xSfHF5PJaUt/kzVclFNNWyNRr99S1mM5IEnAzF3 +PpkWHOke/L1dvWJT7wBSPfwMtyQz7gIGdA6Oq5CkFxE259bb7XJxRwfQV12pB4p5 +ZYUDTpd1P3D+VHQzmGi+EcgKEgoydVp4ikQj7aDUQWzZ49st+xLf0suE6wmNNSd+ +4dSuAeHbV0rglwlo/LZ3UPCd8nzhGTC5t6L8vFcDkrC7RyaBR8X2OeTU8FLP02me +q1eMF8k89L6ar1etLfC2+PKRGhcohJjm1Yz7sTSIeT6SnSxZeoSGAkFFwy70in0m +9mJNpNGfBCr2DS+XncpvVcIIYjHmrKWYfbnxYcouh/PJqpKKp4JXceV0u1e2DlvQ +Cew9o2dZuv5HXMmm4xpp8gyrzCzfZuExPIZd +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/proxy-level-test.key b/third_party/heimdal/lib/hx509/data/proxy-level-test.key new file mode 100644 index 0000000..352bfa8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy-level-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDPMfDYnc56LmPF +qSovq3KUJcBypPhCtrOiJ3vwLIumg+NDlsWdhG0EP8xwGnbikR5RNAi/PtCV8cGs +bQ3+Fio8AFVQs956itoNEvzoL+mbyNpyRVr1ph9qJ/lO5mzdNfCQb++b73bkygUa +NKJPpdL5VNEwdG6bEEw59+WWqATO1geUv//AeNPqLrKFDMg5HQzCjGXhwE99J156 +AQ4fw6lB0Yubssk6AfHLKd+UKh8qRPdO1EYzgHRuSGW7olXUbiS3wmPe1/JYMEiI +LjGmvAaAY55qsxFxZlTEehO99WF6rOrP1lC3ddcBd0fXBvJTiQeQsHT29tiVlPMF +olmnQMbO+bzLUPSx9ukW2deirFViXnC7pb5Cv8ZIJ2jsZEG3D4JM5WqZ1ycrKAq4 +9r284LbXLZH0ZnKZyGJmOjsXqIwWJJthMSlb7l/TA4IdRePYlaYQNQqIYwsPv9o+ +wv3owUaV1PePDbn3PY/LENshooIV1yqhbA/Kr4ayiYuTFLtugPcWwi8sAXFNC3t6 +x4+xTK3nS0n30hvIWZGKes8Zz46E6ANAf+stiKWxhTROrfLNKvenKXc4iVETOzZk +BhQPyhk5dM1aC9rylQnm30o8oVnNpn/z9rePdCDbBluHKcJE4xcX5QpU3qybO5W5 +A7dhxsjw0iVfuheSt5AkE4ixHAy/6wIDAQABAoICAQCfHKLwNn+RpH5KFJao9OiQ +jE01vSpJUTSxmdC7p/m2biHgjbBEPqXZVYURscEKTJcTlPoCo6JbA8TPPRA5x5u3 +aCocR4TaZjb9Q0+knuavE5dtmYU4j9IgG4KA7MM9PWb4BH3lKggLunggn7rln1pc +zp22sDMgMWvYOF6/S1gl3ocD3E3y6NcUR7ggJKi982kRHfA/ZQel/M24s4a9LeyU +9u5XKv0M5uFgO0/O4Gn+c+fXSXx/oG3JIx+87/UppUvdMhKv1vXsc2e/7HmEqW/0 +uIu3NLx4cTU3jOgMQJwTMSdBZDuoJ35tScSJhHQjYl/E5T1tSjMY68GU2hAvOLdy +Z+rsZTcu9orvnMij0kmxjbXdQGK3PlcLiiwYZKrwuyn3b3aMq0nq0OwTsGtSRPDf +30dOSuTEf8GKnxB9wtogYD6aEDOhFJNXYh819W9weNyIeGu6sarsReKAJJihyO3I +1VtlexqEWB5OFn5KbHZoRp4Fvc8XtaXolajHsCcic1uKUOG/Iuegum9EemcPnmPW +XVe6JknXhrjxd48KiaXLQ7dYoIGCQMjvdsOvIwzppf6ZZ7WMyqxGnb3TtmDDJxIf +ovSu43s9uWhTOA5Nrp5sY3VFSyzq0g5U8NgEC+HjGVgA3UB0GDsB+vUaEseZg0Kf +faXIuvJg3WoGJ/VVWnaTwQKCAQEA+FSa4kjKmD+fm4LA9bmVldB+cfsqSl3TUcfr +oxb0i2ouYhrG0eV6EjvXizswF3CuVGKQCtWg7GDeG3vKbVFtkSTg1KU9jir4ha3k +5spAxqNBB5S+IK6xeGipHiu6AuHZZN/8Z2T2FWkGNTdRRKnw8cdfSlBq9wG/LXJW +g/Cnxsvyu8temursSIX2nKYSUsHZIBnJZAXUwBOWUMLpzaS6UtdKIJDCaPprx4Kz +elYqJhddT8eO3HIXXWthVzjm+dgyKnxSjIUVyVekKareNzGxZxjMu1lg6tybnR2O +rBejni9//y2HQyFRuWUzRV9FwjiWS6AJNm1V4OvaxOIjKHFG5wKCAQEA1Zgaierq +g8OudyNGFpNQ9TAS7lcERP3z/nyR0kgnSBlTpppaWzUgkdifmK8tMmiu+M7Mj8Qf +Nb5/h+HdwY62xA476/iI8yrSppHj3nuC2aWn9wg6gP/iKUF0ZvaxR3MsU+k1gs6Z +IcozjzIxuyY1whMm+FaPrHx+1l/P1Dn6JotZ1uFhikzmoZc8atLIK6wPylkz2i/X +7OkOkkz10BpvbC44F66Owlf49Gjwa1c7Mj9kJYsY+Dqoo4nk6j7EqzJN3e3Pa+n6 +pAfQhddVUKl1ULBlnLHGh6x3vAb4L6sfmsq7EhbTGQFd/M1oxUtPW6BAJ63gYPAh +AWU8Emg59lBSXQKCAQAxTApbNXwScT7sDi7kGO1bCkKvud6RWMLkjz116M6vBmsi +ypIBhP6QtBR77UoEvTe+RLq3i+UgR7KP3ik3Plzz3VBMpmjr2hfv4a95KVlmlW4J +ZTvBHSzZ7Fz2QlPw0ojnf5eJpv87DNhQpCSb7uiH9r4x8HjrhAtBqFsIYjPMQRx0 +r1CejFhPpVhpjIZCq3zA5J2YH5g2cSz751WmnzblzxtGD7aoRF41AvtCI+zGFwlN +Fx6DIJsGzpRKTl975bE/weJZRuomSCGsq+DlMBY5kzDBWGLm/NhffkieXSr78g4E +yDL73pdsqGxfLySYA8fCR4jMpzPPLMMHJqU4GBStAoIBAQCBwLi+d5qnGMRvU1pM +dImFqQKXDv1k+/Cw8/ORjotuXRRX7QRey9NRRgsNsbz/FmDUfKv/2eArweGvJiKU +ZqHYT91O59gqACWfUpjemqFOnjd+9dy0aL122nBf7BSdlvWis9Tx9ZdI05CmuJNF +YVze3MubqNn2qlpS2DlkbyPrLlQRGTEr1rN0Dm+BZTJ8dTXScoXxUYcWQC296kqZ +dLWjPiCNIllO7ioqL2V9j6xCRggMVoeApAG19xq8wgyvAwwSeVi78ZN0+dpOtBT7 +vzWpIr9XhRdZbAgAjStPqeC1I9qojn0Gf7Ic1JuE3s8ClkLi19mqibVDJ8BqXi53 +1ytxAoIBAQDCgJk3PsF9v2W2SVHrs1zpcEOP3JR9Oj6q6ThAHLF6uUqXsWEbXjKk +z3ReI7tMO8A5J0rpPuCEJUdiPtly8FsyiXIheSOQ7UN0w6ip3abDwuJFGFYBqrib +MEI+r7b6xT5o3U+csGbimhwCtGeCDL9W9YwK4nYGi/+NO+6qfX4dovOyydCZff5m +Gl5MRo7L76EnLheVHDGq4PQLZtLJCT6O2OAA/p+5IUFWzf1uOnoceDyw2KueijN4 +67gtUS9T6ex5/MWRoWeIcNhmXM+aFcAbW79hAycliP8jIF7q5feUER5QepYGfZ3c +JKt/SLgrlhrJ0BbcNKAnbzOeBZGPpEJk +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/proxy-test.crt b/third_party/heimdal/lib/hx509/data/proxy-test.crt new file mode 100644 index 0000000..9f9cd57 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy-test.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFNzCCAx+gAwIBAgIJAKQmPUkmhyKhMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQwIBcNMTkwMzIyMjIyNTEyWhgPMjUx +ODExMjEyMjI1MTJaMDExCzAJBgNVBAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQx +DjAMBgNVBAMMBXByb3h5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +mPssWfri3hoR0eHC6FCqD3arIBwD+XeYJXS2y1zA9UgijF3rLDtyubOpp/5Or6Q9 +cO7m4S+4xPquasRUS8A9rJZbxi3rvptVFD2DBmpEUNbIjlW2TdymVpAtD4uHKpOA +xeEtn6eXlhDiiJcrrqLds9cLGRG0XaPSeTwzOWqhtyEeMp3rvVQ/NeMfYsMF87m/ +txopxdJnpEoArfxxudLSQ0HrILLVV/VbQZEcoJXEMjhZg0Qnw5rHRV5dacLT1gmp +w2yRQID0rbcKk6b3ukRHXD9OWNt074afzQJmMx1MDlHv8IeFtksxEhhA9i612LTi +KaU5Ac11ZJ+ew2YnV3HU3roH6BHeGeWHDhxqfpV7DPXZsUVo18kgrY+w1E+lcntT +FfWzWXF6p7gIPQKBy/IG3FsdP9ugx4y54Jl2HsrBEOjA+x45TL80T0zA0FXuu6fo +oljNGUrQfPQiWJCnQmWkjIhbVo+aovSlBRnOSsAxr7H8Ry4jhF2eQG8TIDgPRGs3 +DSwIUJyQwoRvRpo01ZJ1akfUkJFzv519EuN/zfNVTO2KBGVXprkONCZVN6eVpDVb +rClN5iUqCimn4xhv2T7VhDKO6mjOMMR38kdLvsrtAWBpob7hDHr0zAXCwSwheVVM +fMkYHZEyVfsxS7/ooA+oLwbHewhV3zJQDK6zAgyi+jUCAwEAAaNgMF4wCQYDVR0T +BAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFFyuJ+5Hf8HzZNaew6ZLRnQubKRB +MCUGCCsGAQUFBwEOAQH/BBYwFAIBADAPBggrBgEFBQcVAAQDZm9vMA0GCSqGSIb3 +DQEBCwUAA4ICAQAqn4xPkjg5lR+wOQwxKyxfzjS2ycEW+8WLp+l5p7qHmv4JOSwO +/XFf+6sRSGiBwHAoOq3yJlU0NzEq+uLjEg20/MXQ1+R4N2AsWeD4wUxRkjoukmc+ +at4wza4SoJLzfv8rYtZRx7quXDq+tFgAHxZv/AB3tghCyjS9JiaAc2aA015XmAec +qZcLjWoDmIH4mgT+LuenPbS9Dus8mGbOiTsns+iVCMZKJOBU1KF1UUy+f+J3SGqX +nsHzfMiFqU8qA6sQ3mZy4yqPG0Yu7r6YfpV2HQPCLXy1VZ3BINf/9YINaUCe/NpQ +Md1Pd6Q3U8+QObyAxXVfmTRFGCDu+S0NlpEfZzPnRYxr0ZfwC3SKWMwVHugv9v3k +qkZAgB4T9u0TqBjuB9mWoyzYEqwRgFg0AjrtgWXPJ8MSnth3eSrJjcXhEqgq1NvJ +SZVPzYW9RKB7lAM/4cDmrGXB1Lq2g4b5R8H1wzBtjL+CGjCuly9uR5HvxCOPLzPm +btZTRQtdA96L490wcv4D3JHN9ro0cq4QB2m6XKr2wDDh3CEgQQmaTKufWR8zAL8R +5HYtKxt1dcz6w4FiLgq9g+ADZMwJpErmGgldX/NKMz4Rfy0qMCprIn6XgPWWlSC4 +BT/0EyLjDJhwap661H5sMkchCx4uywG6EvQBRf4bxpWQgxReSO1znefULQ== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/proxy-test.key b/third_party/heimdal/lib/hx509/data/proxy-test.key new file mode 100644 index 0000000..fc303ea --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCY+yxZ+uLeGhHR +4cLoUKoPdqsgHAP5d5gldLbLXMD1SCKMXessO3K5s6mn/k6vpD1w7ubhL7jE+q5q +xFRLwD2sllvGLeu+m1UUPYMGakRQ1siOVbZN3KZWkC0Pi4cqk4DF4S2fp5eWEOKI +lyuuot2z1wsZEbRdo9J5PDM5aqG3IR4yneu9VD814x9iwwXzub+3GinF0mekSgCt +/HG50tJDQesgstVX9VtBkRyglcQyOFmDRCfDmsdFXl1pwtPWCanDbJFAgPSttwqT +pve6REdcP05Y23Tvhp/NAmYzHUwOUe/wh4W2SzESGED2LrXYtOIppTkBzXVkn57D +ZidXcdTeugfoEd4Z5YcOHGp+lXsM9dmxRWjXySCtj7DUT6Vye1MV9bNZcXqnuAg9 +AoHL8gbcWx0/26DHjLngmXYeysEQ6MD7HjlMvzRPTMDQVe67p+iiWM0ZStB89CJY +kKdCZaSMiFtWj5qi9KUFGc5KwDGvsfxHLiOEXZ5AbxMgOA9EazcNLAhQnJDChG9G +mjTVknVqR9SQkXO/nX0S43/N81VM7YoEZVemuQ40JlU3p5WkNVusKU3mJSoKKafj +GG/ZPtWEMo7qaM4wxHfyR0u+yu0BYGmhvuEMevTMBcLBLCF5VUx8yRgdkTJV+zFL +v+igD6gvBsd7CFXfMlAMrrMCDKL6NQIDAQABAoICAHwnJAhmXyYHHD0sLmUhydJA +6YJmmickkvqa7Rq/zO2DPF6Ufh5opKPnFiH7dlp/PUng6MkKVLawB0soyIytmJ/v +as28SN1o7LQ/c42KQqUkmqFBGHG6R9hqq9c40lqQWOq+46r1dUVZsK9PmCjjjm+8 +bwpKXwm7wT2YyK2pR1L68qn7le0SaTZPfBJH2hXBwsBT4GDmcCxZzpFlFdrMKM5i +ufLQj+oRep0MqqH8ybxEFQk+D9NkUqKOgdsqPYcwUnECNCOYRHqS2WeZEuU9Mni/ ++9KLUCxwIlJbxxtmhGn+v26CXdbi0RExU883e2dC7WUE7O30k3g1PsCvr+/8ttdG +AwzeeLb1o+dYIJrFBb/YmpehrE2JP5aTi47AtSAkKnYo5lSkxPEdqxSNuU6VQp4l ++MtPvV6JKY0HfDYKPxdXFdrGDQurNeRjrgyXZ0MSxxVCscR0TXij2bkiGd6Euknf +Oxgg6KqFRFwXA+aWupNA1lknTEU9AIPb4QBYH8Je3st+Q4FxBCFHE6N0+uKdbX9j +GlZ01d4WJxo3rJf2q11Wq24G3v+UBtHV/RRrWy7ZBedlr0XFQ+i4lhFFPOvLFSS1 +Hv+7Hzuh4h22RhsAOxNveX89MlhPb6ZrR+3C8U2K7EjHxVlGzAvcoutD7qjUF9N7 +rXOHJG2qwkmoGO5L6z6lAoIBAQDHlvHduYwxfAanrITkQRRodkl8V0xcQhQTNFNj +1vhQWqzBo1C1p1A4ICuTEmAPR7r8LuCYAP07RbfxPbMS6qfCT4nnJmGPONgkn1my +s/9s7o5k07TST/Z9VVPCewc0+XcyWHwpgZMPeLSDqB5yRK+t3NoqGOnX3LI4fNE/ +YB5zQWh7cG60SKl18kXvCunMnh0pE8mGE+Mx70RMOrmBxnLv0xDbwbqfY5K8nY7b +ccaFVMLHkE3YipF+0/zp2H0SVlV48h/fkwYdIzcDNje7ejMRJk0/zviPuTJz4S+0 +sJC3IJ6Cyzk12zmyV7zc0VShFutUbLccmKxfWde4N9I2FiUTAoIBAQDEN+49eQho +0q0aNLe4LxCXsjJLhDB7XcZiGsFtKrfd79jAo7v/C0HiqbZCecrbcG62Hip4aEc8 +0bFj980LM57XM89QUylzKFJXtQe7/nxvmozQTuX6tFb2AxwSwFcYHfeFPkjsqWTF +iBsREZ4l7CS1wsgC2vb36rk6GfkAjGd6ZYn7Jl1JXHr6868gBtle1Ad3H/S7BW+J +Io6upgPHbI11/29ScMu8c7oYk6jQiBrVZd6PEq47AhWatFqlSyq2mjlgGkleRzrN +J4SogzRs9Emd0xF23bjdGzK1B8GJY6GqUN+lZ2SvkKT2PyQvDuWSOurlOv9GQuBq +kELci3kNb/SXAoIBAQC0JcEfYQdx7sFO/H9iSn9yHjoL2fvZVecqwlL2TaUJWh6O +FKuXmnHkhtztvWsov5S9ZE5hxJrMsgvp2cfVLinHT+Vn1pO+Iw+sVowuqRrGJrgt +t4yBO51+2NJmOodxwC1fKtC+4e5ry4YbQ1ZfyzFKW4oq7xu6M8BFDhwL+OTjIMl+ +iSfS37bc95U5wn7uqlQlrG977l1lx9G8gFDKGuXJI5gW0lBw5v4d8pRr69DErZG1 +cMFizweuEwc3xqh1MamqJdixAtJE4HEaHAjH1e9b7ldRXa2qg/1O7JUToT6tm+qW +oXl86+ey2lBkeyjI0ZgNNqc8T21eDwiPhQreuLQzAoIBACHdgVnMvN3SlpuyQ48f +WF7GG5Ya/38bRTUDZyTfPZKpZaCB4d135Owo3FMG0DMlaYY3GJ9lZ/4gNtyJFTN8 +ukpsH7i+UaYVbHjEvsv8dR+R7gG5zEmDvIqDKOI3nhCEg4bUpCNsbP8GqZ09jC0B +X6ibMIgFoKBTO5rChs5IbUebpL/a9DjIJFWRn0UIyZVrRMqTklqA6qohc7zC3F4b +5yJZbq4s14zz8EdznKw5AWCZT1skHzwB9RaZUBe9LGcNoR9sCgOiiYyE6Ilo87Bm +TRpXJml8hP5sRkkmSInczzck9CSI/sCqVz5E0YrpqEefsZDUqOBIhJD/yvpjfAYM +r4sCggEBALY2BvWagNcnTdINCI25Tt0S6J4vAScyG/LESS+qRxTUklpqAsXNPMQ+ +O9n3B8knb/1UuXeHC7yAScNUSGqq+Z68D9my5cXanSVzOlLwRu6tUa7J58fbkkif +I3PoVDPjEkYy/yWJEIjqKu5z0x7uMKXid/rf9BHCIH802v0s+EsQZn36kmU3MMpB +Rriubez85f37vXES6A6DD5EmWUvAAuKvfvXWXtml0f9d/JZd+8jMrHQCwFprdTyM +fN1crepFBAl6oheb3ColMByiMvU/WzcT5vwCnUEd+46QLuTU0BdXcKWKXviHI1Us +2f09X6R0XLrRpaAyQD+H/2DVhYM4CV0= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.crt b/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.crt new file mode 100644 index 0000000..a606da6 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFezCCA2OgAwIBAgIJAIZ6hp81I2P5MA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQxEDAOBgNVBAMMB3Byb3h5MTAxDjAM +BgNVBAMMBWNoaWxkMCAXDTE5MDMyMjIyMjUxNloYDzI1MTgxMTIxMjIyNTE2WjBT +MQswCQYDVQQGEwJTRTESMBAGA1UEAwwJVGVzdCBjZXJ0MRAwDgYDVQQDDAdwcm94 +eTEwMQ4wDAYDVQQDDAVjaGlsZDEOMAwGA1UEAwwFY2hpbGQwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQDOIxKHoKGi1/5V21RKfDqag54mjcz/ye0NvVHq +QKXJ4I8EVZyP7fwtl4ElcZ0GyHhqetXsulqgzuoGns5eCAq9mMkX4+3/EXvy0lyz +rVa+K5ysq6rsUMg7LPpiWA6RM3YYahNedzk3gsRghJ8q0vbvpTzNZQ1A+IOY1kdX +AeqyBqUT6kLycPYzU/eL2WzVe6pTRt1p2LKckDjxCKJI1ocYhWrdFhbB9YduvEVp +IRTINGXGvTpk8ZwzvgUQk1BmeGc1qqnmY+/wEEfpu1OZD2+5rJWQ7pSyB1jnMBxq +mTc5jkrMkzJX9F5JleVY9+bKZcBGu34mmAa4vXfwQOnM2HXAvjw3DJGlZCuNKExs +Ji9RyZcbe1NZqlBkp9l79cnlqURV6HftFFTyBNloEaNdzi81rYiMlxEoHEHqjLvo +9HCNV90WDDHPxDG+iOKyY6OAZ/QtjGEAjizp1NYHYkvTG3PzVvqQCsNF4iWzksQY +3M0OgyDybskOxvUN0NzDrF7Zw0+SqBSnYGWokVoghzQHMQHEOv/gYvrdw4kGs5Db +RXPfiYKJSPlsFgi0zXpZgm8Br2GxEW6ZfADaK/eONC6FW2W4aL9oqC8XyV2kYi/v +69G+UeULhVELL4bsUf0moPELFpuwyShHqfQ4l5Us5m66zxc/I0ekz2N66mWv/WQ9 +LNJBBwIDAQABo2AwXjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQU +W8uH0Ungtk49Eykz3IE+8z536hswJQYIKwYBBQUHAQ4BAf8EFjAUAgEKMA8GCCsG +AQUFBxUABANmb28wDQYJKoZIhvcNAQELBQADggIBAAJxESHv3qYUiqzpmWI13Bbe +v9UqS/Le+WmWosv7JfbBV/aL9T2FF0uw/sMojKxxs88wfipYAaf7Or92JBlaSyt0 +YMhmhW7+miLEoWqeKkRfBx0q5IHvtmQMpNjDxA9uTXJW0U6FIyhVxXRte/3x4owk +KUfq5P43ErPMEVipaM0ns2y4+d9WimFtUY/52l/NqH84pwgP/2JuNYtRaOZ5pjyO +//zSUpiDbyE1OCeBG2b+YqKwDnCdxdqj0pZps/1fLieBr89GbS4SEMlqRgqN6LxO +XHkfS3frkD87l32zTuQnhD8vxKU01Kr85t6CPL+FIUhjUCxG3Tll8Z+coxgZp8IX +bjpyJfEx9834UqA3EDKpcuh3vndvov0nXe5XnxpmYevuCpd5fIjnbAdimFMshni7 +WhW+9HzKGTAKqaGXqRyEsPybm6Psw6F60p5Kbr9X8/+WM8j3mReQI4n1yKfW25kR +HlqLPmwrJUOGDsf2NV0kYg/8Zd+D5uT02LUKQPh5gd/9X/vm/YNJfmLvkK9V0yI9 +5U6nxRe+kQDreWSpP0mS2Bl3o/mOKDwinn4zZLU3IStrvhoVEo9LeIuehsul8zpk +57x1zHsKwviywBdAeJOXglQRhGhy76+jcN6Ii5rx6Na7uSlTSQqyz23bXfK8BcJr +TpIzMZLfa2s8faTjnjAD +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.key b/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.key new file mode 100644 index 0000000..7a55601 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-child-child-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOIxKHoKGi1/5V +21RKfDqag54mjcz/ye0NvVHqQKXJ4I8EVZyP7fwtl4ElcZ0GyHhqetXsulqgzuoG +ns5eCAq9mMkX4+3/EXvy0lyzrVa+K5ysq6rsUMg7LPpiWA6RM3YYahNedzk3gsRg +hJ8q0vbvpTzNZQ1A+IOY1kdXAeqyBqUT6kLycPYzU/eL2WzVe6pTRt1p2LKckDjx +CKJI1ocYhWrdFhbB9YduvEVpIRTINGXGvTpk8ZwzvgUQk1BmeGc1qqnmY+/wEEfp +u1OZD2+5rJWQ7pSyB1jnMBxqmTc5jkrMkzJX9F5JleVY9+bKZcBGu34mmAa4vXfw +QOnM2HXAvjw3DJGlZCuNKExsJi9RyZcbe1NZqlBkp9l79cnlqURV6HftFFTyBNlo +EaNdzi81rYiMlxEoHEHqjLvo9HCNV90WDDHPxDG+iOKyY6OAZ/QtjGEAjizp1NYH +YkvTG3PzVvqQCsNF4iWzksQY3M0OgyDybskOxvUN0NzDrF7Zw0+SqBSnYGWokVog +hzQHMQHEOv/gYvrdw4kGs5DbRXPfiYKJSPlsFgi0zXpZgm8Br2GxEW6ZfADaK/eO +NC6FW2W4aL9oqC8XyV2kYi/v69G+UeULhVELL4bsUf0moPELFpuwyShHqfQ4l5Us +5m66zxc/I0ekz2N66mWv/WQ9LNJBBwIDAQABAoICAHrZ6CcwkmRMueVNS9UAaKTB +oDV1+SDQpRi1JeaoFKZV0KZSp3YX7Vz2mB9KsLzkKO+8uVXWUkDYUB0V9AOSY2RP +dDlqu+Jx9x7mRB1JRxMbRsqZnMot8sdhrO+Db1sWAmHWhiicgVsV8hdbssiA5m44 +Wh5HBTkdYsBppCa0m7zxvNw7lx6KOBCrEDMmp3grtXzgFQEKBpjMU0NDVAR45ha1 +HNUaXwHFZKuYRP28m3gd0jI5gF28qM0liDsysI4BX/FZ/tux38OA0Hr6C36C9qD/ +vDueFLxtKIzP3X+iRIlmxilZ6H0GxFKypPb6927UaV0+TJaPsCHVuW9UIILW1oWw +asv7C6hix0Pkyv2mX4E/wIXEbURuNLXidWJdc86PrFHJh4vtogGpLaLJt8ez6hUh +3fpqUG/abQrPS+Sa+B+8XdgbruU9u+egfv+kZ2tXzbB/HMlLthgFpjQdHVgU1ZQj +gCr00fe97BU4oLJO5k+cz0idxNnoBgrgxWL/ffxdETo+Y494D9Gx6oj7JtagqPat ++tG2MVyXzcrV82GWejBPt5IhGcl2xPRSxuJ2xI9VndyAemBNGWL5150PNWAuZmCF +38x5snuuKibeUryek4qndPHeQ6bYT5jNIkgwBjlv8o2KjFnrzA56/v125psL6sSZ +XmkloJNZfpnAehzXWeyBAoIBAQDspyysQoCYp7dFvkJUK3LLX/wCkrPHlP4N0QiO +sa5CUEf6jSrt32a3IR9oo1JycvxMb9zaF+6u03P/y11gVZi6V7plmhlKNDUTg9it +skR6aBt85wrahK6CWRyKnN9hOI8G4gv7jAyW+yVCDaRHTKPMB1KoQkZ+XUFUVt1v +tZxGG1gso7nJTjAPTnR3V9SV6I/T00x7LcrWpr39YWO9dkPzXK4kQzmAnVAIw8Jr +RiEkTjGYWJlTYgGDmhas5u8IsUqJnjbmYMOsXy+hgL5FDp/BssP/Wk8dmHQwEVXw +ksZfeUh67L6+D12J09LXX2f2NObO1lTqGbzTTGqfgo3QEkVhAoIBAQDe/T0zIDSF +x2gPUNaBbaXRVSUg4MjxGtTkBfsf89bzoVeMgrR7tJ1ixu0tv5RcBmmeonGt/BS3 +qQZTHM0GUROnTYME8UqqlwfxGXptawCnyffJDEolE+UzHgm+hKsrajJZN6i+hop6 +ATrSPYwyB1dpcC9IYoaaavlkOxpCeZPvIm5r4eMDkiggip/EngmhnbzzRSv1uoUb +j79VhTbJyOR4uDc9pSBYhtzBEv+bxhbWoH6UUfEPlbw63TtJ3Mtm1gwGy2VDtP5W +tnTNT4U5VGHN7Y4KTKRROwerB/omWAuZfuSK8JAktQ87jCdULn8ZSdkYh3m9CHRr +N7beNCFR4LdnAoIBAQCwF91X+Mwzy2jGjsJQW1w6FRwy1fLMqgM5SLfzZidi1NYa +i/zLsBaAYjc653ysCP/P6NUPvAsxL8r7Jdo/mrHgxvK+M6Jp4tszwEH1TddCtkDt ++gXLgDtSZvij9AMMFsfmuUFtVlLv7cVVl00MeOzRHwnUhixqTv4TwedX/m1ghWxh +Gxtdvb5pRVnIjCR1v+12E56vce2jN8PbzSIokt4RMn+qIBOjrmslenUq2a5Dk6O3 +1wWQVDcINBp3YgewEiyCpqX3Wz1+//0zUddDD5S0z06krhB81zptohiuwKi31kmm +no94YXqa2nHjLOzw+YBdnILnB2vIVu5n7v+TOmVBAoIBAAUZr7uqoejpbbTj+XQO +aPuHwgile5MgNPxeMqdBcYozB4icOLqXn/3xZN1mA2Ozddj+CDGdkW+9+voNr5bU +ZemuuS90wWtzdugJ2CYGi4ZK9VLw6AU/Fj/8EOb9q9ibXjlyL3bkJuixfIHwjHNc +faBYw4wZTNDdX4TuYSRiGYMfu3zWNtYPEsHjydG6d6ftrrO1wlKliIPf3tV67Yzh +/m/QbtsHGt1LgGMeJyCOAFm6ZArKcQQVPa/u/XssBK7+eFnzbwaEbkjXdYZ4qihs +iKwoIdaUeDGvcvZzgUI9Q06oe1u+Mt3UElwfUYr4YUnXyZJpDtzHA7qsFI+yi4yO +4kMCggEBALjlyMbOBKzr95yhoTiO8zONQR4PzYt/mOqVrT5JUQqN7FBlGC5rWaG5 +d8Ur1lXiUtuGEVSzhAERyosr7+10nUWaAKnuFhhtLpggauXHKor7vABeu93dC2KA +6O/K+dMfkx1sMaGXI79B6fCClbEEMJf1J0Zbm5/+UdO4/CyntbVM3tDAPNf0GgIE +5fI84disd4D8HmLW6Snv93bS7BygXYlBq7Cq8xAw5OvxIl6eroYa6vXcymL1P1XY +ksRGLm50drZPooekZlQyPIIUvmP/C+Byz347Hz2sDv4KuTjHV5PZSLbDIUYXinQS +9MZTi7RGridSLpg1QpqCUOcbhOQ1MKQ= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-child-test.crt b/third_party/heimdal/lib/hx509/data/proxy10-child-test.crt new file mode 100644 index 0000000..41cb814 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-child-test.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWzCCA0OgAwIBAgIJAM764JrT/2XxMA0GCSqGSIb3DQEBCwUAMDMxCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQxEDAOBgNVBAMMB3Byb3h5MTAwIBcN +MTkwMzIyMjIyNTE1WhgPMjUxODExMjEyMjI1MTVaMEMxCzAJBgNVBAYTAlNFMRIw +EAYDVQQDDAlUZXN0IGNlcnQxEDAOBgNVBAMMB3Byb3h5MTAxDjAMBgNVBAMMBWNo +aWxkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAunD1wwgtFwDOISki +iVAOjL6Q5UHHTFfGMkeXoa6/awWWjRBZT3IdmQlxxXlIEafS9vBMHW4xvAVf2qmg +Y6IZUy4EGqdrzzzmf64E/QcRW6vGbqRQY+HBqYDum+se4s/XfCo7sSpTLbZexhoM +Uz22k3reKzT3xurXtbxF+GQcpb2HnESnTL2omtU2PgEZ8BwhjisEB3rHTtQFqBdF +1uKSvRDJtDlRSUbqgY+cYCFUMdIEtn4djesLdH7yt34i5kukN6RajXJjQTSQFGce +egHaMOcQ7phIv7j305RFJ6waCXBwTCsBoIPtE2wt9pfgFu8zbcWenXpaxR+en/n/ +2gU7LnK3Odiyh3d0/8a+79gWxXWbmXYV2oYVl9ZxSTqa+wvzYQNaw1BPyhGxd95S +ACJOw8XuZ16ZEqQArEH59A36NKdca3OYjAf82fOEfRdIHm/CD9SEv9NRQpgzfzBF +cmiaIdBJg+QJJ0eNr4wZq8sVp1BKlnDosEq0nJ2ywRB3SeTbUrz3VxR3pzjtNYO1 +fIXUnBsoymZtUYqKiNLVP96RyWplxF204zEMP3zx0vIx6pKMmsWivEURxNdo/Hih +eiDaHB93aw+5+2pgKQOfIg0jj4ChE1JN2FOKBDAFq5+9rJIDuhS0Nk4PtYy/7n4R +iIDKiqWDNc2syEZYlEO+1QQuuRkCAwEAAaNgMF4wCQYDVR0TBAIwADALBgNVHQ8E +BAMCBeAwHQYDVR0OBBYEFD4E+/XklnqAWUXZrJa01AuHb6IbMCUGCCsGAQUFBwEO +AQH/BBYwFAIBCjAPBggrBgEFBQcVAAQDZm9vMA0GCSqGSIb3DQEBCwUAA4ICAQCW +nwXJetxx3Y82aBcyG9sQ5CTObsP1TyHRLVOKeA5jTwVxzSjQOChuUijLFbJ3QYds +vP8h56rjn/hLSi7kdyh1s1+mDBRFWAdJCfRfQhQWvgK7eaphln7qUXUXa3JR66Um +R56cXa6A4KG/Qk2vKw+NLjwA01vF+YzynSijwlaRptYLeOZMUMRzD8IwgqkdOAHr +6+RgiRrRIfdZHYmMX3/7sTvzub/d4QfANjKYPVkciW3E71yeAOLOfjjK68u4OMhn +F3I1vHdhCwxh87gZdiutmUjd+xTHhyIVObpSYIfSDCWqjp70s6sTJBdTCDnzIzcp +ta/iI1EkyOH0aOSzz4bclcWAA2R95JeQDP8PLUA8gddvkbW4f9RJbWMjAk3r6WMM +aSlx7djzbKdXIPd7ecFRWPf5uianNHlTHH2pZkHQoENCfuNTs688OzjBEDzUIvOZ +S3WbVlqSzdf8Xp8xDp01QbC/bwFJwOeZjdj4IVyF2vXB2AaE5Xy/umQz1NVnIqK1 +CUyv/EP4HMbWIW5hpaMZJ4VyhrkoX4sLDj25UN1VAzD9lTyAGpMv5KpWd98MhYIX +7KHP69Xo4CHf1RibdRVX6jW+GvzRZGHPb8/V8qgDwOM7UPjsPuwq5Cacatu0L7tQ +hqtYGxcBDAIRIrmm5sZCW4F3l4efUtzozWZS0vzTyQ== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-child-test.key b/third_party/heimdal/lib/hx509/data/proxy10-child-test.key new file mode 100644 index 0000000..7bc4a02 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-child-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC6cPXDCC0XAM4h +KSKJUA6MvpDlQcdMV8YyR5ehrr9rBZaNEFlPch2ZCXHFeUgRp9L28EwdbjG8BV/a +qaBjohlTLgQap2vPPOZ/rgT9BxFbq8ZupFBj4cGpgO6b6x7iz9d8KjuxKlMttl7G +GgxTPbaTet4rNPfG6te1vEX4ZBylvYecRKdMvaia1TY+ARnwHCGOKwQHesdO1AWo +F0XW4pK9EMm0OVFJRuqBj5xgIVQx0gS2fh2N6wt0fvK3fiLmS6Q3pFqNcmNBNJAU +Zx56Adow5xDumEi/uPfTlEUnrBoJcHBMKwGgg+0TbC32l+AW7zNtxZ6delrFH56f ++f/aBTsucrc52LKHd3T/xr7v2BbFdZuZdhXahhWX1nFJOpr7C/NhA1rDUE/KEbF3 +3lIAIk7Dxe5nXpkSpACsQfn0Dfo0p1xrc5iMB/zZ84R9F0geb8IP1IS/01FCmDN/ +MEVyaJoh0EmD5AknR42vjBmryxWnUEqWcOiwSrScnbLBEHdJ5NtSvPdXFHenOO01 +g7V8hdScGyjKZm1RioqI0tU/3pHJamXEXbTjMQw/fPHS8jHqkoyaxaK8RRHE12j8 +eKF6INocH3drD7n7amApA58iDSOPgKETUk3YU4oEMAWrn72skgO6FLQ2Tg+1jL/u +fhGIgMqKpYM1zazIRliUQ77VBC65GQIDAQABAoICAA5i4wPeoKQSwtUaOHkB/W1s +0v9tuPQyHbAJiDDIrCqU7s4Jwep4csI5UVcciawbGBNH7Yej1iCdBY1441Bs1Klv +do+b9ZyzJVIa2nWv0u4Q7inhcfaTF/99XGwZk3OK+CSzmZGNI4f2d4+vuN2/eFQe ++f+5gZkOzABQ+9Ez4GYFnu42+fXY+Kah5yKXsSmu8gPnW9M77R8vCxSyXwg6yXnf +TsEiXxxZZYUD0Nw2FioV+5kdWCh4R5UAqrfv+r9sfMpyWy5o8jG43ZlFb7uYYv69 +BbhzdcGdgzoHSeLKy+OIkpG+C80YAPYrtcw+YeNDJ+PDiP67zz9Atlu/zbdEChHk +tazsDmDqv6ML07X4fPrkPi5PRMN0AXqDz94nXKEAh9fvgrW7c/jhakNgHWX039Ph +5fGD09GjKUkzHr7zIZ5S6LrBrb9BLe8BiTfaZGqpSmRFEKxGwCr15k5w0Mzj/UpJ +Ftcr78u9qthfooaGYGMXiMWZy1138TD/V6Kro/ajMUDhkmmXNuJghDBAQOhHUmcG +Jldth0gwgyVzbQDpbEhI0ZOL4urGyNqylMmfGkN2uAfBfp0TnQT+7msru5BpNqnW +RRAplCh47TpUJ871P7Tm5bSS4SjysfaFXiG0qQXFUSzaRFCYFkzMRoxHV1PBXr0X +/ZmU8r9MtwRh8O+tXy6BAoIBAQDk04GAIlhDBpHmgCPWKTQ9GiYGhXsY9Wb2rbD5 +VaPdF46RW6mHDUJ+SMvNpwGZGfe59Yox1PJG1f8i7B+UCMZZFShttdBGuKRCH+aJ +SIlkBmXK37ikAQREU+hmp0/mbMgq8Lspsjrxmlmi8rsLRKyHlAK3AUAoC2KqoohT +dLEg3uY+5UzpkZQOfeK5/+DaKXjjkHE6dVkjQm0pNtXHJsMQMvcjfH1T6XCuwUKw +zN8aOfvy/mFv5eOJazhAOZ3+QlUbOWh3EpBeEt7Sqqo7kQ5BZZKR+jDjWZETONya +aYQetRHKnFlYWjewpyp+z7SDPNHcXqtK57+QRLXyrOuuQg1RAoIBAQDQlOs8TOht +dJChYks2eiC5sQ8hC0ybMi+x7lJ8KALwPvf9VCKJIri2BxTvxkbC03YnUTsKlCm6 +7Jgkkx3Vy33FCXfaRhwLHaAuA+DwfzMn7WXtP4MJoKWyOJEck5HJzKWCqetdf7Dh +ie/HsgtH2DHqljjhSleEYWVBcjoXVwWL2ctEcl3qr1JSpsRp+TadnIpoyDVWWszt +xQwXpmVPs24svwI0x7p4Q2JzTAqd1oM+o2P48eFThXOobvRA+XGvucse0wWm3N+T +4p1LbH07fguriOGqHea5ZPw7spURcP3CFEfUlsgiKUWjonuCvqjGGLV1U6RZ83FT +S9o35O1Rut1JAoIBAEXL1dZVo4JeQKaEM2ohi1OP5EVc9Z05TTy04iRLYP4RL2Vb +BiyxeLS4U6HY7P3cE9ne8VYd1ACTSY1HZKJswsNtVrWQHYVU0JVy0YjSXUXrRaVJ +9DHiNYD57wtQwWhRigS/BPfE64HCSNERJMhdHBsGpIVZlk4gmundRaPfFiAmnShW +HM2pn/WDpGKDj/w7ZipTZpYkMRo2KsHFfhOO2TTZttRWJowvyjUjscnn061WPmlx ++hp9jpfd4nyElpJ1fSweqKSZPvvS2bB8agxdRHHiH4DzRXIzYbLxRyi6QphzNogM +hJwUeKQjeSzRAgh9xq1nGuxwH9hLfQwWfpTahOECggEAcBL0aswwP0/Yvr5gB3+L +wfr/VBQML3/B3OtfatLc8VYEThw9Ck6bzUL03vk84EZbQDkHbmG6InQqM8zQxSW4 +CH1T5vaw7tAWV2NCJDdUt2l50QbFVBD7t01pu18XgMTzUcgXbX/E/QruyfBC23Gx +MIlTOsqFR95FV+sWh5/8nO6Dp92D1SwrIbn147NCw2FvhWm+Lw5O+ptcKgEAgti4 +pFZlyxJegWxDpAwB0FmI38lPWF4vYn9ca+5iU980VOWR3Jgqe0RG5eFn/zTl/Wd2 +wc6k4pF6fbdjSHhmXJ7H2tam2fXCx4hBoPEXSGNFsFtqdQZiUurZw5YIROw/ECFF +8QKCAQA8PV4eu8rzdw37cJnZOZRYg60PZ80c6LteqBnXwDp7HP7cAR11GUp1fous +o4L1Od8aNUSVpfmmSOR28MuVhZ4wNbV/t+g9VzO4r2zuI/kkEeMstf85hXPLrkjL +eo2HCu2xgM54vNVhG4MN2G5OWgMMkDDX3sPWeYN4Em428iYPHTgod2GaGQ9AnGI0 +wUGHhfGlP690xAvjQJLk0OvTrzKcjdPKrpUmCzIfT7ljfl2PE7l944C9aNvS9cEY +iGkrbALi+EgfcfahEdEbQyIZU6GFDRltgnGtLeOE8NmqabQQgm0THXPjn/CzR3Os +Qshwvh4gXup0rcomkC+d8vVJ2p35 +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-test.crt b/third_party/heimdal/lib/hx509/data/proxy10-test.crt new file mode 100644 index 0000000..9c89f71 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-test.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFOTCCAyGgAwIBAgIJAKQmPUkmhyKjMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV +BAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQwIBcNMTkwMzIyMjIyNTE0WhgPMjUx +ODExMjEyMjI1MTRaMDMxCzAJBgNVBAYTAlNFMRIwEAYDVQQDDAlUZXN0IGNlcnQx +EDAOBgNVBAMMB3Byb3h5MTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDNg69jn3h/uqasiOdUD/MC0vJoty8ncj9NNGfU7YHSLpRnuoyPL8YCRRbxreUP +lIQ5oAP4ERJSrrRoGWuwiboLthVj6OgM1IrU3h9M2sM7fGdLuQ1QCDP0Bsu23MPJ +KWMCUpd3p7jXrPaf1WzUtaIql0pjFFlqZRf1RLKvH4CfDgrx/k3z49RsiZtgxlw2 +VxpGL3cPUO1MfXEq4roMWdT0sGTdJ56l+PkF3Ud2DxhNytmDv1ld2gZhC5H+k5ZI +i3Xr8zvV2dCbSlnnXk8qTG+aWwYGpHFQPwP7UxQDUAk1XAX5/EBXwCTtTDNIhsNI +qB6k9MF3/mreD5frofvx6xEW8CShdAf2vUXC4OB8hkO/NfdaoQj99PL7d8LiICoQ +u4fOZ20g6zpkS+jir5p3KcVbotN0cMkx+k2YwyK3PoLV74RTsigOjp828eoT24Wz +3/ztjn4C0uMHcJz4yHmbrn7xOf7VcaNvfm9qz9H/MpA2Eg0Nj4nBOnTf25WLvgAB +KN0Ctb6rNbF3UfVR9h+QK4kQqhlwjMfPqeT2AL0fOFptotcdPj86z2ux1cvC/w/x +nZrgUdcj2GLLwvCxsmVx5RWOWU7wFoo3WrWpyx228CvaPTQXN5LKBIgpf1wmk4b1 +wR3afu0I5RQp8kSD/2kQBW24D4+AAH1jFbP9IfxxSXCazwIDAQABo2AwXjAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHQ4EFgQUiFCNi8YSDjclAz4L6ZPKi9Ea +afQwJQYIKwYBBQUHAQ4BAf8EFjAUAgEKMA8GCCsGAQUFBxUABANmb28wDQYJKoZI +hvcNAQELBQADggIBAKEy0OrFQkrc3ngQXWBhOEoLElCYIpM5sVDn3aV8i8UAQ9KB +uLfxmcJm5CPZcIAFive2TWVFm1eq6Fr1WEwZ2QtAOXwoQwCzKISsdFRHEV2SNtpg +uUaKlhGUwiYWt9aPkmJD4f/VZB7LeKE4CWij88ey+76Lujkr+ILZnrXnc2Mwf3J/ +x+/RfINh4oM+7rHccAJtznwZ2TCBvF3p5cLlLH413IGnZjO/myz/EMQ8MJoFNc1G +dWXOZiGnbq2+W9rHKOV9rYhIZ5YLLiK6L7vKsLph83KTzWCZW7tZDAmwtFFXw406 +bdWL2+gWBC9SxN3RI2jB9VQtaLspOW+v8qH7cpDaO0xTXufsVjiGbh1hPdAMonQd +k0rrrkLY6ADguTYkHs1E3Eebki6LvyyXBEKJYTtEHfJnU2T1YWwFpqvvFOghFljH +QyZC29QR0rLB2B6uepQXl6d4fFYfYkhjx7SANDx4QA8QqrLgeGjufj9H3yk9e/XX +lto6sjNsOOncP9svCxJgQkp4w7tQxqZ/51RBQAJkUDkwPImstxTIFRdqeXHxLynX +3zTv6rt/767S7SlDfLZs8OrGKPeILGDBF/Q0UQrnrk9Oa+yP2QV3Msg79odKqBzK +MfcQ4DFIfnN9ZRq7d0ffaZ6AqJVbwYM/LlGFAC57z2xsuEAR+Ea0/bjzbaib +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/proxy10-test.key b/third_party/heimdal/lib/hx509/data/proxy10-test.key new file mode 100644 index 0000000..733c2ff --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/proxy10-test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDNg69jn3h/uqas +iOdUD/MC0vJoty8ncj9NNGfU7YHSLpRnuoyPL8YCRRbxreUPlIQ5oAP4ERJSrrRo +GWuwiboLthVj6OgM1IrU3h9M2sM7fGdLuQ1QCDP0Bsu23MPJKWMCUpd3p7jXrPaf +1WzUtaIql0pjFFlqZRf1RLKvH4CfDgrx/k3z49RsiZtgxlw2VxpGL3cPUO1MfXEq +4roMWdT0sGTdJ56l+PkF3Ud2DxhNytmDv1ld2gZhC5H+k5ZIi3Xr8zvV2dCbSlnn +Xk8qTG+aWwYGpHFQPwP7UxQDUAk1XAX5/EBXwCTtTDNIhsNIqB6k9MF3/mreD5fr +ofvx6xEW8CShdAf2vUXC4OB8hkO/NfdaoQj99PL7d8LiICoQu4fOZ20g6zpkS+ji +r5p3KcVbotN0cMkx+k2YwyK3PoLV74RTsigOjp828eoT24Wz3/ztjn4C0uMHcJz4 +yHmbrn7xOf7VcaNvfm9qz9H/MpA2Eg0Nj4nBOnTf25WLvgABKN0Ctb6rNbF3UfVR +9h+QK4kQqhlwjMfPqeT2AL0fOFptotcdPj86z2ux1cvC/w/xnZrgUdcj2GLLwvCx +smVx5RWOWU7wFoo3WrWpyx228CvaPTQXN5LKBIgpf1wmk4b1wR3afu0I5RQp8kSD +/2kQBW24D4+AAH1jFbP9IfxxSXCazwIDAQABAoICAAXV+HQGwkA2R6dcl90OOuNY +pCOPGBqxptSFaXFlcStLwVEUvgsO2zuTRKyGOJvxprOQNKylp3SLm3ndRu6TaqIM +gJz+ryA2JN8Yk6D2EVcuGCzRS2x7XyZNzxkZOcILl9EoET8HlzsgoTw2rkl4Auvc +sfMQT92ykzSWx9ArP9bEalEm3IXRcWXHno7n8xRj8s4NaP8ZWDO02DLUj13saxyr +qaGSD3I9GK0u9GmI0jLbUMPp+hqtJ0M4NeQZwsm6lBWoKYnQDplqShVE21CjLQQg +E5K6trEFqRJI8KeLbUeDnnPT0uvq++F1KXukwATfKUeb36aNpfE6ViENz362Ix0L +lDqWU6gSOPBOO0hD/LLSzGJY/61MrIy4P8S3gS2u40jm8YaW45Bed72pTGwkyz7Z +9c3YbSJYWNg+o18yI7z4JVlJkptMsq3KJwj7BXIAgFT+uIteCbf7UXCNdsUzSiE8 +k2JxiNKlaaw7xnQvGuwFdDB+uCQC3PGngmDU222mq1Twm8rMHAgjt6RMO3tv42H3 +Fsap/MIDiVUQfYrTHoN2FVG852CzVbnGxPaxDJYS/vfVmSFcMeW91lbQM9J88721 +gG7hs55IrBvEse7U21EtlLISf3HYpLnMlHqH4S61VuKKS9Tmx67llfi6HMKupG27 +NfDFfoLiQCFltTCBcrHxAoIBAQD1YhrgDXmOiVCFuSdiu3k063+2pC/r4uUSo9QZ +zPAMq9XIgXdGJoWCcQ1kg+/qEvhBxBbzywoU5zJQluu3V33JrT1Y2tNzyPaLNIpb +aFYUP27/yC1xOyD5bcYvaVV612pVuORzN8PRShbpTyfSDhGxx8/KxXBg6iN0Adk/ +Rk1rzgl9UH0WLy7hS5hecroX/bfqlKWLjfWEtsDo+dyA/HoL6ku0YDuQvJvzZrDB +gQfDo+FewaL+idZC2Bx61f36h93dlggeJgC4sOHh/j/AXkMaKEHFRvM0SLOE1lrm +RyT3kdhCUoX799+Ke/BxcjfPwY1GKxsVWaiwbFUAwFcWYyPJAoIBAQDWZ/zw75El +PjsrwIGr3BLmmyxMeJKPniIdhdEvgj4/2jY3ao7DdRcLe2RZy6J0vdrA2XfeQDdf +zX03T23Ha0uCGXgqRUUa1wKFrzDnXTD1YAXFqQc8XXozTyEkF7+oz3wQnqpMhK6I +X5CAwmZc6s7mObF4MiBKWQFlyL+rHybc+ZFe2LvS6UgP2btCsWvUJ1xCgwnnCA4a +Q/8ximehCSJqYrt/icOVSdNf4rzzgzQxCObvplw3E/stRgahQcYSI61JN9Ja0ONe +bCpuUpDNShPrE5W6uDB9ogfjX9BN9Zbwq4bR8WwhBGZLDS0Peqfe20yJ4mbsEEez +9mgvvEeBtaXXAoIBAHPTnin6UlGUwXyNnGi/Y4Q2UW+N6szmqgh1ao3PLdRdXCkr +63gigMzEvnSezqVn1OV+QPNM+PJK+3YM9zDwzIBhFN8XU86Ios+suk5RXqhqFOQJ +wmF7bqIuTeldSCsW+auC/drhDL6CwXPZmEtPtsx7K7tkHRqyCpAcu0Zh0fO8KsCL +OLA7D17rRv32G59tdN320nmgRa8icMbIAmykQJvVOWzoK9WzIc3vwClm1ZpkheIr +dtu9hnTA/BiDYEJc1b5drnFEsPx9CfKaB8+u7u+u5vTO+8fHNW3TnM6r8Ggn4LPV +rkb0hwEgZau3JV8c1qmzeTJHwxeb2zfiknkPzPkCggEAMsEnFXoAqApVQ4QsrhxI +tSJimC+qsijC9q4o2NBCICdt0ix9YzOiousw1DjqWixfTmusfoZBFYK1c5Rv7lct +5rxUv9zqAPKI/FB+iSZ8Ynm6pBHhTp7qQJ8ovzyH+FQ1kFGfCsIV9t54fKKITNKg +68sYgdWL402ykP+2r7GOJ51ElmlD/SeQEYB/XchWOEChDHWssG4tuHYEQRv8cBiT +dw+sRwK7s+loCjjIdfTHNBxhXrXI+pjWSt9azm2dj8m2SbDXMPxl9oIwgTE2agJx +OKLIPQ1BHVxv9ZlG3E2Yz5wrLCO0bxR1iqqx0go9Fvpe4f0gVB1+e9GG1FYDr2bq +vQKCAQEA5HDb2Va1e9QkK8mvTKcWad9czLwNXKdvWanv2j2+VJTmjWG0KuzNsoQQ +5ZUpUQ1XFpC8aYaJRuWVsXShZ69E3RHGrH9jtYQ36mf+Aao0oMW4FoJ+szAHoN2K +8f4PES5TcK7wlQafq61Tkgsrr8KT6UbNWr7F97UgcPKI0HVs6yEJ/hY3HExaBxug +VHLUSTOPIx3Sey47wR9I6XvbESSVLh27cy/GIDBOI4OEQTN6bg3t/7Pf7o4agan+ +r41oGtzuhX2CXbiqEaynU1wOrSjBshO29Cm++5MBnqiGUA7UCv5BHX/vU0ECKEW8 +M4C7UTY7JIl5vsDk5aoxq4Rt6pBkQQ== +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/revoke.crt b/third_party/heimdal/lib/hx509/data/revoke.crt new file mode 100644 index 0000000..ded2325 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/revoke.crt @@ -0,0 +1,116 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:03 2019 GMT + Not After : Nov 21 22:25:03 2518 GMT + Subject: C=SE, CN=Revoke cert + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ce:ac:a3:c6:69:47:c4:dd:f4:d9:0e:ac:42:90: + ae:57:f2:68:c4:77:89:9a:65:cd:8f:97:fc:68:6b: + 6b:65:0f:52:2d:d1:db:83:2c:1e:39:35:dd:fb:f6: + e8:c1:40:e9:ab:a6:48:23:e9:f0:e1:8f:72:27:6c: + e2:8d:04:e9:ca:e3:fe:ac:d9:28:16:be:db:19:fc: + 9a:20:d6:93:1f:15:b8:b6:97:cf:07:5a:da:ab:aa: + 97:c0:e9:39:7d:f9:df:96:c9:99:8f:6f:51:3f:64: + 13:0e:ad:0e:4e:2e:66:6f:72:6f:63:a6:a5:fd:85: + 0f:ac:ea:03:4d:81:14:bc:f3:5b:e5:fc:f6:6a:f7: + 57:b3:c3:b0:ed:4b:43:b1:cf:e2:1f:f6:44:07:83: + 27:b8:ef:19:9f:35:2b:95:59:b9:e1:69:c5:19:07: + 06:d7:17:da:35:4b:ba:74:68:c3:d3:28:ab:1e:b4: + 8a:ba:2b:f3:5e:06:75:0c:c8:a2:a9:ea:ec:29:1a: + 98:fb:b6:00:e0:98:78:cf:ea:36:2c:e1:51:8e:15: + 74:ba:4e:2d:8c:df:9b:72:72:52:b7:c7:82:45:35: + ba:c3:62:bf:29:d0:c0:17:6b:be:3b:e4:87:6a:26: + 34:4f:84:b5:ad:34:72:5f:4c:96:d8:d4:cd:5d:6f: + a3:ac:b1:55:a8:c8:c6:5d:99:0b:f0:bd:5e:f2:85: + 3e:74:05:d7:0f:9f:95:5a:14:1f:19:31:af:55:75: + 2a:80:22:7b:f7:ff:89:4b:70:5a:74:52:77:7a:ac: + 6b:86:2d:cc:5e:ca:57:3d:a1:20:d0:95:80:0b:48: + 26:52:69:9d:19:7f:0e:a9:63:97:70:b6:25:64:79: + ae:19:45:f8:7f:fd:23:75:9b:0f:d5:57:ae:56:50: + 9a:0c:fd:eb:f2:1b:a9:0a:3d:a2:1d:f3:07:cd:b9: + 63:5b:3d:95:21:9a:f6:27:2e:46:6a:3f:8f:48:b9: + e5:d7:ef:27:08:fc:45:37:70:23:88:a2:89:50:7e: + a3:ba:06:b3:b9:50:60:7d:aa:d6:eb:1c:b9:79:1c: + 16:06:d2:07:d3:c6:09:73:2a:8a:92:10:93:cc:52: + b4:bf:4b:09:d6:71:c1:60:57:3e:2f:12:13:90:18: + 06:44:cf:79:6f:50:78:11:8c:e9:ab:2b:97:19:5f: + b2:67:a9:fa:9b:b0:99:44:35:0e:00:18:6f:9a:00: + 39:e2:ac:e2:79:25:e1:46:d2:18:e4:80:d5:ca:ed: + 15:dc:7f:a7:90:7f:26:71:26:38:6b:ef:be:92:0c: + 07:64:24:64:a7:85:9d:2b:d9:14:bc:64:40:46:eb: + 78:b9:dd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 3B:AC:F2:D9:72:19:FF:77:61:0C:6B:2C:C0:69:D0:28:46:8A:C1:D7 + Signature Algorithm: sha1WithRSAEncryption + 23:5d:75:da:82:54:6a:eb:29:cf:e0:55:da:4e:69:c3:d1:7b: + 27:20:37:ca:3e:ac:ba:55:30:0d:a6:57:44:de:1b:71:aa:57: + 80:8d:55:e1:48:fb:43:dc:23:d3:fd:85:ab:36:35:11:1d:41: + 30:59:ff:e4:61:e1:4d:14:8b:64:9e:cc:a0:71:19:a3:a9:10: + 84:47:72:dd:2b:56:5e:78:a9:ed:f1:32:8b:b4:5b:87:aa:bd: + 74:4f:ee:50:ba:36:d5:70:56:40:7d:64:d6:04:42:ae:50:2b: + 95:48:f5:74:8b:a6:b5:5c:49:9d:9c:f1:0c:0f:0a:f1:53:43: + ec:1f:59:6f:1e:54:ca:9d:b2:39:73:58:28:b7:0b:74:e3:ed: + d4:36:ef:7d:1d:c6:1f:2c:ff:a7:df:a2:a7:9e:94:b9:3f:3d: + 18:fa:07:d6:e9:03:f6:3a:d1:79:55:df:af:12:13:ef:45:af: + 63:57:fc:ef:db:5c:bd:e7:93:b5:81:35:e9:a9:e4:39:99:b9: + 32:7b:6f:1a:14:41:3a:fa:68:3c:0a:ae:9e:95:51:72:32:dc: + d6:e9:98:7d:65:db:ce:57:1f:1a:e5:2a:5a:c0:07:26:64:f0: + 49:ff:af:97:74:fe:98:20:94:7f:f7:3c:a7:46:ed:ad:e5:1b: + 7a:08:c4:d4:ce:3f:8a:ef:07:79:ec:d5:f1:1b:2b:f6:e0:95: + 31:ef:8e:bd:b8:ec:a7:84:f8:ff:c6:39:7a:15:8d:4b:4e:05: + c8:e6:2e:bb:bb:74:5a:51:92:f7:b1:04:55:2b:dc:42:18:d5: + 83:95:c4:d0:73:10:62:d5:55:8d:ea:a0:fd:ff:ef:10:9b:8f: + b3:ba:8a:91:75:5e:b9:9d:36:7d:53:5d:8d:1b:0d:c5:bb:1c: + 23:fc:08:5b:1f:3a:d5:1c:35:61:48:58:8e:c0:42:7c:3c:c8: + a0:17:8a:04:13:a6:03:49:cf:86:18:39:32:e4:fe:32:38:bd: + 53:bd:49:fa:65:63:3d:41:6a:c7:65:f5:df:7d:7b:8d:d0:74: + b2:c3:8b:bd:1e:4f:96:15:a0:7b:23:fe:81:e0:de:7f:06:b3: + f8:a2:52:cf:43:91:49:6f:ae:d8:6f:4f:51:85:7b:c2:f7:f8: + c8:4d:e0:a8:48:9a:5b:05:e2:60:fd:b7:bb:b7:7a:2b:35:e6: + 15:f3:e8:5f:b6:cb:d5:b0:7b:45:70:db:fe:82:97:c5:6b:be: + a9:60:21:87:19:b6:91:32:2f:01:b3:04:84:a3:1d:8b:06:00: + 3e:37:f4:c3:ff:b4:55:cb:cc:d1:d1:96:9b:d8:1a:0b:9f:47: + 66:b7:90:9c:d1:09:c2:aa +-----BEGIN CERTIFICATE----- +MIIFAzCCAuugAwIBAgIBAzANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwM1oYDzI1 +MTgxMTIxMjIyNTAzWjAjMQswCQYDVQQGEwJTRTEUMBIGA1UEAwwLUmV2b2tlIGNl +cnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDOrKPGaUfE3fTZDqxC +kK5X8mjEd4maZc2Pl/xoa2tlD1It0duDLB45Nd379ujBQOmrpkgj6fDhj3InbOKN +BOnK4/6s2SgWvtsZ/Jog1pMfFbi2l88HWtqrqpfA6Tl9+d+WyZmPb1E/ZBMOrQ5O +LmZvcm9jpqX9hQ+s6gNNgRS881vl/PZq91ezw7DtS0Oxz+If9kQHgye47xmfNSuV +WbnhacUZBwbXF9o1S7p0aMPTKKsetIq6K/NeBnUMyKKp6uwpGpj7tgDgmHjP6jYs +4VGOFXS6Ti2M35tyclK3x4JFNbrDYr8p0MAXa7475IdqJjRPhLWtNHJfTJbY1M1d +b6OssVWoyMZdmQvwvV7yhT50BdcPn5VaFB8ZMa9VdSqAInv3/4lLcFp0Und6rGuG +Lcxeylc9oSDQlYALSCZSaZ0Zfw6pY5dwtiVkea4ZRfh//SN1mw/VV65WUJoM/evy +G6kKPaId8wfNuWNbPZUhmvYnLkZqP49IueXX7ycI/EU3cCOIoolQfqO6BrO5UGB9 +qtbrHLl5HBYG0gfTxglzKoqSEJPMUrS/SwnWccFgVz4vEhOQGAZEz3lvUHgRjOmr +K5cZX7JnqfqbsJlENQ4AGG+aADnirOJ5JeFG0hjkgNXK7RXcf6eQfyZxJjhr776S +DAdkJGSnhZ0r2RS8ZEBG63i53QIDAQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQE +AwIF4DAdBgNVHQ4EFgQUO6zy2XIZ/3dhDGsswGnQKEaKwdcwDQYJKoZIhvcNAQEF +BQADggIBACNdddqCVGrrKc/gVdpOacPReycgN8o+rLpVMA2mV0TeG3GqV4CNVeFI ++0PcI9P9has2NREdQTBZ/+Rh4U0Ui2SezKBxGaOpEIRHct0rVl54qe3xMou0W4eq +vXRP7lC6NtVwVkB9ZNYEQq5QK5VI9XSLprVcSZ2c8QwPCvFTQ+wfWW8eVMqdsjlz +WCi3C3Tj7dQ2730dxh8s/6ffoqeelLk/PRj6B9bpA/Y60XlV368SE+9Fr2NX/O/b +XL3nk7WBNemp5DmZuTJ7bxoUQTr6aDwKrp6VUXIy3NbpmH1l285XHxrlKlrAByZk +8En/r5d0/pgglH/3PKdG7a3lG3oIxNTOP4rvB3ns1fEbK/bglTHvjr247KeE+P/G +OXoVjUtOBcjmLru7dFpRkvexBFUr3EIY1YOVxNBzEGLVVY3qoP3/7xCbj7O6ipF1 +XrmdNn1TXY0bDcW7HCP8CFsfOtUcNWFIWI7AQnw8yKAXigQTpgNJz4YYOTLk/jI4 +vVO9SfplYz1Basdl9d99e43QdLLDi70eT5YVoHsj/oHg3n8Gs/iiUs9DkUlvrthv +T1GFe8L3+MhN4KhImlsF4mD9t7u3eis15hXz6F+2y9Wwe0Vw2/6Cl8VrvqlgIYcZ +tpEyLwGzBISjHYsGAD439MP/tFXLzNHRlpvYGgufR2a3kJzRCcKq +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/revoke.key b/third_party/heimdal/lib/hx509/data/revoke.key new file mode 100644 index 0000000..d70b74f --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/revoke.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOrKPGaUfE3fTZ +DqxCkK5X8mjEd4maZc2Pl/xoa2tlD1It0duDLB45Nd379ujBQOmrpkgj6fDhj3In +bOKNBOnK4/6s2SgWvtsZ/Jog1pMfFbi2l88HWtqrqpfA6Tl9+d+WyZmPb1E/ZBMO +rQ5OLmZvcm9jpqX9hQ+s6gNNgRS881vl/PZq91ezw7DtS0Oxz+If9kQHgye47xmf +NSuVWbnhacUZBwbXF9o1S7p0aMPTKKsetIq6K/NeBnUMyKKp6uwpGpj7tgDgmHjP +6jYs4VGOFXS6Ti2M35tyclK3x4JFNbrDYr8p0MAXa7475IdqJjRPhLWtNHJfTJbY +1M1db6OssVWoyMZdmQvwvV7yhT50BdcPn5VaFB8ZMa9VdSqAInv3/4lLcFp0Und6 +rGuGLcxeylc9oSDQlYALSCZSaZ0Zfw6pY5dwtiVkea4ZRfh//SN1mw/VV65WUJoM +/evyG6kKPaId8wfNuWNbPZUhmvYnLkZqP49IueXX7ycI/EU3cCOIoolQfqO6BrO5 +UGB9qtbrHLl5HBYG0gfTxglzKoqSEJPMUrS/SwnWccFgVz4vEhOQGAZEz3lvUHgR +jOmrK5cZX7JnqfqbsJlENQ4AGG+aADnirOJ5JeFG0hjkgNXK7RXcf6eQfyZxJjhr +776SDAdkJGSnhZ0r2RS8ZEBG63i53QIDAQABAoICAQCH6WxCXJW/1x7fZxDNLYwZ +deaD3QB2sp/94DszCAE2El8+lpU+q9KsWMpEmljyTZfdM5qZU4z/KHAvkSFjD2oX +7NtcG+qLGrPHYSCSm8lgVc6E9UxGT+8hmSv2xujx+VKaPLVpaBEMGOmXayLPMyBW +BfFOnRbno4ttcO7/FvXmVDuJAVOjgEkChJxjUG2SD11rG24dapjCuyokUrj4nGrq +272r+bz70knDZquVRhgRUttFdAEO8Tw4BxMOdxrRlxX66ezVCxmEmYBJaoJ5/Sq+ +v0lmA2ddDueQ2bGf/emjTfQl7Vg9TXQlcstFY8HRgpJAAMvgvW7BUQKaUUdEPNhq +177x6a450fc3oN7sC/gOFXrx0bPmwJMa1gDGIAkdzB6p1R2aeM0WwFPny0iflgf9 +3oNFdA/zvK8eCSiY3TbD/F3qyzdw0j7lRW3BSYn9XWS0FJHQTXYb4H8rjFkcHMHp +Zg7rv8C7H/vS2eCdS6j/7UhJnXLapodmxwLkcpsuilMUT9IjcdMHCqRyuEQT8vtZ +u4Dl9nf9Rw4SMVeCwkEWFmMQUdNDSo4CO2Yyo2Qv4kEh307lFuX5icDFdbY0ODbD +qrBaWKVkSDNKRrzwBu6dwrW5X/zTHNCi+i8nJNCUysm/Pue98x1pHzkKcE0tbSQf +uaT+qSeTR5/iVsmgmNlbAQKCAQEA8g2YTH9SgCXoaanghvbgk4Q5uimEFdEaza6H +XWEgC7PQDehBoJCwBhuMtSj237uU6XB8Q9o1fV1Lv0Y9Xl6Ht9QlAI5p05jXM7a8 +/e9qIg1ZJy0eUmC+ICCdW8UbWnEyb8JAGucRJ4xHSc4QIbE0uYvKlt6n/AidEYiU +zasNUANEdT7BL0EY5XheQ8IIloI8/olz02WxJtyCnvVkfHszXaB9+l/zEQhYXBIy +oo+PLkd0rApB/JDnive1rlwG40eLp5CvlA0uATX6ZKWOGY0UhDbQfuBwzqOoCiXf +0qmmUk3dCAJeRSQcY8zcVn8u8qq9z56IFcaWBHKfPPnDG4kBPQKCAQEA2pUw1KnE +rxcKHs2Giqz4edx35gddaNgvKbX1/iFrFRqjctmf74KVx7E9CAs30UUMgohVhccl +xsbvn3SLkiGKKxp+cK8Sciq2O7g9AXwsKHWzMG6hl/tXjBYAQx7XSkbDYgDJdE9i +PhfUkBi2PAPJzSBGT9BJiPNm5uxCLrkj+YG5qe64fG5ZiBdQ2iLz3ggrWcwUBM6t +a1SaqDbysTiUStoUr8URbZeveRS0NmTUt5YNhQvkYHyWRD8JNMSKBoCMCRrhykEI +oA2tzptesQs92kUrl7C7XHUczFULGH/KrXD9RAVxLFC8rlqiU0PwUEYDbGYVd/+R +f8q+TOAjNsTlIQKCAQEA6CEFh4crFV5FTt/tRUGJCa9qtQ+PbmTEcbAIfRLh6pcc +1dmA5n0bciAFhs6sQs/f9Sc85M1lMr7AH8U6oT/CpBa9DZWGA7i12RBMmrJ5dAKd +Fyb7x0Cj1KeygQm8O7YHCoqdc69ZEjZDP5Jwgf8xcyeOt7T8IIYaK3ByU/LQp4Ua +p93w4mJpf9c5f32bQsvPtsMW4wrJI12hntPy9DYqgoWhivVtY04/frys9pz6UQWR +7FNCCPbmNq1r/LSgnmJEmgP1feRN1Ddx1Ae5COP1Yv42YRbY2DK2ulSsG5k6uf+W +E1JCGciRuVwDiqgZ2/rGYU/FbiyuPcG22IEmDUgMeQKCAQB4sWY8Ft2WfFdHON7w +VaAB0b2Wkzx9ttkb4/BHeXZiOcpEkWvhWS6RDAmSFnekosbMkLEAZD00rAYF+tlS +QBjFwiRM3i6GQZVMFmgBGOpdENh3hq7Nd6gYntFYPoBL8BTUWXDjOy4Y8Rma0zpU +mxbjn82TJoRkDVolahEFMY9uprW44iqV8myXW6B2QlR7pfEh7TCkkuZo3FdlSKnr +Nz2SsyY3A86iv93RMqBrZHOcR0uBylY4/LIQTuora9Z2zqYEJQbFofE8RzFQYrP/ +eCCYFBeE874QyE21ecPdrDpiWIBP/d1GxfHZKAx3g4z/Fhmv0hJKpyBU+sLnOd/X +zxJhAoIBAA1EoDaxl2E8VYtFEb/PSdXI2n1OJJ5Vo5M6ChEtkU1tc3j0GkibRzKH +y4MpFTUYKUaAr0TYil9aZSasCLC3IpHZtTW//QcqalO76Xv/ZTDXIEDq5KIQ0/H6 +3K0cwUl6VzKgwtK+wkqR/vdQnB3uhJgHrYQQ2/9vkpcAJmeYx7Pfjor9hpivloCD +iRhpPjE4H4yiG+85/dRZaZ21X59FKoBleVown6ZYI4Z5BKHEULesTl/kqWXvsHpu +RD4yQ+gR2yKNYmpZ10pqZ+0EYZWf6iqrFZCWJ7pvMO0hMye17yC5QD4qMqJCtJZL +oSgi/Llzrh+HYp+WubHP32IPhXGX+w0= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r1TestCA.cert.pem b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.cert.pem new file mode 100644 index 0000000..3522b09 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBuTCCAWCgAwIBAgIBATAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjA2MQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAE5SuFK+KhglopQr1aMjl4ZEBaw4HYM2yVORyBOQWx3e8Pj90bFocE +4gyS4P2V0YraxACsQgMp+s4e8/6gXPeMtqNdMFswHQYDVR0OBBYEFOtR3wCoaF9m +8dWylzOdd5vfbwmDMB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAwG +A1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0cAMEQCIF/JTbEv +iuYcuREFzWgZ/AgfLe2sRwEgSy6UcAWOYllkAiApMzA3xKjaX1/hhkDGKZnHfcTM +tRuM0FuTdO+e15ku8w== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r1TestCA.key.pem b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.key.pem new file mode 100644 index 0000000..3888266 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgL2N0gdHhAjBGcJ40 +gHePPMwGKygIVDXTfjysn9zPiSOhRANCAATlK4Ur4qGCWilCvVoyOXhkQFrDgdgz +bJU5HIE5BbHd7w+P3RsWhwTiDJLg/ZXRitrEAKxCAyn6zh7z/qBc94y2 +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r1TestCA.pem b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.pem new file mode 100644 index 0000000..9b1df2c --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r1TestCA.pem @@ -0,0 +1,17 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgL2N0gdHhAjBGcJ40 +gHePPMwGKygIVDXTfjysn9zPiSOhRANCAATlK4Ur4qGCWilCvVoyOXhkQFrDgdgz +bJU5HIE5BbHd7w+P3RsWhwTiDJLg/ZXRitrEAKxCAyn6zh7z/qBc94y2 +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIBuTCCAWCgAwIBAgIBATAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjA2MQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAE5SuFK+KhglopQr1aMjl4ZEBaw4HYM2yVORyBOQWx3e8Pj90bFocE +4gyS4P2V0YraxACsQgMp+s4e8/6gXPeMtqNdMFswHQYDVR0OBBYEFOtR3wCoaF9m +8dWylzOdd5vfbwmDMB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAwG +A1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0cAMEQCIF/JTbEv +iuYcuREFzWgZ/AgfLe2sRwEgSy6UcAWOYllkAiApMzA3xKjaX1/hhkDGKZnHfcTM +tRuM0FuTdO+e15ku8w== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestClient.cert.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.cert.pem new file mode 100644 index 0000000..5763c5a --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVegAwIBAgIBAjAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjAwMQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEPMA0GA1UEAwwGQ2xpZW50MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAE7v8wIgEd/yBAtDmW2nW7II4IDDy7KVlnv6/+sHegoe4AjIvqr9CNldkfcVHl +VwjMA1q83lIB/H0IUmk+T6lQhKNaMFgwHQYDVR0OBBYEFKNeDhfd+znE5CBO6aNl +DAUjXdF6MB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAkGA1UdEwQC +MAAwCwYDVR0PBAQDAgSwMAoGCCqGSM49BAMCA0cAMEQCIBVFIAeFxXeB4LURDxv/ +YnGzJJK0b+pjK5hVEPYww8dzAiAmHrccM21Ga7S+/yFWIvMe3BKtAl0O62TTI2Fg +CHiIWQ== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestClient.key.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.key.pem new file mode 100644 index 0000000..36c67f9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6oD5CbNzN7oAWqcq +dKJKw2WU5EwnUV05+7S9gXgeW/qhRANCAATu/zAiAR3/IEC0OZbadbsgjggMPLsp +WWe/r/6wd6Ch7gCMi+qv0I2V2R9xUeVXCMwDWrzeUgH8fQhSaT5PqVCE +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestClient.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.pem new file mode 100644 index 0000000..9f49adc --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestClient.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVegAwIBAgIBAjAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjAwMQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEPMA0GA1UEAwwGQ2xpZW50MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAE7v8wIgEd/yBAtDmW2nW7II4IDDy7KVlnv6/+sHegoe4AjIvqr9CNldkfcVHl +VwjMA1q83lIB/H0IUmk+T6lQhKNaMFgwHQYDVR0OBBYEFKNeDhfd+znE5CBO6aNl +DAUjXdF6MB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAkGA1UdEwQC +MAAwCwYDVR0PBAQDAgSwMAoGCCqGSM49BAMCA0cAMEQCIBVFIAeFxXeB4LURDxv/ +YnGzJJK0b+pjK5hVEPYww8dzAiAmHrccM21Ga7S+/yFWIvMe3BKtAl0O62TTI2Fg +CHiIWQ== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6oD5CbNzN7oAWqcq +dKJKw2WU5EwnUV05+7S9gXgeW/qhRANCAATu/zAiAR3/IEC0OZbadbsgjggMPLsp +WWe/r/6wd6Ch7gCMi+qv0I2V2R9xUeVXCMwDWrzeUgH8fQhSaT5PqVCE +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestServer.cert.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.cert.pem new file mode 100644 index 0000000..71935b8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVegAwIBAgIBAjAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjAwMQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEPMA0GA1UEAwwGU2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAEi1mCfULxkG8qSQ2gSh9YvQksJNodPaUmPt32NG1IqJHY+U613keG14Oo/vwr +h6CVEyTmeqyYSihqV9s2wUHLxKNaMFgwHQYDVR0OBBYEFOowNM57NxGxrHqV/oT9 +eT5DM+iuMB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAkGA1UdEwQC +MAAwCwYDVR0PBAQDAgSwMAoGCCqGSM49BAMCA0cAMEQCIB2nDbiSg6jTeoSWfCvG +23Pn4xxbes8Nb+/8+1lDjLWPAiA+KB8wJhUA4hO/Axfu85wKjddpbGtJR0JlxtEe +whF52Q== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestServer.key.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.key.pem new file mode 100644 index 0000000..fb57e79 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKo/47DaveCl90GxH +LCE7IGBua2XsE+jI4RUWZrqjhBGhRANCAASLWYJ9QvGQbypJDaBKH1i9CSwk2h09 +pSY+3fY0bUiokdj5TrXeR4bXg6j+/CuHoJUTJOZ6rJhKKGpX2zbBQcvE +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/secp256r2TestServer.pem b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.pem new file mode 100644 index 0000000..31a354d --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/secp256r2TestServer.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAVegAwIBAgIBAjAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjAwMQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEPMA0GA1UEAwwGU2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAEi1mCfULxkG8qSQ2gSh9YvQksJNodPaUmPt32NG1IqJHY+U613keG14Oo/vwr +h6CVEyTmeqyYSihqV9s2wUHLxKNaMFgwHQYDVR0OBBYEFOowNM57NxGxrHqV/oT9 +eT5DM+iuMB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAkGA1UdEwQC +MAAwCwYDVR0PBAQDAgSwMAoGCCqGSM49BAMCA0cAMEQCIB2nDbiSg6jTeoSWfCvG +23Pn4xxbes8Nb+/8+1lDjLWPAiA+KB8wJhUA4hO/Axfu85wKjddpbGtJR0JlxtEe +whF52Q== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKo/47DaveCl90GxH +LCE7IGBua2XsE+jI4RUWZrqjhBGhRANCAASLWYJ9QvGQbypJDaBKH1i9CSwk2h09 +pSY+3fY0bUiokdj5TrXeR4bXg6j+/CuHoJUTJOZ6rJhKKGpX2zbBQcvE +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/sf-class2-root.pem b/third_party/heimdal/lib/hx509/data/sf-class2-root.pem new file mode 100644 index 0000000..d552e65 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/sf-class2-root.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/static-file b/third_party/heimdal/lib/hx509/data/static-file new file mode 100644 index 0000000..2216857 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/static-file @@ -0,0 +1,84 @@ +This is a static file don't change the content, it is used in the test + +#!/bin/sh +# +# Copyright (c) 2005 Kungliga Tekniska Hgskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +srcdir="@srcdir@" + +echo "try printing" +./hxtool print \ + --pass=PASS:foobar \ + PKCS12:$srcdir/data/test.p12 || exit 1 + +echo "make sure entry is found (friendlyname)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + PKCS12:$srcdir/data/test.p12 || exit 1 + +echo "make sure entry is not found (friendlyname)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test-not \ + PKCS12:$srcdir/data/test.p12 && exit 1 + +echo "check for ca cert (friendlyname)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=ca \ + PKCS12:$srcdir/data/test.p12 || exit 1 + +echo "make sure entry is not found (friendlyname)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + PKCS12:$srcdir/data/sub-cert.p12 && exit 1 + +echo "make sure entry is found (friendlyname|private key)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + --private-key \ + PKCS12:$srcdir/data/test.p12 || exit 1 + +echo "make sure entry is not found (friendlyname|private key)" +./hxtool query \ + --pass=PASS:foobar \ + --friendlyname=ca \ + --private-key \ + PKCS12:$srcdir/data/test.p12 && exit 1 + +exit 0 + diff --git a/third_party/heimdal/lib/hx509/data/sub-ca.crt b/third_party/heimdal/lib/hx509/data/sub-ca.crt new file mode 100644 index 0000000..25f3ae8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/sub-ca.crt @@ -0,0 +1,123 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 10 (0xa) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:10 2019 GMT + Not After : Nov 21 22:25:10 2518 GMT + Subject: C=SE, CN=Sub CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c7:18:39:67:2a:c4:6b:c6:1a:64:23:bb:ba:4c: + 47:22:35:91:b7:c9:eb:57:b9:8b:8f:83:62:be:0a: + 56:49:cc:ed:de:7e:f9:44:db:8f:f9:f9:ec:db:a2: + 4a:d3:fa:b1:36:c0:93:e9:2b:d0:9a:64:65:43:52: + 64:0e:af:3c:0a:23:57:d9:66:44:0c:ef:a6:73:7e: + 4d:71:94:76:5d:d2:2e:9c:02:1e:44:4b:67:0d:61: + 05:ff:f1:cc:29:94:93:ab:f7:b6:d7:33:d0:9e:b4: + 02:1a:7b:03:bb:9c:52:00:21:43:97:ff:59:f3:b1: + eb:16:67:b1:5a:66:26:99:04:12:28:bb:68:97:38: + 66:cf:d3:cc:da:41:d8:4f:e2:f9:59:48:da:ca:55: + b9:2a:63:43:6b:0d:c5:58:75:8e:6e:55:d2:77:cd: + df:8a:14:82:a2:72:f3:e8:93:a1:e4:72:f3:c0:93: + b3:0b:72:98:ad:53:93:53:86:fc:b0:3b:77:1c:aa: + f5:64:77:ce:92:0c:07:82:60:39:e9:d6:bc:df:dc: + ad:f9:4f:42:d2:db:42:76:6e:0b:f5:fa:58:05:7f: + 3c:d9:cf:eb:d2:c0:9a:26:2c:e8:90:73:0a:3c:42: + e5:f9:0b:cd:53:2d:16:14:75:f8:47:2e:04:1a:47: + d8:a6:20:0f:ec:96:fe:14:30:87:30:84:04:74:42: + 45:b3:3b:c1:48:84:54:4e:69:9b:f5:cb:7a:da:75: + 1e:26:93:87:5e:a2:c6:8f:fd:0f:96:84:76:2d:18: + 86:f7:87:1e:95:47:10:45:b5:45:ea:38:b7:e0:22: + 28:c6:98:42:5f:ed:69:d6:73:a3:d4:72:de:74:f7: + 2a:d2:90:5d:66:86:a1:b5:a4:fb:c7:37:94:65:82: + 80:d7:88:84:be:d6:5f:fd:25:88:0b:ee:6b:bb:4b: + 94:c6:e1:39:95:74:93:44:44:8e:3f:7e:13:33:49: + 8e:e3:f4:a0:43:e7:2d:15:f7:02:e9:bf:a8:94:65: + 71:df:45:35:f7:cc:03:b6:e4:d6:32:d2:98:66:ba: + d6:da:76:35:e0:81:76:25:0a:94:3f:6c:a6:53:49: + 52:c5:38:44:4d:ea:b4:fd:50:ee:63:e1:1b:51:ef: + 62:64:0e:39:cb:10:73:9d:fd:b0:2e:15:5a:cb:90: + 1c:9f:e9:88:37:14:92:32:7b:7a:00:fd:35:b4:d3: + 8c:99:90:74:95:7d:bf:25:41:04:68:56:38:3e:f1: + f5:97:b5:f3:cc:b8:16:99:40:1f:9d:eb:51:88:46: + 2a:62:b9:a5:bd:ad:97:db:58:5a:d4:6c:ed:32:db: + b4:5a:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 63:34:08:C8:42:04:47:74:99:65:DD:4F:EA:C5:0F:05:D9:F8:CE:47 + X509v3 Authority Key Identifier: + keyid:53:B8:CC:09:C6:9F:42:EA:D5:E4:74:20:B4:65:ED:68:F8:9D:B5:05 + DirName:/CN=hx509 Test Root CA/C=SE + serial:8D:F8:0A:D8:C1:70:91:C4 + + X509v3 Basic Constraints: + CA:TRUE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 77:0b:fc:11:37:04:49:92:2b:97:e1:ee:b6:94:33:11:be:bb: + db:8b:6e:ce:42:11:39:b2:be:61:03:a2:ef:d4:06:1f:63:d2: + af:1f:c5:43:80:67:1d:10:a0:3d:93:d1:7f:bd:be:9e:21:48: + d0:a8:ea:8c:32:0a:f7:eb:b0:c7:0f:ac:a7:8b:c6:1a:18:10: + 51:88:fd:1a:53:4b:1b:7b:94:5e:59:02:92:72:6c:df:32:3a: + 9c:f5:87:c9:fd:a2:f8:d3:df:34:be:75:7e:51:15:eb:b0:df: + 87:1b:15:df:fc:97:1e:06:f9:6e:8b:79:45:3d:c4:76:d2:1d: + 8e:04:8f:72:d6:b0:7c:09:79:23:47:7a:9a:41:76:7e:c3:3d: + 2d:46:26:db:72:64:a8:1d:ca:94:fe:d8:69:e7:24:1f:dc:c8: + 7b:4f:2f:89:7b:a3:8c:33:7f:0f:54:16:f4:45:60:e1:df:68: + f5:5b:3a:ce:1c:63:e6:81:ca:a6:aa:e4:a2:c1:07:e3:ec:ef: + ef:ad:cc:ac:5a:e1:57:40:15:09:b3:0f:f1:58:b2:2a:45:eb: + 5e:16:03:9c:2c:c1:ce:22:48:67:06:5e:0a:fd:fd:d5:76:8e: + a8:db:2c:38:15:b4:c1:e4:0f:12:98:0a:43:19:e6:74:b9:8b: + e3:7a:92:2e:2a:30:1d:b7:85:39:d5:29:2f:54:16:7d:b0:f6: + f9:17:e2:95:07:ff:0f:e6:16:55:6d:97:c8:41:c6:5f:8f:a9: + 3c:3a:19:8d:66:29:13:f3:00:6d:31:f3:f1:14:a5:e8:c7:2c: + c0:18:4b:5e:15:88:eb:59:44:97:91:1c:78:d7:a0:4d:a1:bf: + bf:b0:67:4f:68:df:d3:d0:c4:6e:b8:1d:36:bd:a8:c8:b4:67: + 34:c0:b2:28:8a:e9:1a:30:14:b3:be:d5:a3:a0:57:4f:b7:ff: + a0:9e:c0:28:58:90:43:57:e7:7c:d0:81:90:41:54:85:56:4b: + cd:f4:a3:63:3b:1a:8f:82:0d:2c:9d:79:58:40:f4:f6:37:a0: + fc:77:db:82:ab:de:fa:0c:7f:c2:ce:35:80:4e:f7:d8:0d:8b: + cd:5b:8c:a9:82:ec:a3:a1:ca:b8:4e:29:fd:35:79:dc:4d:f3: + bf:ee:41:a0:88:63:b9:65:22:bb:0d:27:e8:91:d4:20:51:06: + f9:e7:9a:e9:7c:4c:4a:64:b5:4f:22:79:36:ad:79:e8:b8:6a: + 6f:f8:e8:39:48:7b:3f:87:14:9a:22:ec:7d:33:94:35:42:29: + 56:11:de:15:bd:4c:c2:5d:ff:9f:82:72:a2:00:b3:e9:68:38: + 5b:ab:dd:0d:90:73:cd:80 +-----BEGIN CERTIFICATE----- +MIIFXzCCA0egAwIBAgIBCjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUxMFoYDzI1 +MTgxMTIxMjIyNTEwWjAeMQswCQYDVQQGEwJTRTEPMA0GA1UEAwwGU3ViIENBMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxxg5ZyrEa8YaZCO7ukxHIjWR +t8nrV7mLj4NivgpWSczt3n75RNuP+fns26JK0/qxNsCT6SvQmmRlQ1JkDq88CiNX +2WZEDO+mc35NcZR2XdIunAIeREtnDWEF//HMKZSTq/e21zPQnrQCGnsDu5xSACFD +l/9Z87HrFmexWmYmmQQSKLtolzhmz9PM2kHYT+L5WUjaylW5KmNDaw3FWHWOblXS +d83fihSConLz6JOh5HLzwJOzC3KYrVOTU4b8sDt3HKr1ZHfOkgwHgmA56da839yt ++U9C0ttCdm4L9fpYBX882c/r0sCaJizokHMKPELl+QvNUy0WFHX4Ry4EGkfYpiAP +7Jb+FDCHMIQEdEJFszvBSIRUTmmb9ct62nUeJpOHXqLGj/0PloR2LRiG94celUcQ +RbVF6ji34CIoxphCX+1p1nOj1HLedPcq0pBdZoahtaT7xzeUZYKA14iEvtZf/SWI +C+5ru0uUxuE5lXSTRESOP34TM0mO4/SgQ+ctFfcC6b+olGVx30U198wDtuTWMtKY +ZrrW2nY14IF2JQqUP2ymU0lSxThETeq0/VDuY+EbUe9iZA45yxBznf2wLhVay5Ac +n+mINxSSMnt6AP01tNOMmZB0lX2/JUEEaFY4PvH1l7XzzLgWmUAfnetRiEYqYrml +va2X21ha1GztMtu0WvUCAwEAAaOBmTCBljAdBgNVHQ4EFgQUYzQIyEIER3SZZd1P +6sUPBdn4zkcwWgYDVR0jBFMwUYAUU7jMCcafQurV5HQgtGXtaPidtQWhLqQsMCox +GzAZBgNVBAMMEmh4NTA5IFRlc3QgUm9vdCBDQTELMAkGA1UEBhMCU0WCCQCN+ArY +wXCRxDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB5jANBgkqhkiG9w0BAQUFAAOC +AgEAdwv8ETcESZIrl+HutpQzEb6724tuzkIRObK+YQOi79QGH2PSrx/FQ4BnHRCg +PZPRf72+niFI0KjqjDIK9+uwxw+sp4vGGhgQUYj9GlNLG3uUXlkCknJs3zI6nPWH +yf2i+NPfNL51flEV67DfhxsV3/yXHgb5bot5RT3EdtIdjgSPctawfAl5I0d6mkF2 +fsM9LUYm23JkqB3KlP7YaeckH9zIe08viXujjDN/D1QW9EVg4d9o9Vs6zhxj5oHK +pqrkosEH4+zv763MrFrhV0AVCbMP8ViyKkXrXhYDnCzBziJIZwZeCv391XaOqNss +OBW0weQPEpgKQxnmdLmL43qSLiowHbeFOdUpL1QWfbD2+RfilQf/D+YWVW2XyEHG +X4+pPDoZjWYpE/MAbTHz8RSl6McswBhLXhWI61lEl5EceNegTaG/v7BnT2jf09DE +brgdNr2oyLRnNMCyKIrpGjAUs77Vo6BXT7f/oJ7AKFiQQ1fnfNCBkEFUhVZLzfSj +Yzsaj4INLJ15WED09jeg/Hfbgqve+gx/ws41gE732A2LzVuMqYLso6HKuE4p/TV5 +3E3zv+5BoIhjuWUiuw0n6JHUIFEG+eea6XxMSmS1TyJ5Nq156Lhqb/joOUh7P4cU +miLsfTOUNUIpVhHeFb1Mwl3/n4JyogCz6Wg4W6vdDZBzzYA= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/sub-ca.key b/third_party/heimdal/lib/hx509/data/sub-ca.key new file mode 100644 index 0000000..1475e42 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/sub-ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDHGDlnKsRrxhpk +I7u6TEciNZG3yetXuYuPg2K+ClZJzO3efvlE24/5+ezbokrT+rE2wJPpK9CaZGVD +UmQOrzwKI1fZZkQM76Zzfk1xlHZd0i6cAh5ES2cNYQX/8cwplJOr97bXM9CetAIa +ewO7nFIAIUOX/1nzsesWZ7FaZiaZBBIou2iXOGbP08zaQdhP4vlZSNrKVbkqY0Nr +DcVYdY5uVdJ3zd+KFIKicvPok6HkcvPAk7MLcpitU5NThvywO3ccqvVkd86SDAeC +YDnp1rzf3K35T0LS20J2bgv1+lgFfzzZz+vSwJomLOiQcwo8QuX5C81TLRYUdfhH +LgQaR9imIA/slv4UMIcwhAR0QkWzO8FIhFROaZv1y3radR4mk4deosaP/Q+WhHYt +GIb3hx6VRxBFtUXqOLfgIijGmEJf7WnWc6PUct509yrSkF1mhqG1pPvHN5RlgoDX +iIS+1l/9JYgL7mu7S5TG4TmVdJNERI4/fhMzSY7j9KBD5y0V9wLpv6iUZXHfRTX3 +zAO25NYy0phmutbadjXggXYlCpQ/bKZTSVLFOERN6rT9UO5j4RtR72JkDjnLEHOd +/bAuFVrLkByf6Yg3FJIye3oA/TW004yZkHSVfb8lQQRoVjg+8fWXtfPMuBaZQB+d +61GIRipiuaW9rZfbWFrUbO0y27Ra9QIDAQABAoICAHBMg6RjhSNdPGmbljoA6Gat +XKIULMDwkX3DmCClaAJ8qvdDG4rxZYaUqDtCkX57+xVtDoEJC8LqOgv9Hx8BTJZT +VSv0+RFq47JlXX1hRlqpQU0SDMxs05XCUkYJtyUE/z6SnPlJ6rR5yG3zUSmzhLU6 +DgxgJfbFNlsO5gSddcv9ddivzNDvKV60kunRFhgJaKgp5e8W5zi3gMGTpOq+dDZc +Bjk5UItsAjtrJ5TaIQjgpgjLxsQAQYoSiBknHMSy5f6vl3ax9Tx/uISbjk8Npr+G +lEL5qDGTJyvx6qE2Mgv3tvUMyHG53bkGv68qlG1lNp6BP7FYzwl/eSl9FSdVuycK +UsUMi+dpuQlXOVprKAKTxYw+E7n8TV7ewmudbOEFR/ao6qCJqNtSQJa5dFFhU9An +ld/rKIcY9gfobYtS0qRiGAt18Be7qt6qGpwAZogfe+VM/G3S00yVP21gGN2qju3M +6vF99CTVLeD+g8JUJT+olzShLpZAgw09hXMx1JJJksl+kv6FNG0EotxlXCdIQTsG +TtWvOFXck7E5FZHjj+5eXCyRNVKzWRJAU6POr3Qr0gLpcg0DBbzfLAvDEA8k3V2Y +DqQeyi7xrd7ALKZmrLWnLQQdXQ8rUN0f/8lsus3TOiXjly3/GIediaYb+uxdACmC +4d+twAWpdnWrAiWDaICBAoIBAQDm7vUgSu2rsbd+YvBhYrNhTmmyVr/5HWOGaDjX +YJWj2Vqh4sVeoVjRpVgC4Yyx/iE9f4MPsiBzWmudMuG/yytxIfWWXEBGXmAHYL8Z +d6acVWer0yZik/xYV8nUUVUzzB7EvB7XdFtGMYPTZNiqhyZ9CGMeIHcaXndqejeJ +ycbOr+IDgBKQ9fGdpAZjTprrB0WqOhnxy6EJoObg6bicgIPCBxzdVCDo6mmkkRrQ +lIYRMAtjIzbGdwT6OADUf9Lr2aPBuKBQeEKFbADyNNyenqvcSFKcGcug2DZ8sIYN +US28VHke87mOg6qrNh166e00Hlp0q42Q2hV/8XxRQDDwxoqFAoIBAQDctIx8lGcJ +kxftf5j7ss0iUYSkT77HF7V9q81X7iMSjHTEyIYD2UHt2PS0gUL1jnjOXjIDFFHU +HzfymvsEjV8Vr8nUvKVkSUXWFnYPQ4rFP2d+Zyv64AhDKRrIOiG9ozLhqDdu7wui +XXigEuuwG6+LObO09FwKOhDRNgpuQnDlgHPidyu4PHoz56SlzGpTXM1/nTIGkWMi +v2aZF2hAzQM3bEqeyRUTnX/DvOQbFLDYLDc/KWaPDvBTJCwa2tPSZRA5ArmEmloc +yxTdf+DaSBy7P2EExfXkKNgvO978GYHUBk3SdA/2BLy0kNU1BSrajtjrxSLqUD8j +aVYafGb5eNGxAoIBAQCBZOkCVBmBt406CtPnrTcXUalVnNfqDHaEjAc1Xs/Zw+LN +jFPMpxkuNrfuvVRpMxyK6dSUydj26XYc2bK2FW/c7ws9WalGBIFIAQRyj6FSPWRe +WWxLleGx2lajWYMlB71BvKqHTJIL7ZiQrRPd0OZW7okjC0vRAZdlmN9fnCiCDPjV +v0An6zabfpl5sUSKZkO5kt6QpekwjPBwm2SuhC/PWs7okMfz2cyhwhBFSMMqBEKN +JOD/KRcn4JNOfeS/8+2WkQ16qTeUrKSHEemAEyX2wqtO/gEjuaImEX67HX5D5Q0M +s8GHweyyDBtOkJ4xMsS6VJl4zUl4q+VdXVtOveBFAoIBAEbpl+37PLP92AVOJxhQ +Fcr+CDFHEhQkEQNE7SBgelJeYLJNf4nDB4TlXZKVqa7+TOB5sXX91GDkevRvSVHo +HnH4XlAFINr9E/w6kUpMOE0yFw2tFptv2hfCIEHPM8IbqqCIjO8OzV0ozTYZfjLC +Yn/IVW5ByUTb7UVbKLTOkjmbMSDFi32RqO3+co93A36vZbOoDUfA9OpYNx3fQHb5 +qBvppnwoPaZkx4Vbrqro1f1PD50yryot8Ze1GpqyTrbeE/1NW9A4S9XOhnC4wsU/ +wEOFlKWU+XGKkhNzGC1GAMngEKca9XnlgcA+fNKhS2iX1yjB2XsRt4eoM6sk520m +nbECggEBAM2u917mgRcyRrOF3orTy0p5aRkHmAi7rdlr/E2CC/I+Uk00cSEJKgfL +IzLOs5ZARc6kkBAilNhz8lWWADaonmE5qDZjAzYwIuNWlZgWGYO74RwpavNaK7UM +MhRWCzomZUyNHKJiubkM8CTaioVsqoZS/OiWGHtGtSTAAknCb1wc5fppNU0xUQ/5 +AZGlrpUdb86VGN/lNNsF16tZ0mWUazXMXDCZgT9869p41OQYgIGDPvf9y9mWyYR6 +VbQSyfvDh4Wiu4Sf7L6OP8VG+xvhD+sRZPB9i3TzvhFWrzkcP3sXRqPxpdSSWgyP +Ca7fU8eAAjotw7SSdeefJ+CduL/cNQE= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/sub-cert.crt b/third_party/heimdal/lib/hx509/data/sub-cert.crt new file mode 100644 index 0000000..b98c463 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/sub-cert.crt @@ -0,0 +1,116 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 11 (0xb) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SE, CN=Sub CA + Validity + Not Before: Mar 22 22:25:12 2019 GMT + Not After : Nov 21 22:25:12 2518 GMT + Subject: C=SE, CN=Test sub cert + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ef:45:00:67:2b:7e:d2:ea:7d:80:b1:ae:81:5e: + fb:dd:82:ca:de:db:98:37:70:e8:3c:a2:01:87:8b: + 88:2e:40:30:22:d4:65:1d:7e:cb:cb:d5:40:e0:51: + 06:f0:f3:d9:00:db:5d:6a:0f:d3:11:bc:a1:3c:69: + 25:65:a9:87:b5:8a:3e:6c:79:2a:e8:5b:1a:9e:b4: + a4:81:5b:c3:83:f6:fd:9a:a8:48:6a:c4:ce:7f:81: + 26:83:c9:e5:b5:c9:a2:18:ed:0c:ea:1a:26:59:49: + df:56:ea:c2:33:2f:65:c2:14:30:5d:78:4e:91:09: + 6d:f5:77:ee:e8:0e:fe:ca:14:92:af:73:c4:8e:91: + b1:62:1a:c1:46:3e:36:d2:33:6a:7f:05:4e:d5:7b: + fe:69:4f:6c:b1:be:89:e6:7e:8d:5b:de:10:6c:a6: + bc:4a:05:66:17:19:71:e3:2c:62:bf:8b:4b:3c:6d: + fb:2a:7b:95:d5:d4:02:f0:43:e0:ce:cc:7a:30:fb: + a9:93:d2:50:a0:17:67:c6:08:8d:3c:9c:83:69:1f: + b7:ab:cf:d0:77:b6:8e:cc:89:0d:82:cd:e1:fb:53: + 2c:1d:f6:6b:81:0d:8f:da:dc:6a:34:93:06:23:32: + fb:83:90:40:8a:7f:ad:cf:2c:81:6a:10:cb:59:29: + d4:f2:af:b2:ee:f0:7b:b2:d5:0f:9d:5c:e6:d3:eb: + 18:9b:89:01:11:5f:e7:f4:50:34:e6:2c:31:b1:f3: + 60:af:03:a5:40:00:47:88:76:cd:52:da:1b:11:03: + 57:f5:3d:a1:01:f6:2f:9e:f5:01:37:22:a0:7d:5f: + 40:87:2d:69:72:70:80:05:16:24:2d:a6:b1:5e:ca: + 40:ad:f2:da:7f:c9:8f:7a:32:b2:8c:be:9b:de:66: + 17:92:81:83:8d:1a:f5:c9:8b:9a:3b:4a:84:b2:24: + 63:97:60:f6:3a:c0:84:88:2a:dd:6b:f8:e7:44:29: + 79:cf:98:d9:ab:36:93:10:a8:7a:7b:90:bc:bb:e0: + 43:c1:93:13:80:9d:cb:a6:68:67:94:67:6b:3a:58: + bd:02:39:20:88:e1:64:8e:a1:7a:6b:99:3b:9b:00: + 65:11:b5:fd:b7:18:55:fe:67:f4:94:ab:c2:08:a7: + 3a:d8:a7:b4:6e:d9:e9:89:1e:b0:81:1e:23:31:a9: + 17:b7:c7:f9:df:5b:90:2c:46:96:c5:d5:a6:cc:8b: + e4:db:fd:4b:47:8d:8f:bb:e4:41:d0:99:fe:81:83: + 88:a7:f0:a5:81:ae:c9:62:f6:4f:d8:12:60:33:20: + 6f:d1:39:37:f5:1f:05:40:62:43:9b:97:a5:7b:16: + cc:93:e5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 48:26:75:6B:4D:E0:98:93:39:02:40:D3:F1:1C:6D:D0:D8:45:A6:04 + Signature Algorithm: sha1WithRSAEncryption + aa:a0:db:44:96:6c:b5:c7:96:93:a3:11:e5:dc:1f:69:08:87: + f5:5f:50:25:99:03:6c:d2:89:55:4c:04:d4:8a:49:73:e8:e1: + 82:4f:f6:45:24:1c:ef:46:09:b2:19:09:16:5f:11:05:13:e7: + 3f:ca:5b:af:4f:6f:39:df:a8:71:1c:cb:62:2b:8d:42:b9:a7: + 58:76:72:db:88:8d:3a:e0:33:5c:ef:41:c7:30:d6:d0:9a:9c: + 70:f1:72:74:e6:0d:6c:1c:11:ff:f3:4a:ee:3d:d2:f7:3a:56: + 9f:41:63:83:60:4c:6b:63:d5:9a:a1:c8:22:b2:a5:8c:03:99: + 2f:04:65:a8:52:1b:1c:cb:4b:e4:b1:a0:86:7c:d7:85:e9:9a: + 8b:8f:f1:2d:e9:45:d0:f4:ee:51:cf:13:da:ff:ea:e8:cc:30: + cc:ed:f3:7e:f9:4d:59:a3:d2:ca:f2:4f:5b:73:65:63:de:39: + 0e:87:e1:16:30:65:d0:fa:da:0d:57:df:82:de:09:2c:24:7a: + ef:9c:d8:fa:7c:5a:25:f1:1e:e3:e1:56:c5:79:c3:13:37:38: + 03:dd:b4:6f:c0:61:b7:cb:41:bb:77:0c:c3:4f:14:e0:8c:e9: + 89:4b:55:6b:dc:ce:11:9b:f0:68:32:e2:64:c8:75:6a:80:26: + 88:fc:c1:ad:56:07:57:07:2d:fc:10:c8:42:94:f6:f4:7a:e2: + 94:ee:05:aa:28:7a:f3:d6:62:4a:fb:99:c0:df:dd:ca:77:14: + 70:6e:63:d1:68:25:6b:de:51:8b:8c:0c:5e:68:79:25:a5:68: + 74:c1:43:23:75:4f:eb:30:c6:84:79:a9:df:25:a6:66:56:cd: + 9c:95:40:b0:12:c0:60:9d:b3:99:02:4d:d1:de:25:2d:00:49: + e4:8f:81:8f:14:5d:3e:1c:c4:ac:11:ac:ef:0d:a7:ca:0c:01: + 88:54:26:bb:38:c7:24:b8:4b:45:97:40:9b:21:ea:7b:e0:5b: + 5f:d4:3d:dc:01:0a:8e:3d:db:31:8b:e8:23:8b:5c:48:34:95: + de:71:cc:61:43:aa:59:0e:be:0a:7f:75:8d:fb:b9:f0:fd:28: + e9:76:8d:5f:ea:9c:59:07:28:a5:b4:df:8f:0b:3c:c7:ad:00: + fe:9e:28:86:cd:52:fe:e3:78:81:ed:5e:73:40:1c:06:02:a8: + b1:84:b3:ec:56:ce:a3:70:22:ce:ab:0f:4b:8d:36:09:2d:6d: + 5e:93:2d:c4:20:c4:bd:8e:78:68:0a:84:81:b9:85:b7:cb:03: + c0:26:b9:c3:d8:e7:ab:c6:a6:7c:55:a4:e6:96:b3:65:84:5b: + 7e:bd:1e:c9:94:f6:25:c7 +-----BEGIN CERTIFICATE----- +MIIE+TCCAuGgAwIBAgIBCzANBgkqhkiG9w0BAQUFADAeMQswCQYDVQQGEwJTRTEP +MA0GA1UEAwwGU3ViIENBMCAXDTE5MDMyMjIyMjUxMloYDzI1MTgxMTIxMjIyNTEy +WjAlMQswCQYDVQQGEwJTRTEWMBQGA1UEAwwNVGVzdCBzdWIgY2VydDCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO9FAGcrftLqfYCxroFe+92Cyt7bmDdw +6DyiAYeLiC5AMCLUZR1+y8vVQOBRBvDz2QDbXWoP0xG8oTxpJWWph7WKPmx5Kuhb +Gp60pIFbw4P2/ZqoSGrEzn+BJoPJ5bXJohjtDOoaJllJ31bqwjMvZcIUMF14TpEJ +bfV37ugO/soUkq9zxI6RsWIawUY+NtIzan8FTtV7/mlPbLG+ieZ+jVveEGymvEoF +ZhcZceMsYr+LSzxt+yp7ldXUAvBD4M7MejD7qZPSUKAXZ8YIjTycg2kft6vP0He2 +jsyJDYLN4ftTLB32a4ENj9rcajSTBiMy+4OQQIp/rc8sgWoQy1kp1PKvsu7we7LV +D51c5tPrGJuJARFf5/RQNOYsMbHzYK8DpUAAR4h2zVLaGxEDV/U9oQH2L571ATci +oH1fQIctaXJwgAUWJC2msV7KQK3y2n/Jj3oysoy+m95mF5KBg40a9cmLmjtKhLIk +Y5dg9jrAhIgq3Wv450Qpec+Y2as2kxCoenuQvLvgQ8GTE4Cdy6ZoZ5RnazpYvQI5 +IIjhZI6hemuZO5sAZRG1/bcYVf5n9JSrwginOtintG7Z6YkesIEeIzGpF7fH+d9b +kCxGlsXVpsyL5Nv9S0eNj7vkQdCZ/oGDiKfwpYGuyWL2T9gSYDMgb9E5N/UfBUBi +Q5uXpXsWzJPlAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMB0GA1Ud +DgQWBBRIJnVrTeCYkzkCQNPxHG3Q2EWmBDANBgkqhkiG9w0BAQUFAAOCAgEAqqDb +RJZstceWk6MR5dwfaQiH9V9QJZkDbNKJVUwE1IpJc+jhgk/2RSQc70YJshkJFl8R +BRPnP8pbr09vOd+ocRzLYiuNQrmnWHZy24iNOuAzXO9BxzDW0JqccPFydOYNbBwR +//NK7j3S9zpWn0Fjg2BMa2PVmqHIIrKljAOZLwRlqFIbHMtL5LGghnzXhemai4/x +LelF0PTuUc8T2v/q6MwwzO3zfvlNWaPSyvJPW3NlY945DofhFjBl0PraDVffgt4J +LCR675zY+nxaJfEe4+FWxXnDEzc4A920b8Bht8tBu3cMw08U4IzpiUtVa9zOEZvw +aDLiZMh1aoAmiPzBrVYHVwct/BDIQpT29HrilO4Fqih689ZiSvuZwN/dyncUcG5j +0Wgla95Ri4wMXmh5JaVodMFDI3VP6zDGhHmp3yWmZlbNnJVAsBLAYJ2zmQJN0d4l +LQBJ5I+BjxRdPhzErBGs7w2nygwBiFQmuzjHJLhLRZdAmyHqe+BbX9Q93AEKjj3b +MYvoI4tcSDSV3nHMYUOqWQ6+Cn91jfu58P0o6XaNX+qcWQcopbTfjws8x60A/p4o +hs1S/uN4ge1ec0AcBgKosYSz7FbOo3AizqsPS402CS1tXpMtxCDEvY54aAqEgbmF +t8sDwCa5w9jnq8amfFWk5pazZYRbfr0eyZT2Jcc= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/sub-cert.key b/third_party/heimdal/lib/hx509/data/sub-cert.key new file mode 100644 index 0000000..481dabb --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/sub-cert.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDvRQBnK37S6n2A +sa6BXvvdgsre25g3cOg8ogGHi4guQDAi1GUdfsvL1UDgUQbw89kA211qD9MRvKE8 +aSVlqYe1ij5seSroWxqetKSBW8OD9v2aqEhqxM5/gSaDyeW1yaIY7QzqGiZZSd9W +6sIzL2XCFDBdeE6RCW31d+7oDv7KFJKvc8SOkbFiGsFGPjbSM2p/BU7Ve/5pT2yx +vonmfo1b3hBsprxKBWYXGXHjLGK/i0s8bfsqe5XV1ALwQ+DOzHow+6mT0lCgF2fG +CI08nINpH7erz9B3to7MiQ2CzeH7Uywd9muBDY/a3Go0kwYjMvuDkECKf63PLIFq +EMtZKdTyr7Lu8Huy1Q+dXObT6xibiQERX+f0UDTmLDGx82CvA6VAAEeIds1S2hsR +A1f1PaEB9i+e9QE3IqB9X0CHLWlycIAFFiQtprFeykCt8tp/yY96MrKMvpveZheS +gYONGvXJi5o7SoSyJGOXYPY6wISIKt1r+OdEKXnPmNmrNpMQqHp7kLy74EPBkxOA +ncumaGeUZ2s6WL0COSCI4WSOoXprmTubAGURtf23GFX+Z/SUq8IIpzrYp7Ru2emJ +HrCBHiMxqRe3x/nfW5AsRpbF1abMi+Tb/UtHjY+75EHQmf6Bg4in8KWBrsli9k/Y +EmAzIG/ROTf1HwVAYkObl6V7FsyT5QIDAQABAoICAQC9cwIdrlfNwrM6mfVVJBMC +0hO1n2QHydNoZtIVM8rQ7Cvw+AFT+Fh+/UxQEHgRgtI4lniBiSQTcCquPYbJ1xDI +EjzZAJuTvMb4EIoMjs7hB0jIEyS7vTbPyD/pq4vBg3Rgjhlipu/kVNSM6nZ3tri4 +kem1qJN0zWWOLbcxcOYWtXFrkJt6UyuDRTHxX0Ni7ikNh/Nin7nSQnwKxJZFtcBR +lCOnE+IULfAmrBP7zuIlTbJ1l5N+kLoTw7nL6cLvmwHJFQqxK56BE+cr6wuBiV+X +dfClDne+wgKROpdDEaczqyhMVRfL6CQWI93H4P3EExMImcgwoWXKmy+g/skzwSaE +tbFeN2cxFd3Ow3f8BWqrWEzXdwp4+26SzVXMNpjbyQoaYtxp0OhyTKI65FmaQjVS +9We5D0asPl7Fbc+xobXQ+1InkrQevZDPcU3ejqsrm9qtGzctpv8wWaU3ByvodkQg +ZxAzXuE8bwwJ/m/jbirXxnKfNo+22nH0ksCYH6UmQEgHdkFO22QpaiDZFvudC3mZ +JMbP/bjXHvzukltMPXXiGcNEeP/PPVtD2EewOZV2vNVYXP/wXu9Gt2djclV1jj9j +X3ABa7WE65ZhREqBT5RpSPizTvlyEYIUwvawnPCrwfEeVbMq/t3em1hquk2d9RTs +UyVjuEaqKDyZdGMumiPEhQKCAQEA/09qzOJWJv5XsPUlbvmzL9Zbsv0vMlchFiNB +zESdSmYbeNBdj9CsJjEIZldqxERAErcsHdtHUuyWNKe4phi1s5bSR3cgcjhdv4LI +bRghUsqf7p86sINxqz5yA4jx+JmLMUbghBCSlbCKruEli0FSxUtpeYzxftEb+jZA +PamBTNDsbaXmNhm6f95I39zxn9Gx++p+7H4/hHpXBAk7PCa1ePAzKWKiDobJbelo +CuFxQSzPFOmhze0wVq98QIvnNnxB/x3wX8ybk4vrJSbX6NQlSWhYsrUt3HnsTDZs +zF++euPTL04kMoaitYvZW9Mg3ZPBxazn2Cu0cswkXn4gHZ6gIwKCAQEA7+p9cMuR +KAv4dllBm3WWxPsX7hP1f8l2d7hmyYW4r5AaWMWNI84HhArpi3EPLxd/DUwvBU57 +YejR4DXQxrZoGr5uYkzXwgPAYQujV80GGK/wpj09jQh1Xn3lE7kpPEweK9SBIJB+ +anD+8FzGo17Bz23/Wp5zjVDi/yovRZdTSqQCowiZ5df4ls42Oms5u9lipwUTv4Rk +QFQsh7zn5JQ30U3Ef36FMpRcM4GlR+gw/JjM9zB5aboxLJmws/e3rfS/eGNXCPKE ++xiDAhdmsx44HOONBEgJ5myxJ44uifY83xIQwaE+nyuXWBIqJLKiEmEm8GJ9bgdz +L1iD1UiNaTm4VwKCAQB49tzIRDjDcuCDdDMPOHmgobSCwpi5BjUj8wJ60Muhc21y +uW6K9DiMQ9ESBDsO0LN26piZcMqDTJsCSbEf6Tc15rCssZGK7I/mbAWgQr2PJ3fN +LF43QZ/6nbSRXjIfMkiTyVwY1m1NRP8ASqZqK0IXPlqz/4ZwKo1R6KBZVtVvWtGa +Re8kFN6bNOtcPaexrD3i+MC4NjzL/Nb7j5AkOMbkjRIAer4DmfMYA22LMjNhyOQ4 +qVVDZyzu9WgugNrEouz1/e5kxWG076cyzAuiQdmExU65JUScYJwHpAW6c2ahfQ4T +LLfTxJyU3bTXX9oDgb1edkTG1DZD6dsVdjarMfv3AoIBAC3J9z772yxlfHo59seQ +3cGimqKZtJU7Ah0/WH7FwsXfHugqbBGVVOHio0g1v8whE+KZ06+TlwDMyqGcI8iJ +L71K8w5X1CX3SVQ8QGSVgMBdc/SGY6TzJFNwe7QT9sbHUErVN//bFAWEo2OEkXTE +tQC94aqN60fhVDGW/4aspvzr6ITtM1Imsg82NCtaI56ykp2F3osC3Y9ZgVY2u5to +nm6YBRTANPO+VQqPh9f9fLv4/cV/vuxq2M/GVW9DrA7LU2/KpeXTQ4YY24gepz8w +WU1KMLPMe/c6b2U5QbCbCmsYq5IJEEaYrz3j2Z8/aKdRW3ktkvrY+SbkIeUm/7ZB +iekCggEBANkmkU/Mxj0C6Exv9YbrFehPxfgPcuyfAt7qdEzazjVmPWbhgpriPW55 +z/FEx/clfhaR8EWTNESKkLhX/qfGXHytlxUn8VWzcM6GIhvBTF6gUTX5hp1+peh+ +hztIBCQVPLpAXhf4Sf9+WwtBGrgo7RkIbzq/S1DynaymuVjBemSUvjKOKrVJm7gr +DTIbmVjw5RXe5/HhPp7w8XlR4nDOYRuSd7ycG2l2xmK4VMK5QqaPEIrKDtsX0dsK ++VsrO5897j4ZZOdBif0YSRL5/zbZEA/HIA3kJ45jZDKMNPNfQBIK8yzW9KhLlBgL +G2q8/Es7kVEQkUPyRNnHTWdnKW+vIQ0= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/sub-cert.p12 b/third_party/heimdal/lib/hx509/data/sub-cert.p12 new file mode 100644 index 0000000..18898c8 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/sub-cert.p12 differ diff --git a/third_party/heimdal/lib/hx509/data/tcg-devid.pem b/third_party/heimdal/lib/hx509/data/tcg-devid.pem new file mode 100644 index 0000000..66b769c --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/tcg-devid.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlFeGFt +cGxlQ0EwHhcNMTQwMTE1MTU0MDUwWhcNMTUwMTE1MTU0MDUwWjAAMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAncvm0aOBK05rdNInYXzJGV5SFteVUFpt +XFxg4evROvlulB3BzUmFGQYFDcItVnJX2fAvf0UJLtLBVBQggb5ylL6bRpj72cS3 +oyNbs0CGmix9Z1QDjkZZFvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGFijWLdRD5eulP +55pq1bAHAvIo4+VLMJVBG71xrKGZeHPjKoq6seYjh7AGy+hk2vmFzpZ8Ghdgqv+K +02IZ7FEdzuylHW8U3qsxBHysMut4inj6AiVf467OOs5meHiifIK9MGkovMrfY9iX +uUVUs/KXpE1sgeoX9BLvx1BPcODosr5K+z5i71OtIXy4CXrPvcGzRwIDAQABo4IB +hzCCAYMwQAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vd3d3LmV4 +YW1wbGUuY29tL0V4YW1wbGVDQS5jcnQwDgYDVR0PAQH/BAQDAgAgMIGBBgNVHREB +Af8EdzB1pEswSTEWMBQGBWeBBQIBDAtpZDo1NDQzNDcwMDEXMBUGBWeBBQICDAxB +QkNERUYxMjM0NTYxFjAUBgVngQUCAwwLaWQ6MDAwMTAwMjOgJgYIKwYBBQUHCASg +GjAYBgVngQUBAgQPdHBtc2VyaWFsbnVtYmVyMAwGA1UdEwEB/wQCMAAwNQYDVR0f +BC4wLDAqoCigJoYkaHR0cDovL3d3dy5leGFtcGxlLmNvbS9FeGFtcGxlQ0EuY3Js +MBAGA1UdIAQJMAcwBQYDKgMEMB8GA1UdIwQYMBaAFDR3ZyRMRK/nnirgskxpV5Uk +sz3aMBAGA1UdJQQJMAcGBWeBBQgBMCEGA1UdCQQaMBgwFgYFZ4EFAhAxDTALDAMy +LjACAQACAWMwDQYJKoZIhvcNAQELBQADggEBABtrZu0n/7jPTYxak2n30AUakS7f +Ihomojo14e8Lp/HF7/2VaUcohJH4KekCHTf8wpPxM/b9xRKLSOORA2Ey255Q2h8T +v19he0dcdTvDPNQVY3AKaFO4cNiXeOYPR8n3IDYK5QdPqrdRX4/Bc34QcTWFDALx +C00L/kDvBjV7l0Et2DBJIiBNziVKxs1xn136buZYRam6ZJhTRzNMMQ0eZ279Um4M +39EI4DIFv6FzX0sC5waacVg6HFYd933NtdkDWV0VTGuk+5V8rH4Sjx+sywHahkoz +BJhQBai2qiWEt7bB0ExGN2ZXPjiQiG4UHvLgGlCOUHX7EDNf0dvfUIZ6hLY= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/tcg-ek-cp.pem b/third_party/heimdal/lib/hx509/data/tcg-ek-cp.pem new file mode 100644 index 0000000..f6631b2 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/tcg-ek-cp.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlFeGFt +cGxlQ0EwHhcNMTQwMTE1MTU0MDUwWhcNMTUwMTE1MTU0MDUwWjAAMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAncvm0aOBK05rdNInYXzJGV5SFteVUFpt +XFxg4evROvlulB3BzUmFGQYFDcItVnJX2fAvf0UJLtLBVBQggb5ylL6bRpj72cS3 +oyNbs0CGmix9Z1QDjkZZFvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGFijWLdRD5eulP +55pq1bAHAvIo4+VLMJVBG71xrKGZeHPjKoq6seYjh7AGy+hk2vmFzpZ8Ghdgqv+K +02IZ7FEdzuylHW8U3qsxBHysMut4inj6AiVf467OOs5meHiifIK9MGkovMrfY9iX +uUVUs/KXpE1sgeoX9BLvx1BPcODosr5K+z5i71OtIXy4CXrPvcGzRwIDAQABo4IB +XjCCAVowQAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vd3d3LmV4 +YW1wbGUuY29tL0V4YW1wbGVDQS5jcnQwDgYDVR0PAQH/BAQDAgAgMFkGA1UdEQEB +/wRPME2kSzBJMRYwFAYFZ4EFAgEMC2lkOjU0NDM0NzAwMRcwFQYFZ4EFAgIMDEFC +Q0RFRjEyMzQ1NjEWMBQGBWeBBQIDDAtpZDowMDAxMDAyMzAMBgNVHRMBAf8EAjAA +MDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly93d3cuZXhhbXBsZS5jb20vRXhhbXBs +ZUNBLmNybDAQBgNVHSAECTAHMAUGAyoDBDAfBgNVHSMEGDAWgBQ0d2ckTESv554q +4LJMaVeVJLM92jAQBgNVHSUECTAHBgVngQUIATAhBgNVHQkEGjAYMBYGBWeBBQIQ +MQ0wCwwDMi4wAgEAAgFjMA0GCSqGSIb3DQEBCwUAA4IBAQAba2btJ/+4z02MWpNp +99AFGpEu3yIaJqI6NeHvC6fxxe/9lWlHKISR+CnpAh03/MKT8TP2/cUSi0jjkQNh +MtueUNofE79fYXtHXHU7wzzUFWNwCmhTuHDYl3jmD0fJ9yA2CuUHT6q3UV+PwXN+ +EHE1hQwC8QtNC/5A7wY1e5dBLdgwSSIgTc4lSsbNcZ9d+m7mWEWpumSYU0czTDEN +Hmdu/VJuDN/RCOAyBb+hc19LAucGmnFYOhxWHfd9zbXZA1ldFUxrpPuVfKx+Eo8f +rMsB2oZKMwSYUAWotqolhLe2wdBMRjdmVz44kIhuFB7y4BpQjlB1+xAzX9Hb31CG +eoS2 +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/test-ds-only.crt b/third_party/heimdal/lib/hx509/data/test-ds-only.crt new file mode 100644 index 0000000..ce0de74 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test-ds-only.crt @@ -0,0 +1,117 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:05 2019 GMT + Not After : Nov 21 22:25:05 2518 GMT + Subject: C=SE, CN=Test cert DigitalSignature + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d2:e5:b6:27:f7:6c:c1:d0:ba:8a:4a:6a:4e:b5: + a6:92:2e:5b:98:d7:0c:6a:7e:f4:bf:19:30:2d:ee: + 1c:5a:ee:28:f6:5c:a8:12:03:20:c7:e8:2b:b1:44: + 9f:b7:54:27:6e:17:fc:c0:f6:f7:ea:38:d2:c8:77: + ab:6a:ae:d1:ab:9f:1e:79:df:8a:51:55:aa:6c:6a: + 13:74:74:2f:c0:20:57:ef:f3:e1:71:da:b0:ec:62: + e9:8a:01:da:f6:e6:c6:5a:fe:11:61:58:5c:a0:01: + ec:0e:af:70:0d:72:94:a1:d4:1c:76:53:ae:39:a0: + cf:70:d8:d9:7c:95:18:2b:5f:36:00:2f:5c:be:a2: + d5:8e:0e:e3:aa:76:0c:1f:86:b3:69:fe:e4:29:0a: + 30:b1:ca:83:1a:f2:88:fc:91:2f:58:be:a4:a0:25: + 82:bf:16:b3:ca:70:09:7e:cf:29:f9:2e:58:0b:4a: + 3a:3c:6d:e7:05:63:d5:53:90:ed:ee:96:9e:8e:d7: + a8:ef:50:8b:37:bd:dc:88:f5:12:bc:04:4e:e4:f3: + ec:5d:9d:e6:46:14:e1:e1:6b:15:ab:f4:52:f6:12: + 76:ae:2d:a7:65:ec:8f:bd:90:51:52:4d:e7:cf:ba: + 23:01:7a:85:8b:22:41:a6:98:08:e4:33:00:c1:e2: + 82:b0:b2:c6:f4:6a:34:c6:a9:d7:b1:cc:c6:1a:0b: + ad:69:1f:89:af:e0:63:cd:51:c9:36:7f:08:f0:31: + 97:ea:78:bb:ae:21:4c:aa:2d:32:de:36:03:cf:64: + f8:8a:c0:c5:b3:c4:f9:79:74:7a:8b:d5:ec:bf:19: + 87:c9:25:0c:99:7d:56:a3:93:68:97:c3:cc:08:fb: + 37:c0:2c:cb:87:f2:b4:4e:fe:ce:86:69:2b:8e:c3: + 9e:40:a9:b6:43:6e:d6:b6:3d:08:43:24:09:58:8d: + af:d2:5d:1c:0e:cd:bc:e3:0b:b3:4b:a5:69:a8:3c: + d7:07:d0:7f:d7:78:c7:5c:a4:9f:e1:a2:bc:76:77: + 80:25:0e:82:2b:43:1e:e4:67:49:47:d9:65:45:57: + ed:59:d7:6e:a1:8d:76:a0:c2:65:52:c8:c8:57:5d: + dd:b4:d2:4f:27:a5:08:f1:88:7e:d2:3e:5d:60:c6: + 67:fb:c9:19:e7:78:cc:41:6d:24:11:cd:a4:e6:cf: + 56:8c:41:4d:af:d6:e2:22:c0:a3:64:2c:4b:27:f6: + b3:87:9d:08:e6:2a:2f:db:c8:50:57:95:a3:cf:67: + 77:f8:80:15:f3:45:00:47:f8:80:6e:21:b5:80:f1: + 81:29:45:3f:a9:8a:e2:12:12:4d:c4:90:e3:da:ab: + 08:80:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation + X509v3 Subject Key Identifier: + C4:44:DE:34:6C:55:F0:21:00:F4:CF:F0:55:67:92:FB:8F:B3:40:46 + Signature Algorithm: sha1WithRSAEncryption + a3:9c:c7:b7:3d:fc:8e:3d:5b:58:98:b0:05:63:fd:a7:50:c2: + d4:e8:c2:48:b8:b0:a8:e3:f9:c2:8b:11:47:a1:11:5e:e8:4d: + 75:c5:b8:d9:ec:af:81:95:1e:ec:d8:f6:8a:b6:17:12:ab:d4: + 30:84:cb:35:6a:c8:50:5e:1c:55:26:77:ee:84:f0:80:92:95: + c3:37:50:b3:23:21:7a:3b:63:5a:18:e4:48:fc:de:9b:26:50: + 38:9e:2f:a3:ad:03:5f:0c:b0:a1:0e:41:0b:01:71:b9:a2:df: + 84:f6:c4:d6:9d:8b:f7:a8:ed:cc:7e:b6:8c:5c:bc:26:0c:97: + 77:15:dc:fb:66:4b:0d:01:d9:8e:58:8e:1c:bf:35:47:b8:10: + d4:12:e5:80:09:b3:d8:4a:f4:0a:3f:6a:2f:9f:47:16:80:a7: + 92:6a:d4:3b:79:7b:25:b9:3e:14:a9:90:4e:92:6e:92:7b:6f: + 04:3a:0d:c6:63:77:82:e2:2d:e9:24:63:ce:a0:b1:8c:23:1d: + db:79:b8:4f:77:b8:7f:d2:49:5d:b4:60:a0:78:bb:d6:d7:56: + ff:23:c1:fa:46:cd:9a:2b:0d:87:df:b5:98:eb:7e:fd:af:6e: + 9d:03:de:d3:97:e7:19:09:20:13:ce:2e:b5:89:f0:47:ad:b2: + 3d:f1:5e:77:8b:dd:d3:6e:e2:a8:3c:cd:6a:22:a1:63:92:8c: + 2e:ca:0a:0d:aa:2c:15:98:de:27:08:e5:ee:a5:e0:e5:54:30: + 26:2f:32:ab:c3:de:e0:82:32:2a:dd:39:cb:3c:75:95:8f:9e: + 37:34:34:80:14:27:aa:c6:89:d3:8f:7a:35:19:3b:8b:c1:56: + 06:76:b3:0c:12:05:10:f4:5a:62:ff:d5:ef:e0:f8:da:aa:dc: + 2b:14:73:ad:31:c8:da:19:fe:54:51:32:0f:3b:7f:13:21:0d: + 5c:4f:33:e7:07:92:36:fd:01:04:d4:e6:4c:ba:dc:b4:75:c0: + f6:1f:3c:5a:4a:34:40:87:3b:8c:44:60:de:11:8d:18:41:0a: + e4:e9:d6:19:f5:7b:8f:53:3c:d8:3d:7c:4f:f4:b0:86:93:69: + c1:f1:e0:cd:8f:df:cd:ef:33:31:a8:e1:93:cf:bd:13:13:66: + 55:ef:44:63:06:0a:11:7a:78:e7:5c:6f:d0:f9:9d:bf:90:e5: + f4:d1:54:31:b8:0d:ed:ed:c0:e2:63:5c:13:01:ff:a8:11:c5: + 7d:42:e1:94:63:6a:63:99:0f:82:ef:49:f7:93:92:e6:72:d7: + ed:88:d6:ab:b2:25:8c:37:8d:08:22:a0:80:9b:14:fb:a4:a2: + 4f:43:be:ff:d4:e9:7e:79 +-----BEGIN CERTIFICATE----- +MIIFEjCCAvqgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwNVoYDzI1 +MTgxMTIxMjIyNTA1WjAyMQswCQYDVQQGEwJTRTEjMCEGA1UEAwwaVGVzdCBjZXJ0 +IERpZ2l0YWxTaWduYXR1cmUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDS5bYn92zB0LqKSmpOtaaSLluY1wxqfvS/GTAt7hxa7ij2XKgSAyDH6CuxRJ+3 +VCduF/zA9vfqONLId6tqrtGrnx5534pRVapsahN0dC/AIFfv8+Fx2rDsYumKAdr2 +5sZa/hFhWFygAewOr3ANcpSh1Bx2U645oM9w2Nl8lRgrXzYAL1y+otWODuOqdgwf +hrNp/uQpCjCxyoMa8oj8kS9YvqSgJYK/FrPKcAl+zyn5LlgLSjo8becFY9VTkO3u +lp6O16jvUIs3vdyI9RK8BE7k8+xdneZGFOHhaxWr9FL2EnauLadl7I+9kFFSTefP +uiMBeoWLIkGmmAjkMwDB4oKwssb0ajTGqdexzMYaC61pH4mv4GPNUck2fwjwMZfq +eLuuIUyqLTLeNgPPZPiKwMWzxPl5dHqL1ey/GYfJJQyZfVajk2iXw8wI+zfALMuH +8rRO/s6GaSuOw55AqbZDbta2PQhDJAlYja/SXRwOzbzjC7NLpWmoPNcH0H/XeMdc +pJ/horx2d4AlDoIrQx7kZ0lH2WVFV+1Z126hjXagwmVSyMhXXd200k8npQjxiH7S +Pl1gxmf7yRnneMxBbSQRzaTmz1aMQU2v1uIiwKNkLEsn9rOHnQjmKi/byFBXlaPP +Z3f4gBXzRQBH+IBuIbWA8YEpRT+piuISEk3EkOPaqwiAvQIDAQABozkwNzAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUxETeNGxV8CEA9M/wVWeS+4+z +QEYwDQYJKoZIhvcNAQEFBQADggIBAKOcx7c9/I49W1iYsAVj/adQwtTowki4sKjj ++cKLEUehEV7oTXXFuNnsr4GVHuzY9oq2FxKr1DCEyzVqyFBeHFUmd+6E8ICSlcM3 +ULMjIXo7Y1oY5Ej83psmUDieL6OtA18MsKEOQQsBcbmi34T2xNadi/eo7cx+toxc +vCYMl3cV3PtmSw0B2Y5Yjhy/NUe4ENQS5YAJs9hK9Ao/ai+fRxaAp5Jq1Dt5eyW5 +PhSpkE6SbpJ7bwQ6DcZjd4LiLekkY86gsYwjHdt5uE93uH/SSV20YKB4u9bXVv8j +wfpGzZorDYfftZjrfv2vbp0D3tOX5xkJIBPOLrWJ8Eetsj3xXneL3dNu4qg8zWoi +oWOSjC7KCg2qLBWY3icI5e6l4OVUMCYvMqvD3uCCMirdOcs8dZWPnjc0NIAUJ6rG +idOPejUZO4vBVgZ2swwSBRD0WmL/1e/g+Nqq3CsUc60xyNoZ/lRRMg87fxMhDVxP +M+cHkjb9AQTU5ky63LR1wPYfPFpKNECHO4xEYN4RjRhBCuTp1hn1e49TPNg9fE/0 +sIaTacHx4M2P383vMzGo4ZPPvRMTZlXvRGMGChF6eOdcb9D5nb+Q5fTRVDG4De3t +wOJjXBMB/6gRxX1C4ZRjamOZD4LvSfeTkuZy1+2I1quyJYw3jQgioICbFPukok9D +vv/U6X55 +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/test-ds-only.key b/third_party/heimdal/lib/hx509/data/test-ds-only.key new file mode 100644 index 0000000..9129038 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test-ds-only.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDS5bYn92zB0LqK +SmpOtaaSLluY1wxqfvS/GTAt7hxa7ij2XKgSAyDH6CuxRJ+3VCduF/zA9vfqONLI +d6tqrtGrnx5534pRVapsahN0dC/AIFfv8+Fx2rDsYumKAdr25sZa/hFhWFygAewO +r3ANcpSh1Bx2U645oM9w2Nl8lRgrXzYAL1y+otWODuOqdgwfhrNp/uQpCjCxyoMa +8oj8kS9YvqSgJYK/FrPKcAl+zyn5LlgLSjo8becFY9VTkO3ulp6O16jvUIs3vdyI +9RK8BE7k8+xdneZGFOHhaxWr9FL2EnauLadl7I+9kFFSTefPuiMBeoWLIkGmmAjk +MwDB4oKwssb0ajTGqdexzMYaC61pH4mv4GPNUck2fwjwMZfqeLuuIUyqLTLeNgPP +ZPiKwMWzxPl5dHqL1ey/GYfJJQyZfVajk2iXw8wI+zfALMuH8rRO/s6GaSuOw55A +qbZDbta2PQhDJAlYja/SXRwOzbzjC7NLpWmoPNcH0H/XeMdcpJ/horx2d4AlDoIr +Qx7kZ0lH2WVFV+1Z126hjXagwmVSyMhXXd200k8npQjxiH7SPl1gxmf7yRnneMxB +bSQRzaTmz1aMQU2v1uIiwKNkLEsn9rOHnQjmKi/byFBXlaPPZ3f4gBXzRQBH+IBu +IbWA8YEpRT+piuISEk3EkOPaqwiAvQIDAQABAoICAQDFT5tL6yY6ctGDvrmVKEhO +bcbOySvZmyvaenNkFWk7/aQfUnMAXyLVRTdTo3OWbspxK0oTMzyhS0aRvbyHlEWg +Pr+hoG3lSLOouNm401c1dk0vt0mOXt+2WZhLwQ6efyzHRvr1y1jlbsbuul6ohjHe +8fcrEYFoczaBSrC36TnyoiKAq88moGwSe4WvHsCa4kiLe6j1aI5EWMaueImHW0Ij +0kFtf4rCwze0x3tqw+FuO1iuP2Ua0mwY091rUKX62bpAxC5OsFl/7kcdb8R2WcWC +WWAj+i3OFY17e9eLyIuxo3ab4STDrD6TSSl8Slz+MRS9Nmco1AT+GzH+ZmVoAEbp +3LeAwXK0oGdbQqi+eSiM3mPH9KTgLs2rfqh/6oKLE/eNsU7CmLWXuMME9ORfSB+i +dLqp3s1HWXJOS8hkJAhoJgHLEQn8XWsOtRFUw4kSgaWu23fultTv5trM3ZyaGR0o +xDpeptKDnV85oul0nT8+Qpbj/w4MQU/INC/sxN29Qkiy3lvHE/y/C7a4GxB8DY6K +kFUdcwT5dWw6SHqqPFxeDf3sz8Uo7RQSiXZkpHHg1U/Md456G7lgQTB5YtpZPVeY +vJt2nlyeeP/61D0K7Im/DmS0Owenz4LyvBIiTA2gZXEbvxBd1Aq9iL/LT+GIDJJN +dC7nbMKaHRXhcG0rysOWIQKCAQEA9+b2neaBBCEoZkH4iQteocBxgXZw60BugMIL +v5KKh58VKC6P720d2TcL3gRfwo+9tuYcXIjn2r/mjM7N1ppDNM9/VNaelQlttK1b +sd3C7RKjhWozWhPSfh8gHl2BKeBT+2wS26pSZX43oIyyj+sa6f7JnVbn7sGqcSFD +js5hw3jIX3z8SR06zqUHOGes9OFn1GABvxAU70PpsCfAnMLvM9TvBopG/4RtGjBA +HyhQYN2wdPnym32P+Ectf0z+SpVqtmTA2uy0VdbacHzhvObI+zN0/PWJhPsj4QMa +8ycDpccwBvpD2XbkC6mEEbTJBfgbmjn+0J60hNh4+kg73Sh6hQKCAQEA2clNNbfh +6AxN5V/MT/aPA/CONexzlAPTfpV1SS6MOcPlzhUScKzcigfMLJ5eHrXpJNRrq9cL +TQOSQq+N8dXI0ZtmLvWFIeLq51jFe3WwCN3RuwWqOpzGHPpXaq/Ib/HUR0AMJ3uV +ofm8kCpF9szx3xb8KeAK5Z3ZPciubETVdAj6ep7T6RrAXMHF+wXhW+yZSNju38tc +IsZgt7LPKqElsSIbilE3qYdfVoHGKabqYZkmWTESURbWQe9wC1WnePyLv8/1ROfU +C9U4Eh/w+WlocEa/1k6pkVu0etTh0v2bKnF4XRE6FoYbMz1dOSD4yxSTG7zKhdka +m/3wEDYJqd3u2QKCAQEAl2ZWLZ8uIjCB9NnLiR8Jf24BpFiKpBJoqnhYJnq/4g41 +JKIzQ713YkatF73CIhgZfE9S+Oyf9UgH7O0MZ0k1TFaBZHXiyhDFEHhjrOBMAO/G +MF/o1tWOU3p86i6fCM05XS7m4YNG6TdJj+L91sl2WXxC87W01msuxgLTuK6wpGnq +re6uQZT5amT9YORoi/HxsJGl32NZ9bqbSPsuNk8TOauNA4iFzd25qCnZr222kUIz +V22jTnVD7RTDY6DJGRHh51znL40qodYi+Fo8n1qvWkNV6numrjGW+wAjgGbOYnuh +CFHmCDUFF15DC3FG6D9b1DghOJYEl7GBSRG+hdYH5QKCAQAuoGFuYcr00kWPGR51 +9DSURFk+BDyOcO9Dx53PqC6PY3h80ZgcFXY1+wtkdhdyfcHHh87xgF3EBEK5EjrS +jtGqxplu7lOteJaQJzpIf17L1ynC36idWdk0dQhoJ/BCv0SSaIzxmwzjG8OaHeLS +vvf9qj8cfAH5PP04tBFbzrTgXde6juyRmI+cjEPlxVGFS7dZmFA0C6bTLyOf0KF3 +3/5g2QuKZm8DVZ88txYE7t55PL+wEsh4IeqHPUsAsjrjtTX6P/yj3vpP+jtB7iK6 +Uy3v88W4jSjSnQ6byZ37fR5OTPLXAgwsrFOAed/OjleVqvb/1kCJvXxr70cJQXh6 +LLCpAoIBAFckgxXk4i3X3grFXa1nhORfvdGtxSzP1Rvq1cLdOTVxtB7Xf+18dAgZ +3OHMW0Q6WKh4hP0pEeLpiptxhhHl0I9nFJBYAd9UrLwmLzUYYySqVQvFO2JifcY2 +Zer0KdNlej0PGjzXMcOkNXyF5IctAD7svPjZ/B3KzL88xHUumKLYhTMflaMhsqhW +RKiMQbo2NT/38Vu3j9EWG6zbizVV9owXrb7atmR/JLZsaIS1Uory7ccIq8svFAW1 +SrQP7eZ1GDg7Kbh+0rfJf6N+Hh9Qumao97yqAYJHS/Udpw5uVhVtXeAEdR2lRoDB +dDGZmYTPMav2jSUmg7BMOO1iyjFI0hg= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-aes-128 b/third_party/heimdal/lib/hx509/data/test-enveloped-aes-128 new file mode 100644 index 0000000..a75409b Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-aes-128 differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-aes-256 b/third_party/heimdal/lib/hx509/data/test-enveloped-aes-256 new file mode 100644 index 0000000..4fda391 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-aes-256 differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-des b/third_party/heimdal/lib/hx509/data/test-enveloped-des new file mode 100644 index 0000000..944da00 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-des differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-des-ede3 b/third_party/heimdal/lib/hx509/data/test-enveloped-des-ede3 new file mode 100644 index 0000000..c27dfbc Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-des-ede3 differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-128 b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-128 new file mode 100644 index 0000000..72f8158 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-128 differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-40 b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-40 new file mode 100644 index 0000000..0e5eb02 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-40 differ diff --git a/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-64 b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-64 new file mode 100644 index 0000000..9ce6694 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-enveloped-rc2-64 differ diff --git a/third_party/heimdal/lib/hx509/data/test-ke-only.crt b/third_party/heimdal/lib/hx509/data/test-ke-only.crt new file mode 100644 index 0000000..a6cc06a --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test-ke-only.crt @@ -0,0 +1,117 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4 (0x4) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:04 2019 GMT + Not After : Nov 21 22:25:04 2518 GMT + Subject: C=SE, CN=Test cert KeyEncipherment + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bf:5f:55:ca:c5:c6:c5:00:a6:40:17:fc:1f:a2: + c7:e7:41:1b:29:37:6e:ba:7c:01:19:f3:4a:d7:c4: + 9a:83:17:4d:40:cd:30:d1:9f:fd:94:49:41:5c:7a: + 2d:32:83:81:29:15:e3:b2:1f:06:1b:f5:f3:7f:91: + cf:dc:82:b1:4e:d5:a9:48:da:63:49:b8:b8:41:0d: + cf:eb:76:df:1a:33:5a:7b:2f:ed:13:5d:ce:77:85: + bc:1f:52:b4:ff:96:20:48:09:19:d7:0d:55:ed:a8: + 9f:de:bd:26:2a:cf:2c:f4:48:d3:eb:94:f1:b4:ca: + 5b:6d:1b:21:82:46:98:23:84:d7:be:08:90:54:f4: + 46:ef:59:6e:8b:8c:7f:65:90:5a:c3:fb:c4:1d:97: + 9e:1a:be:82:96:d7:86:5b:d7:1a:0e:04:1f:30:71: + 99:70:40:28:6c:b2:16:3c:19:f1:f3:9f:54:22:9c: + e0:e5:2b:c9:30:a1:01:cf:7e:1f:a2:40:d7:d3:ad: + 23:6d:fe:55:dc:ad:87:88:ee:e8:9b:81:e8:72:8d: + 2a:25:58:ff:81:18:f0:24:9a:13:31:f9:30:7c:ed: + f1:d5:4b:13:ce:bf:83:48:47:9c:44:99:0d:52:e7: + 52:4f:02:91:10:fe:77:39:f3:fc:ce:04:bf:57:4e: + 3b:17:a3:c2:94:85:10:d6:76:a2:c0:04:45:d1:ff: + 96:a7:c0:a8:39:bb:7a:4c:f4:96:4c:5f:2d:63:85: + 52:6e:74:5d:70:7a:de:35:7c:92:9f:ed:e6:85:c8: + f0:1d:b7:be:29:54:78:5e:7c:4a:a2:b8:85:ee:b7: + 20:2d:0c:78:a6:32:be:c0:a2:89:4f:f4:c8:e0:3c: + 3a:4c:b3:68:a1:a7:eb:b5:c7:21:74:b9:3d:0e:07: + 3f:ce:35:29:b5:33:1f:ac:d8:36:dd:d1:54:3d:47: + c9:29:c6:26:23:e8:51:8d:25:9a:8c:96:84:74:e9: + f0:10:d8:96:f5:ad:22:31:8f:e9:6a:a5:9b:3b:00: + 93:5e:80:22:f1:3a:e5:2d:10:7b:c6:a8:b9:6b:8f: + ab:33:64:99:fe:aa:77:7a:0f:96:f9:3f:fe:15:6d: + 8e:4a:95:a7:35:9b:f4:20:cb:a2:a1:d9:f6:62:6b: + a7:4e:b4:22:3d:22:73:f4:7e:0d:af:62:41:7a:d2: + 15:ab:b9:a2:25:a8:87:e0:b5:1b:be:c0:16:d1:e4: + 40:5b:56:a7:ab:39:d1:85:02:f5:4f:95:3f:37:dc: + 97:e4:89:c8:20:ab:11:9f:d8:f1:77:d6:b0:60:4f: + ab:f9:88:37:ef:9f:bc:2a:f3:22:3d:2e:21:82:63: + c6:21:73 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + FF:78:58:BD:A5:C2:4D:D1:07:04:05:DD:15:6A:A2:2C:92:EB:54:04 + Signature Algorithm: sha1WithRSAEncryption + 0d:b6:af:48:3b:0f:01:49:0b:12:d7:bc:9f:35:09:2a:42:e4: + d2:86:d2:c5:53:65:1b:a4:d5:52:87:28:dc:01:70:97:f3:0b: + 87:35:67:bb:b7:dd:f9:80:09:d3:84:33:11:2a:fe:0b:85:75: + 4b:d1:84:0c:46:35:d3:69:b8:fe:fc:a3:5a:c7:10:8c:2b:36: + c8:f0:ab:e7:f8:98:6c:b5:ec:1e:26:69:31:9b:07:29:03:ee: + 21:34:5c:52:1a:58:4a:c5:10:43:6b:8e:fc:9d:94:12:67:d0: + 12:40:55:14:f0:8f:d5:a7:a9:c7:d4:65:99:53:0d:3f:9a:23: + ab:13:ed:25:eb:33:56:b8:b3:ed:f5:6d:6b:a4:26:6c:80:6d: + 4c:27:8e:e5:5f:4d:e8:83:0b:c8:ca:17:6c:de:b9:af:ff:2f: + cb:9c:25:24:5f:09:e4:d9:62:a8:6e:de:da:c9:9e:1f:be:bf: + 19:1a:df:01:e2:dc:8c:ef:64:40:8e:b3:2a:0d:29:a9:7f:e7: + fa:bb:4b:76:41:c4:82:e7:07:d0:21:d5:1a:88:64:27:58:1a: + 8f:9e:48:e8:cb:40:d2:f0:ff:68:06:10:1b:5a:c3:1b:9f:48: + 52:b6:a0:8a:4c:0e:be:f3:e4:ed:a1:7a:9c:52:91:38:15:fc: + 92:ff:82:55:10:bd:d7:a2:1c:bb:e4:8c:56:d5:f6:c7:77:12: + 2f:cb:61:c6:75:a2:71:9c:4e:96:b3:0f:b6:d7:85:cb:52:0f: + 96:87:4a:05:15:ba:f7:31:b0:76:54:07:b8:59:38:5e:7a:03: + a4:87:60:e9:12:4d:aa:3a:98:d6:b9:46:a1:73:40:87:27:cf: + aa:87:66:e8:32:37:74:0c:93:ff:a9:ef:52:3b:a2:36:1e:16: + 1c:07:45:e9:65:9f:9e:de:ff:7b:b1:c4:a8:7e:59:25:79:1f: + da:7f:35:85:36:ea:cf:79:ff:71:96:77:28:3a:e6:af:68:f5: + 4c:c3:1a:20:7b:09:8d:66:15:b0:92:0a:4b:39:e4:f1:06:9e: + 9e:4e:f1:ca:bf:81:77:e7:00:82:79:26:0f:d1:f9:a2:4d:9a: + c8:7a:da:f6:d0:1e:65:04:02:2b:14:0b:84:45:eb:5d:6c:68: + 04:d7:a6:98:85:8c:fb:7e:de:42:63:68:5d:cd:a1:3d:4b:85: + 5e:e5:c3:38:a6:79:f4:02:5c:d0:ea:53:c6:91:84:08:b2:eb: + 2f:02:bb:5d:3b:bc:f2:e7:8d:67:44:70:0f:96:63:25:25:1a: + 38:1a:cc:a6:72:2d:41:23:8c:cc:95:12:4b:4f:64:91:21:79: + 96:46:70:8d:68:dc:dc:d5 +-----BEGIN CERTIFICATE----- +MIIFETCCAvmgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwNFoYDzI1 +MTgxMTIxMjIyNTA0WjAxMQswCQYDVQQGEwJTRTEiMCAGA1UEAwwZVGVzdCBjZXJ0 +IEtleUVuY2lwaGVybWVudDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AL9fVcrFxsUApkAX/B+ix+dBGyk3brp8ARnzStfEmoMXTUDNMNGf/ZRJQVx6LTKD +gSkV47IfBhv183+Rz9yCsU7VqUjaY0m4uEENz+t23xozWnsv7RNdzneFvB9StP+W +IEgJGdcNVe2on969JirPLPRI0+uU8bTKW20bIYJGmCOE174IkFT0Ru9ZbouMf2WQ +WsP7xB2Xnhq+gpbXhlvXGg4EHzBxmXBAKGyyFjwZ8fOfVCKc4OUryTChAc9+H6JA +19OtI23+Vdyth4ju6JuB6HKNKiVY/4EY8CSaEzH5MHzt8dVLE86/g0hHnESZDVLn +Uk8CkRD+dznz/M4Ev1dOOxejwpSFENZ2osAERdH/lqfAqDm7ekz0lkxfLWOFUm50 +XXB63jV8kp/t5oXI8B23vilUeF58SqK4he63IC0MeKYyvsCiiU/0yOA8OkyzaKGn +67XHIXS5PQ4HP841KbUzH6zYNt3RVD1HySnGJiPoUY0lmoyWhHTp8BDYlvWtIjGP +6WqlmzsAk16AIvE65S0Qe8aouWuPqzNkmf6qd3oPlvk//hVtjkqVpzWb9CDLoqHZ +9mJrp060Ij0ic/R+Da9iQXrSFau5oiWoh+C1G77AFtHkQFtWp6s50YUC9U+VPzfc +l+SJyCCrEZ/Y8XfWsGBPq/mIN++fvCrzIj0uIYJjxiFzAgMBAAGjOTA3MAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgVgMB0GA1UdDgQWBBT/eFi9pcJN0QcEBd0VaqIskutU +BDANBgkqhkiG9w0BAQUFAAOCAgEADbavSDsPAUkLEte8nzUJKkLk0obSxVNlG6TV +Uoco3AFwl/MLhzVnu7fd+YAJ04QzESr+C4V1S9GEDEY102m4/vyjWscQjCs2yPCr +5/iYbLXsHiZpMZsHKQPuITRcUhpYSsUQQ2uO/J2UEmfQEkBVFPCP1aepx9RlmVMN +P5ojqxPtJeszVriz7fVta6QmbIBtTCeO5V9N6IMLyMoXbN65r/8vy5wlJF8J5Nli +qG7e2smeH76/GRrfAeLcjO9kQI6zKg0pqX/n+rtLdkHEgucH0CHVGohkJ1gaj55I +6MtA0vD/aAYQG1rDG59IUragikwOvvPk7aF6nFKROBX8kv+CVRC916Icu+SMVtX2 +x3cSL8thxnWicZxOlrMPtteFy1IPlodKBRW69zGwdlQHuFk4XnoDpIdg6RJNqjqY +1rlGoXNAhyfPqodm6DI3dAyT/6nvUjuiNh4WHAdF6WWfnt7/e7HEqH5ZJXkf2n81 +hTbqz3n/cZZ3KDrmr2j1TMMaIHsJjWYVsJIKSznk8Qaenk7xyr+Bd+cAgnkmD9H5 +ok2ayHra9tAeZQQCKxQLhEXrXWxoBNemmIWM+37eQmNoXc2hPUuFXuXDOKZ59AJc +0OpTxpGECLLrLwK7XTu88ueNZ0RwD5ZjJSUaOBrMpnItQSOMzJUSS09kkSF5lkZw +jWjc3NU= +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/test-ke-only.key b/third_party/heimdal/lib/hx509/data/test-ke-only.key new file mode 100644 index 0000000..1b463b9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test-ke-only.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC/X1XKxcbFAKZA +F/wfosfnQRspN266fAEZ80rXxJqDF01AzTDRn/2USUFcei0yg4EpFeOyHwYb9fN/ +kc/cgrFO1alI2mNJuLhBDc/rdt8aM1p7L+0TXc53hbwfUrT/liBICRnXDVXtqJ/e +vSYqzyz0SNPrlPG0ylttGyGCRpgjhNe+CJBU9EbvWW6LjH9lkFrD+8Qdl54avoKW +14Zb1xoOBB8wcZlwQChsshY8GfHzn1QinODlK8kwoQHPfh+iQNfTrSNt/lXcrYeI +7uibgehyjSolWP+BGPAkmhMx+TB87fHVSxPOv4NIR5xEmQ1S51JPApEQ/nc58/zO +BL9XTjsXo8KUhRDWdqLABEXR/5anwKg5u3pM9JZMXy1jhVJudF1wet41fJKf7eaF +yPAdt74pVHhefEqiuIXutyAtDHimMr7AoolP9MjgPDpMs2ihp+u1xyF0uT0OBz/O +NSm1Mx+s2Dbd0VQ9R8kpxiYj6FGNJZqMloR06fAQ2Jb1rSIxj+lqpZs7AJNegCLx +OuUtEHvGqLlrj6szZJn+qnd6D5b5P/4VbY5Klac1m/Qgy6Kh2fZia6dOtCI9InP0 +fg2vYkF60hWruaIlqIfgtRu+wBbR5EBbVqerOdGFAvVPlT833JfkicggqxGf2PF3 +1rBgT6v5iDfvn7wq8yI9LiGCY8YhcwIDAQABAoICADokNcV4Vw5tRxU79D6MTx2k +OyNHkx2XJSKENx3cvnDLeI4SiR129SzDINd+yxKIv4oC+32XTVzbWZJNc5B0KHhi +E59tsjKoq1ogXyYTpG6qYXgBtI5otpy7hc8iapkoPECGe1JJ2+xrib67SshAz1Cc +e74cL18VB7fbQU/6MKjB6GX05hzZZl+7lQlSszXhKKJYcFnpQYCwlq5LZqeqb2EI +wY0PRmXDKET1yimSXF7+7inh7bXSmrpqgElQ8T1zY98MwDHfzqhQFFh29TahvkRn +PQHBy0amk/ca1HAfXCrog8uglrD+oF0qXIC+2zxvySL2DarTFNgHl6vj51oYC315 +pThrEPf8SZX6d7rg7t0TGAnAfYFwn9ba+cVW8YmSI78CZ/tD2kzD0QA2nnFbuQTW +a/fwWJvPW7Fnw9S5TaCff8vYk3r4eO+R3qdR5zsxJ5io/uB6TVrFmG4JwBSOa2fR +YvBf6SEZ/9VkQffqg6UIVhcj5BhaEIlST/lsLhgSA2nsW6ms7bfMfGjLxWrchNFy +VKgrRC63E58vgkOw1AS8KUzzhqKvJUG2cgvZVoFylNwWY5oVI5shp08XgvoChLOS +S8OY9MQUZby0BbXECRsa0c9/LIjk9wGILXfzORfblNE29IbLXxNsjrRnD0pzdu6k +uGJ1khRueU9JxorWsPKRAoIBAQDeuvOyilg0wVI0Z7qSeKd/Eo9Gc7oSgiEb7uir +XkRjWaO7H1w07b0s0pTww2GfyisgkeJgqi+k4vmYt2+gy4xHFpYJ9Pxa3cTHVRh6 +Ptb3CxXfOoE8pY3k4NH88LLz6j/3c3b8gGOUHKDBdXovPQ/uNgq5IROnMBWyopbE +odPIErOI2Qt8bTywczCnCGaXNDtTijVvZShz3GxOlAHcL+1HIE8Sq12NehFk6MF/ +CDEd4PcIlNmTpz9/7S6fdth+tOrVo9glgC9p8TQpzE6UZEZsfD+N2nYYrmRQ/jQM +WINC7M5rOkOu0QHMrpV7C2BWcnlcSK3xhX2RWVjCIo1ossuZAoIBAQDb9Ue32sI6 +6uAmh2dZ3EMQFTlo4pmk87YSUHaMQlr0KL/ggXxJJ2rINCxnaJXapSHqFu0X06uv +/JaS5Hiyc1xGZdGX9UNPz4PfYDt0akGxPXtYXsLsNRpye1PGYiXeKbWWlI2Vvlpc +wpFFf6lyXvoPZ7Pd4vjH7SgFmh3SsF84IJ6O2I6F/s4sJydROIDdmHfQRy8HpcPS +5QOnsFwK1DKAvas9y73clAohrcfjQnLHIw1pEUtYIWXxLmVNHy73n3YeD9sajNfs +0aypuaQ4T+BxLyqfLrCntwfdk7GljzK/ICQfsFzC/PCLZEmrMjD2cUlng7q4Ctwf +qdURukQMtJzrAoIBAQClFm0LKP+4GpKTxU7EwilkRp1r2ttQXKOt0KckXfrSqN5z +FAuEL7LIRk2fJzJ0/aR5v6fLfllSHepjB5P12ulex57uQmfJ8haoqKo78dfjxJOx +oeuoyA0kWH9MvBvoLvi6sRrAjWlBnvaIbkriOKBWMDhCgAHRKhLrFRgrJseSxEnO +ZRHeaBlTsA2fwNpJuK1AfnCc4J3bQsYEeC/oxJ1a2tfBPsNY2eGKqfrB7ZB6VQTF +l46toomuiF7GU5CkWfS15XuQUDLUk7PWR1j3JFwOjQmOWx6trJUuczyg6fpg4KUf +VVBVgxWSYNTrHsOJT9AkVrqXChrIYTEos/OcZuoBAoIBAQCglFfwZHdqFfDgj/em +xcP76NLJvKyYnQeuJSn2ybanC1zRZRa8PVeao2RLdjH4tpek02nx/CkaSNgQk1V+ +SfPyvQCf5IFoscG/gPzGx4//+jejU0MQuM//BgQqD5s/rsmQDhGzYY2MrMrrpwCo +q6f5OSc59SrUolGWjWX6W6KYUlAPTw/1yQjxeQAeLpb9sALAfkdaWO02eNULRhhc +G4BnNpDeg3CvqTAgWENWqTssIG3455RO2csXoVx5Siu6waK03bSClJJKpORd4FaA +eegMGXgPUEHNnzTR0bJegMV2fNuCevmtrIVb7jJOFk1ijWAefzAAjoUXZKBV2ds2 +P2FTAoIBAF7XhtL2lcAo5dPYzpOR/9p6ue1XLpZf+nbvm0mhrC/Z1jrea1e89Gzg +TurHhSIZFUT7y9yXd2A0qDwJICKkm63XZzZ5rm4B+tfMdT9DPIxIeJMNrnatL4an +IwgSTyvgIoKC6G93nOL9nC3Wa2AJ8dp4MeWKXa7VHGQBRc8JlPoVi9UrwMBXgGVB +uUHvwxhUnUlsJ5kJRyF9ln2wGPba0d+HvddZZY4gPM88vn2JNleke70V0W1DkEPs +BQBJIix7XfvXQqPHiMMaIof9IEgTHHRkhd7gYZohEZ02jlT6CwJMgkjb8+Qosfs3 +hFXFVI1+i1ntO6Nf9NvTPVfjJNWzW7Y= +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/test-nopw.p12 b/third_party/heimdal/lib/hx509/data/test-nopw.p12 new file mode 100644 index 0000000..e94aa9a Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-nopw.p12 differ diff --git a/third_party/heimdal/lib/hx509/data/test-pw.key b/third_party/heimdal/lib/hx509/data/test-pw.key new file mode 100644 index 0000000..495eef6 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test-pw.key @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,AE05E89E216F377B4B073A88DA8A284B + +4DWOJFa1qSC1Mcf/mGI09WyyEbxgbSKmRzZaPaFH7obN2o/D9zMQ6BqjnUVR6Rm7 +UXcXPpzObks/EJVyIPc/vfiGLkq/wWEiqVKWZebV4r0OhCetKdyXipiiSGLUzta8 +olQXfEthbeE9+NPB0hspGzt4owyoPuhvrgO5m+7h++iQj2ljbbUG3WLJf9Frd7eN +GMXKJwtBUVgGPxjs89etY9JMXig9bgUDPwVhE/3VPiG+LlHeZDD5C2+gUi09d2sv +gCN53XD1x7bFWKBzEPmGjFXMraZAd85Ew20re1RJP/R2+KJV+z72Af2DNUl3HL4f +KgeyXkjy8xgKILnkN17hraHCwR4d/onFwjEhHyNeCHgqYSGqD5Tp80eUwHOIC8od +Iwnw1Pe5ZrO9i1w3bdIMhOcP5jyMEAt/l3+Yc4bG34zNgRDam5V2PMYiY//OQ/Ge +pn+Ug4WBNkab7eSOt7Dz+TskKtVy4/twBp1o6WndRwbvu3fTPkVxrOuPH1YYMmUn +xQL/C3aMZXcjytiSHzQ09dQrOXYeT+RYcTrpXvY1RiVFawkPlBn5pSvzNG2mvXhG +ed3iDDfBdLvqjdEeoANYOafuuuvaUBRq1ouq4sPA5zLCWmDCsH/J72RZ1ECyc2rT +BR4Kld47cbw3+oLZmyrIfChOG/ah6IyDbF1qFiV6plmLca8JrmnCxBPbBxP4PG1f +uT6a4ABkXbhGW3iBEzSEAjLIQssMeyHHJ6/87/+ZmvQBy02N5kwRmXRhePy1JnTF +4LPOA/yWDqvNniOfozKvS9g3RZX5ZLKY2NQ9Xz4mPfwv3BdRbNr+8Jyf2jYJGpgQ +pVkLdKJErW9XogbpWDbCeI5q/aA/tbwfjbM4rvH7nXhC44jzg4sHEYPmuFBpvDF0 +gNgU0mglkAFitoCh5yY688ZhbquRZF8lI2/ZwXWjmpUafkTRfrrUJSLLm3izUvtS +R/2OBscqTiWWp7pkaivUX9/nEB7cEoXVYyE/PdbRAf3lSylgHFLfshzKkii2N1pO +jnJ9ZUlduolaHxMMPcu5CJSEQHOavI5gLULld37iNjJwIHfh8hgaP39bcXZeVsMT +EdePCUX2i6moBcmwuOtz2o0jGjGOmoxLv7yFAiRSCxDI04tOa0ulikf5tt/EBKKF +p7h5/DVWN1KkbGu9Ys5xi2GBIAnyK4T7UTdWkvE4xZw6pVL0WUX/qdj42MDu4ocR +ZP8mQqfmoiprzdO+y7J6lo4ZnRV7EK82Q2SFsoyG+Ev3vLGA6Xdr4e7cd9WFuim6 +V7eErJFpt1cHx04nJxuy43nruohDH+wOX6KZnxNQAQHoM7O5JoLGkdN/s+MNirmH +IWUjKlm71lWTllD3UXt+sg0E9+aPbjNA8blc8zZ2VUj+3GoLt0kUTjED81TVT+Qz +uXlGTVWUXnBYBSNN2Gbfv3/cZSHr2eraM4TiKQJ07LvgP1+VioDPG9ZyVjMVbWVT +2Yl7xzF97O5MLIVS0HDIxIEV7MgpCF98SRXGsr4MLgG14u/FByyH6vXHNPIlDd0z ++AXnXWXEJpn73Oh6f1ht/3mXiYSNmXrr7W8kRabZmrrCajQ5Hi8eC4qV/2Z49bWu +ryFbhI8/1+CYrkYzgFkrjptgrUHSZL0VLFINeP9uF1WNkGp3kMzW/ZZK7aksqmEM +v5JE2HoD7+Dn7mNsHL9NfvhbH2kfwHKwrMPa9C3u5OrSX2KyyMS4UJGQ1QX+/6c4 +oYuLhslEwh+Iw1jwVentWTApNw7ONgrsxac59dOiaF/UQUBfWSDmwwlnvoAqJEVp +l4CfetCTgZApsxKUQZWC2ls4cZDcMa3BGdyORV/5vXrxAxYQyIIkACkT3Zsxnu9V +cjkOj/G07To8wgncc+u++yOErQ0m5OrdR0T+cJTgiyeWVgXMahiWZ5qt+GMbCzaJ +xeKb/V6Es9ZPj2Qzqi7Sj1LRtKahh8E3XH5WVMdNKZVWZwXkd3sButezHEzB80p2 +2lhuajOolcwTfgQEtF/F/HuaokjB9r6lN0RmjUq5eIIMQ1KMRrzFsdQNDgCxGdAv +GxjrvxOm5xM/QQ7QlXzNTxkwP4QbBDdn/nMWjAlVtQxurqtz6kxp4p03nkpToydM +P2EeP243RpxRquadw9TqiL5IEqXdjpBon1RlKk+ZNVm4rYJWZ0UXk/CRvMeWKUeb +Ib/0xCe2ZugyZbYQziZzrMl9WX6LKHhJP8bWA7t4Bb05bvDju0casma6gslQ/JdB +1Ok59w59TpJYtSSEU3llMbCS4ll130/OlbKZa2Hy7LKgXkRsjVeYTBzvXC34/PKl +v1E0PY8P6Vz60j1bxHlrEaCb+j4yxZF54cqgmvoWiKdwXSvEDw3Wb64wATFzPQKj +T87vtU4FEVokRxgumF8BKHldKc7RPwmMuISSwG5+G7zOeOpuz7ETF4EyzX/D+a2W +mOqX6WxS08BjzShzkdLEQtJU0TbtTPaYMQ8tVxiosypVQ+UlWh5qRtzQBodmCNYD +3dwmrn/1IJ4LhUq0RFIczjzEP8QfkkwaNUUNp7T7DCFCn6ktkU/IBqzQf9CygfRp +8vCdp0jMNn1JDpAW8SRvvqMlly6QeN9ndQO1Ql22k5Ihlw4yCw2/44XhEmlGsB3x +jKEkSej5ipuQ2xX3DjFfsSKgceF0zOCGeTbw4Kt0CuwGLh6ZQLUHQktD2/BysJZu +XH+y4NtD4Sr06DIgF43ECuTxWdptGiaDgk7neW2/1f7eLDOj8IooCHkt0a1DDzFF +Xt5trABWgb2Qa9sjWJ89eUMc6gC48vyiLeXeaZQ5YuWcCdDcjZHY7KAvLY+r2OKN +49O/X2WY6WmVoByoyi4S2MOER4VUbbyZEcvAqTOBcj6e4JJprtHsl4ppiDYVXVot +U8GSYqxgNN7jyNthIti5sr/kczM3Q9peCLZN92j2CKU2wQb1qilEMkCSWpGUfyzD +9M40fssEtIMAnwVfi8XjAezHFzdlKID0AR/b+aKndeR+4xEMdzEWkNsH452e0tRz +vgebV+wM5Zva0+/+tG57iPQLwEpjv2septoQuuh3ACdgFkmPgcHspcu495+Wdi3g +2Ipxrx/e1o4ragEEQXaaSSGBSCTz8qeWcvKtRm0d8fMtnERc5yzLYHRzhEm/8oc3 +-----END RSA PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/test-signed-data b/third_party/heimdal/lib/hx509/data/test-signed-data new file mode 100644 index 0000000..1228c85 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-data differ diff --git a/third_party/heimdal/lib/hx509/data/test-signed-data-noattr b/third_party/heimdal/lib/hx509/data/test-signed-data-noattr new file mode 100644 index 0000000..f230779 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-data-noattr differ diff --git a/third_party/heimdal/lib/hx509/data/test-signed-data-noattr-nocerts b/third_party/heimdal/lib/hx509/data/test-signed-data-noattr-nocerts new file mode 100644 index 0000000..49fba9b Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-data-noattr-nocerts differ diff --git a/third_party/heimdal/lib/hx509/data/test-signed-sha-1 b/third_party/heimdal/lib/hx509/data/test-signed-sha-1 new file mode 100644 index 0000000..8ad1121 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-sha-1 differ diff --git a/third_party/heimdal/lib/hx509/data/test-signed-sha-256 b/third_party/heimdal/lib/hx509/data/test-signed-sha-256 new file mode 100644 index 0000000..1228c85 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-sha-256 differ diff --git a/third_party/heimdal/lib/hx509/data/test-signed-sha-512 b/third_party/heimdal/lib/hx509/data/test-signed-sha-512 new file mode 100644 index 0000000..1e40abe Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test-signed-sha-512 differ diff --git a/third_party/heimdal/lib/hx509/data/test.combined.crt b/third_party/heimdal/lib/hx509/data/test.combined.crt new file mode 100644 index 0000000..a07dbf1 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test.combined.crt @@ -0,0 +1,168 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:02 2019 GMT + Not After : Nov 21 22:25:02 2518 GMT + Subject: C=SE, CN=Test cert + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:da:1d:4d:ca:51:9d:f1:9f:d7:a4:7a:45:f8:75: + 98:66:b2:c5:7d:53:de:42:35:74:81:cd:1e:9f:f3: + 43:d7:a7:83:7f:fb:a2:ce:3c:44:37:80:4f:21:36: + a6:f6:c9:51:74:9e:e2:9b:bf:ad:e4:eb:72:11:64: + 36:88:b3:a9:91:63:c7:ee:38:c4:f5:8c:06:71:e5: + 09:b7:eb:57:5d:bf:db:5b:72:07:c5:29:e8:6f:33: + b3:a2:27:ef:1f:50:f0:55:33:63:41:23:e0:b2:f7: + 21:77:4b:ab:9d:73:2a:bb:b6:4e:88:7f:7c:e5:c6: + 37:3e:b6:20:c1:57:3e:6d:57:78:ef:0d:47:e9:41: + e7:fa:b6:2d:32:3f:42:05:8d:56:af:f5:c4:b8:6e: + 99:1a:e7:07:d5:a1:3f:29:7d:ce:b2:39:a6:ab:06: + 7a:e2:26:39:d8:96:9e:3b:c8:af:79:3e:9a:24:4e: + 4b:b2:af:e4:07:0e:71:dc:2f:70:27:97:3c:a2:fa: + 69:9b:57:4b:c5:53:5e:28:0c:b0:c7:57:1f:a2:b2: + 26:0f:5f:bf:d3:45:78:90:5a:2c:fc:6a:67:33:b6: + c1:7e:cd:17:c0:58:9e:ba:85:c5:15:5a:5a:67:db: + bf:2f:05:cd:38:d9:94:c9:95:7f:9b:68:b0:62:ff: + 37:92:cf:d8:77:be:cb:72:3d:0f:b9:80:44:57:c0: + c9:10:01:fd:07:25:30:eb:d8:48:05:af:98:fa:c4: + 64:6d:59:a6:6a:8d:1b:d4:4b:f3:07:98:68:e3:bb: + 59:c9:21:f8:11:b4:a2:82:1b:0d:e8:8c:e0:a5:e1: + 1c:71:ca:c3:2d:90:43:c3:ee:99:2c:7d:41:48:39: + c8:00:72:0d:80:39:23:a1:3a:27:ed:07:ca:32:8f: + 34:ca:bb:9d:67:13:7d:31:ed:4a:db:35:7a:ce:b3: + 89:e3:64:9d:3e:47:4e:d3:b7:bd:ab:12:16:10:bb: + 66:e8:1a:77:4c:2a:e0:b9:16:69:66:14:83:4e:4a: + f3:6f:ab:85:6a:70:c6:9b:ce:93:ab:75:36:a3:a5: + aa:9f:45:d6:a2:7f:17:c7:6f:f9:f5:e7:35:51:a5: + 75:c5:07:be:26:ce:7b:3f:29:3a:74:6b:17:79:4e: + cf:4c:0a:69:75:58:db:eb:a8:dd:f1:e6:cc:a3:18: + 53:a5:c5:a5:5a:a1:cf:37:6a:b1:9f:d3:d4:eb:0f: + 02:40:d2:ae:68:ce:bc:c5:46:e3:ee:f8:97:88:ee: + c8:a7:01:7a:a1:23:af:f3:31:2c:2a:6f:12:77:dc: + 3c:51:9d:40:f4:9a:2a:7b:85:29:1f:3e:c3:d5:37: + 8e:6e:09 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 1B:F4:EC:34:42:BA:8B:67:AC:55:F2:37:5D:B4:68:A9:D8:5E:58:7B + Signature Algorithm: sha1WithRSAEncryption + 95:f7:1c:99:72:42:4f:d3:bd:ba:3f:7a:75:bb:01:3a:ad:ce: + 6b:7b:b7:3d:5d:3b:46:51:ea:9a:36:94:70:36:1c:3b:fc:ba: + 9d:8b:0d:44:36:08:ad:a6:73:82:bc:23:ed:f9:5a:09:8f:9d: + 62:11:c1:94:7c:61:66:1f:8b:b9:0a:dc:3a:b5:eb:22:54:de: + a3:e5:8a:94:10:1f:84:52:6d:fe:27:c8:e5:cb:a5:8e:a9:83: + 16:95:0d:6c:3e:57:85:e1:ec:82:05:47:6d:28:ad:0d:84:fa: + 40:a0:96:f4:84:aa:d1:e1:0b:b7:91:e2:47:4f:05:97:f8:10: + a0:e8:57:bd:ed:48:65:55:75:da:e5:34:e8:f1:20:95:d6:40: + 8c:42:bf:b4:d9:55:c8:30:e8:d5:ce:d8:1d:30:65:90:39:eb: + e2:83:ed:11:03:cd:07:c0:e1:c4:91:84:a0:97:8e:6d:22:e6: + 75:77:21:7c:32:8b:48:ed:d6:b2:19:2e:af:26:ad:7d:6c:ce: + 09:e1:78:b6:72:61:60:22:92:b8:df:42:6b:34:6b:5f:35:ef: + f1:d3:c6:7f:92:05:3c:d0:08:77:01:66:f7:57:b8:65:de:d3: + d2:b1:bf:93:b1:8c:a3:27:e6:d4:e2:2b:9b:cd:9d:be:31:82: + 5b:53:dd:5a:bd:39:05:5f:8c:56:f2:7f:9b:b7:ef:e6:07:96: + bf:8a:d9:8d:bb:62:98:86:de:aa:91:c3:fe:e7:bb:a7:1f:f0: + fd:1f:6c:a6:04:04:f0:c2:51:a1:91:8c:9a:ee:f9:87:42:37: + 7e:9c:27:72:59:dc:60:a8:8e:d1:81:97:f1:15:c3:d8:a9:4e: + 9a:09:e9:81:76:39:36:b3:08:a1:e5:5e:97:37:ba:43:8f:06: + 1a:70:69:3b:fe:79:a6:5e:2d:26:04:e9:bc:5f:57:c9:d0:80: + c2:0d:4b:c7:0e:dd:04:e5:15:49:9d:d7:ff:ee:a3:1c:04:56: + 7d:e2:a0:d3:39:1a:59:bd:85:b0:eb:54:ea:81:8b:e1:17:94: + a5:fe:e3:0c:d0:74:42:ee:4a:f4:66:90:49:4b:64:bc:47:35: + f5:b2:60:8e:74:05:d0:a6:d2:94:b4:e0:0f:4b:3f:35:ea:2a: + e0:24:58:c1:6e:d0:65:6e:58:f7:e1:90:02:ae:40:23:25:e9: + 80:9a:d2:a7:ea:5d:fc:6d:f8:45:0f:db:53:91:55:32:46:e3: + 6a:c0:54:0a:5a:4c:e8:1a:1e:a6:33:3e:fe:ed:b6:ad:cf:6a: + 3c:2f:b2:6c:47:75:f1:29:43:31:69:c3:0c:42:56:5b:d9:b8: + 99:7b:ff:2b:50:87:34:2e +-----BEGIN CERTIFICATE----- +MIIFATCCAumgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwMloYDzI1 +MTgxMTIxMjIyNTAyWjAhMQswCQYDVQQGEwJTRTESMBAGA1UEAwwJVGVzdCBjZXJ0 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2h1NylGd8Z/XpHpF+HWY +ZrLFfVPeQjV0gc0en/ND16eDf/uizjxEN4BPITam9slRdJ7im7+t5OtyEWQ2iLOp +kWPH7jjE9YwGceUJt+tXXb/bW3IHxSnobzOzoifvH1DwVTNjQSPgsvchd0urnXMq +u7ZOiH985cY3PrYgwVc+bVd47w1H6UHn+rYtMj9CBY1Wr/XEuG6ZGucH1aE/KX3O +sjmmqwZ64iY52JaeO8iveT6aJE5Lsq/kBw5x3C9wJ5c8ovppm1dLxVNeKAywx1cf +orImD1+/00V4kFos/GpnM7bBfs0XwFieuoXFFVpaZ9u/LwXNONmUyZV/m2iwYv83 +ks/Yd77Lcj0PuYBEV8DJEAH9ByUw69hIBa+Y+sRkbVmmao0b1EvzB5ho47tZySH4 +EbSighsN6IzgpeEcccrDLZBDw+6ZLH1BSDnIAHINgDkjoTon7QfKMo80yrudZxN9 +Me1K2zV6zrOJ42SdPkdO07e9qxIWELtm6Bp3TCrguRZpZhSDTkrzb6uFanDGm86T +q3U2o6Wqn0XWon8Xx2/59ec1UaV1xQe+Js57Pyk6dGsXeU7PTAppdVjb66jd8ebM +oxhTpcWlWqHPN2qxn9PU6w8CQNKuaM68xUbj7viXiO7IpwF6oSOv8zEsKm8Sd9w8 +UZ1A9Joqe4UpHz7D1TeObgkCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMC +BeAwHQYDVR0OBBYEFBv07DRCuotnrFXyN120aKnYXlh7MA0GCSqGSIb3DQEBBQUA +A4ICAQCV9xyZckJP0726P3p1uwE6rc5re7c9XTtGUeqaNpRwNhw7/Lqdiw1ENgit +pnOCvCPt+VoJj51iEcGUfGFmH4u5Ctw6tesiVN6j5YqUEB+EUm3+J8jly6WOqYMW +lQ1sPleF4eyCBUdtKK0NhPpAoJb0hKrR4Qu3keJHTwWX+BCg6Fe97UhlVXXa5TTo +8SCV1kCMQr+02VXIMOjVztgdMGWQOevig+0RA80HwOHEkYSgl45tIuZ1dyF8MotI +7dayGS6vJq19bM4J4Xi2cmFgIpK430JrNGtfNe/x08Z/kgU80Ah3AWb3V7hl3tPS +sb+TsYyjJ+bU4iubzZ2+MYJbU91avTkFX4xW8n+bt+/mB5a/itmNu2KYht6qkcP+ +57unH/D9H2ymBATwwlGhkYya7vmHQjd+nCdyWdxgqI7RgZfxFcPYqU6aCemBdjk2 +swih5V6XN7pDjwYacGk7/nmmXi0mBOm8X1fJ0IDCDUvHDt0E5RVJndf/7qMcBFZ9 +4qDTORpZvYWw61TqgYvhF5Sl/uMM0HRC7kr0ZpBJS2S8RzX1smCOdAXQptKUtOAP +Sz816irgJFjBbtBlblj34ZACrkAjJemAmtKn6l38bfhFD9tTkVUyRuNqwFQKWkzo +Gh6mMz7+7batz2o8L7JsR3XxKUMxacMMQlZb2biZe/8rUIc0Lg== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDaHU3KUZ3xn9ek +ekX4dZhmssV9U95CNXSBzR6f80PXp4N/+6LOPEQ3gE8hNqb2yVF0nuKbv63k63IR +ZDaIs6mRY8fuOMT1jAZx5Qm361ddv9tbcgfFKehvM7OiJ+8fUPBVM2NBI+Cy9yF3 +S6udcyq7tk6If3zlxjc+tiDBVz5tV3jvDUfpQef6ti0yP0IFjVav9cS4bpka5wfV +oT8pfc6yOaarBnriJjnYlp47yK95PpokTkuyr+QHDnHcL3Anlzyi+mmbV0vFU14o +DLDHVx+isiYPX7/TRXiQWiz8amcztsF+zRfAWJ66hcUVWlpn278vBc042ZTJlX+b +aLBi/zeSz9h3vstyPQ+5gERXwMkQAf0HJTDr2EgFr5j6xGRtWaZqjRvUS/MHmGjj +u1nJIfgRtKKCGw3ojOCl4RxxysMtkEPD7pksfUFIOcgAcg2AOSOhOiftB8oyjzTK +u51nE30x7UrbNXrOs4njZJ0+R07Tt72rEhYQu2boGndMKuC5FmlmFINOSvNvq4Vq +cMabzpOrdTajpaqfRdaifxfHb/n15zVRpXXFB74mzns/KTp0axd5Ts9MCml1WNvr +qN3x5syjGFOlxaVaoc83arGf09TrDwJA0q5ozrzFRuPu+JeI7sinAXqhI6/zMSwq +bxJ33DxRnUD0mip7hSkfPsPVN45uCQIDAQABAoICAQDC4zgktLSJtyb5Yf+vN3PL +H6VyjEOlqRnG+T6J8NUHljfbXT5lRFg3tz/9D1Y0YEGWEHmubKC2UOIFRCOuFcpH +jH6SDst+E3WWwu3iFjhkHg+kL8ldlEqJQgsZstDojGuR1W60P5iAkGyoqUZYUxU1 +0HlvYWp57JhkQlwWJRw0mtoFzzoX47mhvLG5megmCdoRM2po2PmYniHT8lX7ftv3 +R6fyXMHj3AAH1Nzh0jln/lXAZu0gZiU7YN6/vOtblLirb1B5apDbadhRtLUoCGLN +/pwfVJCT+Bj38nsLtw8rl/pgkGTOiuCZDPnCUI9DCYhUPbzXNSLK0/fHJs2kRyKh +Nv+skWwmHdkCnzIliutxMlzehRHvRINoQ+/U/mNTE1FaNYnNEnSxpUSMKnPYUyTD +YBhjFjtwkRpRDzbbcMBQk7Tbj2aISvFiAz/KOtRBDmBx70IxzxvqZ/5s94lyHZ5H +fozf6LgBfJ5dmboNqHA18oBTAQDO2UBrIxyPSYExWdJ4o0vpTqwpmk8RTwgBsYfU +EfDj3UqO5KJHTJAqdqdhXhz2c5J6EAyxDDItNg10rEVQVQbGbTPLtI8spjWfwJ6g +P5L0j/cJx+nxNQvhrIMQgJfCrZS92PL6Yt0OqTS44m8mJgmt4z9OqZUtoT21fmcS +uIOMYOY/NZBc+wMJ27UoeQKCAQEA8w6aZ+NAqmdDfEi/37XsbadsxDppPZ+/Ss2b +aWOYwNU8P65rt3+EWjLrwMugiKOH1063QmZYcj74C4iaAhLblBiQH24YtiJi9tYs +JCcFLWp01ZEqcxqBqI2kaHd9tuIaANGM+nKZH2MwTkzZ5IX1eAqZ0qgkC7Dx0JvO +x1fXuhRTuFwTSkKZM3w4ba5G4DgczmKQr2SXm19PsMF61YX0n7HFuss85Z6xkONH +gF6yokmPT7k/Ly4PLXZ9kycNx2EI5s1B79iAjaJAK8ifaEfUNNIi/xBf97oX6+hy +AhO8aiC7snt6Tf2DNaJCZR1IKeO0M+5pkN6DZfV0hbQ9ulhD6wKCAQEA5bqt2VJJ +9Vuuu8jcRlHfc4Cbubu+bMt9gbVp33ckAtRtQGQM4tHoHdd2hv4q8lV/f/K3m6Ps +EMGeQ6QBuCWtkqD659eI5hvkchKjF+YGx/jt7k6EUlVUU1bfKXCgQv6W2VmrckzG +ULsedOBLeT0Keppgw4kHqx+o/5DB9G3pZnVBITqGUP471q5X+c3BbAwN+9q8yRyY +BimYJZKx0qgmpHSZ+4l3L6eLlcQiHev7TxGw1sGkpt3OF8NmR5PEzXUYC8qoi8na +neLwTs9NKyb6hmOwTNJiWR5PNxWJeURxfl6GIfoxyUjptIrc5dve6k+ESxGgsSI1 +vyXgRUeiMlP82wKCAQEAuqx2jl+NZNLWk/fT1d+FbFpwQO2Tso6kfrEXMYQa589d +7JLrjA1V+2ishHBgJVFjnUuJmGe+elA+da0+i2UsW7vZxSnrtMcINwga8tE9OrpO +bVCGx8yN1ISkxs8vMGzLB+HpYtjtHZwyl5CSsN7pvn510cLtnEUUE+H2mEexGetO +uYOOFTS9MTuwoxx8tuyhwykUcoDRp7U2IU0YKDIvxQ7mDCbX6ItPWTYVzlPs4pOY +i+R80KGRaptcqs4N2Rl/mrP+dlVTtnPs0TPOqmqwYrkZw8gxzLOSd88Y8NtzlBb7 +0YLgVlHkmia606n/qJyH5HKxhWBAjuhLy/y4hAwSbQKB/1xtv4SwlxEg0iy7o+Sn +DEBsfjs8TmF3fgex9ebzCIoa7dn6ZzTbP4jCJ+4oVR8rRyEzhqwYR+J2BDcyxX5R +qoRUQJ8HGQ18K226EeSLqC7M+O3oqVR3AHaHfUIvDkvmIstQSKq0ORZCMv7TP4qI +BK9PbZ8+gtdW5aftlhvCHSYcBxhXc7MilvDJNJxNLIVMVFQArfQ8jO3tzklPvDwF +a4a/YzTRGiMSRhb70r43M+WcOIovXw/ELidhdsVVrtj7Q7F62FVl4Y+kvwr2XRX/ +mMx5T3WZL/irOTPwdl9UKlWtskn5YA6cR2tcc4QH8qhTVebeMMkT+ovtsU4uhBO7 +twKCAQAnvazlAlCSy/OeRqucmyqKjWTMEey6c/5dYlCkirF9J5o3n1YHhOSp8DY8 +iEjyl6ptsASapBhD6BpI4AwI6u92WBEwG15bleMlctVmtj7v39AFwNwSvvZtBZcZ +jJ+TWaTT0nMvP90cZe5ql2DTrp/Mp4K9+3oR5qk9+EszobSoHxpgDzLogG+Zp/k/ +2NMj125uhuC0GTV5lKcrY6JquXPtqFBKOiBLr3j5sRe+iZ4UqZEjTo91nrV2E3HD +kFJSP1weCD2HQ48T74nS775yrQnR+mWAJjuLpyDW5UXIDpvYlSbnmJ08+4C5Mu/e +UK2bY3PmI10F5vBYLQpLlCYUyBDf +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/test.crt b/third_party/heimdal/lib/hx509/data/test.crt new file mode 100644 index 0000000..40663c4 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test.crt @@ -0,0 +1,116 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hx509 Test Root CA, C=SE + Validity + Not Before: Mar 22 22:25:02 2019 GMT + Not After : Nov 21 22:25:02 2518 GMT + Subject: C=SE, CN=Test cert + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:da:1d:4d:ca:51:9d:f1:9f:d7:a4:7a:45:f8:75: + 98:66:b2:c5:7d:53:de:42:35:74:81:cd:1e:9f:f3: + 43:d7:a7:83:7f:fb:a2:ce:3c:44:37:80:4f:21:36: + a6:f6:c9:51:74:9e:e2:9b:bf:ad:e4:eb:72:11:64: + 36:88:b3:a9:91:63:c7:ee:38:c4:f5:8c:06:71:e5: + 09:b7:eb:57:5d:bf:db:5b:72:07:c5:29:e8:6f:33: + b3:a2:27:ef:1f:50:f0:55:33:63:41:23:e0:b2:f7: + 21:77:4b:ab:9d:73:2a:bb:b6:4e:88:7f:7c:e5:c6: + 37:3e:b6:20:c1:57:3e:6d:57:78:ef:0d:47:e9:41: + e7:fa:b6:2d:32:3f:42:05:8d:56:af:f5:c4:b8:6e: + 99:1a:e7:07:d5:a1:3f:29:7d:ce:b2:39:a6:ab:06: + 7a:e2:26:39:d8:96:9e:3b:c8:af:79:3e:9a:24:4e: + 4b:b2:af:e4:07:0e:71:dc:2f:70:27:97:3c:a2:fa: + 69:9b:57:4b:c5:53:5e:28:0c:b0:c7:57:1f:a2:b2: + 26:0f:5f:bf:d3:45:78:90:5a:2c:fc:6a:67:33:b6: + c1:7e:cd:17:c0:58:9e:ba:85:c5:15:5a:5a:67:db: + bf:2f:05:cd:38:d9:94:c9:95:7f:9b:68:b0:62:ff: + 37:92:cf:d8:77:be:cb:72:3d:0f:b9:80:44:57:c0: + c9:10:01:fd:07:25:30:eb:d8:48:05:af:98:fa:c4: + 64:6d:59:a6:6a:8d:1b:d4:4b:f3:07:98:68:e3:bb: + 59:c9:21:f8:11:b4:a2:82:1b:0d:e8:8c:e0:a5:e1: + 1c:71:ca:c3:2d:90:43:c3:ee:99:2c:7d:41:48:39: + c8:00:72:0d:80:39:23:a1:3a:27:ed:07:ca:32:8f: + 34:ca:bb:9d:67:13:7d:31:ed:4a:db:35:7a:ce:b3: + 89:e3:64:9d:3e:47:4e:d3:b7:bd:ab:12:16:10:bb: + 66:e8:1a:77:4c:2a:e0:b9:16:69:66:14:83:4e:4a: + f3:6f:ab:85:6a:70:c6:9b:ce:93:ab:75:36:a3:a5: + aa:9f:45:d6:a2:7f:17:c7:6f:f9:f5:e7:35:51:a5: + 75:c5:07:be:26:ce:7b:3f:29:3a:74:6b:17:79:4e: + cf:4c:0a:69:75:58:db:eb:a8:dd:f1:e6:cc:a3:18: + 53:a5:c5:a5:5a:a1:cf:37:6a:b1:9f:d3:d4:eb:0f: + 02:40:d2:ae:68:ce:bc:c5:46:e3:ee:f8:97:88:ee: + c8:a7:01:7a:a1:23:af:f3:31:2c:2a:6f:12:77:dc: + 3c:51:9d:40:f4:9a:2a:7b:85:29:1f:3e:c3:d5:37: + 8e:6e:09 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + 1B:F4:EC:34:42:BA:8B:67:AC:55:F2:37:5D:B4:68:A9:D8:5E:58:7B + Signature Algorithm: sha1WithRSAEncryption + 95:f7:1c:99:72:42:4f:d3:bd:ba:3f:7a:75:bb:01:3a:ad:ce: + 6b:7b:b7:3d:5d:3b:46:51:ea:9a:36:94:70:36:1c:3b:fc:ba: + 9d:8b:0d:44:36:08:ad:a6:73:82:bc:23:ed:f9:5a:09:8f:9d: + 62:11:c1:94:7c:61:66:1f:8b:b9:0a:dc:3a:b5:eb:22:54:de: + a3:e5:8a:94:10:1f:84:52:6d:fe:27:c8:e5:cb:a5:8e:a9:83: + 16:95:0d:6c:3e:57:85:e1:ec:82:05:47:6d:28:ad:0d:84:fa: + 40:a0:96:f4:84:aa:d1:e1:0b:b7:91:e2:47:4f:05:97:f8:10: + a0:e8:57:bd:ed:48:65:55:75:da:e5:34:e8:f1:20:95:d6:40: + 8c:42:bf:b4:d9:55:c8:30:e8:d5:ce:d8:1d:30:65:90:39:eb: + e2:83:ed:11:03:cd:07:c0:e1:c4:91:84:a0:97:8e:6d:22:e6: + 75:77:21:7c:32:8b:48:ed:d6:b2:19:2e:af:26:ad:7d:6c:ce: + 09:e1:78:b6:72:61:60:22:92:b8:df:42:6b:34:6b:5f:35:ef: + f1:d3:c6:7f:92:05:3c:d0:08:77:01:66:f7:57:b8:65:de:d3: + d2:b1:bf:93:b1:8c:a3:27:e6:d4:e2:2b:9b:cd:9d:be:31:82: + 5b:53:dd:5a:bd:39:05:5f:8c:56:f2:7f:9b:b7:ef:e6:07:96: + bf:8a:d9:8d:bb:62:98:86:de:aa:91:c3:fe:e7:bb:a7:1f:f0: + fd:1f:6c:a6:04:04:f0:c2:51:a1:91:8c:9a:ee:f9:87:42:37: + 7e:9c:27:72:59:dc:60:a8:8e:d1:81:97:f1:15:c3:d8:a9:4e: + 9a:09:e9:81:76:39:36:b3:08:a1:e5:5e:97:37:ba:43:8f:06: + 1a:70:69:3b:fe:79:a6:5e:2d:26:04:e9:bc:5f:57:c9:d0:80: + c2:0d:4b:c7:0e:dd:04:e5:15:49:9d:d7:ff:ee:a3:1c:04:56: + 7d:e2:a0:d3:39:1a:59:bd:85:b0:eb:54:ea:81:8b:e1:17:94: + a5:fe:e3:0c:d0:74:42:ee:4a:f4:66:90:49:4b:64:bc:47:35: + f5:b2:60:8e:74:05:d0:a6:d2:94:b4:e0:0f:4b:3f:35:ea:2a: + e0:24:58:c1:6e:d0:65:6e:58:f7:e1:90:02:ae:40:23:25:e9: + 80:9a:d2:a7:ea:5d:fc:6d:f8:45:0f:db:53:91:55:32:46:e3: + 6a:c0:54:0a:5a:4c:e8:1a:1e:a6:33:3e:fe:ed:b6:ad:cf:6a: + 3c:2f:b2:6c:47:75:f1:29:43:31:69:c3:0c:42:56:5b:d9:b8: + 99:7b:ff:2b:50:87:34:2e +-----BEGIN CERTIFICATE----- +MIIFATCCAumgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAqMRswGQYDVQQDDBJoeDUw +OSBUZXN0IFJvb3QgQ0ExCzAJBgNVBAYTAlNFMCAXDTE5MDMyMjIyMjUwMloYDzI1 +MTgxMTIxMjIyNTAyWjAhMQswCQYDVQQGEwJTRTESMBAGA1UEAwwJVGVzdCBjZXJ0 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2h1NylGd8Z/XpHpF+HWY +ZrLFfVPeQjV0gc0en/ND16eDf/uizjxEN4BPITam9slRdJ7im7+t5OtyEWQ2iLOp +kWPH7jjE9YwGceUJt+tXXb/bW3IHxSnobzOzoifvH1DwVTNjQSPgsvchd0urnXMq +u7ZOiH985cY3PrYgwVc+bVd47w1H6UHn+rYtMj9CBY1Wr/XEuG6ZGucH1aE/KX3O +sjmmqwZ64iY52JaeO8iveT6aJE5Lsq/kBw5x3C9wJ5c8ovppm1dLxVNeKAywx1cf +orImD1+/00V4kFos/GpnM7bBfs0XwFieuoXFFVpaZ9u/LwXNONmUyZV/m2iwYv83 +ks/Yd77Lcj0PuYBEV8DJEAH9ByUw69hIBa+Y+sRkbVmmao0b1EvzB5ho47tZySH4 +EbSighsN6IzgpeEcccrDLZBDw+6ZLH1BSDnIAHINgDkjoTon7QfKMo80yrudZxN9 +Me1K2zV6zrOJ42SdPkdO07e9qxIWELtm6Bp3TCrguRZpZhSDTkrzb6uFanDGm86T +q3U2o6Wqn0XWon8Xx2/59ec1UaV1xQe+Js57Pyk6dGsXeU7PTAppdVjb66jd8ebM +oxhTpcWlWqHPN2qxn9PU6w8CQNKuaM68xUbj7viXiO7IpwF6oSOv8zEsKm8Sd9w8 +UZ1A9Joqe4UpHz7D1TeObgkCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMC +BeAwHQYDVR0OBBYEFBv07DRCuotnrFXyN120aKnYXlh7MA0GCSqGSIb3DQEBBQUA +A4ICAQCV9xyZckJP0726P3p1uwE6rc5re7c9XTtGUeqaNpRwNhw7/Lqdiw1ENgit +pnOCvCPt+VoJj51iEcGUfGFmH4u5Ctw6tesiVN6j5YqUEB+EUm3+J8jly6WOqYMW +lQ1sPleF4eyCBUdtKK0NhPpAoJb0hKrR4Qu3keJHTwWX+BCg6Fe97UhlVXXa5TTo +8SCV1kCMQr+02VXIMOjVztgdMGWQOevig+0RA80HwOHEkYSgl45tIuZ1dyF8MotI +7dayGS6vJq19bM4J4Xi2cmFgIpK430JrNGtfNe/x08Z/kgU80Ah3AWb3V7hl3tPS +sb+TsYyjJ+bU4iubzZ2+MYJbU91avTkFX4xW8n+bt+/mB5a/itmNu2KYht6qkcP+ +57unH/D9H2ymBATwwlGhkYya7vmHQjd+nCdyWdxgqI7RgZfxFcPYqU6aCemBdjk2 +swih5V6XN7pDjwYacGk7/nmmXi0mBOm8X1fJ0IDCDUvHDt0E5RVJndf/7qMcBFZ9 +4qDTORpZvYWw61TqgYvhF5Sl/uMM0HRC7kr0ZpBJS2S8RzX1smCOdAXQptKUtOAP +Sz816irgJFjBbtBlblj34ZACrkAjJemAmtKn6l38bfhFD9tTkVUyRuNqwFQKWkzo +Gh6mMz7+7batz2o8L7JsR3XxKUMxacMMQlZb2biZe/8rUIc0Lg== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/test.key b/third_party/heimdal/lib/hx509/data/test.key new file mode 100644 index 0000000..03de157 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDaHU3KUZ3xn9ek +ekX4dZhmssV9U95CNXSBzR6f80PXp4N/+6LOPEQ3gE8hNqb2yVF0nuKbv63k63IR +ZDaIs6mRY8fuOMT1jAZx5Qm361ddv9tbcgfFKehvM7OiJ+8fUPBVM2NBI+Cy9yF3 +S6udcyq7tk6If3zlxjc+tiDBVz5tV3jvDUfpQef6ti0yP0IFjVav9cS4bpka5wfV +oT8pfc6yOaarBnriJjnYlp47yK95PpokTkuyr+QHDnHcL3Anlzyi+mmbV0vFU14o +DLDHVx+isiYPX7/TRXiQWiz8amcztsF+zRfAWJ66hcUVWlpn278vBc042ZTJlX+b +aLBi/zeSz9h3vstyPQ+5gERXwMkQAf0HJTDr2EgFr5j6xGRtWaZqjRvUS/MHmGjj +u1nJIfgRtKKCGw3ojOCl4RxxysMtkEPD7pksfUFIOcgAcg2AOSOhOiftB8oyjzTK +u51nE30x7UrbNXrOs4njZJ0+R07Tt72rEhYQu2boGndMKuC5FmlmFINOSvNvq4Vq +cMabzpOrdTajpaqfRdaifxfHb/n15zVRpXXFB74mzns/KTp0axd5Ts9MCml1WNvr +qN3x5syjGFOlxaVaoc83arGf09TrDwJA0q5ozrzFRuPu+JeI7sinAXqhI6/zMSwq +bxJ33DxRnUD0mip7hSkfPsPVN45uCQIDAQABAoICAQDC4zgktLSJtyb5Yf+vN3PL +H6VyjEOlqRnG+T6J8NUHljfbXT5lRFg3tz/9D1Y0YEGWEHmubKC2UOIFRCOuFcpH +jH6SDst+E3WWwu3iFjhkHg+kL8ldlEqJQgsZstDojGuR1W60P5iAkGyoqUZYUxU1 +0HlvYWp57JhkQlwWJRw0mtoFzzoX47mhvLG5megmCdoRM2po2PmYniHT8lX7ftv3 +R6fyXMHj3AAH1Nzh0jln/lXAZu0gZiU7YN6/vOtblLirb1B5apDbadhRtLUoCGLN +/pwfVJCT+Bj38nsLtw8rl/pgkGTOiuCZDPnCUI9DCYhUPbzXNSLK0/fHJs2kRyKh +Nv+skWwmHdkCnzIliutxMlzehRHvRINoQ+/U/mNTE1FaNYnNEnSxpUSMKnPYUyTD +YBhjFjtwkRpRDzbbcMBQk7Tbj2aISvFiAz/KOtRBDmBx70IxzxvqZ/5s94lyHZ5H +fozf6LgBfJ5dmboNqHA18oBTAQDO2UBrIxyPSYExWdJ4o0vpTqwpmk8RTwgBsYfU +EfDj3UqO5KJHTJAqdqdhXhz2c5J6EAyxDDItNg10rEVQVQbGbTPLtI8spjWfwJ6g +P5L0j/cJx+nxNQvhrIMQgJfCrZS92PL6Yt0OqTS44m8mJgmt4z9OqZUtoT21fmcS +uIOMYOY/NZBc+wMJ27UoeQKCAQEA8w6aZ+NAqmdDfEi/37XsbadsxDppPZ+/Ss2b +aWOYwNU8P65rt3+EWjLrwMugiKOH1063QmZYcj74C4iaAhLblBiQH24YtiJi9tYs +JCcFLWp01ZEqcxqBqI2kaHd9tuIaANGM+nKZH2MwTkzZ5IX1eAqZ0qgkC7Dx0JvO +x1fXuhRTuFwTSkKZM3w4ba5G4DgczmKQr2SXm19PsMF61YX0n7HFuss85Z6xkONH +gF6yokmPT7k/Ly4PLXZ9kycNx2EI5s1B79iAjaJAK8ifaEfUNNIi/xBf97oX6+hy +AhO8aiC7snt6Tf2DNaJCZR1IKeO0M+5pkN6DZfV0hbQ9ulhD6wKCAQEA5bqt2VJJ +9Vuuu8jcRlHfc4Cbubu+bMt9gbVp33ckAtRtQGQM4tHoHdd2hv4q8lV/f/K3m6Ps +EMGeQ6QBuCWtkqD659eI5hvkchKjF+YGx/jt7k6EUlVUU1bfKXCgQv6W2VmrckzG +ULsedOBLeT0Keppgw4kHqx+o/5DB9G3pZnVBITqGUP471q5X+c3BbAwN+9q8yRyY +BimYJZKx0qgmpHSZ+4l3L6eLlcQiHev7TxGw1sGkpt3OF8NmR5PEzXUYC8qoi8na +neLwTs9NKyb6hmOwTNJiWR5PNxWJeURxfl6GIfoxyUjptIrc5dve6k+ESxGgsSI1 +vyXgRUeiMlP82wKCAQEAuqx2jl+NZNLWk/fT1d+FbFpwQO2Tso6kfrEXMYQa589d +7JLrjA1V+2ishHBgJVFjnUuJmGe+elA+da0+i2UsW7vZxSnrtMcINwga8tE9OrpO +bVCGx8yN1ISkxs8vMGzLB+HpYtjtHZwyl5CSsN7pvn510cLtnEUUE+H2mEexGetO +uYOOFTS9MTuwoxx8tuyhwykUcoDRp7U2IU0YKDIvxQ7mDCbX6ItPWTYVzlPs4pOY +i+R80KGRaptcqs4N2Rl/mrP+dlVTtnPs0TPOqmqwYrkZw8gxzLOSd88Y8NtzlBb7 +0YLgVlHkmia606n/qJyH5HKxhWBAjuhLy/y4hAwSbQKB/1xtv4SwlxEg0iy7o+Sn +DEBsfjs8TmF3fgex9ebzCIoa7dn6ZzTbP4jCJ+4oVR8rRyEzhqwYR+J2BDcyxX5R +qoRUQJ8HGQ18K226EeSLqC7M+O3oqVR3AHaHfUIvDkvmIstQSKq0ORZCMv7TP4qI +BK9PbZ8+gtdW5aftlhvCHSYcBxhXc7MilvDJNJxNLIVMVFQArfQ8jO3tzklPvDwF +a4a/YzTRGiMSRhb70r43M+WcOIovXw/ELidhdsVVrtj7Q7F62FVl4Y+kvwr2XRX/ +mMx5T3WZL/irOTPwdl9UKlWtskn5YA6cR2tcc4QH8qhTVebeMMkT+ovtsU4uhBO7 +twKCAQAnvazlAlCSy/OeRqucmyqKjWTMEey6c/5dYlCkirF9J5o3n1YHhOSp8DY8 +iEjyl6ptsASapBhD6BpI4AwI6u92WBEwG15bleMlctVmtj7v39AFwNwSvvZtBZcZ +jJ+TWaTT0nMvP90cZe5ql2DTrp/Mp4K9+3oR5qk9+EszobSoHxpgDzLogG+Zp/k/ +2NMj125uhuC0GTV5lKcrY6JquXPtqFBKOiBLr3j5sRe+iZ4UqZEjTo91nrV2E3HD +kFJSP1weCD2HQ48T74nS775yrQnR+mWAJjuLpyDW5UXIDpvYlSbnmJ08+4C5Mu/e +UK2bY3PmI10F5vBYLQpLlCYUyBDf +-----END PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/data/test.p12 b/third_party/heimdal/lib/hx509/data/test.p12 new file mode 100644 index 0000000..32d9c81 Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/test.p12 differ diff --git a/third_party/heimdal/lib/hx509/data/win-u16-in-printablestring.der b/third_party/heimdal/lib/hx509/data/win-u16-in-printablestring.der new file mode 100644 index 0000000..5f6178f Binary files /dev/null and b/third_party/heimdal/lib/hx509/data/win-u16-in-printablestring.der differ diff --git a/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-ca.pem b/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-ca.pem new file mode 100644 index 0000000..32685d1 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-ca.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICijCCAfOgAwIBAgIJAOSnzE4Qx2H+MA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTQwHhcNMDYwOTA3MTYzMzE4WhcNMDYxMDA3MTYzMzE4WjA5MQswCQYDVQQGEwJK +UDEUMBIGA1UEChMLQ0EgVEVTVCAxLTQxFDASBgNVBAMTC0NBIFRFU1QgMS00MIGd +MA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDZfFjkPDZeorxWqk7/DKM2d/9Nao28 +dM6T5sb5L41hD5C1kXV6MJev5ALASSxtI6OVOmZO4gfubnsvcj0NTZO4SeF1yL1r +VDPdx7juQI1cbDiG/EwIMW29UIdj9h052JTmEbpT0RuP/4JWmAWrdO5UE40xua7S +z2/6+DB2ZklFoQIBA6OBmzCBmDAdBgNVHQ4EFgQU340JbeYcg6V9zi8aozy48aIh +tfgwaQYDVR0jBGIwYIAU340JbeYcg6V9zi8aozy48aIhtfihPaQ7MDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTSCCQDkp8xOEMdh/jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABsH +aJ/c/3cGHssi8IvVRci/aavqj607y7l22nKDtG1p4KAjnfNhBMOhRhFv00nJnokK +y0uc4DIegAW1bxQjqcMNNEmGbzAeixH/cRCot8C1LobEQmxNWCY2DJLWoI3wwqr8 +uUSnI1CDZ5402etkCiNXsDy/eYDrF+2KonkIWRrr +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-cert.pem b/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-cert.pem new file mode 100644 index 0000000..b0726ea --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/yutaka-pad-broken-cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIICzTCCAjagAwIBAgIJAOSnzE4Qx2H/MA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTQwHhcNMDYwOTA3MTY0MDM3WhcNMDcwOTA3MTY0MDM3WjBPMQswCQYDVQQGEwJK +UDEOMAwGA1UECBMFVG9reW8xFjAUBgNVBAoTDVRFU1QgMiBDTElFTlQxGDAWBgNV +BAMTD3d3dzIuZXhhbXBsZS5qcDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +vSpZ6ig9DpeKB60h7ii1RitNuvkn4INOfEXjCjPSFwmIbGJqnyWvKTiMKzguEYkG +6CZAbsx44t3kvsVDeUd5WZBRgMoeQd1tNJBU4BXxOA8bVzdwstzaPeeufQtZDvKf +M4ej+fo/j9lYH9udCug1huaNybcCtijzGonkddX4JEUCAwEAAaOBxjCBwzAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUK0DZtd8K1P2ij9gVKUNcHlx7uCIwaQYDVR0jBGIwYIAU +340JbeYcg6V9zi8aozy48aIhtfihPaQ7MDkxCzAJBgNVBAYTAkpQMRQwEgYDVQQK +EwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAxLTSCCQDkp8xOEMdh/jAN +BgkqhkiG9w0BAQUFAAOBgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAUKJ+eFJYSvXwGF2wxzDXj+x5YCItrHFmrEy4AXXAW+H0NgJVNvqRY/O +Kw== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-ca.pem b/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-ca.pem new file mode 100644 index 0000000..32685d1 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-ca.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICijCCAfOgAwIBAgIJAOSnzE4Qx2H+MA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTQwHhcNMDYwOTA3MTYzMzE4WhcNMDYxMDA3MTYzMzE4WjA5MQswCQYDVQQGEwJK +UDEUMBIGA1UEChMLQ0EgVEVTVCAxLTQxFDASBgNVBAMTC0NBIFRFU1QgMS00MIGd +MA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDZfFjkPDZeorxWqk7/DKM2d/9Nao28 +dM6T5sb5L41hD5C1kXV6MJev5ALASSxtI6OVOmZO4gfubnsvcj0NTZO4SeF1yL1r +VDPdx7juQI1cbDiG/EwIMW29UIdj9h052JTmEbpT0RuP/4JWmAWrdO5UE40xua7S +z2/6+DB2ZklFoQIBA6OBmzCBmDAdBgNVHQ4EFgQU340JbeYcg6V9zi8aozy48aIh +tfgwaQYDVR0jBGIwYIAU340JbeYcg6V9zi8aozy48aIhtfihPaQ7MDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTSCCQDkp8xOEMdh/jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABsH +aJ/c/3cGHssi8IvVRci/aavqj607y7l22nKDtG1p4KAjnfNhBMOhRhFv00nJnokK +y0uc4DIegAW1bxQjqcMNNEmGbzAeixH/cRCot8C1LobEQmxNWCY2DJLWoI3wwqr8 +uUSnI1CDZ5402etkCiNXsDy/eYDrF+2KonkIWRrr +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-cert.pem b/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-cert.pem new file mode 100644 index 0000000..9a89e59 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/yutaka-pad-ok-cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIICzTCCAjagAwIBAgIJAOSnzE4Qx2H/MA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTQwHhcNMDYwOTA3MTY0MDM3WhcNMDcwOTA3MTY0MDM3WjBPMQswCQYDVQQGEwJK +UDEOMAwGA1UECBMFVG9reW8xFjAUBgNVBAoTDVRFU1QgMiBDTElFTlQxGDAWBgNV +BAMTD3d3dzIuZXhhbXBsZS5qcDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +vSpZ6ig9DpeKB60h7ii1RitNuvkn4INOfEXjCjPSFwmIbGJqnyWvKTiMKzguEYkG +6CZAbsx44t3kvsVDeUd5WZBRgMoeQd1tNJBU4BXxOA8bVzdwstzaPeeufQtZDvKf +M4ej+fo/j9lYH9udCug1huaNybcCtijzGonkddX4JEUCAwEAAaOBxjCBwzAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUK0DZtd8K1P2ij9gVKUNcHlx7uCIwaQYDVR0jBGIwYIAU +340JbeYcg6V9zi8aozy48aIhtfihPaQ7MDkxCzAJBgNVBAYTAkpQMRQwEgYDVQQK +EwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAxLTSCCQDkp8xOEMdh/jAN +BgkqhkiG9w0BAQUFAAOBgQCkGhwCDLRwWbDnDFReXkIZ1/9OhfiR8yL1idP9iYVU +cSoWxSHPBWkv6LORFS03APcXCSzDPJ9pxTjFjGGFSI91fNrzkKdHU/+0WCF2uTh7 +Dz2blqtcmnJqMSn1xHxxfM/9e6M3XwFUMf7SGiKRAbDfsauPafEPTn83vSeKj1lg +Dw== +-----END CERTIFICATE----- diff --git a/third_party/heimdal/lib/hx509/data/yutaka-pad.key b/third_party/heimdal/lib/hx509/data/yutaka-pad.key new file mode 100644 index 0000000..1763623 --- /dev/null +++ b/third_party/heimdal/lib/hx509/data/yutaka-pad.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQC9KlnqKD0Ol4oHrSHuKLVGK026+Sfgg058ReMKM9IXCYhsYmqf +Ja8pOIwrOC4RiQboJkBuzHji3eS+xUN5R3lZkFGAyh5B3W00kFTgFfE4DxtXN3Cy +3No95659C1kO8p8zh6P5+j+P2Vgf250K6DWG5o3JtwK2KPMaieR11fgkRQIDAQAB +AoGBAJCYvwJun713uNsFTNpv46EvmMtDiWfk9ymnglVaJ03Uy6ON11Kvy6UGxJ6E +4zIkPFNYaghH5GAGncP1pg4exHKRGJTNcQbMf9iOsCTOuvKSWbBZpnJcFllKyESK +PTt72D6x/cuzDXVTeWvQMoOILa09szW7aqFNIdxae4Vq7a4BAkEA6MoehuRtZ4N9 +Jtc9cIpSKOOatZ1UajWEFV2yVHaDED2kkWxKjppPzRn06LzX8LWm1RT0qe3Zyasi +iXCXlno/+QJBANAGvY+k/+OvzWnv1yTKO8OmrMqkSzh3KAhFbiVWdQaqMSCWtKYk +GoOKnq0PB73ExhdbTFmxC4KBPHTC2guOca0CQCD78pNebnoKUYNdYCFAGCAfD97H +6hwadRqp6gi5uhxk/5pzY6UNDF2dXexURayfsIHktD4Xq5I9o2kiAPibXdECQQDC +KihwlL9K02JVSMl0y1XxDfclxSd4cq9o2PUv4HymVeA43LGMiRI+SPpF6Ut+ctW6 +IzsmVDu7+chl6yD9vFyZAkA3Auv9UxKL3kPtvu5G/lrCVmwzVfAzuwtnmSfp1+M5 +yTYBz+VFSsYrdlDZ3jdLnFzVOMiIm9pZca/L93QjmXJ+ +-----END RSA PRIVATE KEY----- diff --git a/third_party/heimdal/lib/hx509/doxygen.c b/third_party/heimdal/lib/hx509/doxygen.c new file mode 100644 index 0000000..a6d3d9c --- /dev/null +++ b/third_party/heimdal/lib/hx509/doxygen.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** @mainpage Heimdal PKIX/X.509 library + * + * @section intro Introduction + * + * Heimdal libhx509 library is a implementation of the PKIX/X.509 and + * related protocols. + * + * PKIX/X.509 is ... + * + * + * Sections in this manual are: + * - @ref page_name + * - @ref page_cert + * - @ref page_keyset + * - @ref page_error + * - @ref page_lock + * - @ref page_cms + * - @ref page_ca + * - @ref page_revoke + * - @ref page_print + * - @ref page_env + * + * The project web page: + * http://www.h5l.org/ + * + */ + +/** @defgroup hx509 hx509 library */ + +/** @defgroup hx509_error hx509 error functions + * See the @ref page_error for description and examples. */ +/** @defgroup hx509_cert hx509 certificate functions + * See the @ref page_cert for description and examples. */ +/** @defgroup hx509_keyset hx509 certificate store functions + * See the @ref page_keyset for description and examples. */ +/** @defgroup hx509_cms hx509 CMS/pkcs7 functions + * See the @ref page_cms for description and examples. */ +/** @defgroup hx509_crypto hx509 crypto functions */ +/** @defgroup hx509_misc hx509 misc functions */ +/** @defgroup hx509_name hx509 name functions + * See the @ref page_name for description and examples. */ +/** @defgroup hx509_revoke hx509 revokation checking functions + * See the @ref page_revoke for description and examples. */ +/** @defgroup hx509_verify hx509 verification functions */ +/** @defgroup hx509_lock hx509 lock functions + * See the @ref page_lock for description and examples. */ +/** @defgroup hx509_query hx509 query functions */ +/** @defgroup hx509_ca hx509 CA functions + * See the @ref page_ca for description and examples. */ +/** @defgroup hx509_peer hx509 certificate selecting functions */ +/** @defgroup hx509_print hx509 printing functions */ +/** @defgroup hx509_env hx509 environment functions */ diff --git a/third_party/heimdal/lib/hx509/env.c b/third_party/heimdal/lib/hx509/env.c new file mode 100644 index 0000000..7970438 --- /dev/null +++ b/third_party/heimdal/lib/hx509/env.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2007 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_env Hx509 environment functions + * + * See the library functions here: @ref hx509_env + */ + +/** + * Add a new key/value pair to the hx509_env. + * + * @param context A hx509 context. + * @param env environment to add the environment variable too. + * @param key key to add + * @param value value to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_env + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_env_add(hx509_context context, hx509_env *env, + const char *key, const char *value) +{ + hx509_env n; + + n = malloc(sizeof(*n)); + if (n == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + n->type = env_string; + n->next = NULL; + n->name = strdup(key); + if (n->name == NULL) { + free(n); + return ENOMEM; + } + n->u.string = strdup(value); + if (n->u.string == NULL) { + free(n->name); + free(n); + return ENOMEM; + } + + /* add to tail */ + if (*env) { + hx509_env e = *env; + while (e->next) + e = e->next; + e->next = n; + } else + *env = n; + + return 0; +} + +/** + * Add a new key/binding pair to the hx509_env. + * + * @param context A hx509 context. + * @param env environment to add the environment variable too. + * @param key key to add + * @param list binding list to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_env + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_env_add_binding(hx509_context context, hx509_env *env, + const char *key, hx509_env list) +{ + hx509_env n; + + n = malloc(sizeof(*n)); + if (n == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + n->type = env_list; + n->next = NULL; + n->name = strdup(key); + if (n->name == NULL) { + free(n); + return ENOMEM; + } + n->u.list = list; + + /* add to tail */ + if (*env) { + hx509_env e = *env; + while (e->next) + e = e->next; + e->next = n; + } else + *env = n; + + return 0; +} + + +/** + * Search the hx509_env for a length based key. + * + * @param context A hx509 context. + * @param env environment to add the environment variable too. + * @param key key to search for. + * @param len length of key. + * + * @return the value if the key is found, NULL otherwise. + * + * @ingroup hx509_env + */ + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +hx509_env_lfind(hx509_context context, hx509_env env, + const char *key, size_t len) +{ + while(env) { + if (strncmp(key, env->name ,len) == 0 + && env->name[len] == '\0' && env->type == env_string) + return env->u.string; + env = env->next; + } + return NULL; +} + +/** + * Search the hx509_env for a key. + * + * @param context A hx509 context. + * @param env environment to add the environment variable too. + * @param key key to search for. + * + * @return the value if the key is found, NULL otherwise. + * + * @ingroup hx509_env + */ + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +hx509_env_find(hx509_context context, hx509_env env, const char *key) +{ + while(env) { + if (strcmp(key, env->name) == 0 && env->type == env_string) + return env->u.string; + env = env->next; + } + return NULL; +} + +/** + * Search the hx509_env for a binding. + * + * @param context A hx509 context. + * @param env environment to add the environment variable too. + * @param key key to search for. + * + * @return the binding if the key is found, NULL if not found. + * + * @ingroup hx509_env + */ + +hx509_env +hx509_env_find_binding(hx509_context context, + hx509_env env, + const char *key) +{ + while(env) { + if (strcmp(key, env->name) == 0 && env->type == env_list) + return env->u.list; + env = env->next; + } + return NULL; +} + +static void +env_free(hx509_env b) +{ + while(b) { + hx509_env next = b->next; + + if (b->type == env_string) + free(b->u.string); + else if (b->type == env_list) + env_free(b->u.list); + + free(b->name); + free(b); + b = next; + } +} + +/** + * Free an hx509_env environment context. + * + * @param env the environment to free. + * + * @ingroup hx509_env + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_env_free(hx509_env *env) +{ + if (*env) + env_free(*env); + *env = NULL; +} diff --git a/third_party/heimdal/lib/hx509/error.c b/third_party/heimdal/lib/hx509/error.c new file mode 100644 index 0000000..aee4f79 --- /dev/null +++ b/third_party/heimdal/lib/hx509/error.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_error Hx509 error reporting functions + * + * See the library functions here: @ref hx509_error + */ + +struct hx509_error_data { + hx509_error next; + int code; + char *msg; +}; + +/** + * Resets the error strings the hx509 context. + * + * @param context A hx509 context. + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_clear_error_string(hx509_context context) +{ + if (context) { + heim_release(context->error); + context->error = NULL; + } +} + +/** + * Add an error message to the hx509 context. + * + * @param context A hx509 context. + * @param flags + * - HX509_ERROR_APPEND appends the error string to the old messages + (code is updated). + * @param code error code related to error message + * @param fmt error message format + * @param ap arguments to error message format + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_set_error_stringv(hx509_context context, int flags, int code, + const char *fmt, va_list ap) +{ + heim_error_t msg; + + if (context == NULL) + return; + + msg = heim_error_createv(code, fmt, ap); + if (msg) { + if (flags & HX509_ERROR_APPEND) + heim_error_append(msg, context->error); + heim_release(context->error); + } + context->error = msg; +} + +/** + * See hx509_set_error_stringv(). + * + * @param context A hx509 context. + * @param flags + * - HX509_ERROR_APPEND appends the error string to the old messages + (code is updated). + * @param code error code related to error message + * @param fmt error message format + * @param ... arguments to error message format + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_set_error_string(hx509_context context, int flags, int code, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + hx509_set_error_stringv(context, flags, code, fmt, ap); + va_end(ap); +} + +/** + * Sets ENOMEM as the error on a hx509 context. + * + * @param context A hx509 context. + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_enomem(hx509_context context) +{ + return heim_enomem(context->hcontext); +} + +/** + * Get an error string from context associated with error_code. + * + * @param context A hx509 context. + * @param error_code Get error message for this error code. + * + * @return error string, free with hx509_free_error_string(). + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION char * HX509_LIB_CALL +hx509_get_error_string(hx509_context context, int error_code) +{ + heim_string_t s = NULL; + const char *cstr = NULL; + char *str; + + if (context) { + if (context->error && + heim_error_get_code(context->error) == error_code && + (s = heim_error_copy_string(context->error))) + cstr = heim_string_get_utf8(s); + + if (cstr == NULL) + cstr = com_right(context->et_list, error_code); + + if (cstr == NULL && error_code > -1) + cstr = strerror(error_code); + } /* else this could be an error in hx509_context_init() */ + + if (cstr == NULL) + cstr = error_message(error_code); /* never returns NULL */ + + str = strdup(cstr); + heim_release(s); + return str; +} + +/** + * Free error string returned by hx509_get_error_string(). + * + * @param str error string to free. + * + * @ingroup hx509_error + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_free_error_string(char *str) +{ + free(str); +} + +/** + * Print error message and fatally exit from error code + * + * @param context A hx509 context. + * @param exit_code exit() code from process. + * @param error_code Error code for the reason to exit. + * @param fmt format string with the exit message. + * @param ... argument to format string. + * + * @ingroup hx509_error + */ + +HX509_LIB_NORETURN_FUNCTION + __attribute__ ((__noreturn__, __format__ (__printf__, 4, 5))) +void HX509_LIB_CALL +hx509_err(hx509_context context, int exit_code, + int error_code, const char *fmt, ...) +{ + va_list ap; + const char *msg; + char *str; + int ret; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + msg = hx509_get_error_string(context, error_code); + if (msg == NULL) + msg = "no error"; + + errx(exit_code, "%s: %s", ret != -1 ? str : "ENOMEM", msg); +} diff --git a/third_party/heimdal/lib/hx509/file.c b/third_party/heimdal/lib/hx509/file.c new file mode 100644 index 0000000..00f723c --- /dev/null +++ b/third_party/heimdal/lib/hx509/file.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_map_file_os(const char *fn, heim_octet_string *os) +{ + size_t length; + void *data; + int ret; + + ret = rk_undumpdata(fn, &data, &length); + + os->data = data; + os->length = length; + + return ret; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_unmap_file_os(heim_octet_string *os) +{ + rk_xfree(os->data); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_write_file(const char *fn, const void *data, size_t length) +{ + rk_dumpdata(fn, data, length); + return 0; +} + +/* + * + */ + +static void +print_pem_stamp(FILE *f, const char *type, const char *str) +{ + fprintf(f, "-----%s %s-----\n", type, str); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_pem_write(hx509_context context, const char *type, + hx509_pem_header *headers, FILE *f, + const void *data, size_t size) +{ + const char *p = data; + size_t length; + char *line; + +#define ENCODE_LINE_LENGTH 54 + + print_pem_stamp(f, "BEGIN", type); + + while (headers) { + fprintf(f, "%s: %s\n%s", + headers->header, headers->value, + headers->next ? "" : "\n"); + headers = headers->next; + } + + while (size > 0) { + ssize_t l; + + length = size; + if (length > ENCODE_LINE_LENGTH) + length = ENCODE_LINE_LENGTH; + + l = rk_base64_encode(p, length, &line); + if (l < 0) { + hx509_set_error_string(context, 0, ENOMEM, + "malloc - out of memory"); + return ENOMEM; + } + size -= length; + fprintf(f, "%s\n", line); + p += length; + free(line); + } + + print_pem_stamp(f, "END", type); + + return 0; +} + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_pem_add_header(hx509_pem_header **headers, + const char *header, const char *value) +{ + hx509_pem_header *h; + + h = calloc(1, sizeof(*h)); + if (h == NULL) + return ENOMEM; + h->header = strdup(header); + if (h->header == NULL) { + free(h); + return ENOMEM; + } + h->value = strdup(value); + if (h->value == NULL) { + free(h->header); + free(h); + return ENOMEM; + } + + h->next = *headers; + *headers = h; + + return 0; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_pem_free_header(hx509_pem_header *headers) +{ + hx509_pem_header *h; + while (headers) { + h = headers; + headers = headers->next; + free(h->header); + free(h->value); + free(h); + } +} + +/* + * + */ + +HX509_LIB_FUNCTION const char * HX509_LIB_CALL +hx509_pem_find_header(const hx509_pem_header *h, const char *header) +{ + while(h) { + if (strcmp(header, h->header) == 0) + return h->value; + h = h->next; + } + return NULL; +} + + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_pem_read(hx509_context context, + FILE *f, + hx509_pem_read_func func, + void *ctx) +{ + hx509_pem_header *headers = NULL; + char *type = NULL; + void *data = NULL; + size_t len = 0; + char buf[1024]; + int ret = HX509_PARSING_KEY_FAILED; + + enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; + + where = BEFORE; + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + int i; + + i = strcspn(buf, "\n"); + if (buf[i] == '\n') { + buf[i] = '\0'; + if (i > 0) + i--; + } + if (buf[i] == '\r') { + buf[i] = '\0'; + if (i > 0) + i--; + } + + switch (where) { + case BEFORE: + if (strncmp("-----BEGIN ", buf, 11) == 0) { + type = strdup(buf + 11); + if (type == NULL) + break; + p = strchr(type, '-'); + if (p) + *p = '\0'; + where = SEARCHHEADER; + } + break; + case SEARCHHEADER: + p = strchr(buf, ':'); + if (p == NULL) { + where = INDATA; + goto indata; + } + HEIM_FALLTHROUGH; + case INHEADER: + if (buf[0] == '\0') { + where = INDATA; + break; + } + p = strchr(buf, ':'); + if (p) { + *p++ = '\0'; + while (isspace((unsigned char)*p)) + p++; + ret = hx509_pem_add_header(&headers, buf, p); + if (ret) + abort(); + } + break; + case INDATA: + indata: + + if (strncmp("-----END ", buf, 9) == 0) { + where = DONE; + break; + } + + p = emalloc(i); + i = rk_base64_decode(buf, p); + if (i < 0) { + free(p); + goto out; + } + + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + break; + case DONE: + abort(); + } + + if (where == DONE) { + ret = (*func)(context, type, headers, data, len, ctx); + out: + free(data); + data = NULL; + len = 0; + free(type); + type = NULL; + where = BEFORE; + hx509_pem_free_header(headers); + headers = NULL; + if (ret) + break; + } + } + + if (where != BEFORE) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "File ends before end of PEM end tag"); + ret = HX509_PARSING_KEY_FAILED; + } + if (data) + free(data); + if (type) + free(type); + if (headers) + hx509_pem_free_header(headers); + + return ret; +} + +/* + * On modern systems there's no such thing as scrubbing a file. Not this way + * anyways. However, for now we'll cargo-cult this along just as in lib/krb5. + */ +static int +scrub_file(int fd, ssize_t sz) +{ + char buf[128]; + + memset(buf, 0, sizeof(buf)); + while (sz > 0) { + ssize_t tmp; + size_t wr = sizeof(buf) > sz ? (size_t)sz : sizeof(buf); + + tmp = write(fd, buf, wr); + if (tmp == -1) + return errno; + sz -= tmp; + } +#ifdef _MSC_VER + return _commit(fd); +#else + return fsync(fd); +#endif +} + +int +_hx509_erase_file(hx509_context context, const char *fn) +{ + struct stat sb1, sb2; + int ret; + int fd; + + if (fn == NULL) + return 0; + + /* This is based on _krb5_erase_file(), minus file locking */ + ret = lstat(fn, &sb1); + if (ret == -1 && errno == ENOENT) + return 0; + if (ret == -1) { + hx509_set_error_string(context, 0, errno, "hx509_certs_destroy: " + "stat of \"%s\": %s", fn, strerror(errno)); + return errno; + } + + fd = open(fn, O_RDWR | O_BINARY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) + return errno == ENOENT ? 0 : errno; + rk_cloexec(fd); + + if (unlink(fn) < 0) { + ret = errno; + (void) close(fd); + hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: " + "unlinking \"%s\": %s", fn, strerror(ret)); + return ret; + } + + /* check TOCTOU, symlinks */ + ret = fstat(fd, &sb2); + if (ret < 0) { + ret = errno; + hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: " + "fstat of %d, \"%s\": %s", fd, fn, + strerror(ret)); + (void) close(fd); + return ret; + } + if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) { + (void) close(fd); + return EPERM; + } + + /* there are still hard links to this file */ + if (sb2.st_nlink != 0) { + close(fd); + return 0; + } + + ret = scrub_file(fd, sb2.st_size); + (void) close(fd); + return ret; +} diff --git a/third_party/heimdal/lib/hx509/hx509.h b/third_party/heimdal/lib/hx509/hx509.h new file mode 100644 index 0000000..6bd36e9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/hx509.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIMDAL_HX509_H +#define HEIMDAL_HX509_H 1 + +#include +#include +#include +#include +#include + +typedef struct hx509_cert_attribute_data *hx509_cert_attribute; +typedef struct hx509_cert_data *hx509_cert; +typedef struct hx509_certs_data *hx509_certs; +typedef struct hx509_context_data *hx509_context; +typedef struct hx509_crypto_data *hx509_crypto; +typedef struct hx509_lock_data *hx509_lock; +typedef struct hx509_name_data *hx509_name; +typedef struct hx509_private_key *hx509_private_key; +typedef struct hx509_private_key_ops hx509_private_key_ops; +typedef struct hx509_validate_ctx_data *hx509_validate_ctx; +typedef struct hx509_verify_ctx_data *hx509_verify_ctx; +typedef struct hx509_revoke_ctx_data *hx509_revoke_ctx; +typedef struct hx509_query_data hx509_query; +typedef void * hx509_cursor; +typedef struct hx509_request_data *hx509_request; +typedef struct hx509_error_data *hx509_error; +typedef struct hx509_peer_info *hx509_peer_info; +typedef struct hx509_ca_tbs *hx509_ca_tbs; +typedef struct hx509_env_data *hx509_env; +typedef struct hx509_crl *hx509_crl; + +typedef void (*hx509_vprint_func)(void *, const char *, va_list); + +typedef enum { + HX509_SAN_TYPE_UNSUPPORTED = 0, + /* The following correspond to the enum GeneralName_enum values: */ + HX509_SAN_TYPE_EMAIL = 2, + HX509_SAN_TYPE_DNSNAME = 3, + HX509_SAN_TYPE_DN = 4, + HX509_SAN_TYPE_REGISTERED_ID = 7, + /* + * Missing support for: + * - URI SANs + * - IP address SANs + * - various otherName SANs we know about (e.g., DNSSRV) + * + * The following are otherName SAN types, and assigned manually here: + */ + HX509_SAN_TYPE_XMPP = 32, + HX509_SAN_TYPE_PKINIT = 33, + HX509_SAN_TYPE_MS_UPN = 34, + HX509_SAN_TYPE_DNSSRV = 35, /* SRVName [RFC4985] */ + HX509_SAN_TYPE_PERMANENT_ID = 36, /* PermanentIdentifier [RFC4043] */ + HX509_SAN_TYPE_HW_MODULE = 37, /* HardwareModuleName [RFC4108] */ +} hx509_san_type; + +enum { + HX509_VHN_F_ALLOW_NO_MATCH = 1 +}; + +enum { + HX509_VALIDATE_F_VALIDATE = 1, + HX509_VALIDATE_F_VERBOSE = 2 +}; + +enum { + HX509_CRYPTO_PADDING_PKCS7 = 0, + HX509_CRYPTO_PADDING_NONE = 1 +}; + +enum { + HX509_KEY_FORMAT_GUESS = 0, + HX509_KEY_FORMAT_DER = 1, + HX509_KEY_FORMAT_WIN_BACKUPKEY = 2, + HX509_KEY_FORMAT_PKCS8 = 3, +}; +typedef uint32_t hx509_key_format_t; + +struct hx509_cert_attribute_data { + heim_oid oid; + heim_octet_string data; +}; + +typedef enum { + HX509_PROMPT_TYPE_PASSWORD = 0x1, /* password, hidden */ + HX509_PROMPT_TYPE_QUESTION = 0x2, /* question, not hidden */ + HX509_PROMPT_TYPE_INFO = 0x4 /* infomation, reply doesn't matter */ +} hx509_prompt_type; + +typedef struct hx509_prompt { + const char *prompt; + hx509_prompt_type type; + heim_octet_string reply; +} hx509_prompt; + +typedef int (*hx509_prompter_fct)(void *, const hx509_prompt *); + +typedef struct hx509_octet_string_list { + size_t len; + heim_octet_string *val; +} hx509_octet_string_list; + +typedef struct hx509_pem_header { + struct hx509_pem_header *next; + char *header; + char *value; +} hx509_pem_header; + +typedef int +(*hx509_pem_read_func)(hx509_context, const char *, const hx509_pem_header *, + const void *, size_t, void *ctx); + +/* + * Options passed to hx509_query_match_option. + */ +typedef enum { + HX509_QUERY_OPTION_PRIVATE_KEY = 1, + HX509_QUERY_OPTION_KU_ENCIPHERMENT = 2, + HX509_QUERY_OPTION_KU_DIGITALSIGNATURE = 3, + HX509_QUERY_OPTION_KU_KEYCERTSIGN = 4, + HX509_QUERY_OPTION_END = 0xffff +} hx509_query_option; + +/* flags to hx509_certs_init */ +#define HX509_CERTS_CREATE 0x01 +#define HX509_CERTS_UNPROTECT_ALL 0x02 +#define HX509_CERTS_NO_PRIVATE_KEYS 0x04 + +/* flags to hx509_certs_store */ +#define HX509_CERTS_STORE_NO_PRIVATE_KEYS 0x04 +#define HX509_CERTS_STORE_NO_ROOTS 0x08 + + +/* flags to hx509_set_error_string */ +#define HX509_ERROR_APPEND 0x01 + +/* flags to hx509_cms_unenvelope */ +#define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01 +#define HX509_CMS_UE_ALLOW_WEAK 0x02 + +/* flags to hx509_cms_envelope_1 */ +#define HX509_CMS_EV_NO_KU_CHECK 0x01 +#define HX509_CMS_EV_ALLOW_WEAK 0x02 +#define HX509_CMS_EV_ID_NAME 0x04 + +/* flags to hx509_cms_verify_signed */ +#define HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH 0x01 +#define HX509_CMS_VS_NO_KU_CHECK 0x02 +#define HX509_CMS_VS_ALLOW_ZERO_SIGNER 0x04 +#define HX509_CMS_VS_NO_VALIDATE 0x08 + +/* flags from hx509_cms_verify_signed_ext (out verify_flags) */ +#define HX509_CMS_VSE_VALIDATED 0x01 + +/* selectors passed to hx509_crypto_select and hx509_crypto_available */ +#define HX509_SELECT_ALL 0 +#define HX509_SELECT_DIGEST 1 +#define HX509_SELECT_PUBLIC_SIG 2 +#define HX509_SELECT_PUBLIC_ENC 3 +#define HX509_SELECT_SECRET_ENC 4 + +/* flags to hx509_ca_tbs_set_template */ +#define HX509_CA_TEMPLATE_SUBJECT 1 +#define HX509_CA_TEMPLATE_SERIAL 2 +#define HX509_CA_TEMPLATE_NOTBEFORE 4 +#define HX509_CA_TEMPLATE_NOTAFTER 8 +#define HX509_CA_TEMPLATE_SPKI 16 +#define HX509_CA_TEMPLATE_KU 32 +#define HX509_CA_TEMPLATE_EKU 64 +#define HX509_CA_TEMPLATE_PKINIT_MAX_LIFE 128 + +/* flags hx509_cms_create_signed* */ +#define HX509_CMS_SIGNATURE_DETACHED 0x01 +#define HX509_CMS_SIGNATURE_ID_NAME 0x02 +#define HX509_CMS_SIGNATURE_NO_SIGNER 0x04 +#define HX509_CMS_SIGNATURE_LEAF_ONLY 0x08 +#define HX509_CMS_SIGNATURE_NO_CERTS 0x10 + +/* hx509_verify_hostname nametype */ +typedef enum { + HX509_HN_HOSTNAME = 0, + HX509_HN_DNSSRV +} hx509_hostname_type; + +#include +#include + +#endif /* HEIMDAL_HX509_H */ diff --git a/third_party/heimdal/lib/hx509/hx509_err.et b/third_party/heimdal/lib/hx509/hx509_err.et new file mode 100644 index 0000000..9b81675 --- /dev/null +++ b/third_party/heimdal/lib/hx509/hx509_err.et @@ -0,0 +1,110 @@ +# +# Error messages for the hx509 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table hx +prefix HX509 + +# path validation and construction related errors +error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library" +error_code EXTENSION_NOT_FOUND, "Extension not found" +error_code NO_PATH, "Certification path not found" +error_code PARENT_NOT_CA, "Parent certificate is not a CA" +error_code CA_PATH_TOO_DEEP, "CA path too deep" +error_code SIG_ALG_NO_SUPPORTED, "Signature algorithm not supported" +error_code SIG_ALG_DONT_MATCH_KEY_ALG, "Signature algorithm doesn't match certificate key" +error_code CERT_USED_BEFORE_TIME, "Certificate used before it became valid" +error_code CERT_USED_AFTER_TIME, "Certificate used after it became invalid" +error_code PRIVATE_KEY_MISSING, "Private key required for the operation is missing" +error_code ALG_NOT_SUPP, "Algorithm not supported" +error_code ISSUER_NOT_FOUND, "Issuer couldn't be found" +error_code VERIFY_CONSTRAINTS, "Error verifying constraints" +error_code RANGE, "Number too large" +error_code NAME_CONSTRAINT_ERROR, "Error while verifying name constraints" +error_code PATH_TOO_LONG, "Path is too long, failed to find valid anchor" +error_code KU_CERT_MISSING, "Required keyusage for this certificate is missing" +error_code CERT_NOT_FOUND, "Certificate not found" +error_code UNKNOWN_LOCK_COMMAND, "Unknown lock command" +error_code PARENT_IS_CA, "Parent certificate is a CA" +error_code EXTRA_DATA_AFTER_STRUCTURE, "Extra data was found after the structure" +error_code PROXY_CERT_INVALID, "Proxy certificate is invalid" +error_code PROXY_CERT_NAME_WRONG, "Proxy certificate name is wrong" +error_code NAME_MALFORMED, "Name is malformed" +error_code CERTIFICATE_MALFORMED, "Certificate is malformed" +error_code CERTIFICATE_MISSING_EKU, "Certificate is missing a required EKU" +error_code PROXY_CERTIFICATE_NOT_CANONICALIZED, "Proxy certificate not canonicalized" +error_code NO_ITEM, "No such item / iteration end" + +# cms related errors +index 32 +prefix HX509_CMS +error_code FAILED_CREATE_SIGATURE, "Failed to create signature" +error_code MISSING_SIGNER_DATA, "Missing signer data" +error_code SIGNER_NOT_FOUND, "Couldn't find signers certificate" +error_code NO_DATA_AVAILABLE, "No data to perform the operation on" +error_code INVALID_DATA, "Data in the message is invalid" +error_code PADDING_ERROR, "Padding in the message invalid" +error_code NO_RECIPIENT_CERTIFICATE, "Couldn't find recipient certificate" +error_code DATA_OID_MISMATCH, "Mismatch bewteen signed type and unsigned type" + +# crypto related errors +index 64 +prefix HX509_CRYPTO +error_code INTERNAL_ERROR, "Internal error in the crypto engine" +error_code EXTERNAL_ERROR, "External error in the crypto engine" +error_code SIGNATURE_MISSING, "Signature missing for data" +error_code BAD_SIGNATURE, "Signature is not valid" +error_code SIG_NO_CONF, "Sigature doesn't provide confidentiality" +error_code SIG_INVALID_FORMAT, "Invalid format on signature" +error_code OID_MISMATCH, "Mismatch between oids" +error_code NO_PROMPTER, "No prompter function defined" +error_code SIGNATURE_WITHOUT_SIGNER, "Signature requires signer, but none available" +error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed" +error_code RSA_PRIVATE_ENCRYPT, "RSA private encyption failed" +error_code RSA_PUBLIC_DECRYPT, "RSA public decryption failed" +error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed" +error_code ALGORITHM_BEST_BEFORE, "Algorithm has passed its best before date" +error_code KEY_FORMAT_UNSUPPORTED, "Key format is unsupported" + +# revoke related errors +index 96 +prefix HX509 +error_code CRL_USED_BEFORE_TIME, "CRL used before it became valid" +error_code CRL_USED_AFTER_TIME, "CRL used after it became invalid" +error_code CRL_INVALID_FORMAT, "CRL has invalid format" +error_code CERT_REVOKED, "Certificate is revoked" +error_code REVOKE_STATUS_MISSING, "No revoke status found for certificates" +error_code CRL_UNKNOWN_EXTENSION, "Unknown extension" +error_code REVOKE_WRONG_DATA, "Got wrong CRL/OCSP data from server" +error_code REVOKE_NOT_SAME_PARENT, "Doesn't have same parent as other certificates" +error_code CERT_NOT_IN_OCSP, "Certificates not in OCSP reply" + +# misc error +index 108 +error_code LOCAL_ATTRIBUTE_MISSING, "No local key attribute" +error_code PARSING_KEY_FAILED, "Failed to parse key" +error_code UNSUPPORTED_OPERATION, "Unsupported operation" +error_code UNIMPLEMENTED_OPERATION, "Unimplemented operation" +error_code PARSING_NAME_FAILED, "Failed to parse name" + +# keystore related error +index 128 +prefix HX509_PKCS11 +error_code NO_SLOT, "No smartcard reader/device found" +error_code NO_TOKEN, "No smartcard in reader" +error_code NO_MECH, "No supported mech(s)" +error_code TOKEN_CONFUSED, "Token or slot failed in inconsistent way" +error_code OPEN_SESSION, "Failed to open session to slot" +error_code LOGIN, "Failed to login to slot" +error_code LOAD, "Failed to load PKCS module" + +# pkinit related errors +error_code PIN_INCORRECT, "Incorrect User PIN" +error_code PIN_LOCKED, "User PIN locked" +error_code PIN_NOT_INITIALIZED, "User PIN not initialized" +error_code PIN_EXPIRED, "User PIN expired" + +end diff --git a/third_party/heimdal/lib/hx509/hx_locl.h b/third_party/heimdal/lib/hx509/hx_locl.h new file mode 100644 index 0000000..d653f7d --- /dev/null +++ b/third_party/heimdal/lib/hx509/hx_locl.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#include + +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* + * We use OpenSSL for EC, but to do this we need to disable cross-references + * between OpenSSL and hcrypto bn.h and such. Source files that use OpenSSL EC + * must define HEIM_NO_CRYPTO_HDRS before including this file. + */ + +#define HC_DEPRECATED_CRYPTO +#ifndef HEIM_NO_CRYPTO_HDRS +#include "crypto-headers.h" +#endif + +struct hx509_keyset_ops; +struct hx509_collector; +struct hx509_generate_private_context; +typedef struct hx509_path hx509_path; + +#include + +#include + +typedef void (*_hx509_cert_release_func)(struct hx509_cert_data *, void *); + + +#include "sel.h" + +#include +#include + +struct hx509_peer_info { + hx509_cert cert; + AlgorithmIdentifier *val; + size_t len; +}; + +#define HX509_CERTS_FIND_SERIALNUMBER 1 +#define HX509_CERTS_FIND_ISSUER 2 +#define HX509_CERTS_FIND_SUBJECT 4 +#define HX509_CERTS_FIND_ISSUER_KEY_ID 8 +#define HX509_CERTS_FIND_SUBJECT_KEY_ID 16 + +struct hx509_name_data { + Name der_name; +}; + +struct hx509_path { + size_t len; + hx509_cert *val; +}; + +struct hx509_query_data { + int match; +#define HX509_QUERY_FIND_ISSUER_CERT 0x000001 +#define HX509_QUERY_MATCH_SERIALNUMBER 0x000002 +#define HX509_QUERY_MATCH_ISSUER_NAME 0x000004 +#define HX509_QUERY_MATCH_SUBJECT_NAME 0x000008 +#define HX509_QUERY_MATCH_SUBJECT_KEY_ID 0x000010 +#define HX509_QUERY_MATCH_ISSUER_ID 0x000020 +#define HX509_QUERY_PRIVATE_KEY 0x000040 +#define HX509_QUERY_KU_ENCIPHERMENT 0x000080 +#define HX509_QUERY_KU_DIGITALSIGNATURE 0x000100 +#define HX509_QUERY_KU_KEYCERTSIGN 0x000200 +#define HX509_QUERY_KU_CRLSIGN 0x000400 +#define HX509_QUERY_KU_NONREPUDIATION 0x000800 +#define HX509_QUERY_KU_KEYAGREEMENT 0x001000 +#define HX509_QUERY_KU_DATAENCIPHERMENT 0x002000 +#define HX509_QUERY_ANCHOR 0x004000 +#define HX509_QUERY_MATCH_CERTIFICATE 0x008000 +#define HX509_QUERY_MATCH_LOCAL_KEY_ID 0x010000 +#define HX509_QUERY_NO_MATCH_PATH 0x020000 +#define HX509_QUERY_MATCH_FRIENDLY_NAME 0x040000 +#define HX509_QUERY_MATCH_FUNCTION 0x080000 +#define HX509_QUERY_MATCH_KEY_HASH_SHA1 0x100000 +#define HX509_QUERY_MATCH_TIME 0x200000 +#define HX509_QUERY_MATCH_EKU 0x400000 +#define HX509_QUERY_MATCH_EXPR 0x800000 +#define HX509_QUERY_MASK 0xffffff + Certificate *subject; + Certificate *certificate; + heim_integer *serial; + heim_octet_string *subject_id; + heim_octet_string *local_key_id; + Name *issuer_name; + Name *subject_name; + hx509_path *path; + char *friendlyname; + int (*cmp_func)(hx509_context, hx509_cert, void *); + void *cmp_func_ctx; + heim_octet_string *keyhash_sha1; + time_t timenow; + heim_oid *eku; + struct hx_expr *expr; +}; + +struct hx509_keyset_ops { + const char *name; + int flags; + int (*init)(hx509_context, hx509_certs, void **, + int, const char *, hx509_lock); + int (*store)(hx509_context, hx509_certs, void *, int, hx509_lock); + int (*free)(hx509_certs, void *); + int (*add)(hx509_context, hx509_certs, void *, hx509_cert); + int (*query)(hx509_context, hx509_certs, void *, + const hx509_query *, hx509_cert *); + int (*iter_start)(hx509_context, hx509_certs, void *, void **); + int (*iter)(hx509_context, hx509_certs, void *, void *, hx509_cert *); + int (*iter_end)(hx509_context, hx509_certs, void *, void *); + int (*printinfo)(hx509_context, hx509_certs, + void *, int (*)(void *, const char *), void *); + int (*getkeys)(hx509_context, hx509_certs, void *, hx509_private_key **); + int (*addkey)(hx509_context, hx509_certs, void *, hx509_private_key); + int (*destroy)(hx509_context, hx509_certs, void *); +}; + +struct _hx509_password { + size_t len; + char **val; +}; + +extern hx509_lock _hx509_empty_lock; + +struct hx509_context_data { + struct hx509_keyset_ops **ks_ops; + int ks_num_ops; + int flags; +#define HX509_CTX_VERIFY_MISSING_OK 1 + int ocsp_time_diff; +#define HX509_DEFAULT_OCSP_TIME_DIFF (5*60) + heim_error_t error; + struct et_list *et_list; + char *querystat; + hx509_certs default_trust_anchors; + heim_context hcontext; + heim_config_section *cf; +}; + +/* _hx509_calculate_path flag field */ +#define HX509_CALCULATE_PATH_NO_ANCHOR 1 + +/* environment */ +struct hx509_env_data { + enum { env_string, env_list } type; + char *name; + struct hx509_env_data *next; + union { + char *string; + struct hx509_env_data *list; + } u; +}; + + +extern const AlgorithmIdentifier * _hx509_crypto_default_sig_alg; +extern const AlgorithmIdentifier * _hx509_crypto_default_digest_alg; +extern const AlgorithmIdentifier * _hx509_crypto_default_secret_alg; + +/* + * Private bits from crypto.c, so crypto-ec.c can also see them. + * + * This is part of the use-OpenSSL-for-EC hack. + */ + +struct hx509_crypto; + +struct signature_alg; + +struct hx509_generate_private_context { + const heim_oid *key_oid; + int isCA; + unsigned long num_bits; +}; + +struct hx509_private_key_ops { + const char *pemtype; + const heim_oid *key_oid; + int (*available)(const hx509_private_key, + const AlgorithmIdentifier *); + int (*get_spki)(hx509_context, + const hx509_private_key, + SubjectPublicKeyInfo *); + int (*export)(hx509_context context, + const hx509_private_key, + hx509_key_format_t, + heim_octet_string *); + int (*import)(hx509_context, const AlgorithmIdentifier *, + const void *, size_t, hx509_key_format_t, + hx509_private_key); + int (*generate_private_key)(hx509_context, + struct hx509_generate_private_context *, + hx509_private_key); + BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *); +}; + +struct hx509_private_key { + unsigned int ref; + const struct signature_alg *md; + const heim_oid *signature_alg; + union { + RSA *rsa; + void *keydata; + void *ecdsa; /* EC_KEY */ + } private_key; + hx509_private_key_ops *ops; +}; + +/* + * + */ + +struct signature_alg { + const char *name; + const heim_oid *sig_oid; + const AlgorithmIdentifier *sig_alg; + const heim_oid *key_oid; + const AlgorithmIdentifier *digest_alg; + int flags; +#define PROVIDE_CONF 0x1 +#define REQUIRE_SIGNER 0x2 +#define SELF_SIGNED_OK 0x4 +#define WEAK_SIG_ALG 0x8 + +#define SIG_DIGEST 0x100 +#define SIG_PUBLIC_SIG 0x200 +#define SIG_SECRET 0x400 + +#define RA_RSA_USES_DIGEST_INFO 0x1000000 + + time_t best_before; /* refuse signature made after best before date */ + const EVP_MD *(*evp_md)(void); + int (*verify_signature)(hx509_context context, + const struct signature_alg *, + const Certificate *, + const AlgorithmIdentifier *, + const heim_octet_string *, + const heim_octet_string *); + int (*create_signature)(hx509_context, + const struct signature_alg *, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + AlgorithmIdentifier *, + heim_octet_string *); + int digest_size; +}; + +/* + * Configurable options + */ + +#ifdef __APPLE__ +#define HX509_DEFAULT_ANCHORS "KEYCHAIN:system-anchors" +#endif diff --git a/third_party/heimdal/lib/hx509/hxtool-commands.in b/third_party/heimdal/lib/hx509/hxtool-commands.in new file mode 100644 index 0000000..40df936 --- /dev/null +++ b/third_party/heimdal/lib/hx509/hxtool-commands.in @@ -0,0 +1,1088 @@ +/* + * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* $Id$ */ + +command = { + name = "list-oids" + help = "List known OIDs" + function = "hxtool_list_oids" + min_args="0" + max_args="0" +} +command = { + name = "cms-create-sd" + name = "cms-sign" + option = { + long = "certificate" + short = "c" + type = "strings" + argument = "certificate-store" + help = "certificate stores to pull certificates from" + } + option = { + long = "signer" + short = "s" + type = "string" + argument = "signer-friendly-name" + help = "certificate to sign with" + } + option = { + long = "anchors" + type = "strings" + argument = "certificate-store" + help = "trust anchors" + } + option = { + long = "pool" + type = "strings" + argument = "certificate-pool" + help = "certificate store to pull certificates from" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "peer-alg" + type = "strings" + argument = "oid" + help = "oid that the peer support" + } + option = { + long = "content-type" + type = "string" + argument = "oid" + help = "content type oid" + } + option = { + long = "content-info" + type = "flag" + help = "wrapped out-data in a ContentInfo" + } + option = { + long = "pem" + type = "flag" + help = "wrap out-data in PEM armor" + } + option = { + long = "detached-signature" + type = "flag" + help = "create a detached signature" + } + option = { + long = "signer" + type = "-flag" + help = "do not sign" + } + option = { + long = "id-by-name" + type = "flag" + help = "use subject name for CMS Identifier" + } + option = { + long = "embedded-certs" + type = "-flag" + help = "don't embed certificates" + } + option = { + long = "embed-leaf-only" + type = "flag" + help = "only embed leaf certificate" + } + min_args="1" + max_args="2" + argument="in-file out-file" + help = "Wrap a file within a SignedData object" +} +command = { + name = "cms-verify-sd" + option = { + long = "anchors" + short = "D" + type = "strings" + argument = "certificate-store" + help = "trust anchors" + } + option = { + long = "certificate" + short = "c" + type = "strings" + argument = "certificate-store" + help = "certificate store to pull certificates from" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "missing-revoke" + type = "flag" + help = "missing CRL/OCSP is ok" + } + option = { + long = "content-info" + type = "flag" + help = "unwrap in-data that's in a ContentInfo" + } + option = { + long = "pem" + type = "flag" + help = "unwrap in-data from PEM armor" + } + option = { + long = "signer-allowed" + type = "-flag" + help = "allow no signer" + } + option = { + long = "allow-wrong-oid" + type = "flag" + help = "allow wrong oid flag" + } + option = { + long = "signed-content" + type = "string" + help = "file containing content" + } + option = { + long = "oid-sym" + type = "flag" + help = "show symbolic name for OID" + } + min_args="1" + max_args="2" + argument="in-file [out-file]" + help = "Verify a file within a SignedData object" +} +command = { + name = "cms-unenvelope" + option = { + long = "certificate" + short = "c" + type = "strings" + argument = "certificate-store" + help = "certificate used to decrypt the data" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "content-info" + type = "flag" + help = "wrapped out-data in a ContentInfo" + } + option = { + long = "allow-weak-crypto" + type = "flag" + help = "allow weak crypto" + } + min_args="2" + argument="in-file out-file" + help = "Unenvelope a file containing a EnvelopedData object" +} +command = { + name = "cms-envelope" + function = "cms_create_enveloped" + option = { + long = "certificate" + short = "c" + type = "strings" + argument = "certificate-store" + help = "certificates used to receive the data" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "encryption-type" + type = "string" + argument = "enctype" + help = "enctype" + } + option = { + long = "content-type" + type = "string" + argument = "oid" + help = "content type oid" + } + option = { + long = "content-info" + type = "flag" + help = "wrapped out-data in a ContentInfo" + } + option = { + long = "allow-weak-crypto" + type = "flag" + help = "allow weak crypto" + } + min_args="2" + argument="in-file out-file" + help = "Envelope a file containing a EnvelopedData object" +} +command = { + name = "verify" + function = "pcert_verify" + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "allow-proxy-certificate" + type = "flag" + help = "allow proxy certificates" + } + option = { + long = "missing-revoke" + type = "flag" + help = "missing CRL/OCSP is ok" + } + option = { + long = "time" + type = "string" + help = "time when to validate the chain" + } + option = { + long = "verbose" + short = "v" + type = "flag" + help = "verbose logging" + } + option = { + long = "max-depth" + type = "integer" + help = "maximum search length of certificate trust anchor" + } + option = { + long = "hostname" + type = "string" + help = "match hostname to certificate" + } + argument = "cert:foo chain:cert1 chain:cert2 anchor:anchor1 anchor:anchor2" + help = "Verify certificate chain" +} +command = { + name = "print" + function = "pcert_print" + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "content" + type = "flag" + help = "print the content of the certificates" + } + option = { + long = "raw-json" + type = "flag" + help = "print the DER content of the certificates as JSON" + } + option = { + long = "never-fail" + type = "flag" + help = "never fail with an error code" + } + option = { + long = "info" + type = "flag" + help = "print the information about the certificate store" + } + min_args="1" + argument="certificate ..." + help = "Print certificates" +} +command = { + name = "validate" + function = "pcert_validate" + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + min_args="1" + argument="certificate ..." + help = "Validate content of certificates" +} +command = { + name = "certificate-copy" + name = "cc" + option = { + long = "in-pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "out-pass" + type = "string" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "append" + type = "flag" + help = "append source to destination" + } + option = { + long = "root-certs" + type = "-flag" + help = "do not copy root certificates" + } + option = { + long = "private-keys" + type = "-flag" + help = "do not copy private keys" + } + min_args="2" + argument="in-certificates-1 ... out-certificate" + help = "Copy in certificates stores into out certificate store" +} +command = { + name = "ocsp-fetch" + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "sign" + type = "string" + argument = "certificate" + help = "certificate use to sign the request" + } + option = { + long = "url-path" + type = "string" + argument = "url" + help = "part after host in url to put in the request" + } + option = { + long = "nonce" + type = "-flag" + default = "1" + help = "don't include nonce in request" + } + option = { + long = "pool" + type = "strings" + argument = "certificate-store" + help = "pool to find parent certificate in" + } + min_args="2" + argument="outfile certs ..." + help = "Fetch OCSP responses for the following certs" +} +command = { + option = { + long = "ocsp-file" + type = "string" + help = "OCSP file" + } + name = "ocsp-verify" + min_args="1" + argument="certificates ..." + help = "Check that certificates are in OCSP file and valid" +} +command = { + name = "ocsp-print" + option = { + long = "verbose" + type = "flag" + help = "verbose" + } + min_args="1" + argument="ocsp-response-file ..." + help = "Print the OCSP responses" +} +command = { + name = "revoke-print" + option = { + long = "verbose" + type = "flag" + help = "verbose" + } + min_args="1" + argument="ocsp/crl files" + help = "Print the OCSP/CRL files" +} +command = { + name = "generate-key" + option = { + long = "type" + type = "string" + help = "keytype" + } + option = { + long = "key-bits" + type = "integer" + help = "number of bits in the generated key"; + } + option = { + long = "verbose" + type = "flag" + help = "verbose status" + } + min_args="1" + max_args="1" + argument="output-file" + help = "Generate a private key" +} +command = { + name = "request-create" + option = { + long = "ca" + type = "flag" + help = "Request CA certificate" + } + option = { + long = "ca-path-length" + type = "integer" + help = "Path length constraint for CA certificate" + default = "-1" + } + option = { + long = "ee" + type = "flag" + help = "Include BasicConstraints w/ cA set to false" + } + option = { + long = "subject" + type = "string" + help = "Subject DN" + } + option = { + long = "eku" + type = "strings" + argument = "oid-string" + help = "Add Extended Key Usage OID" + } + option = { + long = "email" + type = "strings" + help = "Email address in SubjectAltName" + } + option = { + long = "jid" + type = "strings" + help = "XMPP (Jabber) address in SubjectAltName" + } + option = { + long = "dnsname" + type = "strings" + help = "Hostname or domainname in SubjectAltName" + } + option = { + long = "kerberos" + type = "strings" + help = "Kerberos principal name as SubjectAltName" + } + option = { + long = "ms-kerberos" + type = "strings" + help = "Kerberos principal name as SubjectAltName (Microsoft variant)" + } + option = { + long = "registered" + type = "strings" + help = "Registered object ID as SubjectAltName" + } + option = { + long = "dn" + type = "strings" + help = "Directory name as SubjectAltName" + } + option = { + long = "type" + type = "string" + help = "Type of request CRMF or PKCS10, defaults to PKCS10" + } + option = { + long = "key" + type = "string" + help = "Key-pair" + } + option = { + long = "generate-key" + type = "string" + help = "keytype" + } + option = { + long = "key-bits" + type = "integer" + help = "number of bits in the generated key"; + } + option = { + long = "verbose" + type = "flag" + help = "verbose status" + } + min_args="1" + max_args="1" + argument="output-file" + help = "Create a CRMF or PKCS10 request" +} +command = { + name = "request-print" + option = { + long = "verbose" + type = "flag" + help = "verbose printing" + } + min_args="1" + argument="requests ..." + help = "Print requests" +} +command = { + name = "query" + option = { + long = "exact" + type = "flag" + help = "exact match" + } + option = { + long = "private-key" + type = "flag" + help = "search for private key" + } + option = { + long = "friendlyname" + type = "string" + argument = "name" + help = "match on friendly name" + } + option = { + long = "eku" + type = "string" + argument = "oid-string" + help = "match on EKU" + } + option = { + long = "expr" + type = "string" + argument = "expression" + help = "match on expression" + } + option = { + long = "keyEncipherment" + type = "flag" + help = "match keyEncipherment certificates" + } + option = { + long = "digitalSignature" + type = "flag" + help = "match digitalSignature certificates" + } + option = { + long = "print" + type = "flag" + help = "print matches" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + min_args="1" + argument="certificates ..." + help = "Query the certificates for a match" +} +command = { + name = "info" +} +command = { + name = "random-data" + min_args="1" + argument="bytes" + help = "Generates random bytes and prints them to standard output" +} +command = { + option = { + long = "type" + type = "string" + help = "type of CMS algorithm" + } + option = { + long = "oid-syms" + type = "flag" + help = "show symbolic names for OIDs" + } + name = "crypto-available" + min_args="0" + help = "Print available CMS crypto types" +} +command = { + option = { + long = "type" + type = "string" + help = "type of CMS algorithm" + } + option = { + long = "certificate" + type = "string" + help = "source certificate limiting the choices" + } + option = { + long = "peer-cmstype" + type = "strings" + help = "peer limiting cmstypes" + } + option = { + long = "oid-sym" + type = "flag" + help = "show symbolic name for OID" + } + name = "crypto-select" + min_args="0" + help = "Print selected CMS type" +} +command = { + option = { + long = "decode" + short = "d" + type = "flag" + help = "decode instead of encode" + } + name = "hex" + function = "hxtool_hex" + min_args="0" + help = "Encode input to hex" +} +command = { + option = { + long = "issue-ca" + type = "flag" + help = "Issue a CA certificate" + } + option = { + long = "issue-proxy" + type = "flag" + help = "Issue a proxy certificate" + } + option = { + long = "domain-controller" + type = "flag" + help = "Issue a MS domaincontroller certificate" + } + option = { + long = "subject" + type = "string" + help = "Subject of issued certificate" + } + option = { + long = "ca-certificate" + type = "string" + help = "Issuing CA certificate" + } + option = { + long = "self-signed" + type = "flag" + help = "Issuing a self-signed certificate" + } + option = { + long = "ca-private-key" + type = "string" + help = "Private key for self-signed certificate" + } + option = { + long = "certificate" + type = "string" + help = "Issued certificate" + } + option = { + long = "type" + type = "strings" + help = "Types of certificate to issue (can be used more then once)" + } + option = { + long = "lifetime" + type = "string" + help = "Lifetime of certificate" + } + option = { + long = "signature-algorithm" + type = "string" + help = "Signature algorithm to use" + } + option = { + long = "serial-number" + type = "string" + help = "serial-number of certificate" + } + option = { + long = "path-length" + default = "-1" + type = "integer" + help = "Maximum path length (CA and proxy certificates), -1 no limit" + } + option = { + long = "eku" + type = "strings" + argument = "oid-string" + help = "Add Extended Key Usage OID" + } + option = { + long = "ku" + type = "strings" + help = "Key Usage (digitalSignature, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, decipherOnly)" + } + option = { + long = "hostname" + type = "strings" + help = "DNS names this certificate is allowed to serve" + } + option = { + long = "dnssrv" + type = "strings" + help = "DNS SRV names this certificate is allowed to serve" + } + option = { + long = "email" + type = "strings" + help = "email addresses assigned to this certificate" + } + option = { + long = "pk-init-principal" + type = "strings" + help = "PK-INIT principal (for SAN)" + } + option = { + long = "ms-upn" + type = "string" + help = "Microsoft UPN (for SAN)" + } + option = { + long = "jid" + type = "string" + help = "XMPP jabber id (for SAN)" + } + option = { + long = "permanent-id" + type = "string" + help = "PermanentIdentifier ([oid]:[serial])" + } + option = { + long = "hardware-module-name" + type = "string" + help = "HardwareModuleName (oid:serial)" + } + option = { + long = "policy" + type = "strings" + help = "Certificate Policy OID and optional URI and/or notice (OID:URInotice_text)" + } + option = { + long = "policy-mapping" + type = "strings" + help = "Certificate Policy mapping (OID:OID)" + } + option = { + long = "pkinit-max-life" + type = "string" + help = "maximum Kerberos ticket lifetime extension for PKINIT" + } + option = { + long = "req" + type = "string" + help = "certificate request" + } + option = { + long = "certificate-private-key" + type = "string" + help = "private-key" + } + option = { + long = "generate-key" + type = "string" + help = "keytype" + } + option = { + long = "key-bits" + type = "integer" + help = "number of bits in the generated key" + } + option = { + long = "crl-uri" + type = "string" + help = "URI to CRL" + } + option = { + long = "template-certificate" + type = "string" + help = "certificate" + } + option = { + long = "template-fields" + type = "string" + help = "flag" + } + name = "certificate-sign" + name = "cert-sign" + name = "issue-certificate" + name = "ca" + function = "hxtool_ca" + min_args="0" + help = "Issue a certificate" +} +command = { + name = "test-crypto" + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "verbose" + type = "flag" + help = "verbose printing" + } + min_args="1" + argument="certificates..." + help = "Test crypto system related to the certificates" +} +command = { + option = { + long = "type" + type = "integer" + help = "type of statistics" + } + name = "statistic-print" + min_args="0" + help = "Print statistics" +} +command = { + option = { + long = "signer" + type = "string" + help = "signer certificate" + } + option = { + long = "pass" + type = "strings" + argument = "password" + help = "password, prompter, or environment" + } + option = { + long = "crl-file" + type = "string" + help = "CRL output file" + } + option = { + long = "lifetime" + type = "string" + help = "time the crl will be valid" + } + name = "crl-sign" + min_args="0" + argument="certificates..." + help = "Create a CRL" +} +command = { + option = { + long = "verbose" + short = "v" + type = "flag" + help = "verbose" + } + option = { + long = "end-entity" + type = "flag" + help = "check the first EE certificate in the store" + } + option = { + long = "ca" + type = "flag" + help = "check the first CA certificate in the store" + } + option = { + long = "cert-num" + type = "integer" + default = "-1" + help = "check the nth certificate in the store" + } + option = { + long = "expr" + type = "string" + argument = "expression" + help = "test the first certificate matching expression" + } + option = { + long = "has-email-san" + short = "M" + type = "strings" + argument = "email-address" + help = "check that cert has email SAN" + } + option = { + long = "has-xmpp-san" + type = "strings" + short = "X" + argument = "jabber address" + help = "check that cert has XMPP SAN" + } + option = { + long = "has-ms-upn-san" + short = "U" + type = "strings" + argument = "UPN" + help = "check that cert has UPN SAN" + } + option = { + long = "has-dnsname-san" + short = "D" + type = "strings" + argument = "domainname" + help = "check that cert has domainname SAN" + } + option = { + long = "has-pkinit-san" + short = "P" + type = "strings" + argument = "Kerberos principal name" + help = "check that cert has PKINIT SAN" + } + option = { + long = "has-registeredID-san" + short = "R" + type = "strings" + argument = "OID" + help = "check that cert has registeredID SAN" + } + option = { + long = "has-eku" + short = "E" + type = "strings" + argument = "OID" + help = "check that cert has EKU" + } + option = { + long = "has-ku" + short = "K" + type = "strings" + argument = "key usage element" + help = "check that cert has key usage" + } + option = { + long = "exact" + type = "flag" + help = "check that cert has only given SANs/EKUs/KUs" + } + option = { + long = "valid-now" + short = "n" + type = "flag" + help = "check that current time is in certicate's validity period" + } + option = { + long = "valid-at" + type = "string" + argument = "datetime" + help = "check that the certificate is valid at given time" + } + option = { + long = "not-after-eq" + type = "string" + argument = "datetime" + help = "check that the certificate's notAfter is as given" + } + option = { + long = "not-after-lt" + type = "string" + argument = "datetime" + help = "check that the certificate's notAfter is before the given time" + } + option = { + long = "not-after-gt" + type = "string" + argument = "datetime" + help = "check that the certificate's notAfter is after the given time" + } + option = { + long = "not-before-eq" + type = "string" + argument = "datetime" + help = "check that the certificate's notBefore is as given" + } + option = { + long = "not-before-lt" + type = "string" + argument = "datetime" + help = "check that the certificate's notBefore is before the given time" + } + option = { + long = "not-before-gt" + type = "string" + argument = "datetime" + help = "check that the certificate's notBefore is after the given time" + } + option = { + long = "has-private-key" + type = "flag" + help = "check that the certificate has a private key" + } + option = { + long = "lacks-private-key" + type = "flag" + help = "check that the certificate does not have a private key" + } + name = "acert" + min_args = "1" + max_args = "1" + argument = "certificate-store" + help = "Assert certificate content" +} +command = { + name = "help" + name = "?" + argument = "[command]" + min_args = "0" + max_args = "1" + help = "Help! I need somebody" +} diff --git a/third_party/heimdal/lib/hx509/hxtool-version.rc b/third_party/heimdal/lib/hx509/hxtool-version.rc new file mode 100644 index 0000000..7e5197c --- /dev/null +++ b/third_party/heimdal/lib/hx509/hxtool-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "Heimdal X.509 Certificate Tool" +#define RC_FILE_ORIG_0409 "hxtool.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/hx509/hxtool.1 b/third_party/heimdal/lib/hx509/hxtool.1 new file mode 100644 index 0000000..040573f --- /dev/null +++ b/third_party/heimdal/lib/hx509/hxtool.1 @@ -0,0 +1,380 @@ +.\" Copyright (c) 2022 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2022 +.Dt HXTOOL 1 +.Os HEIMDAL +.Sh NAME +.Nm hxtool +.Nd PKIX command-line utility +.Sh SYNOPSIS +.Nm +.Bk -words +.Oo Fl Fl version Oc +.Oo Fl Fl help Oc +.Op Ar sub-command +.Ek +.Sh DESCRIPTION +.Nm +is a utility for making certificate sigining requests (CSRs), +displaying CSRs, signing certificates, etc. +are given, then the value will be parsed and displayed using just +the self-describing nature of DER. +.Pp +All sub-commands have their own help message, shown when invoked +with the +.Fl Fl help +or +.Fl h +option. +.Pp +Supported commands: +.Bl -tag -width Ds -offset indent +.It help +.It list-oids +.It verify +Verify a certificate and its certification path up to a trust +anchor, possibly checking CRLs. +.It print +Prints a human-readable rendering of certificates in a store. +See +.Sx CERTIFICATE STORES. +.It validate +Validate a certificate (but not a full chain). +.It certificate-copy, cc +Copy ceritificates and possibly private keys from one store to +another. +See +.Sx CERTIFICATE STORES. +.It ocsp-fetch +Fetch an OCSP response. +.It ocsp-verify +Fetch an OCSP response chain. +.It ocsp-print +Prints a human-readable rendering of an OCSP response chain. +.It revoke-print +Prints a human-readable rendering of a CRL or OCSP response +chain. +.It generate-key +Generates a private key. +.It request-create +Generates a Certificate Signing Request (CSR). +.It request-print +Prints a human-readable rendering of a CSR. +.It query +Queries a certificate store. +.It info +Prints information about supported algorithms. +.It random-data +Outputs entropy using a random number generator. +.It crypto-available +Tests if a cryptographic algorithm is available. +.It crypto-select +Selects a supported cryptographic algorithm given a peer's +capabilities. +.It hex +Hex-encode/decode utility. +.It certificate-sign, cert-sign, issue-certificate, ca +Issue a certificate. +.It crl-sign +Sign a CRL. +.It cms-create-sd, cms-sign +Created a CMS SignedData. +.It cms-verify-sd +Verifies a CMS SignedData. +.It cms-unenvelope +Extracts enveloped data from a CMS SignedData. +.It cms-envelope +Creates an enveloped CMS SignedData. +.El +Other sub-commands reported by the +.Nm help +sub-command are not stable or fully supported at this time. +.Sh CERTIFICATE STORES +Stores of certificates and/or keys have string names that can be +used with +.Nm 's +commands as well as in various configuration parameters and +command-line arguments of Heimdal's Kerberos implementation (for +PKINIT). +.Pp +For example, +.Ql FILE:/path/to/file , +.Ql PEM-FILE:/path/to/file , +.Ql DER-FILE:/path/to/file , +etc. +See below for a full list of store types. +.Pp +A certificate store name starts with a store TYPE followed by a +colon followed by a name of form specific to that store type. +.Pp +Private keys can be stored in the same stores as the certificates +that certify their public keys. +.Pp +Private keys can also be stored in separate files, but still be +referenced in one certificate store name by joining two with a +comma: +.Ql FILE:/path/to/certificate,/path/to/private/key +. +.Pp +Heimdal supports a variety of certificate and private key store +types: +.Bl -tag -width Ds -offset indent +.It PEM-FILE:/path +If writing, PEM will be written (private keys may be written in +algorithm-specific formats or in PKCS#8). +If reading, PEM will be expected (private keys may be in +algorithm-specific formats or in PKCS#8). +.It DER-FILE:/path +If writing, DER will be written. +If reading, DER will be expected. +Private keys will be in algorithm-specific formats. +.It FILE:/path +If writing, PEM will be written as if +.Ql PEM-FILE +had been used. +If reading, PEM or DER will be detected and read as if +.Ql PEM-FILE +or +.Ql DER-FILE +had been used. +.It PKCS12:/path +If writing, PKCS#12 will be written. +If reading, PKCS#12 will be expected. +Note that PKCS#12 support is currently very limited. +.It DIR:/path +OpenSSL-style hashed directory of trust anchors. +.It KEYCHAIN:system-anchors +On OS X this refers to the system's trust anchors. +.It KEYCHAIN:FILE:/path +On OS X this refers to an OS X keychain at the given path. +.It PKCS11:/path/to/shared/object[,slot=NUMBER] +Loads the given PKCS#11 provider object and uses the token at the +given slot number, or else the first token found. +.It NULL: +An empty store. +.It MEMORY:name +An in-memory only, ephemeral store, usually never used in +.NM 's +commands. +The MEMORY store name exists primarily for internal +.Sq hx509 +APIs. +.El +.Pp +Use the +.Nm certificate-copy +command to copy certificates from one store to another. +This is useful for, e.g., converting DER files to PEM or +vice-versa, removing private keys, adding certificate chains, +and removing root certificates from chains. +.Sh CERTIFICATES +You can validate a certificate with the +.Nm validate +sub-command, or verify a certificate and its certification path +with the +.Nm verify +sub-command. +.Pp +You can display a certificate using the +.Nm print +sub-command: +.Pp +.Nm print +.Oo options Oc +.Ar STORE +.Pp +Options: +.Bl -tag -width Ds -offset indent +.It Fl Fl content +.It Fl Fl info +.It Fl Fl never-fail +.It Fl Fl pass=password +.It Fl Fl raw-json +.El +.Pp +The +.Fl Fl pass=password +option is for PKCS#8 (PEM), PKCS#12 and PKCS#11 stores, and if +needed and not given, will be prompted for. +Note that it's not secure to pass passwords as command-line +arguments on multi-tenant systems. +.Pp +The +.Fl Fl raw-json +option prints the certificate(s) in the given +.Ar STORE +as a JSON dump of their DER using an experimental (i.e., +unstable) schema. +.Sh KEYS +The +.Nm generate-key +sub-command will generate a key. +.Sh CERTIFICATE SIGNING REQUESTS +The +.Nm request-create +sub-command will create a CSR, and has support for requesting +subject alternative names and extended key usage extensions. +See its +.Fl Fl help +option, and see +.Sx EXAMPLES +below. +.Pp +The +.Nm request-print +sub-command will display a CSR. +.Sh CERTIFICATE ISSUANCE / CERTIFICATION AUTHORITY +The +.Nm certificate-sign +sub-command will issue a certificate. +See its usage message. +.Sh ONLINE CERTIFICATE STATUS PROTOCOL +The +.Nm ocsp-fetch +sub-command will fetch OCSP Responses for the given +certificates. +.Pp +The +.Nm ocsp-verify +sub-command will verify OCSP Responses. +.Pp +The +.Nm ocsp-print +sub-command will display OCSP Responses. +.Sh CERTIFICATE REVOCATION LIST +The +.Nm crl-sign +sub-command will add certificates to a certificate revocation +list. +.Sh EXAMPLES +Generate an RSA key: +.Bd -literal -offset indent +hxtool generate-key --type=rsa --key-bits=4096 PEM-FILE:key.pem +.Ed +.Pp +Create a CSR (with an empty name) for some key: +.Bd -literal -offset indent +hxtool request-create --subject= --key=FILE:key.pem csr.der +.Ed +.Pp +Generate a key and create a CSR (with an empty name) for it: +.Bd -literal -offset indent +hxtool request-create \\ + --subject= \\ + --generate-key=rsa \\ + --key-bits=4096 \\ + --key=FILE:key.pem \\ + csr.der +.Ed +.Pp +Generate a key and create a CSR with an empty name but also +requesting a specific dNSName subject alternative name (SAN) for +it: +.Bd -literal -offset indent +hxtool request-create \\ + --subject= \\ + --generate-key=rsa \\ + --dnsname=foo.test.h5l.se \\ + --key=FILE:key.pem \\ + csr.der +.Ed +.Pp +Print a CSR: +.Bd -literal -offset indent +hxtool request-print csr.der +.Ed +which outputs: +.Bd -literal -offset indent +request print +PKCS#10 CertificationRequest: + name: + san: dNSName: foo.test.h5l.se +.Ed +.Pp +Issue a end-entity certificate for an HTTPS server given a CSR: +.Bd -literal -offset indent +hxtool issue-certificate \\ + --type=https-server \\ + --subject= \\ + --hostname=foo.test.h5l.se \\ + --ca-certificate=FILE:cacert.pem \\ + --ca-private-key=FILE:cakey.pem \\ + --req=PKCS10:csr.der \\ + --certificate=PEM-FILE:ee.pem +.Ed +.Pp +Add a chain to a PEM file: +.Bd -literal -offset indent +hxtool copy-certificiate \\ + --no-private-keys \\ + --no-root-certs \\ + FILE:ca.pem FILE:ee.pem +.Ed +.Pp +Create a self-signed end-entity certificate for an HTTPS server: +.Bd -literal -offset indent +hxtool issue-certificate \\ + --self-signed \\ + --type=https-server \\ + --subject= \\ + --hostname=foo.test.h5l.se \\ + --ca-private-key=FILE:key.pem \\ + --certificate-private-key=FILE:key.pem \\ + --certificate=PEM-FILE:cert.pem +.Ed +.Pp +Create a root certification authority certificate: +.Bd -literal -offset indent +hxtool issue-certificate \\ + --issue-ca \\ + --self-signed \\ + --subject=CN=SomeRootCA \\ + --ca-private-key=FILE:rootkey.pem \\ + --certificate=PEM-FILE:rootcert.pem +.Ed +.Pp +Create an intermediate certification authority certificate from a +CSR: +.Bd -literal -offset indent +hxtool issue-certificate \\ + --type=https-server \\ + --subject=CN=SomeIntermediateCA \\ + --ca-certificate=FILE:parent-cert.pem \\ + --ca-private-key=FILE:parent-key.pem \\ + --req=PKCS10:csr.der \\ + --certificate=PEM-FILE:intermediate.pem +.Ed +.Pp +.Sh SEE ALSO +.Xr openssl 1 diff --git a/third_party/heimdal/lib/hx509/hxtool.c b/third_party/heimdal/lib/hx509/hxtool.c new file mode 100644 index 0000000..e4e9a80 --- /dev/null +++ b/third_party/heimdal/lib/hx509/hxtool.c @@ -0,0 +1,3249 @@ +/* + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +#include +#include +#include +#include +#include + +static hx509_context context; + +static char *stat_file_string; +static int version_flag; +static int help_flag; + +struct getargs args[] = { + { "statistic-file", 0, arg_string, &stat_file_string, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "command"); + printf("Use \"%s help\" to get more help\n", getprogname()); + exit(code); +} + +/* + * + */ + +static void +lock_strings(hx509_lock lock, getarg_strings *pass) +{ + int i; + for (i = 0; i < pass->num_strings; i++) { + int ret = hx509_lock_command_string(lock, pass->strings[i]); + if (ret) + errx(1, "hx509_lock_command_string: %s: %d", + pass->strings[i], ret); + } +} + +static char * +fix_store_name(hx509_context contextp, const char *sn, const char *def_type) +{ + const char *residue = strchr(sn, ':'); + char *s = NULL; + + if (residue) { + s = estrdup(sn); + s[residue - sn] = '\0'; + if (_hx509_ks_type(contextp, s)) { + free(s); + return estrdup(sn); + } + free(s); + s = NULL; + } + if (asprintf(&s, "%s:%s", def_type, sn) == -1 || s == NULL) + err(1, "Out of memory"); + return s; +} + +static char * +fix_csr_name(const char *cn, const char *def_type) +{ + char *s = NULL; + + if (strncmp(cn, "PKCS10:", sizeof("PKCS10:") - 1) == 0 || strchr(cn, ':')) + return estrdup(cn); + if (asprintf(&s, "%s:%s", def_type, cn) == -1 || s == NULL) + err(1, "Out of memory"); + return s; +} + +/* + * + */ + +static void +certs_strings(hx509_context contextp, const char *type, hx509_certs certs, + hx509_lock lock, const getarg_strings *s) +{ + int i, ret; + + for (i = 0; i < s->num_strings; i++) { + char *sn = fix_store_name(contextp, s->strings[i], "FILE"); + + ret = hx509_certs_append(contextp, certs, lock, sn); + if (ret) + hx509_err(contextp, 1, ret, + "hx509_certs_append: %s %s", type, sn); + free(sn); + } +} + +/* + * + */ + +static void +parse_oid(const char *str, const heim_oid *def, heim_oid *oid) +{ + int ret; + + if (str) { + const heim_oid *found = NULL; + + ret = der_find_heim_oid_by_name(str, &found); + if (ret == 0) + ret = der_copy_oid(found, oid); + else + ret = der_parse_heim_oid(str, " .", oid); + } else { + ret = der_copy_oid(def, oid); + } + if (ret) + errx(1, "parse_oid failed for: %s", str ? str : "default oid"); +} + +/* + * + */ + +static void +peer_strings(hx509_context contextp, + hx509_peer_info *peer, + const getarg_strings *s) +{ + AlgorithmIdentifier *val; + int ret, i; + + ret = hx509_peer_info_alloc(contextp, peer); + if (ret) + hx509_err(contextp, 1, ret, "hx509_peer_info_alloc"); + + val = calloc(s->num_strings, sizeof(*val)); + if (val == NULL) + err(1, "malloc"); + + for (i = 0; i < s->num_strings; i++) + parse_oid(s->strings[i], NULL, &val[i].algorithm); + + ret = hx509_peer_info_set_cms_algs(contextp, *peer, val, s->num_strings); + if (ret) + hx509_err(contextp, 1, ret, "hx509_peer_info_set_cms_algs"); + + for (i = 0; i < s->num_strings; i++) + free_AlgorithmIdentifier(&val[i]); + free(val); +} + +/* + * + */ + +struct pem_data { + heim_octet_string *os; + int detached_data; +}; + +static int +pem_reader(hx509_context contextp, const char *type, + const hx509_pem_header *headers, + const void *data , size_t length, void *ctx) +{ + struct pem_data *p = (struct pem_data *)ctx; + const char *h; + + p->os->data = malloc(length); + if (p->os->data == NULL) + return ENOMEM; + memcpy(p->os->data, data, length); + p->os->length = length; + + h = hx509_pem_find_header(headers, "Content-disposition"); + if (h && strcasecmp(h, "detached") == 0) + p->detached_data = 1; + + return 0; +} + +/* + * + */ + +int +cms_verify_sd(struct cms_verify_sd_options *opt, int argc, char **argv) +{ + hx509_verify_ctx ctx = NULL; + heim_oid type; + heim_octet_string c, co, signeddata, *sd = NULL; + hx509_certs store = NULL; + hx509_certs signers = NULL; + hx509_certs anchors = NULL; + hx509_lock lock; + int ret, flags = 0; + + size_t sz; + void *p = NULL; + + if (opt->missing_revoke_flag) + hx509_context_set_missing_revoke(context, 1); + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = hx509_verify_init_ctx(context, &ctx); + if (ret) + hx509_err(context, 1, ret, "hx509_verify_init_ctx"); + + ret = hx509_certs_init(context, "MEMORY:cms-anchors", 0, NULL, &anchors); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + ret = hx509_certs_init(context, "MEMORY:cert-store", 0, NULL, &store); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + certs_strings(context, "anchors", anchors, lock, &opt->anchors_strings); + certs_strings(context, "store", store, lock, &opt->certificate_strings); + + if (opt->pem_flag) { + struct pem_data pd; + FILE *f; + + pd.os = &co; + pd.detached_data = 0; + + f = fopen(argv[0], "r"); + if (f == NULL) + err(1, "Failed to open file %s", argv[0]); + + ret = hx509_pem_read(context, f, pem_reader, &pd); + fclose(f); + if (ret) + errx(1, "PEM reader failed: %d", ret); + + if (pd.detached_data && opt->signed_content_string == NULL) { + char *r = strrchr(argv[0], '.'); + if (r && strcasecmp(r, ".pem") == 0) { + char *s = strdup(argv[0]); + if (s == NULL) + errx(1, "malloc: out of memory"); + s[r - argv[0]] = '\0'; + ret = _hx509_map_file_os(s, &signeddata); + if (ret) + errx(1, "map_file: %s: %d", s, ret); + free(s); + sd = &signeddata; + } + } + + } else { + ret = rk_undumpdata(argv[0], &p, &sz); + if (ret) + err(1, "map_file: %s: %d", argv[0], ret); + + co.data = p; + co.length = sz; + } + + if (opt->signed_content_string) { + ret = _hx509_map_file_os(opt->signed_content_string, &signeddata); + if (ret) + errx(1, "map_file: %s: %d", opt->signed_content_string, ret); + sd = &signeddata; + } + + if (opt->content_info_flag) { + heim_octet_string uwco; + heim_oid oid; + + ret = hx509_cms_unwrap_ContentInfo(&co, &oid, &uwco, NULL); + if (ret) + errx(1, "hx509_cms_unwrap_ContentInfo: %d", ret); + + if (der_heim_oid_cmp(&oid, &asn1_oid_id_pkcs7_signedData) != 0) + errx(1, "Content is not SignedData"); + der_free_oid(&oid); + + if (p == NULL) + der_free_octet_string(&co); + else { + rk_xfree(p); + p = NULL; + } + co = uwco; + } + + hx509_verify_attach_anchors(ctx, anchors); + + if (!opt->signer_allowed_flag) + flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; + if (opt->allow_wrong_oid_flag) + flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; + + ret = hx509_cms_verify_signed(context, ctx, flags, co.data, co.length, sd, + store, &type, &c, &signers); + if (p != co.data) + der_free_octet_string(&co); + else + rk_xfree(p); + if (ret) + hx509_err(context, 1, ret, "hx509_cms_verify_signed"); + + { + char *str; + if (opt->oid_sym_flag) + der_print_heim_oid_sym(&type, '.', &str); + else + der_print_heim_oid(&type, '.', &str); + printf("type: %s\n", str); + free(str); + der_free_oid(&type); + } + if (signers == NULL) { + printf("unsigned\n"); + } else { + printf("signers:\n"); + hx509_certs_iter_f(context, signers, hx509_ci_print_names, stdout); + } + + hx509_verify_destroy_ctx(ctx); + + hx509_certs_free(&store); + hx509_certs_free(&signers); + hx509_certs_free(&anchors); + + hx509_lock_free(lock); + + if (argc > 1) { + ret = _hx509_write_file(argv[1], c.data, c.length); + if (ret) + errx(1, "hx509_write_file: %d", ret); + } + + der_free_octet_string(&c); + + if (sd) + _hx509_unmap_file_os(sd); + + return 0; +} + +static int HX509_LIB_CALL +print_signer(hx509_context contextp, void *ctx, hx509_cert cert) +{ + hx509_pem_header **header = ctx; + char *signer_name = NULL; + hx509_name name; + int ret; + + ret = hx509_cert_get_subject(cert, &name); + if (ret) + errx(1, "hx509_cert_get_subject"); + + ret = hx509_name_to_string(name, &signer_name); + hx509_name_free(&name); + if (ret) + errx(1, "hx509_name_to_string"); + + hx509_pem_add_header(header, "Signer", signer_name); + + free(signer_name); + return 0; +} + +int +cms_create_sd(struct cms_create_sd_options *opt, int argc, char **argv) +{ + heim_oid contentType; + hx509_peer_info peer = NULL; + heim_octet_string o; + hx509_query *q; + hx509_lock lock; + hx509_certs store, pool, anchors, signer = NULL; + size_t sz; + void *p; + int ret, flags = 0; + const char *outfile = NULL; + char *infile, *freeme = NULL; + + memset(&contentType, 0, sizeof(contentType)); + + infile = argv[0]; + + if (argc < 2) { + ret = asprintf(&freeme, "%s.%s", infile, + opt->pem_flag ? "pem" : "cms-signeddata"); + if (ret == -1 || freeme == NULL) + errx(1, "out of memory"); + outfile = freeme; + } else + outfile = argv[1]; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = hx509_certs_init(context, "MEMORY:cert-store", 0, NULL, &store); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + ret = hx509_certs_init(context, "MEMORY:cert-pool", 0, NULL, &pool); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + certs_strings(context, "store", store, lock, &opt->certificate_strings); + certs_strings(context, "pool", pool, lock, &opt->pool_strings); + + if (opt->anchors_strings.num_strings) { + ret = hx509_certs_init(context, "MEMORY:cert-anchors", + 0, NULL, &anchors); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + certs_strings(context, "anchors", anchors, lock, &opt->anchors_strings); + } else + anchors = NULL; + + if (opt->detached_signature_flag) + flags |= HX509_CMS_SIGNATURE_DETACHED; + if (opt->id_by_name_flag) + flags |= HX509_CMS_SIGNATURE_ID_NAME; + if (!opt->signer_flag) { + flags |= HX509_CMS_SIGNATURE_NO_SIGNER; + + } + + if (opt->signer_flag) { + ret = hx509_query_alloc(context, &q); + if (ret) + errx(1, "hx509_query_alloc: %d", ret); + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + + if (opt->signer_string) + hx509_query_match_friendly_name(q, opt->signer_string); + + ret = hx509_certs_filter(context, store, q, &signer); + hx509_query_free(context, q); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_find"); + } + if (!opt->embedded_certs_flag) + flags |= HX509_CMS_SIGNATURE_NO_CERTS; + if (opt->embed_leaf_only_flag) + flags |= HX509_CMS_SIGNATURE_LEAF_ONLY; + + ret = rk_undumpdata(infile, &p, &sz); + if (ret) + err(1, "map_file: %s: %d", infile, ret); + + if (opt->peer_alg_strings.num_strings) + peer_strings(context, &peer, &opt->peer_alg_strings); + + parse_oid(opt->content_type_string, &asn1_oid_id_pkcs7_data, &contentType); + + ret = hx509_cms_create_signed(context, + flags, + &contentType, + p, + sz, + NULL, + signer, + peer, + anchors, + pool, + &o); + if (ret) + hx509_err(context, 1, ret, "hx509_cms_create_signed: %d", ret); + + hx509_certs_free(&anchors); + hx509_certs_free(&pool); + hx509_certs_free(&store); + rk_xfree(p); + hx509_lock_free(lock); + hx509_peer_info_free(peer); + der_free_oid(&contentType); + + if (opt->content_info_flag) { + heim_octet_string wo; + + ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &o, &wo); + if (ret) + errx(1, "hx509_cms_wrap_ContentInfo: %d", ret); + + der_free_octet_string(&o); + o = wo; + } + + if (opt->pem_flag) { + hx509_pem_header *header = NULL; + FILE *f; + + hx509_pem_add_header(&header, "Content-disposition", + opt->detached_signature_flag ? + "detached" : "inline"); + if (signer) { + ret = hx509_certs_iter_f(context, signer, print_signer, header); + if (ret) + hx509_err(context, 1, ret, "print signer"); + } + + f = fopen(outfile, "w"); + if (f == NULL) + err(1, "open %s", outfile); + + ret = hx509_pem_write(context, "CMS SIGNEDDATA", header, f, + o.data, o.length); + fclose(f); + hx509_pem_free_header(header); + if (ret) + errx(1, "hx509_pem_write: %d", ret); + + } else { + ret = _hx509_write_file(outfile, o.data, o.length); + if (ret) + errx(1, "hx509_write_file: %d", ret); + } + + hx509_certs_free(&signer); + free(o.data); + free(freeme); + + return 0; +} + +int +cms_unenvelope(struct cms_unenvelope_options *opt, int argc, char **argv) +{ + heim_oid contentType = { 0, NULL }; + heim_octet_string o, co; + hx509_certs certs; + size_t sz; + void *p; + int ret; + hx509_lock lock; + int flags = 0; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = rk_undumpdata(argv[0], &p, &sz); + if (ret) + err(1, "map_file: %s: %d", argv[0], ret); + + co.data = p; + co.length = sz; + + if (opt->content_info_flag) { + heim_octet_string uwco; + heim_oid oid; + + ret = hx509_cms_unwrap_ContentInfo(&co, &oid, &uwco, NULL); + if (ret) + errx(1, "hx509_cms_unwrap_ContentInfo: %d", ret); + + if (der_heim_oid_cmp(&oid, &asn1_oid_id_pkcs7_envelopedData) != 0) + errx(1, "Content is not SignedData"); + der_free_oid(&oid); + + co = uwco; + } + + ret = hx509_certs_init(context, "MEMORY:cert-store", 0, NULL, &certs); + if (ret) + errx(1, "hx509_certs_init: MEMORY: %d", ret); + + certs_strings(context, "store", certs, lock, &opt->certificate_strings); + + if (opt->allow_weak_crypto_flag) + flags |= HX509_CMS_UE_ALLOW_WEAK; + + ret = hx509_cms_unenvelope(context, certs, flags, co.data, co.length, + NULL, 0, &contentType, &o); + if (co.data != p) + der_free_octet_string(&co); + if (ret) + hx509_err(context, 1, ret, "hx509_cms_unenvelope"); + + rk_xfree(p); + hx509_lock_free(lock); + hx509_certs_free(&certs); + der_free_oid(&contentType); + + ret = _hx509_write_file(argv[1], o.data, o.length); + if (ret) + errx(1, "hx509_write_file: %d", ret); + + der_free_octet_string(&o); + + return 0; +} + +int +cms_create_enveloped(struct cms_envelope_options *opt, int argc, char **argv) +{ + heim_oid contentType; + heim_octet_string o; + const heim_oid *enctype = NULL; + hx509_query *q; + hx509_certs certs; + hx509_cert cert; + int ret; + size_t sz; + void *p; + hx509_lock lock; + int flags = 0; + + memset(&contentType, 0, sizeof(contentType)); + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = rk_undumpdata(argv[0], &p, &sz); + if (ret) + err(1, "map_file: %s: %d", argv[0], ret); + + ret = hx509_certs_init(context, "MEMORY:cert-store", 0, NULL, &certs); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + certs_strings(context, "store", certs, lock, &opt->certificate_strings); + + if (opt->allow_weak_crypto_flag) + flags |= HX509_CMS_EV_ALLOW_WEAK; + + if (opt->encryption_type_string) { + enctype = hx509_crypto_enctype_by_name(opt->encryption_type_string); + if (enctype == NULL) + errx(1, "encryption type: %s no found", + opt->encryption_type_string); + } + + ret = hx509_query_alloc(context, &q); + if (ret) + errx(1, "hx509_query_alloc: %d", ret); + + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_ENCIPHERMENT); + + ret = hx509_certs_find(context, certs, q, &cert); + hx509_query_free(context, q); + if (ret) + errx(1, "hx509_certs_find: %d", ret); + + parse_oid(opt->content_type_string, &asn1_oid_id_pkcs7_data, &contentType); + + ret = hx509_cms_envelope_1(context, flags, cert, p, sz, enctype, + &contentType, &o); + if (ret) + errx(1, "hx509_cms_envelope_1: %d", ret); + + hx509_cert_free(cert); + hx509_certs_free(&certs); + rk_xfree(p); + der_free_oid(&contentType); + + if (opt->content_info_flag) { + heim_octet_string wo; + + ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_envelopedData, &o, &wo); + if (ret) + errx(1, "hx509_cms_wrap_ContentInfo: %d", ret); + + der_free_octet_string(&o); + o = wo; + } + + hx509_lock_free(lock); + + ret = _hx509_write_file(argv[1], o.data, o.length); + if (ret) + errx(1, "hx509_write_file: %d", ret); + + der_free_octet_string(&o); + + return 0; +} + +static void +print_certificate(hx509_context hxcontext, hx509_cert cert, int verbose) +{ + const char *fn; + int ret; + + fn = hx509_cert_get_friendly_name(cert); + if (fn) + printf(" friendly name: %s\n", fn); + printf(" private key: %s\n", + _hx509_cert_private_key(cert) ? "yes" : "no"); + + ret = hx509_print_cert(hxcontext, cert, stdout); + if (ret) + errx(1, "failed to print cert"); + + if (verbose) { + hx509_validate_ctx vctx; + + hx509_validate_ctx_init(hxcontext, &vctx); + hx509_validate_ctx_set_print(vctx, hx509_print_stdout, stdout); + hx509_validate_ctx_add_flags(vctx, HX509_VALIDATE_F_VALIDATE); + hx509_validate_ctx_add_flags(vctx, HX509_VALIDATE_F_VERBOSE); + + hx509_validate_cert(hxcontext, vctx, cert); + + hx509_validate_ctx_free(vctx); + } +} + + +struct print_s { + int counter; + int verbose; +}; + +static int HX509_LIB_CALL +print_f(hx509_context hxcontext, void *ctx, hx509_cert cert) +{ + struct print_s *s = ctx; + + printf("cert: %d\n", s->counter++); + print_certificate(context, cert, s->verbose); + + return 0; +} + +static int HX509_LIB_CALL +print_fjson(hx509_context hxcontext, void *ctx, hx509_cert cert) +{ + const Certificate *c = NULL; + char *json = NULL; + + c = _hx509_get_cert(cert); + if (c) + json = print_Certificate(c, ASN1_PRINT_INDENT); + if (json) + printf("%s\n", json); + else + hx509_err(context, 1, errno, "Could not format certificate as JSON"); + free(json); + return 0; +} + + +int +pcert_print(struct print_options *opt, int argc, char **argv) +{ + hx509_certs certs; + hx509_lock lock; + struct print_s s; + + s.counter = 0; + s.verbose = opt->content_flag; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + while(argc--) { + char *sn = fix_store_name(context, argv[0], "FILE"); + int ret; + + ret = hx509_certs_init(context, sn, 0, lock, &certs); + free(sn); + if (ret) { + if (opt->never_fail_flag) { + printf("ignoreing failure: %d\n", ret); + continue; + } + hx509_err(context, 1, ret, "hx509_certs_init"); + } + if (opt->raw_json_flag) { + hx509_certs_iter_f(context, certs, print_fjson, &s); + } else { + if (opt->info_flag) + hx509_certs_info(context, certs, NULL, NULL); + hx509_certs_iter_f(context, certs, print_f, &s); + } + hx509_certs_free(&certs); + argv++; + } + + hx509_lock_free(lock); + + return 0; +} + + +static int HX509_LIB_CALL +validate_f(hx509_context hxcontext, void *ctx, hx509_cert c) +{ + hx509_validate_cert(hxcontext, ctx, c); + return 0; +} + +int +pcert_validate(struct validate_options *opt, int argc, char **argv) +{ + hx509_validate_ctx ctx; + hx509_certs certs; + hx509_lock lock; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + hx509_validate_ctx_init(context, &ctx); + hx509_validate_ctx_set_print(ctx, hx509_print_stdout, stdout); + hx509_validate_ctx_add_flags(ctx, HX509_VALIDATE_F_VALIDATE); + + while(argc--) { + char *sn = fix_store_name(context, argv[0], "FILE"); + int ret; + + ret = hx509_certs_init(context, sn, 0, lock, &certs); + if (ret) + errx(1, "hx509_certs_init: %d", ret); + hx509_certs_iter_f(context, certs, validate_f, ctx); + hx509_certs_free(&certs); + argv++; + free(sn); + } + hx509_validate_ctx_free(ctx); + + hx509_lock_free(lock); + + return 0; +} + +int +certificate_copy(struct certificate_copy_options *opt, int argc, char **argv) +{ + hx509_certs certs; + hx509_lock inlock, outlock = NULL; + char *sn; + int flags = 0; + int store_flags = 0; + int ret; + + hx509_lock_init(context, &inlock); + lock_strings(inlock, &opt->in_pass_strings); + + if (!opt->root_certs_flag) + /* + * We're probably copying an EE cert, its issuer, and all intermediates + * up to and excluding the root. + */ + store_flags |= HX509_CERTS_STORE_NO_ROOTS; + + if (!opt->private_keys_flag) { + /* Neither read nor store private keys */ + store_flags |= HX509_CERTS_NO_PRIVATE_KEYS; + flags |= HX509_CERTS_NO_PRIVATE_KEYS; + } + + if (opt->out_pass_string) { + hx509_lock_init(context, &outlock); + ret = hx509_lock_command_string(outlock, opt->out_pass_string); + if (ret) + errx(1, "hx509_lock_command_string: %s: %d", + opt->out_pass_string, ret); + } + + if (argc < 2) + errx(1, "hxtool copy-certificate requires at least two positional " + "arguments"); + + /* + * The _last_ positional argument is the destination store. Because we use + * HX509_CERTS_CREATE we'll ignore its contents and then truncate to write + * it (well, if it's a file; see key store plugins). + * + * But note that the truncation doesn't happen until we call + * hx509_certs_store(), which means we still have a chance to _read_ this + * store. That means that one can write this: + * + * hxtool cc FILE:b FILE:a FILE:b + * + * to notionally append FILE:a to FILE:b. Still, we'll have an option to + * do the append anyways: + * + * hxtool cc --append FILE:a FILE:b + */ + sn = fix_store_name(context, argv[argc - 1], "FILE"); + ret = hx509_certs_init(context, sn, + HX509_CERTS_CREATE | flags, inlock, &certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init %s", sn); + + if (opt->append_flag) { + /* Append == read the certs in the dst prior to doing anything else */ + ret = hx509_certs_append(context, certs, inlock, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append %s", sn); + } + free(sn); + + /* + * Read all the certificate stores in all but the last positional argument. + */ + while(argc-- > 1) { + sn = fix_store_name(context, argv[0], "FILE"); + ret = hx509_certs_append(context, certs, inlock, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append %s", sn); + free(sn); + argv++; + } + + ret = hx509_certs_store(context, certs, store_flags, outlock); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_store"); + + hx509_certs_free(&certs); + hx509_lock_free(inlock); + hx509_lock_free(outlock); + + return 0; +} + +struct verify { + hx509_verify_ctx ctx; + hx509_certs chain; + const char *hostname; + int errors; + int count; +}; + +static int HX509_LIB_CALL +verify_f(hx509_context hxcontext, void *ctx, hx509_cert c) +{ + struct verify *v = ctx; + int ret; + + ret = hx509_verify_path(hxcontext, v->ctx, c, v->chain); + if (ret) { + char *s = hx509_get_error_string(hxcontext, ret); + printf("verify_path: %s: %d\n", s, ret); + hx509_free_error_string(s); + v->errors++; + } else { + v->count++; + printf("path ok\n"); + } + + if (v->hostname) { + ret = hx509_verify_hostname(hxcontext, c, 0, HX509_HN_HOSTNAME, + v->hostname, NULL, 0); + if (ret) { + printf("verify_hostname: %d\n", ret); + v->errors++; + } + } + + return 0; +} + +int +pcert_verify(struct verify_options *opt, int argc, char **argv) +{ + hx509_certs anchors, chain, certs; + hx509_revoke_ctx revoke_ctx; + hx509_verify_ctx ctx; + struct verify v; + int ret; + + memset(&v, 0, sizeof(v)); + + if (opt->missing_revoke_flag) + hx509_context_set_missing_revoke(context, 1); + + ret = hx509_verify_init_ctx(context, &ctx); + if (ret) + hx509_err(context, 1, ret, "hx509_verify_init_ctx"); + ret = hx509_certs_init(context, "MEMORY:anchors", 0, NULL, &anchors); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + ret = hx509_certs_init(context, "MEMORY:chain", 0, NULL, &chain); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + if (opt->allow_proxy_certificate_flag) + hx509_verify_set_proxy_certificate(ctx, 1); + + if (opt->time_string) { + const char *p; + struct tm tm; + time_t t; + + memset(&tm, 0, sizeof(tm)); + + p = strptime (opt->time_string, "%Y-%m-%d", &tm); + if (p == NULL) + errx(1, "Failed to parse time %s, need to be on format %%Y-%%m-%%d", + opt->time_string); + + t = tm2time (tm, 0); + + hx509_verify_set_time(ctx, t); + } + + if (opt->hostname_string) + v.hostname = opt->hostname_string; + if (opt->max_depth_integer) + hx509_verify_set_max_depth(ctx, opt->max_depth_integer); + + ret = hx509_revoke_init(context, &revoke_ctx); + if (ret) + errx(1, "hx509_revoke_init: %d", ret); + + while(argc--) { + const char *s = *argv++; + char *sn = NULL; + + if (strncmp(s, "chain:", 6) == 0) { + s += 6; + + sn = fix_store_name(context, s, "FILE"); + ret = hx509_certs_append(context, chain, NULL, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append: chain: %s: %d", + sn, ret); + + } else if (strncmp(s, "anchor:", 7) == 0) { + s += 7; + + sn = fix_store_name(context, s, "FILE"); + ret = hx509_certs_append(context, anchors, NULL, sn); + if (ret) + hx509_err(context, 1, ret, + "hx509_certs_append: anchor: %s: %d", sn, ret); + + } else if (strncmp(s, "cert:", 5) == 0) { + s += 5; + + sn = fix_store_name(context, s, "FILE"); + ret = hx509_certs_append(context, certs, NULL, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append: certs: %s: %d", + sn, ret); + + } else if (strncmp(s, "crl:", 4) == 0) { + s += 4; + + ret = hx509_revoke_add_crl(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_crl: %s: %d", s, ret); + + } else if (strncmp(s, "ocsp:", 5) == 0) { + s += 5; + + ret = hx509_revoke_add_ocsp(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_ocsp: %s: %d", s, ret); + + } else { + errx(1, "unknown option to verify: `%s'\n", s); + } + free(sn); + } + + hx509_verify_attach_anchors(ctx, anchors); + hx509_verify_attach_revoke(ctx, revoke_ctx); + + v.ctx = ctx; + v.chain = chain; + + hx509_certs_iter_f(context, certs, verify_f, &v); + + hx509_verify_destroy_ctx(ctx); + + hx509_certs_free(&certs); + hx509_certs_free(&chain); + hx509_certs_free(&anchors); + + hx509_revoke_free(&revoke_ctx); + + + if (v.count == 0) { + printf("no certs verify at all\n"); + return 1; + } + + if (v.errors) { + printf("failed verifing %d checks\n", v.errors); + return 1; + } + + return 0; +} + +int +query(struct query_options *opt, int argc, char **argv) +{ + hx509_lock lock; + hx509_query *q; + hx509_certs certs; + hx509_cert c; + int ret; + + ret = hx509_query_alloc(context, &q); + if (ret) + errx(1, "hx509_query_alloc: %d", ret); + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = hx509_certs_init(context, "MEMORY:cert-store", 0, NULL, &certs); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + while (argc > 0) { + char *sn = fix_store_name(context, argv[0], "FILE"); + + ret = hx509_certs_append(context, certs, lock, sn); + if (ret) + errx(1, "hx509_certs_append: %s: %d", sn, ret); + free(sn); + + argc--; + argv++; + } + + if (opt->friendlyname_string) + hx509_query_match_friendly_name(q, opt->friendlyname_string); + + if (opt->eku_string) { + heim_oid oid; + + parse_oid(opt->eku_string, NULL, &oid); + + ret = hx509_query_match_eku(q, &oid); + if (ret) + errx(1, "hx509_query_match_eku: %d", ret); + der_free_oid(&oid); + } + + if (opt->private_key_flag) + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + + if (opt->keyEncipherment_flag) + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_ENCIPHERMENT); + + if (opt->digitalSignature_flag) + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + + if (opt->expr_string) + hx509_query_match_expr(context, q, opt->expr_string); + + ret = hx509_certs_find(context, certs, q, &c); + hx509_query_free(context, q); + if (ret) + printf("no match found (%d)\n", ret); + else { + printf("match found\n"); + if (opt->print_flag) + print_certificate(context, c, 0); + } + + hx509_cert_free(c); + hx509_certs_free(&certs); + + hx509_lock_free(lock); + + return ret; +} + +int +ocsp_fetch(struct ocsp_fetch_options *opt, int argc, char **argv) +{ + hx509_certs reqcerts, pool; + heim_octet_string req, nonce_data, *nonce = &nonce_data; + hx509_lock lock; + int i, ret; + char *file; + const char *url = "/"; + + memset(&nonce, 0, sizeof(nonce)); + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + /* no nonce */ + if (!opt->nonce_flag) + nonce = NULL; + + if (opt->url_path_string) + url = opt->url_path_string; + + ret = hx509_certs_init(context, "MEMORY:ocsp-pool", 0, NULL, &pool); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + certs_strings(context, "ocsp-pool", pool, lock, &opt->pool_strings); + + file = argv[0]; + + ret = hx509_certs_init(context, "MEMORY:ocsp-req", 0, NULL, &reqcerts); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + for (i = 1; i < argc; i++) { + char *sn = fix_store_name(context, argv[i], "FILE"); + + ret = hx509_certs_append(context, reqcerts, lock, sn); + if (ret) + errx(1, "hx509_certs_append: req: %s: %d", sn, ret); + free(sn); + } + + ret = hx509_ocsp_request(context, reqcerts, pool, NULL, NULL, &req, nonce); + if (ret) + errx(1, "hx509_ocsp_request: req: %d", ret); + + { + FILE *f; + + f = fopen(file, "w"); + if (f == NULL) + abort(); + + fprintf(f, + "POST %s HTTP/1.0\r\n" + "Content-Type: application/ocsp-request\r\n" + "Content-Length: %ld\r\n" + "\r\n", + url, + (unsigned long)req.length); + fwrite(req.data, req.length, 1, f); + fclose(f); + } + + if (nonce) + der_free_octet_string(nonce); + + hx509_certs_free(&reqcerts); + hx509_certs_free(&pool); + + return 0; +} + +int +ocsp_print(struct ocsp_print_options *opt, int argc, char **argv) +{ + hx509_revoke_ocsp_print(context, argv[0], stdout); + return 0; +} + +int +revoke_print(struct revoke_print_options *opt, int argc, char **argv) +{ + hx509_revoke_ctx revoke_ctx; + int ret; + + ret = hx509_revoke_init(context, &revoke_ctx); + if (ret) + errx(1, "hx509_revoke_init: %d", ret); + + while(argc--) { + char *s = *argv++; + + if (strncmp(s, "crl:", 4) == 0) { + s += 4; + + ret = hx509_revoke_add_crl(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_crl: %s: %d", s, ret); + + } else if (strncmp(s, "ocsp:", 5) == 0) { + s += 5; + + ret = hx509_revoke_add_ocsp(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_ocsp: %s: %d", s, ret); + + } else { + errx(1, "unknown option to verify: `%s'\n", s); + } + } + + ret = hx509_revoke_print(context, revoke_ctx, stdout); + if (ret) + warnx("hx509_revoke_print: %d", ret); + + hx509_revoke_free(&revoke_ctx); + return ret; +} + +/* + * + */ + +static int HX509_LIB_CALL +verify_o(hx509_context hxcontext, void *ctx, hx509_cert c) +{ + heim_octet_string *os = ctx; + time_t expiration; + int ret; + + ret = hx509_ocsp_verify(context, 0, c, 0, + os->data, os->length, &expiration); + if (ret) { + char *s = hx509_get_error_string(hxcontext, ret); + printf("ocsp_verify: %s: %d\n", s, ret); + hx509_free_error_string(s); + } else + printf("expire: %d\n", (int)expiration); + + return ret; +} + + +int +ocsp_verify(struct ocsp_verify_options *opt, int argc, char **argv) +{ + hx509_lock lock; + hx509_certs certs; + int ret, i; + heim_octet_string os; + + hx509_lock_init(context, &lock); + + if (opt->ocsp_file_string == NULL) + errx(1, "no ocsp file given"); + + ret = _hx509_map_file_os(opt->ocsp_file_string, &os); + if (ret) + err(1, "map_file: %s: %d", argv[0], ret); + + ret = hx509_certs_init(context, "MEMORY:test-certs", 0, NULL, &certs); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + for (i = 0; i < argc; i++) { + char *sn = fix_store_name(context, argv[i], "FILE"); + + ret = hx509_certs_append(context, certs, lock, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append: %s", sn); + free(sn); + } + + ret = hx509_certs_iter_f(context, certs, verify_o, &os); + + hx509_certs_free(&certs); + _hx509_unmap_file_os(&os); + hx509_lock_free(lock); + + return ret; +} + +static int +read_private_key(const char *fn, hx509_private_key *key) +{ + hx509_private_key *keys; + hx509_certs certs; + char *sn = fix_store_name(context, fn, "FILE"); + int ret; + + *key = NULL; + + ret = hx509_certs_init(context, sn, 0, NULL, &certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: %s", sn); + + ret = _hx509_certs_keys_get(context, certs, &keys); + hx509_certs_free(&certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_keys_get"); + if (keys[0] == NULL) + errx(1, "no keys in key store: %s", sn); + free(sn); + + *key = _hx509_private_key_ref(keys[0]); + _hx509_certs_keys_free(context, keys); + + return 0; +} + +static void +get_key(const char *fn, const char *type, int optbits, + hx509_private_key *signer) +{ + int ret = 0; + + if (type) { + struct hx509_generate_private_context *gen_ctx = NULL; + + if (strcasecmp(type, "rsa") != 0) + errx(1, "can only handle rsa keys for now"); + + ret = _hx509_generate_private_key_init(context, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &gen_ctx); + if (ret == 0) + ret = _hx509_generate_private_key_bits(context, gen_ctx, optbits); + if (ret == 0) + ret = _hx509_generate_private_key(context, gen_ctx, signer); + _hx509_generate_private_key_free(&gen_ctx); + if (ret) + hx509_err(context, 1, ret, "failed to generate private key of type %s", type); + + if (fn) { + char *sn = fix_store_name(context, fn, "FILE"); + hx509_certs certs = NULL; + hx509_cert cert = NULL; + + cert = hx509_cert_init_private_key(context, *signer, NULL); + if (cert) + ret = hx509_certs_init(context, sn, + HX509_CERTS_CREATE | + HX509_CERTS_UNPROTECT_ALL, + NULL, &certs); + if (ret == 0) + ret = hx509_certs_add(context, certs, cert); + if (ret == 0) + ret = hx509_certs_store(context, certs, 0, NULL); + if (ret) + hx509_err(context, 1, ret, "failed to store generated private " + "key in %s", sn); + + if (certs) + hx509_certs_free(&certs); + if (cert) + hx509_cert_free(cert); + free(sn); + } + } else { + if (fn == NULL) + err(1, "no private key"); + ret = read_private_key(fn, signer); + if (ret) + hx509_err(context, 1, ret, "failed to read private key from %s", + fn); + } +} + +int +generate_key(struct generate_key_options *opt, int argc, char **argv) +{ + hx509_private_key signer; + const char *type = opt->type_string ? opt->type_string : "rsa"; + int bits = opt->key_bits_integer ? opt->key_bits_integer : 2048; + + memset(&signer, 0, sizeof(signer)); + get_key(argv[0], type, bits, &signer); + hx509_private_key_free(&signer); + return 0; +} + +int +request_create(struct request_create_options *opt, int argc, char **argv) +{ + heim_octet_string request; + hx509_request req; + int ret, i; + hx509_private_key signer; + SubjectPublicKeyInfo key; + const char *outfile = argv[0]; + + memset(&key, 0, sizeof(key)); + memset(&signer, 0, sizeof(signer)); + + get_key(opt->key_string, + opt->generate_key_string, + opt->key_bits_integer, + &signer); + + ret = hx509_request_init(context, &req); + if (ret) + hx509_err(context, 1, ret, "Could not initialize CSR context"); + + if (opt->ca_flag && opt->ee_flag) + errx(1, "request-create --ca and --ee are mutually exclusive"); + + if (opt->ca_flag) { + unsigned pathLenConstraint = 0; + unsigned *pathLenConstraintPtr = NULL; + + if (opt->ca_path_length_integer > 0 && + opt->ca_path_length_integer < INT_MAX) { + pathLenConstraint = opt->ca_path_length_integer; + pathLenConstraintPtr = &pathLenConstraint; + } + ret = hx509_request_set_cA(context, req, pathLenConstraintPtr); + if (ret) + errx(1, "hx509_request_set_cA: %d\n", ret); + } else if (opt->ee_flag) { + hx509_request_set_eE(context, req); + } + + if (opt->subject_string) { + hx509_name name = NULL; + + ret = hx509_parse_name(context, opt->subject_string, &name); + if (ret) + errx(1, "hx509_parse_name: %d\n", ret); + hx509_request_set_name(context, req, name); + + if (opt->verbose_flag) { + char *s; + hx509_name_to_string(name, &s); + printf("%s\n", s); + free(s); + } + hx509_name_free(&name); + } + + for (i = 0; i < opt->email_strings.num_strings; i++) { + ret = hx509_request_add_email(context, req, + opt->email_strings.strings[i]); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_email"); + } + + for (i = 0; i < opt->jid_strings.num_strings; i++) { + ret = hx509_request_add_xmpp_name(context, req, + opt->jid_strings.strings[i]); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_xmpp_name"); + } + + for (i = 0; i < opt->dnsname_strings.num_strings; i++) { + ret = hx509_request_add_dns_name(context, req, + opt->dnsname_strings.strings[i]); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_dns_name"); + } + + for (i = 0; i < opt->kerberos_strings.num_strings; i++) { + ret = hx509_request_add_pkinit(context, req, + opt->kerberos_strings.strings[i]); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_pkinit"); + } + + for (i = 0; i < opt->ms_kerberos_strings.num_strings; i++) { + ret = hx509_request_add_ms_upn_name(context, req, + opt->ms_kerberos_strings.strings[i]); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_ms_upn_name"); + } + + for (i = 0; i < opt->registered_strings.num_strings; i++) { + heim_oid oid; + + parse_oid(opt->registered_strings.strings[i], NULL, &oid); + ret = hx509_request_add_registered(context, req, &oid); + der_free_oid(&oid); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_registered"); + } + + for (i = 0; i < opt->eku_strings.num_strings; i++) { + heim_oid oid; + + parse_oid(opt->eku_strings.strings[i], NULL, &oid); + ret = hx509_request_add_eku(context, req, &oid); + der_free_oid(&oid); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_eku"); + } + + + ret = hx509_private_key2SPKI(context, signer, &key); + if (ret) + errx(1, "hx509_private_key2SPKI: %d\n", ret); + + ret = hx509_request_set_SubjectPublicKeyInfo(context, + req, + &key); + free_SubjectPublicKeyInfo(&key); + if (ret) + hx509_err(context, 1, ret, "hx509_request_set_SubjectPublicKeyInfo"); + + ret = hx509_request_to_pkcs10(context, + req, + signer, + &request); + if (ret) + hx509_err(context, 1, ret, "hx509_request_to_pkcs10"); + + hx509_private_key_free(&signer); + hx509_request_free(&req); + + if (ret == 0) + rk_dumpdata(outfile, request.data, request.length); + der_free_octet_string(&request); + + return 0; +} + +int +request_print(struct request_print_options *opt, int argc, char **argv) +{ + int ret, i; + + printf("request print\n"); + + for (i = 0; i < argc; i++) { + hx509_request req; + char *cn = fix_csr_name(argv[i], "PKCS10"); + + ret = hx509_request_parse(context, cn, &req); + if (ret) + hx509_err(context, 1, ret, "parse_request: %s", cn); + + ret = hx509_request_print(context, req, stdout); + hx509_request_free(&req); + if (ret) + hx509_err(context, 1, ret, "Failed to print file %s", cn); + free(cn); + } + + return 0; +} + +int +info(void *opt, int argc, char **argv) +{ + + ENGINE_add_conf_module(); + + { + const RSA_METHOD *m = RSA_get_default_method(); + if (m != NULL) + printf("rsa: %s\n", m->name); + } + { + const DH_METHOD *m = DH_get_default_method(); + if (m != NULL) + printf("dh: %s\n", m->name); + } +#ifdef HAVE_HCRYPTO_W_OPENSSL + { + printf("ecdsa: ECDSA_METHOD-not-export\n"); + } +#else + { + printf("ecdsa: hcrypto null\n"); + } +#endif + { + int ret = RAND_status(); + printf("rand: %s\n", ret == 1 ? "ok" : "not available"); + } + + return 0; +} + +int +random_data(void *opt, int argc, char **argv) +{ + void *ptr; + ssize_t len; + int64_t bytes; + int ret; + + bytes = parse_bytes(argv[0], "byte"); + if (bytes <= 0 || bytes > SSIZE_MAX) { + fprintf(stderr, "bad argument to random-data\n"); + return 1; + } + len = bytes; + + ptr = malloc(len); + if (ptr == NULL) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + ret = RAND_bytes(ptr, len); + if (ret != 1) { + free(ptr); + fprintf(stderr, "did not get cryptographic strong random\n"); + return 1; + } + + fwrite(ptr, len, 1, stdout); + fflush(stdout); + + free(ptr); + + return 0; +} + +int +crypto_available(struct crypto_available_options *opt, int argc, char **argv) +{ + AlgorithmIdentifier *val; + unsigned int len, i; + int ret, type = HX509_SELECT_ALL; + + if (opt->type_string) { + if (strcmp(opt->type_string, "all") == 0) + type = HX509_SELECT_ALL; + else if (strcmp(opt->type_string, "digest") == 0) + type = HX509_SELECT_DIGEST; + else if (strcmp(opt->type_string, "public-sig") == 0) + type = HX509_SELECT_PUBLIC_SIG; + else if (strcmp(opt->type_string, "secret") == 0) + type = HX509_SELECT_SECRET_ENC; + else + errx(1, "unknown type: %s", opt->type_string); + } + + ret = hx509_crypto_available(context, type, NULL, &val, &len); + if (ret) + errx(1, "hx509_crypto_available"); + + for (i = 0; i < len; i++) { + char *s; + if (opt->oid_syms_flag) + der_print_heim_oid_sym(&val[i].algorithm, '.', &s); + else + der_print_heim_oid(&val[i].algorithm, '.', &s); + printf("%s\n", s); + free(s); + } + + hx509_crypto_free_algs(val, len); + + return 0; +} + +int +crypto_select(struct crypto_select_options *opt, int argc, char **argv) +{ + hx509_peer_info peer = NULL; + AlgorithmIdentifier selected; + int ret, type = HX509_SELECT_DIGEST; + char *s; + + if (opt->type_string) { + if (strcmp(opt->type_string, "digest") == 0) + type = HX509_SELECT_DIGEST; + else if (strcmp(opt->type_string, "public-sig") == 0) + type = HX509_SELECT_PUBLIC_SIG; + else if (strcmp(opt->type_string, "secret") == 0) + type = HX509_SELECT_SECRET_ENC; + else + errx(1, "unknown type: %s", opt->type_string); + } + + if (opt->peer_cmstype_strings.num_strings) + peer_strings(context, &peer, &opt->peer_cmstype_strings); + + ret = hx509_crypto_select(context, type, NULL, peer, &selected); + if (ret) + errx(1, "hx509_crypto_available"); + + if (opt->oid_sym_flag) + der_print_heim_oid_sym(&selected.algorithm, '.', &s); + else + der_print_heim_oid(&selected.algorithm, '.', &s); + printf("%s\n", s); + free(s); + free_AlgorithmIdentifier(&selected); + + hx509_peer_info_free(peer); + + return 0; +} + +int +hxtool_hex(struct hex_options *opt, int argc, char **argv) +{ + + if (opt->decode_flag) { + char buf[1024], buf2[1024], *p; + ssize_t len; + + while(fgets(buf, sizeof(buf), stdin) != NULL) { + buf[strcspn(buf, "\r\n")] = '\0'; + p = buf; + while(isspace(*(unsigned char *)p)) + p++; + len = hex_decode(p, buf2, strlen(p)); + if (len < 0) + errx(1, "hex_decode failed"); + if (fwrite(buf2, 1, len, stdout) != (size_t)len) + errx(1, "fwrite failed"); + } + } else { + char buf[28], *p; + ssize_t len; + + while((len = fread(buf, 1, sizeof(buf), stdin)) != 0) { + len = hex_encode(buf, len, &p); + if (len < 0) + continue; + fprintf(stdout, "%s\n", p); + free(p); + } + } + return 0; +} + +struct cert_type_opt { + int pkinit; +}; + + +static int +https_server(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + return hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkix_kp_serverAuth); +} + +static int +https_negotiate_server(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + int ret = hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkekuoid); + if (ret == 0) + ret = hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkix_kp_serverAuth); + opt->pkinit++; + return ret; +} + +static int +https_client(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + return hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkix_kp_clientAuth); +} + +static int +peap_server(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + return hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkix_kp_serverAuth); +} + +static int +pkinit_kdc(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + opt->pkinit++; + return hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkkdcekuoid); +} + +static int +pkinit_client(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + int ret; + + opt->pkinit++; + + ret = hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkekuoid); + if (ret) + return ret; + + ret = hx509_ca_tbs_add_eku(context, tbs, &asn1_oid_id_pkix_kp_clientAuth); + if (ret) + return ret; + + return hx509_ca_tbs_add_eku(context, tbs, &asn1_oid_id_pkinit_ms_eku); +} + +static int +email_client(hx509_context contextp, hx509_ca_tbs tbs, struct cert_type_opt *opt) +{ + return hx509_ca_tbs_add_eku(contextp, tbs, &asn1_oid_id_pkix_kp_emailProtection); +} + +struct { + const char *type; + const char *desc; + int (*eval)(hx509_context, hx509_ca_tbs, struct cert_type_opt *); +} certtypes[] = { + { + "https-server", + "Used for HTTPS server and many other TLS server certificate types", + https_server + }, + { + "https-client", + "Used for HTTPS client certificates", + https_client + }, + { + "email-client", + "Certificate will be use for email", + email_client + }, + { + "pkinit-client", + "Certificate used for Kerberos PK-INIT client certificates", + pkinit_client + }, + { + "pkinit-kdc", + "Certificates used for Kerberos PK-INIT KDC certificates", + pkinit_kdc + }, + { + "https-negotiate-server", + "Used for HTTPS server and many other TLS server certificate types", + https_negotiate_server + }, + { + "peap-server", + "Certificate used for Radius PEAP (Protected EAP)", + peap_server + } +}; + +static void +print_eval_types(FILE *out) +{ + rtbl_t table; + unsigned i; + + table = rtbl_create(); + rtbl_add_column_by_id (table, 0, "Name", 0); + rtbl_add_column_by_id (table, 1, "Description", 0); + + for (i = 0; i < sizeof(certtypes)/sizeof(certtypes[0]); i++) { + rtbl_add_column_entry_by_id(table, 0, certtypes[i].type); + rtbl_add_column_entry_by_id(table, 1, certtypes[i].desc); + } + + rtbl_format (table, out); + rtbl_destroy (table); +} + +static int +eval_types(hx509_context contextp, + hx509_ca_tbs tbs, + const struct certificate_sign_options *opt) +{ + struct cert_type_opt ctopt; + int i; + size_t j; + int ret; + + memset(&ctopt, 0, sizeof(ctopt)); + + for (i = 0; i < opt->type_strings.num_strings; i++) { + const char *type = opt->type_strings.strings[i]; + + for (j = 0; j < sizeof(certtypes)/sizeof(certtypes[0]); j++) { + if (strcasecmp(type, certtypes[j].type) == 0) { + ret = (*certtypes[j].eval)(contextp, tbs, &ctopt); + if (ret) + hx509_err(contextp, 1, ret, + "Failed to evaluate cert type %s", type); + break; + } + } + if (j >= sizeof(certtypes)/sizeof(certtypes[0])) { + fprintf(stderr, "Unknown certificate type %s\n\n", type); + fprintf(stderr, "Available types:\n"); + print_eval_types(stderr); + exit(1); + } + } + + for (i = 0; i < opt->pk_init_principal_strings.num_strings; i++) { + const char *pk_init_princ = opt->pk_init_principal_strings.strings[i]; + + if (!ctopt.pkinit) + errx(1, "pk-init principal given but no pk-init oid"); + + ret = hx509_ca_tbs_add_san_pkinit(contextp, tbs, pk_init_princ); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_pkinit"); + } + + if (opt->ms_upn_string) { + if (!ctopt.pkinit) + errx(1, "MS upn given but no pk-init oid"); + + ret = hx509_ca_tbs_add_san_ms_upn(contextp, tbs, opt->ms_upn_string); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_ms_upn"); + } + + + for (i = 0; i < opt->hostname_strings.num_strings; i++) { + const char *hostname = opt->hostname_strings.strings[i]; + + ret = hx509_ca_tbs_add_san_hostname(contextp, tbs, hostname); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_hostname"); + } + + for (i = 0; i < opt->dnssrv_strings.num_strings; i++) { + const char *dnssrv = opt->dnssrv_strings.strings[i]; + + ret = hx509_ca_tbs_add_san_dnssrv(contextp, tbs, dnssrv); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_dnssrv"); + } + + for (i = 0; i < opt->email_strings.num_strings; i++) { + const char *email = opt->email_strings.strings[i]; + + ret = hx509_ca_tbs_add_san_rfc822name(contextp, tbs, email); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_hostname"); + + ret = hx509_ca_tbs_add_eku(contextp, tbs, + &asn1_oid_id_pkix_kp_emailProtection); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_eku"); + } + + if (opt->jid_string) { + ret = hx509_ca_tbs_add_san_jid(contextp, tbs, opt->jid_string); + if (ret) + hx509_err(contextp, 1, ret, "hx509_ca_tbs_add_san_jid"); + } + + return 0; +} + +int +hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv) +{ + int ret; + hx509_ca_tbs tbs; + hx509_cert signer = NULL, cert = NULL; + hx509_private_key private_key = NULL; + hx509_private_key cert_key = NULL; + hx509_name subject = NULL; + SubjectPublicKeyInfo spki; + heim_oid oid; + size_t i; + int delta = 0; + + memset(&oid, 0, sizeof(oid)); + memset(&spki, 0, sizeof(spki)); + + if (opt->ca_certificate_string == NULL && !opt->self_signed_flag) + errx(1, "--ca-certificate argument missing (not using --self-signed)"); + if (opt->ca_private_key_string == NULL && opt->generate_key_string == NULL && opt->self_signed_flag) + errx(1, "--ca-private-key argument missing (using --self-signed)"); + if (opt->certificate_string == NULL) + errx(1, "--certificate argument missing"); + + if (opt->template_certificate_string && opt->template_fields_string == NULL) + errx(1, "--template-certificate used but no --template-fields given"); + + if (opt->lifetime_string) { + delta = parse_time(opt->lifetime_string, "day"); + if (delta < 0) + errx(1, "Invalid lifetime: %s", opt->lifetime_string); + } + + if (opt->ca_certificate_string) { + hx509_certs cacerts = NULL; + hx509_query *q; + char *sn = fix_store_name(context, opt->ca_certificate_string, "FILE"); + + ret = hx509_certs_init(context, sn, 0, NULL, &cacerts); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: %s", sn); + + ret = hx509_query_alloc(context, &q); + if (ret) + errx(1, "hx509_query_alloc: %d", ret); + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + if (!opt->issue_proxy_flag) + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_KEYCERTSIGN); + + ret = hx509_certs_find(context, cacerts, q, &signer); + hx509_query_free(context, q); + hx509_certs_free(&cacerts); + if (ret) + hx509_err(context, 1, ret, "no CA certificate found"); + free(sn); + } else if (opt->self_signed_flag) { + if (opt->generate_key_string == NULL + && opt->ca_private_key_string == NULL) + errx(1, "no signing private key"); + + if (opt->req_string) + errx(1, "can't be self-signing and have a request at the same time"); + } else + errx(1, "missing ca key"); + + if (opt->ca_private_key_string) { + + ret = read_private_key(opt->ca_private_key_string, &private_key); + if (ret) + err(1, "read_private_key"); + + ret = hx509_private_key2SPKI(context, private_key, &spki); + if (ret) + errx(1, "hx509_private_key2SPKI: %d\n", ret); + + if (opt->self_signed_flag) + cert_key = private_key; + } + + if (opt->req_string) { + hx509_request req; + char *cn = fix_csr_name(opt->req_string, "PKCS10"); + + /* + * Extract the CN and other attributes we want to preserve from the + * requested subjectName and then set them in the hx509_env for the + * template. + */ + ret = hx509_request_parse(context, cn, &req); + if (ret) + hx509_err(context, 1, ret, "parse_request: %s", cn); + ret = hx509_request_get_name(context, req, &subject); + if (ret) + hx509_err(context, 1, ret, "get name"); + ret = hx509_request_get_SubjectPublicKeyInfo(context, req, &spki); + if (ret) + hx509_err(context, 1, ret, "get spki"); + hx509_request_free(&req); + free(cn); + } + + if (opt->generate_key_string) { + /* + * Note that we used to set isCA in the key gen context. Now that we + * use get_key() we no longer set isCA in the key gen context. But + * nothing uses that field of the key gen context. + */ + get_key(opt->certificate_private_key_string, + opt->generate_key_string, + opt->key_bits_integer, + &cert_key); + + ret = hx509_private_key2SPKI(context, cert_key, &spki); + if (ret) + errx(1, "hx509_private_key2SPKI: %d\n", ret); + + if (opt->self_signed_flag) + private_key = cert_key; + } else if (opt->certificate_private_key_string) { + ret = read_private_key(opt->certificate_private_key_string, &cert_key); + if (ret) + err(1, "read_private_key for certificate"); + + ret = hx509_private_key2SPKI(context, cert_key, &spki); + if (ret) + errx(1, "hx509_private_key2SPKI: %d\n", ret); + + if (opt->self_signed_flag) + private_key = cert_key; + } + + if (opt->subject_string) { + if (subject) + hx509_name_free(&subject); + ret = hx509_parse_name(context, opt->subject_string, &subject); + if (ret) + hx509_err(context, 1, ret, "hx509_parse_name"); + } + + /* + * + */ + + ret = hx509_ca_tbs_init(context, &tbs); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_init"); + + for (i = 0; i < opt->eku_strings.num_strings; i++) { + parse_oid(opt->eku_strings.strings[i], NULL, &oid); + ret = hx509_ca_tbs_add_eku(context, tbs, &oid); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_eku"); + der_free_oid(&oid); + } + if (opt->ku_strings.num_strings) { + const struct units *kus = asn1_KeyUsage_units(); + const struct units *kup; + uint64_t n = 0; + + for (i = 0; i < opt->ku_strings.num_strings; i++) { + for (kup = kus; kup->name; kup++) { + if (strcmp(kup->name, opt->ku_strings.strings[i])) + continue; + n |= kup->mult; + break; + } + } + ret = hx509_ca_tbs_add_ku(context, tbs, int2KeyUsage(n)); + if (ret) + hx509_err(context, 1, ret, "hx509_request_add_ku"); + } + if (opt->signature_algorithm_string) { + const AlgorithmIdentifier *sigalg; + if (strcasecmp(opt->signature_algorithm_string, "rsa-with-sha1") == 0) + sigalg = hx509_signature_rsa_with_sha1(); + else if (strcasecmp(opt->signature_algorithm_string, "rsa-with-sha256") == 0) + sigalg = hx509_signature_rsa_with_sha256(); + else + errx(1, "unsupported sigature algorithm"); + hx509_ca_tbs_set_signature_algorithm(context, tbs, sigalg); + } + + if (opt->template_certificate_string) { + hx509_cert template; + hx509_certs tcerts; + char *sn = fix_store_name(context, opt->template_certificate_string, + "FILE"); + int flags; + + ret = hx509_certs_init(context, sn, 0, NULL, &tcerts); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: %s", sn); + + ret = hx509_get_one_cert(context, tcerts, &template); + + hx509_certs_free(&tcerts); + if (ret) + hx509_err(context, 1, ret, "no template certificate found"); + + flags = parse_units(opt->template_fields_string, + hx509_ca_tbs_template_units(), ""); + + ret = hx509_ca_tbs_set_template(context, tbs, flags, template); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_template"); + + hx509_cert_free(template); + free(sn); + } + + if (opt->serial_number_string) { + heim_integer serialNumber; + + ret = der_parse_hex_heim_integer(opt->serial_number_string, + &serialNumber); + if (ret) + err(1, "der_parse_hex_heim_integer"); + ret = hx509_ca_tbs_set_serialnumber(context, tbs, &serialNumber); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_init"); + der_free_heim_integer(&serialNumber); + } + + if (spki.subjectPublicKey.length) { + ret = hx509_ca_tbs_set_spki(context, tbs, &spki); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_spki"); + } + + if (subject) { + ret = hx509_ca_tbs_set_subject(context, tbs, subject); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_subject"); + } + + if (opt->crl_uri_string) { + ret = hx509_ca_tbs_add_crl_dp_uri(context, tbs, + opt->crl_uri_string, NULL); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_add_crl_dp_uri"); + } + + eval_types(context, tbs, opt); + + if (opt->permanent_id_string) { + ret = hx509_ca_tbs_add_san_permanentIdentifier_string(context, tbs, + opt->permanent_id_string); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_add_san_permanentIdentifier"); + } + + if (opt->hardware_module_name_string) { + ret = hx509_ca_tbs_add_san_hardwareModuleName_string(context, tbs, + opt->hardware_module_name_string); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_add_san_hardwareModuleName_string"); + } + + for (i = 0; ret == 0 && i < opt->policy_strings.num_strings; i++) { + char *oidstr, *uri, *dt; + + if ((oidstr = strdup(opt->policy_strings.strings[i])) == NULL) + hx509_err(context, 1, ENOMEM, "out of memory"); + uri = strchr(oidstr, ':'); + if (uri) + *(uri++) = '\0'; + dt = strchr(uri ? uri : "", ' '); + if (dt) + *(dt++) = '\0'; + + parse_oid(oidstr, NULL, &oid); + ret = hx509_ca_tbs_add_pol(context, tbs, &oid, uri, dt); + der_free_oid(&oid); + free(oidstr); + } + + for (i = 0; ret == 0 && i < opt->policy_mapping_strings.num_strings; i++) { + char *issuer_oidstr, *subject_oidstr; + heim_oid issuer_oid, subject_oid; + + if ((issuer_oidstr = + strdup(opt->policy_mapping_strings.strings[i])) == NULL) + hx509_err(context, 1, ENOMEM, "out of memory"); + subject_oidstr = strchr(issuer_oidstr, ':'); + if (subject_oidstr == NULL) + subject_oidstr = issuer_oidstr; + else + *(subject_oidstr++) = '\0'; + + parse_oid(issuer_oidstr, NULL, &issuer_oid); + parse_oid(subject_oidstr, NULL, &subject_oid); + ret = hx509_ca_tbs_add_pol_mapping(context, tbs, &issuer_oid, + &subject_oid); + if (ret) + hx509_err(context, 1, ret, "failed to add policy mapping"); + der_free_oid(&issuer_oid); + der_free_oid(&subject_oid); + free(issuer_oidstr); + } + + if (opt->issue_ca_flag) { + ret = hx509_ca_tbs_set_ca(context, tbs, opt->path_length_integer); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_ca"); + } + if (opt->issue_proxy_flag) { + ret = hx509_ca_tbs_set_proxy(context, tbs, opt->path_length_integer); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_proxy"); + } + if (opt->domain_controller_flag) { + hx509_ca_tbs_set_domaincontroller(context, tbs); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_domaincontroller"); + } + + if (delta) { + ret = hx509_ca_tbs_set_notAfter_lifetime(context, tbs, delta); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_notAfter_lifetime"); + } + if (opt->pkinit_max_life_string) { + time_t t = parse_time(opt->pkinit_max_life_string, "s"); + + ret = hx509_ca_tbs_set_pkinit_max_life(context, tbs, t); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_tbs_set_pkinit_max_life"); + } + + if (opt->self_signed_flag) { + ret = hx509_ca_sign_self(context, tbs, private_key, &cert); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_sign_self"); + } else { + ret = hx509_ca_sign(context, tbs, signer, &cert); + if (ret) + hx509_err(context, 1, ret, "hx509_ca_sign"); + } + + /* Copy the private key to the output store, maybe */ + if (cert_key && opt->generate_key_string && + !opt->certificate_private_key_string) { + /* + * Yes: because we're generating the key and --certificate-private-key + * was not given. + */ + ret = _hx509_cert_assign_key(cert, cert_key); + if (ret) + hx509_err(context, 1, ret, "_hx509_cert_assign_key"); + } else if (opt->certificate_private_key_string && opt->certificate_string && + strcmp(opt->certificate_private_key_string, + opt->certificate_string) == 0) { + /* + * Yes: because we're re-writing the store whence the private key. We + * would lose the key otherwise. + */ + ret = _hx509_cert_assign_key(cert, cert_key); + if (ret) + hx509_err(context, 1, ret, "_hx509_cert_assign_key"); + } else if (opt->self_signed_flag && opt->ca_private_key_string && + opt->certificate_string && + strcmp(opt->ca_private_key_string, + opt->certificate_string) == 0) { + /* Yes: same as preceding */ + ret = _hx509_cert_assign_key(cert, cert_key); + if (ret) + hx509_err(context, 1, ret, "_hx509_cert_assign_key"); + } + + { + hx509_certs certs; + char *sn = fix_store_name(context, opt->certificate_string, "FILE"); + + ret = hx509_certs_init(context, sn, HX509_CERTS_CREATE, NULL, &certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init"); + + ret = hx509_certs_add(context, certs, cert); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_add"); + + ret = hx509_certs_store(context, certs, 0, NULL); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_store"); + + hx509_certs_free(&certs); + free(sn); + } + + if (subject) + hx509_name_free(&subject); + if (signer) + hx509_cert_free(signer); + hx509_cert_free(cert); + free_SubjectPublicKeyInfo(&spki); + + if (private_key != cert_key) + hx509_private_key_free(&private_key); + hx509_private_key_free(&cert_key); + + hx509_ca_tbs_free(&tbs); + + return 0; +} + +static int HX509_LIB_CALL +test_one_cert(hx509_context hxcontext, void *ctx, hx509_cert cert) +{ + heim_octet_string sd, c; + hx509_verify_ctx vctx = ctx; + hx509_certs signer = NULL; + heim_oid type; + int ret; + + if (_hx509_cert_private_key(cert) == NULL) + return 0; + + ret = hx509_cms_create_signed_1(context, 0, NULL, NULL, 0, + NULL, cert, NULL, NULL, NULL, &sd); + if (ret) + errx(1, "hx509_cms_create_signed_1"); + + ret = hx509_cms_verify_signed(context, vctx, 0, sd.data, sd.length, + NULL, NULL, &type, &c, &signer); + free(sd.data); + if (ret) + hx509_err(context, 1, ret, "hx509_cms_verify_signed"); + + printf("create-signature verify-sigature done\n"); + + free(c.data); + + return 0; +} + +int +test_crypto(struct test_crypto_options *opt, int argc, char ** argv) +{ + hx509_verify_ctx vctx; + hx509_certs certs; + hx509_lock lock; + int i, ret; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = hx509_certs_init(context, "MEMORY:test-crypto", 0, NULL, &certs); + if (ret) hx509_err(context, 1, ret, "hx509_certs_init: MEMORY"); + + for (i = 0; i < argc; i++) { + char *sn = fix_store_name(context, argv[i], "FILE"); + ret = hx509_certs_append(context, certs, lock, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append %s", sn); + free(sn); + } + + ret = hx509_verify_init_ctx(context, &vctx); + if (ret) + hx509_err(context, 1, ret, "hx509_verify_init_ctx"); + + hx509_verify_attach_anchors(vctx, certs); + + ret = hx509_certs_iter_f(context, certs, test_one_cert, vctx); + if (ret) + hx509_err(context, 1, ret, "hx509_cert_iter"); + + hx509_certs_free(&certs); + hx509_verify_destroy_ctx(vctx); + + return 0; +} + +int +statistic_print(struct statistic_print_options*opt, int argc, char **argv) +{ + int type = 0; + + if (stat_file_string == NULL) + errx(1, "no stat file"); + + if (opt->type_integer) + type = opt->type_integer; + + hx509_query_unparse_stats(context, type, stdout); + return 0; +} + +/* + * + */ + +int +crl_sign(struct crl_sign_options *opt, int argc, char **argv) +{ + hx509_crl crl; + heim_octet_string os; + hx509_cert signer = NULL; + hx509_lock lock; + int ret; + + hx509_lock_init(context, &lock); + lock_strings(lock, &opt->pass_strings); + + ret = hx509_crl_alloc(context, &crl); + if (ret) + errx(1, "crl alloc"); + + if (opt->signer_string == NULL) + errx(1, "signer missing"); + + { + hx509_certs certs = NULL; + hx509_query *q; + char *sn = fix_store_name(context, opt->signer_string, "FILE"); + + ret = hx509_certs_init(context, sn, 0, NULL, &certs); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_init: %s", sn); + + ret = hx509_query_alloc(context, &q); + if (ret) + hx509_err(context, 1, ret, "hx509_query_alloc: %d", ret); + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + + ret = hx509_certs_find(context, certs, q, &signer); + hx509_query_free(context, q); + hx509_certs_free(&certs); + if (ret) + hx509_err(context, 1, ret, "no signer certificate found"); + free(sn); + } + + if (opt->lifetime_string) { + int delta; + + delta = parse_time(opt->lifetime_string, "day"); + if (delta < 0) + errx(1, "Invalid lifetime: %s", opt->lifetime_string); + + hx509_crl_lifetime(context, crl, delta); + } + + { + hx509_certs revoked = NULL; + int i; + + ret = hx509_certs_init(context, "MEMORY:revoked-certs", 0, + NULL, &revoked); + if (ret) + hx509_err(context, 1, ret, + "hx509_certs_init: MEMORY cert"); + + for (i = 0; i < argc; i++) { + char *sn = fix_store_name(context, argv[i], "FILE"); + + ret = hx509_certs_append(context, revoked, lock, sn); + if (ret) + hx509_err(context, 1, ret, "hx509_certs_append: %s", sn); + free(sn); + } + + hx509_crl_add_revoked_certs(context, crl, revoked); + hx509_certs_free(&revoked); + } + + hx509_crl_sign(context, signer, crl, &os); + + if (opt->crl_file_string) + rk_dumpdata(opt->crl_file_string, os.data, os.length); + + free(os.data); + + hx509_crl_free(context, &crl); + hx509_cert_free(signer); + hx509_lock_free(lock); + + return 0; +} + +int +hxtool_list_oids(void *opt, int argc, char **argv) +{ + const heim_oid *oid; + int cursor = -1; + + while (der_match_heim_oid_by_name("", &cursor, &oid) == 0) { + char *s = NULL; + + if ((errno = der_print_heim_oid_sym(oid, '.', &s)) > 0) + err(1, "der_print_heim_oid_sym"); + printf("%s\n", s); + free(s); + } + return 0; +} + +static int +acert1_sans_utf8_other(struct acert_options *opt, + struct getarg_strings *wanted, + const char *type, + heim_any *san, + size_t *count) +{ + size_t k, len; + + if (!wanted->num_strings) + return 0; + for (k = 0; k < wanted->num_strings; k++) { + len = strlen(wanted->strings[k]); + if (len == san->length && + strncmp(san->data, wanted->strings[k], len) == 0) { + if (opt->verbose_flag) + fprintf(stderr, "Matched OtherName SAN %s (%s)\n", + wanted->strings[k], type); + (*count)++; + return 0; + } + } + if (opt->verbose_flag) + fprintf(stderr, "Did not match OtherName SAN %s (%s)\n", + wanted->strings[k], type); + return -1; +} + +static int +acert1_sans_other(struct acert_options *opt, + heim_oid *type_id, + heim_any *value, + size_t *count) +{ + heim_any pkinit; + size_t k, match; + const char *type_str = NULL; + char *s = NULL; + int ret; + + (void) der_print_heim_oid_sym(type_id, '.', &s); + type_str = s ? s : ""; + if (der_heim_oid_cmp(type_id, &asn1_oid_id_pkix_on_xmppAddr) == 0) { + ret = acert1_sans_utf8_other(opt, &opt->has_xmpp_san_strings, + s ? s : "xmpp", value, count); + free(s); + return ret; + } + if (der_heim_oid_cmp(type_id, &asn1_oid_id_pkinit_san) != 0) { + if (opt->verbose_flag) + fprintf(stderr, "Ignoring OtherName SAN of type %s\n", type_str); + free(s); + return -1; + } + + free(s); + type_str = s = NULL; + + if (opt->has_pkinit_san_strings.num_strings == 0) + return 0; + + for (k = 0; k < opt->has_pkinit_san_strings.num_strings; k++) { + const char *s2 = opt->has_pkinit_san_strings.strings[k]; + + if ((ret = _hx509_make_pkinit_san(context, s2, &pkinit))) + return ret; + match = (pkinit.length == value->length && + memcmp(pkinit.data, value->data, pkinit.length) == 0); + free(pkinit.data); + if (match) { + if (opt->verbose_flag) + fprintf(stderr, "Matched PKINIT SAN %s\n", s2); + (*count)++; + return 0; + } + } + if (opt->verbose_flag) + fprintf(stderr, "Unexpected PKINIT SAN\n"); + return -1; +} + +static int +acert1_sans(struct acert_options *opt, + Extension *e, + size_t *count, + size_t *found) +{ + heim_printable_string hps; + GeneralNames gns; + size_t i, k, sz; + size_t unwanted = 0; + int ret = 0; + + memset(&gns, 0, sizeof(gns)); + decode_GeneralNames(e->extnValue.data, e->extnValue.length, &gns, &sz); + for (i = 0; (ret == -1 || ret == 0) && i < gns.len; i++) { + GeneralName *gn = &gns.val[i]; + const char *s; + + (*found)++; + if (gn->element == choice_GeneralName_rfc822Name) { + for (k = 0; k < opt->has_email_san_strings.num_strings; k++) { + s = opt->has_email_san_strings.strings[k]; + hps.data = rk_UNCONST(s); + hps.length = strlen(s); + if (der_printable_string_cmp(&gn->u.rfc822Name, &hps) == 0) { + if (opt->verbose_flag) + fprintf(stderr, "Matched e-mail address SAN %s\n", s); + (*count)++; + break; + } + } + if (k && k == opt->has_email_san_strings.num_strings) { + if (opt->verbose_flag) + fprintf(stderr, "Unexpected e-mail address SAN %.*s\n", + (int)gn->u.rfc822Name.length, + (const char *)gn->u.rfc822Name.data); + unwanted++; + } + } else if (gn->element == choice_GeneralName_dNSName) { + for (k = 0; k < opt->has_dnsname_san_strings.num_strings; k++) { + s = opt->has_dnsname_san_strings.strings[k]; + hps.data = rk_UNCONST(s); + hps.length = strlen(s); + if (der_printable_string_cmp(&gn->u.dNSName, &hps) == 0) { + if (opt->verbose_flag) + fprintf(stderr, "Matched dNSName SAN %s\n", s); + (*count)++; + break; + } + } + if (k && k == opt->has_dnsname_san_strings.num_strings) { + if (opt->verbose_flag) + fprintf(stderr, "Unexpected e-mail address SAN %.*s\n", + (int)gn->u.dNSName.length, + (const char *)gn->u.dNSName.data); + unwanted++; + } + } else if (gn->element == choice_GeneralName_registeredID) { + for (k = 0; k < opt->has_registeredID_san_strings.num_strings; k++) { + heim_oid oid; + + s = opt->has_registeredID_san_strings.strings[k]; + memset(&oid, 0, sizeof(oid)); + parse_oid(s, NULL, &oid); + if (der_heim_oid_cmp(&gn->u.registeredID, &oid) == 0) { + der_free_oid(&oid); + if (opt->verbose_flag) + fprintf(stderr, "Matched registeredID SAN %s\n", s); + (*count)++; + break; + } + der_free_oid(&oid); + } + if (k && k == opt->has_dnsname_san_strings.num_strings) { + if (opt->verbose_flag) + fprintf(stderr, "Unexpected registeredID SAN\n"); + unwanted++; + } + } else if (gn->element == choice_GeneralName_otherName) { + ret = acert1_sans_other(opt, &gn->u.otherName.type_id, + &gn->u.otherName.value, count); + } else if (opt->verbose_flag) { + fprintf(stderr, "Unexpected unsupported SAN\n"); + unwanted++; + } + } + free_GeneralNames(&gns); + if (ret == 0 && unwanted && opt->exact_flag) + return -1; + return ret; +} + +static int +acert1_ekus(struct acert_options *opt, + Extension *e, + size_t *count, + size_t *found) +{ + ExtKeyUsage eku; + size_t i, k, sz; + size_t unwanted = 0; + int ret = 0; + + memset(&eku, 0, sizeof(eku)); + decode_ExtKeyUsage(e->extnValue.data, e->extnValue.length, &eku, &sz); + for (i = 0; (ret == -1 || ret == 0) && i < eku.len; i++) { + (*found)++; + for (k = 0; k < opt->has_eku_strings.num_strings; k++) { + const char *s = opt->has_eku_strings.strings[k]; + heim_oid oid; + + memset(&oid, 0, sizeof(oid)); + parse_oid(s, NULL, &oid); + if (der_heim_oid_cmp(&eku.val[i], &oid) == 0) { + der_free_oid(&oid); + if (opt->verbose_flag) + fprintf(stderr, "Matched EKU OID %s\n", s); + (*count)++; + break; + } + der_free_oid(&oid); + } + if (k && k == opt->has_eku_strings.num_strings) { + char *oids = NULL; + + (void) der_print_heim_oid_sym(&eku.val[i], '.', &oids); + if (opt->verbose_flag) + fprintf(stderr, "Unexpected EKU OID %s\n", + oids ? oids : ""); + unwanted++; + } + } + free_ExtKeyUsage(&eku); + if (ret == 0 && unwanted && opt->exact_flag) + return -1; + return ret; +} + +static int +acert1_kus(struct acert_options *opt, + Extension *e, + size_t *count, + size_t *found) +{ + const struct units *u = asn1_KeyUsage_units(); + uint64_t ku_num; + KeyUsage ku; + size_t unwanted = 0; + size_t wanted = opt->has_ku_strings.num_strings; + size_t i, k, sz; + int ret; + + memset(&ku, 0, sizeof(ku)); + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &sz); + if (ret) + return ret; + ku_num = KeyUsage2int(ku); + + /* Validate requested key usage values */ + for (k = 0; k < wanted; k++) { + const char *s = opt->has_ku_strings.strings[k]; + + for (i = 0; u[i].name; i++) + if (strcmp(s, u[i].name) == 0) + break; + + if (u[i].name == NULL) + warnx("Warning: requested key usage %s unknown", s); + } + + for (i = 0; u[i].name; i++) { + if ((u[i].mult & ku_num)) + (*found)++; + for (k = 0; k < wanted; k++) { + const char *s = opt->has_ku_strings.strings[k]; + + if (!(u[i].mult & ku_num) || strcmp(s, u[i].name) != 0) + continue; + + if (opt->verbose_flag) + fprintf(stderr, "Matched key usage %s\n", s); + (*count)++; + break; + } + if ((u[i].mult & ku_num) && k == wanted) { + if (opt->verbose_flag) + fprintf(stderr, "Unexpected key usage %s\n", u[i].name); + unwanted++; + } + } + + return (unwanted && opt->exact_flag) ? -1 : 0; +} + +static time_t +ptime(const char *s) +{ + struct tm at_tm; + char *rest; + int at_s; + + memset(&at_tm, 0, sizeof at_tm); + if ((rest = strptime(s, "%Y-%m-%dT%H:%M:%S", &at_tm)) != NULL && + rest[0] == '\0') + return mktime(&at_tm); + memset(&at_tm, 0, sizeof at_tm); + if ((rest = strptime(s, "%Y%m%d%H%M%S", &at_tm)) != NULL && rest[0] == '\0') + return mktime(&at_tm); + if ((at_s = parse_time(s, "s")) != -1) + return time(NULL) + at_s; + errx(1, "Could not parse time spec %s", s); +} + +static int +acert1_validity(struct acert_options *opt, hx509_cert cert) +{ + time_t not_before_eq = 0; + time_t not_before_lt = 0; + time_t not_before_gt = 0; + time_t not_after_eq = 0; + time_t not_after_lt = 0; + time_t not_after_gt = 0; + int ret = 0; + + if (opt->valid_now_flag) { + time_t now = time(NULL); + + if (hx509_cert_get_notBefore(cert) > now) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate not valid yet\n"); + ret = -1; + } + if (hx509_cert_get_notAfter(cert) < now) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate currently expired\n"); + ret = -1; + } + } + if (opt->valid_at_string) { + time_t at = ptime(opt->valid_at_string); + + if (hx509_cert_get_notBefore(cert) > at) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate not valid yet at %s\n", + opt->valid_at_string); + ret = -1; + } + if (hx509_cert_get_notAfter(cert) < at) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate expired before %s\n", + opt->valid_at_string); + ret = -1; + } + } + + if (opt->not_before_eq_string) + not_before_eq = ptime(opt->not_before_eq_string); + if (opt->not_before_lt_string) + not_before_lt = ptime(opt->not_before_lt_string); + if (opt->not_before_gt_string) + not_before_gt = ptime(opt->not_before_gt_string); + if (opt->not_after_eq_string) + not_after_eq = ptime(opt->not_after_eq_string); + if (opt->not_after_lt_string) + not_after_lt = ptime(opt->not_after_lt_string); + if (opt->not_after_gt_string) + not_after_gt = ptime(opt->not_after_gt_string); + + if ((not_before_eq && hx509_cert_get_notBefore(cert) != not_before_eq) || + (not_before_lt && hx509_cert_get_notBefore(cert) >= not_before_lt) || + (not_before_gt && hx509_cert_get_notBefore(cert) <= not_before_gt)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate notBefore not as requested\n"); + ret = -1; + } + if ((not_after_eq && hx509_cert_get_notAfter(cert) != not_after_eq) || + (not_after_lt && hx509_cert_get_notAfter(cert) >= not_after_lt) || + (not_after_gt && hx509_cert_get_notAfter(cert) <= not_after_gt)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate notAfter not as requested\n"); + ret = -1; + } + + if (opt->has_private_key_flag && !hx509_cert_have_private_key(cert)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate does not have a private key\n"); + ret = -1; + } + + if (opt->lacks_private_key_flag && hx509_cert_have_private_key(cert)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate does not have a private key\n"); + ret = -1; + } + + return ret; +} + +static int +acert1(struct acert_options *opt, size_t cert_num, hx509_cert cert, int *matched) +{ + const heim_oid *misc_exts [] = { + &asn1_oid_id_x509_ce_authorityKeyIdentifier, + &asn1_oid_id_x509_ce_subjectKeyIdentifier, + &asn1_oid_id_x509_ce_basicConstraints, + &asn1_oid_id_x509_ce_nameConstraints, + &asn1_oid_id_x509_ce_certificatePolicies, + &asn1_oid_id_x509_ce_policyMappings, + &asn1_oid_id_x509_ce_issuerAltName, + &asn1_oid_id_x509_ce_subjectDirectoryAttributes, + &asn1_oid_id_x509_ce_policyConstraints, + &asn1_oid_id_x509_ce_cRLDistributionPoints, + &asn1_oid_id_x509_ce_deltaCRLIndicator, + &asn1_oid_id_x509_ce_issuingDistributionPoint, + &asn1_oid_id_x509_ce_inhibitAnyPolicy, + &asn1_oid_id_x509_ce_cRLNumber, + &asn1_oid_id_x509_ce_freshestCRL, + NULL + }; + const Certificate *c; + const Extensions *e; + KeyUsage ku; + size_t matched_elements = 0; + size_t wanted, sans_wanted, ekus_wanted, kus_wanted; + size_t found, sans_found, ekus_found, kus_found; + size_t i, k; + int ret; + + if ((c = _hx509_get_cert(cert)) == NULL) + errx(1, "Could not get Certificate"); + e = c->tbsCertificate.extensions; + + ret = _hx509_cert_get_keyusage(context, cert, &ku); + if (ret && ret != HX509_KU_CERT_MISSING) + hx509_err(context, 1, ret, "Could not get key usage of certificate"); + if (ret == HX509_KU_CERT_MISSING && opt->ca_flag) + return 0; /* want CA cert; this isn't it */ + if (ret == 0 && opt->ca_flag && !ku.keyCertSign) + return 0; /* want CA cert; this isn't it */ + if (ret == 0 && opt->end_entity_flag && ku.keyCertSign) + return 0; /* want EE cert; this isn't it */ + + if (opt->cert_num_integer != -1 && cert_num <= INT_MAX && + opt->cert_num_integer != (int)cert_num) + return 0; + if (opt->cert_num_integer == -1 || opt->cert_num_integer == (int)cert_num) + *matched = 1; + + if (_hx509_cert_get_version(c) < 3) { + warnx("Certificate with version %d < 3 ignored", + _hx509_cert_get_version(c)); + return 0; + } + + sans_wanted = opt->has_email_san_strings.num_strings + + opt->has_xmpp_san_strings.num_strings + + opt->has_ms_upn_san_strings.num_strings + + opt->has_dnsname_san_strings.num_strings + + opt->has_pkinit_san_strings.num_strings + + opt->has_registeredID_san_strings.num_strings; + ekus_wanted = opt->has_eku_strings.num_strings; + kus_wanted = opt->has_ku_strings.num_strings; + wanted = sans_wanted + ekus_wanted + kus_wanted; + sans_found = ekus_found = kus_found = 0; + + if (e == NULL) { + if (wanted) + return -1; + return acert1_validity(opt, cert); + } + + for (i = 0; i < e->len; i++) { + if (der_heim_oid_cmp(&e->val[i].extnID, + &asn1_oid_id_x509_ce_subjectAltName) == 0) { + ret = acert1_sans(opt, &e->val[i], &matched_elements, &sans_found); + if (ret == -1 && sans_wanted == 0 && + (!opt->exact_flag || sans_found == 0)) + ret = 0; + } else if (der_heim_oid_cmp(&e->val[i].extnID, + &asn1_oid_id_x509_ce_extKeyUsage) == 0) { + ret = acert1_ekus(opt, &e->val[i], &matched_elements, &ekus_found); + if (ret == -1 && ekus_wanted == 0 && + (!opt->exact_flag || ekus_found == 0)) + ret = 0; + } else if (der_heim_oid_cmp(&e->val[i].extnID, + &asn1_oid_id_x509_ce_keyUsage) == 0) { + ret = acert1_kus(opt, &e->val[i], &matched_elements, &kus_found); + if (ret == -1 && kus_wanted == 0 && + (!opt->exact_flag || kus_found == 0)) + ret = 0; + } else { + char *oids = NULL; + + for (k = 0; misc_exts[k]; k++) { + if (der_heim_oid_cmp(&e->val[i].extnID, misc_exts[k]) == 0) + break; + } + if (misc_exts[k]) + continue; + + (void) der_print_heim_oid(&e->val[i].extnID, '.', &oids); + warnx("Matching certificate has unexpected certificate " + "extension %s", oids ? oids : ""); + free(oids); + ret = -1; + } + if (ret && ret != -1) + hx509_err(context, 1, ret, "Error checking matching certificate"); + if (ret == -1) + break; + } + if (matched_elements != wanted) + return -1; + found = sans_found + ekus_found + kus_found; + if (matched_elements != found && opt->exact_flag) + return -1; + if (ret) + return ret; + return acert1_validity(opt, cert); +} + +int +acert(struct acert_options *opt, int argc, char **argv) +{ + hx509_cursor cursor = NULL; + hx509_query *q = NULL; + hx509_certs certs = NULL; + hx509_cert cert = NULL; + char *sn = fix_store_name(context, argv[0], "FILE"); + size_t n = 0; + int matched = 0; + int ret; + + if (opt->not_after_eq_string && + (opt->not_after_lt_string || opt->not_after_gt_string)) + errx(1, "--not-after-eq should not be given with --not-after-lt/gt"); + if (opt->not_before_eq_string && + (opt->not_before_lt_string || opt->not_before_gt_string)) + errx(1, "--not-before-eq should not be given with --not-before-lt/gt"); + + if ((ret = hx509_certs_init(context, sn, 0, NULL, &certs))) + hx509_err(context, 1, ret, "Could not load certificates from %s", sn); + + if (opt->expr_string) { + if ((ret = hx509_query_alloc(context, &q)) || + (ret = hx509_query_match_expr(context, q, opt->expr_string))) + hx509_err(context, 1, ret, "Could not initialize query"); + if ((ret = hx509_certs_find(context, certs, q, &cert)) || !cert) + hx509_err(context, 1, ret, "No matching certificate"); + ret = acert1(opt, -1, cert, &matched); + matched = 1; + } else { + ret = hx509_certs_start_seq(context, certs, &cursor); + while (ret == 0 && + (ret = hx509_certs_next_cert(context, certs, + cursor, &cert)) == 0 && + cert) { + ret = acert1(opt, n++, cert, &matched); + if (matched) + break; + hx509_cert_free(cert); + cert = NULL; + } + if (cursor) + (void) hx509_certs_end_seq(context, certs, cursor); + } + if (!matched && ret) + hx509_err(context, 1, ret, "Could not find certificate"); + if (!matched) + errx(1, "Could not find certificate"); + if (ret == -1) + errx(1, "Matching certificate did not meet requirements"); + if (ret) + hx509_err(context, 1, ret, "Matching certificate did not meet " + "requirements"); + hx509_cert_free(cert); + free(sn); + return 0; +} + +/* + * + */ + +int +help(void *opt, int argc, char **argv) +{ + sl_slc_help(commands, argc, argv); + return 0; +} + +int +main(int argc, char **argv) +{ + int ret, optidx = 0; + + setprogname (argv[0]); + + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + + if (argc == 0) + usage(1); + + ret = hx509_context_init(&context); + if (ret) + errx(1, "hx509_context_init failed with %d", ret); + + if (stat_file_string) + hx509_query_statistic_file(context, stat_file_string); + + ret = sl_command(commands, argc, argv); + if(ret == -1) + warnx ("unrecognized command: %s", argv[0]); + + hx509_context_free(&context); + + return ret; +} diff --git a/third_party/heimdal/lib/hx509/keyset.c b/third_party/heimdal/lib/hx509/keyset.c new file mode 100644 index 0000000..f25cdf4 --- /dev/null +++ b/third_party/heimdal/lib/hx509/keyset.c @@ -0,0 +1,846 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_keyset Certificate store operations + * + * Type of certificates store: + * - MEMORY + * In memory based format. Doesn't support storing. + * - FILE + * FILE supports raw DER certicates and PEM certicates. When PEM is + * used the file can contain may certificates and match private + * keys. Support storing the certificates. DER format only supports + * on certificate and no private key. + * - PEM-FILE + * Same as FILE, defaulting to PEM encoded certificates. + * - PEM-FILE + * Same as FILE, defaulting to DER encoded certificates. + * - PKCS11 + * - PKCS12 + * - DIR + * - KEYCHAIN + * Apple Mac OS X KeyChain backed keychain object. + * + * See the library functions here: @ref hx509_keyset + */ + +struct hx509_certs_data { + unsigned int ref; + struct hx509_keyset_ops *ops; + void *ops_data; + int flags; +}; + +struct hx509_keyset_ops * +_hx509_ks_type(hx509_context context, const char *type) +{ + int i; + + for (i = 0; i < context->ks_num_ops; i++) + if (strcasecmp(type, context->ks_ops[i]->name) == 0) + return context->ks_ops[i]; + + return NULL; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops) +{ + struct hx509_keyset_ops **val; + + if (_hx509_ks_type(context, ops->name)) + return; + + val = realloc(context->ks_ops, + (context->ks_num_ops + 1) * sizeof(context->ks_ops[0])); + if (val == NULL) + return; + val[context->ks_num_ops] = ops; + context->ks_ops = val; + context->ks_num_ops++; +} + +/** + * Open or creates a new hx509 certificate store. + * + * @param context A hx509 context + * @param name name of the store, format is TYPE:type-specific-string, + * if NULL is used the MEMORY store is used. + * @param flags list of flags: + * - HX509_CERTS_CREATE create a new keystore of the specific TYPE. + * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted. + * - HX509_CERTS_NO_PRIVATE_KEYS does not load or permit adding private keys + * @param lock a lock that unlocks the certificates store, use NULL to + * select no password/certifictes/prompt lock (see @ref page_lock). + * @param certs return pointer, free with hx509_certs_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_init(hx509_context context, + const char *name, int flags, + hx509_lock lock, hx509_certs *certs) +{ + struct hx509_keyset_ops *ops; + const char *residue; + hx509_certs c; + char *type; + int ret; + + *certs = NULL; + + if (name == NULL) + name = ""; + + residue = strchr(name, ':'); + if (residue) { + type = malloc(residue - name + 1); + if (type) + strlcpy(type, name, residue - name + 1); + residue++; + if (residue[0] == '\0') + residue = NULL; + } else { + type = strdup("MEMORY"); + residue = name; + } + if (type == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ops = _hx509_ks_type(context, type); + if (ops == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Keyset type %s is not supported", type); + free(type); + return ENOENT; + } + free(type); + c = calloc(1, sizeof(*c)); + if (c == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + c->flags = flags; + c->ops = ops; + c->ref = 1; + + ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock); + if (ret) { + free(c); + return ret; + } + + *certs = c; + return 0; +} + +/** + * Destroys and frees a hx509 certificate store. + * + * @param context A hx509 context + * @param certs A store to destroy + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_destroy(hx509_context context, + hx509_certs *certs) +{ + int ret = 0; + + if (*certs) { + if ((*certs)->ops->destroy) + ret = ((*certs)->ops->destroy)(context, *certs, (*certs)->ops_data); + else + ret = ENOTSUP; + } + hx509_certs_free(certs); + return ret; +} + +/** + * Write the certificate store to stable storage. + * + * Use the HX509_CERTS_STORE_NO_PRIVATE_KEYS flag to ensure that no private + * keys are stored, even if added. + * + * @param context A hx509 context. + * @param certs a certificate store to store. + * @param flags currently one flag is defined: HX509_CERTS_STORE_NO_PRIVATE_KEYS + * @param lock a lock that unlocks the certificates store, use NULL to + * select no password/certifictes/prompt lock (see @ref page_lock). + * + * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if + * the certificate store doesn't support the store operation. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_store(hx509_context context, + hx509_certs certs, + int flags, + hx509_lock lock) +{ + if (certs->ops->store == NULL) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "keystore if type %s doesn't support " + "store operation", + certs->ops->name); + return HX509_UNSUPPORTED_OPERATION; + } + + return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock); +} + + +HX509_LIB_FUNCTION hx509_certs HX509_LIB_CALL +hx509_certs_ref(hx509_certs certs) +{ + if (certs == NULL) + return NULL; + if (certs->ref == 0) + _hx509_abort("certs refcount == 0 on ref"); + if (certs->ref == UINT_MAX) + _hx509_abort("certs refcount == UINT_MAX on ref"); + certs->ref++; + return certs; +} + +/** + * Free a certificate store. + * + * @param certs certificate store to free. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_certs_free(hx509_certs *certs) +{ + if (*certs) { + if ((*certs)->ref == 0) + _hx509_abort("cert refcount == 0 on free"); + if (--(*certs)->ref > 0) + return; + + (*(*certs)->ops->free)(*certs, (*certs)->ops_data); + free(*certs); + *certs = NULL; + } +} + +/** + * Start the integration + * + * @param context a hx509 context. + * @param certs certificate store to iterate over + * @param cursor cursor that will keep track of progress, free with + * hx509_certs_end_seq(). + * + * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is + * returned if the certificate store doesn't support the iteration + * operation. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_start_seq(hx509_context context, + hx509_certs certs, + hx509_cursor *cursor) +{ + int ret; + + if (certs->ops->iter_start == NULL) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "Keyset type %s doesn't support iteration", + certs->ops->name); + return HX509_UNSUPPORTED_OPERATION; + } + + ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor); + if (ret) + return ret; + + return 0; +} + +/** + * Get next ceritificate from the certificate keystore pointed out by + * cursor. + * + * @param context a hx509 context. + * @param certs certificate store to iterate over. + * @param cursor cursor that keeps track of progress. + * @param cert return certificate next in store, NULL if the store + * contains no more certificates. Free with hx509_cert_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_next_cert(hx509_context context, + hx509_certs certs, + hx509_cursor cursor, + hx509_cert *cert) +{ + *cert = NULL; + return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert); +} + +/** + * End the iteration over certificates. + * + * @param context a hx509 context. + * @param certs certificate store to iterate over. + * @param cursor cursor that will keep track of progress, freed. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_end_seq(hx509_context context, + hx509_certs certs, + hx509_cursor cursor) +{ + (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor); + return 0; +} + +/** + * Iterate over all certificates in a keystore and call a function + * for each of them. + * + * @param context a hx509 context. + * @param certs certificate store to iterate over. + * @param func function to call for each certificate. The function + * should return non-zero to abort the iteration, that value is passed + * back to the caller of hx509_certs_iter_f(). + * @param ctx context variable that will passed to the function. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_iter_f(hx509_context context, + hx509_certs certs, + int (HX509_LIB_CALL *func)(hx509_context, void *, hx509_cert), + void *ctx) +{ + hx509_cursor cursor; + hx509_cert c; + int ret; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) { + ret = 0; + break; + } + ret = (*func)(context, ctx, c); + hx509_cert_free(c); + if (ret) + break; + } + + hx509_certs_end_seq(context, certs, cursor); + + return ret; +} + +#ifdef __BLOCKS__ + +static int +certs_iter(hx509_context context, void *ctx, hx509_cert cert) +{ + int (^func)(hx509_cert) = ctx; + return func(cert); +} + +/** + * Iterate over all certificates in a keystore and call a block + * for each of them. + * + * @param context a hx509 context. + * @param certs certificate store to iterate over. + * @param func block to call for each certificate. The function + * should return non-zero to abort the iteration, that value is passed + * back to the caller of hx509_certs_iter(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_iter(hx509_context context, + hx509_certs certs, + int (^func)(hx509_cert)) +{ + return hx509_certs_iter_f(context, certs, certs_iter, func); +} +#endif + + +/** + * Function to use to hx509_certs_iter_f() as a function argument, the + * ctx variable to hx509_certs_iter_f() should be a FILE file descriptor. + * + * @param context a hx509 context. + * @param ctx used by hx509_certs_iter_f(). + * @param c a certificate + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c) +{ + Certificate *cert; + hx509_name n; + char *s, *i; + + cert = _hx509_get_cert(c); + + _hx509_name_from_Name(&cert->tbsCertificate.subject, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n); + hx509_name_to_string(n, &i); + hx509_name_free(&n); + fprintf(ctx, "subject: %s\nissuer: %s\n", s, i); + free(s); + free(i); + return 0; +} + +/** + * Add a certificate to the certificiate store. + * + * The receiving keyset certs will either increase reference counter + * of the cert or make a deep copy, either way, the caller needs to + * free the cert itself. + * + * @param context a hx509 context. + * @param certs certificate store to add the certificate to. + * @param cert certificate to add. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert) +{ + hx509_cert copy = NULL; + int ret; + + if (certs->ops->add == NULL) { + hx509_set_error_string(context, 0, ENOENT, + "Keyset type %s doesn't support add operation", + certs->ops->name); + return ENOENT; + } + + if ((certs->flags & HX509_CERTS_NO_PRIVATE_KEYS) && + hx509_cert_have_private_key(cert)) { + if ((copy = hx509_cert_copy_no_private_key(context, cert, + NULL)) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Could not add certificate to store"); + return ENOMEM; + } + cert = copy; + } + + ret = (*certs->ops->add)(context, certs, certs->ops_data, cert); + hx509_cert_free(copy); + return ret; +} + +/** + * Find a certificate matching the query. + * + * @param context a hx509 context. + * @param certs certificate store to search. + * @param q query allocated with @ref hx509_query functions. + * @param r return certificate (or NULL on error), should be freed + * with hx509_cert_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_find(hx509_context context, + hx509_certs certs, + const hx509_query *q, + hx509_cert *r) +{ + hx509_cursor cursor; + hx509_cert c; + int ret; + + *r = NULL; + + _hx509_query_statistic(context, 0, q); + + if (certs->ops->query) + return (*certs->ops->query)(context, certs, certs->ops_data, q, r); + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_query_match_cert(context, q, c)) { + *r = c; + c = NULL; + break; + } + hx509_cert_free(c); + c = NULL; + } + + hx509_cert_free(c); + hx509_certs_end_seq(context, certs, cursor); + if (ret) + return ret; + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ + if (*r == NULL) { + hx509_clear_error_string(context); + return HX509_CERT_NOT_FOUND; + } + + return 0; +} + +/** + * Filter certificate matching the query. + * + * @param context a hx509 context. + * @param certs certificate store to search. + * @param q query allocated with @ref hx509_query functions. + * @param result the filtered certificate store, caller must free with + * hx509_certs_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_filter(hx509_context context, + hx509_certs certs, + const hx509_query *q, + hx509_certs *result) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = 0; + + _hx509_query_statistic(context, 0, q); + + ret = hx509_certs_init(context, "MEMORY:filter-certs", 0, + NULL, result); + if (ret) + return ret; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_query_match_cert(context, q, c)) { + hx509_certs_add(context, *result, c); + found = 1; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ + if (!found) { + hx509_certs_free(result); + hx509_clear_error_string(context); + return HX509_CERT_NOT_FOUND; + } + + return 0; +} + + +static int HX509_LIB_CALL +certs_merge_func(hx509_context context, void *ctx, hx509_cert c) +{ + return hx509_certs_add(context, (hx509_certs)ctx, c); +} + +/** + * Merge one certificate store into another. The from store is kept intact. + * + * @param context a hx509 context. + * @param to the store to merge into. + * @param from the store to copy the object from. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from) +{ + if (from == NULL) + return 0; + return hx509_certs_iter_f(context, from, certs_merge_func, to); +} + +/** + * Same a hx509_certs_merge() but use a lock and name to describe the + * from source. + * + * @param context a hx509 context. + * @param to the store to merge into. + * @param lock a lock that unlocks the certificates store, use NULL to + * select no password/certifictes/prompt lock (see @ref page_lock). + * @param name name of the source store + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_append(hx509_context context, + hx509_certs to, + hx509_lock lock, + const char *name) +{ + hx509_certs s; + int ret; + + ret = hx509_certs_init(context, name, 0, lock, &s); + if (ret) + return ret; + ret = hx509_certs_merge(context, to, s); + hx509_certs_free(&s); + return ret; +} + +/** + * Get one random certificate from the certificate store. + * + * @param context a hx509 context. + * @param certs a certificate store to get the certificate from. + * @param c return certificate, should be freed with hx509_cert_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c) +{ + hx509_cursor cursor; + int ret; + + *c = NULL; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) + return ret; + + ret = hx509_certs_next_cert(context, certs, cursor, c); + if (ret) + return ret; + + hx509_certs_end_seq(context, certs, cursor); + return 0; +} + +static int +certs_info_stdio(void *ctx, const char *str) +{ + FILE *f = ctx; + fprintf(f, "%s\n", str); + return 0; +} + +/** + * Print some info about the certificate store. + * + * @param context a hx509 context. + * @param certs certificate store to print information about. + * @param func function that will get each line of the information, if + * NULL is used the data is printed on a FILE descriptor that should + * be passed in ctx, if ctx also is NULL, stdout is used. + * @param ctx parameter to func. + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_certs_info(hx509_context context, + hx509_certs certs, + int (*func)(void *, const char *), + void *ctx) +{ + if (func == NULL) { + func = certs_info_stdio; + if (ctx == NULL) + ctx = stdout; + } + if (certs->ops->printinfo == NULL) { + (*func)(ctx, "No info function for certs"); + return 0; + } + return (*certs->ops->printinfo)(context, certs, certs->ops_data, + func, ctx); +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_pi_printf(int (*func)(void *, const char *), void *ctx, + const char *fmt, ...) +{ + va_list ap; + char *str; + int ret; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + if (ret == -1 || str == NULL) + return; + (*func)(ctx, str); + free(str); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_certs_keys_get(hx509_context context, + hx509_certs certs, + hx509_private_key **keys) +{ + if (certs->ops->getkeys == NULL) { + *keys = NULL; + return 0; + } + return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_certs_keys_add(hx509_context context, + hx509_certs certs, + hx509_private_key key) +{ + if (certs->ops->addkey == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "keystore if type %s doesn't support " + "key add operation", + certs->ops->name); + return EINVAL; + } + return (*certs->ops->addkey)(context, certs, certs->ops_data, key); +} + + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_certs_keys_free(hx509_context context, + hx509_private_key *keys) +{ + size_t i; + + if (keys == NULL) + return; + for (i = 0; keys[i]; i++) + hx509_private_key_free(&keys[i]); + free(keys); +} diff --git a/third_party/heimdal/lib/hx509/ks_dir.c b/third_party/heimdal/lib/hx509/ks_dir.c new file mode 100644 index 0000000..3bc99f2 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_dir.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include + +/* + * The DIR keyset module is strange compared to the other modules + * since it does lazy evaluation and really doesn't keep any local + * state except for the directory iteration and cert iteration of + * files. DIR ignores most errors so that the consumer doesn't get + * failes for stray files in directories. + */ + +struct dircursor { + DIR *dir; + hx509_certs certs; + void *iter; +}; + +/* + * + */ + +static int +dir_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + *data = NULL; + + if (residue == NULL || residue[0] == '\0') { + hx509_set_error_string(context, 0, EINVAL, + "DIR file name not specified"); + return EINVAL; + } + + { + struct stat sb; + int ret; + + ret = stat(residue, &sb); + if (ret == -1) { + hx509_set_error_string(context, 0, ENOENT, + "No such file %s", residue); + return ENOENT; + } + + if (!S_ISDIR(sb.st_mode)) { + hx509_set_error_string(context, 0, ENOTDIR, + "%s is not a directory", residue); + return ENOTDIR; + } + } + + *data = strdup(residue); + if (*data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + return 0; +} + +static int +dir_free(hx509_certs certs, void *data) +{ + free(data); + return 0; +} + +static int +dir_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct dircursor *d; + + *cursor = NULL; + + d = calloc(1, sizeof(*d)); + if (d == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + d->dir = opendir(data); + if (d->dir == NULL) { + hx509_clear_error_string(context); + free(d); + return errno; + } + rk_cloexec_dir(d->dir); + d->certs = NULL; + d->iter = NULL; + + *cursor = d; + return 0; +} + +static int +dir_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + struct dircursor *d = iter; + int ret = 0; + + *cert = NULL; + + do { + struct dirent *dir; + char *fn; + + if (d->certs) { + ret = hx509_certs_next_cert(context, d->certs, d->iter, cert); + if (ret) { + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + return ret; + } + if (*cert) { + ret = 0; + break; + } + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + } + + dir = readdir(d->dir); + if (dir == NULL) { + ret = 0; + break; + } + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) + continue; + + if (asprintf(&fn, "FILE:%s/%s", (char *)data, dir->d_name) == -1) + return ENOMEM; + + ret = hx509_certs_init(context, fn, 0, NULL, &d->certs); + if (ret == 0) { + + ret = hx509_certs_start_seq(context, d->certs, &d->iter); + if (ret) + hx509_certs_free(&d->certs); + } + /* ignore errors */ + if (ret) { + d->certs = NULL; + ret = 0; + } + + free(fn); + } while(ret == 0); + + return ret; +} + + +static int +dir_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct dircursor *d = cursor; + + if (d->certs) { + hx509_certs_end_seq(context, d->certs, d->iter); + d->iter = NULL; + hx509_certs_free(&d->certs); + } + closedir(d->dir); + free(d); + return 0; +} + + +static struct hx509_keyset_ops keyset_dir = { + "DIR", + 0, + dir_init, + NULL, + dir_free, + NULL, + NULL, + dir_iter_start, + dir_iter, + dir_iter_end, + NULL, + NULL, + NULL, + NULL +}; + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_dir_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_dir); +} diff --git a/third_party/heimdal/lib/hx509/ks_file.c b/third_party/heimdal/lib/hx509/ks_file.c new file mode 100644 index 0000000..35796ad --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_file.c @@ -0,0 +1,808 @@ +/* + * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#ifndef WIN32 +#include +#endif + +typedef enum { USE_PEM, USE_DER } outformat; + +struct ks_file { + hx509_certs certs; + char *fn; + outformat format; +}; + +/* + * + */ + +static int +parse_certificate(hx509_context context, const char *fn, int flags, + struct hx509_collector *c, + const hx509_pem_header *headers, + const void *data, size_t len, + const AlgorithmIdentifier *ai) +{ + heim_error_t error = NULL; + hx509_cert cert; + int ret; + + cert = hx509_cert_init_data(context, data, len, &error); + if (cert == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + return ret; + } + + ret = _hx509_collector_certs_add(context, c, cert); + hx509_cert_free(cert); + return ret; +} + +static int +try_decrypt(hx509_context context, + struct hx509_collector *collector, + int flags, + const AlgorithmIdentifier *alg, + const EVP_CIPHER *c, + const void *ivdata, + const void *password, + size_t passwordlen, + const void *cipher, + size_t len) +{ + heim_octet_string clear; + size_t keylen; + void *key; + int ret; + + keylen = EVP_CIPHER_key_length(c); + + key = malloc(keylen); + if (key == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = EVP_BytesToKey(c, EVP_md5(), ivdata, + password, passwordlen, + 1, key, NULL); + if (ret <= 0) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + hx509_set_error_string(context, 0, ret, + "Failed to do string2key for private key"); + goto out; + } + + clear.data = malloc(len); + if (clear.data == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Out of memory to decrypt for private key"); + ret = ENOMEM; + goto out; + } + clear.length = len; + + { + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0); + EVP_Cipher(&ctx, clear.data, cipher, len); + EVP_CIPHER_CTX_cleanup(&ctx); + } + + if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) + ret = _hx509_collector_private_key_add(context, collector, alg, NULL, + &clear, NULL); + + memset_s(clear.data, clear.length, 0, clear.length); + free(clear.data); +out: + memset_s(key, keylen, 0, keylen); + free(key); + return ret; +} + +static int +parse_pkcs8_private_key(hx509_context context, const char *fn, int flags, + struct hx509_collector *c, + const hx509_pem_header *headers, + const void *data, size_t length, + const AlgorithmIdentifier *ai) +{ + PKCS8PrivateKeyInfo ki; + heim_octet_string keydata; + int ret; + + ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); + if (ret) + return ret; + + if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) { + keydata.data = rk_UNCONST(data); + keydata.length = length; + ret = _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + &keydata); + } + free_PKCS8PrivateKeyInfo(&ki); + return ret; +} + +static int +parse_pem_private_key(hx509_context context, const char *fn, int flags, + struct hx509_collector *c, + const hx509_pem_header *headers, + const void *data, size_t len, + const AlgorithmIdentifier *ai) +{ + int ret = 0; + const char *enc; + + enc = hx509_pem_find_header(headers, "Proc-Type"); + if (enc) { + const char *dek; + char *type, *iv; + ssize_t ssize, size; + void *ivdata; + const EVP_CIPHER *cipher; + const struct _hx509_password *pw; + hx509_lock lock; + int decrypted = 0; + size_t i; + + lock = _hx509_collector_get_lock(c); + if (lock == NULL) { + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "Failed to get password for " + "password protected file %s", fn); + return HX509_ALG_NOT_SUPP; + } + + if (strcmp(enc, "4,ENCRYPTED") != 0) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Private key encrypted in unknown method %s " + "in file %s", + enc, fn); + hx509_clear_error_string(context); + return HX509_PARSING_KEY_FAILED; + } + + dek = hx509_pem_find_header(headers, "DEK-Info"); + if (dek == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Encrypted private key missing DEK-Info"); + return HX509_PARSING_KEY_FAILED; + } + + type = strdup(dek); + if (type == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + iv = strchr(type, ','); + if (iv == NULL) { + free(type); + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "IV missing"); + return HX509_PARSING_KEY_FAILED; + } + + *iv++ = '\0'; + + size = strlen(iv); + ivdata = malloc(size); + if (ivdata == NULL) { + hx509_clear_error_string(context); + free(type); + return ENOMEM; + } + + cipher = EVP_get_cipherbyname(type); + if (cipher == NULL) { + free(ivdata); + hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, + "Private key encrypted with " + "unsupported cipher: %s", + type); + free(type); + return HX509_ALG_NOT_SUPP; + } + +#define PKCS5_SALT_LEN 8 + + ssize = hex_decode(iv, ivdata, size); + free(type); + type = NULL; + iv = NULL; + + if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) { + free(ivdata); + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Salt have wrong length in " + "private key file"); + return HX509_PARSING_KEY_FAILED; + } + + pw = _hx509_lock_get_passwords(lock); + if (pw != NULL) { + const void *password; + size_t passwordlen; + + for (i = 0; i < pw->len; i++) { + password = pw->val[i]; + passwordlen = strlen(password); + + ret = try_decrypt(context, c, flags, ai, cipher, ivdata, + password, passwordlen, data, len); + if (ret == 0) { + decrypted = 1; + break; + } + } + } + if (!decrypted) { + hx509_prompt prompt; + char password[128]; + + memset(&prompt, 0, sizeof(prompt)); + + prompt.prompt = "Password for keyfile: "; + prompt.type = HX509_PROMPT_TYPE_PASSWORD; + prompt.reply.data = password; + prompt.reply.length = sizeof(password); + + ret = hx509_lock_prompt(lock, &prompt); + if (ret == 0) + ret = try_decrypt(context, c, flags, ai, cipher, ivdata, + password, strlen(password), data, len); + /* XXX add password to lock password collection ? */ + memset_s(password, sizeof(password), 0, sizeof(password)); + } + free(ivdata); + + } else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) { + heim_octet_string keydata; + + keydata.data = rk_UNCONST(data); + keydata.length = len; + + ret = _hx509_collector_private_key_add(context, c, ai, NULL, + &keydata, NULL); + } + + return ret; +} + + +struct pem_formats { + const char *name; + int (*func)(hx509_context, const char *, int, struct hx509_collector *, + const hx509_pem_header *, const void *, size_t, + const AlgorithmIdentifier *); + const AlgorithmIdentifier *(*ai)(void); +} formats[] = { + { "CERTIFICATE", parse_certificate, NULL }, + { "PRIVATE KEY", parse_pkcs8_private_key, NULL }, + { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa }, +#ifdef HAVE_HCRYPTO_W_OPENSSL + { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey } +#endif +}; + + +struct pem_ctx { + int flags; + struct hx509_collector *c; +}; + +static int +pem_func(hx509_context context, const char *type, + const hx509_pem_header *header, + const void *data, size_t len, void *ctx) +{ + struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx; + int ret = 0; + size_t j; + + for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { + const char *q = formats[j].name; + if (strcasecmp(type, q) == 0) { + const AlgorithmIdentifier *ai = NULL; + + if (formats[j].ai != NULL) + ai = (*formats[j].ai)(); + + ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c, + header, data, len, ai); + if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed parseing PEM format %s", type); + return ret; + } + break; + } + } + if (j == sizeof(formats)/sizeof(formats[0])) { + ret = HX509_UNSUPPORTED_OPERATION; + hx509_set_error_string(context, 0, ret, + "Found no matching PEM format for %s", type); + return ret; + } + return 0; +} + +/* + * + */ + +static int +file_init_common(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock, outformat format) +{ + char *p, *pnext; + struct ks_file *ksf = NULL; + hx509_private_key *keys = NULL; + int ret; + struct pem_ctx pem_ctx; + + pem_ctx.flags = flags; + pem_ctx.c = NULL; + + if (residue == NULL || residue[0] == '\0') { + hx509_set_error_string(context, 0, EINVAL, + "PEM file name not specified"); + return EINVAL; + } + + *data = NULL; + + if (lock == NULL) + lock = _hx509_empty_lock; + + ksf = calloc(1, sizeof(*ksf)); + if (ksf == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + ksf->format = format; + + ksf->fn = strdup(residue); + if (ksf->fn == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + /* + * XXX this is broken, the function should parse the file before + * overwriting it + */ + + if (flags & HX509_CERTS_CREATE) { + /* + * Note that the file creation is deferred until file_store() is + * called. + */ + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, lock, &ksf->certs); + if (ret) + goto out; + *data = ksf; + return 0; + } + + ret = _hx509_collector_alloc(context, lock, &pem_ctx.c); + if (ret) + goto out; + + for (p = ksf->fn; p != NULL; p = pnext) { + FILE *f; + + pnext = strchr(p, ','); + if (pnext) + *pnext++ = '\0'; + + + if ((f = fopen(p, "r")) == NULL) { + ret = ENOENT; + hx509_set_error_string(context, 0, ret, + "Failed to open PEM file \"%s\": %s", + p, strerror(errno)); + goto out; + } + rk_cloexec_file(f); + + ret = hx509_pem_read(context, f, pem_func, &pem_ctx); + fclose(f); + if (ret != 0 && ret != HX509_PARSING_KEY_FAILED) + goto out; + else if (ret == HX509_PARSING_KEY_FAILED) { + size_t length; + void *ptr; + size_t i; + + ret = rk_undumpdata(p, &ptr, &length); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { + const AlgorithmIdentifier *ai = NULL; + + if (formats[i].ai != NULL) + ai = (*formats[i].ai)(); + + ret = (*formats[i].func)(context, p, pem_ctx.flags, pem_ctx.c, + NULL, ptr, length, ai); + if (ret == 0) + break; + } + rk_xfree(ptr); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + + ret = _hx509_collector_collect_certs(context, pem_ctx.c, &ksf->certs); + if (ret) + goto out; + + ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys); + if (ret == 0) { + int i; + + for (i = 0; keys[i]; i++) + _hx509_certs_keys_add(context, ksf->certs, keys[i]); + _hx509_certs_keys_free(context, keys); + } + +out: + if (ret == 0) + *data = ksf; + else { + if (ksf->fn) + free(ksf->fn); + free(ksf); + } + if (pem_ctx.c) + _hx509_collector_free(pem_ctx.c); + + return ret; +} + +static int +file_init_pem(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + return file_init_common(context, certs, data, flags, residue, lock, USE_PEM); +} + +static int +file_init_der(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + return file_init_common(context, certs, data, flags, residue, lock, USE_DER); +} + +static int +file_free(hx509_certs certs, void *data) +{ + struct ks_file *ksf = data; + hx509_certs_free(&ksf->certs); + free(ksf->fn); + free(ksf); + return 0; +} + +struct store_ctx { + FILE *f; + outformat format; + int store_flags; +}; + +static int HX509_LIB_CALL +store_func(hx509_context context, void *ctx, hx509_cert c) +{ + struct store_ctx *sc = ctx; + heim_octet_string data; + int ret = 0; + + if ((sc->store_flags & HX509_CERTS_STORE_NO_ROOTS)) { + int self_signed = 0; + + ret = hx509_cert_is_self_signed(context, c, &self_signed); + if (ret || self_signed) + return ret; + } + + if (hx509_cert_have_private_key_only(c)) { + data.length = 0; + data.data = NULL; + } else { + ret = hx509_cert_binary(context, c, &data); + if (ret) + return ret; + } + + switch (sc->format) { + case USE_DER: + /* Can't store both. Well, we could, but nothing will support it */ + if (data.data) { + fwrite(data.data, data.length, 1, sc->f); + } else if (_hx509_cert_private_key_exportable(c) && + !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { + hx509_private_key key = _hx509_cert_private_key(c); + + free(data.data); + data.length = 0; + data.data = NULL; + ret = _hx509_private_key_export(context, key, + HX509_KEY_FORMAT_DER, &data); + if (ret == 0 && data.length) + fwrite(data.data, data.length, 1, sc->f); + } + break; + case USE_PEM: + if (_hx509_cert_private_key_exportable(c) && + !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { + heim_octet_string priv_key; + hx509_private_key key = _hx509_cert_private_key(c); + + ret = _hx509_private_key_export(context, key, + HX509_KEY_FORMAT_DER, &priv_key); + if (ret == 0) + ret = hx509_pem_write(context, _hx509_private_pem_name(key), NULL, + sc->f, priv_key.data, priv_key.length); + free(priv_key.data); + } + if (ret == 0 && data.data) { + ret = hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, + data.data, data.length); + } + break; + } + + free(data.data); + return ret; +} + +static int +mk_temp(const char *fn, char **tfn) +{ + char *ds; + int ret = -1; + +#ifdef WIN32 + char buf[PATH_MAX]; + char *p; + + *tfn = NULL; + + if ((ds = _fullpath(buf, fn, sizeof(buf))) == NULL) { + errno = errno ? errno : ENAMETOOLONG; + return -1; + } + + if ((p = strrchr(ds, '\\')) == NULL) { + ret = asprintf(tfn, ".%s-XXXXXX", ds); /* XXX can't happen */ + } else { + *(p++) = '\0'; + ret = asprintf(tfn, "%s/.%s-XXXXXX", ds, p); + } +#else + *tfn = NULL; + if ((ds = strdup(fn))) + ret = asprintf(tfn, "%s/.%s-XXXXXX", dirname(ds), basename(ds)); + free(ds); +#endif + + /* + * Using mkostemp() risks leaving garbage files lying around. To do better + * without resorting to file locks (which have their own problems) we need + * O_TMPFILE and linkat(2), which only Linux has. + */ + return (ret == -1 || *tfn == NULL) ? -1 : mkostemp(*tfn, O_CLOEXEC); +} + +static int +file_store(hx509_context context, + hx509_certs certs, void *data, int flags, hx509_lock lock) +{ + struct ks_file *ksf = data; + struct store_ctx sc; + char *tfn; + int ret; + int fd; + + sc.f = NULL; + fd = mk_temp(ksf->fn, &tfn); + if (fd > -1) + sc.f = fdopen(fd, "w"); + if (sc.f == NULL) { + hx509_set_error_string(context, 0, ret = errno, + "Failed to open file %s for writing", ksf->fn); + if (fd > -1) + (void) close(fd); + return ret; + } + rk_cloexec_file(sc.f); + sc.store_flags = flags; + sc.format = ksf->format; + + ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc); + if (ret == 0) + ret = fclose(sc.f); + else + (void) fclose(sc.f); + if (ret) + (void) unlink(tfn); + else + (void) rename(tfn, ksf->fn); + free(tfn); + return ret; +} + +static int +file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct ks_file *ksf = data; + return hx509_certs_add(context, ksf->certs, c); +} + +static int +file_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct ks_file *ksf = data; + return hx509_certs_start_seq(context, ksf->certs, cursor); +} + +static int +file_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + struct ks_file *ksf = data; + return hx509_certs_next_cert(context, ksf->certs, iter, cert); +} + +static int +file_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct ks_file *ksf = data; + return hx509_certs_end_seq(context, ksf->certs, cursor); +} + +static int +file_getkeys(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key **keys) +{ + struct ks_file *ksf = data; + return _hx509_certs_keys_get(context, ksf->certs, keys); +} + +static int +file_addkey(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key key) +{ + struct ks_file *ksf = data; + return _hx509_certs_keys_add(context, ksf->certs, key); +} + +static int +file_destroy(hx509_context context, + hx509_certs certs, + void *data) +{ + struct ks_file *ksf = data; + return _hx509_erase_file(context, ksf->fn); +} + +static struct hx509_keyset_ops keyset_file = { + "FILE", + 0, + file_init_pem, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey, + file_destroy +}; + +static struct hx509_keyset_ops keyset_pemfile = { + "PEM-FILE", + 0, + file_init_pem, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey, + file_destroy +}; + +static struct hx509_keyset_ops keyset_derfile = { + "DER-FILE", + 0, + file_init_der, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey, + file_destroy +}; + + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_file_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_file); + _hx509_ks_register(context, &keyset_pemfile); + _hx509_ks_register(context, &keyset_derfile); +} diff --git a/third_party/heimdal/lib/hx509/ks_keychain.c b/third_party/heimdal/lib/hx509/ks_keychain.c new file mode 100644 index 0000000..3243ee8 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_keychain.c @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +#ifdef HAVE_FRAMEWORK_SECURITY + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#include + +/* Missing function decls in pre Leopard */ +#ifdef NEED_SECKEYGETCSPHANDLE_PROTO +OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); +OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, + int, const CSSM_ACCESS_CREDENTIALS **); +#define kSecCredentialTypeDefault 0 +#define CSSM_SIZE uint32_t +#endif + + +static int +getAttribute(SecKeychainItemRef itemRef, SecItemAttr item, + SecKeychainAttributeList **attrs) +{ + SecKeychainAttributeInfo attrInfo; + UInt32 attrFormat = 0; + OSStatus ret; + + *attrs = NULL; + + attrInfo.count = 1; + attrInfo.tag = &item; + attrInfo.format = &attrFormat; + + ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, + attrs, NULL, NULL); + if (ret) + return EINVAL; + return 0; +} + + +/* + * + */ + +struct kc_rsa { + SecKeychainItemRef item; + size_t keysize; +}; + + +static int +kc_rsa_public_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +kc_rsa_public_decrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + + +static int +kc_rsa_private_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + struct kc_rsa *kc = RSA_get_app_data(rsa); + + CSSM_RETURN cret; + OSStatus ret; + const CSSM_ACCESS_CREDENTIALS *creds; + SecKeyRef privKeyRef = (SecKeyRef)kc->item; + CSSM_CSP_HANDLE cspHandle; + const CSSM_KEY *cssmKey; + CSSM_CC_HANDLE sigHandle = 0; + CSSM_DATA sig, in; + int fret = 0; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); + if(cret) abort(); + + cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); + if(cret) abort(); + + ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, + kSecCredentialTypeDefault, &creds); + if(ret) abort(); + + ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, + creds, cssmKey, &sigHandle); + if(ret) abort(); + + in.Data = (uint8 *)from; + in.Length = flen; + + sig.Data = (uint8 *)to; + sig.Length = kc->keysize; + + cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); + if(cret) { + /* cssmErrorString(cret); */ + fret = -1; + } else + fret = sig.Length; + + if(sigHandle) + CSSM_DeleteContext(sigHandle); + + return fret; +} + +static int +kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, + RSA * rsa, int padding) +{ + struct kc_rsa *kc = RSA_get_app_data(rsa); + + CSSM_RETURN cret; + OSStatus ret; + const CSSM_ACCESS_CREDENTIALS *creds; + SecKeyRef privKeyRef = (SecKeyRef)kc->item; + CSSM_CSP_HANDLE cspHandle; + const CSSM_KEY *cssmKey; + CSSM_CC_HANDLE handle = 0; + CSSM_DATA out, in, rem; + int fret = 0; + CSSM_SIZE outlen = 0; + char remdata[1024]; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); + if(cret) abort(); + + cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); + if(cret) abort(); + + ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, + kSecCredentialTypeDefault, &creds); + if(ret) abort(); + + + ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, + CSSM_ALGID_RSA, + creds, + cssmKey, + CSSM_PADDING_PKCS1, + &handle); + if(ret) abort(); + + in.Data = (uint8 *)from; + in.Length = flen; + + out.Data = (uint8 *)to; + out.Length = kc->keysize; + + rem.Data = (uint8 *)remdata; + rem.Length = sizeof(remdata); + + cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); + if(cret) { + /* cssmErrorString(cret); */ + fret = -1; + } else + fret = out.Length; + + if(handle) + CSSM_DeleteContext(handle); + + return fret; +} + +static int +kc_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +kc_rsa_finish(RSA *rsa) +{ + struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); + CFRelease(kc_rsa->item); + memset(kc_rsa, 0, sizeof(*kc_rsa)); + free(kc_rsa); + return 1; +} + +static const RSA_METHOD kc_rsa_pkcs1_method = { + "hx509 Keychain PKCS#1 RSA", + kc_rsa_public_encrypt, + kc_rsa_public_decrypt, + kc_rsa_private_encrypt, + kc_rsa_private_decrypt, + NULL, + NULL, + kc_rsa_init, + kc_rsa_finish, + 0, + NULL, + NULL, + NULL, + NULL +}; + +static int +set_private_key(hx509_context context, + SecKeychainItemRef itemRef, + hx509_cert cert) +{ + struct kc_rsa *kc; + hx509_private_key key; + RSA *rsa; + int ret; + + ret = hx509_private_key_init(&key, NULL, NULL); + if (ret) + return ret; + + kc = calloc(1, sizeof(*kc)); + if (kc == NULL) + _hx509_abort("out of memory"); + + kc->item = itemRef; + + rsa = RSA_new(); + if (rsa == NULL) + _hx509_abort("out of memory"); + + /* Argh, fake modulus since OpenSSL API is on crack */ + { + SecKeychainAttributeList *attrs = NULL; + uint32_t size; + void *data; + + rsa->n = BN_new(); + if (rsa->n == NULL) abort(); + + ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); + if (ret) abort(); + + size = *(uint32_t *)attrs->attr[0].data; + SecKeychainItemFreeAttributesAndData(attrs, NULL); + + kc->keysize = (size + 7) / 8; + + data = malloc(kc->keysize); + memset(data, 0xe0, kc->keysize); + BN_bin2bn(data, kc->keysize, rsa->n); + free(data); + } + rsa->e = NULL; + + RSA_set_method(rsa, &kc_rsa_pkcs1_method); + ret = RSA_set_app_data(rsa, kc); + if (ret != 1) + _hx509_abort("RSA_set_app_data"); + + hx509_private_key_assign_rsa(key, rsa); + _hx509_cert_assign_key(cert, key); + + return 0; +} + +/* + * + */ + +struct ks_keychain { + int anchors; + SecKeychainRef keychain; +}; + +static int +keychain_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct ks_keychain *ctx; + + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) { + hx509_set_error_string(context, 0, ENOTSUP, + "KEYCHAIN store does not support not reading " + "private keys"); + return ENOTSUP; + } + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + if (residue) { + if (strcasecmp(residue, "system-anchors") == 0) { + ctx->anchors = 1; + } else if (strncasecmp(residue, "FILE:", 5) == 0) { + OSStatus ret; + + ret = SecKeychainOpen(residue + 5, &ctx->keychain); + if (ret != noErr) { + hx509_set_error_string(context, 0, ENOENT, + "Failed to open %s", residue); + free(ctx); + return ENOENT; + } + } else { + hx509_set_error_string(context, 0, ENOENT, + "Unknown subtype %s", residue); + free(ctx); + return ENOENT; + } + } + + *data = ctx; + return 0; +} + +/* + * + */ + +static int +keychain_free(hx509_certs certs, void *data) +{ + struct ks_keychain *ctx = data; + if (ctx->keychain) + CFRelease(ctx->keychain); + memset(ctx, 0, sizeof(*ctx)); + free(ctx); + return 0; +} + +/* + * + */ + +struct iter { + hx509_certs certs; + void *cursor; + SecKeychainSearchRef searchRef; +}; + +static int +keychain_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct ks_keychain *ctx = data; + struct iter *iter; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + if (ctx->anchors) { + CFArrayRef anchors; + int ret; + int i; + + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, NULL, &iter->certs); + if (ret) { + free(iter); + return ret; + } + + ret = SecTrustCopyAnchorCertificates(&anchors); + if (ret != 0) { + hx509_certs_free(&iter->certs); + free(iter); + hx509_set_error_string(context, 0, ENOMEM, + "Can't get trust anchors from Keychain"); + return ENOMEM; + } + for (i = 0; i < CFArrayGetCount(anchors); i++) { + SecCertificateRef cr; + hx509_cert cert; + CSSM_DATA cssm; + + cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); + + SecCertificateGetData(cr, &cssm); + + cert = hx509_cert_init_data(context, cssm.Data, cssm.Length, NULL); + if (cert == NULL) + continue; + + ret = hx509_certs_add(context, iter->certs, cert); + hx509_cert_free(cert); + } + CFRelease(anchors); + } + + if (iter->certs) { + int ret; + ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); + if (ret) { + hx509_certs_free(&iter->certs); + free(iter); + return ret; + } + } else { + OSStatus ret; + + ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, + kSecCertificateItemClass, + NULL, + &iter->searchRef); + if (ret) { + free(iter); + hx509_set_error_string(context, 0, ret, + "Failed to start search for attributes"); + return ENOMEM; + } + } + + *cursor = iter; + return 0; +} + +/* + * + */ + +static int +keychain_iter(hx509_context context, + hx509_certs certs, void *data, void *cursor, hx509_cert *cert) +{ + SecKeychainAttributeList *attrs = NULL; + SecKeychainAttributeInfo attrInfo; + UInt32 attrFormat[1] = { 0 }; + SecKeychainItemRef itemRef; + SecItemAttr item[1]; + heim_error_t error = NULL; + struct iter *iter = cursor; + OSStatus ret; + UInt32 len; + void *ptr = NULL; + + if (iter->certs) + return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); + + *cert = NULL; + + ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); + if (ret == errSecItemNotFound) + return 0; + else if (ret != 0) + return EINVAL; + + /* + * Pick out certificate and matching "keyid" + */ + + item[0] = kSecPublicKeyHashItemAttr; + + attrInfo.count = 1; + attrInfo.tag = item; + attrInfo.format = attrFormat; + + ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, + &attrs, &len, &ptr); + if (ret) + return EINVAL; + + *cert = hx509_cert_init_data(context, ptr, len, &error); + if (*cert == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + goto out; + } + + /* + * Find related private key if there is one by looking at + * kSecPublicKeyHashItemAttr == kSecKeyLabel + */ + { + SecKeychainSearchRef search; + SecKeychainAttribute attrKeyid; + SecKeychainAttributeList attrList; + + attrKeyid.tag = kSecKeyLabel; + attrKeyid.length = attrs->attr[0].length; + attrKeyid.data = attrs->attr[0].data; + + attrList.count = 1; + attrList.attr = &attrKeyid; + + ret = SecKeychainSearchCreateFromAttributes(NULL, + CSSM_DL_DB_RECORD_PRIVATE_KEY, + &attrList, + &search); + if (ret) { + ret = 0; + goto out; + } + + ret = SecKeychainSearchCopyNext(search, &itemRef); + CFRelease(search); + if (ret == errSecItemNotFound) { + ret = 0; + goto out; + } else if (ret) { + ret = EINVAL; + goto out; + } + set_private_key(context, itemRef, *cert); + } + +out: + SecKeychainItemFreeAttributesAndData(attrs, ptr); + + return ret; +} + +/* + * + */ + +static int +keychain_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct iter *iter = cursor; + + if (iter->certs) { + hx509_certs_end_seq(context, iter->certs, iter->cursor); + hx509_certs_free(&iter->certs); + } else { + CFRelease(iter->searchRef); + } + + memset(iter, 0, sizeof(*iter)); + free(iter); + return 0; +} + +/* + * + */ + +struct hx509_keyset_ops keyset_keychain = { + "KEYCHAIN", + 0, + keychain_init, + NULL, + keychain_free, + NULL, + NULL, + keychain_iter_start, + keychain_iter, + keychain_iter_end, + NULL, + NULL, + NULL, + NULL +}; + +#pragma clang diagnostic pop + +#endif /* HAVE_FRAMEWORK_SECURITY */ + +/* + * + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_keychain_register(hx509_context context) +{ +#ifdef HAVE_FRAMEWORK_SECURITY + _hx509_ks_register(context, &keyset_keychain); +#endif +} diff --git a/third_party/heimdal/lib/hx509/ks_mem.c b/third_party/heimdal/lib/hx509/ks_mem.c new file mode 100644 index 0000000..f325d12 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_mem.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/* + * Should use two hash/tree certificates intead of a array. Criteria + * should be subject and subjectKeyIdentifier since those two are + * commonly seached on in CMS and path building. + */ + +struct mem_data { + char *name; + struct { + unsigned long len; + hx509_cert *val; + } certs; + hx509_private_key *keys; +}; + +static int +mem_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct mem_data *mem; + mem = calloc(1, sizeof(*mem)); + if (mem == NULL) + return ENOMEM; + if (residue == NULL || residue[0] == '\0') + residue = "anonymous"; + mem->name = strdup(residue); + if (mem->name == NULL) { + free(mem); + return ENOMEM; + } + *data = mem; + return 0; +} + +static int +mem_free(hx509_certs certs, void *data) +{ + struct mem_data *mem = data; + unsigned long i; + + for (i = 0; i < mem->certs.len; i++) + hx509_cert_free(mem->certs.val[i]); + free(mem->certs.val); + for (i = 0; mem->keys && mem->keys[i]; i++) + hx509_private_key_free(&mem->keys[i]); + free(mem->keys); + free(mem->name); + free(mem); + + return 0; +} + +static int +mem_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct mem_data *mem = data; + hx509_cert *val; + + val = realloc(mem->certs.val, + (mem->certs.len + 1) * sizeof(mem->certs.val[0])); + if (val == NULL) + return ENOMEM; + + mem->certs.val = val; + mem->certs.val[mem->certs.len] = hx509_cert_ref(c); + mem->certs.len++; + + return 0; +} + +static int +mem_iter_start(hx509_context context, + hx509_certs certs, + void *data, + void **cursor) +{ + unsigned long *iter = malloc(sizeof(*iter)); + + if (iter == NULL) + return ENOMEM; + + *iter = 0; + *cursor = iter; + + return 0; +} + +static int +mem_iter(hx509_context contexst, + hx509_certs certs, + void *data, + void *cursor, + hx509_cert *cert) +{ + unsigned long *iter = cursor; + struct mem_data *mem = data; + + if (*iter >= mem->certs.len) { + *cert = NULL; + return 0; + } + + *cert = hx509_cert_ref(mem->certs.val[*iter]); + (*iter)++; + return 0; +} + +static int +mem_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + free(cursor); + return 0; +} + +static int +mem_getkeys(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key **keys) +{ + struct mem_data *mem = data; + int i; + + for (i = 0; mem->keys && mem->keys[i]; i++) + ; + *keys = calloc(i + 1, sizeof(**keys)); + for (i = 0; mem->keys && mem->keys[i]; i++) { + (*keys)[i] = _hx509_private_key_ref(mem->keys[i]); + if ((*keys)[i] == NULL) { + while (--i >= 0) + hx509_private_key_free(&(*keys)[i]); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + } + (*keys)[i] = NULL; + return 0; +} + +static int +mem_addkey(hx509_context context, + hx509_certs certs, + void *data, + hx509_private_key key) +{ + struct mem_data *mem = data; + void *ptr; + int i; + + for (i = 0; mem->keys && mem->keys[i]; i++) + ; + ptr = realloc(mem->keys, (i + 2) * sizeof(*mem->keys)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + mem->keys = ptr; + mem->keys[i] = _hx509_private_key_ref(key); + mem->keys[i + 1] = NULL; + return 0; +} + + +static struct hx509_keyset_ops keyset_mem = { + "MEMORY", + 0, + mem_init, + NULL, + mem_free, + mem_add, + NULL, + mem_iter_start, + mem_iter, + mem_iter_end, + NULL, + mem_getkeys, + mem_addkey, + NULL +}; + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_mem_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_mem); +} diff --git a/third_party/heimdal/lib/hx509/ks_null.c b/third_party/heimdal/lib/hx509/ks_null.c new file mode 100644 index 0000000..c241d30 --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_null.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + + +static int +null_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + *data = NULL; + return 0; +} + +static int +null_free(hx509_certs certs, void *data) +{ + assert(data == NULL); + return 0; +} + +static int +null_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + *cursor = NULL; + return 0; +} + +static int +null_iter(hx509_context context, + hx509_certs certs, void *data, void *iter, hx509_cert *cert) +{ + *cert = NULL; + return ENOENT; +} + +static int +null_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + assert(cursor == NULL); + return 0; +} + + +struct hx509_keyset_ops keyset_null = { + "NULL", + 0, + null_init, + NULL, + null_free, + NULL, + NULL, + null_iter_start, + null_iter, + null_iter_end, + NULL, + NULL, + NULL, + NULL +}; + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_null_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_null); +} diff --git a/third_party/heimdal/lib/hx509/ks_p11.c b/third_party/heimdal/lib/hx509/ks_p11.c new file mode 100644 index 0000000..265523b --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_p11.c @@ -0,0 +1,1230 @@ +/* + * Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +#ifdef HAVE_DLOPEN + +#include "ref/pkcs11.h" + +struct p11_slot { + uint64_t flags; +#define P11_SESSION 1 +#define P11_SESSION_IN_USE 2 +#define P11_LOGIN_REQ 4 +#define P11_LOGIN_DONE 8 +#define P11_TOKEN_PRESENT 16 + CK_SESSION_HANDLE session; + CK_SLOT_ID id; + CK_BBOOL token; + char *name; + hx509_certs certs; + char *pin; + struct { + CK_MECHANISM_TYPE_PTR list; + CK_ULONG num; + CK_MECHANISM_INFO_PTR *infos; + } mechs; +}; + +struct p11_module { + void *dl_handle; + CK_FUNCTION_LIST_PTR funcs; + CK_ULONG num_slots; + unsigned int ref; + unsigned int selected_slot; + struct p11_slot *slot; +}; + +#define P11FUNC(module,f,args) (*(module)->funcs->C_##f)args + +static int p11_get_session(hx509_context, + struct p11_module *, + struct p11_slot *, + hx509_lock, + CK_SESSION_HANDLE *); +static int p11_put_session(struct p11_module *, + struct p11_slot *, + CK_SESSION_HANDLE); +static void p11_release_module(struct p11_module *); + +static int p11_list_keys(hx509_context, + struct p11_module *, + struct p11_slot *, + CK_SESSION_HANDLE, + hx509_lock, + hx509_certs *); + +/* + * + */ + +struct p11_rsa { + struct p11_module *p; + struct p11_slot *slot; + CK_OBJECT_HANDLE private_key; + CK_OBJECT_HANDLE public_key; +}; + +static int +p11_rsa_public_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +p11_rsa_public_decrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + + +static int +p11_rsa_private_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + CK_OBJECT_HANDLE key = p11rsa->private_key; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_ULONG ck_sigsize; + int ret; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ck_sigsize = RSA_size(rsa); + + ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); + if (ret) + return -1; + + ret = P11FUNC(p11rsa->p, SignInit, (session, &mechanism, key)); + if (ret != CKR_OK) { + p11_put_session(p11rsa->p, p11rsa->slot, session); + return -1; + } + + ret = P11FUNC(p11rsa->p, Sign, + (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize)); + p11_put_session(p11rsa->p, p11rsa->slot, session); + if (ret != CKR_OK) + return -1; + + return ck_sigsize; +} + +static int +p11_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, + RSA * rsa, int padding) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + CK_OBJECT_HANDLE key = p11rsa->private_key; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_ULONG ck_sigsize; + int ret; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ck_sigsize = RSA_size(rsa); + + ret = p11_get_session(NULL, p11rsa->p, p11rsa->slot, NULL, &session); + if (ret) + return -1; + + ret = P11FUNC(p11rsa->p, DecryptInit, (session, &mechanism, key)); + if (ret != CKR_OK) { + p11_put_session(p11rsa->p, p11rsa->slot, session); + return -1; + } + + ret = P11FUNC(p11rsa->p, Decrypt, + (session, (CK_BYTE *)(intptr_t)from, flen, to, &ck_sigsize)); + p11_put_session(p11rsa->p, p11rsa->slot, session); + if (ret != CKR_OK) + return -1; + + return ck_sigsize; +} + +static int +p11_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +p11_rsa_finish(RSA *rsa) +{ + struct p11_rsa *p11rsa = RSA_get_app_data(rsa); + p11_release_module(p11rsa->p); + free(p11rsa); + return 1; +} + +static const RSA_METHOD p11_rsa_pkcs1_method = { + "hx509 PKCS11 PKCS#1 RSA", + p11_rsa_public_encrypt, + p11_rsa_public_decrypt, + p11_rsa_private_encrypt, + p11_rsa_private_decrypt, + NULL, + NULL, + p11_rsa_init, + p11_rsa_finish, + 0, + NULL, + NULL, + NULL, + NULL +}; + +/* + * + */ + +static int +p11_mech_info(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + int num) +{ + CK_ULONG i; + int ret; + + ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech list count for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + if (i == 0) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "no mech supported for slot %d", num); + return HX509_PKCS11_NO_MECH; + } + slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + slot->mechs.num = i; + ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech list for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + assert(i == slot->mechs.num); + + slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + + for (i = 0; i < slot->mechs.num; i++) { + slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); + if (slot->mechs.infos[i] == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], + slot->mechs.infos[i])); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_MECH, + "Failed to get mech info for slot %d", + num); + return HX509_PKCS11_NO_MECH; + } + } + + return 0; +} + +static int +p11_init_slot(hx509_context context, + struct p11_module *p, + hx509_lock lock, + CK_SLOT_ID id, + int num, + struct p11_slot *slot) +{ + CK_SESSION_HANDLE session; + CK_SLOT_INFO slot_info; + CK_TOKEN_INFO token_info; + size_t i; + int ret; + + slot->certs = NULL; + slot->id = id; + + ret = P11FUNC(p, GetSlotInfo, (slot->id, &slot_info)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, + "Failed to init PKCS11 slot %d", + num); + return HX509_PKCS11_TOKEN_CONFUSED; + } + + for (i = sizeof(slot_info.slotDescription) - 1; i > 0; i--) { + char c = slot_info.slotDescription[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0') + continue; + i++; + break; + } + + ret = asprintf(&slot->name, "%.*s", (int)i, + slot_info.slotDescription); + if (ret == -1) + return ENOMEM; + + if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) + return 0; + + ret = P11FUNC(p, GetTokenInfo, (slot->id, &token_info)); + if (ret) { + hx509_set_error_string(context, 0, HX509_PKCS11_NO_TOKEN, + "Failed to init PKCS11 slot %d " + "with error 0x%08x", + num, ret); + return HX509_PKCS11_NO_TOKEN; + } + slot->flags |= P11_TOKEN_PRESENT; + + if (token_info.flags & CKF_LOGIN_REQUIRED) + slot->flags |= P11_LOGIN_REQ; + + ret = p11_get_session(context, p, slot, lock, &session); + if (ret) + return ret; + + ret = p11_mech_info(context, p, slot, num); + if (ret) + goto out; + + ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); + out: + p11_put_session(p, slot, session); + + return ret; +} + +static int +p11_get_session(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + hx509_lock lock, + CK_SESSION_HANDLE *psession) +{ + CK_RV ret; + + if (slot->flags & P11_SESSION_IN_USE) + _hx509_abort("slot already in session"); + + if (slot->flags & P11_SESSION) { + slot->flags |= P11_SESSION_IN_USE; + *psession = slot->session; + return 0; + } + + ret = P11FUNC(p, OpenSession, (slot->id, + CKF_SERIAL_SESSION, + NULL, + NULL, + &slot->session)); + if (ret != CKR_OK) { + if (context) + hx509_set_error_string(context, 0, HX509_PKCS11_OPEN_SESSION, + "Failed to OpenSession for slot id %d " + "with error: 0x%08x", + (int)slot->id, ret); + return HX509_PKCS11_OPEN_SESSION; + } + + slot->flags |= P11_SESSION; + + /* + * If we have have to login, and haven't tried before and have a + * prompter or known to work pin code. + * + * This code is very conversative and only uses the prompter in + * the hx509_lock, the reason is that it's bad to try many + * passwords on a pkcs11 token, it might lock up and have to be + * unlocked by a administrator. + * + * XXX try harder to not use pin several times on the same card. + */ + + if ( (slot->flags & P11_LOGIN_REQ) + && (slot->flags & P11_LOGIN_DONE) == 0 + && (lock || slot->pin)) + { + hx509_prompt prompt; + char pin[20]; + char *str; + + if (slot->pin == NULL) { + + memset(&prompt, 0, sizeof(prompt)); + + ret = asprintf(&str, "PIN code for %s: ", slot->name); + if (ret == -1 || str == NULL) { + if (context) + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + prompt.prompt = str; + prompt.type = HX509_PROMPT_TYPE_PASSWORD; + prompt.reply.data = pin; + prompt.reply.length = sizeof(pin); + + ret = hx509_lock_prompt(lock, &prompt); + if (ret) { + free(str); + if (context) + hx509_set_error_string(context, 0, ret, + "Failed to get pin code for slot " + "id %d with error: %d", + (int)slot->id, ret); + return ret; + } + free(str); + } else { + strlcpy(pin, slot->pin, sizeof(pin)); + } + + ret = P11FUNC(p, Login, (slot->session, CKU_USER, + (unsigned char*)pin, strlen(pin))); + if (ret != CKR_OK) { + if (context) + hx509_set_error_string(context, 0, HX509_PKCS11_LOGIN, + "Failed to login on slot id %d " + "with error: 0x%08x", + (int)slot->id, ret); + switch(ret) { + case CKR_PIN_LOCKED: + return HX509_PKCS11_PIN_LOCKED; + case CKR_PIN_EXPIRED: + return HX509_PKCS11_PIN_EXPIRED; + case CKR_PIN_INCORRECT: + return HX509_PKCS11_PIN_INCORRECT; + case CKR_USER_PIN_NOT_INITIALIZED: + return HX509_PKCS11_PIN_NOT_INITIALIZED; + default: + return HX509_PKCS11_LOGIN; + } + } else + slot->flags |= P11_LOGIN_DONE; + + if (slot->pin == NULL) { + slot->pin = strdup(pin); + if (slot->pin == NULL) { + if (context) + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + } + } else + slot->flags |= P11_LOGIN_DONE; + + slot->flags |= P11_SESSION_IN_USE; + + *psession = slot->session; + + return 0; +} + +static int +p11_put_session(struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session) +{ + if ((slot->flags & P11_SESSION_IN_USE) == 0) + _hx509_abort("slot not in session"); + slot->flags &= ~P11_SESSION_IN_USE; + + return 0; +} + +static int +iterate_entries(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_ATTRIBUTE *search_data, int num_search_data, + CK_ATTRIBUTE *query, int num_query, + int (*func)(hx509_context, + struct p11_module *, struct p11_slot *, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *, CK_ATTRIBUTE *, int), void *ptr) +{ + CK_OBJECT_HANDLE object; + CK_ULONG object_count; + int ret, ret2, i; + + ret = P11FUNC(p, FindObjectsInit, (session, search_data, num_search_data)); + if (ret != CKR_OK) { + return -1; + } + while (1) { + ret = P11FUNC(p, FindObjects, (session, &object, 1, &object_count)); + if (ret != CKR_OK) { + return -1; + } + if (object_count == 0) + break; + + for (i = 0; i < num_query; i++) + query[i].pValue = NULL; + + ret = P11FUNC(p, GetAttributeValue, + (session, object, query, num_query)); + if (ret != CKR_OK) { + return -1; + } + for (i = 0; i < num_query; i++) { + query[i].pValue = malloc(query[i].ulValueLen); + if (query[i].pValue == NULL) { + ret = ENOMEM; + goto out; + } + } + ret = P11FUNC(p, GetAttributeValue, + (session, object, query, num_query)); + if (ret != CKR_OK) { + ret = -1; + goto out; + } + + ret = (*func)(context, p, slot, session, object, ptr, query, num_query); + if (ret) + goto out; + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + } + out: + + for (i = 0; i < num_query; i++) { + if (query[i].pValue) + free(query[i].pValue); + query[i].pValue = NULL; + } + + ret2 = P11FUNC(p, FindObjectsFinal, (session)); + if (ret2 != CKR_OK) { + return ret2; + } + + return ret; +} + +static BIGNUM * +getattr_bn(struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + unsigned int type) +{ + CK_ATTRIBUTE query; + BIGNUM *bn; + int ret; + + query.type = type; + query.pValue = NULL; + query.ulValueLen = 0; + + ret = P11FUNC(p, GetAttributeValue, + (session, object, &query, 1)); + if (ret != CKR_OK) + return NULL; + + query.pValue = malloc(query.ulValueLen); + + ret = P11FUNC(p, GetAttributeValue, + (session, object, &query, 1)); + if (ret != CKR_OK) { + free(query.pValue); + return NULL; + } + bn = BN_bin2bn(query.pValue, query.ulValueLen, NULL); + free(query.pValue); + + return bn; +} + +static int +collect_private_key(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + struct hx509_collector *collector = ptr; + hx509_private_key key; + heim_octet_string localKeyId; + int ret; + RSA *rsa; + struct p11_rsa *p11rsa; + + localKeyId.data = query[0].pValue; + localKeyId.length = query[0].ulValueLen; + + ret = hx509_private_key_init(&key, NULL, NULL); + if (ret) + return ret; + + rsa = RSA_new(); + if (rsa == NULL) + _hx509_abort("out of memory"); + + /* + * The exponent and modulus should always be present according to + * the pkcs11 specification, but some smartcards leaves it out, + * let ignore any failure to fetch it. + */ + rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS); + rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); + + p11rsa = calloc(1, sizeof(*p11rsa)); + if (p11rsa == NULL) + _hx509_abort("out of memory"); + + p11rsa->p = p; + p11rsa->slot = slot; + p11rsa->private_key = object; + + if (p->ref == 0) + _hx509_abort("pkcs11 ref == 0 on alloc"); + p->ref++; + if (p->ref == UINT_MAX) + _hx509_abort("pkcs11 ref == UINT_MAX on alloc"); + + RSA_set_method(rsa, &p11_rsa_pkcs1_method); + ret = RSA_set_app_data(rsa, p11rsa); + if (ret != 1) + _hx509_abort("RSA_set_app_data"); + + hx509_private_key_assign_rsa(key, rsa); + + ret = _hx509_collector_private_key_add(context, + collector, + hx509_signature_rsa(), + key, + NULL, + &localKeyId); + + if (ret) { + hx509_private_key_free(&key); + return ret; + } + return 0; +} + +static void +p11_cert_release(hx509_cert cert, void *ctx) +{ + struct p11_module *p = ctx; + p11_release_module(p); +} + + +static int +collect_cert(hx509_context context, + struct p11_module *p, struct p11_slot *slot, + CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + void *ptr, CK_ATTRIBUTE *query, int num_query) +{ + struct hx509_collector *collector = ptr; + heim_error_t error = NULL; + hx509_cert cert; + int ret; + + if ((CK_LONG)query[0].ulValueLen == -1 || + (CK_LONG)query[1].ulValueLen == -1) + { + return 0; + } + + cert = hx509_cert_init_data(context, query[1].pValue, + query[1].ulValueLen, &error); + if (cert == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + return ret; + } + + if (p->ref == 0) + _hx509_abort("pkcs11 ref == 0 on alloc"); + p->ref++; + if (p->ref == UINT_MAX) + _hx509_abort("pkcs11 ref to high"); + + _hx509_cert_set_release(cert, p11_cert_release, p); + + { + heim_octet_string data; + + data.data = query[0].pValue; + data.length = query[0].ulValueLen; + + _hx509_set_cert_attribute(context, + cert, + &asn1_oid_id_pkcs_9_at_localKeyId, + &data); + } + + if ((CK_LONG)query[2].ulValueLen != -1) { + char *str; + + ret = asprintf(&str, "%.*s", + (int)query[2].ulValueLen, (char *)query[2].pValue); + if (ret != -1 && str) { + hx509_cert_set_friendly_name(cert, str); + free(str); + } + } + + ret = _hx509_collector_certs_add(context, collector, cert); + hx509_cert_free(cert); + + return ret; +} + + +static int +p11_list_keys(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + CK_SESSION_HANDLE session, + hx509_lock lock, + hx509_certs *certs) +{ + struct hx509_collector *collector; + CK_OBJECT_CLASS key_class; + CK_ATTRIBUTE search_data[] = { + {CKA_CLASS, NULL, 0}, + }; + CK_ATTRIBUTE query_data[3] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + int ret; + + search_data[0].pValue = &key_class; + search_data[0].ulValueLen = sizeof(key_class); + + if (lock == NULL) + lock = _hx509_empty_lock; + + ret = _hx509_collector_alloc(context, lock, &collector); + if (ret) + return ret; + + key_class = CKO_PRIVATE_KEY; + ret = iterate_entries(context, p, slot, session, + search_data, 1, + query_data, 1, + collect_private_key, collector); + if (ret) + goto out; + + key_class = CKO_CERTIFICATE; + ret = iterate_entries(context, p, slot, session, + search_data, 1, + query_data, 3, + collect_cert, collector); + if (ret) + goto out; + + ret = _hx509_collector_collect_certs(context, collector, &slot->certs); + +out: + _hx509_collector_free(collector); + + return ret; +} + + +static int +p11_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + CK_C_GetFunctionList getFuncs; + struct p11_module *p; + char *list, *str; + int ret; + + *data = NULL; + + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) { + hx509_set_error_string(context, 0, ENOTSUP, + "PKCS#11 store does not support " + "HX509_CERTS_NO_PRIVATE_KEYS flag"); + return ENOTSUP; + } + + if (residue == NULL || residue[0] == '\0') { + hx509_set_error_string(context, 0, EINVAL, + "PKCS#11 store not specified"); + return EINVAL; + } + list = strdup(residue); + if (list == NULL) + return ENOMEM; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + free(list); + return ENOMEM; + } + + p->ref = 1; + p->selected_slot = 0; + + str = strchr(list, ','); + if (str) + *str++ = '\0'; + while (str) { + char *strnext; + strnext = strchr(str, ','); + if (strnext) + *strnext++ = '\0'; + if (strncasecmp(str, "slot=", 5) == 0) + p->selected_slot = atoi(str + 5); + str = strnext; + } + + p->dl_handle = dlopen(list, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); + if (p->dl_handle == NULL) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "Failed to open %s: %s", list, dlerror()); + goto out; + } + + getFuncs = (CK_C_GetFunctionList) dlsym(p->dl_handle, "C_GetFunctionList"); + if (getFuncs == NULL) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "C_GetFunctionList missing in %s: %s", + list, dlerror()); + goto out; + } + + ret = (*getFuncs)(&p->funcs); + if (ret) { + ret = HX509_PKCS11_LOAD; + hx509_set_error_string(context, 0, ret, + "C_GetFunctionList failed in %s", list); + goto out; + } + + ret = P11FUNC(p, Initialize, (NULL_PTR)); + if (ret != CKR_OK) { + ret = HX509_PKCS11_TOKEN_CONFUSED; + hx509_set_error_string(context, 0, ret, + "Failed initialize the PKCS11 module"); + goto out; + } + + ret = P11FUNC(p, GetSlotList, (FALSE, NULL, &p->num_slots)); + if (ret) { + ret = HX509_PKCS11_TOKEN_CONFUSED; + hx509_set_error_string(context, 0, ret, + "Failed to get number of PKCS11 slots"); + goto out; + } + + if (p->num_slots == 0) { + ret = HX509_PKCS11_NO_SLOT; + hx509_set_error_string(context, 0, ret, + "Selected PKCS11 module have no slots"); + goto out; + } + + + { + CK_SLOT_ID_PTR slot_ids; + int num_tokens = 0; + size_t i; + + slot_ids = malloc(p->num_slots * sizeof(*slot_ids)); + if (slot_ids == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = P11FUNC(p, GetSlotList, (FALSE, slot_ids, &p->num_slots)); + if (ret) { + free(slot_ids); + hx509_set_error_string(context, 0, HX509_PKCS11_TOKEN_CONFUSED, + "Failed getting slot-list from " + "PKCS11 module"); + ret = HX509_PKCS11_TOKEN_CONFUSED; + goto out; + } + + p->slot = calloc(p->num_slots, sizeof(p->slot[0])); + if (p->slot == NULL) { + free(slot_ids); + hx509_set_error_string(context, 0, ENOMEM, + "Failed to get memory for slot-list"); + ret = ENOMEM; + goto out; + } + + for (i = 0; i < p->num_slots; i++) { + if ((p->selected_slot != 0) && (slot_ids[i] != (p->selected_slot - 1))) + continue; + ret = p11_init_slot(context, p, lock, slot_ids[i], i, &p->slot[i]); + if (!ret) { + if (p->slot[i].flags & P11_TOKEN_PRESENT) + num_tokens++; + } + } + free(slot_ids); + if (ret) + goto out; + if (num_tokens == 0) { + ret = HX509_PKCS11_NO_TOKEN; + goto out; + } + } + + free(list); + + *data = p; + + return 0; + out: + if (list) + free(list); + p11_release_module(p); + return ret; +} + +static void +p11_release_module(struct p11_module *p) +{ + size_t i; + + if (p->ref == 0) + _hx509_abort("pkcs11 ref to low"); + if (--p->ref > 0) + return; + + for (i = 0; i < p->num_slots; i++) { + if (p->slot[i].flags & P11_SESSION_IN_USE) + _hx509_abort("pkcs11 module release while session in use"); + if (p->slot[i].flags & P11_SESSION) { + P11FUNC(p, CloseSession, (p->slot[i].session)); + } + + if (p->slot[i].name) + free(p->slot[i].name); + if (p->slot[i].pin) { + memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); + free(p->slot[i].pin); + } + if (p->slot[i].mechs.num) { + free(p->slot[i].mechs.list); + + if (p->slot[i].mechs.infos) { + size_t j; + + for (j = 0 ; j < p->slot[i].mechs.num ; j++) + free(p->slot[i].mechs.infos[j]); + free(p->slot[i].mechs.infos); + } + } + } + free(p->slot); + + if (p->funcs) + P11FUNC(p, Finalize, (NULL)); + + if (p->dl_handle) + dlclose(p->dl_handle); + + memset(p, 0, sizeof(*p)); + free(p); +} + +static int +p11_free(hx509_certs certs, void *data) +{ + struct p11_module *p = data; + size_t i; + + for (i = 0; i < p->num_slots; i++) { + if (p->slot[i].certs) + hx509_certs_free(&p->slot[i].certs); + } + p11_release_module(p); + return 0; +} + +struct p11_cursor { + hx509_certs certs; + void *cursor; +}; + +static int +p11_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct p11_module *p = data; + struct p11_cursor *c; + int ret; + size_t i; + + c = malloc(sizeof(*c)); + if (c == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + ret = hx509_certs_init(context, "MEMORY:pkcs11-iter", 0, NULL, &c->certs); + if (ret) { + free(c); + return ret; + } + + for (i = 0 ; i < p->num_slots; i++) { + if (p->slot[i].certs == NULL) + continue; + ret = hx509_certs_merge(context, c->certs, p->slot[i].certs); + if (ret) { + hx509_certs_free(&c->certs); + free(c); + return ret; + } + } + + ret = hx509_certs_start_seq(context, c->certs, &c->cursor); + if (ret) { + hx509_certs_free(&c->certs); + free(c); + return 0; + } + *cursor = c; + + return 0; +} + +static int +p11_iter(hx509_context context, + hx509_certs certs, void *data, void *cursor, hx509_cert *cert) +{ + struct p11_cursor *c = cursor; + return hx509_certs_next_cert(context, c->certs, c->cursor, cert); +} + +static int +p11_iter_end(hx509_context context, + hx509_certs certs, void *data, void *cursor) +{ + struct p11_cursor *c = cursor; + int ret; + ret = hx509_certs_end_seq(context, c->certs, c->cursor); + hx509_certs_free(&c->certs); + free(c); + return ret; +} + +#define MECHFLAG(x) { "unknown-flag-" #x, x } +static struct units mechflags[] = { + MECHFLAG(0x80000000), + MECHFLAG(0x40000000), + MECHFLAG(0x20000000), + MECHFLAG(0x10000000), + MECHFLAG(0x08000000), + MECHFLAG(0x04000000), + {"ec-compress", 0x2000000 }, + {"ec-uncompress", 0x1000000 }, + {"ec-namedcurve", 0x0800000 }, + {"ec-ecparameters", 0x0400000 }, + {"ec-f-2m", 0x0200000 }, + {"ec-f-p", 0x0100000 }, + {"derive", 0x0080000 }, + {"unwrap", 0x0040000 }, + {"wrap", 0x0020000 }, + {"genereate-key-pair", 0x0010000 }, + {"generate", 0x0008000 }, + {"verify-recover", 0x0004000 }, + {"verify", 0x0002000 }, + {"sign-recover", 0x0001000 }, + {"sign", 0x0000800 }, + {"digest", 0x0000400 }, + {"decrypt", 0x0000200 }, + {"encrypt", 0x0000100 }, + MECHFLAG(0x00080), + MECHFLAG(0x00040), + MECHFLAG(0x00020), + MECHFLAG(0x00010), + MECHFLAG(0x00008), + MECHFLAG(0x00004), + MECHFLAG(0x00002), + {"hw", 0x0000001 }, + { NULL, 0x0000000 } +}; +#undef MECHFLAG + +static int +p11_printinfo(hx509_context context, + hx509_certs certs, + void *data, + int (*func)(void *, const char *), + void *ctx) +{ + struct p11_module *p = data; + size_t i, j; + + _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slot%s", + p->num_slots, p->num_slots > 1 ? "s" : ""); + + for (i = 0; i < p->num_slots; i++) { + struct p11_slot *s = &p->slot[i]; + + _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x", + i, (int)s->id, s->name, s->flags); + + _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu", + (unsigned long)s->mechs.num); + for (j = 0; j < s->mechs.num; j++) { + const char *mechname = "unknown"; + char flags[256], unknownname[40]; +#define MECHNAME(s,n) case s: mechname = n; break + switch(s->mechs.list[j]) { + MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen"); + MECHNAME(CKM_RSA_PKCS, "rsa-pkcs"); + MECHNAME(CKM_RSA_X_509, "rsa-x-509"); + MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); + MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); + MECHNAME(CKM_SHA256_RSA_PKCS, "sha256-rsa-pkcs"); + MECHNAME(CKM_SHA384_RSA_PKCS, "sha384-rsa-pkcs"); + MECHNAME(CKM_SHA512_RSA_PKCS, "sha512-rsa-pkcs"); + MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs"); + MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep"); + MECHNAME(CKM_SHA512_HMAC, "sha512-hmac"); + MECHNAME(CKM_SHA512, "sha512"); + MECHNAME(CKM_SHA384_HMAC, "sha384-hmac"); + MECHNAME(CKM_SHA384, "sha384"); + MECHNAME(CKM_SHA256_HMAC, "sha256-hmac"); + MECHNAME(CKM_SHA256, "sha256"); + MECHNAME(CKM_SHA_1, "sha1"); + MECHNAME(CKM_MD5, "md5"); + MECHNAME(CKM_RIPEMD160, "ripemd-160"); + MECHNAME(CKM_DES_ECB, "des-ecb"); + MECHNAME(CKM_DES_CBC, "des-cbc"); + MECHNAME(CKM_AES_ECB, "aes-ecb"); + MECHNAME(CKM_AES_CBC, "aes-cbc"); + MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen"); + default: + snprintf(unknownname, sizeof(unknownname), + "unknown-mech-%lu", + (unsigned long)s->mechs.list[j]); + mechname = unknownname; + break; + } +#undef MECHNAME + unparse_flags(s->mechs.infos[j]->flags, mechflags, + flags, sizeof(flags)); + + _hx509_pi_printf(func, ctx, " %s: %s", mechname, flags); + } + } + + return 0; +} + +static struct hx509_keyset_ops keyset_pkcs11 = { + "PKCS11", + 0, + p11_init, + NULL, + p11_free, + NULL, + NULL, + p11_iter_start, + p11_iter, + p11_iter_end, + p11_printinfo, + NULL, + NULL, + NULL +}; + +#endif /* HAVE_DLOPEN */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_pkcs11_register(hx509_context context) +{ +#ifdef HAVE_DLOPEN + _hx509_ks_register(context, &keyset_pkcs11); +#endif +} diff --git a/third_party/heimdal/lib/hx509/ks_p12.c b/third_party/heimdal/lib/hx509/ks_p12.c new file mode 100644 index 0000000..1e9a92a --- /dev/null +++ b/third_party/heimdal/lib/hx509/ks_p12.c @@ -0,0 +1,764 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +struct ks_pkcs12 { + hx509_certs certs; + char *fn; + unsigned int store_no_priv_keys; +}; + +typedef int (*collector_func)(hx509_context, + struct hx509_collector *, + int, + const void *, size_t, + const PKCS12_Attributes *); + +struct type { + const heim_oid *oid; + collector_func func; +}; + +static void +parse_pkcs12_type(hx509_context, struct hx509_collector *, int, + const heim_oid *, const void *, size_t, + const PKCS12_Attributes *); + + +static const PKCS12_Attribute * +find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid) +{ + size_t i; + if (attrs == NULL) + return NULL; + for (i = 0; i < attrs->len; i++) + if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0) + return &attrs->val[i]; + return NULL; +} + +static int +keyBag_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + const PKCS12_Attribute *attr; + PKCS8PrivateKeyInfo ki; + const heim_octet_string *os = NULL; + int ret; + + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) + return 0; + + attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId); + if (attr) + os = &attr->attrValues; + + ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); + if (ret) + return ret; + + ret = _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + os); + free_PKCS8PrivateKeyInfo(&ki); + return ret; +} + +static int +ShroudedKeyBag_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + PKCS8EncryptedPrivateKeyInfo pk; + heim_octet_string content; + int ret; + + memset(&pk, 0, sizeof(pk)); + + ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL); + if (ret) + return ret; + + ret = _hx509_pbe_decrypt(context, + _hx509_collector_get_lock(c), + &pk.encryptionAlgorithm, + &pk.encryptedData, + &content); + free_PKCS8EncryptedPrivateKeyInfo(&pk); + if (ret) + return ret; + + ret = keyBag_parser(context, c, flags, content.data, content.length, + attrs); + der_free_octet_string(&content); + return ret; +} + +static int +certBag_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_error_t error = NULL; + heim_octet_string os; + hx509_cert cert; + PKCS12_CertBag cb; + int ret; + + ret = decode_PKCS12_CertBag(data, length, &cb, NULL); + if (ret) + return ret; + + if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) { + free_PKCS12_CertBag(&cb); + return 0; + } + + ret = decode_PKCS12_OctetString(cb.certValue.data, + cb.certValue.length, + &os, + NULL); + free_PKCS12_CertBag(&cb); + if (ret) + return ret; + + cert = hx509_cert_init_data(context, os.data, os.length, &error); + der_free_octet_string(&os); + if (cert == NULL) { + ret = heim_error_get_code(error); + heim_release(error); + return ret; + } + + ret = _hx509_collector_certs_add(context, c, cert); + if (ret) { + hx509_cert_free(cert); + return ret; + } + + { + const PKCS12_Attribute *attr; + const heim_oid *oids[] = { + &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName + }; + size_t i; + + for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { + const heim_oid *oid = oids[i]; + attr = find_attribute(attrs, oid); + if (attr) + _hx509_set_cert_attribute(context, cert, oid, + &attr->attrValues); + } + } + + hx509_cert_free(cert); + + return 0; +} + +static int +parse_safe_content(hx509_context context, + struct hx509_collector *c, + int flags, + const unsigned char *p, size_t len) +{ + PKCS12_SafeContents sc; + int ret; + size_t i; + + memset(&sc, 0, sizeof(sc)); + + ret = decode_PKCS12_SafeContents(p, len, &sc, NULL); + if (ret) + return ret; + + for (i = 0; i < sc.len ; i++) + parse_pkcs12_type(context, + c, + flags, + &sc.val[i].bagId, + sc.val[i].bagValue.data, + sc.val[i].bagValue.length, + sc.val[i].bagAttributes); + + free_PKCS12_SafeContents(&sc); + return 0; +} + +static int +safeContent_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string os; + int ret; + + ret = decode_PKCS12_OctetString(data, length, &os, NULL); + if (ret) + return ret; + ret = parse_safe_content(context, c, flags, os.data, os.length); + der_free_octet_string(&os); + return ret; +} + +static int +encryptedData_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + ret = hx509_cms_decrypt_encrypted(context, + _hx509_collector_get_lock(c), + data, length, + &contentType, + &content); + if (ret) + return ret; + + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) + ret = parse_safe_content(context, c, flags, + content.data, content.length); + + der_free_octet_string(&content); + der_free_oid(&contentType); + return ret; +} + +static int +envelopedData_parser(hx509_context context, + struct hx509_collector *c, + int flags, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + heim_octet_string content; + heim_oid contentType; + hx509_lock lock; + int ret; + + memset(&contentType, 0, sizeof(contentType)); + + lock = _hx509_collector_get_lock(c); + + ret = hx509_cms_unenvelope(context, + _hx509_lock_unlock_certs(lock), + 0, + data, length, + NULL, + 0, + &contentType, + &content); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "PKCS12 failed to unenvelope"); + return ret; + } + + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) + ret = parse_safe_content(context, c, flags, + content.data, content.length); + + der_free_octet_string(&content); + der_free_oid(&contentType); + + return ret; +} + + +struct type bagtypes[] = { + { &asn1_oid_id_pkcs12_keyBag, keyBag_parser }, + { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, + { &asn1_oid_id_pkcs12_certBag, certBag_parser }, + { &asn1_oid_id_pkcs7_data, safeContent_parser }, + { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser }, + { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser } +}; + +static void +parse_pkcs12_type(hx509_context context, + struct hx509_collector *c, + int flags, + const heim_oid *oid, + const void *data, size_t length, + const PKCS12_Attributes *attrs) +{ + size_t i; + + for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) + if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0) + (*bagtypes[i].func)(context, c, flags, data, length, attrs); +} + +static int +p12_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct ks_pkcs12 *p12; + size_t len; + void *buf; + PKCS12_PFX pfx; + PKCS12_AuthenticatedSafe as; + int ret; + size_t i; + struct hx509_collector *c; + + *data = NULL; + + if (residue == NULL || residue[0] == '\0') { + hx509_set_error_string(context, 0, EINVAL, + "PKCS#12 file not specified"); + return EINVAL; + } + + if (lock == NULL) + lock = _hx509_empty_lock; + + ret = _hx509_collector_alloc(context, lock, &c); + if (ret) + return ret; + + p12 = calloc(1, sizeof(*p12)); + if (p12 == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + p12->fn = strdup(residue); + if (p12->fn == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + if (flags & HX509_CERTS_CREATE) { + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, lock, &p12->certs); + if (ret == 0) + *data = p12; + goto out; + } + + ret = rk_undumpdata(residue, &buf, &len); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ret = decode_PKCS12_PFX(buf, len, &pfx, NULL); + rk_xfree(buf); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode the PFX in %s", residue); + goto out; + } + + if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "PKCS PFX isn't a pkcs7-data container"); + goto out; + } + + if (pfx.authSafe.content == NULL) { + free_PKCS12_PFX(&pfx); + ret = EINVAL; + hx509_set_error_string(context, 0, ret, + "PKCS PFX missing data"); + goto out; + } + + { + heim_octet_string asdata; + + ret = decode_PKCS12_OctetString(pfx.authSafe.content->data, + pfx.authSafe.content->length, + &asdata, + NULL); + free_PKCS12_PFX(&pfx); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + ret = decode_PKCS12_AuthenticatedSafe(asdata.data, + asdata.length, + &as, + NULL); + der_free_octet_string(&asdata); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + + for (i = 0; i < as.len; i++) + parse_pkcs12_type(context, + c, + flags, + &as.val[i].contentType, + as.val[i].content->data, + as.val[i].content->length, + NULL); + + free_PKCS12_AuthenticatedSafe(&as); + + ret = _hx509_collector_collect_certs(context, c, &p12->certs); + if (ret == 0) + *data = p12; + +out: + _hx509_collector_free(c); + + if (ret && p12) { + if (p12->fn) + free(p12->fn); + if (p12->certs) + hx509_certs_free(&p12->certs); + free(p12); + } + + return ret; +} + +static int +addBag(hx509_context context, + PKCS12_AuthenticatedSafe *as, + const heim_oid *oid, + void *data, + size_t length) +{ + void *ptr; + int ret; + + ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + as->val = ptr; + + ret = der_copy_oid(oid, &as->val[as->len].contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } + + as->val[as->len].content = calloc(1, sizeof(*as->val[0].content)); + if (as->val[as->len].content == NULL) { + der_free_oid(&as->val[as->len].contentType); + hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); + return ENOMEM; + } + + as->val[as->len].content->data = data; + as->val[as->len].content->length = length; + + as->len++; + + return 0; +} + +struct store_func_ctx { + PKCS12_AuthenticatedSafe as; + int store_flags; +}; + +static int HX509_LIB_CALL +store_func(hx509_context context, void *d, hx509_cert c) +{ + struct store_func_ctx *ctx = d; + PKCS12_OctetString os; + PKCS12_CertBag cb; + size_t size; + int ret; + + if ((ctx->store_flags & HX509_CERTS_STORE_NO_ROOTS)) { + int is_root = 0; + + ret = hx509_cert_is_root(context, c, &is_root); + if (ret || is_root) + return ret; + } + + memset(&os, 0, sizeof(os)); + memset(&cb, 0, sizeof(cb)); + + os.data = NULL; + os.length = 0; + + ret = hx509_cert_binary(context, c, &os); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(PKCS12_OctetString, + cb.certValue.data,cb.certValue.length, + &os, &size, ret); + free(os.data); + if (ret) + goto out; + ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType); + if (ret) { + free_PKCS12_CertBag(&cb); + goto out; + } + ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length, + &cb, &size, ret); + free_PKCS12_CertBag(&cb); + if (ret) + goto out; + + ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_certBag, os.data, + os.length); + + if (_hx509_cert_private_key_exportable(c) && + !(ctx->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { + hx509_private_key key = _hx509_cert_private_key(c); + PKCS8PrivateKeyInfo pki; + + memset(&pki, 0, sizeof(pki)); + + ret = der_parse_hex_heim_integer("00", &pki.version); + if (ret) + return ret; + ret = _hx509_private_key_oid(context, key, + &pki.privateKeyAlgorithm.algorithm); + if (ret) { + free_PKCS8PrivateKeyInfo(&pki); + return ret; + } + ret = _hx509_private_key_export(context, + _hx509_cert_private_key(c), + HX509_KEY_FORMAT_DER, + &pki.privateKey); + if (ret) { + free_PKCS8PrivateKeyInfo(&pki); + return ret; + } + /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */ + + ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length, + &pki, &size, ret); + free_PKCS8PrivateKeyInfo(&pki); + if (ret) + return ret; + + ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_keyBag, os.data, + os.length); + if (ret) + return ret; + } + +out: + return ret; +} + +static int +p12_store(hx509_context context, + hx509_certs certs, void *data, int flags, hx509_lock lock) +{ + struct ks_pkcs12 *p12 = data; + PKCS12_PFX pfx; + struct store_func_ctx ctx; + PKCS12_OctetString asdata; + size_t size; + int ret; + + memset(&ctx, 0, sizeof(ctx)); + memset(&pfx, 0, sizeof(pfx)); + ctx.store_flags = flags; + + ret = hx509_certs_iter_f(context, p12->certs, store_func, &ctx); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length, + &ctx.as, &size, ret); + free_PKCS12_AuthenticatedSafe(&ctx.as); + if (ret) + return ret; + + ret = der_parse_hex_heim_integer("03", &pfx.version); + if (ret) { + free(asdata.data); + goto out; + } + + pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content)); + + ASN1_MALLOC_ENCODE(PKCS12_OctetString, + pfx.authSafe.content->data, + pfx.authSafe.content->length, + &asdata, &size, ret); + free(asdata.data); + if (ret) + goto out; + + ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length, + &pfx, &size, ret); + if (ret) + goto out; + +#if 0 + const struct _hx509_password *pw; + + pw = _hx509_lock_get_passwords(lock); + if (pw != NULL) { + pfx.macData = calloc(1, sizeof(*pfx.macData)); + if (pfx.macData == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; + } + if (pfx.macData == NULL) { + free(asdata.data); + goto out; + } + } + ret = calculate_hash(&aspath, pw, pfx.macData); +#endif + + rk_dumpdata(p12->fn, asdata.data, asdata.length); + free(asdata.data); + +out: + free_PKCS12_AuthenticatedSafe(&ctx.as); + free_PKCS12_PFX(&pfx); + + return ret; +} + + +static int +p12_free(hx509_certs certs, void *data) +{ + struct ks_pkcs12 *p12 = data; + hx509_certs_free(&p12->certs); + free(p12->fn); + free(p12); + return 0; +} + +static int +p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_add(context, p12->certs, c); +} + +static int +p12_iter_start(hx509_context context, + hx509_certs certs, + void *data, + void **cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_start_seq(context, p12->certs, cursor); +} + +static int +p12_iter(hx509_context context, + hx509_certs certs, + void *data, + void *cursor, + hx509_cert *cert) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_next_cert(context, p12->certs, cursor, cert); +} + +static int +p12_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct ks_pkcs12 *p12 = data; + return hx509_certs_end_seq(context, p12->certs, cursor); +} + +static int +p12_destroy(hx509_context context, hx509_certs certs, void *data) +{ + struct ks_pkcs12 *p12 = data; + return _hx509_erase_file(context, p12->fn); +} + +static struct hx509_keyset_ops keyset_pkcs12 = { + "PKCS12", + 0, + p12_init, + p12_store, + p12_free, + p12_add, + NULL, + p12_iter_start, + p12_iter, + p12_iter_end, + NULL, + NULL, + NULL, + p12_destroy +}; + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_ks_pkcs12_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_pkcs12); +} diff --git a/third_party/heimdal/lib/hx509/libhx509-exports.def b/third_party/heimdal/lib/hx509/libhx509-exports.def new file mode 100644 index 0000000..12c45da --- /dev/null +++ b/third_party/heimdal/lib/hx509/libhx509-exports.def @@ -0,0 +1,305 @@ + +EXPORTS + _hx509_cert_assign_key + _hx509_cert_get_keyusage + _hx509_cert_get_version + _hx509_cert_private_key + _hx509_certs_keys_free + _hx509_certs_keys_get + _hx509_expr_eval + _hx509_expr_free + _hx509_expr_parse + _hx509_generate_private_key + _hx509_generate_private_key_bits + _hx509_generate_private_key_free + _hx509_generate_private_key_init + _hx509_generate_private_key_is_ca + _hx509_get_cert + _hx509_ks_type + _hx509_make_pkinit_san + _hx509_map_file_os + _hx509_name_from_Name + _hx509_private_key_export + _hx509_private_key_exportable + _hx509_private_key_get_internal + _hx509_private_key_oid + _hx509_private_key_ref + hx509_private_key2SPKI + hx509_private_key_free + _hx509_private_key_ref + hx509_request_add_GeneralName + hx509_request_add_dns_name + hx509_request_add_dns_srv + hx509_request_add_eku + hx509_request_add_email + hx509_request_add_ms_upn_name + hx509_request_add_pkinit + hx509_request_add_registered + hx509_request_add_xmpp_name + hx509_request_authorize_cA + hx509_request_authorize_ku + hx509_request_authorize_eku + hx509_request_authorize_san + hx509_request_count_unsupported + hx509_request_count_unauthorized + _hx509_private_key_export + _hx509_private_key_exportable + _hx509_private_key_get_internal + _hx509_private_key_oid + _hx509_private_key_ref + hx509_request_eku_authorized_p + hx509_request_free + hx509_request_get_cA + hx509_request_get_cA_pathLenConstraint + hx509_request_get_eku + hx509_request_get_exts + hx509_request_get_ku + hx509_request_get_name + hx509_request_get_san + hx509_request_get_SubjectPublicKeyInfo + hx509_request_get_name + hx509_request_init + hx509_request_parse + hx509_request_parse_der + hx509_request_print + hx509_request_set_SubjectPublicKeyInfo + hx509_request_add_email + hx509_request_reject_eku + hx509_request_reject_san + hx509_request_set_cA + hx509_request_set_eE + hx509_request_set_name + hx509_request_set_ku + hx509_request_san_authorized_p + hx509_request_to_pkcs10 + _hx509_unmap_file_os + _hx509_write_file + hx509_bitstring_print + _hx509_ca_issue_certificate + hx509_ca_sign + hx509_ca_sign_self + hx509_ca_tbs_add_crl_dp_uri + hx509_ca_tbs_add_eku + hx509_ca_tbs_add_ku + hx509_ca_tbs_add_pol + hx509_ca_tbs_add_pol_mapping + hx509_ca_tbs_add_san + hx509_ca_tbs_add_san_dnssrv + hx509_ca_tbs_add_san_hardwareModuleName + hx509_ca_tbs_add_san_hardwareModuleName_string + hx509_ca_tbs_add_san_hostname + hx509_ca_tbs_add_san_jid + hx509_ca_tbs_add_san_ms_upn + hx509_ca_tbs_add_san_otherName + hx509_ca_tbs_add_san_permanentIdentifier + hx509_ca_tbs_add_san_permanentIdentifier_string + hx509_ca_tbs_add_san_pkinit + hx509_ca_tbs_add_san_rfc822name + hx509_ca_tbs_free + hx509_ca_tbs_get_name + hx509_ca_tbs_init + hx509_ca_tbs_set_ca + hx509_ca_tbs_set_domaincontroller + hx509_ca_tbs_set_from_csr + hx509_ca_tbs_set_notAfter + hx509_ca_tbs_set_notAfter_lifetime + hx509_ca_tbs_set_notBefore + hx509_ca_tbs_set_pkinit_max_life + hx509_ca_tbs_set_proxy + hx509_ca_tbs_set_serialnumber + hx509_ca_tbs_set_signature_algorithm + hx509_ca_tbs_set_spki + hx509_ca_tbs_set_subject + hx509_ca_tbs_set_template + hx509_ca_tbs_subject_expand + hx509_ca_tbs_template_units +; hx509_cert +; hx509_cert_attribute + hx509_cert_binary + hx509_cert_check_eku + hx509_cert_cmp + hx509_cert_find_subjectAltName_otherName + hx509_cert_free + hx509_cert_get_SPKI + hx509_cert_get_SPKI_AlgorithmIdentifier + hx509_cert_get_attribute + hx509_cert_get_base_subject + hx509_cert_get_friendly_name + hx509_cert_get_issuer + hx509_cert_get_notAfter + hx509_cert_get_notBefore + hx509_cert_get_pkinit_max_life + hx509_cert_get_serialnumber + hx509_cert_get_subject + hx509_cert_have_private_key + hx509_cert_have_private_key_only + hx509_cert_init + hx509_cert_init_data + hx509_cert_init_private_key + hx509_cert_is_ca + hx509_cert_is_root + hx509_cert_is_self_signed + hx509_cert_keyusage_print + hx509_cert_ref + hx509_cert_set_friendly_name + hx509_certs_add + hx509_certs_append + hx509_certs_destroy + hx509_certs_end_seq + hx509_certs_ref + hx509_certs_filter + hx509_certs_find + hx509_certs_free + hx509_certs_info + hx509_certs_init +; hx509_certs_iter + hx509_certs_iter_f + hx509_certs_merge + hx509_certs_next_cert + hx509_certs_start_seq + hx509_certs_store + hx509_ci_print_names + hx509_clear_error_string + hx509_cms_create_signed + hx509_cms_create_signed_1 + hx509_cms_decrypt_encrypted + hx509_cms_envelope_1 + hx509_cms_unenvelope + hx509_cms_unwrap_ContentInfo + hx509_cms_verify_signed + hx509_cms_verify_signed_ext + hx509_cms_wrap_ContentInfo + hx509_context_free + hx509_context_init + hx509_context_set_missing_revoke + hx509_crl_add_revoked_certs + hx509_crl_alloc + hx509_crl_free + hx509_crl_lifetime + hx509_crl_sign + hx509_crypto_aes128_cbc + hx509_crypto_aes256_cbc + hx509_crypto_allow_weak + hx509_crypto_available + hx509_crypto_decrypt + hx509_crypto_des_rsdi_ede3_cbc + hx509_crypto_destroy + hx509_crypto_encrypt + hx509_crypto_enctype_by_name + hx509_crypto_free_algs + hx509_crypto_get_params + hx509_crypto_init + hx509_crypto_provider + hx509_crypto_select + hx509_crypto_set_key_data + hx509_crypto_set_key_name + hx509_crypto_set_padding + hx509_crypto_set_params + hx509_crypto_set_random_key + hx509_empty_name + hx509_env_add + hx509_env_add_binding + hx509_env_find + hx509_env_find_binding + hx509_env_free +; hx509_env_init + hx509_env_lfind + hx509_err + hx509_free_error_string + hx509_free_octet_string_list + hx509_general_name_unparse + hx509_get_error_string + hx509_get_instance + hx509_get_one_cert + hx509_lock_add_cert + hx509_lock_add_certs + hx509_lock_add_password + hx509_lock_command_string + hx509_lock_free + hx509_lock_init + hx509_lock_prompt + hx509_lock_reset_certs + hx509_lock_reset_passwords + hx509_lock_reset_promper + hx509_lock_set_prompter + hx509_name_binary + hx509_name_cmp + hx509_name_copy + hx509_name_expand + hx509_name_free + hx509_name_is_null_p + hx509_name_normalize + hx509_name_to_Name + hx509_name_to_string + hx509_ocsp_request + hx509_ocsp_verify + hx509_oid_print + hx509_oid_sprint + hx509_parse_name + hx509_parse_private_key + hx509_peer_info_add_cms_alg + hx509_peer_info_alloc + hx509_peer_info_free + hx509_peer_info_set_cert + hx509_peer_info_set_cms_algs + hx509_pem_add_header + hx509_pem_find_header + hx509_pem_free_header + hx509_pem_read + hx509_pem_write + hx509_print_stdout + hx509_print_cert + hx509_prompt_hidden + hx509_query_alloc + hx509_query_free + hx509_query_match_cmp_func + hx509_query_match_eku + hx509_query_match_expr + hx509_query_match_friendly_name + hx509_query_match_issuer_serial + hx509_query_match_option + hx509_query_statistic_file + hx509_query_unparse_stats + hx509_revoke_add_crl + hx509_revoke_add_ocsp + hx509_revoke_free + hx509_revoke_init + hx509_revoke_ocsp_print + hx509_revoke_print + hx509_revoke_verify + hx509_set_error_string + hx509_set_error_stringv + hx509_signature_md5 + hx509_signature_rsa + hx509_signature_rsa_with_md5 + hx509_signature_rsa_with_sha1 + hx509_signature_rsa_with_sha256 + hx509_signature_rsa_with_sha384 + hx509_signature_rsa_with_sha512 + hx509_signature_sha1 + hx509_signature_sha256 + hx509_signature_sha384 + hx509_signature_sha512 + hx509_unparse_der_name + hx509_validate_cert + hx509_validate_ctx_add_flags + hx509_validate_ctx_free + hx509_validate_ctx_init + hx509_validate_ctx_set_print + hx509_verify_attach_anchors + hx509_verify_attach_revoke + hx509_verify_ctx_f_allow_default_trustanchors + hx509_verify_destroy_ctx + hx509_verify_hostname + hx509_verify_init_ctx + hx509_verify_path + hx509_verify_set_max_depth + hx509_verify_set_proxy_certificate + hx509_verify_set_strict_rfc3280_verification + hx509_verify_set_time + hx509_verify_signature + hx509_xfree + initialize_hx_error_table_r + +; pkcs11 symbols + C_GetFunctionList diff --git a/third_party/heimdal/lib/hx509/lock.c b/third_party/heimdal/lib/hx509/lock.c new file mode 100644 index 0000000..7f767d2 --- /dev/null +++ b/third_party/heimdal/lib/hx509/lock.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_lock Locking and unlocking certificates and encrypted data. + * + * See the library functions here: @ref hx509_lock + */ + +struct hx509_lock_data { + struct _hx509_password password; + hx509_certs certs; + hx509_prompter_fct prompt; + void *prompt_data; +}; + +static struct hx509_lock_data empty_lock_data = { + { 0, NULL }, + NULL, + NULL, + NULL +}; + +hx509_lock _hx509_empty_lock = &empty_lock_data; + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_init(hx509_context context, hx509_lock *lock) +{ + hx509_lock l; + int ret; + + *lock = NULL; + + l = calloc(1, sizeof(*l)); + if (l == NULL) + return ENOMEM; + + ret = hx509_certs_init(context, + "MEMORY:locks-internal", + 0, + NULL, + &l->certs); + if (ret) { + free(l); + return ret; + } + + *lock = l; + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_add_password(hx509_lock lock, const char *password) +{ + void *d; + char *s; + + s = strdup(password); + if (s == NULL) + return ENOMEM; + + d = realloc(lock->password.val, + (lock->password.len + 1) * sizeof(lock->password.val[0])); + if (d == NULL) { + free(s); + return ENOMEM; + } + lock->password.val = d; + lock->password.val[lock->password.len] = s; + lock->password.len++; + + return 0; +} + +HX509_LIB_FUNCTION const struct _hx509_password * HX509_LIB_CALL +_hx509_lock_get_passwords(hx509_lock lock) +{ + return &lock->password; +} + +HX509_LIB_FUNCTION hx509_certs HX509_LIB_CALL +_hx509_lock_unlock_certs(hx509_lock lock) +{ + return lock->certs; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_lock_reset_passwords(hx509_lock lock) +{ + size_t i; + for (i = 0; i < lock->password.len; i++) + free(lock->password.val[i]); + free(lock->password.val); + lock->password.val = NULL; + lock->password.len = 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_add_cert(hx509_context context, hx509_lock lock, hx509_cert cert) +{ + return hx509_certs_add(context, lock->certs, cert); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_add_certs(hx509_context context, hx509_lock lock, hx509_certs certs) +{ + return hx509_certs_merge(context, lock->certs, certs); +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_lock_reset_certs(hx509_context context, hx509_lock lock) +{ + hx509_certs certs = lock->certs; + int ret; + + ret = hx509_certs_init(context, + "MEMORY:locks-internal", + 0, + NULL, + &lock->certs); + if (ret == 0) + hx509_certs_free(&certs); + else + lock->certs = certs; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_lock_find_cert(hx509_lock lock, const hx509_query *q, hx509_cert *c) +{ + *c = NULL; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_set_prompter(hx509_lock lock, hx509_prompter_fct prompt, void *data) +{ + lock->prompt = prompt; + lock->prompt_data = data; + return 0; +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_lock_reset_promper(hx509_lock lock) +{ + lock->prompt = NULL; + lock->prompt_data = NULL; +} + +static int +default_prompter(void *data, const hx509_prompt *prompter) +{ + if (hx509_prompt_hidden(prompter->type)) { + if(UI_UTIL_read_pw_string(prompter->reply.data, + prompter->reply.length, + prompter->prompt, + 0)) + return 1; + } else { + char *s = prompter->reply.data; + + fputs (prompter->prompt, stdout); + fflush (stdout); + if(fgets(prompter->reply.data, + prompter->reply.length, + stdin) == NULL) + return 1; + s[strcspn(s, "\n")] = '\0'; + } + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_prompt(hx509_lock lock, hx509_prompt *prompt) +{ + if (lock->prompt == NULL) + return HX509_CRYPTO_NO_PROMPTER; + return (*lock->prompt)(lock->prompt_data, prompt); +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_lock_free(hx509_lock lock) +{ + if (lock) { + hx509_certs_free(&lock->certs); + hx509_lock_reset_passwords(lock); + memset(lock, 0, sizeof(*lock)); + free(lock); + } +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_prompt_hidden(hx509_prompt_type type) +{ + /* default to hidden if unknown */ + + switch (type) { + case HX509_PROMPT_TYPE_QUESTION: + case HX509_PROMPT_TYPE_INFO: + return 0; + default: + return 1; + } +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_lock_command_string(hx509_lock lock, const char *string) +{ + if (strncasecmp(string, "PASS:", 5) == 0) { + hx509_lock_add_password(lock, string + 5); + } else if (strcasecmp(string, "PROMPT") == 0) { + hx509_lock_set_prompter(lock, default_prompter, NULL); + } else + return HX509_UNKNOWN_LOCK_COMMAND; + return 0; +} diff --git a/third_party/heimdal/lib/hx509/name.c b/third_party/heimdal/lib/hx509/name.c new file mode 100644 index 0000000..7d67716 --- /dev/null +++ b/third_party/heimdal/lib/hx509/name.c @@ -0,0 +1,1529 @@ +/* + * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include +#include "char_map.h" + +/** + * @page page_name PKIX/X.509 Names + * + * There are several names in PKIX/X.509, GeneralName and Name. + * + * A Name consists of an ordered list of Relative Distinguished Names + * (RDN). Each RDN consists of an unordered list of typed strings. The + * types are defined by OID and have long and short description. For + * example id-at-commonName (2.5.4.3) have the long name CommonName + * and short name CN. The string itself can be of several encoding, + * UTF8, UTF16, Teltex string, etc. The type limit what encoding + * should be used. + * + * GeneralName is a broader nametype that can contains al kind of + * stuff like Name, IP addresses, partial Name, etc. + * + * Name is mapped into a hx509_name object. + * + * Parse and string name into a hx509_name object with hx509_parse_name(), + * make it back into string representation with hx509_name_to_string(). + * + * Name string are defined rfc2253, rfc1779 and X.501. + * + * See the library functions here: @ref hx509_name + */ + +static const struct { + const char *n; + const heim_oid *o; + int type_choice; /* Preference for DirectoryString choice; 0 -> no pref */ + wind_profile_flags flags; + /* + * RFC52380 imposes maximum lengths for some strings in Names. These are + * ASN.1 size limits. We should implement these in our copy of the PKIX + * ASN.1 module. For now we treat them as maximum byte counts rather than + * maximum character counts, and we encode and enforce them here. + * + * 0 -> no max + * + * Some of these attributes aren't of type DirectoryString, so our + * type_choice isn't really correct. We're not really set up for + * attributes whose types aren't DirectoryString or one of its choice arms' + * type, much less are we set up for non-string attribute value types. + */ + size_t max_bytes; +} no[] = { + { "C", &asn1_oid_id_at_countryName, + choice_DirectoryString_printableString, 0, 2 }, + { "CN", &asn1_oid_id_at_commonName, 0, 0, ub_common_name }, + { "DC", &asn1_oid_id_domainComponent, choice_DirectoryString_ia5String, + 0, 63 }, /* DNS label */ + { "L", &asn1_oid_id_at_localityName, 0, 0, ub_locality_name }, + { "O", &asn1_oid_id_at_organizationName, 0, 0, ub_organization_name }, + { "OU", &asn1_oid_id_at_organizationalUnitName, 0, 0, + ub_organizational_unit_name }, + { "S", &asn1_oid_id_at_stateOrProvinceName, 0, 0, ub_state_name }, + { "STREET", &asn1_oid_id_at_streetAddress, 0, 0, 0 }, /* ENOTSUP */ + { "UID", &asn1_oid_id_Userid, 0, 0, ub_numeric_user_id_length }, + { "emailAddress", &asn1_oid_id_pkcs9_emailAddress, + choice_DirectoryString_ia5String, 0, ub_emailaddress_length }, + /* This is for DevID certificates and maybe others */ + { "serialNumber", &asn1_oid_id_at_serialNumber, 0, 0, ub_serial_number }, + /* These are for TPM 2.0 Endorsement Key Certificates (EKCerts) */ + { "TPMManufacturer", &asn1_oid_tcg_at_tpmManufacturer, 0, 0, + ub_emailaddress_length }, + { "TPMModel", &asn1_oid_tcg_at_tpmModel, 0, 0, ub_emailaddress_length }, + { "TPMVersion", &asn1_oid_tcg_at_tpmVersion, 0, 0, ub_emailaddress_length }, +}; + +static char * +quote_string(const char *f, size_t len, int flags, size_t *rlen) +{ + size_t i, j, tolen; + const unsigned char *from = (const unsigned char *)f; + unsigned char *to; + + tolen = len * 3 + 1; + to = malloc(tolen); + if (to == NULL) + return NULL; + + for (i = 0, j = 0; i < len; i++) { + unsigned char map = char_map[from[i]] & flags; + if (i == 0 && (map & Q_RFC2253_QUOTE_FIRST)) { + to[j++] = '\\'; + to[j++] = from[i]; + } else if ((i + 1) == len && (map & Q_RFC2253_QUOTE_LAST)) { + + to[j++] = '\\'; + to[j++] = from[i]; + } else if (map & Q_RFC2253_QUOTE) { + to[j++] = '\\'; + to[j++] = from[i]; + } else if (map & Q_RFC2253_HEX) { + int l = snprintf((char *)&to[j], tolen - j - 1, + "#%02x", (unsigned char)from[i]); + j += l; + } else { + to[j++] = from[i]; + } + } + to[j] = '\0'; + assert(j < tolen); + *rlen = j; + return (char *)to; +} + + +static int +append_string(char **str, size_t *total_len, const char *ss, + size_t len, int quote) +{ + char *s, *qs; + + if (quote) + qs = quote_string(ss, len, Q_RFC2253, &len); + else + qs = rk_UNCONST(ss); + + s = realloc(*str, len + *total_len + 1); + if (s == NULL) + _hx509_abort("allocation failure"); /* XXX */ + memcpy(s + *total_len, qs, len); + if (qs != ss) + free(qs); + s[*total_len + len] = '\0'; + *str = s; + *total_len += len; + return 0; +} + +static char * +oidtostring(const heim_oid *type, int *type_choice) +{ + char *s; + size_t i; + + if (type_choice) + *type_choice = choice_DirectoryString_utf8String; + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (der_heim_oid_cmp(no[i].o, type) == 0) { + if (type_choice && no[i].type_choice) + *type_choice = no[i].type_choice; + return strdup(no[i].n); + } + } + if (der_print_heim_oid(type, '.', &s) != 0) + return NULL; + return s; +} + +static size_t +oidtomaxlen(const heim_oid *type) +{ + size_t i; + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (der_heim_oid_cmp(no[i].o, type) == 0) + return no[i].max_bytes; + } + return 0; +} + +static int +stringtooid(const char *name, size_t len, heim_oid *oid) +{ + int ret; + size_t i; + char *s; + + memset(oid, 0, sizeof(*oid)); + + for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { + if (strncasecmp(no[i].n, name, len) == 0) + return der_copy_oid(no[i].o, oid); + } + s = malloc(len + 1); + if (s == NULL) + return ENOMEM; + memcpy(s, name, len); + s[len] = '\0'; + ret = der_parse_heim_oid(s, ".", oid); + free(s); + return ret; +} + +/** + * Convert the hx509 name object into a printable string. + * The resulting string should be freed with free(). + * + * @param name name to print + * @param str the string to return + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_to_string(const hx509_name name, char **str) +{ + return _hx509_Name_to_string(&name->der_name, str); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_Name_to_string(const Name *n, char **str) +{ + size_t total_len = 0; + size_t i, j, m; + int ret; + + *str = strdup(""); + if (*str == NULL) + return ENOMEM; + + for (m = n->u.rdnSequence.len; m > 0; m--) { + size_t len; + i = m - 1; + + for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; + char *oidname; + char *ss; + + oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type, NULL); + + switch(ds->element) { + case choice_DirectoryString_ia5String: + ss = ds->u.ia5String.data; + len = ds->u.ia5String.length; + break; + case choice_DirectoryString_printableString: + ss = ds->u.printableString.data; + len = ds->u.printableString.length; + break; + case choice_DirectoryString_utf8String: + ss = ds->u.utf8String; + len = strlen(ss); + break; + case choice_DirectoryString_bmpString: { + const uint16_t *bmp = ds->u.bmpString.data; + size_t bmplen = ds->u.bmpString.length; + size_t k; + + ret = wind_ucs2utf8_length(bmp, bmplen, &k); + if (ret) { + free(oidname); + free(*str); + *str = NULL; + return ret; + } + + ss = malloc(k + 1); + if (ss == NULL) + _hx509_abort("allocation failure"); /* XXX */ + ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); + if (ret) { + free(oidname); + free(ss); + free(*str); + *str = NULL; + return ret; + } + ss[k] = '\0'; + len = k; + break; + } + case choice_DirectoryString_teletexString: + ss = ds->u.teletexString; + len = strlen(ss); + break; + case choice_DirectoryString_universalString: { + const uint32_t *uni = ds->u.universalString.data; + size_t unilen = ds->u.universalString.length; + size_t k; + + ret = wind_ucs4utf8_length(uni, unilen, &k); + if (ret) { + free(oidname); + free(*str); + *str = NULL; + return ret; + } + + ss = malloc(k + 1); + if (ss == NULL) + _hx509_abort("allocation failure"); /* XXX */ + ret = wind_ucs4utf8(uni, unilen, ss, NULL); + if (ret) { + free(ss); + free(oidname); + free(*str); + *str = NULL; + return ret; + } + ss[k] = '\0'; + len = k; + break; + } + default: + _hx509_abort("unknown directory type: %d", ds->element); + exit(1); + } + append_string(str, &total_len, oidname, strlen(oidname), 0); + free(oidname); + append_string(str, &total_len, "=", 1, 0); + append_string(str, &total_len, ss, len, 1); + if (ds->element == choice_DirectoryString_bmpString || + ds->element == choice_DirectoryString_universalString) + { + free(ss); + } + if (j + 1 < n->u.rdnSequence.val[i].len) + append_string(str, &total_len, "+", 1, 0); + } + + if (i > 0) + append_string(str, &total_len, ",", 1, 0); + } + return 0; +} + +#define COPYCHARARRAY(_ds,_el,_l,_n) \ + (_l) = strlen(_ds->u._el); \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ + (_n)[i] = _ds->u._el[i] + + +#define COPYVALARRAY(_ds,_el,_l,_n) \ + (_l) = _ds->u._el.length; \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ + (_n)[i] = _ds->u._el.data[i] + +#define COPYVOIDARRAY(_ds,_el,_l,_n) \ + (_l) = _ds->u._el.length; \ + (_n) = malloc((_l + 1) * sizeof((_n)[0])); \ + if ((_n) == NULL) \ + return ENOMEM; \ + for (i = 0; i < (_l); i++) \ + (_n)[i] = ((unsigned char *)_ds->u._el.data)[i] + + + +static int +dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) +{ + wind_profile_flags flags; + size_t i, len; + int ret = 0; + uint32_t *name; + + *rname = NULL; + *rlen = 0; + + switch(ds->element) { + case choice_DirectoryString_ia5String: + flags = WIND_PROFILE_LDAP; + COPYVOIDARRAY(ds, ia5String, len, name); + break; + case choice_DirectoryString_printableString: + flags = WIND_PROFILE_LDAP; + flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE; + COPYVOIDARRAY(ds, printableString, len, name); + break; + case choice_DirectoryString_teletexString: + flags = WIND_PROFILE_LDAP_CASE; + COPYCHARARRAY(ds, teletexString, len, name); + break; + case choice_DirectoryString_bmpString: + flags = WIND_PROFILE_LDAP; + COPYVALARRAY(ds, bmpString, len, name); + break; + case choice_DirectoryString_universalString: + flags = WIND_PROFILE_LDAP; + COPYVALARRAY(ds, universalString, len, name); + break; + case choice_DirectoryString_utf8String: + flags = WIND_PROFILE_LDAP; + ret = wind_utf8ucs4_length(ds->u.utf8String, &len); + if (ret) + return ret; + name = malloc((len + 1) * sizeof(name[0])); + if (name == NULL) + return ENOMEM; + ret = wind_utf8ucs4(ds->u.utf8String, name, &len); + if (ret) { + free(name); + return ret; + } + break; + default: + _hx509_abort("unknown directory type: %d", ds->element); + } + + *rlen = len; + /* try a couple of times to get the length right, XXX gross */ + for (i = 0; i < 4; i++) { + *rlen = *rlen * 2; + if ((*rname = malloc((rlen[0] + 1) * sizeof((*rname)[0]))) == NULL) { + ret = ENOMEM; + break; + } + + ret = wind_stringprep(name, len, *rname, rlen, flags); + if (ret == WIND_ERR_OVERRUN) { + free(*rname); + *rname = NULL; + continue; + } else + break; + } + free(name); + if (ret) { + if (*rname) + free(*rname); + *rname = NULL; + *rlen = 0; + return ret; + } + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_name_ds_cmp(const DirectoryString *ds1, + const DirectoryString *ds2, + int *diff) +{ + uint32_t *ds1lp, *ds2lp; + size_t ds1len, ds2len, i; + int ret; + + ret = dsstringprep(ds1, &ds1lp, &ds1len); + if (ret) + return ret; + ret = dsstringprep(ds2, &ds2lp, &ds2len); + if (ret) { + free(ds1lp); + return ret; + } + + if (ds1len != ds2len) + *diff = ds1len - ds2len; + else { + for (i = 0; i < ds1len; i++) { + *diff = ds1lp[i] - ds2lp[i]; + if (*diff) + break; + } + } + free(ds1lp); + free(ds2lp); + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_name_cmp(const Name *n1, const Name *n2, int *c) +{ + int ret; + size_t i, j; + + *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; + if (*c) + return 0; + + for (i = 0 ; i < n1->u.rdnSequence.len; i++) { + *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; + if (*c) + return 0; + + for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { + *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, + &n1->u.rdnSequence.val[i].val[j].type); + if (*c) + return 0; + + ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, + &n2->u.rdnSequence.val[i].val[j].value, + c); + if (ret) + return ret; + if (*c) + return 0; + } + } + *c = 0; + return 0; +} + +/** + * Compare to hx509 name object, useful for sorting. + * + * @param n1 a hx509 name object. + * @param n2 a hx509 name object. + * + * @return 0 the objects are the same, returns > 0 is n2 is "larger" + * then n2, < 0 if n1 is "smaller" then n2. + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_cmp(hx509_name n1, hx509_name n2) +{ + int ret, diff; + ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff); + if (ret) + return ret; + return diff; +} + + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_name_from_Name(const Name *n, hx509_name *name) +{ + int ret; + *name = calloc(1, sizeof(**name)); + if (*name == NULL) + return ENOMEM; + ret = copy_Name(n, &(*name)->der_name); + if (ret) { + free(*name); + *name = NULL; + } + return ret; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_name_modify(hx509_context context, + Name *name, + int append, + const heim_oid *oid, + const char *str) +{ + RelativeDistinguishedName rdn; + size_t max_len = oidtomaxlen(oid); + char *s = NULL; + int type_choice = choice_DirectoryString_printableString; + int ret; + + /* + * Check string length upper bounds. + * + * Because we don't have these bounds in our copy of the PKIX ASN.1 module, + * and because we might like to catch these early anyways, we enforce them + * here. + */ + if (max_len && strlen(str) > max_len) { + char *a = oidtostring(oid, &type_choice); + + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, "RDN attribute %s value too " + "long (max %llu): %s", a ? a : "", + max_len, str); + free(a); + return ret; + } + + memset(&rdn, 0, sizeof(rdn)); + if ((rdn.val = malloc(sizeof(rdn.val[0]))) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); + return ENOMEM; + } + rdn.len = 1; + + /* + * How best to pick a type for this attribute value? + * + * Options: + * + * 1) the API deals only in UTF-8, let the callers convert to/from UTF-8 + * and whatever the current locale wants + * + * 2) use the best type for the codeset of the current locale. + * + * We choose (1). + * + * However, for some cases we really should prefer other types when the + * input string is all printable ASCII. + */ + rdn.val[0].value.element = type_choice; + if ((s = strdup(str)) == NULL || + der_copy_oid(oid, &rdn.val[0].type)) { + free(rdn.val); + free(s); + return hx509_enomem(context); + } + switch (rdn.val[0].value.element) { + /* C strings: */ + case choice_DirectoryString_utf8String: + rdn.val[0].value.u.utf8String = s; + break; + case choice_DirectoryString_teletexString: + rdn.val[0].value.u.teletexString = s; + break; + + /* Length and pointer */ + case choice_DirectoryString_ia5String: + rdn.val[0].value.u.ia5String.data = s; + rdn.val[0].value.u.ia5String.length = strlen(s); + break; + case choice_DirectoryString_printableString: + rdn.val[0].value.u.printableString.data = s; + rdn.val[0].value.u.printableString.length = strlen(s); + break; + case choice_DirectoryString_universalString: + free(s); + free(rdn.val); + hx509_set_error_string(context, 0, ENOTSUP, "UniversalString not supported"); + return ENOTSUP; + case choice_DirectoryString_bmpString: + free(s); + free(rdn.val); + hx509_set_error_string(context, 0, ENOTSUP, "BMPString not supported"); + return ENOTSUP; + default: + free(s); + free(rdn.val); + hx509_set_error_string(context, 0, ENOTSUP, + "Internal error; unknown DirectoryString choice"); + return ENOTSUP; + } + + /* Append RDN. If the caller wanted to prepend instead, we'll rotate. */ + ret = add_RDNSequence(&name->u.rdnSequence, &rdn); + free_RelativeDistinguishedName(&rdn); + + if (ret || append || name->u.rdnSequence.len < 2) + return ret; + + /* Rotate */ + rdn = name->u.rdnSequence.val[name->u.rdnSequence.len - 1]; + memmove(&name->u.rdnSequence.val[1], + &name->u.rdnSequence.val[0], + (name->u.rdnSequence.len - 1) * + sizeof(name->u.rdnSequence.val[0])); + name->u.rdnSequence.val[0] = rdn; + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_empty_name(hx509_context context, hx509_name *name) +{ + if ((*name = calloc(1, sizeof(**name))) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + (*name)->der_name.element = choice_Name_rdnSequence; + (*name)->der_name.u.rdnSequence.val = 0; + (*name)->der_name.u.rdnSequence.len = 0; + return 0; +} + +/** + * Parse a string into a hx509 name object. + * + * @param context A hx509 context. + * @param str a string to parse. + * @param name the resulting object, NULL in case of error. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_parse_name(hx509_context context, const char *str, hx509_name *name) +{ + const char *p, *q; + size_t len; + hx509_name n; + int ret; + + *name = NULL; + + n = calloc(1, sizeof(*n)); + if (n == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + n->der_name.element = choice_Name_rdnSequence; + + p = str; + + while (p != NULL && *p != '\0') { + heim_oid oid; + int last; + + q = strchr(p, ','); + if (q) { + len = (q - p); + last = 1; + } else { + len = strlen(p); + last = 0; + } + + q = strchr(p, '='); + if (q == NULL) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, "missing = in %s", p); + goto out; + } + if (q == p) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "missing name before = in %s", p); + goto out; + } + + if ((size_t)(q - p) > len) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, " = after , in %s", p); + goto out; + } + + ret = stringtooid(p, q - p, &oid); + if (ret) { + ret = HX509_PARSING_NAME_FAILED; + hx509_set_error_string(context, 0, ret, + "unknown type: %.*s", (int)(q - p), p); + goto out; + } + + { + size_t pstr_len = len - (q - p) - 1; + const char *pstr = p + (q - p) + 1; + char *r; + + r = malloc(pstr_len + 1); + if (r == NULL) { + der_free_oid(&oid); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + memcpy(r, pstr, pstr_len); + r[pstr_len] = '\0'; + + ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r); + free(r); + der_free_oid(&oid); + if(ret) + goto out; + } + p += len + last; + } + + *name = n; + + return 0; +out: + hx509_name_free(&n); + return HX509_NAME_MALFORMED; +} + +/** + * Copy a hx509 name object. + * + * @param context A hx509 cotext. + * @param from the name to copy from + * @param to the name to copy to + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) +{ + int ret; + + *to = calloc(1, sizeof(**to)); + if (*to == NULL) + return ENOMEM; + ret = copy_Name(&from->der_name, &(*to)->der_name); + if (ret) { + free(*to); + *to = NULL; + return ENOMEM; + } + return 0; +} + +/** + * Convert a hx509_name into a Name. + * + * @param from the name to copy from + * @param to the name to copy to + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_to_Name(const hx509_name from, Name *to) +{ + return copy_Name(&from->der_name, to); +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_normalize(hx509_context context, hx509_name name) +{ + return 0; +} + +/** + * Expands variables in the name using env. Variables are on the form + * ${name}. Useful when dealing with certificate templates. + * + * @param context A hx509 cotext. + * @param name the name to expand. + * @param env environment variable to expand. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_expand(hx509_context context, + hx509_name name, + hx509_env env) +{ + Name *n = &name->der_name; + size_t i, j; + int bounds_check = 1; + + if (env == NULL) + return 0; + + if (n->element != choice_Name_rdnSequence) { + hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type"); + return EINVAL; + } + + for (i = 0 ; i < n->u.rdnSequence.len; i++) { + for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + /** Only UTF8String rdnSequence names are allowed */ + /* + THIS SHOULD REALLY BE: + COMP = n->u.rdnSequence.val[i].val[j]; + normalize COMP to utf8 + check if there are variables + expand variables + convert back to orignal format, store in COMP + free normalized utf8 string + */ + DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; + heim_oid *type = &n->u.rdnSequence.val[i].val[j].type; + const char *sval = NULL; + char *p, *p2; + char *s = NULL; + struct rk_strpool *strpool = NULL; + + switch (ds->element) { + case choice_DirectoryString_utf8String: + sval = ds->u.utf8String; + break; + case choice_DirectoryString_teletexString: + sval = ds->u.utf8String; + break; + case choice_DirectoryString_ia5String: + s = strndup(ds->u.ia5String.data, + ds->u.ia5String.length); + break; + case choice_DirectoryString_printableString: + s = strndup(ds->u.printableString.data, + ds->u.printableString.length); + break; + case choice_DirectoryString_universalString: + hx509_set_error_string(context, 0, ENOTSUP, "UniversalString not supported"); + return ENOTSUP; + case choice_DirectoryString_bmpString: + hx509_set_error_string(context, 0, ENOTSUP, "BMPString not supported"); + return ENOTSUP; + } + if (sval == NULL && s == NULL) + return hx509_enomem(context); + if (s) + sval = s; + + p = strstr(sval, "${"); + if (p) { + strpool = rk_strpoolprintf(strpool, "%.*s", (int)(p - sval), sval); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + free(s); + return ENOMEM; + } + } + + while (p != NULL) { + /* expand variables */ + const char *value; + p2 = strchr(p, '}'); + if (p2 == NULL) { + hx509_set_error_string(context, 0, EINVAL, "missing }"); + rk_strpoolfree(strpool); + free(s); + return EINVAL; + } + p += 2; + value = hx509_env_lfind(context, env, p, p2 - p); + if (value == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "variable %.*s missing", + (int)(p2 - p), p); + rk_strpoolfree(strpool); + free(s); + return EINVAL; + } + strpool = rk_strpoolprintf(strpool, "%s", value); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + free(s); + return ENOMEM; + } + p2++; + + p = strstr(p2, "${"); + if (p) + strpool = rk_strpoolprintf(strpool, "%.*s", + (int)(p - p2), p2); + else + strpool = rk_strpoolprintf(strpool, "%s", p2); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + free(s); + return ENOMEM; + } + } + + free(s); + s = NULL; + + if (strpool) { + size_t max_bytes; + + if ((s = rk_strpoolcollect(strpool)) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + /* Check upper bounds! */ + if ((max_bytes = oidtomaxlen(type)) && strlen(s) > max_bytes) + bounds_check = 0; + + switch (ds->element) { + /* C strings: */ + case choice_DirectoryString_utf8String: + free(ds->u.utf8String); + ds->u.utf8String = s; + break; + case choice_DirectoryString_teletexString: + free(ds->u.teletexString); + ds->u.teletexString = s; + break; + + /* Length and pointer */ + case choice_DirectoryString_ia5String: + free(ds->u.ia5String.data); + ds->u.ia5String.data = s; + ds->u.ia5String.length = strlen(s); + break; + case choice_DirectoryString_printableString: + free(ds->u.printableString.data); + ds->u.printableString.data = s; + ds->u.printableString.length = strlen(s); + break; + default: + break; /* Handled above */ + } + } + } + } + + if (!bounds_check) { + hx509_set_error_string(context, 0, HX509_PARSING_NAME_FAILED, + "some expanded RDNs are too long"); + return HX509_PARSING_NAME_FAILED; + } + return 0; +} + +/** + * Free a hx509 name object, upond return *name will be NULL. + * + * @param name a hx509 name object to be freed. + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_name_free(hx509_name *name) +{ + free_Name(&(*name)->der_name); + memset(*name, 0, sizeof(**name)); + free(*name); + *name = NULL; +} + +/** + * Convert a DER encoded name info a string. + * + * @param data data to a DER/BER encoded name + * @param length length of data + * @param str the resulting string, is NULL on failure. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_unparse_der_name(const void *data, size_t length, char **str) +{ + Name name; + int ret; + + *str = NULL; + + ret = decode_Name(data, length, &name, NULL); + if (ret) + return ret; + ret = _hx509_Name_to_string(&name, str); + free_Name(&name); + return ret; +} + +/** + * Convert a hx509_name object to DER encoded name. + * + * @param name name to concert + * @param os data to a DER encoded name, free the resulting octet + * string with hx509_xfree(os->data). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_binary(const hx509_name name, heim_octet_string *os) +{ + size_t size; + int ret; + + ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret); + if (ret) + return ret; + if (os->length != size) + _hx509_abort("internal ASN.1 encoder error"); + + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_unparse_Name(const Name *aname, char **str) +{ + hx509_name name; + int ret; + + ret = _hx509_name_from_Name(aname, &name); + if (ret) + return ret; + + ret = hx509_name_to_string(name, str); + hx509_name_free(&name); + return ret; +} + +/** + * Check if a name is empty. + * + * @param name the name to check if its empty/null. + * + * @return non zero if the name is empty/null. + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_name_is_null_p(const hx509_name name) +{ + return name->der_name.element == choice_Name_rdnSequence && + name->der_name.u.rdnSequence.len == 0; +} + +int +_hx509_unparse_PermanentIdentifier(hx509_context context, + struct rk_strpool **strpool, + heim_any *value) +{ + PermanentIdentifier pi; + size_t len; + const char *pid = ""; + char *s = NULL; + int ret; + + ret = decode_PermanentIdentifier(value->data, value->length, &pi, &len); + if (ret == 0 && pi.assigner && + der_print_heim_oid(pi.assigner, '.', &s) != 0) + ret = hx509_enomem(context); + if (pi.identifierValue && *pi.identifierValue) + pid = *pi.identifierValue; + if (ret == 0 && + (*strpool = rk_strpoolprintf(*strpool, "%s:%s", s ? s : "", pid)) == NULL) + ret = hx509_enomem(context); + free_PermanentIdentifier(&pi); + free(s); + if (ret) { + rk_strpoolfree(*strpool); + *strpool = rk_strpoolprintf(NULL, + "data, value->length, &hm, &len); + if (ret == 0 && hm.hwSerialNum.length > 256) + hm.hwSerialNum.length = 256; + if (ret == 0) + ret = der_print_heim_oid(&hm.hwType, '.', &s); + if (ret == 0) { + *strpool = rk_strpoolprintf(*strpool, "%s:%.*s%s", s, + (int)hm.hwSerialNum.length, + (char *)hm.hwSerialNum.data, + value->length == len ? "" : ", "); + if (*strpool == NULL) + ret = hx509_enomem(context); + } + free_HardwareModuleName(&hm); + free(s); + if (ret) { + rk_strpoolfree(*strpool); + *strpool = rk_strpoolprintf(NULL, + "data, value->length, &kn, &len); + if (ret == 0 && + (*strpool = _hx509_unparse_kerberos_name(*strpool, &kn)) == NULL) + ret = hx509_enomem(context); + free_KRB5PrincipalName(&kn); + if (ret == 0 && (value->length != len) && + (*strpool = rk_strpoolprintf(*strpool, " ")) == NULL) + ret = hx509_enomem(context); + if (ret) { + rk_strpoolfree(*strpool); + *strpool = rk_strpoolprintf(NULL, + "principalName.name_string.len; i++) { + s = kn->principalName.name_string.val[i]; + len = strlen(s); + + if (need_slash) + strpool = rk_strpoolprintf(strpool, "/"); + need_slash = 1; + + for (k = 0; k < len; s += plen, k += plen) { + char c; + + plen = strcspn(s, comp_quotable_chars); + if (plen) + strpool = rk_strpoolprintf(strpool, "%.*s", (int)plen, s); + if (k + plen >= len) + continue; + switch ((c = s[plen++])) { + case '\n': strpool = rk_strpoolprintf(strpool, "\\n"); break; + case '\t': strpool = rk_strpoolprintf(strpool, "\\t"); break; + case '\b': strpool = rk_strpoolprintf(strpool, "\\b"); break; + /* default -> '@', ' ', '\\', or '/' */ + default: strpool = rk_strpoolprintf(strpool, "\\%c", c); break; + } + } + } + if (!kn->realm) + return strpool; + strpool = rk_strpoolprintf(strpool, "@"); + + s = kn->realm; + len = strlen(kn->realm); + for (k = 0; k < len; s += plen, k += plen) { + char c; + + plen = strcspn(s, realm_quotable_chars); + if (plen) + strpool = rk_strpoolprintf(strpool, "%.*s", (int)plen, s); + if (k + plen >= len) + continue; + switch ((c = s[plen++])) { + case '\n': strpool = rk_strpoolprintf(strpool, "\\n"); break; + case '\t': strpool = rk_strpoolprintf(strpool, "\\t"); break; + case '\b': strpool = rk_strpoolprintf(strpool, "\\b"); break; + /* default -> '@', ' ', or '\\' */ + default: strpool = rk_strpoolprintf(strpool, "\\%c", c); break; + } + } + return strpool; +} + +int +_hx509_unparse_utf8_string_name(hx509_context context, + struct rk_strpool **strpool, + heim_any *value) +{ + PKIXXmppAddr us; + size_t size; + int ret; + + ret = decode_PKIXXmppAddr(value->data, value->length, &us, &size); + if (ret == 0 && + (*strpool = rk_strpoolprintf(*strpool, "%s", us)) == NULL) + ret = hx509_enomem(context); + if (ret) { + rk_strpoolfree(*strpool); + *strpool = rk_strpoolprintf(NULL, + ""); + hx509_set_error_string(context, 0, ret, + "Failed to decode UTF8String SAN"); + } + free_PKIXXmppAddr(&us); + return ret; +} + +int +_hx509_unparse_ia5_string_name(hx509_context context, + struct rk_strpool **strpool, + heim_any *value) +{ + SRVName us; + size_t size; + int ret; + + ret = decode_SRVName(value->data, value->length, &us, &size); + if (ret == 0) { + rk_strpoolfree(*strpool); + *strpool = rk_strpoolprintf(NULL, + ""); + hx509_set_error_string(context, 0, ret, + "Failed to decode UTF8String SAN"); + return ret; + } + *strpool = rk_strpoolprintf(*strpool, "%.*s", + (int)us.length, (char *)us.data); + free_SRVName(&us); + return ret; +} + +typedef int (*other_unparser_f)(hx509_context, + struct rk_strpool **, + heim_any *); + +struct { + const heim_oid *oid; + const char *friendly_name; + other_unparser_f f; +} o_unparsers[] = { + { &asn1_oid_id_pkinit_san, + "KerberosPrincipalName", + _hx509_unparse_KRB5PrincipalName }, + { &asn1_oid_id_pkix_on_permanentIdentifier, + "PermanentIdentifier", + _hx509_unparse_PermanentIdentifier }, + { &asn1_oid_id_on_hardwareModuleName, + "HardwareModuleName", + _hx509_unparse_HardwareModuleName }, + { &asn1_oid_id_pkix_on_xmppAddr, + "XMPPName", + _hx509_unparse_utf8_string_name }, + { &asn1_oid_id_pkinit_ms_san, + "MSFTKerberosPrincipalName", + _hx509_unparse_utf8_string_name }, + { &asn1_oid_id_pkix_on_dnsSRV, + "SRVName", + _hx509_unparse_ia5_string_name }, +}; + +/** + * Unparse the hx509 name in name into a string. + * + * @param name the name to print + * @param str an allocated string returns the name in string form + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_general_name_unparse(GeneralName *name, char **str) +{ + hx509_context context; + int ret; + + if ((ret = hx509_context_init(&context))) + return ret; + ret = hx509_general_name_unparse2(context, name, str); + hx509_context_free(&context); + return ret; +} + +/** + * Unparse the hx509 name in name into a string. + * + * @param context hx509 library context + * @param name the name to print + * @param str an allocated string returns the name in string form + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_name + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_general_name_unparse2(hx509_context context, + GeneralName *name, + char **str) +{ + struct rk_strpool *strpool = NULL; + int ret = 0; + + *str = NULL; + + switch (name->element) { + case choice_GeneralName_otherName: { + size_t i; + char *oid; + + ret = hx509_oid_sprint(&name->u.otherName.type_id, &oid); + if (ret == 0) + strpool = rk_strpoolprintf(strpool, "otherName: %s ", oid); + if (strpool == NULL) + ret = ENOMEM; + + for (i = 0; ret == 0 && i < sizeof(o_unparsers)/sizeof(o_unparsers[0]); i++) { + if (der_heim_oid_cmp(&name->u.otherName.type_id, + o_unparsers[i].oid)) + continue; + strpool = rk_strpoolprintf(strpool, "%s ",o_unparsers[i].friendly_name); + if (strpool == NULL) + ret = ENOMEM; + if (ret == 0) + ret = o_unparsers[i].f(context, &strpool, &name->u.otherName.value); + break; + } + if (ret == 0 && i == sizeof(o_unparsers)/sizeof(o_unparsers[0])) { + strpool = rk_strpoolprintf(strpool, ""); + ret = ENOTSUP; + } + free(oid); + break; + } + case choice_GeneralName_rfc822Name: + strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s", + (int)name->u.rfc822Name.length, + (char *)name->u.rfc822Name.data); + break; + case choice_GeneralName_dNSName: + strpool = rk_strpoolprintf(strpool, "dNSName: %.*s", + (int)name->u.dNSName.length, + (char *)name->u.dNSName.data); + break; + case choice_GeneralName_directoryName: { + Name dir; + char *s; + memset(&dir, 0, sizeof(dir)); + dir.element = (enum Name_enum)name->u.directoryName.element; + dir.u.rdnSequence = name->u.directoryName.u.rdnSequence; + ret = _hx509_unparse_Name(&dir, &s); + if (ret) + return ret; + strpool = rk_strpoolprintf(strpool, "directoryName: %s", s); + free(s); + break; + } + case choice_GeneralName_uniformResourceIdentifier: + strpool = rk_strpoolprintf(strpool, "URI: %.*s", + (int)name->u.uniformResourceIdentifier.length, + (char *)name->u.uniformResourceIdentifier.data); + break; + case choice_GeneralName_iPAddress: { + unsigned char *a = name->u.iPAddress.data; + + strpool = rk_strpoolprintf(strpool, "IPAddress: "); + if (strpool == NULL) + break; + if (name->u.iPAddress.length == 4) + strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d", + a[0], a[1], a[2], a[3]); + else if (name->u.iPAddress.length == 16) + strpool = rk_strpoolprintf(strpool, + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X", + a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15]); + else + strpool = rk_strpoolprintf(strpool, + "unknown IP address of length %lu", + (unsigned long)name->u.iPAddress.length); + break; + } + case choice_GeneralName_registeredID: { + char *oid; + hx509_oid_sprint(&name->u.registeredID, &oid); + if (oid == NULL) + return ENOMEM; + strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid); + free(oid); + break; + } + default: + return EINVAL; + } + if (ret) + rk_strpoolfree(strpool); + else if (strpool == NULL || (*str = rk_strpoolcollect(strpool)) == NULL) + return ENOMEM; + return ret; +} diff --git a/third_party/heimdal/lib/hx509/peer.c b/third_party/heimdal/lib/hx509/peer.c new file mode 100644 index 0000000..2501f01 --- /dev/null +++ b/third_party/heimdal/lib/hx509/peer.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +/** + * @page page_peer Hx509 crypto selecting functions + * + * Peer info structures are used togeter with hx509_crypto_select() to + * select the best avaible crypto algorithm to use. + * + * See the library functions here: @ref hx509_peer + */ + +/** + * Allocate a new peer info structure an init it to default values. + * + * @param context A hx509 context. + * @param peer return an allocated peer, free with hx509_peer_info_free(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_alloc(hx509_context context, hx509_peer_info *peer) +{ + *peer = calloc(1, sizeof(**peer)); + if (*peer == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + return 0; +} + + +static void +free_cms_alg(hx509_peer_info peer) +{ + if (peer->val) { + size_t i; + for (i = 0; i < peer->len; i++) + free_AlgorithmIdentifier(&peer->val[i]); + free(peer->val); + peer->val = NULL; + peer->len = 0; + } +} + +/** + * Free a peer info structure. + * + * @param peer peer info to be freed. + * + * @ingroup hx509_peer + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_peer_info_free(hx509_peer_info peer) +{ + if (peer == NULL) + return; + if (peer->cert) + hx509_cert_free(peer->cert); + free_cms_alg(peer); + memset(peer, 0, sizeof(*peer)); + free(peer); +} + +/** + * Set the certificate that remote peer is using. + * + * @param peer peer info to update + * @param cert cerificate of the remote peer. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_set_cert(hx509_peer_info peer, + hx509_cert cert) +{ + if (peer->cert) + hx509_cert_free(peer->cert); + peer->cert = hx509_cert_ref(cert); + return 0; +} + +/** + * Add an additional algorithm that the peer supports. + * + * @param context A hx509 context. + * @param peer the peer to set the new algorithms for + * @param val an AlgorithmsIdentier to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_add_cms_alg(hx509_context context, + hx509_peer_info peer, + const AlgorithmIdentifier *val) +{ + void *ptr; + int ret; + + ptr = realloc(peer->val, sizeof(peer->val[0]) * (peer->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + peer->val = ptr; + ret = copy_AlgorithmIdentifier(val, &peer->val[peer->len]); + if (ret == 0) + peer->len += 1; + else + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; +} + +/** + * Set the algorithms that the peer supports. + * + * @param context A hx509 context. + * @param peer the peer to set the new algorithms for + * @param val array of supported AlgorithmsIdentiers + * @param len length of array val. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_set_cms_algs(hx509_context context, + hx509_peer_info peer, + const AlgorithmIdentifier *val, + size_t len) +{ + size_t i; + + free_cms_alg(peer); + + peer->val = calloc(len, sizeof(*peer->val)); + if (peer->val == NULL) { + peer->len = 0; + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + peer->len = len; + for (i = 0; i < len; i++) { + int ret; + ret = copy_AlgorithmIdentifier(&val[i], &peer->val[i]); + if (ret) { + hx509_clear_error_string(context); + free_cms_alg(peer); + return ret; + } + } + return 0; +} + +#if 0 + +/* + * S/MIME + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_parse_smime(hx509_peer_info peer, + const heim_octet_string *data) +{ + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_unparse_smime(hx509_peer_info peer, + heim_octet_string *data) +{ + return 0; +} + +/* + * For storing hx509_peer_info to be able to cache them. + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_parse(hx509_peer_info peer, + const heim_octet_string *data) +{ + return 0; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_peer_info_unparse(hx509_peer_info peer, + heim_octet_string *data) +{ + return 0; +} +#endif diff --git a/third_party/heimdal/lib/hx509/print.c b/third_party/heimdal/lib/hx509/print.c new file mode 100644 index 0000000..3309913 --- /dev/null +++ b/third_party/heimdal/lib/hx509/print.c @@ -0,0 +1,1144 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include +#include + +/** + * @page page_print Hx509 printing functions + * + * See the library functions here: @ref hx509_print + */ + +struct hx509_validate_ctx_data { + hx509_context context; + int flags; + hx509_vprint_func vprint_func; + void *ctx; +}; + +struct cert_status { + unsigned int selfsigned:1; + unsigned int isca:1; + unsigned int isproxy:1; + unsigned int haveSAN:1; + unsigned int haveIAN:1; + unsigned int haveSKI:1; + unsigned int haveAKI:1; + unsigned int haveCRLDP:1; +}; + + +/* + * + */ + +static int +Time2string(const Time *T, char **str) +{ + time_t t; + char *s; + struct tm *tm; + + *str = NULL; + t = _hx509_Time2time_t(T); + tm = gmtime (&t); + s = malloc(30); + if (s == NULL) + return ENOMEM; + strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm); + *str = s; + return 0; +} + +/** + * Helper function to print on stdout for: + * - hx509_oid_print(), + * - hx509_bitstring_print(), + * - hx509_validate_ctx_set_print(). + * + * @param ctx the context to the print function. If the ctx is NULL, + * stdout is used. + * @param fmt the printing format. + * @param va the argumet list. + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void +hx509_print_stdout(void *ctx, const char *fmt, va_list va) +{ + FILE *f = ctx; + if (f == NULL) + f = stdout; + vfprintf(f, fmt, va); +} + +static void +print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + (*func)(ctx, fmt, va); + va_end(va); +} + +/** + * Print a oid to a string. + * + * @param oid oid to print + * @param str allocated string, free with hx509_xfree(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_oid_sprint(const heim_oid *oid, char **str) +{ + return der_print_heim_oid(oid, '.', str); +} + +/** + * Print a oid using a hx509_vprint_func function. To print to stdout + * use hx509_print_stdout(). + * + * @param oid oid to print + * @param func hx509_vprint_func to print with. + * @param ctx context variable to hx509_vprint_func function. + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx) +{ + char *str; + hx509_oid_sprint(oid, &str); + print_func(func, ctx, "%s", str); + free(str); +} + +/** + * Print a bitstring using a hx509_vprint_func function. To print to + * stdout use hx509_print_stdout(). + * + * @param b bit string to print. + * @param func hx509_vprint_func to print with. + * @param ctx context variable to hx509_vprint_func function. + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_bitstring_print(const heim_bit_string *b, + hx509_vprint_func func, void *ctx) +{ + size_t i; + print_func(func, ctx, "\tlength: %d\n\t", b->length); + for (i = 0; i < (b->length + 7) / 8; i++) + print_func(func, ctx, "%02x%s%s", + ((unsigned char *)b->data)[i], + i < (b->length - 7) / 8 + && (i == 0 || (i % 16) != 15) ? ":" : "", + i != 0 && (i % 16) == 15 ? + (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):""); +} + +/** + * Print certificate usage for a certificate to a string. + * + * @param context A hx509 context. + * @param c a certificate print the keyusage for. + * @param s the return string with the keysage printed in to, free + * with hx509_xfree(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s) +{ + KeyUsage ku; + char buf[256]; + int ret; + + *s = NULL; + + ret = _hx509_cert_get_keyusage(context, c, &ku); + if (ret) + return ret; + unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf)); + *s = strdup(buf); + if (*s == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + return 0; +} + +/* + * + */ + +static void +validate_vprint(void *c, const char *fmt, va_list va) +{ + hx509_validate_ctx ctx = c; + if (ctx->vprint_func == NULL) + return; + (ctx->vprint_func)(ctx->ctx, fmt, va); +} + +static void +validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...) +{ + va_list va; + if ((ctx->flags & flags) == 0) + return; + va_start(va, fmt); + validate_vprint(ctx, fmt, va); + va_end(va); +} + +/* + * Don't Care, SHOULD critical, SHOULD NOT critical, MUST critical, + * MUST NOT critical + */ +enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C }; + +static int +check_Null(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, const Extension *e) +{ + switch(cf) { + case D_C: + break; + case S_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on SHOULD\n"); + break; + case S_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on SHOULD NOT\n"); + break; + case M_C: + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical not set on MUST\n"); + break; + case M_N_C: + if (e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tCritical set on MUST NOT\n"); + break; + default: + _hx509_abort("internal check_Null state error"); + } + return 0; +} + +static int +check_subjectKeyIdentifier(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + SubjectKeyIdentifier si; + size_t size; + int ret; + + status->haveSKI = 1; + check_Null(ctx, status, cf, e); + + ret = decode_SubjectKeyIdentifier(e->extnValue.data, + e->extnValue.length, + &si, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SubjectKeyIdentifier failed: %d", ret); + return 1; + } + if (size != e->extnValue.length) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SKI ahve extra bits on the end"); + return 1; + } + if (si.length == 0) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "SKI is too short (0 bytes)"); + if (si.length > 20) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "SKI is too long"); + + { + char *id; + hex_encode(si.data, si.length, &id); + if (id) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tsubject key id: %s\n", id); + free(id); + } + } + + free_SubjectKeyIdentifier(&si); + + return 0; +} + +static int +check_authorityKeyIdentifier(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + AuthorityKeyIdentifier ai; + size_t size; + int ret; + + status->haveAKI = 1; + check_Null(ctx, status, cf, e); + + ret = decode_AuthorityKeyIdentifier(e->extnValue.data, + e->extnValue.length, + &ai, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding AuthorityKeyIdentifier failed: %d", ret); + return 1; + } + if (size != e->extnValue.length) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SKI ahve extra bits on the end"); + return 1; + } + + if (ai.keyIdentifier) { + char *id; + hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id); + if (id) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tauthority key id: %s\n", id); + free(id); + } + } + + free_AuthorityKeyIdentifier(&ai); + return 0; +} + +static int +check_extKeyUsage(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + ExtKeyUsage eku; + size_t size, i; + int ret; + + check_Null(ctx, status, cf, e); + + ret = decode_ExtKeyUsage(e->extnValue.data, + e->extnValue.length, + &eku, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding ExtKeyUsage failed: %d", ret); + return 1; + } + if (size != e->extnValue.length) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Padding data in EKU"); + free_ExtKeyUsage(&eku); + return 1; + } + if (eku.len == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "ExtKeyUsage length is 0"); + return 1; + } + + for (i = 0; i < eku.len; i++) { + char *str; + ret = der_print_heim_oid (&eku.val[i], '.', &str); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tEKU: failed to print oid %d", i); + free_ExtKeyUsage(&eku); + return 1; + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\teku-%d: %s\n", i, str);; + free(str); + } + + free_ExtKeyUsage(&eku); + + return 0; +} + +static int +check_CRLDistributionPoints(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + CRLDistributionPoints dp; + size_t size; + int ret; + size_t i; + + check_Null(ctx, status, cf, e); + + ret = decode_CRLDistributionPoints(e->extnValue.data, + e->extnValue.length, + &dp, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding CRL Distribution Points failed: %d\n", ret); + return 1; + } + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n"); + for (i = 0 ; i < dp.len; i++) { + if (dp.val[i].distributionPoint) { + DistributionPointName dpname = dp.val[i].distributionPoint[0]; + size_t j; + + switch (dpname.element) { + case choice_DistributionPointName_fullName: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n"); + + for (j = 0 ; j < dpname.u.fullName.len; j++) { + char *s; + GeneralName *name = &dpname.u.fullName.val[j]; + + ret = hx509_general_name_unparse2(ctx->context, name, &s); + if (ret) { + s = hx509_get_error_string(ctx->context, ret); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Unknown DistributionPointName: %s", s); + hx509_free_error_string(s); + } else { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s); + free(s); + } + } + break; + case choice_DistributionPointName_nameRelativeToCRLIssuer: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Unknown nameRelativeToCRLIssuer"); + break; + default: + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Unknown DistributionPointName"); + break; + } + } + } + free_CRLDistributionPoints(&dp); + + status->haveCRLDP = 1; + + return 0; +} + +static int +check_altName(hx509_validate_ctx ctx, + struct cert_status *status, + const char *name, + enum critical_flag cf, + const Extension *e) +{ + GeneralNames gn; + size_t size; + int ret; + size_t i; + + check_Null(ctx, status, cf, e); + + if (e->extnValue.length == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "%sAltName empty, not allowed", name); + return 1; + } + ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, + &gn, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tret = %d while decoding %s GeneralNames\n", + ret, name); + return 1; + } + if (gn.len == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "%sAltName generalName empty, not allowed\n", name); + return 1; + } + + for (i = 0; i < gn.len; i++) { + char *s; + + ret = hx509_general_name_unparse2(ctx->context, &gn.val[i], &s); + if (ret) { + s = hx509_get_error_string(ctx->context, ret); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Error unparsing GeneralName: %s\n", s); + hx509_free_error_string(s); + return 1; + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\t%s\n", s); + free(s); + } + + free_GeneralNames(&gn); + return 0; +} + +static int +check_subjectAltName(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + status->haveSAN = 1; + return check_altName(ctx, status, "subject", cf, e); +} + +static int +check_issuerAltName(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + status->haveIAN = 1; + return check_altName(ctx, status, "issuer", cf, e); +} + + +static int +check_basicConstraints(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + BasicConstraints b; + size_t size; + int ret; + + check_Null(ctx, status, cf, e); + + ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, + &b, &size); + if (ret) { + printf("\tret = %d while decoding BasicConstraints\n", ret); + return 0; + } + if (size != e->extnValue.length) + printf("\tlength of der data isn't same as extension\n"); + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tis %sa CA\n", b.cA ? "" : "NOT "); + if (b.pathLenConstraint) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tpathLenConstraint: %d\n", *b.pathLenConstraint); + + if (b.cA) { + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Is a CA and not BasicConstraints CRITICAL\n"); + status->isca = 1; + } + free_BasicConstraints(&b); + + return 0; +} + +static int +check_proxyCertInfo(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + check_Null(ctx, status, cf, e); + status->isproxy = 1; + return 0; +} + +static int +check_authorityInfoAccess(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + AuthorityInfoAccessSyntax aia; + size_t size; + int ret; + size_t i; + + check_Null(ctx, status, cf, e); + + ret = decode_AuthorityInfoAccessSyntax(e->extnValue.data, + e->extnValue.length, + &aia, &size); + if (ret) { + printf("\tret = %d while decoding AuthorityInfoAccessSyntax\n", ret); + return 0; + } + + for (i = 0; i < aia.len; i++) { + char *str; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\ttype: "); + hx509_oid_print(&aia.val[i].accessMethod, validate_vprint, ctx); + ret = hx509_general_name_unparse2(ctx->context, + &aia.val[i].accessLocation, &str); + if (ret) { + str = hx509_get_error_string(ctx->context, ret); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Error unparsing AuthorityInfoAccessSyntax " + "accessLocation: %s", str); + hx509_free_error_string(str); + } else { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\n\tdirname: %s\n", str); + free(str); + } + } + free_AuthorityInfoAccessSyntax(&aia); + + return ret; +} + +static int +get_display_text(DisplayText *dt, char **out) +{ + int r = -1; + + *out = NULL; + + /* + * XXX We're cheating with various string types here. + * + * Proper support for IA5String is a real pain, and we don't have it. + * + * We also don't have support for BMPString. + */ + switch (dt->element) { + case choice_DisplayText_ia5String: + r = rk_strasvisx(out, dt->u.ia5String.data, dt->u.ia5String.length, + VIS_CSTYLE | VIS_TAB | VIS_NL, ""); + break; + case choice_DisplayText_visibleString: + r = rk_strasvis(out, dt->u.visibleString, + VIS_CSTYLE | VIS_TAB | VIS_NL, ""); + break; + case choice_DisplayText_bmpString: + errno = ENOTSUP; /* XXX Need a UTF-16 -> UTF-8 conversion */ + break; + case choice_DisplayText_utf8String: + r = rk_strasvis(out, dt->u.visibleString, + VIS_CSTYLE | VIS_TAB | VIS_NL, ""); + break; + default: + errno = EINVAL; + } + return r < 0 ? errno : 0; +} + +static int +check_certificatePolicies(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + CertificatePolicies cp; + size_t i, size; + int ret = 0; + + check_Null(ctx, status, cf, e); + + if (e->extnValue.length == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "CertificatePolicies empty, not allowed"); + return 1; + } + ret = decode_CertificatePolicies(e->extnValue.data, e->extnValue.length, + &cp, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tret = %d while decoding CertificatePolicies\n", ret); + return 1; + } + if (cp.len == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "CertificatePolicies empty, not allowed\n"); + return 1; + } + + for (i = 0; ret == 0 && i < cp.len; i++) { + size_t k; + char *poid = NULL; + char *qoid = NULL; + char *dt = NULL; + + ret = der_print_heim_oid(&cp.val[i].policyIdentifier, '.', &poid); + if (ret == 0) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tPolicy: %s", poid); + + for (k = 0; + ret == 0 && cp.val[i].policyQualifiers && + k < cp.val[i].policyQualifiers->len; + k++) { + PolicyQualifierInfo *pi = &cp.val[i].policyQualifiers->val[k]; + + if (der_heim_oid_cmp(&pi->policyQualifierId, + &asn1_oid_id_pkix_qt_cps) == 0) { + CPSuri cps; + + ret = decode_CPSuri(pi->qualifier.data, pi->qualifier.length, + &cps, &size); + if (ret == 0) { + if (cps.length > 4096) + cps.length = 4096; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + ":CPSuri:%.*s", + (int)cps.length, (char *)cps.data); + free_CPSuri(&cps); + } + } else if (der_heim_oid_cmp(&pi->policyQualifierId, + &asn1_oid_id_pkix_qt_unotice) == 0) { + UserNotice un; + + ret = decode_UserNotice(pi->qualifier.data, + pi->qualifier.length, &un, &size); + if (ret == 0) { + if (un.explicitText) { + /* + * get_display_text() will strvis to make it safer to + * print. + */ + ret = get_display_text(un.explicitText, &dt); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + " UserNotice:DistplayText:%s", dt); + } else if (un.noticeRef) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + " UserNotice:NoticeRef:", + qoid); + } else { + ret = der_print_heim_oid(&pi->policyQualifierId, '.', + &qoid); + if (ret) + break; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + " Unknown:%s", qoid); + } + free_UserNotice(&un); + } + } else { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + ", qualifier %s:", qoid); + } + free(qoid); + free(dt); + qoid = dt = 0; + } + if (ret == 0) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); + } else { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\nOut of memory formatting certificate policy"); + ret = ENOMEM; + } + free(poid); + free(qoid); + free(dt); + poid = qoid = dt = 0; + } + + free_CertificatePolicies(&cp); + + return ret ? 1 : 0; +} + +static int +check_policyMappings(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + PolicyMappings pm; + size_t i, size; + int ret = 0; + + check_Null(ctx, status, cf, e); + + if (e->extnValue.length == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "PolicyMappings empty, not allowed"); + return 1; + } + ret = decode_PolicyMappings(e->extnValue.data, e->extnValue.length, + &pm, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tret = %d while decoding PolicyMappings\n", ret); + return 1; + } + if (pm.len == 0) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "PolicyMappings empty, not allowed\n"); + return 1; + } + + for (i = 0; ret == 0 && i < pm.len; i++) { + char *idpoid = NULL; + char *sdpoid = NULL; + + ret = der_print_heim_oid(&pm.val[i].issuerDomainPolicy, '.', &idpoid); + if (ret == 0) + ret = der_print_heim_oid(&pm.val[i].subjectDomainPolicy, '.', + &sdpoid); + if (ret == 0) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tPolicy mapping %s -> %s\n", idpoid, sdpoid); + else + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "ret=%d while decoding PolicyMappings\n", ret); + free(sdpoid); + free(idpoid); + } + + free_PolicyMappings(&pm); + return 0; +} + +/* + * + */ + +struct { + const char *name; + const heim_oid *oid; + int (*func)(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *); + enum critical_flag cf; +} check_extension[] = { +#define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname + { ext(subjectDirectoryAttributes, Null), M_N_C }, + { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, + { ext(keyUsage, Null), S_C }, + { ext(subjectAltName, subjectAltName), M_N_C }, + { ext(issuerAltName, issuerAltName), S_N_C }, + { ext(basicConstraints, basicConstraints), D_C }, + { ext(cRLNumber, Null), M_N_C }, + { ext(cRLReason, Null), M_N_C }, + { ext(holdInstructionCode, Null), M_N_C }, + { ext(invalidityDate, Null), M_N_C }, + { ext(deltaCRLIndicator, Null), M_C }, + { ext(issuingDistributionPoint, Null), M_C }, + { ext(certificateIssuer, Null), M_C }, + { ext(nameConstraints, Null), M_C }, + { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C }, + { ext(certificatePolicies, certificatePolicies), 0 }, + { ext(policyMappings, policyMappings), M_N_C }, + { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C }, + { ext(policyConstraints, Null), D_C }, + { ext(extKeyUsage, extKeyUsage), D_C }, + { ext(freshestCRL, Null), M_N_C }, + { ext(inhibitAnyPolicy, Null), M_C }, +#undef ext +#define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname + { ext(proxyCertInfo, proxyCertInfo), M_C }, + { ext(authorityInfoAccess, authorityInfoAccess), M_C }, +#undef ext + { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim, + check_Null, D_C }, + { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment, + check_Null, D_C }, + { NULL, NULL, NULL, 0 } +}; + +/** + * Allocate a hx509 validation/printing context. + * + * @param context A hx509 context. + * @param ctx a new allocated hx509 validation context, free with + * hx509_validate_ctx_free(). + + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx) +{ + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) + return hx509_enomem(context); + (*ctx)->context = context; + return 0; +} + +/** + * Set the printing functions for the validation context. + * + * @param ctx a hx509 valication context. + * @param func the printing function to usea. + * @param c the context variable to the printing function. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_validate_ctx_set_print(hx509_validate_ctx ctx, + hx509_vprint_func func, + void *c) +{ + ctx->vprint_func = func; + ctx->ctx = c; +} + +/** + * Add flags to control the behaivor of the hx509_validate_cert() + * function. + * + * @param ctx A hx509 validation context. + * @param flags flags to add to the validation context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags) +{ + ctx->flags |= flags; +} + +/** + * Free an hx509 validate context. + * + * @param ctx the hx509 validate context to free. + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_validate_ctx_free(hx509_validate_ctx ctx) +{ + free(ctx); +} + +/** + * Validate/Print the status of the certificate. + * + * @param context A hx509 context. + * @param ctx A hx509 validation context. + * @param cert the cerificate to validate/print. + + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_print + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_validate_cert(hx509_context context, + hx509_validate_ctx ctx, + hx509_cert cert) +{ + Certificate *c = _hx509_get_cert(cert); + TBSCertificate *t = &c->tbsCertificate; + hx509_name issuer, subject; + char *str; + struct cert_status status; + int ret; + + memset(&status, 0, sizeof(status)); + + if (_hx509_cert_get_version(c) != 3) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Not version 3 certificate\n"); + + if ((t->version == NULL || *t->version < 2) && t->extensions) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Not version 3 certificate with extensions\n"); + + if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Version 3 certificate without extensions\n"); + + ret = hx509_cert_get_subject(cert, &subject); + if (ret) abort(); + hx509_name_to_string(subject, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "subject name: %s\n", str); + free(str); + + ret = hx509_cert_get_issuer(cert, &issuer); + if (ret) abort(); + hx509_name_to_string(issuer, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "issuer name: %s\n", str); + free(str); + + if (hx509_name_cmp(subject, issuer) == 0) { + status.selfsigned = 1; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tis a self-signed certificate\n"); + } + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Validity:\n"); + + Time2string(&t->validity.notBefore, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); + free(str); + Time2string(&t->validity.notAfter, &str); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); + free(str); + + if (t->extensions) { + size_t i, j; + + if (t->extensions->len == 0) { + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "The empty extensions list is not " + "allowed by PKIX\n"); + } + + for (i = 0; i < t->extensions->len; i++) { + + for (j = 0; check_extension[j].name; j++) + if (der_heim_oid_cmp(check_extension[j].oid, + &t->extensions->val[i].extnID) == 0) + break; + if (check_extension[j].name == NULL) { + int flags = HX509_VALIDATE_F_VERBOSE; + if (t->extensions->val[i].critical) + flags |= HX509_VALIDATE_F_VALIDATE; + validate_print(ctx, flags, "don't know what "); + if (t->extensions->val[i].critical) + validate_print(ctx, flags, "and is CRITICAL "); + if (ctx->flags & flags) + hx509_oid_print(&t->extensions->val[i].extnID, + validate_vprint, ctx); + validate_print(ctx, flags, " is\n"); + continue; + } + validate_print(ctx, + HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, + "checking extension: %s\n", + check_extension[j].name); + (*check_extension[j].func)(ctx, + &status, + check_extension[j].cf, + &t->extensions->val[i]); + } + } else + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extensions\n"); + + if (status.isca) { + if (!status.haveSKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "CA certificate have no SubjectKeyIdentifier\n"); + + } else { + if (!status.haveAKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Is not CA and doesn't have " + "AuthorityKeyIdentifier\n"); + } + + + if (!status.haveSKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Doesn't have SubjectKeyIdentifier\n"); + + if (status.isproxy && status.isca) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and CA at the same time!\n"); + + if (status.isproxy) { + if (status.haveSAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and have SAN\n"); + if (status.haveIAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and have IAN\n"); + } + + if (hx509_name_is_null_p(subject) && !status.haveSAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "NULL subject DN and doesn't have a SAN\n"); + + if (!status.selfsigned && !status.haveCRLDP) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Not a CA nor PROXY and doesn't have" + "CRL Dist Point\n"); + + if (status.selfsigned) { + ret = _hx509_verify_signature_bitstring(context, + cert, + &c->signatureAlgorithm, + &c->tbsCertificate._save, + &c->signatureValue); + if (ret == 0) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Self-signed certificate was self-signed\n"); + else + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Self-signed certificate NOT really self-signed!\n"); + } + + hx509_name_free(&subject); + hx509_name_free(&issuer); + + return 0; +} diff --git a/third_party/heimdal/lib/hx509/quote.py b/third_party/heimdal/lib/hx509/quote.py new file mode 100644 index 0000000..41887e5 --- /dev/null +++ b/third_party/heimdal/lib/hx509/quote.py @@ -0,0 +1,101 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2010 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +CONTROL_CHAR = 1 +PRINTABLE = 2 +RFC2253_QUOTE_FIRST = 4 +RFC2253_QUOTE_LAST = 8 +RFC2253_QUOTE = 16 +RFC2253_HEX = 32 + +chars = [] + +for i in range(0, 256): + chars.append(0); + +for i in range(0, 256): + if (i < 32 or i > 126): + chars[i] |= CONTROL_CHAR | RFC2253_HEX; + +for i in range(ord("A"), ord("Z") + 1): + chars[i] |= PRINTABLE +for i in range(ord("a"), ord("z") + 1): + chars[i] |= PRINTABLE +for i in range(ord("0"), ord("9") + 1): + chars[i] |= PRINTABLE + +chars[ord(' ')] |= PRINTABLE +chars[ord('+')] |= PRINTABLE +chars[ord(',')] |= PRINTABLE +chars[ord('-')] |= PRINTABLE +chars[ord('.')] |= PRINTABLE +chars[ord('/')] |= PRINTABLE +chars[ord(':')] |= PRINTABLE +chars[ord('=')] |= PRINTABLE +chars[ord('?')] |= PRINTABLE + +chars[ord(' ')] |= RFC2253_QUOTE_FIRST | RFC2253_QUOTE_FIRST + +chars[ord(',')] |= RFC2253_QUOTE +chars[ord('=')] |= RFC2253_QUOTE +chars[ord('+')] |= RFC2253_QUOTE +chars[ord('<')] |= RFC2253_QUOTE +chars[ord('>')] |= RFC2253_QUOTE +chars[ord('#')] |= RFC2253_QUOTE +chars[ord(';')] |= RFC2253_QUOTE + +print "#define Q_CONTROL_CHAR 1" +print "#define Q_PRINTABLE 2" +print "#define Q_RFC2253_QUOTE_FIRST 4" +print "#define Q_RFC2253_QUOTE_LAST 8" +print "#define Q_RFC2253_QUOTE 16" +print "#define Q_RFC2253_HEX 32" +print "" +print "#define Q_RFC2253 (Q_RFC2253_QUOTE_FIRST|Q_RFC2253_QUOTE_LAST|Q_RFC2253_QUOTE|Q_RFC2253_HEX)" +print "\n" * 2 + + + + +print "unsigned char char_map[] = {\n\t", +for x in range(0, 256): + if (x % 8) == 0 and x != 0: + print "\n\t", + print "0x%(char)02x" % { 'char' : chars[x] }, + if x < 255: + print ", ", + else: + print "" +print "};" diff --git a/third_party/heimdal/lib/hx509/ref/pkcs11.h b/third_party/heimdal/lib/hx509/ref/pkcs11.h new file mode 100644 index 0000000..a294c5e --- /dev/null +++ b/third_party/heimdal/lib/hx509/ref/pkcs11.h @@ -0,0 +1,1722 @@ +/* pkcs11.h + Copyright 2006, 2007 g10 Code GmbH + Copyright 2006 Andreas Jellinghaus + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. */ + +/* Please submit changes back to the Scute project at + http://www.scute.org/ (or send them to marcus@g10code.com), so that + they can be picked up by other projects from there as well. */ + +/* This file is a modified implementation of the PKCS #11 standard by + RSA Security Inc. It is mostly a drop-in replacement, with the + following change: + + This header file does not require any macro definitions by the user + (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros + for you (if useful, some are missing, let me know if you need + more). + + There is an additional API available that does comply better to the + GNU coding standard. It can be switched on by defining + CRYPTOKI_GNU before including this header file. For this, the + following changes are made to the specification: + + All structure types are changed to a "struct ck_foo" where CK_FOO + is the type name in PKCS #11. + + All non-structure types are changed to ck_foo_t where CK_FOO is the + lowercase version of the type name in PKCS #11. The basic types + (CK_ULONG et al.) are removed without substitute. + + All members of structures are modified in the following way: Type + indication prefixes are removed, and underscore characters are + inserted before words. Then the result is lowercased. + + Note that function names are still in the original case, as they + need for ABI compatibility. + + CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use + . + + If CRYPTOKI_COMPAT is defined before including this header file, + then none of the API changes above take place, and the API is the + one defined by the PKCS #11 standard. */ + +#ifndef PKCS11_H +#define PKCS11_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The version of cryptoki we implement. The revision is changed with + each modification of this file. If you do not use the "official" + version of this file, please consider deleting the revision macro + (you may use a macro with a different name to keep track of your + versions). */ +#define CRYPTOKI_VERSION_MAJOR 2 +#define CRYPTOKI_VERSION_MINOR 30 +#define CRYPTOKI_VERSION_REVISION 0 +#define CRYPTOKI_VERSION_AMENDMENT 0 + + +/* Compatibility interface is default, unless CRYPTOKI_GNU is + given. */ +#ifndef CRYPTOKI_GNU +#ifndef CRYPTOKI_COMPAT +#define CRYPTOKI_COMPAT 1 +#endif +#endif + +/* System dependencies. */ + +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) + +/* There is a matching pop below. */ +#pragma pack(push, cryptoki, 1) + +#ifdef CRYPTOKI_EXPORTS +#define CK_SPEC __declspec(dllexport) +#else +#define CK_SPEC __declspec(dllimport) +#endif + +#else + +#if defined(CRYPTOKI_VISIBILITY) && defined(CRYPTOKI_EXPORTS) +#define CK_SPEC __attribute__((visibility("default"))) +#else +#define CK_SPEC +#endif + +#endif + + +#ifdef CRYPTOKI_COMPAT + /* If we are in compatibility mode, switch all exposed names to the + PKCS #11 variant. There are corresponding #undefs below. */ + +#define ck_flags_t CK_FLAGS +#define ck_version _CK_VERSION + +#define ck_info _CK_INFO +#define cryptoki_version cryptokiVersion +#define manufacturer_id manufacturerID +#define library_description libraryDescription +#define library_version libraryVersion + +#define ck_notification_t CK_NOTIFICATION +#define ck_slot_id_t CK_SLOT_ID + +#define ck_slot_info _CK_SLOT_INFO +#define slot_description slotDescription +#define hardware_version hardwareVersion +#define firmware_version firmwareVersion + +#define ck_token_info _CK_TOKEN_INFO +#define serial_number serialNumber +#define max_session_count ulMaxSessionCount +#define session_count ulSessionCount +#define max_rw_session_count ulMaxRwSessionCount +#define rw_session_count ulRwSessionCount +#define max_pin_len ulMaxPinLen +#define min_pin_len ulMinPinLen +#define total_public_memory ulTotalPublicMemory +#define free_public_memory ulFreePublicMemory +#define total_private_memory ulTotalPrivateMemory +#define free_private_memory ulFreePrivateMemory +#define utc_time utcTime + +#define ck_session_handle_t CK_SESSION_HANDLE +#define ck_user_type_t CK_USER_TYPE +#define ck_state_t CK_STATE + +#define ck_session_info _CK_SESSION_INFO +#define slot_id slotID +#define device_error ulDeviceError + +#define ck_object_handle_t CK_OBJECT_HANDLE +#define ck_object_class_t CK_OBJECT_CLASS +#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE +#define ck_key_type_t CK_KEY_TYPE +#define ck_certificate_type_t CK_CERTIFICATE_TYPE +#define ck_attribute_type_t CK_ATTRIBUTE_TYPE + +#define ck_attribute _CK_ATTRIBUTE +#define value pValue +#define value_len ulValueLen + +#define ck_date _CK_DATE + +#define ck_mechanism_type_t CK_MECHANISM_TYPE + +#define ck_mechanism _CK_MECHANISM +#define parameter pParameter +#define parameter_len ulParameterLen + +#define ck_mechanism_info _CK_MECHANISM_INFO +#define min_key_size ulMinKeySize +#define max_key_size ulMaxKeySize + +#define hash_alg hashAlg +#define source_data pSourceData +#define source_data_len ulSourceDataLen + +#define slen sLen + +#define ck_ec_kdf_type_t CK_EC_KDF_TYPE + +#define shared_data_len ulSharedDataLen +#define shared_data pSharedData +#define public_data_len ulPublicDataLen +#define public_data pPublicData + +#define private_data_len ulPrivateDataLen +#define private_data hPrivateData +#define public_data_len2 ulPublicDataLen2 +#define public_data2 pPublicData2 + +#define public_key publicKey + +#define ck_x9_42_dh_kdf_type_t CK_X9_42_DH_KDF_TYPE + +#define other_info_len ulOtherInfoLen +#define other_info pOtherInfo + +#define data pData +#define len ulLen + +#define ck_rv_t CK_RV +#define ck_notify_t CK_NOTIFY + +#define ck_function_list _CK_FUNCTION_LIST + +#define ck_createmutex_t CK_CREATEMUTEX +#define ck_destroymutex_t CK_DESTROYMUTEX +#define ck_lockmutex_t CK_LOCKMUTEX +#define ck_unlockmutex_t CK_UNLOCKMUTEX + +#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS +#define create_mutex CreateMutex +#define destroy_mutex DestroyMutex +#define lock_mutex LockMutex +#define unlock_mutex UnlockMutex +#define reserved pReserved + +#endif /* CRYPTOKI_COMPAT */ + + + +typedef unsigned long ck_flags_t; + +struct ck_version +{ + unsigned char major; + unsigned char minor; +}; + + +struct ck_info +{ + struct ck_version cryptoki_version; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + unsigned char library_description[32]; + struct ck_version library_version; +}; + + +typedef unsigned long ck_notification_t; + +#define CKN_SURRENDER (0) +#define CKN_OTP_CHANGED (1) + +typedef unsigned long ck_slot_id_t; + + +struct ck_slot_info +{ + unsigned char slot_description[64]; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + struct ck_version hardware_version; + struct ck_version firmware_version; +}; + + +#define CKF_TOKEN_PRESENT (1 << 0) +#define CKF_REMOVABLE_DEVICE (1 << 1) +#define CKF_HW_SLOT (1 << 2) +#define CKF_ARRAY_ATTRIBUTE (1 << 30) + + +struct ck_token_info +{ + unsigned char label[32]; + unsigned char manufacturer_id[32]; + unsigned char model[16]; + unsigned char serial_number[16]; + ck_flags_t flags; + unsigned long max_session_count; + unsigned long session_count; + unsigned long max_rw_session_count; + unsigned long rw_session_count; + unsigned long max_pin_len; + unsigned long min_pin_len; + unsigned long total_public_memory; + unsigned long free_public_memory; + unsigned long total_private_memory; + unsigned long free_private_memory; + struct ck_version hardware_version; + struct ck_version firmware_version; + unsigned char utc_time[16]; +}; + + +#define CKF_RNG (1 << 0) +#define CKF_WRITE_PROTECTED (1 << 1) +#define CKF_LOGIN_REQUIRED (1 << 2) +#define CKF_USER_PIN_INITIALIZED (1 << 3) +#define CKF_RESTORE_KEY_NOT_NEEDED (1 << 5) +#define CKF_CLOCK_ON_TOKEN (1 << 6) +#define CKF_PROTECTED_AUTHENTICATION_PATH (1 << 8) +#define CKF_DUAL_CRYPTO_OPERATIONS (1 << 9) +#define CKF_TOKEN_INITIALIZED (1 << 10) +#define CKF_SECONDARY_AUTHENTICATION (1 << 11) +#define CKF_USER_PIN_COUNT_LOW (1 << 16) +#define CKF_USER_PIN_FINAL_TRY (1 << 17) +#define CKF_USER_PIN_LOCKED (1 << 18) +#define CKF_USER_PIN_TO_BE_CHANGED (1 << 19) +#define CKF_SO_PIN_COUNT_LOW (1 << 20) +#define CKF_SO_PIN_FINAL_TRY (1 << 21) +#define CKF_SO_PIN_LOCKED (1 << 22) +#define CKF_SO_PIN_TO_BE_CHANGED (1 << 23) +#define CKF_ERROR_STATE (1 << 24) + +#define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1) +#define CK_EFFECTIVELY_INFINITE (0) + + +typedef unsigned long ck_session_handle_t; + +#define CK_INVALID_HANDLE (0) + + +typedef unsigned long ck_user_type_t; + +#define CKU_SO (0) +#define CKU_USER (1) +#define CKU_CONTEXT_SPECIFIC (2) + + +typedef unsigned long ck_state_t; + +#define CKS_RO_PUBLIC_SESSION (0) +#define CKS_RO_USER_FUNCTIONS (1) +#define CKS_RW_PUBLIC_SESSION (2) +#define CKS_RW_USER_FUNCTIONS (3) +#define CKS_RW_SO_FUNCTIONS (4) + + +struct ck_session_info +{ + ck_slot_id_t slot_id; + ck_state_t state; + ck_flags_t flags; + unsigned long device_error; +}; + +#define CKF_RW_SESSION (1 << 1) +#define CKF_SERIAL_SESSION (1 << 2) + + +typedef unsigned long ck_object_handle_t; + + +typedef unsigned long ck_object_class_t; + +#define CKO_DATA (0) +#define CKO_CERTIFICATE (1) +#define CKO_PUBLIC_KEY (2) +#define CKO_PRIVATE_KEY (3) +#define CKO_SECRET_KEY (4) +#define CKO_HW_FEATURE (5) +#define CKO_DOMAIN_PARAMETERS (6) +#define CKO_MECHANISM (7) +#define CKO_OTP_KEY (8) +#define CKO_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + +typedef unsigned long ck_hw_feature_type_t; + +#define CKH_MONOTONIC_COUNTER (1) +#define CKH_CLOCK (2) +#define CKH_USER_INTERFACE (3) +#define CKH_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + +typedef unsigned long ck_key_type_t; + +#define CKK_RSA (0) +#define CKK_DSA (1) +#define CKK_DH (2) +#define CKK_ECDSA (3) +#define CKK_EC (3) +#define CKK_X9_42_DH (4) +#define CKK_KEA (5) +#define CKK_GENERIC_SECRET (0x10) +#define CKK_RC2 (0x11) +#define CKK_RC4 (0x12) +#define CKK_DES (0x13) +#define CKK_DES2 (0x14) +#define CKK_DES3 (0x15) +#define CKK_CAST (0x16) +#define CKK_CAST3 (0x17) +#define CKK_CAST5 (0x18) +#define CKK_CAST128 (0x18) +#define CKK_RC5 (0x19) +#define CKK_IDEA (0x1a) +#define CKK_SKIPJACK (0x1b) +#define CKK_BATON (0x1c) +#define CKK_JUNIPER (0x1d) +#define CKK_CDMF (0x1e) +#define CKK_AES (0x1f) +#define CKK_BLOWFISH (0x20) +#define CKK_TWOFISH (0x21) +#define CKK_SECURID (0x22) +#define CKK_HOTP (0x23) +#define CKK_ACTI (0x24) +#define CKK_CAMELLIA (0x25) +#define CKK_ARIA (0x26) +#define CKK_MD5_HMAC (0x27) +#define CKK_SHA_1_HMAC (0x28) +#define CKK_RIPEMD128_HMAC (0x29) +#define CKK_RIPEMD160_HMAC (0x2A) +#define CKK_SHA256_HMAC (0x2B) +#define CKK_SHA384_HMAC (0x2C) +#define CKK_SHA512_HMAC (0x2D) +#define CKK_SHA224_HMAC (0x2E) +#define CKK_SEED (0x2F) +#define CKK_GOSTR3410 (0x30) +#define CKK_GOSTR3411 (0x31) +#define CKK_GOST28147 (0x32) +#define CKK_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + +typedef unsigned long ck_certificate_type_t; + +#define CKC_X_509 (0) +#define CKC_X_509_ATTR_CERT (1) +#define CKC_WTLS (2) +#define CKC_VENDOR_DEFINED ((unsigned long) (1ul << 31)) +#define CKC_OPENPGP (CKC_VENDOR_DEFINED|0x00504750) + +#define CK_OTP_FORMAT_DECIMAL (0) +#define CK_OTP_FORMAT_HEXADECIMAL (1) +#define CK_OTP_FORMAT_ALPHANUMERIC (2) +#define CK_OTP_FORMAT_BINARY (3) + +#define CK_OTP_PARAM_IGNORED (0) +#define CK_OTP_PARAM_OPTIONAL (1) +#define CK_OTP_PARAM_MANDATORY (2) + +typedef unsigned long ck_attribute_type_t; + +#define CKA_CLASS (0) +#define CKA_TOKEN (1) +#define CKA_PRIVATE (2) +#define CKA_LABEL (3) +#define CKA_APPLICATION (0x10) +#define CKA_VALUE (0x11) +#define CKA_OBJECT_ID (0x12) +#define CKA_CERTIFICATE_TYPE (0x80) +#define CKA_ISSUER (0x81) +#define CKA_SERIAL_NUMBER (0x82) +#define CKA_AC_ISSUER (0x83) +#define CKA_OWNER (0x84) +#define CKA_ATTR_TYPES (0x85) +#define CKA_TRUSTED (0x86) +#define CKA_CERTIFICATE_CATEGORY (0x87) +#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88) +#define CKA_URL (0x89) +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a) +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8b) +#define CKA_NAME_HASH_ALGORITHM (0x8c) +#define CKA_CHECK_VALUE (0x90) +#define CKA_KEY_TYPE (0x100) +#define CKA_SUBJECT (0x101) +#define CKA_ID (0x102) +#define CKA_SENSITIVE (0x103) +#define CKA_ENCRYPT (0x104) +#define CKA_DECRYPT (0x105) +#define CKA_WRAP (0x106) +#define CKA_UNWRAP (0x107) +#define CKA_SIGN (0x108) +#define CKA_SIGN_RECOVER (0x109) +#define CKA_VERIFY (0x10a) +#define CKA_VERIFY_RECOVER (0x10b) +#define CKA_DERIVE (0x10c) +#define CKA_START_DATE (0x110) +#define CKA_END_DATE (0x111) +#define CKA_MODULUS (0x120) +#define CKA_MODULUS_BITS (0x121) +#define CKA_PUBLIC_EXPONENT (0x122) +#define CKA_PRIVATE_EXPONENT (0x123) +#define CKA_PRIME_1 (0x124) +#define CKA_PRIME_2 (0x125) +#define CKA_EXPONENT_1 (0x126) +#define CKA_EXPONENT_2 (0x127) +#define CKA_COEFFICIENT (0x128) +#define CKA_PRIME (0x130) +#define CKA_SUBPRIME (0x131) +#define CKA_BASE (0x132) +#define CKA_PRIME_BITS (0x133) +#define CKA_SUB_PRIME_BITS (0x134) +#define CKA_SUBPRIME_BITS (0x134) +#define CKA_VALUE_BITS (0x160) +#define CKA_VALUE_LEN (0x161) +#define CKA_EXTRACTABLE (0x162) +#define CKA_LOCAL (0x163) +#define CKA_NEVER_EXTRACTABLE (0x164) +#define CKA_ALWAYS_SENSITIVE (0x165) +#define CKA_KEY_GEN_MECHANISM (0x166) +#define CKA_MODIFIABLE (0x170) +#define CKA_COPYABLE (0x171) +#define CKA_ECDSA_PARAMS (0x180) +#define CKA_EC_PARAMS (0x180) +#define CKA_EC_POINT (0x181) +#define CKA_SECONDARY_AUTH (0x200) +#define CKA_AUTH_PIN_FLAGS (0x201) +#define CKA_ALWAYS_AUTHENTICATE (0x202) +#define CKA_WRAP_WITH_TRUSTED (0x210) +#define CKA_OTP_FORMAT (0x220) +#define CKA_OTP_LENGTH (0x221) +#define CKA_OTP_TIME_INTERVAL (0x222) +#define CKA_OTP_USER_FRIENDLY_MODE (0x223) +#define CKA_OTP_CHALLENGE_REQUIREMENT (0x224) +#define CKA_OTP_TIME_REQUIREMENT (0x225) +#define CKA_OTP_COUNTER_REQUIREMENT (0x226) +#define CKA_OTP_PIN_REQUIREMENT (0x227) +#define CKA_OTP_COUNTER (0x22E) +#define CKA_OTP_TIME (0x22F) +#define CKA_OTP_USER_IDENTIFIER (0x22A) +#define CKA_OTP_SERVICE_IDENTIFIER (0x22B) +#define CKA_OTP_SERVICE_LOGO (0x22C) +#define CKA_OTP_SERVICE_LOGO_TYPE (0x22D) +#define CKA_GOSTR3410_PARAMS (0x250) +#define CKA_GOSTR3411_PARAMS (0x251) +#define CKA_GOST28147_PARAMS (0x252) +#define CKA_HW_FEATURE_TYPE (0x300) +#define CKA_RESET_ON_INIT (0x301) +#define CKA_HAS_RESET (0x302) +#define CKA_PIXEL_X (0x400) +#define CKA_PIXEL_Y (0x401) +#define CKA_RESOLUTION (0x402) +#define CKA_CHAR_ROWS (0x403) +#define CKA_CHAR_COLUMNS (0x404) +#define CKA_COLOR (0x405) +#define CKA_BITS_PER_PIXEL (0x406) +#define CKA_CHAR_SETS (0x480) +#define CKA_ENCODING_METHODS (0x481) +#define CKA_MIME_TYPES (0x482) +#define CKA_MECHANISM_TYPE (0x500) +#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501) +#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502) +#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503) +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212) +#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x213) +#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600) +#define CKA_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + +struct ck_attribute +{ + ck_attribute_type_t type; + void *value; + unsigned long value_len; +}; + + +struct ck_date +{ + unsigned char year[4]; + unsigned char month[2]; + unsigned char day[2]; +}; + + +typedef unsigned long ck_mechanism_type_t; + +#define CKM_RSA_PKCS_KEY_PAIR_GEN (0) +#define CKM_RSA_PKCS (1) +#define CKM_RSA_9796 (2) +#define CKM_RSA_X_509 (3) +#define CKM_MD2_RSA_PKCS (4) +#define CKM_MD5_RSA_PKCS (5) +#define CKM_SHA1_RSA_PKCS (6) +#define CKM_RIPEMD128_RSA_PKCS (7) +#define CKM_RIPEMD160_RSA_PKCS (8) +#define CKM_RSA_PKCS_OAEP (9) +#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xa) +#define CKM_RSA_X9_31 (0xb) +#define CKM_SHA1_RSA_X9_31 (0xc) +#define CKM_RSA_PKCS_PSS (0xd) +#define CKM_SHA1_RSA_PKCS_PSS (0xe) +#define CKM_DSA_KEY_PAIR_GEN (0x10) +#define CKM_DSA (0x11) +#define CKM_DSA_SHA1 (0x12) +#define CKM_DSA_SHA224 (0x13) +#define CKM_DSA_SHA256 (0x14) +#define CKM_DSA_SHA384 (0x15) +#define CKM_DSA_SHA512 (0x16) +#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20) +#define CKM_DH_PKCS_DERIVE (0x21) +#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30) +#define CKM_X9_42_DH_DERIVE (0x31) +#define CKM_X9_42_DH_HYBRID_DERIVE (0x32) +#define CKM_X9_42_MQV_DERIVE (0x33) +#define CKM_SHA256_RSA_PKCS (0x40) +#define CKM_SHA384_RSA_PKCS (0x41) +#define CKM_SHA512_RSA_PKCS (0x42) +#define CKM_SHA256_RSA_PKCS_PSS (0x43) +#define CKM_SHA384_RSA_PKCS_PSS (0x44) +#define CKM_SHA512_RSA_PKCS_PSS (0x45) +#define CKM_SHA224_RSA_PKCS (0x46) +#define CKM_SHA224_RSA_PKCS_PSS (0x47) +#define CKM_RC2_KEY_GEN (0x100) +#define CKM_RC2_ECB (0x101) +#define CKM_RC2_CBC (0x102) +#define CKM_RC2_MAC (0x103) +#define CKM_RC2_MAC_GENERAL (0x104) +#define CKM_RC2_CBC_PAD (0x105) +#define CKM_RC4_KEY_GEN (0x110) +#define CKM_RC4 (0x111) +#define CKM_DES_KEY_GEN (0x120) +#define CKM_DES_ECB (0x121) +#define CKM_DES_CBC (0x122) +#define CKM_DES_MAC (0x123) +#define CKM_DES_MAC_GENERAL (0x124) +#define CKM_DES_CBC_PAD (0x125) +#define CKM_DES2_KEY_GEN (0x130) +#define CKM_DES3_KEY_GEN (0x131) +#define CKM_DES3_ECB (0x132) +#define CKM_DES3_CBC (0x133) +#define CKM_DES3_MAC (0x134) +#define CKM_DES3_MAC_GENERAL (0x135) +#define CKM_DES3_CBC_PAD (0x136) +#define CKM_DES3_CMAC_GENERAL (0x137) +#define CKM_DES3_CMAC (0x138) +#define CKM_CDMF_KEY_GEN (0x140) +#define CKM_CDMF_ECB (0x141) +#define CKM_CDMF_CBC (0x142) +#define CKM_CDMF_MAC (0x143) +#define CKM_CDMF_MAC_GENERAL (0x144) +#define CKM_CDMF_CBC_PAD (0x145) +#define CKM_DES_OFB64 (0x150) +#define CKM_DES_OFB8 (0x151) +#define CKM_DES_CFB64 (0x152) +#define CKM_DES_CFB8 (0x153) +#define CKM_MD2 (0x200) +#define CKM_MD2_HMAC (0x201) +#define CKM_MD2_HMAC_GENERAL (0x202) +#define CKM_MD5 (0x210) +#define CKM_MD5_HMAC (0x211) +#define CKM_MD5_HMAC_GENERAL (0x212) +#define CKM_SHA_1 (0x220) +#define CKM_SHA_1_HMAC (0x221) +#define CKM_SHA_1_HMAC_GENERAL (0x222) +#define CKM_RIPEMD128 (0x230) +#define CKM_RIPEMD128_HMAC (0x231) +#define CKM_RIPEMD128_HMAC_GENERAL (0x232) +#define CKM_RIPEMD160 (0x240) +#define CKM_RIPEMD160_HMAC (0x241) +#define CKM_RIPEMD160_HMAC_GENERAL (0x242) +#define CKM_SHA256 (0x250) +#define CKM_SHA256_HMAC (0x251) +#define CKM_SHA256_HMAC_GENERAL (0x252) +#define CKM_SHA224 (0x255) +#define CKM_SHA224_HMAC (0x256) +#define CKM_SHA224_HMAC_GENERAL (0x257) +#define CKM_SHA384 (0x260) +#define CKM_SHA384_HMAC (0x261) +#define CKM_SHA384_HMAC_GENERAL (0x262) +#define CKM_SHA512 (0x270) +#define CKM_SHA512_HMAC (0x271) +#define CKM_SHA512_HMAC_GENERAL (0x272) +#define CKM_SECURID_KEY_GEN (0x280) +#define CKM_SECURID (0x282) +#define CKM_HOTP_KEY_GEN (0x290) +#define CKM_HOTP (0x291) +#define CKM_ACTI (0x2A0) +#define CKM_ACTI_KEY_GEN (0x2A1) +#define CKM_CAST_KEY_GEN (0x300) +#define CKM_CAST_ECB (0x301) +#define CKM_CAST_CBC (0x302) +#define CKM_CAST_MAC (0x303) +#define CKM_CAST_MAC_GENERAL (0x304) +#define CKM_CAST_CBC_PAD (0x305) +#define CKM_CAST3_KEY_GEN (0x310) +#define CKM_CAST3_ECB (0x311) +#define CKM_CAST3_CBC (0x312) +#define CKM_CAST3_MAC (0x313) +#define CKM_CAST3_MAC_GENERAL (0x314) +#define CKM_CAST3_CBC_PAD (0x315) +#define CKM_CAST5_KEY_GEN (0x320) +#define CKM_CAST128_KEY_GEN (0x320) +#define CKM_CAST5_ECB (0x321) +#define CKM_CAST128_ECB (0x321) +#define CKM_CAST5_CBC (0x322) +#define CKM_CAST128_CBC (0x322) +#define CKM_CAST5_MAC (0x323) +#define CKM_CAST128_MAC (0x323) +#define CKM_CAST5_MAC_GENERAL (0x324) +#define CKM_CAST128_MAC_GENERAL (0x324) +#define CKM_CAST5_CBC_PAD (0x325) +#define CKM_CAST128_CBC_PAD (0x325) +#define CKM_RC5_KEY_GEN (0x330) +#define CKM_RC5_ECB (0x331) +#define CKM_RC5_CBC (0x332) +#define CKM_RC5_MAC (0x333) +#define CKM_RC5_MAC_GENERAL (0x334) +#define CKM_RC5_CBC_PAD (0x335) +#define CKM_IDEA_KEY_GEN (0x340) +#define CKM_IDEA_ECB (0x341) +#define CKM_IDEA_CBC (0x342) +#define CKM_IDEA_MAC (0x343) +#define CKM_IDEA_MAC_GENERAL (0x344) +#define CKM_IDEA_CBC_PAD (0x345) +#define CKM_GENERIC_SECRET_KEY_GEN (0x350) +#define CKM_CONCATENATE_BASE_AND_KEY (0x360) +#define CKM_CONCATENATE_BASE_AND_DATA (0x362) +#define CKM_CONCATENATE_DATA_AND_BASE (0x363) +#define CKM_XOR_BASE_AND_DATA (0x364) +#define CKM_EXTRACT_KEY_FROM_KEY (0x365) +#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370) +#define CKM_SSL3_MASTER_KEY_DERIVE (0x371) +#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372) +#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373) +#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374) +#define CKM_TLS_MASTER_KEY_DERIVE (0x375) +#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376) +#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377) +#define CKM_TLS_PRF (0x378) +#define CKM_SSL3_MD5_MAC (0x380) +#define CKM_SSL3_SHA1_MAC (0x381) +#define CKM_MD5_KEY_DERIVATION (0x390) +#define CKM_MD2_KEY_DERIVATION (0x391) +#define CKM_SHA1_KEY_DERIVATION (0x392) +#define CKM_SHA256_KEY_DERIVATION (0x393) +#define CKM_SHA384_KEY_DERIVATION (0x394) +#define CKM_SHA512_KEY_DERIVATION (0x395) +#define CKM_SHA224_KEY_DERIVATION (0x396) +#define CKM_PBE_MD2_DES_CBC (0x3a0) +#define CKM_PBE_MD5_DES_CBC (0x3a1) +#define CKM_PBE_MD5_CAST_CBC (0x3a2) +#define CKM_PBE_MD5_CAST3_CBC (0x3a3) +#define CKM_PBE_MD5_CAST5_CBC (0x3a4) +#define CKM_PBE_MD5_CAST128_CBC (0x3a4) +#define CKM_PBE_SHA1_CAST5_CBC (0x3a5) +#define CKM_PBE_SHA1_CAST128_CBC (0x3a5) +#define CKM_PBE_SHA1_RC4_128 (0x3a6) +#define CKM_PBE_SHA1_RC4_40 (0x3a7) +#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8) +#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9) +#define CKM_PBE_SHA1_RC2_128_CBC (0x3aa) +#define CKM_PBE_SHA1_RC2_40_CBC (0x3ab) +#define CKM_PKCS5_PBKD2 (0x3b0) +#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0) +#define CKM_WTLS_PRE_MASTER_KEY_GEN (0x3d0) +#define CKM_WTLS_MASTER_KEY_DERIVE (0x3d1) +#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC (0x3d2) +#define CKM_WTLS_PRF (0x3d3) +#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE (0x3d4) +#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE (0x3d5) +#define CKM_KEY_WRAP_LYNKS (0x400) +#define CKM_KEY_WRAP_SET_OAEP (0x401) +#define CKM_CMS_SIG (0x500) +#define CKM_KIP_DERIVE (0x510) +#define CKM_KIP_WRAP (0x511) +#define CKM_KIP_MAC (0x512) +#define CKM_CAMELLIA_KEY_GEN (0x550) +#define CKM_CAMELLIA_ECB (0x551) +#define CKM_CAMELLIA_CBC (0x552) +#define CKM_CAMELLIA_MAC (0x553) +#define CKM_CAMELLIA_MAC_GENERAL (0x554) +#define CKM_CAMELLIA_CBC_PAD (0x555) +#define CKM_CAMELLIA_ECB_ENCRYPT_DATA (0x556) +#define CKM_CAMELLIA_CBC_ENCRYPT_DATA (0x557) +#define CKM_CAMELLIA_CTR (0x558) +#define CKM_ARIA_KEY_GEN (0x560) +#define CKM_ARIA_ECB (0x561) +#define CKM_ARIA_CBC (0x562) +#define CKM_ARIA_MAC (0x563) +#define CKM_ARIA_MAC_GENERAL (0x564) +#define CKM_ARIA_CBC_PAD (0x565) +#define CKM_ARIA_ECB_ENCRYPT_DATA (0x566) +#define CKM_ARIA_CBC_ENCRYPT_DATA (0x567) +#define CKM_SEED_KEY_GEN (0x650) +#define CKM_SEED_ECB (0x651) +#define CKM_SEED_CBC (0x652) +#define CKM_SEED_MAC (0x653) +#define CKM_SEED_MAC_GENERAL (0x654) +#define CKM_SEED_CBC_PAD (0x655) +#define CKM_SEED_ECB_ENCRYPT_DATA (0x656) +#define CKM_SEED_CBC_ENCRYPT_DATA (0x657) +#define CKM_SKIPJACK_KEY_GEN (0x1000) +#define CKM_SKIPJACK_ECB64 (0x1001) +#define CKM_SKIPJACK_CBC64 (0x1002) +#define CKM_SKIPJACK_OFB64 (0x1003) +#define CKM_SKIPJACK_CFB64 (0x1004) +#define CKM_SKIPJACK_CFB32 (0x1005) +#define CKM_SKIPJACK_CFB16 (0x1006) +#define CKM_SKIPJACK_CFB8 (0x1007) +#define CKM_SKIPJACK_WRAP (0x1008) +#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009) +#define CKM_SKIPJACK_RELAYX (0x100a) +#define CKM_KEA_KEY_PAIR_GEN (0x1010) +#define CKM_KEA_KEY_DERIVE (0x1011) +#define CKM_FORTEZZA_TIMESTAMP (0x1020) +#define CKM_BATON_KEY_GEN (0x1030) +#define CKM_BATON_ECB128 (0x1031) +#define CKM_BATON_ECB96 (0x1032) +#define CKM_BATON_CBC128 (0x1033) +#define CKM_BATON_COUNTER (0x1034) +#define CKM_BATON_SHUFFLE (0x1035) +#define CKM_BATON_WRAP (0x1036) +#define CKM_ECDSA_KEY_PAIR_GEN (0x1040) +#define CKM_EC_KEY_PAIR_GEN (0x1040) +#define CKM_ECDSA (0x1041) +#define CKM_ECDSA_SHA1 (0x1042) +#define CKM_ECDSA_SHA224 (0x1043) +#define CKM_ECDSA_SHA256 (0x1044) +#define CKM_ECDSA_SHA384 (0x1045) +#define CKM_ECDSA_SHA512 (0x1046) +#define CKM_ECDH1_DERIVE (0x1050) +#define CKM_ECDH1_COFACTOR_DERIVE (0x1051) +#define CKM_ECMQV_DERIVE (0x1052) +#define CKM_JUNIPER_KEY_GEN (0x1060) +#define CKM_JUNIPER_ECB128 (0x1061) +#define CKM_JUNIPER_CBC128 (0x1062) +#define CKM_JUNIPER_COUNTER (0x1063) +#define CKM_JUNIPER_SHUFFLE (0x1064) +#define CKM_JUNIPER_WRAP (0x1065) +#define CKM_FASTHASH (0x1070) +#define CKM_AES_KEY_GEN (0x1080) +#define CKM_AES_ECB (0x1081) +#define CKM_AES_CBC (0x1082) +#define CKM_AES_MAC (0x1083) +#define CKM_AES_MAC_GENERAL (0x1084) +#define CKM_AES_CBC_PAD (0x1085) +#define CKM_AES_CTR (0x1086) +#define CKM_AES_GCM (0x1087) +#define CKM_AES_CCM (0x1088) +#define CKM_AES_CTS (0x1089) +#define CKM_AES_CMAC (0x108a) +#define CKM_AES_CMAC_GENERAL (0x108b) +#define CKM_BLOWFISH_KEY_GEN (0x1090) +#define CKM_BLOWFISH_CBC (0x1091) +#define CKM_TWOFISH_KEY_GEN (0x1092) +#define CKM_TWOFISH_CBC (0x1093) +#define CKM_BLOWFISH_CBC_PAD (0x1094) +#define CKM_TWOFISH_CBC_PAD (0x1095) +#define CKM_DES_ECB_ENCRYPT_DATA (0x1100) +#define CKM_DES_CBC_ENCRYPT_DATA (0x1101) +#define CKM_DES3_ECB_ENCRYPT_DATA (0x1102) +#define CKM_DES3_CBC_ENCRYPT_DATA (0x1103) +#define CKM_AES_ECB_ENCRYPT_DATA (0x1104) +#define CKM_AES_CBC_ENCRYPT_DATA (0x1105) +#define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200) +#define CKM_GOSTR3410 (0x1201) +#define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202) +#define CKM_GOSTR3410_KEY_WRAP (0x1203) +#define CKM_GOSTR3410_DERIVE (0x1204) +#define CKM_GOSTR3411 (0x1210) +#define CKM_GOSTR3411_HMAC (0x1211) +#define CKM_GOST28147_KEY_GEN (0x1220) +#define CKM_GOST28147_ECB (0x1221) +#define CKM_GOST28147 (0x1222) +#define CKM_GOST28147_MAC (0x1223) +#define CKM_GOST28147_KEY_WRAP (0x1224) +#define CKM_DSA_PARAMETER_GEN (0x2000) +#define CKM_DH_PKCS_PARAMETER_GEN (0x2001) +#define CKM_X9_42_DH_PARAMETER_GEN (0x2002) +#define CKM_AES_OFB (0x2104) +#define CKM_AES_CFB64 (0x2105) +#define CKM_AES_CFB8 (0x2106) +#define CKM_AES_CFB128 (0x2107) +#define CKM_AES_KEY_WRAP (0x2109) +#define CKM_AES_KEY_WRAP_PAD (0x210a) +#define CKM_RSA_PKCS_TPM_1_1 (0x4001) +#define CKM_RSA_PKCS_OAEPTPM_1_1 (0x4002) +#define CKM_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + +struct ck_mechanism +{ + ck_mechanism_type_t mechanism; + void *parameter; + unsigned long parameter_len; +}; + + +struct ck_mechanism_info +{ + unsigned long min_key_size; + unsigned long max_key_size; + ck_flags_t flags; +}; + +#define CKF_HW (1 << 0) +#define CKF_ENCRYPT (1 << 8) +#define CKF_DECRYPT (1 << 9) +#define CKF_DIGEST (1 << 10) +#define CKF_SIGN (1 << 11) +#define CKF_SIGN_RECOVER (1 << 12) +#define CKF_VERIFY (1 << 13) +#define CKF_VERIFY_RECOVER (1 << 14) +#define CKF_GENERATE (1 << 15) +#define CKF_GENERATE_KEY_PAIR (1 << 16) +#define CKF_WRAP (1 << 17) +#define CKF_UNWRAP (1 << 18) +#define CKF_DERIVE (1 << 19) +#define CKF_EC_F_P (1 << 20) +#define CKF_EC_F_2M (1 << 21) +#define CKF_EC_ECPARAMETERS (1 << 22) +#define CKF_EC_NAMEDCURVE (1 << 23) +#define CKF_EC_UNCOMPRESS (1 << 24) +#define CKF_EC_COMPRESS (1 << 25) +#define CKF_EXTENSION ((unsigned long) (1ul << 31)) + + +/* The following MGFs are defined */ +#define CKG_MGF1_SHA1 (0x00000001) +#define CKG_MGF1_SHA256 (0x00000002) +#define CKG_MGF1_SHA384 (0x00000003) +#define CKG_MGF1_SHA512 (0x00000004) +#define CKG_MGF1_SHA224 (0x00000005) + +#define CKZ_DATA_SPECIFIED (0x00000001) + +struct ck_rsa_pkcs_oaep_params { + ck_mechanism_type_t hash_alg; + unsigned long mgf; + unsigned long source; + void *source_data; + unsigned long source_data_len; +}; + +struct ck_rsa_pkcs_pss_params { + ck_mechanism_type_t hash_alg; + unsigned long mgf; + unsigned long slen; +}; + +typedef unsigned long ck_ec_kdf_type_t; + +/* The following EC Key Derivation Functions are defined */ +#define CKD_NULL (0x00000001) +#define CKD_SHA1_KDF (0x00000002) + +struct ck_ecdh1_derive_params { + ck_ec_kdf_type_t kdf; + unsigned long shared_data_len; + unsigned char *shared_data; + unsigned long public_data_len; + unsigned char *public_data; +}; + +struct ck_ecdh2_derive_params { + ck_ec_kdf_type_t kdf; + unsigned long shared_data_len; + unsigned char *shared_data; + unsigned long public_data_len; + unsigned char *public_data; + unsigned long private_data_len; + ck_object_handle_t private_data; + unsigned long public_data_len2; + unsigned char *public_data2; +}; + +struct ck_ecmqv_derive_params { + ck_ec_kdf_type_t kdf; + unsigned long shared_data_len; + unsigned char *shared_data; + unsigned long public_data_len; + unsigned char *public_data; + unsigned long private_data_len; + ck_object_handle_t private_data; + unsigned long public_data_len2; + unsigned char *public_data2; + ck_object_handle_t public_key; +}; + +typedef unsigned long ck_x9_42_dh_kdf_type_t; + +/* The following X9.42 DH key derivation functions are defined */ +#define CKD_SHA1_KDF_ASN1 (0x00000003) +#define CKD_SHA1_KDF_CONCATENATE (0x00000004) +#define CKD_SHA224_KDF (0x00000005) +#define CKD_SHA256_KDF (0x00000006) +#define CKD_SHA384_KDF (0x00000007) +#define CKD_SHA512_KDF (0x00000008) +#define CKD_CPDIVERSIFY_KDF (0x00000009) + +struct ck_x9_42_dh1_derive_params { + ck_x9_42_dh_kdf_type_t kdf; + unsigned long other_info_len; + unsigned char *other_info; + unsigned long public_data_len; + unsigned char *public_data; +}; + +struct ck_x9_42_dh2_derive_params { + ck_x9_42_dh_kdf_type_t kdf; + unsigned long other_info_len; + unsigned char *other_info; + unsigned long public_data_len; + unsigned char *public_data; + unsigned long private_data_len; + ck_object_handle_t private_data; + unsigned long public_data_len2; + unsigned char *public_data2; +}; + +struct ck_x9_42_mqv_derive_params { + ck_x9_42_dh_kdf_type_t kdf; + unsigned long other_info_len; + unsigned char *other_info; + unsigned long public_data_len; + unsigned char *public_data; + unsigned long private_data_len; + ck_object_handle_t private_data; + unsigned long public_data_len2; + unsigned char *public_data2; + ck_object_handle_t public_key; +}; + +struct ck_des_cbc_encrypt_data_params { + unsigned char iv[8]; + unsigned char *data; + unsigned long length; +}; + +struct ck_aes_cbc_encrypt_data_params { + unsigned char iv[16]; + unsigned char *data; + unsigned long length; +}; + +struct ck_key_derivation_string_data { + unsigned char *data; + unsigned long len; +}; + +/* Flags for C_WaitForSlotEvent. */ +#define CKF_DONT_BLOCK (1) + + +typedef unsigned long ck_rv_t; + + +typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session, + ck_notification_t event, void *application); + +/* Forward reference. */ +struct ck_function_list; + +#define _CK_DECLARE_FUNCTION(name, args) \ +typedef ck_rv_t (*CK_ ## name) args; \ +ck_rv_t CK_SPEC name args + +_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args)); +_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved)); +_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info)); +_CK_DECLARE_FUNCTION (C_GetFunctionList, + (struct ck_function_list **function_list)); + +_CK_DECLARE_FUNCTION (C_GetSlotList, + (unsigned char token_present, ck_slot_id_t *slot_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetSlotInfo, + (ck_slot_id_t slot_id, struct ck_slot_info *info)); +_CK_DECLARE_FUNCTION (C_GetTokenInfo, + (ck_slot_id_t slot_id, struct ck_token_info *info)); +_CK_DECLARE_FUNCTION (C_WaitForSlotEvent, + (ck_flags_t flags, ck_slot_id_t *slot, void *reserved)); +_CK_DECLARE_FUNCTION (C_GetMechanismList, + (ck_slot_id_t slot_id, + ck_mechanism_type_t *mechanism_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetMechanismInfo, + (ck_slot_id_t slot_id, ck_mechanism_type_t type, + struct ck_mechanism_info *info)); +_CK_DECLARE_FUNCTION (C_InitToken, + (ck_slot_id_t slot_id, unsigned char *pin, + unsigned long pin_len, unsigned char *label)); +_CK_DECLARE_FUNCTION (C_InitPIN, + (ck_session_handle_t session, unsigned char *pin, + unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_SetPIN, + (ck_session_handle_t session, unsigned char *old_pin, + unsigned long old_len, unsigned char *new_pin, + unsigned long new_len)); + +_CK_DECLARE_FUNCTION (C_OpenSession, + (ck_slot_id_t slot_id, ck_flags_t flags, + void *application, ck_notify_t notify, + ck_session_handle_t *session)); +_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id)); +_CK_DECLARE_FUNCTION (C_GetSessionInfo, + (ck_session_handle_t session, + struct ck_session_info *info)); +_CK_DECLARE_FUNCTION (C_GetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long *operation_state_len)); +_CK_DECLARE_FUNCTION (C_SetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long operation_state_len, + ck_object_handle_t encryption_key, + ck_object_handle_t authentiation_key)); +_CK_DECLARE_FUNCTION (C_Login, + (ck_session_handle_t session, ck_user_type_t user_type, + unsigned char *pin, unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_CreateObject, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count, ck_object_handle_t *object)); +_CK_DECLARE_FUNCTION (C_CopyObject, + (ck_session_handle_t session, ck_object_handle_t object, + struct ck_attribute *templ, unsigned long count, + ck_object_handle_t *new_object)); +_CK_DECLARE_FUNCTION (C_DestroyObject, + (ck_session_handle_t session, + ck_object_handle_t object)); +_CK_DECLARE_FUNCTION (C_GetObjectSize, + (ck_session_handle_t session, + ck_object_handle_t object, + unsigned long *size)); +_CK_DECLARE_FUNCTION (C_GetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_SetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjectsInit, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjects, + (ck_session_handle_t session, + ck_object_handle_t *object, + unsigned long max_object_count, + unsigned long *object_count)); +_CK_DECLARE_FUNCTION (C_FindObjectsFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_EncryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Encrypt, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *encrypted_data, + unsigned long *encrypted_data_len)); +_CK_DECLARE_FUNCTION (C_EncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_EncryptFinal, + (ck_session_handle_t session, + unsigned char *last_encrypted_part, + unsigned long *last_encrypted_part_len)); + +_CK_DECLARE_FUNCTION (C_DecryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Decrypt, + (ck_session_handle_t session, + unsigned char *encrypted_data, + unsigned long encrypted_data_len, + unsigned char *data, unsigned long *data_len)); +_CK_DECLARE_FUNCTION (C_DecryptUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_DecryptFinal, + (ck_session_handle_t session, + unsigned char *last_part, + unsigned long *last_part_len)); + +_CK_DECLARE_FUNCTION (C_DigestInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism)); +_CK_DECLARE_FUNCTION (C_Digest, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *digest, + unsigned long *digest_len)); +_CK_DECLARE_FUNCTION (C_DigestUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_DigestKey, + (ck_session_handle_t session, ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_DigestFinal, + (ck_session_handle_t session, + unsigned char *digest, + unsigned long *digest_len)); + +_CK_DECLARE_FUNCTION (C_SignInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Sign, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_SignFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_SignRecover, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); + +_CK_DECLARE_FUNCTION (C_VerifyInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Verify, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_VerifyFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_VerifyRecover, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len, + unsigned char *data, + unsigned long *data_len)); + +_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_SignEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); + +_CK_DECLARE_FUNCTION (C_GenerateKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *templ, + unsigned long count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_GenerateKeyPair, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *public_key_template, + unsigned long public_key_attribute_count, + struct ck_attribute *private_key_template, + unsigned long private_key_attribute_count, + ck_object_handle_t *public_key, + ck_object_handle_t *private_key)); +_CK_DECLARE_FUNCTION (C_WrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t wrapping_key, + ck_object_handle_t key, + unsigned char *wrapped_key, + unsigned long *wrapped_key_len)); +_CK_DECLARE_FUNCTION (C_UnwrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t unwrapping_key, + unsigned char *wrapped_key, + unsigned long wrapped_key_len, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_DeriveKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t base_key, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); + +_CK_DECLARE_FUNCTION (C_SeedRandom, + (ck_session_handle_t session, unsigned char *seed, + unsigned long seed_len)); +_CK_DECLARE_FUNCTION (C_GenerateRandom, + (ck_session_handle_t session, + unsigned char *random_data, + unsigned long random_len)); + +_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session)); + + +struct ck_function_list +{ + struct ck_version version; + CK_C_Initialize C_Initialize; + CK_C_Finalize C_Finalize; + CK_C_GetInfo C_GetInfo; + CK_C_GetFunctionList C_GetFunctionList; + CK_C_GetSlotList C_GetSlotList; + CK_C_GetSlotInfo C_GetSlotInfo; + CK_C_GetTokenInfo C_GetTokenInfo; + CK_C_GetMechanismList C_GetMechanismList; + CK_C_GetMechanismInfo C_GetMechanismInfo; + CK_C_InitToken C_InitToken; + CK_C_InitPIN C_InitPIN; + CK_C_SetPIN C_SetPIN; + CK_C_OpenSession C_OpenSession; + CK_C_CloseSession C_CloseSession; + CK_C_CloseAllSessions C_CloseAllSessions; + CK_C_GetSessionInfo C_GetSessionInfo; + CK_C_GetOperationState C_GetOperationState; + CK_C_SetOperationState C_SetOperationState; + CK_C_Login C_Login; + CK_C_Logout C_Logout; + CK_C_CreateObject C_CreateObject; + CK_C_CopyObject C_CopyObject; + CK_C_DestroyObject C_DestroyObject; + CK_C_GetObjectSize C_GetObjectSize; + CK_C_GetAttributeValue C_GetAttributeValue; + CK_C_SetAttributeValue C_SetAttributeValue; + CK_C_FindObjectsInit C_FindObjectsInit; + CK_C_FindObjects C_FindObjects; + CK_C_FindObjectsFinal C_FindObjectsFinal; + CK_C_EncryptInit C_EncryptInit; + CK_C_Encrypt C_Encrypt; + CK_C_EncryptUpdate C_EncryptUpdate; + CK_C_EncryptFinal C_EncryptFinal; + CK_C_DecryptInit C_DecryptInit; + CK_C_Decrypt C_Decrypt; + CK_C_DecryptUpdate C_DecryptUpdate; + CK_C_DecryptFinal C_DecryptFinal; + CK_C_DigestInit C_DigestInit; + CK_C_Digest C_Digest; + CK_C_DigestUpdate C_DigestUpdate; + CK_C_DigestKey C_DigestKey; + CK_C_DigestFinal C_DigestFinal; + CK_C_SignInit C_SignInit; + CK_C_Sign C_Sign; + CK_C_SignUpdate C_SignUpdate; + CK_C_SignFinal C_SignFinal; + CK_C_SignRecoverInit C_SignRecoverInit; + CK_C_SignRecover C_SignRecover; + CK_C_VerifyInit C_VerifyInit; + CK_C_Verify C_Verify; + CK_C_VerifyUpdate C_VerifyUpdate; + CK_C_VerifyFinal C_VerifyFinal; + CK_C_VerifyRecoverInit C_VerifyRecoverInit; + CK_C_VerifyRecover C_VerifyRecover; + CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; + CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; + CK_C_SignEncryptUpdate C_SignEncryptUpdate; + CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; + CK_C_GenerateKey C_GenerateKey; + CK_C_GenerateKeyPair C_GenerateKeyPair; + CK_C_WrapKey C_WrapKey; + CK_C_UnwrapKey C_UnwrapKey; + CK_C_DeriveKey C_DeriveKey; + CK_C_SeedRandom C_SeedRandom; + CK_C_GenerateRandom C_GenerateRandom; + CK_C_GetFunctionStatus C_GetFunctionStatus; + CK_C_CancelFunction C_CancelFunction; + CK_C_WaitForSlotEvent C_WaitForSlotEvent; +}; + + +typedef ck_rv_t (*ck_createmutex_t) (void **mutex); +typedef ck_rv_t (*ck_destroymutex_t) (void *mutex); +typedef ck_rv_t (*ck_lockmutex_t) (void *mutex); +typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex); + + +struct ck_c_initialize_args +{ + ck_createmutex_t create_mutex; + ck_destroymutex_t destroy_mutex; + ck_lockmutex_t lock_mutex; + ck_unlockmutex_t unlock_mutex; + ck_flags_t flags; + void *reserved; +}; + + +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1 << 0) +#define CKF_OS_LOCKING_OK (1 << 1) + +#define CKR_OK (0) +#define CKR_CANCEL (1) +#define CKR_HOST_MEMORY (2) +#define CKR_SLOT_ID_INVALID (3) +#define CKR_GENERAL_ERROR (5) +#define CKR_FUNCTION_FAILED (6) +#define CKR_ARGUMENTS_BAD (7) +#define CKR_NO_EVENT (8) +#define CKR_NEED_TO_CREATE_THREADS (9) +#define CKR_CANT_LOCK (0xa) +#define CKR_ATTRIBUTE_READ_ONLY (0x10) +#define CKR_ATTRIBUTE_SENSITIVE (0x11) +#define CKR_ATTRIBUTE_TYPE_INVALID (0x12) +#define CKR_ATTRIBUTE_VALUE_INVALID (0x13) +#define CKR_COPY_PROHIBITED (0x1A) +#define CKR_DATA_INVALID (0x20) +#define CKR_DATA_LEN_RANGE (0x21) +#define CKR_DEVICE_ERROR (0x30) +#define CKR_DEVICE_MEMORY (0x31) +#define CKR_DEVICE_REMOVED (0x32) +#define CKR_ENCRYPTED_DATA_INVALID (0x40) +#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41) +#define CKR_FUNCTION_CANCELED (0x50) +#define CKR_FUNCTION_NOT_PARALLEL (0x51) +#define CKR_FUNCTION_NOT_SUPPORTED (0x54) +#define CKR_KEY_HANDLE_INVALID (0x60) +#define CKR_KEY_SIZE_RANGE (0x62) +#define CKR_KEY_TYPE_INCONSISTENT (0x63) +#define CKR_KEY_NOT_NEEDED (0x64) +#define CKR_KEY_CHANGED (0x65) +#define CKR_KEY_NEEDED (0x66) +#define CKR_KEY_INDIGESTIBLE (0x67) +#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68) +#define CKR_KEY_NOT_WRAPPABLE (0x69) +#define CKR_KEY_UNEXTRACTABLE (0x6a) +#define CKR_MECHANISM_INVALID (0x70) +#define CKR_MECHANISM_PARAM_INVALID (0x71) +#define CKR_OBJECT_HANDLE_INVALID (0x82) +#define CKR_OPERATION_ACTIVE (0x90) +#define CKR_OPERATION_NOT_INITIALIZED (0x91) +#define CKR_PIN_INCORRECT (0xa0) +#define CKR_PIN_INVALID (0xa1) +#define CKR_PIN_LEN_RANGE (0xa2) +#define CKR_PIN_EXPIRED (0xa3) +#define CKR_PIN_LOCKED (0xa4) +#define CKR_SESSION_CLOSED (0xb0) +#define CKR_SESSION_COUNT (0xb1) +#define CKR_SESSION_HANDLE_INVALID (0xb3) +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4) +#define CKR_SESSION_READ_ONLY (0xb5) +#define CKR_SESSION_EXISTS (0xb6) +#define CKR_SESSION_READ_ONLY_EXISTS (0xb7) +#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8) +#define CKR_SIGNATURE_INVALID (0xc0) +#define CKR_SIGNATURE_LEN_RANGE (0xc1) +#define CKR_TEMPLATE_INCOMPLETE (0xd0) +#define CKR_TEMPLATE_INCONSISTENT (0xd1) +#define CKR_TOKEN_NOT_PRESENT (0xe0) +#define CKR_TOKEN_NOT_RECOGNIZED (0xe1) +#define CKR_TOKEN_WRITE_PROTECTED (0xe2) +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0) +#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1) +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2) +#define CKR_USER_ALREADY_LOGGED_IN (0x100) +#define CKR_USER_NOT_LOGGED_IN (0x101) +#define CKR_USER_PIN_NOT_INITIALIZED (0x102) +#define CKR_USER_TYPE_INVALID (0x103) +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104) +#define CKR_USER_TOO_MANY_TYPES (0x105) +#define CKR_WRAPPED_KEY_INVALID (0x110) +#define CKR_WRAPPED_KEY_LEN_RANGE (0x112) +#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113) +#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114) +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115) +#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120) +#define CKR_RANDOM_NO_RNG (0x121) +#define CKR_DOMAIN_PARAMS_INVALID (0x130) +#define CKR_BUFFER_TOO_SMALL (0x150) +#define CKR_SAVED_STATE_INVALID (0x160) +#define CKR_INFORMATION_SENSITIVE (0x170) +#define CKR_STATE_UNSAVEABLE (0x180) +#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190) +#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191) +#define CKR_MUTEX_BAD (0x1a0) +#define CKR_MUTEX_NOT_LOCKED (0x1a1) +#define CKR_NEW_PIN_MODE (0x1b0) +#define CKR_NEXT_OTP (0x1b1) +#define CKR_EXCEEDED_MAX_ITERATIONS (0x1b5) +#define CKR_FIPS_SELF_TEST_FAILED (0x1b6) +#define CKR_LIBRARY_LOAD_FAILED (0x1b7) +#define CKR_PIN_TOO_WEAK (0x1b8) +#define CKR_PUBLIC_KEY_INVALID (0x1b9) +#define CKR_FUNCTION_REJECTED (0x200) +#define CKR_VENDOR_DEFINED ((unsigned long) (1ul << 31)) + + + +/* Compatibility layer. */ + +#ifdef CRYPTOKI_COMPAT + +#undef CK_DEFINE_FUNCTION +#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name + +/* For NULL. */ +#include + +typedef unsigned char CK_BYTE; +typedef unsigned char CK_CHAR; +typedef unsigned char CK_UTF8CHAR; +typedef unsigned char CK_BBOOL; +typedef unsigned long int CK_ULONG; +typedef long int CK_LONG; +typedef CK_BYTE *CK_BYTE_PTR; +typedef CK_CHAR *CK_CHAR_PTR; +typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR; +typedef CK_ULONG *CK_ULONG_PTR; +typedef void *CK_VOID_PTR; +typedef void **CK_VOID_PTR_PTR; +#define CK_FALSE 0 +#define CK_TRUE 1 +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#endif + +typedef struct ck_version CK_VERSION; +typedef struct ck_version *CK_VERSION_PTR; + +typedef struct ck_info CK_INFO; +typedef struct ck_info *CK_INFO_PTR; + +typedef ck_slot_id_t *CK_SLOT_ID_PTR; + +typedef struct ck_slot_info CK_SLOT_INFO; +typedef struct ck_slot_info *CK_SLOT_INFO_PTR; + +typedef struct ck_token_info CK_TOKEN_INFO; +typedef struct ck_token_info *CK_TOKEN_INFO_PTR; + +typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR; + +typedef struct ck_session_info CK_SESSION_INFO; +typedef struct ck_session_info *CK_SESSION_INFO_PTR; + +typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR; + +typedef ck_object_class_t *CK_OBJECT_CLASS_PTR; + +typedef struct ck_attribute CK_ATTRIBUTE; +typedef struct ck_attribute *CK_ATTRIBUTE_PTR; + +typedef struct ck_date CK_DATE; +typedef struct ck_date *CK_DATE_PTR; + +typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; + +typedef struct ck_mechanism CK_MECHANISM; +typedef struct ck_mechanism *CK_MECHANISM_PTR; + +typedef struct ck_mechanism_info CK_MECHANISM_INFO; +typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; + +typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS; +typedef struct ck_rsa_pkcs_oaep_params *CK_RSA_PKCS_OAEP_PARAMS_PTR; + +typedef struct ck_rsa_pkcs_pss_params CK_RSA_PKCS_PSS_PARAMS; +typedef struct ck_rsa_pkcs_pss_params *CK_RSA_PKCS_PSS_PARAMS_PTR; + +typedef struct ck_ecdh1_derive_params CK_ECDH1_DERIVE_PARAMS; +typedef struct ck_ecdh1_derive_params *CK_ECDH1_DERIVE_PARAMS_PTR; + +typedef struct ck_des_cbc_encrypt_data_params CK_DES_CBC_ENCRYPT_DATA_PARAMS; +typedef struct ck_des_cbc_encrypt_data_params *CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR; + +typedef struct ck_aes_cbc_encrypt_data_params CK_AES_CBC_ENCRYPT_DATA_PARAMS; +typedef struct ck_aes_cbc_encrypt_data_params *CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; + +typedef struct ck_key_derivation_string_data CK_KEY_DERIVATION_STRING_DATA; +typedef struct ck_key_derivation_string_data *CK_KEY_DERIVATION_STRING_DATA_PTR; + +typedef struct ck_function_list CK_FUNCTION_LIST; +typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; +typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; + +typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; +typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; + +#define NULL_PTR NULL + +/* Delete the helper macros defined at the top of the file. */ +#undef ck_flags_t +#undef ck_version + +#undef ck_info +#undef cryptoki_version +#undef manufacturer_id +#undef library_description +#undef library_version + +#undef ck_notification_t +#undef ck_slot_id_t + +#undef ck_slot_info +#undef slot_description +#undef hardware_version +#undef firmware_version + +#undef ck_token_info +#undef serial_number +#undef max_session_count +#undef session_count +#undef max_rw_session_count +#undef rw_session_count +#undef max_pin_len +#undef min_pin_len +#undef total_public_memory +#undef free_public_memory +#undef total_private_memory +#undef free_private_memory +#undef utc_time + +#undef ck_session_handle_t +#undef ck_user_type_t +#undef ck_state_t + +#undef ck_session_info +#undef slot_id +#undef device_error + +#undef ck_object_handle_t +#undef ck_object_class_t +#undef ck_hw_feature_type_t +#undef ck_key_type_t +#undef ck_certificate_type_t +#undef ck_attribute_type_t + +#undef ck_attribute +#undef value +#undef value_len + +#undef ck_date + +#undef ck_mechanism_type_t + +#undef ck_mechanism +#undef parameter +#undef parameter_len + +#undef ck_mechanism_info +#undef min_key_size +#undef max_key_size + +#undef ck_rsa_pkcs_oaep_params +#undef hash_alg +#undef source_data +#undef source_data_len +#undef slen + +#undef ck_ec_kdf_type_t +#undef shared_data_len +#undef shared_data +#undef public_data_len +#undef public_data +#undef private_data_len +#undef private_data +#undef public_data_len2 +#undef public_data2 +#undef public_key + +#undef ck_x9_42_dh_kdf_type_t +#undef other_info_len +#undef other_info + +#undef data +#undef len + +#undef ck_rv_t +#undef ck_notify_t + +#undef ck_function_list + +#undef ck_createmutex_t +#undef ck_destroymutex_t +#undef ck_lockmutex_t +#undef ck_unlockmutex_t + +#undef ck_c_initialize_args +#undef create_mutex +#undef destroy_mutex +#undef lock_mutex +#undef unlock_mutex +#undef reserved + +#endif /* CRYPTOKI_COMPAT */ + + +/* System dependencies. */ +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) +#pragma pack(pop, cryptoki) +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* PKCS11_H */ diff --git a/third_party/heimdal/lib/hx509/req.c b/third_party/heimdal/lib/hx509/req.c new file mode 100644 index 0000000..c8be1d4 --- /dev/null +++ b/third_party/heimdal/lib/hx509/req.c @@ -0,0 +1,1681 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +#include + +typedef struct abitstring_s { + unsigned char *feats; + size_t feat_bytes; +} *abitstring; + +struct hx509_request_data { + hx509_context context; + hx509_name name; + SubjectPublicKeyInfo key; + KeyUsage ku; + ExtKeyUsage eku; + GeneralNames san; + BasicConstraints bc; + struct abitstring_s authorized_EKUs; + struct abitstring_s authorized_SANs; + uint32_t nunsupported_crit; /* Count of unsupported critical features requested */ + uint32_t nunsupported_opt; /* Count of unsupported optional features requested */ + uint32_t nauthorized; /* Count of supported features authorized */ + uint32_t ca_is_authorized:1; + uint32_t ku_are_authorized:1; + uint32_t include_BasicConstraints:1; +}; + +/** + * Allocate and initialize an hx509_request structure representing a PKCS#10 + * certificate signing request. + * + * @param context An hx509 context. + * @param req Where to put the new hx509_request object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_init(hx509_context context, hx509_request *req) +{ + *req = calloc(1, sizeof(**req)); + if (*req == NULL) + return ENOMEM; + + (*req)->context = context; + return 0; +} + +/** + * Free a certificate signing request object. + * + * @param req A pointer to the hx509_request to free. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_request_free(hx509_request *reqp) +{ + hx509_request req = *reqp; + + *reqp = NULL; + if (req == NULL) + return; + if (req->name) + hx509_name_free(&req->name); + free(req->authorized_EKUs.feats); + free(req->authorized_SANs.feats); + free_SubjectPublicKeyInfo(&req->key); + free_ExtKeyUsage(&req->eku); + free_GeneralNames(&req->san); + free_BasicConstraints(&req->bc); + memset(req, 0, sizeof(*req)); + free(req); +} + +/** + * Make the CSR request a CA certificate + * + * @param context An hx509 context. + * @param req The hx509_request to alter. + * @param pathLenConstraint the pathLenConstraint for the BasicConstraints (optional) + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_set_cA(hx509_context context, + hx509_request req, + unsigned *pathLenConstraint) +{ + req->bc.cA = 1; + if (pathLenConstraint) { + if (req->bc.pathLenConstraint == NULL) + req->bc.pathLenConstraint = malloc(sizeof(*pathLenConstraint)); + if (req->bc.pathLenConstraint == NULL) + return ENOMEM; + *req->bc.pathLenConstraint = *pathLenConstraint; + } + return 0; +} + +/** + * Make the CSR request an EE (end-entity, i.e., not a CA) certificate + * + * @param context An hx509 context. + * @param req The hx509_request to alter. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_request_set_eE(hx509_context context, hx509_request req) +{ + req->bc.cA = 0; + free(req->bc.pathLenConstraint); + req->include_BasicConstraints = 1; + req->ca_is_authorized = 0; +} + +/** + * Set the subjectName of the CSR. + * + * @param context An hx509 context. + * @param req The hx509_request to alter. + * @param name The subjectName. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_set_name(hx509_context context, + hx509_request req, + hx509_name name) +{ + if (req->name) + hx509_name_free(&req->name); + if (name) { + int ret = hx509_name_copy(context, name, &req->name); + if (ret) + return ret; + } + return 0; +} + +/** + * Get the subject name requested by a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param name Where to put the name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_name(hx509_context context, + hx509_request req, + hx509_name *name) +{ + if (req->name == NULL) { + hx509_set_error_string(context, 0, EINVAL, "Request has no name"); + return EINVAL; + } + return hx509_name_copy(context, req->name, name); +} + +/** + * Set the subject public key requested by a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param key The public key. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_set_SubjectPublicKeyInfo(hx509_context context, + hx509_request req, + const SubjectPublicKeyInfo *key) +{ + free_SubjectPublicKeyInfo(&req->key); + return copy_SubjectPublicKeyInfo(key, &req->key); +} + +/** + * Get the subject public key requested by a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param key Where to put the key. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_SubjectPublicKeyInfo(hx509_context context, + hx509_request req, + SubjectPublicKeyInfo *key) +{ + return copy_SubjectPublicKeyInfo(&req->key, key); +} + +/** + * Set the key usage requested by a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param ku The key usage. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_set_ku(hx509_context context, hx509_request req, KeyUsage ku) +{ + uint64_t n = KeyUsage2int(ku); + + if ((KeyUsage2int(req->ku) & n) != n) + req->ku_are_authorized = 0; + req->ku = ku; + return 0; +} + +/** + * Get the key usage requested by a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param ku Where to put the key usage. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_ku(hx509_context context, hx509_request req, KeyUsage *ku) +{ + *ku = req->ku; + return 0; +} + +/** + * Add an extended key usage OID to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param oid The EKU OID. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_eku(hx509_context context, + hx509_request req, + const heim_oid *oid) +{ + void *val; + int ret; + + val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1)); + if (val == NULL) + return ENOMEM; + req->eku.val = val; + + ret = der_copy_oid(oid, &req->eku.val[req->eku.len]); + if (ret) + return ret; + + req->eku.len += 1; + + return 0; +} + +/** + * Add a GeneralName (Jabber ID) subject alternative name to a CSR. + * + * XXX Make this take a heim_octet_string, not a GeneralName*. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param gn The GeneralName object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_GeneralName(hx509_context context, + hx509_request req, + const GeneralName *gn) +{ + return add_GeneralNames(&req->san, gn); +} + +static int +add_utf8_other_san(hx509_context context, + GeneralNames *gns, + const heim_oid *oid, + const char *s) +{ + const PKIXXmppAddr us = (const PKIXXmppAddr)(uintptr_t)s; + GeneralName gn; + size_t size; + int ret; + + gn.element = choice_GeneralName_otherName; + gn.u.otherName.type_id.length = 0; + gn.u.otherName.type_id.components = 0; + gn.u.otherName.value.data = NULL; + gn.u.otherName.value.length = 0; + ret = der_copy_oid(oid, &gn.u.otherName.type_id); + if (ret == 0) + ASN1_MALLOC_ENCODE(PKIXXmppAddr, gn.u.otherName.value.data, + gn.u.otherName.value.length, &us, &size, ret); + if (ret == 0 && size != gn.u.otherName.value.length) + _hx509_abort("internal ASN.1 encoder error"); + if (ret == 0) + ret = add_GeneralNames(gns, &gn); + free_GeneralName(&gn); + if (ret) + hx509_set_error_string(context, 0, ret, "Out of memory"); + return ret; +} + +/** + * Add an xmppAddr (Jabber ID) subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param jid The XMPP address. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_xmpp_name(hx509_context context, + hx509_request req, + const char *jid) +{ + return add_utf8_other_san(context, &req->san, + &asn1_oid_id_pkix_on_xmppAddr, jid); +} + +/** + * Add a Microsoft UPN subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param hostname The XMPP address. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_ms_upn_name(hx509_context context, + hx509_request req, + const char *upn) +{ + return add_utf8_other_san(context, &req->san, &asn1_oid_id_pkinit_ms_san, + upn); +} + +/** + * Add a dNSName (hostname) subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param hostname The fully-qualified hostname. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_dns_name(hx509_context context, + hx509_request req, + const char *hostname) +{ + GeneralName name; + + memset(&name, 0, sizeof(name)); + name.element = choice_GeneralName_dNSName; + name.u.dNSName.data = rk_UNCONST(hostname); + name.u.dNSName.length = strlen(hostname); + + return add_GeneralNames(&req->san, &name); +} + +/** + * Add a dnsSRV (_service.hostname) subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param dnssrv The DNS SRV name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_dns_srv(hx509_context context, + hx509_request req, + const char *dnssrv) +{ + GeneralName gn; + SRVName n; + size_t size; + int ret; + + memset(&n, 0, sizeof(n)); + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_otherName; + gn.u.otherName.type_id.length = 0; + gn.u.otherName.type_id.components = 0; + gn.u.otherName.value.data = NULL; + gn.u.otherName.value.length = 0; + n.length = strlen(dnssrv); + n.data = (void *)(uintptr_t)dnssrv; + ASN1_MALLOC_ENCODE(SRVName, + gn.u.otherName.value.data, + gn.u.otherName.value.length, &n, &size, ret); + if (ret == 0) + ret = der_copy_oid(&asn1_oid_id_pkix_on_dnsSRV, &gn.u.otherName.type_id); + if (ret == 0) + ret = add_GeneralNames(&req->san, &gn); + free_GeneralName(&gn); + return ret; +} + +/** + * Add an rfc822Name (e-mail address) subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param email The e-mail address. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_email(hx509_context context, + hx509_request req, + const char *email) +{ + GeneralName name; + + memset(&name, 0, sizeof(name)); + name.element = choice_GeneralName_rfc822Name; + name.u.rfc822Name.data = rk_UNCONST(email); + name.u.rfc822Name.length = strlen(email); + + return add_GeneralNames(&req->san, &name); +} + +/** + * Add a registeredID (OID) subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param oid The OID. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_registered(hx509_context context, + hx509_request req, + heim_oid *oid) +{ + GeneralName name; + int ret; + + memset(&name, 0, sizeof(name)); + name.element = choice_GeneralName_registeredID; + ret = der_copy_oid(oid, &name.u.registeredID); + if (ret) + return ret; + ret = add_GeneralNames(&req->san, &name); + free_GeneralName(&name); + return ret; +} + +/** + * Add a Kerberos V5 principal subject alternative name to a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param princ The Kerberos principal name. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_add_pkinit(hx509_context context, + hx509_request req, + const char *princ) +{ + KRB5PrincipalName kn; + GeneralName gn; + int ret; + + memset(&kn, 0, sizeof(kn)); + memset(&gn, 0, sizeof(gn)); + gn.element = choice_GeneralName_otherName; + gn.u.otherName.type_id.length = 0; + gn.u.otherName.type_id.components = 0; + gn.u.otherName.value.data = NULL; + gn.u.otherName.value.length = 0; + ret = der_copy_oid(&asn1_oid_id_pkinit_san, &gn.u.otherName.type_id); + if (ret == 0) + ret = _hx509_make_pkinit_san(context, princ, &gn.u.otherName.value); + if (ret == 0) + ret = add_GeneralNames(&req->san, &gn); + free_GeneralName(&gn); + return ret; +} + +/* XXX Add DNSSRV and other SANs */ + +static int +get_exts(hx509_context context, + const hx509_request req, + Extensions *exts) +{ + size_t size; + int ret = 0; + + exts->val = NULL; + exts->len = 0; + + if (req->bc.cA || req->include_BasicConstraints) { + Extension e; + + /* + * If `!req->bc.cA' then we don't include BasicConstraints unless + * hx509_request_set_eE() was called on this request, and in that case + * we make this extension non-critical. We do this to emulate Dell + * iDRAC CSR-making software. + * + * If `req->bc.cA' then we make the BasicConstraints critical, + * obviously. + */ + memset(&e, 0, sizeof(e)); + e.critical = req->bc.cA ? 1 : 0; + if (ret == 0) + ASN1_MALLOC_ENCODE(BasicConstraints, e.extnValue.data, e.extnValue.length, + &req->bc, &size, ret); + if (ret == 0) + ret = der_copy_oid(&asn1_oid_id_x509_ce_basicConstraints, &e.extnID); + if (ret == 0) + ret = add_Extensions(exts, &e); + free_Extension(&e); + } + if (KeyUsage2int(req->ku)) { + Extension e; + + memset(&e, 0, sizeof(e)); + /* The critical field needs to be made DEFAULT FALSE... */ + e.critical = 1; + if (ret == 0) + ASN1_MALLOC_ENCODE(KeyUsage, e.extnValue.data, e.extnValue.length, + &req->ku, &size, ret); + if (ret == 0) + ret = der_copy_oid(&asn1_oid_id_x509_ce_keyUsage, &e.extnID); + if (ret == 0) + ret = add_Extensions(exts, &e); + free_Extension(&e); + } + if (ret == 0 && req->eku.len) { + Extension e; + + memset(&e, 0, sizeof(e)); + e.critical = 1; + if (ret == 0) + ASN1_MALLOC_ENCODE(ExtKeyUsage, + e.extnValue.data, e.extnValue.length, + &req->eku, &size, ret); + if (ret == 0) + ret = der_copy_oid(&asn1_oid_id_x509_ce_extKeyUsage, &e.extnID); + if (ret == 0) + ret = add_Extensions(exts, &e); + free_Extension(&e); + } + if (ret == 0 && req->san.len) { + Extension e; + + memset(&e, 0, sizeof(e)); + /* + * SANs are critical when the subject Name is empty. + * + * The empty DN check could probably stand to be a function we export. + */ + e.critical = FALSE; + if (req->name && + req->name->der_name.element == choice_Name_rdnSequence && + req->name->der_name.u.rdnSequence.len == 0) + e.critical = 1; + if (ret == 0) + ASN1_MALLOC_ENCODE(GeneralNames, + e.extnValue.data, e.extnValue.length, + &req->san, + &size, ret); + if (ret == 0) + ret = der_copy_oid(&asn1_oid_id_x509_ce_subjectAltName, &e.extnID); + if (ret == 0) + ret = add_Extensions(exts, &e); + free_Extension(&e); + } + + return ret; +} + +/** + * Get the KU/EKUs/SANs set on a request as a DER-encoding of Extensions. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param exts_der Where to put the DER-encoded Extensions. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_exts(hx509_context context, + const hx509_request req, + heim_octet_string *exts_der) +{ + Extensions exts; + size_t size; + int ret; + + exts_der->data = NULL; + exts_der->length = 0; + ret = get_exts(context, req, &exts); + if (ret == 0 && exts.len /* Extensions has a min size constraint of 1 */) + ASN1_MALLOC_ENCODE(Extensions, exts_der->data, exts_der->length, + &exts, &size, ret); + free_Extensions(&exts); + return ret; +} + +/* XXX Add PEM */ + +/** + * Encode a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param signer The private key corresponding to the CSR's subject public key. + * @param request Where to put the DER-encoded CSR. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_to_pkcs10(hx509_context context, + const hx509_request req, + const hx509_private_key signer, + heim_octet_string *request) +{ + CertificationRequest r; + Extensions exts; + heim_octet_string data; + size_t size; + int ret; + + request->data = NULL; + request->length = 0; + + data.length = 0; + data.data = NULL; + + if (req->name == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "PKCS10 needs to have a subject"); + return EINVAL; + } + + memset(&r, 0, sizeof(r)); + + /* Setup CSR */ + r.certificationRequestInfo.version = pkcs10_v1; + ret = copy_Name(&req->name->der_name, + &r.certificationRequestInfo.subject); + if (ret == 0) + ret = copy_SubjectPublicKeyInfo(&req->key, + &r.certificationRequestInfo.subjectPKInfo); + + /* Encode extReq attribute with requested Certificate Extensions */ + + if (ret == 0) + ret = get_exts(context, req, &exts); + if (ret == 0 && exts.len) { + Attribute *a = NULL; /* Quiet VC */ + heim_any extns; + + extns.data = NULL; + extns.length = 0; + r.certificationRequestInfo.attributes = + calloc(1, sizeof(r.certificationRequestInfo.attributes[0])); + if (r.certificationRequestInfo.attributes == NULL) + ret = ENOMEM; + if (ret == 0) { + r.certificationRequestInfo.attributes[0].len = 1; + r.certificationRequestInfo.attributes[0].val = + calloc(1, sizeof(r.certificationRequestInfo.attributes[0].val[0])); + if (r.certificationRequestInfo.attributes[0].val == NULL) + ret = ENOMEM; + if (ret == 0) + a = r.certificationRequestInfo.attributes[0].val; + } + if (ret == 0) + ASN1_MALLOC_ENCODE(Extensions, extns.data, extns.length, + &exts, &size, ret); + if (ret == 0 && a) + ret = der_copy_oid(&asn1_oid_id_pkcs9_extReq, &a->type); + if (ret == 0) + ret = add_AttributeValues(&a->value, &extns); + free_heim_any(&extns); + } + + /* Encode CSR body for signing */ + if (ret == 0) + ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length, + &r.certificationRequestInfo, &size, ret); + if (ret == 0 && data.length != size) + abort(); + + /* Self-sign CSR body */ + if (ret == 0) { + ret = _hx509_create_signature_bitstring(context, signer, + _hx509_crypto_default_sig_alg, + &data, + &r.signatureAlgorithm, + &r.signature); + } + free(data.data); + + /* Encode CSR */ + if (ret == 0) + ASN1_MALLOC_ENCODE(CertificationRequest, request->data, request->length, + &r, &size, ret); + if (ret == 0 && request->length != size) + abort(); + + free_CertificationRequest(&r); + free_Extensions(&exts); + return ret; +} + +/** + * Parse an encoded CSR and verify its self-signature. + * + * @param context An hx509 context. + * @param der The DER-encoded CSR. + * @param req Where to put request object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_parse_der(hx509_context context, + heim_octet_string *der, + hx509_request *req) +{ + CertificationRequestInfo *rinfo = NULL; + CertificationRequest r; + hx509_cert signer = NULL; + Extensions exts; + size_t i, size; + int ret; + + memset(&exts, 0, sizeof(exts)); + + /* Initial setup and decoding of CSR */ + ret = hx509_request_init(context, req); + if (ret) + return ret; + ret = decode_CertificationRequest(der->data, der->length, &r, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to decode CSR"); + free(*req); + *req = NULL; + return ret; + } + rinfo = &r.certificationRequestInfo; + + /* + * Setup a 'signer' for verifying the self-signature for proof of + * possession. + * + * Sadly we need a "certificate" here because _hx509_verify_signature_*() + * functions want one as a signer even though all the verification + * functions that use the signer argument only ever use the spki of the + * signer certificate. + * + * FIXME Change struct signature_alg's verify_signature's prototype to use + * an spki instead of an hx509_cert as the signer! The we won't have + * to do this. + */ + if (ret == 0) { + Certificate c; + memset(&c, 0, sizeof(c)); + c.tbsCertificate.subjectPublicKeyInfo = rinfo->subjectPKInfo; + if ((signer = hx509_cert_init(context, &c, NULL)) == NULL) + ret = ENOMEM; + } + + /* Verify the signature */ + if (ret == 0) + ret = _hx509_verify_signature_bitstring(context, signer, + &r.signatureAlgorithm, + &rinfo->_save, + &r.signature); + if (ret) + hx509_set_error_string(context, 0, ret, + "CSR signature verification failed"); + hx509_cert_free(signer); + + /* Populate the hx509_request */ + if (ret == 0) + ret = hx509_request_set_SubjectPublicKeyInfo(context, *req, + &rinfo->subjectPKInfo); + if (ret == 0) + ret = _hx509_name_from_Name(&rinfo->subject, &(*req)->name); + + /* Extract KUs, EKUs, and SANs from the CSR's attributes */ + if (ret || !rinfo->attributes || !rinfo->attributes[0].len) + goto out; + + for (i = 0; ret == 0 && i < rinfo->attributes[0].len; i++) { + Attribute *a = &rinfo->attributes[0].val[i]; + heim_any *av = NULL; + + /* We only support Extensions request attributes */ + if (der_heim_oid_cmp(&a->type, &asn1_oid_id_pkcs9_extReq) != 0) { + char *oidstr = NULL; + + /* + * We need an HX509_TRACE facility for this sort of warning. + * + * We'd put the warning in the context and then allow the caller to + * extract and reset the warning. + * + * FIXME + */ + der_print_heim_oid(&a->type, '.', &oidstr); + warnx("Unknown or unsupported CSR attribute %s", + oidstr ? oidstr : ""); + free(oidstr); + continue; + } + if (!a->value.val) + continue; + + av = a->value.val; + ret = decode_Extensions(av->data, av->length, &exts, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, + "CSR signature verification failed " + "due to invalid extReq attribute"); + goto out; + } + } + for (i = 0; ret == 0 && i < exts.len; i++) { + const char *what = ""; + Extension *e = &exts.val[i]; + + if (der_heim_oid_cmp(&e->extnID, + &asn1_oid_id_x509_ce_keyUsage) == 0) { + ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, + &(*req)->ku, NULL); + what = "keyUsage"; + /* + * Count all KUs as one requested extension to be authorized, + * though the caller will have to check the KU values individually. + */ + if (KeyUsage2int((*req)->ku) & ~KeyUsage2int(int2KeyUsage(~0ULL))) { + if (e->critical) + (*req)->nunsupported_crit++; + else + (*req)->nunsupported_opt++; + } + } else if (der_heim_oid_cmp(&e->extnID, + &asn1_oid_id_x509_ce_extKeyUsage) == 0) { + ret = decode_ExtKeyUsage(e->extnValue.data, e->extnValue.length, + &(*req)->eku, NULL); + what = "extKeyUsage"; + + /* + * Count each EKU as a separate requested extension to be + * authorized. + */ + } else if (der_heim_oid_cmp(&e->extnID, + &asn1_oid_id_x509_ce_subjectAltName) == 0) { + ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, + &(*req)->san, NULL); + what = "subjectAlternativeName"; + + /* + * Count each SAN as a separate requested extension to be + * authorized. + */ + } else if (der_heim_oid_cmp(&e->extnID, + &asn1_oid_id_x509_ce_basicConstraints) == 0) { + (*req)->include_BasicConstraints = 1; + ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, + &(*req)->bc, NULL); + } else { + char *oidstr = NULL; + + if (e->critical) + (*req)->nunsupported_crit++; + else + (*req)->nunsupported_opt++; + + /* + * We need an HX509_TRACE facility for this sort of warning. + * + * We'd put the warning in the context and then allow the caller to + * extract and reset the warning. + * + * FIXME + */ + der_print_heim_oid(&e->extnID, '.', &oidstr); + warnx("Unknown or unsupported CSR extension request %s", + oidstr ? oidstr : ""); + free(oidstr); + } + if (ret) { + hx509_set_error_string(context, 0, ret, + "CSR signature verification failed " + "due to invalid %s extension", what); + break; + } + } + +out: + free_CertificationRequest(&r); + free_Extensions(&exts); + if (ret) + hx509_request_free(req); + return ret; +} + +/** + * Parse an encoded CSR and verify its self-signature. + * + * @param context An hx509 context. + * @param csr The name of a store containing the CSR ("PKCS10:/path/to/file") + * @param req Where to put request object. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_parse(hx509_context context, + const char *csr, + hx509_request *req) +{ + heim_octet_string d; + int ret; + + /* XXX Add support for PEM */ + if (strncmp(csr, "PKCS10:", 7) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "CSR location does not start with \"PKCS10:\": %s", + csr); + return HX509_UNSUPPORTED_OPERATION; + } + + ret = rk_undumpdata(csr + 7, &d.data, &d.length); + if (ret) { + hx509_set_error_string(context, 0, ret, "Could not read %s", csr); + return ret; + } + + ret = hx509_request_parse_der(context, &d, req); + free(d.data); + if (ret) + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + " (while parsing CSR from %s)", csr); + return ret; +} + +/** + * Get some EKU from a CSR. Usable as an iterator. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param idx The index of the EKU (0 for the first) to return + * @param out A pointer to a char * variable where the OID will be placed + * (caller must free with free()) + * + * @return Zero on success, HX509_NO_ITEM if no such item exists (denoting + * iteration end), or an error. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_eku(hx509_request req, + size_t idx, + char **out) +{ + *out = NULL; + if (idx >= req->eku.len) + return HX509_NO_ITEM; + return der_print_heim_oid(&req->eku.val[idx], '.', out); +} + +static int +abitstring_check(abitstring a, size_t n, int idx) +{ + size_t bytes; + + if (idx >= n) + return HX509_NO_ITEM; + + bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0); + if (a->feat_bytes < bytes) + return 0; + + return !!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT))); +} + +/* + * Sets and returns 0 if not already set, -1 if already set. Positive return + * values are system errors. + */ +static int +abitstring_set(abitstring a, size_t n, int idx) +{ + size_t bytes; + + if (idx >= n) + return HX509_NO_ITEM; + + bytes = n / CHAR_BIT + ((n % CHAR_BIT) ? 1 : 0); + if (a->feat_bytes < bytes) { + unsigned char *tmp; + + if ((tmp = realloc(a->feats, bytes)) == NULL) + return ENOMEM; + memset(tmp + a->feat_bytes, 0, bytes - a->feat_bytes); + a->feats = tmp; + a->feat_bytes = bytes; + } + + if (!(a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) { + a->feats[idx / CHAR_BIT] |= 1UL<<(idx % CHAR_BIT); + return 0; + } + return -1; +} + +/* + * Resets and returns 0 if not already reset, -1 if already reset. Positive + * return values are system errors. + */ +static int +abitstring_reset(abitstring a, size_t n, int idx) +{ + size_t bytes; + + if (idx >= n) + return HX509_NO_ITEM; + + bytes = (idx + 1) / CHAR_BIT + (((idx + 1) % CHAR_BIT) ? 1 : 0); + if (a->feat_bytes >= bytes && + (a->feats[idx / CHAR_BIT] & (1UL<<(idx % CHAR_BIT)))) { + a->feats[idx / CHAR_BIT] &= ~(1UL<<(idx % CHAR_BIT)); + return 0; + } + return -1; +} + +static int +authorize_feat(hx509_request req, abitstring a, size_t n, int idx) +{ + int ret; + + ret = abitstring_set(a, n, idx); + switch (ret) { + case 0: + req->nauthorized++; + HEIM_FALLTHROUGH; + case -1: + return 0; + default: + return ret; + } +} + +static int +reject_feat(hx509_request req, abitstring a, size_t n, int idx) +{ + int ret; + + ret = abitstring_reset(a, n, idx); + switch (ret) { + case 0: + req->nauthorized--; + HEIM_FALLTHROUGH; + case -1: + return 0; + default: + return ret; + } +} + +/** + * Authorize issuance of a CA certificate as requested. + * + * @param req The hx509_request object. + * @param pathLenConstraint the pathLenConstraint for the BasicConstraints (optional) + * + * @return an hx509 or system error. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_authorize_cA(hx509_request req, unsigned *pathLenConstraint) +{ + int ret; + + ret = hx509_request_set_cA(NULL, req, pathLenConstraint); + req->ca_is_authorized++; + return ret; +} + +/** + * Filter the requested KeyUsage and mark it authorized. + * + * @param req The hx509_request object. + * @param ku Permitted KeyUsage + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_request_authorize_ku(hx509_request req, KeyUsage ku) +{ + (void) hx509_request_set_ku(NULL, req, ku); + req->ku = int2KeyUsage(KeyUsage2int(req->ku) & KeyUsage2int(ku)); + if (KeyUsage2int(ku)) + req->ku_are_authorized = 1; +} + +/** + * Mark a requested EKU as authorized. + * + * @param req The hx509_request object. + * @param idx The index of an EKU that can be fetched with + * hx509_request_get_eku() + * + * @return Zero on success, an error otherwise. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_authorize_eku(hx509_request req, size_t idx) +{ + return authorize_feat(req, &req->authorized_EKUs, req->eku.len, idx); +} + +/** + * Mark a requested EKU as not authorized. + * + * @param req The hx509_request object. + * @param idx The index of an EKU that can be fetched with + * hx509_request_get_eku() + * + * @return Zero on success, an error otherwise. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_reject_eku(hx509_request req, size_t idx) +{ + return reject_feat(req, &req->authorized_EKUs, req->eku.len, idx); +} + +/** + * Check if an EKU has been marked authorized. + * + * @param req The hx509_request object. + * @param idx The index of an EKU that can be fetched with + * hx509_request_get_eku() + * + * @return Non-zero if authorized, zero if not. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_eku_authorized_p(hx509_request req, size_t idx) +{ + return abitstring_check(&req->authorized_EKUs, req->eku.len, idx); +} + +/** + * Mark a requested SAN as authorized. + * + * @param req The hx509_request object. + * @param idx The cursor as modified by a SAN iterator. + * + * @return Zero on success, an error otherwise. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_authorize_san(hx509_request req, size_t idx) +{ + return authorize_feat(req, &req->authorized_SANs, req->san.len, idx); +} + +/** + * Mark a requested SAN as not authorized. + * + * @param req The hx509_request object. + * @param idx The cursor as modified by a SAN iterator. + * + * @return Zero on success, an error otherwise. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_reject_san(hx509_request req, size_t idx) +{ + return reject_feat(req, &req->authorized_SANs, req->san.len, idx); +} + +/** + * Check if a SAN has been marked authorized. + * + * @param req The hx509_request object. + * @param idx The index of a SAN that can be fetched with + * hx509_request_get_san() + * + * @return Non-zero if authorized, zero if not. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_san_authorized_p(hx509_request req, size_t idx) +{ + return abitstring_check(&req->authorized_SANs, req->san.len, idx); +} + +/** + * Return the count of unsupported requested certificate extensions. + * + * @param req The hx509_request object. + * @return The number of unsupported certificate extensions requested. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION size_t HX509_LIB_CALL +hx509_request_count_unsupported(hx509_request req) +{ + return req->nunsupported_crit; +} + +/** + * Return the count of as-yet unauthorized certificate extensions requested. + * + * @param req The hx509_request object. + * @return The number of as-yet unauthorized certificate extensions requested. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION size_t HX509_LIB_CALL +hx509_request_count_unauthorized(hx509_request req) +{ + size_t nrequested = req->eku.len + req->san.len + + (KeyUsage2int(req->ku) ? 1 : 0) + !!req->bc.cA + + req->nunsupported_crit; + + return nrequested - (req->nauthorized + req->ku_are_authorized + req->ca_is_authorized); +} + +static hx509_san_type +san_map_type(GeneralName *san) +{ + static const struct { + const heim_oid *oid; + hx509_san_type type; + } map[] = { + { &asn1_oid_id_pkix_on_dnsSRV, HX509_SAN_TYPE_DNSSRV }, + { &asn1_oid_id_pkinit_san, HX509_SAN_TYPE_PKINIT }, + { &asn1_oid_id_pkix_on_xmppAddr, HX509_SAN_TYPE_XMPP }, + { &asn1_oid_id_pkinit_ms_san, HX509_SAN_TYPE_MS_UPN }, + { &asn1_oid_id_pkix_on_permanentIdentifier, HX509_SAN_TYPE_PERMANENT_ID }, + { &asn1_oid_id_on_hardwareModuleName, HX509_SAN_TYPE_HW_MODULE }, + }; + size_t i; + + switch (san->element) { + case choice_GeneralName_rfc822Name: return HX509_SAN_TYPE_EMAIL; + case choice_GeneralName_dNSName: return HX509_SAN_TYPE_DNSNAME; + case choice_GeneralName_directoryName: return HX509_SAN_TYPE_DN; + case choice_GeneralName_registeredID: return HX509_SAN_TYPE_REGISTERED_ID; + case choice_GeneralName_otherName: { + for (i = 0; i < sizeof(map)/sizeof(map[0]); i++) + if (der_heim_oid_cmp(&san->u.otherName.type_id, map[i].oid) == 0) + return map[i].type; + } + HEIM_FALLTHROUGH; + default: return HX509_SAN_TYPE_UNSUPPORTED; + } +} + +/** + * Return the count of as-yet unauthorized certificate extensions requested. + * + * @param req The hx509_request object. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION size_t HX509_LIB_CALL +hx509_request_get_san(hx509_request req, + size_t idx, + hx509_san_type *type, + char **out) +{ + struct rk_strpool *pool = NULL; + GeneralName *san; + + *out = NULL; + if (idx >= req->san.len) + return HX509_NO_ITEM; + + san = &req->san.val[idx]; + switch ((*type = san_map_type(san))) { + case HX509_SAN_TYPE_UNSUPPORTED: return 0; + case HX509_SAN_TYPE_EMAIL: + *out = strndup(san->u.rfc822Name.data, + san->u.rfc822Name.length); + break; + case HX509_SAN_TYPE_DNSNAME: + *out = strndup(san->u.dNSName.data, + san->u.dNSName.length); + break; + case HX509_SAN_TYPE_DNSSRV: { + SRVName name; + size_t size; + int ret; + + ret = decode_SRVName(san->u.otherName.value.data, + san->u.otherName.value.length, &name, &size); + if (ret) + return ret; + *out = strndup(name.data, name.length); + break; + } + case HX509_SAN_TYPE_PERMANENT_ID: { + PermanentIdentifier pi; + size_t size; + char *s = NULL; + int ret; + + ret = decode_PermanentIdentifier(san->u.otherName.value.data, + san->u.otherName.value.length, + &pi, &size); + if (ret == 0 && pi.assigner) { + ret = der_print_heim_oid(pi.assigner, '.', &s); + if (ret == 0 && + (pool = rk_strpoolprintf(NULL, "%s", s)) == NULL) + ret = ENOMEM; + } else if (ret == 0) { + pool = rk_strpoolprintf(NULL, "-"); + } + if (ret == 0 && + (pool = rk_strpoolprintf(pool, "%s%s", + *pi.identifierValue ? " " : "", + *pi.identifierValue ? *pi.identifierValue : "")) == NULL) + ret = ENOMEM; + if (ret == 0 && (*out = rk_strpoolcollect(pool)) == NULL) + ret = ENOMEM; + free_PermanentIdentifier(&pi); + free(s); + return ret; + } + case HX509_SAN_TYPE_HW_MODULE: { + HardwareModuleName hn; + size_t size; + char *s = NULL; + int ret; + + ret = decode_HardwareModuleName(san->u.otherName.value.data, + san->u.otherName.value.length, + &hn, &size); + if (ret == 0 && hn.hwSerialNum.length > 256) + hn.hwSerialNum.length = 256; + if (ret == 0) + ret = der_print_heim_oid(&hn.hwType, '.', &s); + if (ret == 0) + pool = rk_strpoolprintf(NULL, "%s", s); + if (ret == 0 && pool) + pool = rk_strpoolprintf(pool, " %.*s", + (int)hn.hwSerialNum.length, + (char *)hn.hwSerialNum.data); + if (ret == 0 && + (pool == NULL || (*out = rk_strpoolcollect(pool)) == NULL)) + ret = ENOMEM; + free_HardwareModuleName(&hn); + return ret; + } + case HX509_SAN_TYPE_DN: { + Name name; + + if (san->u.directoryName.element == choice_Name_rdnSequence) { + name.element = choice_Name_rdnSequence; + name.u.rdnSequence = san->u.directoryName.u.rdnSequence; + return _hx509_Name_to_string(&name, out); + } + *type = HX509_SAN_TYPE_UNSUPPORTED; + return 0; + } + case HX509_SAN_TYPE_REGISTERED_ID: + return der_print_heim_oid(&san->u.registeredID, '.', out); + case HX509_SAN_TYPE_XMPP: + HEIM_FALLTHROUGH; + case HX509_SAN_TYPE_MS_UPN: { + int ret; + + ret = _hx509_unparse_utf8_string_name(req->context, &pool, + &san->u.otherName.value); + if ((*out = rk_strpoolcollect(pool)) == NULL) + return hx509_enomem(req->context); + return ret; + } + case HX509_SAN_TYPE_PKINIT: { + int ret; + + ret = _hx509_unparse_KRB5PrincipalName(req->context, &pool, + &san->u.otherName.value); + if ((*out = rk_strpoolcollect(pool)) == NULL) + return hx509_enomem(req->context); + return ret; + } + default: + *type = HX509_SAN_TYPE_UNSUPPORTED; + return 0; + } + if (*out == NULL) + return ENOMEM; + return 0; +} + +/** + * Indicate if a CSR requested a CA certificate. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * + * @return 1 if the CSR requested CA certificate, 0 otherwise. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_cA(hx509_context context, + hx509_request req) +{ + return req->bc.cA; +} + +/** + * Return the CSR's requested BasicConstraints pathLenConstraint. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * + * @return -1 if no pathLenConstraint was requested (or the BasicConstraints + * does not request a CA certificate), or the actual requested + * pathLenConstraint. + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_get_cA_pathLenConstraint(hx509_context context, + hx509_request req) +{ + if (req->bc.cA && req->bc.pathLenConstraint && + *req->bc.pathLenConstraint < INT_MAX) + return *req->bc.pathLenConstraint; + return -1; +} + +/** + * Display a CSR. + * + * @param context An hx509 context. + * @param req The hx509_request object. + * @param f A FILE * to print the CSR to. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_request + */ +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_request_print(hx509_context context, hx509_request req, FILE *f) +{ + uint64_t ku_num; + size_t i; + char *s = NULL; + int ret = 0; + + /* + * It's really unformatunate that we can't reuse more of the + * lib/hx509/print.c infrastructure here, as it's too focused on + * Certificates. + * + * For that matter, it's really annoying that CSRs don't more resemble + * Certificates. Indeed, an ideal CSR would look like this: + * + * CSRInfo ::= { + * desiredTbsCertificate TBSCertificate, + * attributes [1] SEQUENCE OF Attribute OPTIONAL, + * } + * CSR :: = { + * csrInfo CSRInfo, + * sigAlg AlgorithmIdentifier, + * signature BIT STRING + * } + * + * with everything related to the desired certificate in + * desiredTbsCertificate and anything not related to the CSR's contents in + * the 'attributes' field. + * + * That wouldn't allow one to have optional desired TBSCertificate + * features, but hey. One could express "gimme all or gimme nothing" as an + * attribute, or "gimme what you can", then check what one got. + */ + fprintf(f, "PKCS#10 CertificationRequest:\n"); + + if (req->include_BasicConstraints) { + fprintf(f, " cA: %s\n", req->bc.cA ? "yes" : "no"); + if (req->bc.pathLenConstraint) + fprintf(f, " pathLenConstraint: %u\n", *req->bc.pathLenConstraint); + else + fprintf(f, " pathLenConstraint: unspecified\n"); + } + if (req->name) { + char *subject; + ret = hx509_name_to_string(req->name, &subject); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to print name"); + return ret; + } + fprintf(f, " name: %s\n", subject); + free(subject); + } + /* XXX Use hx509_request_get_ku() accessor */ + if ((ku_num = KeyUsage2int(req->ku))) { + const struct units *u; + const char *first = " "; + + fprintf(f, " key usage:"); + for (u = asn1_KeyUsage_units(); u->name; ++u) { + if ((ku_num & u->mult)) { + fprintf(f, "%s%s", first, u->name); + first = ", "; + ku_num &= ~u->mult; + } + } + if (ku_num) + fprintf(f, "%s", first); + fprintf(f, "\n"); + } + if (req->eku.len) { + const char *first = " "; + + fprintf(f, " eku:"); + for (i = 0; ret == 0; i++) { + free(s); s = NULL; + ret = hx509_request_get_eku(req, i, &s); + if (ret) + break; + fprintf(f, "%s{%s}", first, s); + first = ", "; + } + fprintf(f, "\n"); + } + free(s); s = NULL; + if (ret == HX509_NO_ITEM) + ret = 0; + for (i = 0; ret == 0; i++) { + hx509_san_type san_type; + + free(s); s = NULL; + ret = hx509_request_get_san(req, i, &san_type, &s); + if (ret) + break; + switch (san_type) { + case HX509_SAN_TYPE_EMAIL: + fprintf(f, " san: rfc822Name: %s\n", s); + break; + case HX509_SAN_TYPE_DNSNAME: + fprintf(f, " san: dNSName: %s\n", s); + break; + case HX509_SAN_TYPE_DN: + fprintf(f, " san: dn: %s\n", s); + break; + case HX509_SAN_TYPE_REGISTERED_ID: + fprintf(f, " san: registeredID: %s\n", s); + break; + case HX509_SAN_TYPE_XMPP: + fprintf(f, " san: xmpp: %s\n", s); + break; + case HX509_SAN_TYPE_PKINIT: + fprintf(f, " san: pkinit: %s\n", s); + break; + case HX509_SAN_TYPE_MS_UPN: + fprintf(f, " san: ms-upn: %s\n", s); + break; + default: + fprintf(f, " san: \n"); + break; + } + } + if (req->nunsupported_crit) { + fprintf(f, " unsupported_critical_extensions_count: %u\n", + (unsigned)req->nunsupported_crit); + } + if (req->nunsupported_crit) { + fprintf(f, " unsupported_optional_extensions_count: %u\n", + (unsigned)req->nunsupported_opt); + } + free(s); s = NULL; + if (ret == HX509_NO_ITEM) + ret = 0; + return ret; +} diff --git a/third_party/heimdal/lib/hx509/revoke.c b/third_party/heimdal/lib/hx509/revoke.c new file mode 100644 index 0000000..ade0bd3 --- /dev/null +++ b/third_party/heimdal/lib/hx509/revoke.c @@ -0,0 +1,1647 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @page page_revoke Revocation methods + * + * There are two revocation method for PKIX/X.509: CRL and OCSP. + * Revocation is needed if the private key is lost and + * stolen. Depending on how picky you are, you might want to make + * revocation for destroyed private keys too (smartcard broken), but + * that should not be a problem. + * + * CRL is a list of certificates that have expired. + * + * OCSP is an online checking method where the requestor sends a list + * of certificates to the OCSP server to return a signed reply if they + * are valid or not. Some services sends a OCSP reply as part of the + * hand-shake to make the revoktion decision simpler/faster for the + * client. + */ + +#include "hx_locl.h" + +struct revoke_crl { + char *path; + time_t last_modfied; + CRLCertificateList crl; + int verified; + int failed_verify; +}; + +struct revoke_ocsp { + char *path; + time_t last_modfied; + OCSPBasicOCSPResponse ocsp; + hx509_certs certs; + hx509_cert signer; +}; + + +struct hx509_revoke_ctx_data { + unsigned int ref; + struct { + struct revoke_crl *val; + size_t len; + } crls; + struct { + struct revoke_ocsp *val; + size_t len; + } ocsps; +}; + +/** + * Allocate a revocation context. Free with hx509_revoke_free(). + * + * @param context A hx509 context. + * @param ctx returns a newly allocated revocation context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) +{ + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) + return ENOMEM; + + (*ctx)->ref = 1; + (*ctx)->crls.len = 0; + (*ctx)->crls.val = NULL; + (*ctx)->ocsps.len = 0; + (*ctx)->ocsps.val = NULL; + + return 0; +} + +HX509_LIB_FUNCTION hx509_revoke_ctx HX509_LIB_CALL +_hx509_revoke_ref(hx509_revoke_ctx ctx) +{ + if (ctx == NULL) + return NULL; + if (ctx->ref == 0) + _hx509_abort("revoke ctx refcount == 0 on ref"); + ctx->ref++; + if (ctx->ref == UINT_MAX) + _hx509_abort("revoke ctx refcount == UINT_MAX on ref"); + return ctx; +} + +static void +free_ocsp(struct revoke_ocsp *ocsp) +{ + free(ocsp->path); + free_OCSPBasicOCSPResponse(&ocsp->ocsp); + hx509_certs_free(&ocsp->certs); + hx509_cert_free(ocsp->signer); +} + +/** + * Free a hx509 revocation context. + * + * @param ctx context to be freed + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_revoke_free(hx509_revoke_ctx *ctx) +{ + size_t i ; + + if (ctx == NULL || *ctx == NULL) + return; + + if ((*ctx)->ref == 0) + _hx509_abort("revoke ctx refcount == 0 on free"); + if (--(*ctx)->ref > 0) + return; + + for (i = 0; i < (*ctx)->crls.len; i++) { + free((*ctx)->crls.val[i].path); + free_CRLCertificateList(&(*ctx)->crls.val[i].crl); + } + + for (i = 0; i < (*ctx)->ocsps.len; i++) + free_ocsp(&(*ctx)->ocsps.val[i]); + free((*ctx)->ocsps.val); + + free((*ctx)->crls.val); + + memset(*ctx, 0, sizeof(**ctx)); + free(*ctx); + *ctx = NULL; +} + +static int +verify_ocsp(hx509_context context, + struct revoke_ocsp *ocsp, + time_t time_now, + hx509_certs certs, + hx509_cert parent) +{ + hx509_cert signer = NULL; + hx509_query q; + int ret; + + _hx509_query_clear(&q); + + /* + * Need to match on issuer too in case there are two CA that have + * issued the same name to a certificate. One example of this is + * the www.openvalidation.org test's ocsp validator. + */ + + q.match = HX509_QUERY_MATCH_ISSUER_NAME; + q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; + + switch(ocsp->ocsp.tbsResponseData.responderID.element) { + case choice_OCSPResponderID_byName: + q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; + q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; + break; + case choice_OCSPResponderID_byKey: + q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; + q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; + break; + } + + ret = hx509_certs_find(context, certs, &q, &signer); + if (ret && ocsp->certs) + ret = hx509_certs_find(context, ocsp->certs, &q, &signer); + if (ret == 0 && signer == NULL) + ret = HX509_CERT_NOT_FOUND; + if (ret) + goto out; + + /* + * If signer certificate isn't the CA certificate, let's check that + * it is the CA that signed the signer certificate and that the OCSP EKU + * is set. + */ + if (hx509_cert_cmp(signer, parent) != 0) { + Certificate *p = _hx509_get_cert(parent); + Certificate *s = _hx509_get_cert(signer); + + ret = _hx509_cert_is_parent_cmp(s, p, 0); + if (ret != 0) { + ret = HX509_PARENT_NOT_CA; + hx509_set_error_string(context, 0, ret, "Revoke OCSP signer " + "doesn't have CA as signer certificate"); + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + parent, + &s->signatureAlgorithm, + &s->tbsCertificate._save, + &s->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "OCSP signer signature invalid"); + goto out; + } + + ret = hx509_cert_check_eku(context, signer, + &asn1_oid_id_pkix_kp_OCSPSigning, 0); + if (ret) + goto out; + } + + ret = _hx509_verify_signature_bitstring(context, + signer, + &ocsp->ocsp.signatureAlgorithm, + &ocsp->ocsp.tbsResponseData._save, + &ocsp->ocsp.signature); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "OCSP signature invalid"); + goto out; + } + + ocsp->signer = signer; + signer = NULL; +out: + if (signer) + hx509_cert_free(signer); + + return ret; +} + +/* + * + */ + +static int +parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) +{ + OCSPResponse resp; + size_t size; + int ret; + + memset(basic, 0, sizeof(*basic)); + + ret = decode_OCSPResponse(data, length, &resp, &size); + if (ret) + return ret; + if (length != size) { + free_OCSPResponse(&resp); + return ASN1_EXTRA_DATA; + } + + switch (resp.responseStatus) { + case successful: + break; + default: + free_OCSPResponse(&resp); + return HX509_REVOKE_WRONG_DATA; + } + + if (resp.responseBytes == NULL) { + free_OCSPResponse(&resp); + return EINVAL; + } + + ret = der_heim_oid_cmp(&resp.responseBytes->responseType, + &asn1_oid_id_pkix_ocsp_basic); + if (ret != 0) { + free_OCSPResponse(&resp); + return HX509_REVOKE_WRONG_DATA; + } + + ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, + resp.responseBytes->response.length, + basic, + &size); + if (ret) { + free_OCSPResponse(&resp); + return ret; + } + if (size != resp.responseBytes->response.length) { + free_OCSPResponse(&resp); + free_OCSPBasicOCSPResponse(basic); + return ASN1_EXTRA_DATA; + } + free_OCSPResponse(&resp); + + return 0; +} + +/* + * + */ + +static int +load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) +{ + OCSPBasicOCSPResponse basic; + hx509_certs certs = NULL; + size_t length; + struct stat sb; + void *data; + int ret; + + ret = rk_undumpdata(ocsp->path, &data, &length); + if (ret) + return ret; + + ret = stat(ocsp->path, &sb); + if (ret) { + rk_xfree(data); + return errno; + } + + ret = parse_ocsp_basic(data, length, &basic); + rk_xfree(data); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to parse OCSP response"); + return ret; + } + + if (basic.certs) { + size_t i; + + ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, + NULL, &certs); + if (ret) { + free_OCSPBasicOCSPResponse(&basic); + return ret; + } + + for (i = 0; i < basic.certs->len; i++) { + hx509_cert c; + + c = hx509_cert_init(context, &basic.certs->val[i], NULL); + if (c == NULL) + continue; + + ret = hx509_certs_add(context, certs, c); + hx509_cert_free(c); + if (ret) + continue; + } + } + + ocsp->last_modfied = sb.st_mtime; + + free_OCSPBasicOCSPResponse(&ocsp->ocsp); + hx509_certs_free(&ocsp->certs); + hx509_cert_free(ocsp->signer); + + ocsp->ocsp = basic; + ocsp->certs = certs; + ocsp->signer = NULL; + + return 0; +} + +/** + * Add a OCSP file to the revocation context. + * + * @param context hx509 context + * @param ctx hx509 revocation context + * @param path path to file that is going to be added to the context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_add_ocsp(hx509_context context, + hx509_revoke_ctx ctx, + const char *path) +{ + void *data; + int ret; + size_t i; + + if (strncmp(path, "FILE:", 5) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "unsupported type in %s", path); + return HX509_UNSUPPORTED_OPERATION; + } + + path += 5; + + for (i = 0; i < ctx->ocsps.len; i++) { + if (strcmp(ctx->ocsps.val[0].path, path) == 0) + return 0; + } + + data = realloc(ctx->ocsps.val, + (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); + if (data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ctx->ocsps.val = data; + + memset(&ctx->ocsps.val[ctx->ocsps.len], 0, + sizeof(ctx->ocsps.val[0])); + + ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); + if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); + if (ret) { + free(ctx->ocsps.val[ctx->ocsps.len].path); + return ret; + } + ctx->ocsps.len++; + + return ret; +} + +/* + * + */ + +static int +verify_crl(hx509_context context, + hx509_revoke_ctx ctx, + CRLCertificateList *crl, + time_t time_now, + hx509_certs certs, + hx509_cert parent) +{ + hx509_cert signer; + hx509_query q; + time_t t; + int ret; + + t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); + if (t > time_now) { + hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, + "CRL used before time"); + return HX509_CRL_USED_BEFORE_TIME; + } + + if (crl->tbsCertList.nextUpdate == NULL) { + hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, + "CRL missing nextUpdate"); + return HX509_CRL_INVALID_FORMAT; + } + + t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); + if (t < time_now) { + hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, + "CRL used after time"); + return HX509_CRL_USED_AFTER_TIME; + } + + _hx509_query_clear(&q); + + /* + * If it's the signer have CRLSIGN bit set, use that as the signer + * cert for the certificate, otherwise, search for a certificate. + */ + if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { + signer = hx509_cert_ref(parent); + } else { + q.match = HX509_QUERY_MATCH_SUBJECT_NAME; + q.match |= HX509_QUERY_KU_CRLSIGN; + q.subject_name = &crl->tbsCertList.issuer; + + ret = hx509_certs_find(context, certs, &q, &signer); + if (ret == 0 && signer == NULL) + ret = HX509_CERT_NOT_FOUND; + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to find certificate for CRL"); + return ret; + } + } + + ret = _hx509_verify_signature_bitstring(context, + signer, + &crl->signatureAlgorithm, + &crl->tbsCertList._save, + &crl->signatureValue); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "CRL signature invalid"); + goto out; + } + + /* + * If signer is not CA cert, need to check revoke status of this + * CRL signing cert too, this include all parent CRL signer cert + * up to the root *sigh*, assume root at least has CERTSIGN flag + * set. + */ + while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { + hx509_cert crl_parent; + + _hx509_query_clear(&q); + + q.match = HX509_QUERY_MATCH_SUBJECT_NAME; + q.match |= HX509_QUERY_KU_CRLSIGN; + q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; + + ret = hx509_certs_find(context, certs, &q, &crl_parent); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to find parent of CRL signer"); + goto out; + } + + ret = hx509_revoke_verify(context, + ctx, + certs, + time_now, + signer, + crl_parent); + hx509_cert_free(signer); + signer = crl_parent; + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed to verify revocation " + "status of CRL signer"); + goto out; + } + } + +out: + hx509_cert_free(signer); + + return ret; +} + +static int +crl_parser(hx509_context context, const char *type, + const hx509_pem_header *header, + const void *data, size_t len, void *ctx) +{ + CRLCertificateList *crl = (CRLCertificateList *)ctx; + size_t size; + int ret; + + if (strcasecmp("X509 CRL", type) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + ret = decode_CRLCertificateList(data, len, crl, &size); + if (ret) + return ret; + + /* check signature is aligned */ + if (crl->signatureValue.length & 7) { + free_CRLCertificateList(crl); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + return 0; +} + +static int +load_crl(hx509_context context, const char *path, time_t *t, CRLCertificateList *crl) +{ + struct stat sb; + size_t length; + void *data; + FILE *f; + int ret; + + *t = 0; + memset(crl, 0, sizeof(*crl)); + + if ((f = fopen(path, "r")) == NULL) + return errno; + + rk_cloexec_file(f); + if (fstat(fileno(f), &sb) == 0) + *t = sb.st_mtime; + + ret = hx509_pem_read(context, f, crl_parser, crl); + fclose(f); + + if (ret == HX509_PARSING_KEY_FAILED) { + + ret = rk_undumpdata(path, &data, &length); + if (ret) + return ret; + + ret = crl_parser(context, "X509 CRL", NULL, data, length, crl); + rk_xfree(data); + } + return ret; +} + +/** + * Add a CRL file to the revocation context. + * + * @param context hx509 context + * @param ctx hx509 revocation context + * @param path path to file that is going to be added to the context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_add_crl(hx509_context context, + hx509_revoke_ctx ctx, + const char *path) +{ + void *data; + size_t i; + int ret; + + if (strncmp(path, "FILE:", 5) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "unsupported type in %s", path); + return HX509_UNSUPPORTED_OPERATION; + } + + + path += 5; + + for (i = 0; i < ctx->crls.len; i++) { + if (strcmp(ctx->crls.val[i].path, path) == 0) + return 0; + } + + data = realloc(ctx->crls.val, + (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); + if (data == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + ctx->crls.val = data; + + memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); + + ctx->crls.val[ctx->crls.len].path = strdup(path); + if (ctx->crls.val[ctx->crls.len].path == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + ret = load_crl(context, + path, + &ctx->crls.val[ctx->crls.len].last_modfied, + &ctx->crls.val[ctx->crls.len].crl); + if (ret) { + free(ctx->crls.val[ctx->crls.len].path); + return ret; + } + + ctx->crls.len++; + + return ret; +} + +/** + * Check that a certificate is not expired according to a revocation + * context. Also need the parent certificate to check the OCSP + * parent identifier. + * + * @param context hx509 context + * @param ctx hx509 revocation context + * @param certs + * @param now + * @param cert + * @param parent_cert + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_verify(hx509_context context, + hx509_revoke_ctx ctx, + hx509_certs certs, + time_t now, + hx509_cert cert, + hx509_cert parent_cert) +{ + const Certificate *c = _hx509_get_cert(cert); + const Certificate *p = _hx509_get_cert(parent_cert); + unsigned long i, j, k; + int ret; + + hx509_clear_error_string(context); + + for (i = 0; i < ctx->ocsps.len; i++) { + struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; + struct stat sb; + + /* check if this ocsp applies to this cert */ + + /* check if there is a newer version of the file */ + ret = stat(ocsp->path, &sb); + if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { + ret = load_ocsp(context, ocsp); + if (ret) + continue; + } + + /* verify signature in ocsp if not already done */ + if (ocsp->signer == NULL) { + ret = verify_ocsp(context, ocsp, now, certs, parent_cert); + if (ret) + continue; + } + + for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { + heim_octet_string os; + + ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + /* verify issuer hashes hash */ + ret = _hx509_verify_signature(context, + NULL, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &c->tbsCertificate.issuer._save, + &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); + if (ret != 0) + continue; + + os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_verify_signature(context, + NULL, + &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, + &os, + &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); + if (ret != 0) + continue; + + switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { + case choice_OCSPCertStatus_good: + break; + case choice_OCSPCertStatus_revoked: + hx509_set_error_string(context, 0, + HX509_CERT_REVOKED, + "Certificate revoked by issuer in OCSP"); + return HX509_CERT_REVOKED; + case choice_OCSPCertStatus_unknown: + continue; + } + + /* don't allow the update to be in the future */ + if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > + now + context->ocsp_time_diff) + continue; + + /* don't allow the next update to be in the past */ + if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { + if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) + continue; + } /* else should force a refetch, but can we ? */ + + return 0; + } + } + + for (i = 0; i < ctx->crls.len; i++) { + struct revoke_crl *crl = &ctx->crls.val[i]; + struct stat sb; + int diff; + + /* check if cert.issuer == crls.val[i].crl.issuer */ + ret = _hx509_name_cmp(&c->tbsCertificate.issuer, + &crl->crl.tbsCertList.issuer, &diff); + if (ret || diff) + continue; + + ret = stat(crl->path, &sb); + if (ret == 0 && crl->last_modfied != sb.st_mtime) { + CRLCertificateList cl; + + ret = load_crl(context, crl->path, &crl->last_modfied, &cl); + if (ret == 0) { + free_CRLCertificateList(&crl->crl); + crl->crl = cl; + crl->verified = 0; + crl->failed_verify = 0; + } + } + if (crl->failed_verify) + continue; + + /* verify signature in crl if not already done */ + if (crl->verified == 0) { + ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); + if (ret) { + crl->failed_verify = 1; + continue; + } + crl->verified = 1; + } + + if (crl->crl.tbsCertList.crlExtensions) { + for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { + if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { + hx509_set_error_string(context, 0, + HX509_CRL_UNKNOWN_EXTENSION, + "Unknown CRL extension"); + return HX509_CRL_UNKNOWN_EXTENSION; + } + } + } + + if (crl->crl.tbsCertList.revokedCertificates == NULL) + return 0; + + /* check if cert is in crl */ + for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { + time_t t; + + ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); + if (t > now) + continue; + + if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) + for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) + if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) + return HX509_CRL_UNKNOWN_EXTENSION; + + hx509_set_error_string(context, 0, + HX509_CERT_REVOKED, + "Certificate revoked by issuer in CRL"); + return HX509_CERT_REVOKED; + } + + return 0; + } + + + if (context->flags & HX509_CTX_VERIFY_MISSING_OK) + return 0; + hx509_set_error_string(context, HX509_ERROR_APPEND, + HX509_REVOKE_STATUS_MISSING, + "No revocation status found for certificates"); + return HX509_REVOKE_STATUS_MISSING; +} + +struct ocsp_add_ctx { + OCSPTBSRequest *req; + hx509_certs certs; + const AlgorithmIdentifier *digest; + hx509_cert parent; +}; + +static int HX509_LIB_CALL +add_to_req(hx509_context context, void *ptr, hx509_cert cert) +{ + struct ocsp_add_ctx *ctx = ptr; + OCSPInnerRequest *one; + hx509_cert parent = NULL; + Certificate *p, *c = _hx509_get_cert(cert); + heim_octet_string os; + int ret; + hx509_query q; + void *d; + + d = realloc(ctx->req->requestList.val, + sizeof(ctx->req->requestList.val[0]) * + (ctx->req->requestList.len + 1)); + if (d == NULL) + return ENOMEM; + ctx->req->requestList.val = d; + + one = &ctx->req->requestList.val[ctx->req->requestList.len]; + memset(one, 0, sizeof(*one)); + + _hx509_query_clear(&q); + + q.match |= HX509_QUERY_FIND_ISSUER_CERT; + q.subject = c; + + ret = hx509_certs_find(context, ctx->certs, &q, &parent); + if (ret) + goto out; + + if (ctx->parent) { + if (hx509_cert_cmp(ctx->parent, parent) != 0) { + ret = HX509_REVOKE_NOT_SAME_PARENT; + hx509_set_error_string(context, 0, ret, + "Not same parent certificate as " + "last certificate in request"); + goto out; + } + } else + ctx->parent = hx509_cert_ref(parent); + + p = _hx509_get_cert(parent); + + ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); + if (ret) + goto out; + + ret = _hx509_create_signature(context, + NULL, + &one->reqCert.hashAlgorithm, + &c->tbsCertificate.issuer._save, + NULL, + &one->reqCert.issuerNameHash); + if (ret) + goto out; + + os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; + os.length = + p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; + + ret = _hx509_create_signature(context, + NULL, + &one->reqCert.hashAlgorithm, + &os, + NULL, + &one->reqCert.issuerKeyHash); + if (ret) + goto out; + + ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, + &one->reqCert.serialNumber); + if (ret) + goto out; + + ctx->req->requestList.len++; +out: + hx509_cert_free(parent); + if (ret) { + free_OCSPInnerRequest(one); + memset(one, 0, sizeof(*one)); + } + + return ret; +} + +/** + * Create an OCSP request for a set of certificates. + * + * @param context a hx509 context + * @param reqcerts list of certificates to request ocsp data for + * @param pool certificate pool to use when signing + * @param signer certificate to use to sign the request + * @param digest the signing algorithm in the request, if NULL use the + * default signature algorithm, + * @param request the encoded request, free with free_heim_octet_string(). + * @param nonce nonce in the request, free with free_heim_octet_string(). + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ocsp_request(hx509_context context, + hx509_certs reqcerts, + hx509_certs pool, + hx509_cert signer, + const AlgorithmIdentifier *digest, + heim_octet_string *request, + heim_octet_string *nonce) +{ + OCSPRequest req; + size_t size; + int ret; + struct ocsp_add_ctx ctx; + Extensions *es; + + memset(&req, 0, sizeof(req)); + + if (digest == NULL) + digest = _hx509_crypto_default_digest_alg; + + ctx.req = &req.tbsRequest; + ctx.certs = pool; + ctx.digest = digest; + ctx.parent = NULL; + + ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx); + hx509_cert_free(ctx.parent); + if (ret) + goto out; + + if (nonce) { + req.tbsRequest.requestExtensions = + calloc(1, sizeof(*req.tbsRequest.requestExtensions)); + if (req.tbsRequest.requestExtensions == NULL) { + ret = ENOMEM; + goto out; + } + + es = req.tbsRequest.requestExtensions; + + es->val = calloc(es->len, sizeof(es->val[0])); + if (es->val == NULL) { + ret = ENOMEM; + goto out; + } + es->len = 1; + ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); + if (ret) { + free_OCSPRequest(&req); + return ret; + } + + es->val[0].extnValue.data = malloc(10); + if (es->val[0].extnValue.data == NULL) { + ret = ENOMEM; + goto out; + } + es->val[0].extnValue.length = 10; + + ret = RAND_bytes(es->val[0].extnValue.data, + es->val[0].extnValue.length); + if (ret != 1) { + ret = HX509_CRYPTO_INTERNAL_ERROR; + goto out; + } + ret = der_copy_octet_string(nonce, &es->val[0].extnValue); + if (ret) { + ret = ENOMEM; + goto out; + } + } + + ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, + &req, &size, ret); + free_OCSPRequest(&req); + if (ret) + goto out; + if (size != request->length) + _hx509_abort("internal ASN.1 encoder error"); + + return 0; + +out: + free_OCSPRequest(&req); + return ret; +} + +static char * +printable_time(time_t t) +{ + static char s[128]; + char *p; + if ((p = ctime(&t)) == NULL) + strlcpy(s, "?", sizeof(s)); + else { + strlcpy(s, p + 4, sizeof(s)); + s[20] = 0; + } + return s; +} + +/* + * + */ + +static int +print_ocsp(hx509_context context, struct revoke_ocsp *ocsp, FILE *out) +{ + int ret = 0; + size_t i; + + fprintf(out, "signer: "); + + switch(ocsp->ocsp.tbsResponseData.responderID.element) { + case choice_OCSPResponderID_byName: { + hx509_name n; + char *s; + _hx509_name_from_Name(&ocsp->ocsp.tbsResponseData.responderID.u.byName, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + fprintf(out, " byName: %s\n", s); + free(s); + break; + } + case choice_OCSPResponderID_byKey: { + char *s; + hex_encode(ocsp->ocsp.tbsResponseData.responderID.u.byKey.data, + ocsp->ocsp.tbsResponseData.responderID.u.byKey.length, + &s); + fprintf(out, " byKey: %s\n", s); + free(s); + break; + } + default: + _hx509_abort("choice_OCSPResponderID unknown"); + break; + } + + fprintf(out, "producedAt: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.producedAt)); + + fprintf(out, "replies: %d\n", ocsp->ocsp.tbsResponseData.responses.len); + + for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) { + const char *status; + switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + status = "good"; + break; + case choice_OCSPCertStatus_revoked: + status = "revoked"; + break; + case choice_OCSPCertStatus_unknown: + status = "unknown"; + break; + default: + status = "element unknown"; + } + + fprintf(out, "\t%llu. status: %s\n", (unsigned long long)i, status); + + fprintf(out, "\tthisUpdate: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate)); + if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate) + fprintf(out, "\tproducedAt: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate)); + + } + + fprintf(out, "appended certs:\n"); + if (ocsp->certs) + ret = hx509_certs_iter_f(context, ocsp->certs, hx509_ci_print_names, out); + + return ret; +} + +static int +print_crl(hx509_context context, struct revoke_crl *crl, FILE *out) +{ + { + hx509_name n; + char *s; + _hx509_name_from_Name(&crl->crl.tbsCertList.issuer, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + fprintf(out, " issuer: %s\n", s); + free(s); + } + + fprintf(out, " thisUpdate: %s\n", + printable_time(_hx509_Time2time_t(&crl->crl.tbsCertList.thisUpdate))); + + return 0; +} + + +/* + * + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_print(hx509_context context, + hx509_revoke_ctx ctx, + FILE *out) +{ + int saved_ret = 0, ret; + size_t n; + + for (n = 0; n < ctx->ocsps.len; n++) { + struct revoke_ocsp *ocsp = &ctx->ocsps.val[n]; + + fprintf(out, "OCSP %s\n", ocsp->path); + + ret = print_ocsp(context, ocsp, out); + if (ret) { + fprintf(out, "failure printing OCSP: %d\n", ret); + saved_ret = ret; + } + } + + for (n = 0; n < ctx->crls.len; n++) { + struct revoke_crl *crl = &ctx->crls.val[n]; + + fprintf(out, "CRL %s\n", crl->path); + + ret = print_crl(context, crl, out); + if (ret) { + fprintf(out, "failure printing CRL: %d\n", ret); + saved_ret = ret; + } + } + return saved_ret; + +} + +/** + * Print the OCSP reply stored in a file. + * + * @param context a hx509 context + * @param path path to a file with a OCSP reply + * @param out the out FILE descriptor to print the reply on + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_revoke + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) +{ + struct revoke_ocsp ocsp; + int ret; + + if (out == NULL) + out = stdout; + + memset(&ocsp, 0, sizeof(ocsp)); + + ocsp.path = strdup(path); + if (ocsp.path == NULL) + return ENOMEM; + + ret = load_ocsp(context, &ocsp); + if (ret) { + free_ocsp(&ocsp); + return ret; + } + + ret = print_ocsp(context, &ocsp, out); + + free_ocsp(&ocsp); + return ret; +} + +/** + * Verify that the certificate is part of the OCSP reply and it's not + * expired. Doesn't verify signature the OCSP reply or it's done by a + * authorized sender, that is assumed to be already done. + * + * @param context a hx509 context + * @param now the time right now, if 0, use the current time. + * @param cert the certificate to verify + * @param flags flags control the behavior + * @param data pointer to the encode ocsp reply + * @param length the length of the encode ocsp reply + * @param expiration return the time the OCSP will expire and need to + * be rechecked. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_ocsp_verify(hx509_context context, + time_t now, + hx509_cert cert, + int flags, + const void *data, size_t length, + time_t *expiration) +{ + const Certificate *c = _hx509_get_cert(cert); + OCSPBasicOCSPResponse basic; + int ret; + size_t i; + + if (now == 0) + now = time(NULL); + + *expiration = 0; + + ret = parse_ocsp_basic(data, length, &basic); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to parse OCSP response"); + return ret; + } + + for (i = 0; i < basic.tbsResponseData.responses.len; i++) { + + ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, + &c->tbsCertificate.serialNumber); + if (ret != 0) + continue; + + /* verify issuer hashes hash */ + ret = _hx509_verify_signature(context, + NULL, + &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &c->tbsCertificate.issuer._save, + &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); + if (ret != 0) + continue; + + switch (basic.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + break; + case choice_OCSPCertStatus_revoked: + case choice_OCSPCertStatus_unknown: + continue; + } + + /* don't allow the update to be in the future */ + if (basic.tbsResponseData.responses.val[i].thisUpdate > + now + context->ocsp_time_diff) + continue; + + /* don't allow the next update to be in the past */ + if (basic.tbsResponseData.responses.val[i].nextUpdate) { + if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) + continue; + *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; + } else + *expiration = now; + + free_OCSPBasicOCSPResponse(&basic); + return 0; + } + + free_OCSPBasicOCSPResponse(&basic); + + { + hx509_name name; + char *subject; + + ret = hx509_cert_get_subject(cert, &name); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + ret = hx509_name_to_string(name, &subject); + hx509_name_free(&name); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, + "Certificate %s not in OCSP response " + "or not good", + subject); + free(subject); + } +out: + return HX509_CERT_NOT_IN_OCSP; +} + +struct hx509_crl { + hx509_certs revoked; + time_t expire; +}; + +/** + * Create a CRL context. Use hx509_crl_free() to free the CRL context. + * + * @param context a hx509 context. + * @param crl return pointer to a newly allocated CRL context. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crl_alloc(hx509_context context, hx509_crl *crl) +{ + int ret; + + *crl = calloc(1, sizeof(**crl)); + if (*crl == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); + if (ret) { + free(*crl); + *crl = NULL; + return ret; + } + (*crl)->expire = 0; + return ret; +} + +/** + * Add revoked certificate to an CRL context. + * + * @param context a hx509 context. + * @param crl the CRL to add the revoked certificate to. + * @param certs keyset of certificate to revoke. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crl_add_revoked_certs(hx509_context context, + hx509_crl crl, + hx509_certs certs) +{ + return hx509_certs_merge(context, crl->revoked, certs); +} + +/** + * Set the lifetime of a CRL context. + * + * @param context a hx509 context. + * @param crl a CRL context + * @param delta delta time the certificate is valid, library adds the + * current time to this. + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) +{ + crl->expire = time(NULL) + delta; + return 0; +} + +/** + * Free a CRL context. + * + * @param context a hx509 context. + * @param crl a CRL context to free. + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION void HX509_LIB_CALL +hx509_crl_free(hx509_context context, hx509_crl *crl) +{ + if (*crl == NULL) + return; + hx509_certs_free(&(*crl)->revoked); + memset(*crl, 0, sizeof(**crl)); + free(*crl); + *crl = NULL; +} + +static int HX509_LIB_CALL +add_revoked(hx509_context context, void *ctx, hx509_cert cert) +{ + TBSCRLCertList *c = ctx; + unsigned int num; + void *ptr; + int ret; + + num = c->revokedCertificates->len; + ptr = realloc(c->revokedCertificates->val, + (num + 1) * sizeof(c->revokedCertificates->val[0])); + if (ptr == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + c->revokedCertificates->val = ptr; + + ret = hx509_cert_get_serialnumber(cert, + &c->revokedCertificates->val[num].userCertificate); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + c->revokedCertificates->val[num].revocationDate.element = + choice_Time_generalTime; + c->revokedCertificates->val[num].revocationDate.u.generalTime = + time(NULL) - 3600 * 24; + c->revokedCertificates->val[num].crlEntryExtensions = NULL; + + c->revokedCertificates->len++; + + return 0; +} + +/** + * Sign a CRL and return an encode certificate. + * + * @param context a hx509 context. + * @param signer certificate to sign the CRL with + * @param crl the CRL to sign + * @param os return the signed and encoded CRL, free with + * free_heim_octet_string() + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_verify + */ + +HX509_LIB_FUNCTION int HX509_LIB_CALL +hx509_crl_sign(hx509_context context, + hx509_cert signer, + hx509_crl crl, + heim_octet_string *os) +{ + const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; + CRLCertificateList c; + size_t size; + int ret; + hx509_private_key signerkey; + + memset(&c, 0, sizeof(c)); + + signerkey = _hx509_cert_private_key(signer); + if (signerkey == NULL) { + ret = HX509_PRIVATE_KEY_MISSING; + hx509_set_error_string(context, 0, ret, + "Private key missing for CRL signing"); + return ret; + } + + c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); + if (c.tbsCertList.version == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + *c.tbsCertList.version = 1; + + ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, + &c.tbsCertList.issuer); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + c.tbsCertList.thisUpdate.element = choice_Time_generalTime; + c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; + + c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); + if (c.tbsCertList.nextUpdate == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + ret = ENOMEM; + goto out; + } + + { + time_t next = crl->expire; + if (next == 0) + next = time(NULL) + 24 * 3600 * 365; + + c.tbsCertList.nextUpdate->element = choice_Time_generalTime; + c.tbsCertList.nextUpdate->u.generalTime = next; + } + + c.tbsCertList.revokedCertificates = + calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); + if (c.tbsCertList.revokedCertificates == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + ret = ENOMEM; + goto out; + } + c.tbsCertList.crlExtensions = NULL; + + ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList); + if (ret) + goto out; + + /* if not revoked certs, remove OPTIONAL entry */ + if (c.tbsCertList.revokedCertificates->len == 0) { + free(c.tbsCertList.revokedCertificates); + c.tbsCertList.revokedCertificates = NULL; + } + + ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, + &c.tbsCertList, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); + goto out; + } + if (size != os->length) + _hx509_abort("internal ASN.1 encoder error"); + + + ret = _hx509_create_signature_bitstring(context, + signerkey, + sigalg, + os, + &c.signatureAlgorithm, + &c.signatureValue); + free(os->data); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to sign CRL"); + goto out; + } + + ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, + &c, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "failed to encode CRL"); + goto out; + } + if (size != os->length) + _hx509_abort("internal ASN.1 encoder error"); + + free_CRLCertificateList(&c); + + return 0; + +out: + free_CRLCertificateList(&c); + return ret; +} diff --git a/third_party/heimdal/lib/hx509/sel-gram.y b/third_party/heimdal/lib/hx509/sel-gram.y new file mode 100644 index 0000000..09f641d --- /dev/null +++ b/third_party/heimdal/lib/hx509/sel-gram.y @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +%{ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + +#if !defined(yylex) +#define yylex _hx509_sel_yylex +#define yywrap _hx509_sel_yywrap +#endif +#if !defined(yyparse) +#define yyparse _hx509_sel_yyparse +#define yyerror _hx509_sel_yyerror +#define yylval _hx509_sel_yylval +#define yychar _hx509_sel_yychar +#define yydebug _hx509_sel_yydebug +#define yynerrs _hx509_sel_yynerrs +#endif + +%} + +%union { + char *string; + struct hx_expr *expr; +} + +%token kw_TRUE +%token kw_FALSE +%token kw_AND +%token kw_OR +%token kw_IN +%token kw_TAILMATCH + +%type expr +%type comp +%type word words +%type number +%type string +%type function +%type variable variables + +%token NUMBER +%token STRING +%token IDENTIFIER + +%left '!' +%left kw_AND +%left kw_OR + +%start start + +%% + +start: expr { _hx509_expr_input.expr = $1; } + +expr : kw_TRUE { $$ = _hx509_make_expr(op_TRUE, NULL, NULL); } + | kw_FALSE { $$ = _hx509_make_expr(op_FALSE, NULL, NULL); } + | '!' expr { $$ = _hx509_make_expr(op_NOT, $2, NULL); } + | expr kw_AND expr { $$ = _hx509_make_expr(op_AND, $1, $3); } + | expr kw_OR expr { $$ = _hx509_make_expr(op_OR, $1, $3); } + | '(' expr ')' { $$ = $2; } + | comp { $$ = _hx509_make_expr(op_COMP, $1, NULL); } + ; + +words : word { $$ = _hx509_make_expr(expr_WORDS, $1, NULL); } + | word ',' words { $$ = _hx509_make_expr(expr_WORDS, $1, $3); } + ; + +comp : word '=' '=' word { $$ = _hx509_make_expr(comp_EQ, $1, $4); } + | word '!' '=' word { $$ = _hx509_make_expr(comp_NE, $1, $4); } + | word kw_TAILMATCH word { $$ = _hx509_make_expr(comp_TAILEQ, $1, $3); } + | word kw_IN '(' words ')' { $$ = _hx509_make_expr(comp_IN, $1, $4); } + | word kw_IN variable { $$ = _hx509_make_expr(comp_IN, $1, $3); } + ; + +word : number { $$ = $1; } + | string { $$ = $1; } + | function { $$ = $1; } + | variable { $$ = $1; } + ; + +number : NUMBER { $$ = _hx509_make_expr(expr_NUMBER, $1, NULL); }; +string : STRING { $$ = _hx509_make_expr(expr_STRING, $1, NULL); }; + +function: IDENTIFIER '(' words ')' { + $$ = _hx509_make_expr(expr_FUNCTION, $1, $3); } + ; +variable: '%' '{' variables '}' { $$ = $3; } + ; + +variables: IDENTIFIER '.' variables { + $$ = _hx509_make_expr(expr_VAR, $1, $3); } + | IDENTIFIER { + $$ = _hx509_make_expr(expr_VAR, $1, NULL); } + ; diff --git a/third_party/heimdal/lib/hx509/sel-lex.l b/third_party/heimdal/lib/hx509/sel-lex.l new file mode 100644 index 0000000..f401e40 --- /dev/null +++ b/third_party/heimdal/lib/hx509/sel-lex.l @@ -0,0 +1,148 @@ +%{ +/* + * Copyright (c) 2004 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#undef ECHO + +#include +#include +#include +#include +#include "sel.h" +#include "sel-gram.h" +unsigned lineno = 1; + +static char * handle_string(void); +static int lex_input(char *, int); + +struct hx_expr_input _hx509_expr_input; + +#ifndef YY_NULL +#define YY_NULL 0 +#endif + +#define YY_NO_UNPUT 1 + +#undef YY_INPUT +#define YY_INPUT(buf,res,maxsize) (res = lex_input(buf, maxsize)) + +#undef ECHO + +%} +%% + +TRUE { return kw_TRUE; } +FALSE { return kw_FALSE; } +AND { return kw_AND; } +OR { return kw_OR; } +IN { return kw_IN; } +TAILMATCH { return kw_TAILMATCH; } + +[A-Za-z][-A-Za-z0-9_]* { + yylval.string = strdup ((const char *)yytext); + return IDENTIFIER; + } +"\"" { yylval.string = handle_string(); return STRING; } +\n { ++lineno; } +[,.!={}()%] { return *yytext; } +[ \t] ; +%% + +static char * +handle_string(void) +{ + char x[1024]; + int i = 0; + int c; + int quote = 0; + while((c = input()) != EOF){ + if(quote) { + x[i++] = '\\'; + x[i++] = c; + quote = 0; + continue; + } + if(c == '\n'){ + _hx509_sel_yyerror("unterminated string"); + lineno++; + break; + } + if(c == '\\'){ + quote++; + continue; + } + if(c == '\"') + break; + x[i++] = c; + } + x[i] = '\0'; + return strdup(x); +} + +#if !defined(yywrap) +#define yywrap _hx509_sel_yywrap +#endif + +int +yywrap () +{ + return 1; +} + +static int +lex_input(char *buf, int max_size) +{ + int n; + + n = _hx509_expr_input.length - _hx509_expr_input.offset; + if (max_size < n) + n = max_size; + if (n <= 0) + return YY_NULL; + + memcpy(buf, _hx509_expr_input.buf + _hx509_expr_input.offset, n); + _hx509_expr_input.offset += n; + + return n; +} diff --git a/third_party/heimdal/lib/hx509/sel.c b/third_party/heimdal/lib/hx509/sel.c new file mode 100644 index 0000000..bfd55e9 --- /dev/null +++ b/third_party/heimdal/lib/hx509/sel.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" + +HX509_LIB_FUNCTION struct hx_expr * HX509_LIB_CALL +_hx509_make_expr(enum hx_expr_op op, void *arg1, void *arg2) +{ + struct hx_expr *expr; + + expr = malloc(sizeof(*expr)); + if (expr == NULL) + return NULL; + expr->op = op; + expr->arg1 = arg1; + expr->arg2 = arg2; + + return expr; +} + +static const char * +eval_word(hx509_context context, hx509_env env, struct hx_expr *word) +{ + switch (word->op) { + case expr_STRING: + return word->arg1; + case expr_VAR: + if (word->arg2 == NULL) + return hx509_env_find(context, env, word->arg1); + + env = hx509_env_find_binding(context, env, word->arg1); + if (env == NULL) + return NULL; + + return eval_word(context, env, word->arg2); + default: + return NULL; + } +} + +static hx509_env +find_variable(hx509_context context, hx509_env env, struct hx_expr *word) +{ + assert(word->op == expr_VAR); + + if (word->arg2 == NULL) + return hx509_env_find_binding(context, env, word->arg1); + + env = hx509_env_find_binding(context, env, word->arg1); + if (env == NULL) + return NULL; + return find_variable(context, env, word->arg2); +} + +static int +eval_comp(hx509_context context, hx509_env env, struct hx_expr *expr) +{ + switch (expr->op) { + case comp_NE: + case comp_EQ: + case comp_TAILEQ: { + const char *s1, *s2; + int ret; + + s1 = eval_word(context, env, expr->arg1); + s2 = eval_word(context, env, expr->arg2); + + if (s1 == NULL || s2 == NULL) + return FALSE; + + if (expr->op == comp_TAILEQ) { + size_t len1 = strlen(s1); + size_t len2 = strlen(s2); + + if (len1 < len2) + return 0; + ret = strcmp(s1 + (len1 - len2), s2) == 0; + } else { + ret = strcmp(s1, s2) == 0; + if (expr->op == comp_NE) + ret = !ret; + } + return ret; + } + case comp_IN: { + struct hx_expr *subexpr; + const char *w, *s1; + + w = eval_word(context, env, expr->arg1); + + subexpr = expr->arg2; + + if (subexpr->op == expr_WORDS) { + while (subexpr) { + s1 = eval_word(context, env, subexpr->arg1); + if (strcmp(w, s1) == 0) + return TRUE; + subexpr = subexpr->arg2; + } + } else if (subexpr->op == expr_VAR) { + hx509_env subenv; + + subenv = find_variable(context, env, subexpr); + if (subenv == NULL) + return FALSE; + + while (subenv) { + if (subenv->type != env_string) + continue; + if (strcmp(w, subenv->name) == 0) + return TRUE; + if (strcmp(w, subenv->u.string) == 0) + return TRUE; + subenv = subenv->next; + } + + } else + _hx509_abort("hx509 eval IN unknown op: %d", (int)subexpr->op); + + return FALSE; + } + default: + _hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op); + } + return FALSE; +} + +HX509_LIB_FUNCTION int HX509_LIB_CALL +_hx509_expr_eval(hx509_context context, hx509_env env, struct hx_expr *expr) +{ + switch (expr->op) { + case op_TRUE: + return 1; + case op_FALSE: + return 0; + case op_NOT: + return ! _hx509_expr_eval(context, env, expr->arg1); + case op_AND: + return _hx509_expr_eval(context, env, expr->arg1) && + _hx509_expr_eval(context, env, expr->arg2); + case op_OR: + return _hx509_expr_eval(context, env, expr->arg1) || + _hx509_expr_eval(context, env, expr->arg2); + case op_COMP: + return eval_comp(context, env, expr->arg1); + default: + _hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op); + UNREACHABLE(return 0); + } +} + +HX509_LIB_FUNCTION void HX509_LIB_CALL +_hx509_expr_free(struct hx_expr *expr) +{ + switch (expr->op) { + case expr_STRING: + case expr_NUMBER: + free(expr->arg1); + break; + case expr_WORDS: + case expr_FUNCTION: + case expr_VAR: + free(expr->arg1); + if (expr->arg2) + _hx509_expr_free(expr->arg2); + break; + default: + if (expr->arg1) + _hx509_expr_free(expr->arg1); + if (expr->arg2) + _hx509_expr_free(expr->arg2); + break; + } + free(expr); +} + +/* XXX Horrible, no good cause not thread-safe */ +HX509_LIB_FUNCTION struct hx_expr * HX509_LIB_CALL +_hx509_expr_parse(const char *buf) +{ + _hx509_expr_input.buf = buf; + _hx509_expr_input.length = strlen(buf); + _hx509_expr_input.offset = 0; + _hx509_expr_input.expr = NULL; + + if (_hx509_expr_input.error) { + free(_hx509_expr_input.error); + _hx509_expr_input.error = NULL; + } + + yyparse(); + + return _hx509_expr_input.expr; +} + +const char * +_hx509_expr_parse_error(void) +{ + return _hx509_expr_input.error; +} + +void +_hx509_sel_yyerror (const char *s) +{ + if (_hx509_expr_input.error) + free(_hx509_expr_input.error); + + _hx509_expr_input.error = strdup(s); +} + diff --git a/third_party/heimdal/lib/hx509/sel.h b/third_party/heimdal/lib/hx509/sel.h new file mode 100644 index 0000000..daa471e --- /dev/null +++ b/third_party/heimdal/lib/hx509/sel.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +enum hx_expr_op { + op_TRUE, + op_FALSE, + op_NOT, + op_AND, + op_OR, + op_COMP, + + comp_EQ, + comp_NE, + comp_IN, + comp_TAILEQ, + + expr_NUMBER, + expr_STRING, + expr_FUNCTION, + expr_VAR, + expr_WORDS +}; + +struct hx_expr { + enum hx_expr_op op; + void *arg1; + void *arg2; +}; + +struct hx_expr_input { + const char *buf; + size_t length; + size_t offset; + struct hx_expr *expr; + char *error; +}; + +extern struct hx_expr_input _hx509_expr_input; + +/* + * With bison/flex, the more modern way to allow multiple yacc/lex grammars to + * be linked into a single executable is to use the + * + * bison: -p, --name-prefix=,PREFIX/, -Dapi.prefix=PREFIX + * flex: -Pprefix, --prefix=STRING + * + * options, these take care of renaming all the machine-generated global entry + * points, some of which are new. When these options are used "yylex", + * "yyparse", ... are already defined and our (potentially incomplete) attempt + * to do the same conflicts with the "right" new way to handle this. The below + * logic gets us out of the way when the job has already been taken care of by + * the parser-generator. + */ +#if !defined(yylex) +#define yylex _hx509_sel_yylex +#define yywrap _hx509_sel_yywrap +#endif +#if !defined(yyparse) +#define yyparse _hx509_sel_yyparse +#define yyerror _hx509_sel_yyerror +#define yylval _hx509_sel_yylval +#define yychar _hx509_sel_yychar +#define yydebug _hx509_sel_yydebug +#define yynerrs _hx509_sel_yynerrs +#endif + +int _hx509_sel_yyparse(void); +int _hx509_sel_yylex(void); +void _hx509_sel_yyerror(const char *); + diff --git a/third_party/heimdal/lib/hx509/softp11.c b/third_party/heimdal/lib/hx509/softp11.c new file mode 100644 index 0000000..75f6755 --- /dev/null +++ b/third_party/heimdal/lib/hx509/softp11.c @@ -0,0 +1,1777 @@ +/* + * Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define CRYPTOKI_EXPORTS 1 + +#include "hx_locl.h" +#include "ref/pkcs11.h" + +#define OBJECT_ID_MASK 0xfff +#define HANDLE_OBJECT_ID(h) ((h) & OBJECT_ID_MASK) +#define OBJECT_ID(obj) HANDLE_OBJECT_ID((obj)->object_handle) + +#ifndef HAVE_RANDOM +#define random() rand() +#define srandom(s) srand(s) +#endif + +#ifdef _WIN32 +#include +#endif + +struct st_attr { + CK_ATTRIBUTE attribute; + int secret; +}; + +struct st_object { + CK_OBJECT_HANDLE object_handle; + struct st_attr *attrs; + int num_attributes; + hx509_cert cert; +}; + +static struct soft_token { + CK_VOID_PTR application; + CK_NOTIFY notify; + char *config_file; + hx509_certs certs; + struct { + struct st_object **objs; + int num_objs; + } object; + struct { + int hardware_slot; + int app_error_fatal; + int login_done; + } flags; + int open_sessions; + struct session_state { + CK_SESSION_HANDLE session_handle; + + struct { + CK_ATTRIBUTE *attributes; + CK_ULONG num_attributes; + int next_object; + } find; + + int sign_object; + CK_MECHANISM_PTR sign_mechanism; + int verify_object; + CK_MECHANISM_PTR verify_mechanism; + } state[10]; +#define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0])) + FILE *logfile; +} soft_token; + +static hx509_context context; + +static void +application_error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + if (soft_token.flags.app_error_fatal) + abort(); +} + +static void +st_logf(const char *fmt, ...) +{ + va_list ap; + if (soft_token.logfile == NULL) + return; + va_start(ap, fmt); + vfprintf(soft_token.logfile, fmt, ap); + va_end(ap); + fflush(soft_token.logfile); +} + +static CK_RV +init_context(void) +{ + if (context == NULL) { + int ret = hx509_context_init(&context); + if (ret) + return CKR_GENERAL_ERROR; + } + return CKR_OK; +} + +#define INIT_CONTEXT() { CK_RV icret = init_context(); if (icret) return icret; } + +static void +snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...) +{ + int len; + va_list ap; + va_start(ap, fmt); + len = vsnprintf(str, size, fmt, ap); + va_end(ap); + if (len < 0 || (size_t)len > size) + return; + while ((size_t)len < size) + str[len++] = fillchar; +} + +#ifndef TEST_APP +#define printf error_use_st_logf +#endif + +#define VERIFY_SESSION_HANDLE(s, state) \ +{ \ + CK_RV xret; \ + xret = verify_session_handle(s, state); \ + if (xret != CKR_OK) { \ + /* return CKR_OK */; \ + } \ +} + +static CK_RV +verify_session_handle(CK_SESSION_HANDLE hSession, + struct session_state **state) +{ + size_t i; + + for (i = 0; i < MAX_NUM_SESSION; i++){ + if (soft_token.state[i].session_handle == hSession) + break; + } + if (i == MAX_NUM_SESSION) { + application_error("use of invalid handle: 0x%08lx\n", + (unsigned long)hSession); + return CKR_SESSION_HANDLE_INVALID; + } + if (state) + *state = &soft_token.state[i]; + return CKR_OK; +} + +static CK_RV +object_handle_to_object(CK_OBJECT_HANDLE handle, + struct st_object **object) +{ + int i = HANDLE_OBJECT_ID(handle); + + *object = NULL; + if (i >= soft_token.object.num_objs) + return CKR_ARGUMENTS_BAD; + if (soft_token.object.objs[i] == NULL) + return CKR_ARGUMENTS_BAD; + if (soft_token.object.objs[i]->object_handle != handle) + return CKR_ARGUMENTS_BAD; + *object = soft_token.object.objs[i]; + return CKR_OK; +} + +static int +attributes_match(const struct st_object *obj, + const CK_ATTRIBUTE *attributes, + CK_ULONG num_attributes) +{ + CK_ULONG i; + int j; + + st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj)); + + for (i = 0; i < num_attributes; i++) { + int match = 0; + for (j = 0; j < obj->num_attributes; j++) { + if (attributes[i].type == obj->attrs[j].attribute.type && + attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen && + memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue, + attributes[i].ulValueLen) == 0) { + match = 1; + break; + } + } + if (match == 0) { + st_logf("type %d attribute have no match\n", attributes[i].type); + return 0; + } + } + st_logf("attribute matches\n"); + return 1; +} + +static void +print_attributes(const CK_ATTRIBUTE *attributes, + CK_ULONG num_attributes) +{ + CK_ULONG i; + + st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes); + + for (i = 0; i < num_attributes; i++) { + st_logf(" type: "); + switch (attributes[i].type) { + case CKA_TOKEN: { + CK_BBOOL *ck_true; + if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) { + application_error("token attribute wrong length\n"); + break; + } + ck_true = attributes[i].pValue; + st_logf("token: %s", *ck_true ? "TRUE" : "FALSE"); + break; + } + case CKA_CLASS: { + CK_OBJECT_CLASS *class; + if (attributes[i].ulValueLen != sizeof(CK_ULONG)) { + application_error("class attribute wrong length\n"); + break; + } + class = attributes[i].pValue; + st_logf("class "); + switch (*class) { + case CKO_CERTIFICATE: + st_logf("certificate"); + break; + case CKO_PUBLIC_KEY: + st_logf("public key"); + break; + case CKO_PRIVATE_KEY: + st_logf("private key"); + break; + case CKO_SECRET_KEY: + st_logf("secret key"); + break; + case CKO_DOMAIN_PARAMETERS: + st_logf("domain parameters"); + break; + default: + st_logf("[class %lx]", (long unsigned)*class); + break; + } + break; + } + case CKA_PRIVATE: + st_logf("private"); + break; + case CKA_LABEL: + st_logf("label"); + break; + case CKA_APPLICATION: + st_logf("application"); + break; + case CKA_VALUE: + st_logf("value"); + break; + case CKA_ID: + st_logf("id"); + break; + default: + st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type); + break; + } + st_logf("\n"); + } +} + +static struct st_object * +add_st_object(void) +{ + struct st_object *o, **objs; + int i; + + o = calloc(1, sizeof(*o)); + if (o == NULL) + return NULL; + + for (i = 0; i < soft_token.object.num_objs; i++) { + if (soft_token.object.objs[i] == NULL) { + soft_token.object.objs[i] = o; + break; + } + } + if (i == soft_token.object.num_objs) { + objs = realloc(soft_token.object.objs, + (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0])); + if (objs == NULL) { + free(o); + return NULL; + } + soft_token.object.objs = objs; + soft_token.object.objs[soft_token.object.num_objs++] = o; + } + soft_token.object.objs[i]->object_handle = + (random() & (~OBJECT_ID_MASK)) | i; + + return o; +} + +static CK_RV +add_object_attribute(struct st_object *o, + int secret, + CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR pValue, + CK_ULONG ulValueLen) +{ + struct st_attr *a; + int i; + + if (pValue == NULL && ulValueLen) + return CKR_ARGUMENTS_BAD; + + i = o->num_attributes; + a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0])); + if (a == NULL) + return CKR_DEVICE_MEMORY; + o->attrs = a; + o->attrs[i].secret = secret; + o->attrs[i].attribute.type = type; + o->attrs[i].attribute.pValue = malloc(ulValueLen); + if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0) + return CKR_DEVICE_MEMORY; + if (ulValueLen) + memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen); + o->attrs[i].attribute.ulValueLen = ulValueLen; + o->num_attributes++; + + return CKR_OK; +} + +static CK_RV +add_pubkey_info(hx509_context hxctx, struct st_object *o, + CK_KEY_TYPE key_type, hx509_cert cert) +{ + BIGNUM *num; + CK_BYTE *modulus = NULL; + size_t modulus_len = 0; + CK_ULONG modulus_bits = 0; + CK_BYTE *exponent = NULL; + size_t exponent_len = 0; + + if (key_type != CKK_RSA) + return CKR_OK; + if (_hx509_cert_private_key(cert) == NULL) + return CKR_OK; + + num = _hx509_private_key_get_internal(context, + _hx509_cert_private_key(cert), + "rsa-modulus"); + if (num == NULL) + return CKR_GENERAL_ERROR; + modulus_bits = BN_num_bits(num); + + modulus_len = BN_num_bytes(num); + modulus = malloc(modulus_len); + BN_bn2bin(num, modulus); + BN_free(num); + + add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len); + add_object_attribute(o, 0, CKA_MODULUS_BITS, + &modulus_bits, sizeof(modulus_bits)); + + free(modulus); + + num = _hx509_private_key_get_internal(context, + _hx509_cert_private_key(cert), + "rsa-exponent"); + if (num == NULL) + return CKR_GENERAL_ERROR; + + exponent_len = BN_num_bytes(num); + exponent = malloc(exponent_len); + BN_bn2bin(num, exponent); + BN_free(num); + + add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT, + exponent, exponent_len); + + free(exponent); + + return CKR_OK; +} + + +struct foo { + char *label; + char *id; +}; + +static int HX509_LIB_CALL +add_cert(hx509_context hxctx, void *ctx, hx509_cert cert) +{ + static char empty[] = ""; + struct foo *foo = (struct foo *)ctx; + struct st_object *o = NULL; + CK_OBJECT_CLASS type; + CK_BBOOL bool_true = CK_TRUE; + CK_BBOOL bool_false = CK_FALSE; + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_KEY_TYPE key_type; + CK_MECHANISM_TYPE mech_type; + CK_RV ret = CKR_GENERAL_ERROR; + int hret; + heim_octet_string cert_data, subject_data, issuer_data, serial_data; + + st_logf("adding certificate\n"); + + serial_data.data = NULL; + serial_data.length = 0; + cert_data = subject_data = issuer_data = serial_data; + + hret = hx509_cert_binary(hxctx, cert, &cert_data); + if (hret) + goto out; + + { + hx509_name name; + + hret = hx509_cert_get_issuer(cert, &name); + if (hret) + goto out; + hret = hx509_name_binary(name, &issuer_data); + hx509_name_free(&name); + if (hret) + goto out; + + hret = hx509_cert_get_subject(cert, &name); + if (hret) + goto out; + hret = hx509_name_binary(name, &subject_data); + hx509_name_free(&name); + if (hret) + goto out; + } + + { + AlgorithmIdentifier alg; + + hret = hx509_cert_get_SPKI_AlgorithmIdentifier(context, cert, &alg); + if (hret) { + ret = CKR_DEVICE_MEMORY; + goto out; + } + + key_type = CKK_RSA; /* XXX */ + + free_AlgorithmIdentifier(&alg); + } + + + type = CKO_CERTIFICATE; + o = add_st_object(); + if (o == NULL) { + ret = CKR_DEVICE_MEMORY; + goto out; + } + + o->cert = hx509_cert_ref(cert); + + add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type)); + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label)); + + add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)); + add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id)); + + add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length); + add_object_attribute(o, 0, CKA_ISSUER, issuer_data.data, issuer_data.length); + add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data.data, serial_data.length); + add_object_attribute(o, 0, CKA_VALUE, cert_data.data, cert_data.length); + add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false)); + + st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o)); + + type = CKO_PUBLIC_KEY; + o = add_st_object(); + if (o == NULL) { + ret = CKR_DEVICE_MEMORY; + goto out; + } + o->cert = hx509_cert_ref(cert); + + add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type)); + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label)); + + add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type)); + add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id)); + add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */ + add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */ + add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false)); + mech_type = CKM_RSA_X_509; + add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type)); + + add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length); + add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true)); + + add_pubkey_info(hxctx, o, key_type, cert); + + st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o)); + + if (hx509_cert_have_private_key(cert)) { + CK_FLAGS flags; + + type = CKO_PRIVATE_KEY; + + /* Note to static analyzers: `o' is still referred to via globals */ + o = add_st_object(); + if (o == NULL) { + ret = CKR_DEVICE_MEMORY; + goto out; + } + o->cert = hx509_cert_ref(cert); + + add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type)); + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label)); + + add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type)); + add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id)); + add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */ + add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */ + add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false)); + mech_type = CKM_RSA_X_509; + add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type)); + + add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length); + add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true)); + flags = 0; + add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags)); + + add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false)); + add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true)); + add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false)); + + add_pubkey_info(hxctx, o, key_type, cert); + } + + ret = CKR_OK; + out: + if (ret != CKR_OK) { + st_logf("something went wrong when adding cert!\n"); + + /* XXX wack o */; + } + hx509_xfree(cert_data.data); + hx509_xfree(serial_data.data); + hx509_xfree(issuer_data.data); + hx509_xfree(subject_data.data); + + /* Note to static analyzers: `o' is still referred to via globals */ + return 0; +} + +static CK_RV +add_certificate(const char *cert_file, + const char *pin, + char *id, + char *label) +{ + hx509_certs certs; + hx509_lock lock = NULL; + int ret, flags = 0; + + struct foo foo; + foo.id = id; + foo.label = label; + + if (pin == NULL) + flags |= HX509_CERTS_UNPROTECT_ALL; + + if (pin) { + char *str; + ret = asprintf(&str, "PASS:%s", pin); + if (ret == -1 || !str) { + st_logf("failed to allocate memory\n"); + return CKR_GENERAL_ERROR; + } + + hx509_lock_init(context, &lock); + hx509_lock_command_string(lock, str); + + memset(str, 0, strlen(str)); + free(str); + } + + ret = hx509_certs_init(context, cert_file, flags, lock, &certs); + if (ret) { + st_logf("failed to open file %s\n", cert_file); + return CKR_GENERAL_ERROR; + } + + ret = hx509_certs_iter_f(context, certs, add_cert, &foo); + hx509_certs_free(&certs); + if (ret) { + st_logf("failed adding certs from file %s\n", cert_file); + return CKR_GENERAL_ERROR; + } + + return CKR_OK; +} + +static void +find_object_final(struct session_state *state) +{ + if (state->find.attributes) { + CK_ULONG i; + + for (i = 0; i < state->find.num_attributes; i++) { + if (state->find.attributes[i].pValue) + free(state->find.attributes[i].pValue); + } + free(state->find.attributes); + state->find.attributes = NULL; + state->find.num_attributes = 0; + state->find.next_object = -1; + } +} + +static void +reset_crypto_state(struct session_state *state) +{ + state->sign_object = -1; + if (state->sign_mechanism) + free(state->sign_mechanism); + state->sign_mechanism = NULL_PTR; + state->verify_object = -1; + if (state->verify_mechanism) + free(state->verify_mechanism); + state->verify_mechanism = NULL_PTR; +} + +static void +close_session(struct session_state *state) +{ + if (state->find.attributes) { + application_error("application didn't do C_FindObjectsFinal\n"); + find_object_final(state); + } + + state->session_handle = CK_INVALID_HANDLE; + soft_token.application = NULL_PTR; + soft_token.notify = NULL_PTR; + reset_crypto_state(state); +} + +static const char * +has_session(void) +{ + return soft_token.open_sessions > 0 ? "yes" : "no"; +} + +static CK_RV +read_conf_file(const char *fn, CK_USER_TYPE userType, const char *pin) +{ + char buf[1024], *type, *s, *p; + FILE *f; + CK_RV ret = CKR_OK; + CK_RV failed = CKR_OK; + + if (fn == NULL) { + st_logf("Can't open configuration file. No file specified\n"); + return CKR_GENERAL_ERROR; + } + + f = fopen(fn, "r"); + if (f == NULL) { + st_logf("can't open configuration file %s\n", fn); + return CKR_GENERAL_ERROR; + } + rk_cloexec_file(f); + + while(fgets(buf, sizeof(buf), f) != NULL) { + buf[strcspn(buf, "\n")] = '\0'; + + st_logf("line: %s\n", buf); + + p = buf; + while (isspace((unsigned char)*p)) + p++; + if (*p == '#') + continue; + while (isspace((unsigned char)*p)) + p++; + + s = NULL; + type = strtok_r(p, "\t", &s); + if (type == NULL) + continue; + + if (strcasecmp("certificate", type) == 0) { + char *cert, *id, *label; + + id = strtok_r(NULL, "\t", &s); + if (id == NULL) { + st_logf("no id\n"); + continue; + } + st_logf("id: %s\n", id); + label = strtok_r(NULL, "\t", &s); + if (label == NULL) { + st_logf("no label\n"); + continue; + } + cert = strtok_r(NULL, "\t", &s); + if (cert == NULL) { + st_logf("no certfiicate store\n"); + continue; + } + + st_logf("adding: %s: %s in file %s\n", id, label, cert); + + ret = add_certificate(cert, pin, id, label); + if (ret) + failed = ret; + } else if (strcasecmp("debug", type) == 0) { + char *name; + + name = strtok_r(NULL, "\t", &s); + if (name == NULL) { + st_logf("no filename\n"); + continue; + } + + if (soft_token.logfile) + fclose(soft_token.logfile); + + if (strcasecmp(name, "stdout") == 0) + soft_token.logfile = stdout; + else { + soft_token.logfile = fopen(name, "a"); + if (soft_token.logfile) + rk_cloexec_file(soft_token.logfile); + } + if (soft_token.logfile == NULL) + st_logf("failed to open file: %s\n", name); + + } else if (strcasecmp("app-fatal", type) == 0) { + char *name; + + name = strtok_r(NULL, "\t", &s); + if (name == NULL) { + st_logf("argument to app-fatal\n"); + continue; + } + + if (strcmp(name, "true") == 0 || strcmp(name, "on") == 0) + soft_token.flags.app_error_fatal = 1; + else if (strcmp(name, "false") == 0 || strcmp(name, "off") == 0) + soft_token.flags.app_error_fatal = 0; + else + st_logf("unknown app-fatal: %s\n", name); + + } else { + st_logf("unknown type: %s\n", type); + } + } + + fclose(f); + + return failed; +} + +static CK_RV +func_not_supported(void) +{ + st_logf("function not supported\n"); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +static char * +get_config_file_for_user(void) +{ + char *fn; + int ret; + + fn = secure_getenv("SOFTPKCS11RC"); + if (fn) + fn = strdup(fn); + if (fn == NULL) { + char homebuf[MAX_PATH]; + const char *home = roken_get_appdatadir(homebuf, sizeof(homebuf)); + + if (home) { + ret = asprintf(&fn, "%s/.soft-token.rc", home); + if (ret == -1) + fn = NULL; + } else { +#ifndef WIN32 + fn = strdup("/etc/soft-token.rc"); +#endif + } + } + + return fn; +} + + +CK_RV CK_SPEC +C_Initialize(CK_VOID_PTR a) +{ + CK_C_INITIALIZE_ARGS_PTR args = a; + CK_RV ret; + size_t i; + + st_logf("Initialize\n"); + + INIT_CONTEXT(); + + OpenSSL_add_all_algorithms(); + + srandom(getpid() ^ (int) time(NULL)); + + for (i = 0; i < MAX_NUM_SESSION; i++) { + soft_token.state[i].session_handle = CK_INVALID_HANDLE; + soft_token.state[i].find.attributes = NULL; + soft_token.state[i].find.num_attributes = 0; + soft_token.state[i].find.next_object = -1; + reset_crypto_state(&soft_token.state[i]); + } + + soft_token.flags.hardware_slot = 1; + soft_token.flags.app_error_fatal = 0; + soft_token.flags.login_done = 0; + + soft_token.object.objs = NULL; + soft_token.object.num_objs = 0; + + soft_token.logfile = NULL; +#if 0 + soft_token.logfile = stdout; +#endif +#if 0 + soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a"); +#endif + + if (a != NULL_PTR) { + st_logf("\tCreateMutex:\t%p\n", args->CreateMutex); + st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex); + st_logf("\tLockMutext\t%p\n", args->LockMutex); + st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex); + st_logf("\tFlags\t%04x\n", (unsigned int)args->flags); + } + + soft_token.config_file = get_config_file_for_user(); + + /* + * This operations doesn't return CKR_OK if any of the + * certificates failes to be unparsed (ie password protected). + */ + ret = read_conf_file(soft_token.config_file, CKU_USER, NULL); + if (ret == CKR_OK) + soft_token.flags.login_done = 1; + + return CKR_OK; +} + +CK_RV +C_Finalize(CK_VOID_PTR args) +{ + size_t i; + + INIT_CONTEXT(); + + st_logf("Finalize\n"); + + for (i = 0; i < MAX_NUM_SESSION; i++) { + if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) { + application_error("application finalized without " + "closing session\n"); + close_session(&soft_token.state[i]); + } + } + + return CKR_OK; +} + +CK_RV +C_GetInfo(CK_INFO_PTR args) +{ + INIT_CONTEXT(); + + st_logf("GetInfo\n"); + + memset(args, 17, sizeof(*args)); + args->cryptokiVersion.major = 2; + args->cryptokiVersion.minor = 10; + snprintf_fill((char *)args->manufacturerID, + sizeof(args->manufacturerID), + ' ', + "Heimdal hx509 SoftToken"); + snprintf_fill((char *)args->libraryDescription, + sizeof(args->libraryDescription), ' ', + "Heimdal hx509 SoftToken"); + args->libraryVersion.major = 2; + args->libraryVersion.minor = 0; + + return CKR_OK; +} + +extern CK_FUNCTION_LIST funcs; + +CK_RV +C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) +{ + INIT_CONTEXT(); + + *ppFunctionList = &funcs; + return CKR_OK; +} + +CK_RV +C_GetSlotList(CK_BBOOL tokenPresent, + CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pulCount) +{ + INIT_CONTEXT(); + st_logf("GetSlotList: %s\n", + tokenPresent ? "tokenPresent" : "token not Present"); + if (pSlotList) + pSlotList[0] = 1; + *pulCount = 1; + return CKR_OK; +} + +CK_RV +C_GetSlotInfo(CK_SLOT_ID slotID, + CK_SLOT_INFO_PTR pInfo) +{ + INIT_CONTEXT(); + st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session()); + + memset(pInfo, 18, sizeof(*pInfo)); + + if (slotID != 1) + return CKR_ARGUMENTS_BAD; + + snprintf_fill((char *)pInfo->slotDescription, + sizeof(pInfo->slotDescription), + ' ', + "Heimdal hx509 SoftToken (slot)"); + snprintf_fill((char *)pInfo->manufacturerID, + sizeof(pInfo->manufacturerID), + ' ', + "Heimdal hx509 SoftToken (slot)"); + pInfo->flags = CKF_TOKEN_PRESENT; + if (soft_token.flags.hardware_slot) + pInfo->flags |= CKF_HW_SLOT; + pInfo->hardwareVersion.major = 1; + pInfo->hardwareVersion.minor = 0; + pInfo->firmwareVersion.major = 1; + pInfo->firmwareVersion.minor = 0; + + return CKR_OK; +} + +CK_RV +C_GetTokenInfo(CK_SLOT_ID slotID, + CK_TOKEN_INFO_PTR pInfo) +{ + INIT_CONTEXT(); + st_logf("GetTokenInfo: %s\n", has_session()); + + memset(pInfo, 19, sizeof(*pInfo)); + + snprintf_fill((char *)pInfo->label, + sizeof(pInfo->label), + ' ', + "Heimdal hx509 SoftToken (token)"); + snprintf_fill((char *)pInfo->manufacturerID, + sizeof(pInfo->manufacturerID), + ' ', + "Heimdal hx509 SoftToken (token)"); + snprintf_fill((char *)pInfo->model, + sizeof(pInfo->model), + ' ', + "Heimdal hx509 SoftToken (token)"); + snprintf_fill((char *)pInfo->serialNumber, + sizeof(pInfo->serialNumber), + ' ', + "4711"); + pInfo->flags = + CKF_TOKEN_INITIALIZED | + CKF_USER_PIN_INITIALIZED; + + if (soft_token.flags.login_done == 0) + pInfo->flags |= CKF_LOGIN_REQUIRED; + + /* CFK_RNG | + CKF_RESTORE_KEY_NOT_NEEDED | + */ + pInfo->ulMaxSessionCount = MAX_NUM_SESSION; + pInfo->ulSessionCount = soft_token.open_sessions; + pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION; + pInfo->ulRwSessionCount = soft_token.open_sessions; + pInfo->ulMaxPinLen = 1024; + pInfo->ulMinPinLen = 0; + pInfo->ulTotalPublicMemory = 4711; + pInfo->ulFreePublicMemory = 4712; + pInfo->ulTotalPrivateMemory = 4713; + pInfo->ulFreePrivateMemory = 4714; + pInfo->hardwareVersion.major = 2; + pInfo->hardwareVersion.minor = 0; + pInfo->firmwareVersion.major = 2; + pInfo->firmwareVersion.minor = 0; + + return CKR_OK; +} + +CK_RV +C_GetMechanismList(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + INIT_CONTEXT(); + st_logf("GetMechanismList\n"); + + *pulCount = 1; + if (pMechanismList == NULL_PTR) + return CKR_OK; + pMechanismList[0] = CKM_RSA_PKCS; + + return CKR_OK; +} + +CK_RV +C_GetMechanismInfo(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + INIT_CONTEXT(); + st_logf("GetMechanismInfo: slot %d type: %d\n", + (int)slotID, (int)type); + memset(pInfo, 0, sizeof(*pInfo)); + + return CKR_OK; +} + +CK_RV +C_InitToken(CK_SLOT_ID slotID, + CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen, + CK_UTF8CHAR_PTR pLabel) +{ + INIT_CONTEXT(); + st_logf("InitToken: slot %d\n", (int)slotID); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_OpenSession(CK_SLOT_ID slotID, + CK_FLAGS flags, + CK_VOID_PTR pApplication, + CK_NOTIFY Notify, + CK_SESSION_HANDLE_PTR phSession) +{ + size_t i; + INIT_CONTEXT(); + st_logf("OpenSession: slot: %d\n", (int)slotID); + + if (soft_token.open_sessions == MAX_NUM_SESSION) + return CKR_SESSION_COUNT; + + soft_token.application = pApplication; + soft_token.notify = Notify; + + for (i = 0; i < MAX_NUM_SESSION; i++) + if (soft_token.state[i].session_handle == CK_INVALID_HANDLE) + break; + if (i == MAX_NUM_SESSION) + abort(); + + soft_token.open_sessions++; + + soft_token.state[i].session_handle = + (CK_SESSION_HANDLE)(random() & 0xfffff); + *phSession = soft_token.state[i].session_handle; + + return CKR_OK; +} + +CK_RV +C_CloseSession(CK_SESSION_HANDLE hSession) +{ + struct session_state *state; + INIT_CONTEXT(); + st_logf("CloseSession\n"); + + if (verify_session_handle(hSession, &state) != CKR_OK) + application_error("closed session not open"); + else + close_session(state); + + return CKR_OK; +} + +CK_RV +C_CloseAllSessions(CK_SLOT_ID slotID) +{ + size_t i; + INIT_CONTEXT(); + + st_logf("CloseAllSessions\n"); + + for (i = 0; i < MAX_NUM_SESSION; i++) + if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) + close_session(&soft_token.state[i]); + + return CKR_OK; +} + +CK_RV +C_GetSessionInfo(CK_SESSION_HANDLE hSession, + CK_SESSION_INFO_PTR pInfo) +{ + st_logf("GetSessionInfo\n"); + INIT_CONTEXT(); + + VERIFY_SESSION_HANDLE(hSession, NULL); + + memset(pInfo, 20, sizeof(*pInfo)); + + pInfo->slotID = 1; + if (soft_token.flags.login_done) + pInfo->state = CKS_RO_USER_FUNCTIONS; + else + pInfo->state = CKS_RO_PUBLIC_SESSION; + pInfo->flags = CKF_SERIAL_SESSION; + pInfo->ulDeviceError = 0; + + return CKR_OK; +} + +CK_RV +C_Login(CK_SESSION_HANDLE hSession, + CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, + CK_ULONG ulPinLen) +{ + char *pin = NULL; + CK_RV ret; + INIT_CONTEXT(); + + st_logf("Login\n"); + + VERIFY_SESSION_HANDLE(hSession, NULL); + + if (pPin != NULL_PTR) { + int aret; + + aret = asprintf(&pin, "%.*s", (int)ulPinLen, pPin); + if (aret != -1 && pin) + st_logf("type: %d password: %s\n", (int)userType, pin); + else + st_logf("memory error: asprintf failed\n"); + } + + /* + * Login + */ + + ret = read_conf_file(soft_token.config_file, userType, pin); + if (ret == CKR_OK) + soft_token.flags.login_done = 1; + + free(pin); + + return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT; +} + +CK_RV +C_Logout(CK_SESSION_HANDLE hSession) +{ + st_logf("Logout\n"); + INIT_CONTEXT(); + + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_GetObjectSize(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ULONG_PTR pulSize) +{ + st_logf("GetObjectSize\n"); + INIT_CONTEXT(); + + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_GetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + struct session_state *state; + struct st_object *obj; + CK_ULONG i; + CK_RV ret; + int j; + + INIT_CONTEXT(); + + st_logf("GetAttributeValue: %lx\n", + (unsigned long)HANDLE_OBJECT_ID(hObject)); + VERIFY_SESSION_HANDLE(hSession, &state); + + if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) { + st_logf("object not found: %lx\n", + (unsigned long)HANDLE_OBJECT_ID(hObject)); + return ret; + } + + for (i = 0; i < ulCount; i++) { + st_logf(" getting 0x%08lx\n", (unsigned long)pTemplate[i].type); + for (j = 0; j < obj->num_attributes; j++) { + if (obj->attrs[j].secret) { + pTemplate[i].ulValueLen = (CK_ULONG)-1; + break; + } + if (pTemplate[i].type == obj->attrs[j].attribute.type) { + if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) { + if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen) + memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue, + obj->attrs[j].attribute.ulValueLen); + } + pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen; + break; + } + } + if (j == obj->num_attributes) { + st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type); + pTemplate[i].ulValueLen = (CK_ULONG)-1; + } + + } + return CKR_OK; +} + +CK_RV +C_FindObjectsInit(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + struct session_state *state; + + st_logf("FindObjectsInit\n"); + + INIT_CONTEXT(); + + VERIFY_SESSION_HANDLE(hSession, &state); + + if (state->find.next_object != -1) { + application_error("application didn't do C_FindObjectsFinal\n"); + find_object_final(state); + } + if (ulCount) { + CK_ULONG i; + + print_attributes(pTemplate, ulCount); + + state->find.attributes = + calloc(1, ulCount * sizeof(state->find.attributes[0])); + if (state->find.attributes == NULL) + return CKR_DEVICE_MEMORY; + for (i = 0; i < ulCount; i++) { + state->find.attributes[i].pValue = + malloc(pTemplate[i].ulValueLen); + if (state->find.attributes[i].pValue == NULL) { + find_object_final(state); + return CKR_DEVICE_MEMORY; + } + memcpy(state->find.attributes[i].pValue, + pTemplate[i].pValue, pTemplate[i].ulValueLen); + state->find.attributes[i].type = pTemplate[i].type; + state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen; + } + state->find.num_attributes = ulCount; + state->find.next_object = 0; + } else { + st_logf("find all objects\n"); + state->find.attributes = NULL; + state->find.num_attributes = 0; + state->find.next_object = 0; + } + + return CKR_OK; +} + +CK_RV +C_FindObjects(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount) +{ + struct session_state *state; + int i; + + INIT_CONTEXT(); + + st_logf("FindObjects\n"); + + VERIFY_SESSION_HANDLE(hSession, &state); + + if (state->find.next_object == -1) { + application_error("application didn't do C_FindObjectsInit\n"); + return CKR_ARGUMENTS_BAD; + } + if (ulMaxObjectCount == 0) { + application_error("application asked for 0 objects\n"); + return CKR_ARGUMENTS_BAD; + } + *pulObjectCount = 0; + for (i = state->find.next_object; i < soft_token.object.num_objs; i++) { + st_logf("FindObjects: %d\n", i); + state->find.next_object = i + 1; + if (attributes_match(soft_token.object.objs[i], + state->find.attributes, + state->find.num_attributes)) { + *phObject++ = soft_token.object.objs[i]->object_handle; + ulMaxObjectCount--; + (*pulObjectCount)++; + if (ulMaxObjectCount == 0) + break; + } + } + return CKR_OK; +} + +CK_RV +C_FindObjectsFinal(CK_SESSION_HANDLE hSession) +{ + struct session_state *state; + + INIT_CONTEXT(); + + st_logf("FindObjectsFinal\n"); + VERIFY_SESSION_HANDLE(hSession, &state); + find_object_final(state); + return CKR_OK; +} + +static CK_RV +commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len, + const CK_MECHANISM_TYPE *mechs, int mechs_len, + const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, + struct st_object **o) +{ + CK_RV ret; + int i; + + *o = NULL; + if ((ret = object_handle_to_object(hKey, o)) != CKR_OK) + return ret; + + ret = attributes_match(*o, attr_match, attr_match_len); + if (!ret) { + application_error("called commonInit on key that doesn't " + "support required attr"); + return CKR_ARGUMENTS_BAD; + } + + for (i = 0; i < mechs_len; i++) + if (mechs[i] == pMechanism->mechanism) + break; + if (i == mechs_len) { + application_error("called mech (%08lx) not supported\n", + pMechanism->mechanism); + return CKR_ARGUMENTS_BAD; + } + return CKR_OK; +} + + +static CK_RV +dup_mechanism(CK_MECHANISM_PTR *dp, const CK_MECHANISM_PTR pMechanism) +{ + CK_MECHANISM_PTR p; + + p = malloc(sizeof(*p)); + if (p == NULL) + return CKR_DEVICE_MEMORY; + + if (*dp) + free(*dp); + *dp = p; + memcpy(p, pMechanism, sizeof(*p)); + + return CKR_OK; +} + +CK_RV +C_DigestInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism) +{ + st_logf("DigestInit\n"); + INIT_CONTEXT(); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_SignInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + struct session_state *state; + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS }; + CK_BBOOL bool_true = CK_TRUE; + CK_ATTRIBUTE attr[] = { + { CKA_SIGN, &bool_true, sizeof(bool_true) } + }; + struct st_object *o; + CK_RV ret; + + INIT_CONTEXT(); + st_logf("SignInit\n"); + VERIFY_SESSION_HANDLE(hSession, &state); + + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), + mechs, sizeof(mechs)/sizeof(mechs[0]), + pMechanism, hKey, &o); + if (ret) + return ret; + + ret = dup_mechanism(&state->sign_mechanism, pMechanism); + if (ret == CKR_OK) + state->sign_object = OBJECT_ID(o); + + return CKR_OK; +} + +CK_RV +C_Sign(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + struct session_state *state; + struct st_object *o; + CK_RV ret; + int hret; + const AlgorithmIdentifier *alg; + heim_octet_string sig, data; + + INIT_CONTEXT(); + st_logf("Sign\n"); + VERIFY_SESSION_HANDLE(hSession, &state); + + sig.data = NULL; + sig.length = 0; + + if (state->sign_object == -1) + return CKR_ARGUMENTS_BAD; + + if (pulSignatureLen == NULL) { + st_logf("signature len NULL\n"); + ret = CKR_ARGUMENTS_BAD; + goto out; + } + + if (pData == NULL_PTR) { + st_logf("data NULL\n"); + ret = CKR_ARGUMENTS_BAD; + goto out; + } + + o = soft_token.object.objs[state->sign_object]; + + if (hx509_cert_have_private_key(o->cert) == 0) { + st_logf("private key NULL\n"); + return CKR_ARGUMENTS_BAD; + } + + switch(state->sign_mechanism->mechanism) { + case CKM_RSA_PKCS: + alg = hx509_signature_rsa_pkcs1_x509(); + break; + default: + ret = CKR_FUNCTION_NOT_SUPPORTED; + goto out; + } + + data.data = pData; + data.length = ulDataLen; + + hret = _hx509_create_signature(context, + _hx509_cert_private_key(o->cert), + alg, + &data, + NULL, + &sig); + if (hret) { + ret = CKR_DEVICE_ERROR; + goto out; + } + *pulSignatureLen = sig.length; + + if (pSignature != NULL_PTR) + memcpy(pSignature, sig.data, sig.length); + + ret = CKR_OK; + out: + if (sig.data) { + memset(sig.data, 0, sig.length); + der_free_octet_string(&sig); + } + return ret; +} + +CK_RV +C_SignUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen) +{ + INIT_CONTEXT(); + st_logf("SignUpdate\n"); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV +C_SignFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + INIT_CONTEXT(); + st_logf("SignUpdate\n"); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_VerifyInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey) +{ + struct session_state *state; + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS }; + CK_BBOOL bool_true = CK_TRUE; + CK_ATTRIBUTE attr[] = { + { CKA_VERIFY, &bool_true, sizeof(bool_true) } + }; + struct st_object *o; + CK_RV ret; + + INIT_CONTEXT(); + st_logf("VerifyInit\n"); + VERIFY_SESSION_HANDLE(hSession, &state); + + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]), + mechs, sizeof(mechs)/sizeof(mechs[0]), + pMechanism, hKey, &o); + if (ret) + return ret; + + ret = dup_mechanism(&state->verify_mechanism, pMechanism); + if (ret == CKR_OK) + state->verify_object = OBJECT_ID(o); + + return ret; +} + +CK_RV +C_Verify(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + struct session_state *state; + struct st_object *o; + const AlgorithmIdentifier *alg; + CK_RV ret; + int hret; + heim_octet_string data, sig; + + INIT_CONTEXT(); + st_logf("Verify\n"); + VERIFY_SESSION_HANDLE(hSession, &state); + + if (state->verify_object == -1) + return CKR_ARGUMENTS_BAD; + + o = soft_token.object.objs[state->verify_object]; + + switch(state->verify_mechanism->mechanism) { + case CKM_RSA_PKCS: + alg = hx509_signature_rsa_pkcs1_x509(); + break; + default: + ret = CKR_FUNCTION_NOT_SUPPORTED; + goto out; + } + + sig.data = pData; + sig.length = ulDataLen; + data.data = pSignature; + data.length = ulSignatureLen; + + hret = _hx509_verify_signature(context, + o->cert, + alg, + &data, + &sig); + if (hret) { + ret = CKR_GENERAL_ERROR; + goto out; + } + ret = CKR_OK; + + out: + return ret; +} + + +CK_RV +C_VerifyUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen) +{ + INIT_CONTEXT(); + st_logf("VerifyUpdate\n"); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_VerifyFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + INIT_CONTEXT(); + st_logf("VerifyFinal\n"); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV +C_GenerateRandom(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR RandomData, + CK_ULONG ulRandomLen) +{ + INIT_CONTEXT(); + st_logf("GenerateRandom\n"); + VERIFY_SESSION_HANDLE(hSession, NULL); + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_FUNCTION_LIST funcs = { + { 2, 11 }, + C_Initialize, + C_Finalize, + C_GetInfo, + C_GetFunctionList, + C_GetSlotList, + C_GetSlotInfo, + C_GetTokenInfo, + C_GetMechanismList, + C_GetMechanismInfo, + C_InitToken, + (void *)func_not_supported, /* C_InitPIN */ + (void *)func_not_supported, /* C_SetPIN */ + C_OpenSession, + C_CloseSession, + C_CloseAllSessions, + C_GetSessionInfo, + (void *)func_not_supported, /* C_GetOperationState */ + (void *)func_not_supported, /* C_SetOperationState */ + C_Login, + C_Logout, + (void *)func_not_supported, /* C_CreateObject */ + (void *)func_not_supported, /* C_CopyObject */ + (void *)func_not_supported, /* C_DestroyObject */ + (void *)func_not_supported, /* C_GetObjectSize */ + C_GetAttributeValue, + (void *)func_not_supported, /* C_SetAttributeValue */ + C_FindObjectsInit, + C_FindObjects, + C_FindObjectsFinal, + (void *)func_not_supported, /* C_EncryptInit, */ + (void *)func_not_supported, /* C_Encrypt, */ + (void *)func_not_supported, /* C_EncryptUpdate, */ + (void *)func_not_supported, /* C_EncryptFinal, */ + (void *)func_not_supported, /* C_DecryptInit, */ + (void *)func_not_supported, /* C_Decrypt, */ + (void *)func_not_supported, /* C_DecryptUpdate, */ + (void *)func_not_supported, /* C_DecryptFinal, */ + C_DigestInit, + (void *)func_not_supported, /* C_Digest */ + (void *)func_not_supported, /* C_DigestUpdate */ + (void *)func_not_supported, /* C_DigestKey */ + (void *)func_not_supported, /* C_DigestFinal */ + C_SignInit, + C_Sign, + C_SignUpdate, + C_SignFinal, + (void *)func_not_supported, /* C_SignRecoverInit */ + (void *)func_not_supported, /* C_SignRecover */ + C_VerifyInit, + C_Verify, + C_VerifyUpdate, + C_VerifyFinal, + (void *)func_not_supported, /* C_VerifyRecoverInit */ + (void *)func_not_supported, /* C_VerifyRecover */ + (void *)func_not_supported, /* C_DigestEncryptUpdate */ + (void *)func_not_supported, /* C_DecryptDigestUpdate */ + (void *)func_not_supported, /* C_SignEncryptUpdate */ + (void *)func_not_supported, /* C_DecryptVerifyUpdate */ + (void *)func_not_supported, /* C_GenerateKey */ + (void *)func_not_supported, /* C_GenerateKeyPair */ + (void *)func_not_supported, /* C_WrapKey */ + (void *)func_not_supported, /* C_UnwrapKey */ + (void *)func_not_supported, /* C_DeriveKey */ + (void *)func_not_supported, /* C_SeedRandom */ + C_GenerateRandom, + (void *)func_not_supported, /* C_GetFunctionStatus */ + (void *)func_not_supported, /* C_CancelFunction */ + (void *)func_not_supported /* C_WaitForSlotEvent */ +}; diff --git a/third_party/heimdal/lib/hx509/test_ca.in b/third_party/heimdal/lib/hx509/test_ca.in new file mode 100644 index 0000000..cf739a1 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_ca.in @@ -0,0 +1,480 @@ +#!/bin/sh +# +# Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +echo "create certificate request" +${hxtool} request-create \ + --subject="CN=Love,DC=it,DC=su,DC=se" \ + --key=FILE:$srcdir/data/key.der \ + pkcs10-request.der || exit 1 + +echo "issue certificate" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 + +echo "verify certificate" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "issue crl (no cert)" +${hxtool} crl-sign \ + --crl-file=crl.crl \ + --signer=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key || exit 1 + +echo "verify certificate (with CRL)" +${hxtool} verify \ + cert:FILE:cert-ee.pem \ + crl:FILE:crl.crl \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "issue crl (with cert)" +${hxtool} crl-sign \ + --crl-file=crl.crl \ + --signer=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + FILE:cert-ee.pem || exit 1 + +echo "verify certificate (included in CRL)" +${hxtool} verify \ + cert:FILE:cert-ee.pem \ + crl:FILE:crl.crl \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +# XXX Check that the certs issued below have the requested content + +echo "issue crl (with cert)" +${hxtool} crl-sign \ + --crl-file=crl.crl \ + --lifetime='1 month' \ + --signer=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + FILE:cert-ee.pem || exit 1 + +echo "verify certificate (included in CRL, and lifetime 1 month)" +${hxtool} verify \ + cert:FILE:cert-ee.pem \ + crl:FILE:crl.crl \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "issue certificate (10years 1 month)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --lifetime="10years 1 month" \ + --req="PKCS10:pkcs10-request.der" \ + --permanent-id=1.2.3.4.5.6.6:SomeVendor:A0B1C2D3 \ + --hardware-module-name=tcg-tpm20:SomeVendor:Z0Y1X2W3 \ + --policy="1.2.3.4.5.6:data:foo this is a warning" \ + --policy="id-x509-ce-certificatePolicies-anyPolicy" \ + --policy-mapping="1.2.3.4.5.6:1.2.3.4.5.6" \ + --policy-mapping="1.2.3.4.5.6:1.2.3.4.5.7" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue certificate (with https ekus)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --type="https-server" \ + --type="https-client" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue certificate (pkinit KDC)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --type="pkinit-kdc" \ + --pk-init-principal="krbtgt/TEST.H5L.SE@TEST.H5L.SE" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue certificate (pkinit client)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --type="pkinit-client" \ + --pk-init-principal="lha@TEST.H5L.SE" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue certificate (hostnames)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --type="https-server" \ + --hostname="www.test.h5l.se" \ + --hostname="ftp.test.h5l.se" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "verify certificate hostname (ok)" +${hxtool} verify --missing-revoke \ + --hostname=www.test.h5l.se \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "verify certificate hostname (fail)" +${hxtool} verify --missing-revoke \ + --hostname=www2.test.h5l.se \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "verify certificate hostname (fail)" +${hxtool} verify --missing-revoke \ + --hostname=2www.test.h5l.se \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "issue certificate (hostname in CN)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=www.test.h5l.se" \ + --type="https-server" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "verify certificate hostname (ok)" +${hxtool} verify --missing-revoke \ + --hostname=www.test.h5l.se \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "verify certificate hostname (fail)" +${hxtool} verify --missing-revoke \ + --hostname=www2.test.h5l.se \ + cert:FILE:cert-ee.pem \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "issue certificate (email)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --email="lha@test.h5l.se" \ + --email="test@test.h5l.se" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue certificate (email, null subject DN)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="" \ + --email="lha@test.h5l.se" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-null.pem" || exit 1 +${hxtool} print --content FILE:cert-null.pem || exit 1 + +echo "issue certificate (jabber)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --subject="cn=foo" \ + --jid="lha@test.h5l.se" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue self-signed cert" +${hxtool} issue-certificate \ + --self-signed \ + --ca-private-key=FILE:$srcdir/data/key.der \ + --subject="cn=test" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue ca cert" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/ca.crt,$srcdir/data/ca.key \ + --issue-ca \ + --subject="cn=ca-cert" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ca.der" || exit 1 +${hxtool} print --content FILE:cert-ca.der || exit 1 + +echo "issue self-signed ca cert" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --ca-private-key=FILE:$srcdir/data/key.der \ + --subject="cn=ca-root" \ + --certificate="FILE:cert-ca.der" || exit 1 +${hxtool} print --content FILE:cert-ca.der || exit 1 + +echo "issue proxy certificate" +${hxtool} issue-certificate \ + --ca-certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --issue-proxy \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-proxy.der" || exit 1 +${hxtool} print --content FILE:cert-proxy.der || exit 1 + +echo "verify proxy cert" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:cert-proxy.der \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "issue ca cert (generate rsa key)" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --serial-number="deadbeaf" \ + --generate-key=rsa \ + --path-length=-1 \ + --subject="cn=ca2-cert" \ + --certificate="FILE:cert-ca.pem" || exit 1 +${hxtool} print --content FILE:cert-ca.pem || exit 1 + +echo "issue sub-ca cert (generate rsa key)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --issue-ca \ + --serial-number="deadbeaf22" \ + --generate-key=rsa \ + --subject="cn=sub-ca2-cert" \ + --certificate="FILE:cert-sub-ca.pem" || exit 1 +${hxtool} print --content FILE:cert-sub-ca.pem || exit 1 + +echo "issue ee cert (generate rsa key)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --generate-key=rsa \ + --subject="cn=cert-ee2" \ + --certificate="FILE:cert-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-ee.pem || exit 1 + +echo "issue sub-ca ee cert (generate rsa key)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-sub-ca.pem \ + --generate-key=rsa \ + --subject="cn=cert-sub-ee2" \ + --certificate="FILE:cert-sub-ee.pem" || exit 1 +${hxtool} print --content FILE:cert-sub-ee.pem || exit 1 + +echo "verify certificate (ee)" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "verify certificate (sub-ee)" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-sub-ee.pem \ + chain:FILE:cert-sub-ca.pem \ + anchor:FILE:cert-ca.pem || exit 1 + +echo "sign CMS signature (generate key)" +${hxtool} cms-create-sd \ + --certificate=FILE:cert-ee.pem \ + "$srcdir/test_name.c" \ + sd.data > /dev/null || exit 1 + +echo "verify CMS signature (generate key)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:cert-ca.pem \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_name.c" sd.data.out || exit 1 + +echo "extend ca cert" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --lifetime="2years" \ + --serial-number="deadbeaf" \ + --ca-private-key=FILE:cert-ca.pem \ + --subject="cn=ca2-cert" \ + --certificate="FILE:cert-ca.pem" || exit 1 +${hxtool} print --content FILE:cert-ca.pem || exit 1 + +echo "verify certificate generated by previous ca" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "extend ca cert (template)" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --lifetime="3years" \ + --template-certificate="FILE:cert-ca.pem" \ + --template-fields="serialNumber,notBefore,subject" \ + --path-length=-1 \ + --ca-private-key=FILE:cert-ca.pem \ + --certificate="FILE:cert-ca.pem" || exit 1 +${hxtool} print --content FILE:cert-ca.pem || exit 1 + +echo "verify certificate generated by previous ca" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "extend sub-ca cert (template)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --issue-ca \ + --lifetime="2years" \ + --template-certificate="FILE:cert-sub-ca.pem" \ + --template-fields="serialNumber,notBefore,subject,SPKI" \ + --certificate="FILE:cert-sub-ca2.pem" || exit 1 +${hxtool} print --content FILE:cert-sub-ca2.pem || exit 1 + +echo "verify certificate (sub-ee) with extended chain" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-sub-ee.pem \ + chain:FILE:cert-sub-ca.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "+++++++++++ test basic constraints" + +echo "extend ca cert (too low path-length constraint)" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --lifetime="3years" \ + --template-certificate="FILE:cert-ca.pem" \ + --template-fields="serialNumber,notBefore,subject" \ + --path-length=0 \ + --ca-private-key=FILE:cert-ca.pem \ + --certificate="FILE:cert-ca.pem" || exit 1 + +echo "verify failure of certificate (sub-ee) with path-length constraint" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-sub-ee.pem \ + chain:FILE:cert-sub-ca.pem \ + anchor:FILE:cert-ca.pem > /dev/null && exit 1 + +echo "extend ca cert (exact path-length constraint)" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --lifetime="3years" \ + --template-certificate="FILE:cert-ca.pem" \ + --template-fields="serialNumber,notBefore,subject" \ + --path-length=1 \ + --ca-private-key=FILE:cert-ca.pem \ + --certificate="FILE:cert-ca.pem" || exit 1 + +echo "verify certificate (sub-ee) with exact path-length constraint" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-sub-ee.pem \ + chain:FILE:cert-sub-ca.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "Check missing basicConstrants.isCa" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --lifetime="2years" \ + --template-certificate="FILE:cert-sub-ca.pem" \ + --template-fields="serialNumber,notBefore,subject,SPKI" \ + --certificate="FILE:cert-sub-ca2.pem" || exit 1 + +echo "verify failure certificate (sub-ee) with missing isCA" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-sub-ee.pem \ + chain:FILE:cert-sub-ca2.pem \ + anchor:FILE:cert-ca.pem > /dev/null && exit 1 + +echo "issue ee cert (crl uri)" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --req="PKCS10:pkcs10-request.der" \ + --crl-uri="http://www.test.h5l.se/crl1.crl" \ + --subject="cn=cert-ee-crl-uri" \ + --certificate="FILE:cert-ee.pem" || exit 1 + +echo "issue null subject cert" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --req="PKCS10:pkcs10-request.der" \ + --subject="" \ + --email="lha@test.h5l.se" \ + --certificate="FILE:cert-ee.pem" || exit 1 + +echo "verify certificate null subject" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "+++++++++++ test sigalg" + +echo "issue cert with sha256" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --signature-algorithm=rsa-with-sha256 \ + --subject="cn=foo" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 + +echo "verify certificate" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +echo "issue cert with sha1" +${hxtool} issue-certificate \ + --ca-certificate=FILE:cert-ca.pem \ + --signature-algorithm=rsa-with-sha1 \ + --subject="cn=foo" \ + --req="PKCS10:pkcs10-request.der" \ + --certificate="FILE:cert-ee.pem" || exit 1 + +echo "verify certificate" +${hxtool} verify --missing-revoke \ + cert:FILE:cert-ee.pem \ + anchor:FILE:cert-ca.pem > /dev/null || exit 1 + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_cert.in b/third_party/heimdal/lib/hx509/test_cert.in new file mode 100644 index 0000000..5fa14d0 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_cert.in @@ -0,0 +1,84 @@ +#!/bin/sh +# +# Copyright (c) 2007 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id: test_chain.in 20809 2007-06-03 03:19:06Z lha $ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +echo "print DIR" +${hxtool} print --content DIR:$srcdir/data > /dev/null 2>/dev/null || exit 1 + +echo "print FILE" +for a in $srcdir/data/*.crt; do + ${hxtool} print --content FILE:"$a" > /dev/null 2>/dev/null +done + +echo "print NULL" +${hxtool} print --content NULL: > /dev/null || exit 1 + +echo "copy dance" +${hxtool} certificate-copy \ + FILE:${srcdir}/data/test.crt PEM-FILE:cert-pem.tmp || exit 1 + +${hxtool} certificate-copy PEM-FILE:cert-pem.tmp DER-FILE:cert-der.tmp || exit 1 +${hxtool} certificate-copy DER-FILE:cert-der.tmp PEM-FILE:cert-pem2.tmp || exit 1 + +cmp cert-pem.tmp cert-pem2.tmp || exit 1 + +echo "verify n0ll cert (fail)" +${hxtool} verify --missing-revoke \ + --hostname=foo.com \ + cert:FILE:$srcdir/data/n0ll.pem \ + anchor:FILE:$srcdir/data/n0ll.pem && exit 1 + +echo "verify n0ll cert (fail)" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/n0ll.pem \ + anchor:FILE:$srcdir/data/n0ll.pem && exit 1 + +echo "check that windows cert with utf16 in printable string works" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/win-u16-in-printablestring.der \ + anchor:FILE:$srcdir/data/win-u16-in-printablestring.der || exit 1 + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_chain.in b/third_party/heimdal/lib/hx509/test_chain.in new file mode 100644 index 0000000..b8c8cf5 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_chain.in @@ -0,0 +1,256 @@ +#!/bin/sh +# +# Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +echo "cert -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/test.crt \ + chain:FILE:$srcdir/data/test.crt \ + chain:FILE:$srcdir/data/ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "cert -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/test.crt \ + chain:FILE:$srcdir/data/ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "cert -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "sub-cert -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "sub-cert -> sub-ca -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + chain:FILE:$srcdir/data/ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "sub-cert -> sub-ca" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + anchor:FILE:$srcdir/data/sub-ca.crt > /dev/null || exit 1 + +echo "sub-cert -> sub-ca -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + chain:FILE:$srcdir/data/ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "sub-cert -> sub-ca -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/ca.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "sub-cert -> sub-ca -> root" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "max depth 2 (ok)" +${hxtool} verify --missing-revoke \ + --max-depth=2 \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "max depth 1 (fail)" +${hxtool} verify --missing-revoke \ + --max-depth=1 \ + cert:FILE:$srcdir/data/sub-cert.crt \ + chain:FILE:$srcdir/data/sub-ca.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "ocsp non-ca responder" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp1-ocsp.der > /dev/null || exit 1 + +echo "ocsp ca responder" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp1-ca.der > /dev/null || exit 1 + +echo "ocsp no-ca responder, missing cert" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp1-ocsp-no-cert.der > /dev/null && exit 1 + +echo "ocsp no-ca responder, missing cert, in pool" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp1-ocsp-no-cert.der \ + chain:FILE:$srcdir/data/ocsp-responder.crt > /dev/null || exit 1 + +echo "ocsp no-ca responder, keyHash" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp1-keyhash.der > /dev/null || exit 1 + +echo "ocsp revoked cert" +${hxtool} verify \ + cert:FILE:$srcdir/data/revoke.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + ocsp:FILE:$srcdir/data/ocsp-resp2.der > /dev/null && exit 1 + +for a in resp1-ocsp-no-cert resp1-ca resp1-keyhash resp2 ; do + echo "ocsp print reply $a" + ${hxtool} ocsp-print \ + $srcdir/data/ocsp-${a}.der > /dev/null || exit 1 +done + +echo "ocsp verify exists" +${hxtool} ocsp-verify \ + --ocsp-file=$srcdir/data/ocsp-resp1-ca.der \ + FILE:$srcdir/data/test.crt > /dev/null || exit 1 + +echo "ocsp verify not exists" +${hxtool} ocsp-verify \ + --ocsp-file=$srcdir/data/ocsp-resp1.der \ + FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "ocsp verify revoked" +${hxtool} ocsp-verify \ + --ocsp-file=$srcdir/data/ocsp-resp2.der \ + FILE:$srcdir/data/revoke.crt > /dev/null && exit 1 + +echo "crl non-revoked cert" +${hxtool} verify \ + cert:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + crl:FILE:$srcdir/data/crl1.der > /dev/null || exit 1 + +echo "crl revoked cert" +${hxtool} verify \ + cert:FILE:$srcdir/data/revoke.crt \ + anchor:FILE:$srcdir/data/ca.crt \ + crl:FILE:$srcdir/data/crl1.der > /dev/null && exit 1 + +if ${hxtool} info | grep 'ecdsa: hcrypto null' > /dev/null ; then + echo "not testing ECDSA since hcrypto doesnt support ECDSA" +else + echo "eccert -> root" + ${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/secp256r2TestServer.cert.pem \ + anchor:FILE:$srcdir/data/secp256r1TestCA.cert.pem > /dev/null || exit 1 + + echo "eccert -> root" + ${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/secp256r2TestClient.cert.pem \ + anchor:FILE:$srcdir/data/secp256r1TestCA.cert.pem > /dev/null || exit 1 +fi + +echo "proxy cert" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/proxy-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "proxy cert (negative)" +${hxtool} verify --missing-revoke \ + cert:FILE:$srcdir/data/proxy-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "proxy cert (level fail)" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/proxy-level-test.crt \ + chain:FILE:$srcdir/data/proxy-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "not a proxy cert" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/no-proxy-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null && exit 1 + +echo "proxy cert (max level 10)" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/proxy10-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "proxy cert (second level)" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/proxy10-child-test.crt \ + chain:FILE:$srcdir/data/proxy10-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +echo "proxy cert (third level)" +${hxtool} verify --missing-revoke \ + --allow-proxy-certificate \ + cert:FILE:$srcdir/data/proxy10-child-child-test.crt \ + chain:FILE:$srcdir/data/proxy10-child-test.crt \ + chain:FILE:$srcdir/data/proxy10-test.crt \ + chain:FILE:$srcdir/data/test.crt \ + anchor:FILE:$srcdir/data/ca.crt > /dev/null || exit 1 + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_cms.in b/third_party/heimdal/lib/hx509/test_cms.in new file mode 100644 index 0000000..8edb62a --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_cms.in @@ -0,0 +1,514 @@ +#!/bin/sh +# +# Copyright (c) 2005 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +if ${hxtool} info | grep 'ecdsa: hcrypto null' > /dev/null ; then + echo "not testing ECDSA since hcrypto doesnt support ECDSA" +else + echo "create signed data (ec)" + ${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/secp256r2TestClient.pem \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + + echo "verify signed data (ec)" + ${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/secp256r1TestCA.cert.pem \ + sd.data sd.data.out > /dev/null || exit 1 + cmp "$srcdir/test_chain.in" sd.data.out || exit 1 +fi + +echo "create signed data" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (no signer)" +${hxtool} cms-create-sd \ + --no-signer \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (no signer)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --no-signer-allowed \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > signer.tmp || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 +grep "unsigned" signer.tmp > /dev/null || exit 1 + +echo "verify signed data (no signer) (test failure)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out 2> signer.tmp && exit 1 +grep "No signers were found" signer.tmp > /dev/null || exit 1 + +echo "create signed data (id-by-name)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --id-by-name \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "verify signed data (EE cert as anchor)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/test.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (password)" +${hxtool} cms-create-sd \ + --pass=PASS:foobar \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test-pw.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (combined)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.combined.crt \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (content info)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --content-info \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (content info)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (content type)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --content-type=1.1.1.1 \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (content type)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (pem)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --pem \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (pem)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --pem \ + sd.data sd.data.out > /dev/null +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (pem, detached)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --detached-signature \ + --pem \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (pem, detached)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --pem \ + --signed-content="$srcdir/test_chain.in" \ + sd.data sd.data.out > /dev/null +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (p12)" +${hxtool} cms-create-sd \ + --pass=PASS:foobar \ + --certificate=PKCS12:$srcdir/data/test.p12 \ + --signer=friendlyname-test \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + "$srcdir/data/test-signed-data" sd.data.out > /dev/null || exit 1 +cmp "$srcdir/data/static-file" sd.data.out || exit 1 + +echo "verify signed data (no attr)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + "$srcdir/data/test-signed-data-noattr" sd.data.out > /dev/null || exit 1 +cmp "$srcdir/data/static-file" sd.data.out || exit 1 + +echo "verify failure signed data (no attr, no certs)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + "$srcdir/data/test-signed-data-noattr-nocerts" \ + sd.data.out > /dev/null 2>/dev/null && exit 1 + +echo "verify signed data (no attr, no certs)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --certificate=FILE:$srcdir/data/test.crt \ + --content-info \ + "$srcdir/data/test-signed-data-noattr-nocerts" \ + sd.data.out > /dev/null || exit 1 +cmp "$srcdir/data/static-file" sd.data.out || exit 1 + +echo "verify signed data - sha1" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + "$srcdir/data/test-signed-sha-1" sd.data.out > /dev/null || exit 1 +cmp "$srcdir/data/static-file" sd.data.out || exit 1 + +echo "verify signed data - sha256" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --content-info \ + "$srcdir/data/test-signed-sha-256" sd.data.out > /dev/null || exit 1 +cmp "$srcdir/data/static-file" sd.data.out || exit 1 + +#echo "verify signed data - sha512" +#${hxtool} cms-verify-sd \ +# --missing-revoke \ +# --anchors=FILE:$srcdir/data/ca.crt \ +# --content-info \ +# "$srcdir/data/test-signed-sha-512" sd.data.out > /dev/null || exit 1 +#cmp "$srcdir/data/static-file" sd.data.out || exit 1 + + +echo "create signed data (subcert, no certs)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify failure signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null 2> /dev/null && exit 1 + +echo "verify success signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --certificate=FILE:$srcdir/data/sub-ca.crt \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (subcert, certs)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + --pool=FILE:$srcdir/data/sub-ca.crt \ + --anchors=FILE:$srcdir/data/ca.crt \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify success signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (subcert, certs, no-root)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + --pool=FILE:$srcdir/data/sub-ca.crt \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify success signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (subcert, no-subca, no-root)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify failure signed data" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null 2>/dev/null && exit 1 + +echo "create signed data (sd cert)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test-ds-only.crt,$srcdir/data/test-ds-only.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "create signed data (ke cert)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test-ke-only.crt,$srcdir/data/test-ke-only.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null 2>/dev/null && exit 1 + +echo "create signed data (sd + ke certs)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test-ke-only.crt,$srcdir/data/test-ke-only.key \ + --certificate=FILE:$srcdir/data/test-ds-only.crt,$srcdir/data/test-ds-only.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "create signed data (ke + sd certs)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test-ds-only.crt,$srcdir/data/test-ds-only.key \ + --certificate=FILE:$srcdir/data/test-ke-only.crt,$srcdir/data/test-ke-only.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "create signed data (detached)" +${hxtool} cms-create-sd \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --detached-signature \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (detached)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --signed-content="$srcdir/test_chain.in" \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "verify failure signed data (detached)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null 2>/dev/null && exit 1 + +echo "create signed data (rsa)" +${hxtool} cms-create-sd \ + --peer-alg=1.2.840.113549.1.1.1 \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + "$srcdir/test_chain.in" \ + sd.data > /dev/null || exit 1 + +echo "verify signed data (rsa)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + sd.data sd.data.out > /dev/null 2>/dev/null || exit 1 +cmp "$srcdir/test_chain.in" sd.data.out || exit 1 + +echo "create signed data (pem, detached)" +cp "$srcdir/test_chain.in" sd +${hxtool} cms-sign \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --detached-signature \ + --pem \ + sd > /dev/null || exit 1 + +echo "verify signed data (pem, detached)" +${hxtool} cms-verify-sd \ + --missing-revoke \ + --anchors=FILE:$srcdir/data/ca.crt \ + --pem \ + sd.pem > /dev/null + +echo "create signed data (no certs, detached sig)" +cp "$srcdir/test_chain.in" sd +${hxtool} cms-sign \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --detached-signature \ + --no-embedded-certs \ + "$srcdir/data/static-file" \ + sd > /dev/null || exit 1 + +echo "create signed data (leif only, detached sig)" +cp "$srcdir/test_chain.in" sd +${hxtool} cms-sign \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --detached-signature \ + --embed-leaf-only \ + "$srcdir/data/static-file" \ + sd > /dev/null || exit 1 + +echo "create signed data (no certs, detached sig, 2 signers)" +cp "$srcdir/test_chain.in" sd +${hxtool} cms-sign \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + --detached-signature \ + --no-embedded-certs \ + "$srcdir/data/static-file" \ + sd > /dev/null || exit 1 + +echo "create signed data (no certs, detached sig, 3 signers)" +cp "$srcdir/test_chain.in" sd +${hxtool} cms-sign \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --certificate=FILE:$srcdir/data/sub-cert.crt,$srcdir/data/sub-cert.key \ + --certificate=FILE:$srcdir/data/test-ds-only.crt,$srcdir/data/test-ds-only.key \ + --detached-signature \ + --no-embedded-certs \ + "$srcdir/data/static-file" \ + sd > /dev/null || exit 1 + +echo "envelope data (content-type)" +${hxtool} cms-envelope \ + --certificate=FILE:$srcdir/data/test.crt \ + --content-type=1.1.1.1 \ + "$srcdir/data/static-file" \ + ev.data > /dev/null || exit 1 + +echo "unenvelope data (content-type)" +${hxtool} cms-unenvelope \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + ev.data ev.data.out \ + FILE:$srcdir/data/test.crt,$srcdir/data/test.key > /dev/null || exit 1 +cmp "$srcdir/data/static-file" ev.data.out || exit 1 + +echo "envelope data (content-info)" +${hxtool} cms-envelope \ + --certificate=FILE:$srcdir/data/test.crt \ + --content-info \ + "$srcdir/data/static-file" \ + ev.data > /dev/null || exit 1 + +echo "unenvelope data (content-info)" +${hxtool} cms-unenvelope \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --content-info \ + ev.data ev.data.out \ + FILE:$srcdir/data/test.crt,$srcdir/data/test.key > /dev/null || exit 1 +cmp "$srcdir/data/static-file" ev.data.out || exit 1 + +for a in des-ede3 aes-128 aes-256; do + + rm -f ev.data ev.data.out + echo "envelope data ($a)" + ${hxtool} cms-envelope \ + --encryption-type="$a-cbc" \ + --certificate=FILE:$srcdir/data/test.crt \ + "$srcdir/data/static-file" \ + ev.data || exit 1 + + echo "unenvelope data ($a)" + ${hxtool} cms-unenvelope \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + ev.data ev.data.out > /dev/null || exit 1 + cmp "$srcdir/data/static-file" ev.data.out || exit 1 +done + +for a in rc2-40 rc2-64 rc2-128 des-ede3 aes-128 aes-256; do + echo "static unenvelope data ($a)" + + rm -f ev.data.out + ${hxtool} cms-unenvelope \ + --certificate=FILE:$srcdir/data/test.crt,$srcdir/data/test.key \ + --content-info \ + --allow-weak \ + "$srcdir/data/test-enveloped-$a" ev.data.out > /dev/null || exit 1 + cmp "$srcdir/data/static-file" ev.data.out || exit 1 +done + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_crypto.in b/third_party/heimdal/lib/hx509/test_crypto.in new file mode 100644 index 0000000..9206031 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_crypto.in @@ -0,0 +1,192 @@ +#!/bin/sh +# +# Copyright (c) 2006 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + + +echo "Bleichenbacher good cert (from eay)" +${hxtool} verify --missing-revoke \ + --time=2006-09-25 \ + cert:FILE:$srcdir/data/bleichenbacher-good.pem \ + anchor:FILE:$srcdir/data/bleichenbacher-good.pem > /dev/null || exit 1 + +echo "Bleichenbacher bad cert (from eay)" +${hxtool} verify --missing-revoke \ + --time=2006-09-25 \ + cert:FILE:$srcdir/data/bleichenbacher-bad.pem \ + anchor:FILE:$srcdir/data/bleichenbacher-bad.pem > /dev/null && exit 1 + +echo "Bleichenbacher good cert (from yutaka)" +${hxtool} verify --missing-revoke \ + --time=2006-09-25 \ + cert:FILE:$srcdir/data/yutaka-pad-ok-cert.pem \ + anchor:FILE:$srcdir/data/yutaka-pad-ok-ca.pem > /dev/null || exit 1 + +echo "Bleichenbacher bad cert (from yutaka)" +${hxtool} verify --missing-revoke \ + --time=2006-09-25 \ + cert:FILE:$srcdir/data/yutaka-pad-broken-cert.pem \ + anchor:FILE:$srcdir/data/yutaka-pad-broken-ca.pem > /dev/null && exit 1 + +# Ralf-Philipp Weinmann +# Andrew Pyshkin +echo "Bleichenbacher bad cert (sf pad correct)" +${hxtool} verify --missing-revoke \ + --time=2006-09-25 \ + cert:FILE:$srcdir/data/bleichenbacher-sf-pad-correct.pem \ + anchor:FILE:$srcdir/data/sf-class2-root.pem > /dev/null && exit 1 + +echo Read 50 kilobyte random data +${hxtool} random-data 50kilobyte > random-data || exit 1 + +echo "crypto select1" +${hxtool} crypto-select > test || { echo "select1"; exit 1; } +cmp test ${srcdir}/tst-crypto-select1 > /dev/null || \ + { echo "select1 failure"; exit 1; } + +echo "crypto select1" +${hxtool} crypto-select --type=digest > test || { echo "select1"; exit 1; } +cmp test ${srcdir}/tst-crypto-select1 > /dev/null || \ + { echo "select1 failure"; exit 1; } + +echo "crypto select2" +${hxtool} crypto-select --type=public-sig > test || { echo "select2"; exit 1; } +cmp test ${srcdir}/tst-crypto-select2 > /dev/null || \ + { echo "select2 failure"; exit 1; } + +echo "crypto select3" +${hxtool} crypto-select \ + --type=public-sig \ + --peer-cmstype=1.2.840.113549.1.1.4 \ + > test || { echo "select3"; exit 1; } +cmp test ${srcdir}/tst-crypto-select3 > /dev/null || \ + { echo "select3 failure"; exit 1; } + +echo "crypto select4" +${hxtool} crypto-select \ + --type=public-sig \ + --peer-cmstype=1.2.840.113549.1.1.5 \ + --peer-cmstype=1.2.840.113549.1.1.4 \ + > test || { echo "select4"; exit 1; } +cmp test ${srcdir}/tst-crypto-select4 > /dev/null || \ + { echo "select4 failure"; exit 1; } + +echo "crypto select5" +${hxtool} crypto-select \ + --type=public-sig \ + --peer-cmstype=1.2.840.113549.1.1.11 \ + --peer-cmstype=1.2.840.113549.1.1.5 \ + > test || { echo "select5"; exit 1; } +cmp test ${srcdir}/tst-crypto-select5 > /dev/null || \ + { echo "select5 failure"; exit 1; } + +echo "crypto select6" +${hxtool} crypto-select \ + --type=public-sig \ + --peer-cmstype=1.2.840.113549.2.5 \ + --peer-cmstype=1.2.840.113549.1.1.5 \ + > test || { echo "select6"; exit 1; } +cmp test ${srcdir}/tst-crypto-select6 > /dev/null || \ + { echo "select6 failure"; exit 1; } + +echo "crypto select7" +${hxtool} crypto-select \ + --type=secret \ + --peer-cmstype=2.16.840.1.101.3.4.1.42 \ + --peer-cmstype=1.2.840.113549.3.7 \ + --peer-cmstype=1.2.840.113549.1.1.5 \ + > test || { echo "select7"; exit 1; } +cmp test ${srcdir}/tst-crypto-select7 > /dev/null || \ + { echo "select7 failure"; exit 1; } + +#echo "crypto available1" +#${hxtool} crypto-available \ +# --type=all \ +# > test || { echo "available1"; exit 1; } +#cmp test ${srcdir}/tst-crypto-available1 > /dev/null || \ +# { echo "available1 failure"; exit 1; } + +echo "crypto available2" +${hxtool} crypto-available \ + --type=digest \ + > test || { echo "available2"; exit 1; } +cmp test ${srcdir}/tst-crypto-available2 > /dev/null || \ + { echo "available2 failure"; exit 1; } + +#echo "crypto available3" +#${hxtool} crypto-available \ +# --type=public-sig \ +# > test || { echo "available3"; exit 1; } +#cmp test ${srcdir}/tst-crypto-available3 > /dev/null || \ +# { echo "available3 failure"; exit 1; } + +echo "copy keystore FILE existing -> FILE" +${hxtool} certificate-copy \ + FILE:${srcdir}/data/test.crt,${srcdir}/data/test.key \ + FILE:out.pem || exit 1 + +echo "copy keystore FILE -> FILE" +${hxtool} certificate-copy \ + FILE:out.pem \ + FILE:out2.pem || exit 1 + +echo "copy keystore FILE -> PKCS12" +${hxtool} certificate-copy \ + FILE:out.pem \ + PKCS12:out2.pem || exit 1 + +echo "print certificate with utf8" +${hxtool} print \ + FILE:$srcdir/data/j.pem >/dev/null 2>/dev/null || exit 1 + +echo "Make sure that we can parse EC private keys" +${hxtool} print --content \ + FILE:$srcdir/data/pkinit-ec.crt,$srcdir/data/pkinit-ec.key \ + > /dev/null || exit 1 + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_expr.c b/third_party/heimdal/lib/hx509/test_expr.c new file mode 100644 index 0000000..8c2c0a5 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_expr.c @@ -0,0 +1,87 @@ + +#include "hx_locl.h" +#include + +struct foo { + int val; + char *str; +} foo[] = { + { 0, "FALSE" }, + { 1, "TRUE" }, + { 0, "!TRUE" }, + { 0, "! TRUE" }, + { 0, "!\tTRUE" }, + { 0, "( FALSE AND FALSE )" }, + { 0, "( TRUE AND FALSE )" }, + { 1, "( TRUE AND TRUE )" }, + { 1, "( TRUE OR TRUE )" }, + { 1, "( TRUE OR FALSE )" }, + { 0, "( FALSE OR FALSE )" }, + { 1, "! ( FALSE OR FALSE )" }, + + { 1, "\"foo\" TAILMATCH \"foo\"" }, + { 1, "\"foobar\" TAILMATCH \"bar\"" }, + { 0, "\"foobar\" TAILMATCH \"foo\"" }, + + { 1, "\"foo\" == \"foo\"" }, + { 0, "\"foo\" == \"bar\"" }, + { 0, "\"foo\" != \"foo\"" }, + { 1, "\"foo\" != \"bar\"" }, + { 1, "%{variable} == \"foo\"" }, + { 0, "%{variable} == \"bar\"" }, + { 1, "%{context.variable} == \"foo\"" }, + { 0, "%{context.variable} == \"bar\"" }, + { 1, "\"foo\" IN ( \"bar\", \"foo\")" }, + { 0, "\"foo\" IN ( \"bar\", \"baz\")" }, + { 0, "\"bar\" IN %{context}" }, + { 1, "\"foo\" IN %{context}" }, + { 1, "\"variable\" IN %{context}" }, + + { 1, "\"foo\" IN %{context} AND %{context.variable} == \"foo\"" } +}; + +int +main(int argc, char **argv) +{ + struct hx_expr *expr; + hx509_context context; + hx509_env env = NULL, env2 = NULL; + int val, i, ret; + +#if 0 + extern int yydebug; + yydebug = 1; +#endif + + ret = hx509_context_init(&context); + if (ret) + errx(1, "hx509_context_init failed with %d", ret); + + hx509_env_add(context, &env, "variable", "foo"); + hx509_env_add(context, &env2, "variable", "foo"); + hx509_env_add_binding(context, &env, "context", env2); + + for (i = 0; i < sizeof(foo)/sizeof(foo[0]); i++) { + + expr = _hx509_expr_parse(foo[i].str); + if (expr == NULL) + errx(1, "_hx509_expr_parse failed for %d: %s", i, foo[i].str); + + val = _hx509_expr_eval(context, env, expr); + if (foo[i].val) { + if (val == 0) + errx(1, "_hx509_expr_eval not true when it should: %d: %s", + i, foo[i].str); + } else { + if (val) + errx(1, "_hx509_expr_eval true when it should not: %d: %s", + i, foo[i].str); + } + + _hx509_expr_free(expr); + } + + hx509_env_free(&env); + + return 0; +} diff --git a/third_party/heimdal/lib/hx509/test_java_pkcs11.in b/third_party/heimdal/lib/hx509/test_java_pkcs11.in new file mode 100644 index 0000000..9a843a4 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_java_pkcs11.in @@ -0,0 +1,73 @@ +#!/bin/sh +# +# Copyright (c) 2008 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +exit 0 + +srcdir="@srcdir@" +objdir="@objdir@" + +dir=$objdir +file= + +for a in libhx509.so .libs/libhx509.so libhx509.dylib .libs/libhx509.dylib ; do + if [ -f $dir/$a ] ; then + file=$dir/$a + break + fi +done + +if [ "X$file" = X ] ; then + exit 0 +fi + +cat > pkcs11.cfg < test-rc-file.rc < /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +echo "nist tests" + +if [ ! -d "$nistdir" ] ; then + ( mkdir "$nistdir" && unzip -d "${nistdir}" "${nistzip}" ) >/dev/null || \ + { rm -rf "$nistdir" ; exit 1; } +fi + +ec=0 +while read id verify cert arg1 arg2 arg3 arg4 arg5 ; do + expr "$id" : "#" > /dev/null && continue + + test "$id" = "end" && break + + args="" + case "$arg1" in + *.crt) args="$args chain:FILE:$nistdir/certs/$arg1" ;; + *.crl) args="$args crl:FILE:$nistdir/crls/$arg1" ;; + *) args="$args $arg1" ;; + esac + case "$arg2" in + *.crt) args="$args chain:FILE:$nistdir/certs/$arg2" ;; + *.crl) args="$args crl:FILE:$nistdir/crls/$arg2" ;; + *) args="$args $arg2" ;; + esac + case "$arg3" in + *.crt) args="$args chain:FILE:$nistdir/certs/$arg3" ;; + *.crl) args="$args crl:FILE:$nistdir/crls/$arg3" ;; + *) args="$args $arg3" ;; + esac + case "$arg4" in + *.crt) args="$args chain:FILE:$nistdir/certs/$arg4" ;; + *.crl) args="$args crl:FILE:$nistdir/crls/$arg4" ;; + *) args="$args $arg4" ;; + esac + case "$arg5" in + *.crt) args="$args chain:FILE:$nistdir/certs/$arg5" ;; + *.crl) args="$args crl:FILE:$nistdir/crls/$arg5" ;; + *) args="$args $arg5" ;; + esac + + args="$args anchor:FILE:$nistdir/certs/TrustAnchorRootCertificate.crt" + args="$args crl:FILE:$nistdir/crls/TrustAnchorRootCRL.crl" + args="$args cert:FILE:$nistdir/certs/$cert" + + if ${hxtool} verify --time=2008-05-20 $args > /dev/null; then + if test "$verify" = "f"; then + echo ${hxtool} verify --time=2008-05-20 $args + echo "verify passed on fail: $id $cert" + ec=1 + fi + elif test "$verify" = "p"; then + echo ${hxtool} verify --time=2008-05-20 $args + echo "verify failed on pass: $id $cert" + ec=1 + fi + +done < $srcdir/data/nist-data + + +echo "done!" + +exit $ec diff --git a/third_party/heimdal/lib/hx509/test_nist2.in b/third_party/heimdal/lib/hx509/test_nist2.in new file mode 100644 index 0000000..0c4276b --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_nist2.in @@ -0,0 +1,136 @@ +#!/bin/sh +# +# Copyright (c) 2004 - 2008 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id: test_nist.in 21787 2007-08-02 08:50:24Z lha $ +# + +srcdir="@srcdir@" +objdir="@objdir@" +nistdir=${objdir}/PKITS_data +nistzip=${srcdir}/data/PKITS_data.zip +egrep="@egrep@" + +limit="${1:-nolimit}" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +# nistzip is not distributed part of the distribution +test -f "$nistzip" || exit 77 + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +#--------- Try to find unzip + +oldifs=$IFS +IFS=: +set -- $PATH +IFS=$oldifs +found= + +for p in "$@" ; do + test -x "$p/unzip" && { found=1 ; break; } +done +test "X$found" = "X" && exit 77 + +#--------- + + +echo "nist tests, version 2" + +if [ ! -d "$nistdir" ] ; then + ( mkdir "$nistdir" && unzip -d "${nistdir}" "${nistzip}" ) >/dev/null || \ + { rm -rf "$nistdir" ; exit 1; } +fi + +ec= +name= +description= +while read result cert other ; do + if expr "$result" : "#" > /dev/null; then + name=${cert} + description="${other}" + continue + fi + + test nolimit != "${limit}" && ! expr "$name" : "$limit" > /dev/null && continue + + test "$result" = "end" && break + + args= + args="$args cert:FILE:$nistdir/certs/$cert" + args="$args chain:DIR:$nistdir/certs" + args="$args anchor:FILE:$nistdir/certs/TrustAnchorRootCertificate.crt" + + for a in $nistdir/crls/*.crl; do + args="$args crl:FILE:$a" + done + + cmd="${hxtool} verify --time=2008-05-20 $args" + eval ${cmd} > /dev/null + res=$? + + case "${result},${res}" in + 0,0) r="PASSs";; + 0,*) r="FAILs";; + [123],0) r="FAILf";; + [123],*) r="PASSf";; + *) echo="unknown result ${result},${res}" ; exit 1 ;; + esac + if ${egrep} "^${name} FAIL" $srcdir/data/nist-result2 > /dev/null; then + if expr "$r" : "PASS" >/dev/null; then + echo "${name} passed when expected not to" + echo "# ${description}" > nist2-passed-${name}.tmp + ec=1 + fi + elif ${egrep} "^${name} EITHER" $srcdir/data/nist-result2 > /dev/null; then + : + elif expr "$r" : "FAIL.*" >/dev/null ; then + echo "$r ${name} ${description}" + echo "# ${description}" > nist2-failed-${name}.tmp + echo "$cmd" >> nist2-failed-${name}.tmp + ec=1 + fi + +done < $srcdir/data/nist-data2 + + +echo "done!" + +exit $ec diff --git a/third_party/heimdal/lib/hx509/test_nist_cert.in b/third_party/heimdal/lib/hx509/test_nist_cert.in new file mode 100644 index 0000000..8c683d6 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_nist_cert.in @@ -0,0 +1,68 @@ +#!/bin/sh +# +# Copyright (c) 2006 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" +nistdir=${objdir}/PKITS_data +nistzip=${srcdir}/data/PKITS_data.zip + +# nistzip is not distributed part of the distribution +test -f "$nistzip" || exit 77 + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +if [ ! -d "$nistdir" ] ; then + ( mkdir "$nistdir" && cd "$nistdir" && unzip "$nistzip" ) >/dev/null || \ + { rm -rf "$nistdir" ; exit 1; } +fi + +if ${hxtool} validate DIR:$nistdir/certs > /dev/null; then + : +else + echo "validate failed" + exit 1 +fi + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_nist_pkcs12.in b/third_party/heimdal/lib/hx509/test_nist_pkcs12.in new file mode 100644 index 0000000..7898eee --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_nist_pkcs12.in @@ -0,0 +1,77 @@ +#!/bin/sh +# +# Copyright (c) 2004 - 2005 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" +pass="--pass=PASS:password" +nistdir=${objdir}/PKITS_data +nistzip=${srcdir}/data/PKITS_data.zip + +# nistzip is not distributed part of the distribution +test -f "$nistzip" || exit 77 + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +if [ ! -d "$nistdir" ] ; then + ( mkdir "$nistdir" && cd "$nistdir" && unzip "$nistzip" ) >/dev/null || \ + { rm -rf "$nistdir" ; exit 1; } +fi + +echo "nist pkcs12 tests" + +for a in $nistdir/pkcs12/*.p12 ; do + + if ${hxtool} validate $pass PKCS12:$a > /dev/null; then + : + else + echo "$a failed" + exit 1 + fi + +done + +echo "done!" + +exit 0 \ No newline at end of file diff --git a/third_party/heimdal/lib/hx509/test_pkcs11.in b/third_party/heimdal/lib/hx509/test_pkcs11.in new file mode 100644 index 0000000..278296a --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_pkcs11.in @@ -0,0 +1,62 @@ +#!/bin/sh +# +# Copyright (c) 2008 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +srcdir="@srcdir@" +objdir="@objdir@" + +SOFTPKCS11RC="test-rc-file.rc" \ +export SOFTPKCS11RC + +echo "password less" + +cat > test-rc-file.rc < test-rc-file.rc </dev/null 2>/dev/null || exit 1 + +echo "try printing" +${hxtool} print \ + --pass=PASS:foobar \ + --info --content \ + FILE:$srcdir/data/kdc.crt >/dev/null 2>/dev/null || exit 1 + +${hxtool} print \ + --pass=PASS:foobar \ + --info \ + PKCS12:$srcdir/data/test.p12 >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is found (friendlyname)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + PKCS12:$srcdir/data/test.p12 >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is not found (friendlyname)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test-not \ + PKCS12:$srcdir/data/test.p12 >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (eku)" +${hxtool} query \ + --eku=1.3.6.1.5.2.3.5 \ + FILE:$srcdir/data/kdc.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is not found (eku)" +${hxtool} query \ + --eku=1.3.6.1.5.2.3.6 \ + FILE:$srcdir/data/kdc.crt >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (friendlyname, no-pw)" +${hxtool} query \ + --friendlyname=friendlyname-cert \ + PKCS12:$srcdir/data/test-nopw.p12 >/dev/null 2>/dev/null || exit 1 + +echo "check for ca cert (friendlyname)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=ca \ + PKCS12:$srcdir/data/test.p12 >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is not found (friendlyname)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + PKCS12:$srcdir/data/sub-cert.p12 >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (friendlyname|private key)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=friendlyname-test \ + --private-key \ + PKCS12:$srcdir/data/test.p12 > /dev/null || exit 1 + +echo "make sure entry is not found (friendlyname|private key)" +${hxtool} query \ + --pass=PASS:foobar \ + --friendlyname=ca \ + --private-key \ + PKCS12:$srcdir/data/test.p12 >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (cert ds)" +${hxtool} query \ + --digitalSignature \ + FILE:$srcdir/data/test.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is found (cert ke)" +${hxtool} query \ + --keyEncipherment \ + FILE:$srcdir/data/test.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is found (cert ke + ds)" +${hxtool} query \ + --digitalSignature \ + --keyEncipherment \ + FILE:$srcdir/data/test.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is found (cert-ds ds)" +${hxtool} query \ + --digitalSignature \ + FILE:$srcdir/data/test-ds-only.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is not found (cert-ds ke)" +${hxtool} query \ + --keyEncipherment \ + FILE:$srcdir/data/test-ds-only.crt >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is not found (cert-ds ke + ds)" +${hxtool} query \ + --digitalSignature \ + --keyEncipherment \ + FILE:$srcdir/data/test-ds-only.crt >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is not found (cert-ke ds)" +${hxtool} query \ + --digitalSignature \ + FILE:$srcdir/data/test-ke-only.crt >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (cert-ke ke)" +${hxtool} query \ + --keyEncipherment \ + FILE:$srcdir/data/test-ke-only.crt >/dev/null 2>/dev/null || exit 1 + +echo "make sure entry is not found (cert-ke ke + ds)" +${hxtool} query \ + --digitalSignature \ + --keyEncipherment \ + FILE:$srcdir/data/test-ke-only.crt >/dev/null 2>/dev/null && exit 1 + +echo "make sure entry is found (eku) in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.5" IN %{certificate.eku}' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry is not found (eku) in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.6" IN %{certificate.eku}' \ + FILE:$srcdir/data/kdc.crt > /dev/null && exit 1 + +echo "make sure entry is found (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} == "CN=kdc,C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry is found using TAILMATCH (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} TAILMATCH "C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry is not found using TAILMATCH (subject) in query language" +${hxtool} query \ + --expr='%{certificate.subject} TAILMATCH "C=FI"' \ + FILE:$srcdir/data/kdc.crt > /dev/null && exit 1 + +echo "make sure entry is found (issuer) in query language" +${hxtool} query \ + --expr='%{certificate.issuer} == "C=SE,CN=hx509 Test Root CA"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry match with EKU and TAILMATCH in query language" +${hxtool} query \ + --expr='"1.3.6.1.5.2.3.5" IN %{certificate.eku} AND %{certificate.subject} TAILMATCH "C=SE"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + +echo "make sure entry match with hash.sha1" +${hxtool} query \ + --expr='"%{certificate.hash.sha1}EQ "412120212A2CBFD777DE5499ECB4724345F33F16"' \ + FILE:$srcdir/data/kdc.crt > /dev/null || exit 1 + + +exit 0 diff --git a/third_party/heimdal/lib/hx509/test_req.in b/third_party/heimdal/lib/hx509/test_req.in new file mode 100644 index 0000000..1d553db --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_req.in @@ -0,0 +1,211 @@ +#!/bin/sh +# +# Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +${hxtool} request-create \ + --subject="CN=Love,DC=it,DC=su,DC=se" \ + --key="FILE:$srcdir/data/key.der" \ + "${objdir}/request.out" || exit 1 + +${hxtool} request-print \ + PKCS10:request.out > /dev/null || exit 1 + +${hxtool} request-create \ + --subject="CN=Love,DC=it,DC=su,DC=se" \ + --eku=1.2.3.4.5.6.7 --eku=1.2.3.4.5.6.8 \ + --registered=1.2.3.4.5.6.9 --eku=1.2.3.4.5.6.10 \ + --dnsname=nutcracker.test.h5l.se \ + --dnsname=foo.nutcracker.test.h5l.se \ + --kerberos=HTTP/foo.nutcracker.it.su.se@TEST.H5L.SE \ + --kerberos=host/foo.nutcracker.it.su.se@TEST.H5L.SE \ + --email=foo@test.h5l.se \ + --key="FILE:$srcdir/data/key.der" \ + "${objdir}/request.out" || exit 1 + +cat > "$objdir/expected" < "${objdir}/actual" || exit 1 + +diff "$objdir/expected" "${objdir}/actual" || exit 1 + +# Check that OpenSSL can parse our request: +if openssl version > /dev/null; then + openssl req -inform DER -in "${objdir}/request.out" -text | head -25 > "${objdir}/actual" + + # Various versions of openssl differ slightly in their text output for our + # CSR. Figure out what to expect: + if grep "Version: 0" "${objdir}/actual" > /dev/null; then + v=0 + else + v=1 + fi + if grep "RSA Public-Key:" "${objdir}/actual" > /dev/null; then + k="RSA " + else + k="" + fi + # Note interpolation of $v and $k in the here doc below: + cat > "$objdir/expected" <, othername:, Registered ID:1.2.3.4.5.6.9 + Signature Algorithm: sha256WithRSAEncryption +EOF + if ! diff -u -w "${objdir}/expected" "${objdir}/actual"; then + cat > "$objdir/expected" <, othername: 1.3.6.1.5.2.2::, Registered ID:1.2.3.4.5.6.9 + Signature Algorithm: sha256WithRSAEncryption +EOF + fi +fi + +${hxtool} request-create \ + --ca \ + --ca-path-length=3 \ + --subject="cn=ca-cert" \ + --key=FILE:$srcdir/data/key.der \ + pkcs10-request.der || exit 1 +${hxtool} request-print PKCS10:pkcs10-request.der > "${objdir}/actual"|| exit 1 +cat > "$objdir/expected" < "${objdir}/actual"|| exit 1 +cat > "$objdir/expected" < "${objdir}/actual" || exit 1 +cat > "$objdir/expected" < + +static CK_FUNCTION_LIST_PTR func; + + +static CK_RV +find_object(CK_SESSION_HANDLE session, + char *id, + CK_OBJECT_CLASS key_class, + CK_OBJECT_HANDLE_PTR object) +{ + CK_ULONG object_count; + CK_RV ret; + CK_ATTRIBUTE search_data[] = { + {CKA_ID, id, 0 }, + {CKA_CLASS, &key_class, sizeof(key_class)} + }; + CK_ULONG num_search_data = sizeof(search_data)/sizeof(search_data[0]); + + search_data[0].ulValueLen = strlen(id); + + ret = (*func->C_FindObjectsInit)(session, search_data, num_search_data); + if (ret != CKR_OK) + return ret; + + ret = (*func->C_FindObjects)(session, object, 1, &object_count); + if (ret != CKR_OK) + return ret; + if (object_count == 0) { + printf("found no object\n"); + return 1; + } + + ret = (*func->C_FindObjectsFinal)(session); + if (ret != CKR_OK) + return ret; + + return CKR_OK; +} + +static char *sighash = "hej"; +static char signature[1024]; + + +int +main(int argc, char **argv) +{ + CK_SLOT_ID_PTR slot_ids; + CK_SLOT_ID slot; + CK_ULONG num_slots; + CK_RV ret; + CK_SLOT_INFO slot_info; + CK_TOKEN_INFO token_info; + CK_SESSION_HANDLE session; + CK_OBJECT_HANDLE public, private; + + ret = C_GetFunctionList(&func); + if (ret != CKR_OK) + errx(1, "C_GetFunctionList failed: %d", (int)ret); + + (*func->C_Initialize)(NULL_PTR); + + ret = (*func->C_GetSlotList)(FALSE, NULL, &num_slots); + if (ret != CKR_OK) + errx(1, "C_GetSlotList1 failed: %d", (int)ret); + + if (num_slots == 0) + errx(1, "no slots"); + + if ((slot_ids = calloc(1, num_slots * sizeof(*slot_ids))) == NULL) + err(1, "alloc slots failed"); + + ret = (*func->C_GetSlotList)(FALSE, slot_ids, &num_slots); + if (ret != CKR_OK) + errx(1, "C_GetSlotList2 failed: %d", (int)ret); + + slot = slot_ids[0]; + free(slot_ids); + + ret = (*func->C_GetSlotInfo)(slot, &slot_info); + if (ret) + errx(1, "C_GetSlotInfo failed: %d", (int)ret); + + if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) + errx(1, "no token present"); + + ret = (*func->C_OpenSession)(slot, CKF_SERIAL_SESSION, + NULL, NULL, &session); + if (ret != CKR_OK) + errx(1, "C_OpenSession failed: %d", (int)ret); + + ret = (*func->C_GetTokenInfo)(slot, &token_info); + if (ret) + errx(1, "C_GetTokenInfo1 failed: %d", (int)ret); + + if (token_info.flags & CKF_LOGIN_REQUIRED) { + ret = (*func->C_Login)(session, CKU_USER, + (unsigned char*)"foobar", 6); + if (ret != CKR_OK) + errx(1, "C_Login failed: %d", (int)ret); + } + + ret = (*func->C_GetTokenInfo)(slot, &token_info); + if (ret) + errx(1, "C_GetTokenInfo2 failed: %d", (int)ret); + + if (token_info.flags & CKF_LOGIN_REQUIRED) + errx(1, "login required, even after C_Login"); + + ret = find_object(session, "cert", CKO_PUBLIC_KEY, &public); + if (ret != CKR_OK) + errx(1, "find cert failed: %d", (int)ret); + ret = find_object(session, "cert", CKO_PRIVATE_KEY, &private); + if (ret != CKR_OK) + errx(1, "find private key failed: %d", (int)ret); + + { + CK_ULONG ck_sigsize; + CK_MECHANISM mechanism; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ret = (*func->C_SignInit)(session, &mechanism, private); + if (ret != CKR_OK) + return 1; + + ck_sigsize = sizeof(signature); + ret = (*func->C_Sign)(session, (CK_BYTE *)sighash, strlen(sighash), + (CK_BYTE *)signature, &ck_sigsize); + if (ret != CKR_OK) { + printf("C_Sign failed with: %d\n", (int)ret); + return 1; + } + + ret = (*func->C_VerifyInit)(session, &mechanism, public); + if (ret != CKR_OK) + return 1; + + ret = (*func->C_Verify)(session, (CK_BYTE *)signature, ck_sigsize, + (CK_BYTE *)sighash, strlen(sighash)); + if (ret != CKR_OK) { + printf("message: %d\n", (int)ret); + return 1; + } + } + +#if 0 + { + CK_ULONG ck_sigsize, outsize; + CK_MECHANISM mechanism; + char outdata[1024]; + + memset(&mechanism, 0, sizeof(mechanism)); + mechanism.mechanism = CKM_RSA_PKCS; + + ret = (*func->C_EncryptInit)(session, &mechanism, public); + if (ret != CKR_OK) + return 1; + + ck_sigsize = sizeof(signature); + ret = (*func->C_Encrypt)(session, (CK_BYTE *)sighash, strlen(sighash), + (CK_BYTE *)signature, &ck_sigsize); + if (ret != CKR_OK) { + printf("message: %d\n", (int)ret); + return 1; + } + + ret = (*func->C_DecryptInit)(session, &mechanism, private); + if (ret != CKR_OK) + return 1; + + outsize = sizeof(outdata); + ret = (*func->C_Decrypt)(session, (CK_BYTE *)signature, ck_sigsize, + (CK_BYTE *)outdata, &outsize); + if (ret != CKR_OK) { + printf("message: %d\n", (int)ret); + return 1; + } + + if (ct_memcmp(sighash, outdata, strlen(sighash)) != 0) + return 1; + } +#endif + + ret = (*func->C_CloseSession)(session); + if (ret != CKR_OK) + return 1; + + (*func->C_Finalize)(NULL_PTR); + + return 0; +} diff --git a/third_party/heimdal/lib/hx509/test_windows.in b/third_party/heimdal/lib/hx509/test_windows.in new file mode 100644 index 0000000..c617f81 --- /dev/null +++ b/third_party/heimdal/lib/hx509/test_windows.in @@ -0,0 +1,89 @@ +#!/bin/sh +# +# Copyright (c) 2007 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Id$ +# + +srcdir="@srcdir@" +objdir="@objdir@" + +stat="--statistic-file=${objdir}/statfile" + +hxtool="${TESTS_ENVIRONMENT} ./hxtool ${stat}" + +if ${hxtool} info | grep 'rsa: hcrypto null RSA' > /dev/null ; then + exit 77 +fi +if ${hxtool} info | grep 'rand: not available' > /dev/null ; then + exit 77 +fi + +echo "Create trust anchor" +${hxtool} issue-certificate \ + --self-signed \ + --issue-ca \ + --generate-key=rsa \ + --subject="CN=Windows-CA,DC=heimdal,DC=pki" \ + --lifetime=10years \ + --certificate="FILE:wca.pem" || exit 1 + +echo "Create domain controller cert" +${hxtool} issue-certificate \ + --type="pkinit-kdc" \ + --pk-init-principal="krbtgt/HEIMDAL.PKI@HEIMDAL.PKI" \ + --hostname=kdc.heimdal.pki \ + --generate-key=rsa \ + --subject="CN=kdc.heimdal.pki,dc=heimdal,dc=pki" \ + --certificate="FILE:wdc.pem" \ + --domain-controller \ + --crl-uri="http://www.test.h5l.se/test-hemdal-pki-crl1.crl" \ + --ca-certificate=FILE:wca.pem || exit 1 + + +echo "Create user cert" +${hxtool} issue-certificate \ + --type="pkinit-client" \ + --pk-init-principal="user@HEIMDAL.PKI" \ + --generate-key=rsa \ + --subject="CN=User,DC=heimdal,DC=pki" \ + --ms-upn="user@heimdal.pki" \ + --crl-uri="http://www.test.h5l.se/test-hemdal-pki-crl1.crl" \ + --certificate="FILE:wuser.pem" \ + --ca-certificate=FILE:wca.pem || exit 1 + +echo "Create crl" +${hxtool} crl-sign \ + --crl-file=wcrl.crl \ + --signer=FILE:wca.pem || exit 1 + +exit 0 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-available1 b/third_party/heimdal/lib/hx509/tst-crypto-available1 new file mode 100644 index 0000000..71fa741 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-available1 @@ -0,0 +1,13 @@ +1.2.840.113549.1.1.11 +1.2.840.113549.1.1.5 +1.2.840.113549.1.1.5 +1.2.840.113549.1.1.4 +1.2.840.113549.1.1.2 +1.2.752.43.16.1 +2.16.840.1.101.3.4.2.1 +1.3.14.3.2.26 +1.2.840.113549.2.5 +1.2.840.113549.2.2 +1.2.840.113549.3.7 +2.16.840.1.101.3.4.1.2 +2.16.840.1.101.3.4.1.42 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-available2 b/third_party/heimdal/lib/hx509/tst-crypto-available2 new file mode 100644 index 0000000..22c0920 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-available2 @@ -0,0 +1,5 @@ +2.16.840.1.101.3.4.2.3 +2.16.840.1.101.3.4.2.2 +2.16.840.1.101.3.4.2.1 +1.3.14.3.2.26 +1.2.840.113549.2.5 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-available3 b/third_party/heimdal/lib/hx509/tst-crypto-available3 new file mode 100644 index 0000000..0b1a855 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-available3 @@ -0,0 +1,6 @@ +1.2.840.113549.1.1.11 +1.2.840.113549.1.1.5 +1.2.840.113549.1.1.5 +1.2.840.113549.1.1.4 +1.2.840.113549.1.1.2 +1.2.752.43.16.1 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select b/third_party/heimdal/lib/hx509/tst-crypto-select new file mode 100644 index 0000000..399c883 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select @@ -0,0 +1 @@ +1.2.840.113549.1.1.11 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select1 b/third_party/heimdal/lib/hx509/tst-crypto-select1 new file mode 100644 index 0000000..c343b57 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select1 @@ -0,0 +1 @@ +2.16.840.1.101.3.4.2.1 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select2 b/third_party/heimdal/lib/hx509/tst-crypto-select2 new file mode 100644 index 0000000..399c883 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select2 @@ -0,0 +1 @@ +1.2.840.113549.1.1.11 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select3 b/third_party/heimdal/lib/hx509/tst-crypto-select3 new file mode 100644 index 0000000..ba9f29f --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select3 @@ -0,0 +1 @@ +1.2.840.113549.1.1.4 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select4 b/third_party/heimdal/lib/hx509/tst-crypto-select4 new file mode 100644 index 0000000..749a549 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select4 @@ -0,0 +1 @@ +1.2.840.113549.1.1.5 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select5 b/third_party/heimdal/lib/hx509/tst-crypto-select5 new file mode 100644 index 0000000..399c883 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select5 @@ -0,0 +1 @@ +1.2.840.113549.1.1.11 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select6 b/third_party/heimdal/lib/hx509/tst-crypto-select6 new file mode 100644 index 0000000..749a549 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select6 @@ -0,0 +1 @@ +1.2.840.113549.1.1.5 diff --git a/third_party/heimdal/lib/hx509/tst-crypto-select7 b/third_party/heimdal/lib/hx509/tst-crypto-select7 new file mode 100644 index 0000000..9b0ac64 --- /dev/null +++ b/third_party/heimdal/lib/hx509/tst-crypto-select7 @@ -0,0 +1 @@ +2.16.840.1.101.3.4.1.42 diff --git a/third_party/heimdal/lib/hx509/version-script.map b/third_party/heimdal/lib/hx509/version-script.map new file mode 100644 index 0000000..27f5f51 --- /dev/null +++ b/third_party/heimdal/lib/hx509/version-script.map @@ -0,0 +1,315 @@ +# $Id$ + +HEIMDAL_X509_1.2 { + global: + _hx509_cert_assign_key; + _hx509_cert_get_keyusage; + _hx509_cert_get_version; + _hx509_cert_private_key; + _hx509_certs_keys_free; + _hx509_certs_keys_get; + _hx509_expr_eval; + _hx509_expr_free; + _hx509_expr_parse; + _hx509_generate_private_key; + _hx509_generate_private_key_bits; + _hx509_generate_private_key_free; + _hx509_generate_private_key_init; + _hx509_generate_private_key_is_ca; + _hx509_get_cert; + _hx509_ks_type; + _hx509_make_pkinit_san; + _hx509_map_file_os; + _hx509_name_from_Name; + _hx509_ossl_oid2nid; + _hx509_private_key_export; + _hx509_private_key_exportable; + _hx509_private_key_get_internal; + _hx509_private_key_oid; + _hx509_private_key_ref; + hx509_request_add_GeneralName; + hx509_request_add_dns_name; + hx509_request_add_dns_srv; + hx509_request_add_eku; + hx509_request_add_email; + hx509_request_add_ms_upn_name; + hx509_request_add_pkinit; + hx509_request_add_registered; + hx509_request_add_xmpp_name; + hx509_request_authorize_cA; + hx509_request_authorize_ku; + hx509_request_authorize_eku; + hx509_request_authorize_san; + hx509_request_count_unsupported; + hx509_request_count_unauthorized; + hx509_request_eku_authorized_p; + hx509_request_print; + hx509_request_reject_eku; + hx509_request_reject_san; + hx509_request_san_authorized_p; + hx509_request_to_pkcs10; + _hx509_unmap_file_os; + _hx509_write_file; + hx509_bitstring_print; + _hx509_ca_issue_certificate; + hx509_ca_sign; + hx509_ca_sign_self; + hx509_ca_tbs_add_crl_dp_uri; + hx509_ca_tbs_add_eku; + hx509_ca_tbs_add_ku; + hx509_ca_tbs_add_pol; + hx509_ca_tbs_add_pol_mapping; + hx509_ca_tbs_add_san; + hx509_ca_tbs_add_san_dnssrv; + hx509_ca_tbs_add_san_hardwareModuleName; + hx509_ca_tbs_add_san_hardwareModuleName_string; + hx509_ca_tbs_add_san_hostname; + hx509_ca_tbs_add_san_jid; + hx509_ca_tbs_add_san_ms_upn; + hx509_ca_tbs_add_san_otherName; + hx509_ca_tbs_add_san_permanentIdentifier; + hx509_ca_tbs_add_san_permanentIdentifier_string; + hx509_ca_tbs_add_san_pkinit; + hx509_ca_tbs_add_san_rfc822name; + hx509_ca_tbs_free; + hx509_ca_tbs_get_name; + hx509_ca_tbs_init; + hx509_ca_tbs_set_ca; + hx509_ca_tbs_set_domaincontroller; + hx509_ca_tbs_set_from_csr; + hx509_ca_tbs_set_notAfter; + hx509_ca_tbs_set_notAfter_lifetime; + hx509_ca_tbs_set_notBefore; + hx509_ca_tbs_set_pkinit_max_life; + hx509_ca_tbs_set_proxy; + hx509_ca_tbs_set_serialnumber; + hx509_ca_tbs_set_spki; + hx509_ca_tbs_set_subject; + hx509_ca_tbs_set_template; + hx509_ca_tbs_set_unique; + hx509_ca_tbs_subject_expand; + hx509_ca_tbs_template_units; + hx509_cert; + hx509_cert_attribute; + hx509_cert_binary; + hx509_cert_check_eku; + hx509_cert_cmp; + hx509_cert_find_subjectAltName_otherName; + hx509_cert_free; + hx509_cert_get_SPKI; + hx509_cert_get_SPKI_AlgorithmIdentifier; + hx509_cert_get_attribute; + hx509_cert_get_base_subject; + hx509_cert_get_friendly_name; + hx509_cert_get_issuer; + hx509_cert_get_notAfter; + hx509_cert_get_notBefore; + hx509_cert_get_pkinit_max_life; + hx509_cert_get_serialnumber; + hx509_cert_get_subject; + hx509_cert_get_issuer_unique_id; + hx509_cert_get_subject_unique_id; + hx509_cert_have_private_key; + hx509_cert_have_private_key_only; + hx509_cert_init; + hx509_cert_init_data; + hx509_cert_init_private_key; + hx509_cert_is_ca; + hx509_cert_is_root; + hx509_cert_is_self_signed; + hx509_cert_keyusage_print; + hx509_cert_public_encrypt; + hx509_cert_ref; + hx509_cert_set_friendly_name; + hx509_certs_add; + hx509_certs_append; + hx509_certs_end_seq; + hx509_certs_destroy; + hx509_certs_ref; + hx509_certs_filter; + hx509_certs_find; + hx509_certs_free; + hx509_certs_info; + hx509_certs_init; + hx509_certs_iter; + hx509_certs_iter_f; + hx509_certs_merge; + hx509_certs_next_cert; + hx509_certs_start_seq; + hx509_certs_store; + hx509_ci_print_names; + hx509_clear_error_string; + hx509_cms_create_signed; + hx509_cms_create_signed_1; + hx509_cms_decrypt_encrypted; + hx509_cms_envelope_1; + hx509_cms_unenvelope; + hx509_cms_unwrap_ContentInfo; + hx509_cms_verify_signed; + hx509_cms_verify_signed_ext; + hx509_cms_wrap_ContentInfo; + hx509_context_free; + hx509_context_init; + hx509_context_set_missing_revoke; + hx509_crl_add_revoked_certs; + hx509_crl_alloc; + hx509_crl_free; + hx509_crl_lifetime; + hx509_crl_sign; + hx509_crypto_aes128_cbc; + hx509_crypto_aes256_cbc; + hx509_crypto_allow_weak; + hx509_crypto_available; + hx509_crypto_decrypt; + hx509_crypto_des_rsdi_ede3_cbc; + hx509_crypto_destroy; + hx509_crypto_encrypt; + hx509_crypto_enctype_by_name; + hx509_crypto_free_algs; + hx509_crypto_get_params; + hx509_crypto_init; + hx509_crypto_provider; + hx509_crypto_select; + hx509_crypto_set_key_data; + hx509_crypto_set_key_name; + hx509_crypto_set_padding; + hx509_crypto_set_params; + hx509_crypto_set_random_key; + hx509_empty_name; + hx509_env_add; + hx509_env_add_binding; + hx509_env_find; + hx509_env_find_binding; + hx509_env_free; + hx509_env_init; + hx509_env_lfind; + hx509_err; + hx509_free_error_string; + hx509_free_octet_string_list; + hx509_find_private_alg; + hx509_general_name_unparse; + hx509_get_error_string; + hx509_get_instance; + hx509_get_one_cert; + hx509_lock_add_cert; + hx509_lock_add_certs; + hx509_lock_add_password; + hx509_lock_command_string; + hx509_lock_free; + hx509_lock_init; + hx509_lock_prompt; + hx509_lock_reset_certs; + hx509_lock_reset_passwords; + hx509_lock_reset_promper; + hx509_lock_set_prompter; + hx509_name_binary; + hx509_name_cmp; + hx509_name_copy; + hx509_name_expand; + hx509_name_free; + hx509_name_is_null_p; + hx509_name_normalize; + hx509_name_to_Name; + hx509_name_to_string; + hx509_ocsp_request; + hx509_ocsp_verify; + hx509_oid_print; + hx509_oid_sprint; + hx509_parse_name; + hx509_parse_private_key; + hx509_peer_info_add_cms_alg; + hx509_peer_info_alloc; + hx509_peer_info_free; + hx509_peer_info_set_cert; + hx509_peer_info_set_cms_algs; + hx509_pem_add_header; + hx509_pem_find_header; + hx509_pem_free_header; + hx509_pem_read; + hx509_pem_write; + hx509_print_stdout; + hx509_print_cert; + hx509_private_key_assign_rsa; + hx509_private_key_free; + hx509_private_key_private_decrypt; + hx509_private_key_init; + hx509_private_key2SPKI; + hx509_prompt_hidden; + hx509_query_alloc; + hx509_query_free; + hx509_query_match_cmp_func; + hx509_query_match_eku; + hx509_query_match_expr; + hx509_query_match_friendly_name; + hx509_query_match_issuer_serial; + hx509_query_match_option; + hx509_query_statistic_file; + hx509_query_unparse_stats; + hx509_request_get_cA; + hx509_request_get_cA_pathLenConstraint; + hx509_request_get_eku; + hx509_request_get_exts; + hx509_request_get_ku; + hx509_request_get_name; + hx509_request_get_san; + hx509_request_get_SubjectPublicKeyInfo; + hx509_request_free; + hx509_request_init; + hx509_request_parse; + hx509_request_parse_der; + hx509_request_set_cA; + hx509_request_set_eE; + hx509_request_set_ku; + hx509_request_set_name; + hx509_request_set_SubjectPublicKeyInfo; + hx509_revoke_add_crl; + hx509_revoke_add_ocsp; + hx509_revoke_free; + hx509_revoke_init; + hx509_revoke_ocsp_print; + hx509_revoke_verify; + hx509_revoke_print; + hx509_set_error_string; + hx509_set_error_stringv; + hx509_signature_md5; + hx509_signature_rsa; + hx509_signature_rsa_with_md5; + hx509_signature_rsa_with_sha1; + hx509_signature_rsa_with_sha256; + hx509_signature_rsa_with_sha384; + hx509_signature_rsa_with_sha512; + hx509_signature_sha1; + hx509_signature_sha256; + hx509_signature_sha384; + hx509_signature_sha512; + hx509_unparse_der_name; + hx509_validate_cert; + hx509_validate_ctx_add_flags; + hx509_validate_ctx_free; + hx509_validate_ctx_init; + hx509_validate_ctx_set_print; + hx509_verify_attach_anchors; + hx509_verify_attach_revoke; + hx509_verify_ctx_f_allow_default_trustanchors; + hx509_verify_destroy_ctx; + hx509_verify_hostname; + hx509_verify_init_ctx; + hx509_verify_path; + hx509_verify_set_max_depth; + hx509_verify_set_proxy_certificate; + hx509_verify_set_strict_rfc3280_verification; + hx509_verify_set_time; + hx509_verify_signature; + hx509_xfree; + initialize_hx_error_table_r; + # pkcs11 symbols + C_GetFunctionList; + local: + *; +}; + +HEIMDAL_X509_1.3 { + global: + hx509_ca_tbs_set_signature_algorithm; +}; + diff --git a/third_party/heimdal/lib/ipc/Makefile.am b/third_party/heimdal/lib/ipc/Makefile.am new file mode 100644 index 0000000..04ff213 --- /dev/null +++ b/third_party/heimdal/lib/ipc/Makefile.am @@ -0,0 +1,76 @@ +include $(top_srcdir)/Makefile.am.common + +noinst_LTLIBRARIES = libheim-ipcc.la libheim-ipcs.la + +dist_libheim_ipcc_la_SOURCES = hi_locl.h heim_ipc_types.h client.c common.c +dist_libheim_ipcs_la_SOURCES = hi_locl.h heim_ipc_types.h server.c common.c + +include_HEADERS = heim-ipc.h + +## +## Enable when this is not a noinst_ library +## +#libheim_ipcc_la_LDFLAGS = -version-info 0:0:0 +#libheim_ipcs_la_LDFLAGS = -version-info 0:0:0 +# +#if versionscript +#libheim_ipcc_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scriptc.map +#libheim_ipcs_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scripts.map +#endif + +libheim_ipcc_la_LIBADD = \ + $(LIB_heimbase) \ + $(LIB_roken) \ + $(PTHREAD_LIBADD) + +if SUNOS +libheim_ipcc_la_LIBADD += -lsocket +endif + +libheim_ipcs_la_LIBADD = $(libheim_ipcc_la_LIBADD) + +TESTS = $(check_PROGRAMS) + +noinst_PROGRAMS = tc ts ts-http + +ts_LDADD = libheim-ipcs.la $(LIB_roken) +ts_http_LDADD = $(ts_LDADD) +tc_LDADD = libheim-ipcc.la $(LIB_roken) + + +EXTRA_DIST = heim_ipc.defs heim_ipc_async.defs heim_ipc_reply.defs + +if have_gcd + +# We still use dispatch_get_current_queue(), which is deprecated, and that +# stops building on recent OS X releases unless we disable this warning. +WFLAGS += -Wno-deprecated-declarations + +heim_ipc.h heim_ipcUser.c heim_ipcServer.c heim_ipcServer.h: heim_ipc.defs + mig -header heim_ipc.h -user heim_ipcUser.c -sheader heim_ipcServer.h -server heim_ipcServer.c -I$(srcdir) $(srcdir)/heim_ipc.defs + +heim_ipc_async.h heim_ipc_asyncUser.c heim_ipc_asyncServer.c heim_ipc_asyncServer.h: heim_ipc_async.defs + mig -header heim_ipc_async.h -user heim_ipc_asyncUser.c -sheader heim_ipc_asyncServer.h -server heim_ipc_asyncServer.c -I$(srcdir) $(srcdir)/heim_ipc_async.defs + +heim_ipc_reply.h heim_ipc_replyUser.c: heim_ipc_reply.defs + mig -header heim_ipc_reply.h -user heim_ipc_replyUser.c -sheader /dev/null -server /dev/null -I$(srcdir) $(srcdir)/heim_ipc_reply.defs + +built_ipcc = heim_ipc.h heim_ipcUser.c +built_ipcc += heim_ipc_asyncServer.c heim_ipc_asyncServer.h + +nodist_libheim_ipcc_la_SOURCES = $(built_ipcc) + +built_ipcs = heim_ipcServer.c heim_ipcServer.h +built_ipcs += heim_ipc_asyncUser.c heim_ipc_async.h +built_ipcs += heim_ipc_reply.h heim_ipc_replyUser.c + +nodist_libheim_ipcs_la_SOURCES = $(built_ipcs) + +libheim_ipcs_la_LIBADD += -lbsm + +CLEANFILES = $(built_ipcc) $(built_ipcs) + +$(srcdir)/client.c: $(built_ipcc) +$(srcdir)/server.c: $(built_ipcs) + +endif diff --git a/third_party/heimdal/lib/ipc/client.c b/third_party/heimdal/lib/ipc/client.c new file mode 100644 index 0000000..d4d3c03 --- /dev/null +++ b/third_party/heimdal/lib/ipc/client.c @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" + +#if defined(__APPLE__) && defined(HAVE_GCD) + +#include "heim_ipc.h" +#include "heim_ipc_asyncServer.h" + +#include +#include + +static dispatch_once_t jobqinited = 0; +static dispatch_queue_t jobq = NULL; +static dispatch_queue_t syncq; + +struct mach_ctx { + mach_port_t server; + char *name; +}; + +static int +mach_release(void *ctx); + +static int +mach_init(const char *service, void **ctx) +{ + struct mach_ctx *ipc; + mach_port_t sport; + int ret; + + dispatch_once(&jobqinited, ^{ + jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + syncq = dispatch_queue_create("heim-ipc-syncq", NULL); + }); + + ret = bootstrap_look_up(bootstrap_port, service, &sport); + if (ret) + return ret; + + ipc = malloc(sizeof(*ipc)); + if (ipc == NULL) { + mach_port_destroy(mach_task_self(), sport); + return ENOMEM; + } + + ipc->server = sport; + ipc->name = strdup(service); + if (ipc->name == NULL) { + mach_release(ipc); + return ENOMEM; + } + + *ctx = ipc; + + return 0; +} + +static int +mach_ipc(void *ctx, + const heim_idata *request, heim_idata *response, + heim_icred *cred) +{ + struct mach_ctx *ipc = ctx; + heim_ipc_message_inband_t requestin; + mach_msg_type_number_t requestin_length = 0; + heim_ipc_message_outband_t requestout = NULL; + mach_msg_type_number_t requestout_length = 0; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyin_length; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyout_length; + int ret, errorcode, retries = 0; + + memcpy(requestin, request->data, request->length); + requestin_length = request->length; + + while (retries < 2) { + __block mach_port_t sport; + + dispatch_sync(syncq, ^{ sport = ipc->server; }); + + ret = mheim_ipc_call(sport, + requestin, requestin_length, + requestout, requestout_length, + &errorcode, + replyin, &replyin_length, + &replyout, &replyout_length); + if (ret == MACH_SEND_INVALID_DEST) { + mach_port_t nport; + /* race other threads to get a new port */ + ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport); + if (ret) + return ret; + dispatch_sync(syncq, ^{ + /* check if we lost the race to lookup the port */ + if (sport != ipc->server) { + mach_port_deallocate(mach_task_self(), nport); + } else { + mach_port_deallocate(mach_task_self(), ipc->server); + ipc->server = nport; + } + }); + retries++; + } else if (ret) { + return ret; + } else + break; + } + if (retries >= 2) + return EINVAL; + + if (errorcode) { + if (replyout_length) + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + return errorcode; + } + + if (replyout_length) { + response->data = malloc(replyout_length); + if (response->data == NULL) { + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + return ENOMEM; + } + memcpy(response->data, replyout, replyout_length); + response->length = replyout_length; + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + } else { + response->data = malloc(replyin_length); + if (response->data == NULL) + return ENOMEM; + memcpy(response->data, replyin, replyin_length); + response->length = replyin_length; + } + + return 0; +} + +struct async_client { + mach_port_t mp; + dispatch_source_t source; + dispatch_queue_t queue; + void (*func)(void *, int, heim_idata *, heim_icred); + void *userctx; +}; + +kern_return_t +mheim_ado_acall_reply(mach_port_t server_port, + audit_token_t client_creds, + int returnvalue, + heim_ipc_message_inband_t replyin, + mach_msg_type_number_t replyinCnt, + heim_ipc_message_outband_t replyout, + mach_msg_type_number_t replyoutCnt) +{ + struct async_client *c = dispatch_get_context(dispatch_get_current_queue()); + heim_idata response; + + if (returnvalue) { + response.data = NULL; + response.length = 0; + } else if (replyoutCnt) { + response.data = replyout; + response.length = replyoutCnt; + } else { + response.data = replyin; + response.length = replyinCnt; + } + + (*c->func)(c->userctx, returnvalue, &response, NULL); + + if (replyoutCnt) + vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt); + + dispatch_source_cancel(c->source); + + return 0; + + +} + + +static int +mach_async(void *ctx, const heim_idata *request, void *userctx, + void (*func)(void *, int, heim_idata *, heim_icred)) +{ + struct mach_ctx *ipc = ctx; + heim_ipc_message_inband_t requestin; + mach_msg_type_number_t requestin_length = 0; + heim_ipc_message_outband_t requestout = NULL; + mach_msg_type_number_t requestout_length = 0; + int ret, retries = 0; + kern_return_t kr; + struct async_client *c; + + /* first create the service that will catch the reply from the server */ + /* XXX these object should be cached and reused */ + + c = malloc(sizeof(*c)); + if (c == NULL) + return ENOMEM; + + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp); + if (kr != KERN_SUCCESS) + return EINVAL; + + c->queue = dispatch_queue_create("heim-ipc-async-client", NULL); + c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue); + dispatch_set_context(c->queue, c); + + dispatch_source_set_event_handler(c->source, ^{ + dispatch_mig_server(c->source, + sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem), + mheim_aipc_server); + }); + + dispatch_source_set_cancel_handler(c->source, ^{ + mach_port_mod_refs(mach_task_self(), c->mp, + MACH_PORT_RIGHT_RECEIVE, -1); + dispatch_release(c->queue); + dispatch_release(c->source); + free(c); + }); + + c->func = func; + c->userctx = userctx; + + dispatch_resume(c->source); + + /* ok, send the message */ + + memcpy(requestin, request->data, request->length); + requestin_length = request->length; + + while (retries < 2) { + __block mach_port_t sport; + + dispatch_sync(syncq, ^{ sport = ipc->server; }); + + ret = mheim_ipc_call_request(sport, c->mp, + requestin, requestin_length, + requestout, requestout_length); + if (ret == MACH_SEND_INVALID_DEST) { + ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport); + if (ret) { + dispatch_source_cancel(c->source); + return ret; + } + mach_port_deallocate(mach_task_self(), ipc->server); + ipc->server = sport; + retries++; + } else if (ret) { + dispatch_source_cancel(c->source); + return ret; + } else + break; + } + if (retries >= 2) { + dispatch_source_cancel(c->source); + return EINVAL; + } + + return 0; +} + +static int +mach_release(void *ctx) +{ + struct mach_ctx *ipc = ctx; + if (ipc->server != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), ipc->server); + free(ipc->name); + free(ipc); + return 0; +} + +#endif + +struct path_ctx { + char *path; + int fd; +}; + +static int common_release(void *); + +static int +connect_unix(struct path_ctx *s) +{ + struct sockaddr_un addr; + + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path)); + + s->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->fd < 0) + return errno; + rk_cloexec(s->fd); + + if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + return errno; + + return 0; +} + +static int +common_path_init(const char *base, + const char *service, + const char *file, + void **ctx) +{ + struct path_ctx *s; + + s = malloc(sizeof(*s)); + if (s == NULL) + return ENOMEM; + s->fd = -1; + + if (asprintf(&s->path, "%s/.heim_%s-%s", base, service, file) == -1) { + free(s); + return ENOMEM; + } + + *ctx = s; + return 0; +} + +static int +unix_socket_init(const char *service, + void **ctx) +{ + const char *base = secure_getenv("HEIM_IPC_DIR"); + int ret; + + ret = common_path_init(base ? base : _PATH_VARRUN, service, "socket", ctx); + if (ret) + return ret; + ret = connect_unix(*ctx); + if (ret) + common_release(*ctx); + + return ret; +} + +static int +unix_socket_ipc(void *ctx, + const heim_idata *req, heim_idata *rep, + heim_icred *cred) +{ + struct path_ctx *s = ctx; + uint32_t len = htonl(req->length); + uint32_t rv; + int retval; + + if (cred) + *cred = NULL; + + rep->data = NULL; + rep->length = 0; + + if (net_write(s->fd, &len, sizeof(len)) != sizeof(len)) + return -1; + if (net_write(s->fd, req->data, req->length) != (ssize_t)req->length) + return -1; + + if (net_read(s->fd, &len, sizeof(len)) != sizeof(len)) + return -1; + if (net_read(s->fd, &rv, sizeof(rv)) != sizeof(rv)) + return -1; + retval = ntohl(rv); + + rep->length = ntohl(len); + if (rep->length > 0) { + rep->data = malloc(rep->length); + if (rep->data == NULL) + return -1; + if (net_read(s->fd, rep->data, rep->length) != (ssize_t)rep->length) + return -1; + } else + rep->data = NULL; + + return retval; +} + +int +common_release(void *ctx) +{ + struct path_ctx *s = ctx; + if (s->fd >= 0) + close(s->fd); + free(s->path); + free(s); + return 0; +} + +#ifdef HAVE_DOOR_CREATE + +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +static int +door_init(const char *service, + void **ctx) +{ + const char *base = secure_getenv("HEIM_IPC_DIR"); + int ret; + struct path_ctx *d; + + ret = common_path_init(base ? base : _PATH_VARRUN, service, "door", ctx); + if (ret) + return ret; + + d = (struct path_ctx *)*ctx; + d->fd = open(d->path, O_RDWR); + if (d->fd < 0) { + ret = errno; + common_release(*ctx); + return ret; + } + + return 0; +} + +struct door_reply { + int returnvalue; + size_t length; + unsigned char data[1]; +}; + +static int +door_ipc(void *ctx, + const heim_idata *request, heim_idata *response, + heim_icred *cred) +{ + struct path_ctx *d = (struct path_ctx *)ctx; + door_arg_t arg; + int ret; + struct door_reply *r; + + arg.data_ptr = request->data; + arg.data_size = request->length; + arg.desc_ptr = NULL; + arg.desc_num = 0; + arg.rbuf = NULL; + arg.rsize = 0; + + ret = door_call(d->fd, &arg); + if (ret != 0) + return errno; + + if (arg.rsize < offsetof(struct door_reply, data)) + return EINVAL; + + r = (struct door_reply *)arg.rbuf; + if (r->returnvalue != 0) + return r->returnvalue; + + if (arg.rsize < offsetof(struct door_reply, data) + r->length) + return ERANGE; + + response->data = malloc(r->length); + if (response->data == NULL) { + munmap(arg.rbuf, arg.rsize); + return ENOMEM; + } + + memcpy(response->data, r->data, r->length); + response->length = r->length; + munmap(arg.rbuf, arg.rsize); + + return 0; +} + +#endif /* HAVE_DOOR_CREATE */ + +struct hipc_ops { + const char *prefix; + int (*init)(const char *, void **); + int (*release)(void *); + int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *); + int (*async)(void *, const heim_idata *, void *, + void (*)(void *, int, heim_idata *, heim_icred)); +}; + +static const struct hipc_ops ipcs[] = { +#if defined(__APPLE__) && defined(HAVE_GCD) + { "MACH", mach_init, mach_release, mach_ipc, mach_async }, +#endif +#ifdef HAVE_DOOR_CREATE + { "DOOR", door_init, common_release, door_ipc, NULL }, +#endif + { "UNIX", unix_socket_init, common_release, unix_socket_ipc, NULL } +}; + +struct heim_ipc { + const struct hipc_ops *ops; + void *ctx; +}; + + +int +heim_ipc_init_context(const char *name, heim_ipc *ctx) +{ + unsigned int i; + int ret, any = 0; + + for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) { + size_t prefix_len = strlen(ipcs[i].prefix); + heim_ipc c; + if(strncmp(ipcs[i].prefix, name, prefix_len) == 0 + && name[prefix_len] == ':') { + } else if (strncmp("ANY:", name, 4) == 0) { + prefix_len = 3; + any = 1; + } else + continue; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->ops = &ipcs[i]; + + ret = (c->ops->init)(name + prefix_len + 1, &c->ctx); + if (ret) { + free(c); + if (any) + continue; + return ret; + } + + *ctx = c; + return 0; + } + + return ENOENT; +} + +void +heim_ipc_free_context(heim_ipc ctx) +{ + (ctx->ops->release)(ctx->ctx); + free(ctx); +} + +int +heim_ipc_call(heim_ipc ctx, const heim_idata *snd, heim_idata *rcv, + heim_icred *cred) +{ + if (cred) + *cred = NULL; + return (ctx->ops->ipc)(ctx->ctx, snd, rcv, cred); +} + +int +heim_ipc_async(heim_ipc ctx, const heim_idata *snd, void *userctx, + void (*func)(void *, int, heim_idata *, heim_icred)) +{ + if (ctx->ops->async == NULL) { + heim_idata rcv; + heim_icred cred = NULL; + int ret; + + ret = (ctx->ops->ipc)(ctx->ctx, snd, &rcv, &cred); + (*func)(userctx, ret, &rcv, cred); + heim_ipc_free_cred(cred); + free(rcv.data); + return ret; + } else { + return (ctx->ops->async)(ctx->ctx, snd, userctx, func); + } +} diff --git a/third_party/heimdal/lib/ipc/common.c b/third_party/heimdal/lib/ipc/common.c new file mode 100644 index 0000000..cfbe4b5 --- /dev/null +++ b/third_party/heimdal/lib/ipc/common.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" +#ifdef HAVE_GCD +#include +#else +#include "heim_threads.h" +#endif + +struct heim_icred { + uid_t uid; + gid_t gid; + pid_t pid; + pid_t session; +}; + +void +heim_ipc_free_cred(heim_icred cred) +{ + free(cred); +} + +uid_t +heim_ipc_cred_get_uid(heim_icred cred) +{ + return cred ? cred->uid : (uid_t)-1; +} + +gid_t +heim_ipc_cred_get_gid(heim_icred cred) +{ + return cred ? cred->gid : (gid_t)-1; +} + +pid_t +heim_ipc_cred_get_pid(heim_icred cred) +{ + return cred ? cred->pid : (pid_t)0; +} + +pid_t +heim_ipc_cred_get_session(heim_icred cred) +{ + return cred ? cred->session : (pid_t)-1; +} + + +int +_heim_ipc_create_cred(uid_t uid, gid_t gid, pid_t pid, pid_t session, heim_icred *cred) +{ + *cred = calloc(1, sizeof(**cred)); + if (*cred == NULL) + return ENOMEM; + (*cred)->uid = uid; + (*cred)->gid = gid; + (*cred)->pid = pid; + (*cred)->session = session; + return 0; +} + +#ifndef HAVE_GCD +struct heim_isemaphore { + HEIMDAL_MUTEX mutex; +#ifdef ENABLE_PTHREAD_SUPPORT + pthread_cond_t cond; +#endif + long counter; +}; +#endif + +heim_isemaphore +heim_ipc_semaphore_create(long value) +{ +#ifdef HAVE_GCD + return (heim_isemaphore)dispatch_semaphore_create(value); +#elif !defined(ENABLE_PTHREAD_SUPPORT) + heim_assert(0, "no semaphore support w/o pthreads"); + return NULL; +#else + heim_isemaphore s = malloc(sizeof(*s)); + if (s == NULL) + return NULL; + HEIMDAL_MUTEX_init(&s->mutex); + pthread_cond_init(&s->cond, NULL); + s->counter = value; + return s; +#endif +} + +long +heim_ipc_semaphore_wait(heim_isemaphore s, time_t t) +{ +#ifdef HAVE_GCD + uint64_t timeout; + if (t == HEIM_IPC_WAIT_FOREVER) + timeout = DISPATCH_TIME_FOREVER; + else + timeout = (uint64_t)t * NSEC_PER_SEC; + + return dispatch_semaphore_wait((dispatch_semaphore_t)s, timeout); +#elif !defined(ENABLE_PTHREAD_SUPPORT) + heim_assert(0, "no semaphore support w/o pthreads"); + return 0; +#else + HEIMDAL_MUTEX_lock(&s->mutex); + /* if counter hits below zero, we get to wait */ + if (--s->counter < 0) { + int ret; + + if (t == HEIM_IPC_WAIT_FOREVER) + ret = pthread_cond_wait(&s->cond, &s->mutex); + else { + struct timespec ts; + ts.tv_sec = t; + ts.tv_nsec = 0; + ret = pthread_cond_timedwait(&s->cond, &s->mutex, &ts); + } + if (ret) { + HEIMDAL_MUTEX_unlock(&s->mutex); + return errno; + } + } + HEIMDAL_MUTEX_unlock(&s->mutex); + + return 0; +#endif +} + +long +heim_ipc_semaphore_signal(heim_isemaphore s) +{ +#ifdef HAVE_GCD + return dispatch_semaphore_signal((dispatch_semaphore_t)s); +#elif !defined(ENABLE_PTHREAD_SUPPORT) + heim_assert(0, "no semaphore support w/o pthreads"); + return EINVAL; +#else + int wakeup; + HEIMDAL_MUTEX_lock(&s->mutex); + wakeup = (++s->counter == 0) ; + HEIMDAL_MUTEX_unlock(&s->mutex); + if (wakeup) + pthread_cond_signal(&s->cond); + return 0; +#endif +} + +void +heim_ipc_semaphore_release(heim_isemaphore s) +{ +#ifdef HAVE_GCD + dispatch_release((dispatch_semaphore_t)s); +#elif !defined(ENABLE_PTHREAD_SUPPORT) + heim_assert(0, "no semaphore support w/o pthreads"); +#else + HEIMDAL_MUTEX_lock(&s->mutex); + if (s->counter != 0) + abort(); + HEIMDAL_MUTEX_unlock(&s->mutex); + HEIMDAL_MUTEX_destroy(&s->mutex); + pthread_cond_destroy(&s->cond); + free(s); +#endif +} + +void +heim_ipc_free_data(heim_idata *data) +{ + if (data->data) + free(data->data); + data->data = NULL; + data->length = 0; +} diff --git a/third_party/heimdal/lib/ipc/heim-ipc.h b/third_party/heimdal/lib/ipc/heim-ipc.h new file mode 100644 index 0000000..a34e338 --- /dev/null +++ b/third_party/heimdal/lib/ipc/heim-ipc.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +typedef struct heim_ipc *heim_ipc; +typedef struct heim_sipc *heim_sipc; +typedef struct heim_icred *heim_icred; +typedef struct heim_isemaphore *heim_isemaphore; +typedef struct heim_base_data heim_idata; +typedef struct heim_sipc_call *heim_sipc_call; + +/* common */ + +void +heim_ipc_free_cred(heim_icred); + +uid_t +heim_ipc_cred_get_uid(heim_icred); + +gid_t +heim_ipc_cred_get_gid(heim_icred); + +pid_t +heim_ipc_cred_get_pid(heim_icred); + +pid_t +heim_ipc_cred_get_session(heim_icred); + +void +heim_ipc_main(void); + +heim_isemaphore +heim_ipc_semaphore_create(long); + +long +heim_ipc_semaphore_wait(heim_isemaphore, time_t); + +long +heim_ipc_semaphore_signal(heim_isemaphore); + +void +heim_ipc_semaphore_release(heim_isemaphore); + +#define HEIM_IPC_WAIT_FOREVER ((time_t)-1) + +void +heim_ipc_free_data(heim_idata *); + +/* client */ + +int +heim_ipc_init_context(const char *, heim_ipc *); + +void +heim_ipc_free_context(heim_ipc); + +int +heim_ipc_call(heim_ipc, const heim_idata *, heim_idata *, heim_icred *); + +int +heim_ipc_async(heim_ipc, const heim_idata *, void *, void (*func)(void *, int, heim_idata *, heim_icred)); + +/* server */ + +#define HEIM_SIPC_TYPE_IPC 1 +#define HEIM_SIPC_TYPE_UINT32 2 +#define HEIM_SIPC_TYPE_HTTP 4 + +typedef void +(*heim_ipc_complete)(heim_sipc_call, int, heim_idata *); + +typedef void +(*heim_ipc_callback)(void *, const heim_idata *, + const heim_icred, heim_ipc_complete, heim_sipc_call); + + +int +heim_sipc_launchd_mach_init(const char *, heim_ipc_callback, + void *, heim_sipc *); + +int +heim_sipc_stream_listener(int, int, heim_ipc_callback, + void *, heim_sipc *); + +int +heim_sipc_service_unix(const char *, heim_ipc_callback, + void *, heim_sipc *); + +int +heim_sipc_service_door(const char *, heim_ipc_callback, + void *, heim_sipc *); + +void +heim_sipc_timeout(time_t); + +void +heim_sipc_set_timeout_handler(void (*)(void)); + +void +heim_sipc_free_context(heim_sipc); diff --git a/third_party/heimdal/lib/ipc/heim_ipc.defs b/third_party/heimdal/lib/ipc/heim_ipc.defs new file mode 100644 index 0000000..d2af7ec --- /dev/null +++ b/third_party/heimdal/lib/ipc/heim_ipc.defs @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem mheim_ipc 1; +userprefix mheim_ipc_; +serverprefix mheim_do_; + +routine call( + server_port : mach_port_t; + ServerAuditToken client_creds : audit_token_t; + sreplyport reply_port : mach_port_make_send_once_t; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t; + out returnvalue : int; + out replyin : heim_ipc_message_inband_t; + out replyout : heim_ipc_message_outband_t, dealloc); + +simpleroutine call_request( + server_port : mach_port_t; + ServerAuditToken client_creds : audit_token_t; + in reply_to : mach_port_make_send_once_t; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t); + + + diff --git a/third_party/heimdal/lib/ipc/heim_ipc_async.defs b/third_party/heimdal/lib/ipc/heim_ipc_async.defs new file mode 100644 index 0000000..406e6a2 --- /dev/null +++ b/third_party/heimdal/lib/ipc/heim_ipc_async.defs @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem mheim_aipc 201; +userprefix mheim_aipc_; +serverprefix mheim_ado_; + +simpleroutine acall_reply( + server_port : mach_port_move_send_once_t; + ServerAuditToken client_creds : audit_token_t; + in returnvalue : int; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t); + + + diff --git a/third_party/heimdal/lib/ipc/heim_ipc_reply.defs b/third_party/heimdal/lib/ipc/heim_ipc_reply.defs new file mode 100644 index 0000000..f95d0fa --- /dev/null +++ b/third_party/heimdal/lib/ipc/heim_ipc_reply.defs @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem heim_ipc 101; +userprefix mheim_ripc_; + +simpleroutine call_reply( + reply_port : mach_port_move_send_once_t; + returnvalue : int; + replyin : heim_ipc_message_inband_t; + replyout : heim_ipc_message_outband_t, dealloc); diff --git a/third_party/heimdal/lib/ipc/heim_ipc_types.h b/third_party/heimdal/lib/ipc/heim_ipc_types.h new file mode 100644 index 0000000..fb5c165 --- /dev/null +++ b/third_party/heimdal/lib/ipc/heim_ipc_types.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _HEIM_IPC_TYPES_H_ +#define _HEIM_IPC_TYPES_H_ + +#define HEIM_KCM_BOOTSTRAP_NAME "org.h5l.Kerberos.kcm" + +typedef char heim_ipc_message_inband_t[2048]; +typedef char *heim_ipc_message_outband_t; + +#endif diff --git a/third_party/heimdal/lib/ipc/hi_locl.h b/third_party/heimdal/lib/ipc/hi_locl.h new file mode 100644 index 0000000..6ec28ff --- /dev/null +++ b/third_party/heimdal/lib/ipc/hi_locl.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_SYS_UN_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#ifdef HAVE_GETPEERUCRED +#include +#endif + +#include +#include + +#include +#include + +#include + +#if defined(__APPLE__) && defined(HAVE_GCD) +#include +#include +#include +#include + +#ifndef __APPLE_PRIVATE__ /* awe, using private interface */ +typedef boolean_t (*dispatch_mig_callback_t)(mach_msg_header_t *message, mach_msg_header_t *reply); + +mach_msg_return_t +dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, dispatch_mig_callback_t callback); +#endif + +#endif + + +#include + +int +_heim_ipc_create_cred(uid_t, gid_t, pid_t, pid_t, heim_icred *); diff --git a/third_party/heimdal/lib/ipc/server.c b/third_party/heimdal/lib/ipc/server.c new file mode 100644 index 0000000..5ada75a --- /dev/null +++ b/third_party/heimdal/lib/ipc/server.c @@ -0,0 +1,1372 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" +#include +#include + +#define MAX_PACKET_SIZE (128 * 1024) + +struct heim_sipc { + int (*release)(heim_sipc ctx); + heim_ipc_callback callback; + void *userctx; + void *mech; +}; + +#if defined(__APPLE__) && defined(HAVE_GCD) + +#include "heim_ipcServer.h" +#include "heim_ipc_reply.h" +#include "heim_ipc_async.h" + +static dispatch_source_t timer; +static dispatch_queue_t timerq; +static uint64_t timeoutvalue; + +static dispatch_queue_t eventq; + +static dispatch_queue_t workq; + +static void +default_timer_ev(void) +{ + exit(0); +} + +static void (*timer_ev)(void) = default_timer_ev; + +static void +set_timer(void) +{ + dispatch_source_set_timer(timer, + dispatch_time(DISPATCH_TIME_NOW, + timeoutvalue * NSEC_PER_SEC), + timeoutvalue * NSEC_PER_SEC, 1000000); +} + +static void +init_globals(void) +{ + static dispatch_once_t once; + dispatch_once(&once, ^{ + timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL); + timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq); + dispatch_source_set_event_handler(timer, ^{ timer_ev(); } ); + + workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + eventq = dispatch_queue_create("heim-ipc.event-queue", NULL); + }); +} + +static void +suspend_timer(void) +{ + dispatch_suspend(timer); +} + +static void +restart_timer(void) +{ + dispatch_sync(timerq, ^{ set_timer(); }); + dispatch_resume(timer); +} + +struct mach_service { + mach_port_t sport; + dispatch_source_t source; + dispatch_queue_t queue; +}; + +struct mach_call_ctx { + mach_port_t reply_port; + heim_icred cred; + heim_idata req; +}; + + +static void +mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyinCnt = 0; + heim_ipc_message_outband_t replyout = 0; + mach_msg_type_number_t replyoutCnt = 0; + + if (returnvalue) { + /* on error, no reply */ + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + } else { + vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); + } + + mheim_ripc_call_reply(s->reply_port, returnvalue, + replyin, replyinCnt, + replyout, replyoutCnt); + + heim_ipc_free_cred(s->cred); + free(s->req.data); + free(s); + restart_timer(); +} + +static void +mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyinCnt = 0; + heim_ipc_message_outband_t replyout = 0; + mach_msg_type_number_t replyoutCnt = 0; + + if (returnvalue) { + /* on error, no reply */ + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + } else { + vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); + } + + mheim_aipc_acall_reply(s->reply_port, returnvalue, + replyin, replyinCnt, + replyout, replyoutCnt); + heim_ipc_free_cred(s->cred); + free(s->req.data); + free(s); + restart_timer(); +} + + +kern_return_t +mheim_do_call(mach_port_t server_port, + audit_token_t client_creds, + mach_port_t reply_port, + heim_ipc_message_inband_t requestin, + mach_msg_type_number_t requestinCnt, + heim_ipc_message_outband_t requestout, + mach_msg_type_number_t requestoutCnt, + int *returnvalue, + heim_ipc_message_inband_t replyin, + mach_msg_type_number_t *replyinCnt, + heim_ipc_message_outband_t *replyout, + mach_msg_type_number_t *replyoutCnt) +{ + heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_call_ctx *s; + kern_return_t kr; + uid_t uid; + gid_t gid; + pid_t pid; + au_asid_t session; + + *replyout = NULL; + *replyoutCnt = 0; + *replyinCnt = 0; + + s = malloc(sizeof(*s)); + if (s == NULL) + return KERN_MEMORY_FAILURE; /* XXX */ + + s->reply_port = reply_port; + + audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); + + kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); + if (kr) { + free(s); + return kr; + } + + suspend_timer(); + + if (requestinCnt) { + s->req.data = malloc(requestinCnt); + memcpy(s->req.data, requestin, requestinCnt); + s->req.length = requestinCnt; + } else { + s->req.data = malloc(requestoutCnt); + memcpy(s->req.data, requestout, requestoutCnt); + s->req.length = requestoutCnt; + } + + dispatch_async(workq, ^{ + (ctx->callback)(ctx->userctx, &s->req, s->cred, + mach_complete_sync, (heim_sipc_call)s); + }); + + return MIG_NO_REPLY; +} + +kern_return_t +mheim_do_call_request(mach_port_t server_port, + audit_token_t client_creds, + mach_port_t reply_port, + heim_ipc_message_inband_t requestin, + mach_msg_type_number_t requestinCnt, + heim_ipc_message_outband_t requestout, + mach_msg_type_number_t requestoutCnt) +{ + heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_call_ctx *s; + kern_return_t kr; + uid_t uid; + gid_t gid; + pid_t pid; + au_asid_t session; + + s = malloc(sizeof(*s)); + if (s == NULL) + return KERN_MEMORY_FAILURE; /* XXX */ + + s->reply_port = reply_port; + + audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); + + kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); + if (kr) { + free(s); + return kr; + } + + suspend_timer(); + + if (requestinCnt) { + s->req.data = malloc(requestinCnt); + memcpy(s->req.data, requestin, requestinCnt); + s->req.length = requestinCnt; + } else { + s->req.data = malloc(requestoutCnt); + memcpy(s->req.data, requestout, requestoutCnt); + s->req.length = requestoutCnt; + } + + dispatch_async(workq, ^{ + (ctx->callback)(ctx->userctx, &s->req, s->cred, + mach_complete_async, (heim_sipc_call)s); + }); + + return KERN_SUCCESS; +} + +static int +mach_init(const char *service, mach_port_t sport, heim_sipc ctx) +{ + struct mach_service *s; + char *name; + + init_globals(); + + s = calloc(1, sizeof(*s)); + if (s == NULL) + return ENOMEM; + + asprintf(&name, "heim-ipc-mach-%s", service); + + s->queue = dispatch_queue_create(name, NULL); + free(name); + s->sport = sport; + + s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, + s->sport, 0, s->queue); + if (s->source == NULL) { + dispatch_release(s->queue); + free(s); + return ENOMEM; + } + ctx->mech = s; + + dispatch_set_context(s->queue, ctx); + dispatch_set_context(s->source, s); + + dispatch_source_set_event_handler(s->source, ^{ + dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server); + }); + + dispatch_source_set_cancel_handler(s->source, ^{ + heim_sipc sctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_service *st = sctx->mech; + mach_port_mod_refs(mach_task_self(), st->sport, + MACH_PORT_RIGHT_RECEIVE, -1); + dispatch_release(st->queue); + dispatch_release(st->source); + free(st); + free(sctx); + }); + + dispatch_resume(s->source); + + return 0; +} + +static int +mach_release(heim_sipc ctx) +{ + struct mach_service *s = ctx->mech; + dispatch_source_cancel(s->source); + dispatch_release(s->source); + return 0; +} + +static mach_port_t +mach_checkin_or_register(const char *service) +{ + mach_port_t mp; + kern_return_t kr; + + kr = bootstrap_check_in(bootstrap_port, service, &mp); + if (kr == KERN_SUCCESS) + return mp; + +#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 + /* Pre SnowLeopard version */ + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); + if (kr != KERN_SUCCESS) + return MACH_PORT_NULL; + + kr = mach_port_insert_right(mach_task_self(), mp, mp, + MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + mach_port_destroy(mach_task_self(), mp); + return MACH_PORT_NULL; + } + + kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp); + if (kr != KERN_SUCCESS) { + mach_port_destroy(mach_task_self(), mp); + return MACH_PORT_NULL; + } + + return mp; +#else + return MACH_PORT_NULL; +#endif +} + + +#endif /* __APPLE__ && HAVE_GCD */ + + +int +heim_sipc_launchd_mach_init(const char *service, + heim_ipc_callback callback, + void *user, heim_sipc *ctx) +{ +#if defined(__APPLE__) && defined(HAVE_GCD) + mach_port_t sport = MACH_PORT_NULL; + heim_sipc c = NULL; + int ret; + + *ctx = NULL; + + sport = mach_checkin_or_register(service); + if (sport == MACH_PORT_NULL) { + ret = ENOENT; + goto error; + } + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = ENOMEM; + goto error; + } + c->release = mach_release; + c->userctx = user; + c->callback = callback; + + ret = mach_init(service, sport, c); + if (ret) + goto error; + + *ctx = c; + return 0; + error: + if (c) + free(c); + if (sport != MACH_PORT_NULL) + mach_port_mod_refs(mach_task_self(), sport, + MACH_PORT_RIGHT_RECEIVE, -1); + return ret; +#else /* !(__APPLE__ && HAVE_GCD) */ + *ctx = NULL; + return EINVAL; +#endif /* __APPLE__ && HAVE_GCD */ +} + +struct client { + int fd; + heim_ipc_callback callback; + void *userctx; + int flags; +#define LISTEN_SOCKET 1 +#define WAITING_READ 2 +#define WAITING_WRITE 4 +#define WAITING_CLOSE 8 + +#define HTTP_REPLY 16 +#define DOOR_FD 32 + +#define INHERIT_MASK 0xffff0000 +#define INCLUDE_ERROR_CODE (1 << 16) +#define ALLOW_HTTP (1<<17) +#define UNIX_SOCKET (1<<18) + unsigned calls; + size_t ptr, len; + uint8_t *inmsg; + size_t olen; + uint8_t *outmsg; +#ifdef HAVE_GCD + dispatch_source_t in; + dispatch_source_t out; +#endif + struct { + uid_t uid; + gid_t gid; + pid_t pid; + } unixrights; +}; + +#ifndef HAVE_GCD +static unsigned num_clients = 0; +static struct client **clients = NULL; +#endif + +static void handle_read(struct client *); +static void handle_write(struct client *); +static int maybe_close(struct client *); + +/* + * Update peer credentials from socket. + * + * SCM_CREDS can only be updated the first time there is read data to + * read from the filedescriptor, so if we read do it before this + * point, the cred data might not be is not there yet. + */ + +static int +update_client_creds(struct client *c) +{ +#ifdef HAVE_GETPEERUCRED + /* Solaris 10 */ + { + ucred_t *peercred = NULL; + + if (getpeerucred(c->fd, &peercred) == 0) { + c->unixrights.uid = ucred_geteuid(peercred); + c->unixrights.gid = ucred_getegid(peercred); + c->unixrights.pid = 0; + ucred_free(peercred); + return 1; + } + } +#endif +#ifdef HAVE_GETPEEREID + /* FreeBSD, OpenBSD */ + { + uid_t uid; + gid_t gid; + + if (getpeereid(c->fd, &uid, &gid) == 0) { + c->unixrights.uid = uid; + c->unixrights.gid = gid; + c->unixrights.pid = 0; + return 1; + } + } +#endif +#if defined(SO_PEERCRED) && defined(__linux__) + /* Linux */ + { + struct ucred pc; + socklen_t pclen = sizeof(pc); + + if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) { + c->unixrights.uid = pc.uid; + c->unixrights.gid = pc.gid; + c->unixrights.pid = pc.pid; + return 1; + } + } +#endif +#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION) + { + struct xucred peercred; + socklen_t peercredlen = sizeof(peercred); + + if (getsockopt(c->fd, LOCAL_PEERCRED, 1, + (void *)&peercred, &peercredlen) == 0 + && peercred.cr_version == XUCRED_VERSION) + { + c->unixrights.uid = peercred.cr_uid; + c->unixrights.gid = peercred.cr_gid; + c->unixrights.pid = 0; + return 1; + } + } +#endif +#if defined(SOCKCREDSIZE) && defined(SCM_CREDS) + /* NetBSD */ + if (c->unixrights.uid == (uid_t)-1) { + struct msghdr msg; + socklen_t crmsgsize; + void *crmsg; + struct cmsghdr *cmp; + struct sockcred *sc; + + memset(&msg, 0, sizeof(msg)); + crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS)); + if (crmsgsize == 0) + return 1 ; + + crmsg = malloc(crmsgsize); + if (crmsg == NULL) + goto failed_scm_creds; + + memset(crmsg, 0, crmsgsize); + + msg.msg_control = crmsg; + msg.msg_controllen = crmsgsize; + + if (recvmsg(c->fd, &msg, 0) < 0) { + free(crmsg); + goto failed_scm_creds; + } + + if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { + free(crmsg); + goto failed_scm_creds; + } + + cmp = CMSG_FIRSTHDR(&msg); + if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) { + free(crmsg); + goto failed_scm_creds; + } + + sc = (struct sockcred *)(void *)CMSG_DATA(cmp); + + c->unixrights.uid = sc->sc_euid; + c->unixrights.gid = sc->sc_egid; + c->unixrights.pid = 0; + + free(crmsg); + return 1; + } else { + /* we already got the cred, just return it */ + return 1; + } + failed_scm_creds: +#endif + return 0; +} + +static struct client * +add_new_socket(int fd, + int flags, + heim_ipc_callback callback, + void *userctx) +{ + struct client *c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return NULL; + + if (flags & LISTEN_SOCKET) { + c->fd = fd; + } else if (flags & DOOR_FD) { + c->fd = -1; /* cannot poll a door descriptor */ + } else { + c->fd = accept(fd, NULL, NULL); + if(c->fd < 0) { + free(c); + return NULL; + } + } + + c->flags = flags; + c->callback = callback; + c->userctx = userctx; + + socket_set_nonblocking(fd, 1); + +#ifdef HAVE_GCD + init_globals(); + + c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, + c->fd, 0, eventq); + c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, + c->fd, 0, eventq); + + dispatch_source_set_event_handler(c->in, ^{ + int rw = (c->flags & WAITING_WRITE); + handle_read(c); + if (rw == 0 && (c->flags & WAITING_WRITE)) + dispatch_resume(c->out); + if ((c->flags & WAITING_READ) == 0) + dispatch_suspend(c->in); + maybe_close(c); + }); + dispatch_source_set_event_handler(c->out, ^{ + handle_write(c); + if ((c->flags & WAITING_WRITE) == 0) { + dispatch_suspend(c->out); + } + maybe_close(c); + }); + + dispatch_resume(c->in); +#else + clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1)); + clients[num_clients] = c; + num_clients++; +#endif + + return c; +} + +static int +maybe_close(struct client *c) +{ + if (c->calls != 0) + return 0; + if (c->flags & (WAITING_READ|WAITING_WRITE)) + return 0; + +#ifdef HAVE_GCD + dispatch_source_cancel(c->in); + if ((c->flags & WAITING_READ) == 0) + dispatch_resume(c->in); + dispatch_release(c->in); + + dispatch_source_cancel(c->out); + if ((c->flags & WAITING_WRITE) == 0) + dispatch_resume(c->out); + dispatch_release(c->out); +#endif + close(c->fd); /* ref count fd close */ + free(c->inmsg); + free(c); + return 1; +} + + +struct socket_call { + heim_idata in; + struct client *c; + heim_icred cred; +}; + +static void +output_data(struct client *c, const void *data, size_t len) +{ + if (c->olen + len < c->olen) + abort(); + c->outmsg = erealloc(c->outmsg, c->olen + len); + memcpy(&c->outmsg[c->olen], data, len); + c->olen += len; + c->flags |= WAITING_WRITE; +} + +static void +socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + struct socket_call *sc = (struct socket_call *)ctx; + struct client *c = sc->c; + + /* double complete ? */ + if (c == NULL) + abort(); + + if ((c->flags & WAITING_CLOSE) == 0) { + uint32_t u32; + + /* length */ + u32 = htonl(reply->length); + output_data(c, &u32, sizeof(u32)); + + /* return value */ + if (c->flags & INCLUDE_ERROR_CODE) { + u32 = htonl(returnvalue); + output_data(c, &u32, sizeof(u32)); + } + + /* data */ + output_data(c, reply->data, reply->length); + + /* if HTTP, close connection */ + if (c->flags & HTTP_REPLY) { + c->flags |= WAITING_CLOSE; + c->flags &= ~WAITING_READ; + } + } + + c->calls--; + if (sc->cred) + heim_ipc_free_cred(sc->cred); + free(sc->in.data); + sc->c = NULL; /* so we can catch double complete */ + free(sc); + + maybe_close(c); +} + +/* remove HTTP %-quoting from buf */ +static int +de_http(char *buf) +{ + unsigned char *p, *q; + for(p = q = (unsigned char *)buf; *p; p++, q++) { + if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) { + unsigned int x; + if(sscanf((char *)p + 1, "%2x", &x) != 1) + return -1; + *q = x; + p += 2; + } else + *q = *p; + } + *q = '\0'; + return 0; +} + +static struct socket_call * +handle_http_tcp(struct client *c) +{ + struct socket_call *cs; + char *s, *p, *t; + void *data; + char *proto; + int len; + + s = (char *)c->inmsg; + + p = strstr(s, "\r\n"); + if (p == NULL) + return NULL; + + *p = 0; + + p = NULL; + t = strtok_r(s, " \t", &p); + if (t == NULL) + return NULL; + + t = strtok_r(NULL, " \t", &p); + if (t == NULL) + return NULL; + + data = malloc(strlen(t)); + if (data == NULL) + return NULL; + + if(*t == '/') + t++; + if(de_http(t) != 0) { + free(data); + return NULL; + } + proto = strtok_r(NULL, " \t", &p); + if (proto == NULL) { + free(data); + return NULL; + } + len = rk_base64_decode(t, data); + if(len <= 0){ + const char *msg = + " 404 Not found\r\n" + "Server: Heimdal/" VERSION "\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "Content-type: text/html\r\n" + "Content-transfer-encoding: 8bit\r\n\r\n" + "404 Not found\r\n" + "

404 Not found

\r\n" + "That page doesn't exist, maybe you are looking for " + "Heimdal?\r\n"; + free(data); + output_data(c, proto, strlen(proto)); + output_data(c, msg, strlen(msg)); + return NULL; + } + + cs = emalloc(sizeof(*cs)); + cs->c = c; + cs->in.data = data; + cs->in.length = len; + c->ptr = 0; + + { + const char *msg = + " 200 OK\r\n" + "Server: Heimdal/" VERSION "\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "Content-type: application/octet-stream\r\n" + "Content-transfer-encoding: binary\r\n\r\n"; + output_data(c, proto, strlen(proto)); + output_data(c, msg, strlen(msg)); + } + + return cs; +} + + +static void +handle_read(struct client *c) +{ + ssize_t len; + uint32_t dlen; + + assert((c->flags & DOOR_FD) == 0); + + if (c->flags & LISTEN_SOCKET) { + add_new_socket(c->fd, + WAITING_READ | (c->flags & INHERIT_MASK), + c->callback, + c->userctx); + return; + } + + if (c->ptr - c->len < 1024) { + c->inmsg = erealloc(c->inmsg, + c->len + 1024); + c->len += 1024; + } + + len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr); + if (len <= 0) { + c->flags |= WAITING_CLOSE; + c->flags &= ~WAITING_READ; + return; + } + c->ptr += len; + if (c->ptr > c->len) + abort(); + + while (c->ptr >= sizeof(dlen)) { + struct socket_call *cs; + + if((c->flags & ALLOW_HTTP) && c->ptr >= 4 && + strncmp((char *)c->inmsg, "GET ", 4) == 0 && + strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) { + + /* remove the trailing \r\n\r\n so the string is NUL terminated */ + c->inmsg[c->ptr - 4] = '\0'; + + c->flags |= HTTP_REPLY; + + cs = handle_http_tcp(c); + if (cs == NULL) { + c->flags |= WAITING_CLOSE; + c->flags &= ~WAITING_READ; + break; + } + } else { + memcpy(&dlen, c->inmsg, sizeof(dlen)); + dlen = ntohl(dlen); + + if (dlen > MAX_PACKET_SIZE) { + c->flags |= WAITING_CLOSE; + c->flags &= ~WAITING_READ; + return; + } + if (dlen > c->ptr - sizeof(dlen)) { + break; + } + + cs = emalloc(sizeof(*cs)); + cs->c = c; + cs->in.data = emalloc(dlen); + memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen); + cs->in.length = dlen; + cs->cred = NULL; + + c->ptr -= sizeof(dlen) + dlen; + memmove(c->inmsg, + c->inmsg + sizeof(dlen) + dlen, + c->ptr); + } + + c->calls++; + + if ((c->flags & UNIX_SOCKET) != 0) { + if (update_client_creds(c)) + _heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid, + c->unixrights.pid, -1, &cs->cred); + } + + c->callback(c->userctx, &cs->in, + cs->cred, socket_complete, + (heim_sipc_call)cs); + } +} + +static void +handle_write(struct client *c) +{ + ssize_t len; + + len = write(c->fd, c->outmsg, c->olen); + if (len <= 0) { + c->flags |= WAITING_CLOSE; + c->flags &= ~(WAITING_WRITE); + } else if (c->olen != (size_t)len) { + memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len); + c->olen -= len; + } else { + c->olen = 0; + free(c->outmsg); + c->outmsg = NULL; + c->flags &= ~(WAITING_WRITE); + } +} + + +#ifndef HAVE_GCD + +static void +process_loop(void) +{ + struct pollfd *fds; + unsigned n; + unsigned num_fds; + + while (num_clients > 0) { + + fds = malloc(num_clients * sizeof(fds[0])); + if(fds == NULL) + abort(); + + num_fds = num_clients; + + for (n = 0 ; n < num_fds; n++) { + fds[n].fd = clients[n]->fd; + fds[n].events = 0; + if (clients[n]->flags & WAITING_READ) + fds[n].events |= POLLIN; + if (clients[n]->flags & WAITING_WRITE) + fds[n].events |= POLLOUT; + + fds[n].revents = 0; + } + + while (poll(fds, num_fds, -1) == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + err(1, "poll(2) failed"); + } + + for (n = 0 ; n < num_fds; n++) { + if (clients[n] == NULL) + continue; + if (fds[n].revents & POLLIN) + handle_read(clients[n]); + if (fds[n].revents & POLLOUT) + handle_write(clients[n]); + if (fds[n].revents & POLLERR) + clients[n]->flags |= WAITING_CLOSE; + } + + n = 0; + while (n < num_clients) { + struct client *c = clients[n]; + if (maybe_close(c)) { + if (n < num_clients - 1) + clients[n] = clients[num_clients - 1]; + num_clients--; + } else + n++; + } + + free(fds); + } +} + +#endif + +static int +socket_release(heim_sipc ctx) +{ + struct client *c = ctx->mech; + c->flags |= WAITING_CLOSE; + return 0; +} + +int +heim_sipc_stream_listener(int fd, int type, + heim_ipc_callback callback, + void *user, heim_sipc *ctx) +{ + heim_sipc ct; + struct client *c; + + if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP))) + return EINVAL; + + ct = calloc(1, sizeof(*ct)); + if (ct == NULL) + return ENOMEM; + + switch (type) { + case HEIM_SIPC_TYPE_IPC: + c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user); + break; + case HEIM_SIPC_TYPE_UINT32: + c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user); + break; + case HEIM_SIPC_TYPE_HTTP: + case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP: + c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user); + break; + default: + free(ct); + return EINVAL; + } + + ct->mech = c; + ct->release = socket_release; + + c->unixrights.uid = (uid_t) -1; + c->unixrights.gid = (gid_t) -1; + c->unixrights.pid = (pid_t) 0; + + *ctx = ct; + return 0; +} + +int +heim_sipc_service_unix(const char *service, + heim_ipc_callback callback, + void *user, heim_sipc *ctx) +{ + struct sockaddr_un un; + const char *d = secure_getenv("HEIM_IPC_DIR"); + int fd, ret; + + if (strncasecmp(service, "UNIX:", sizeof("UNIX:") - 1) == 0) + service += sizeof("UNIX:") - 1; + + un.sun_family = AF_UNIX; + + if (snprintf(un.sun_path, sizeof(un.sun_path), + "%s/.heim_%s-socket", d ? d : _PATH_VARRUN, + service) > sizeof(un.sun_path) + sizeof("-s") - 1) + return ENAMETOOLONG; + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return errno; + + socket_set_reuseaddr(fd, 1); +#ifdef LOCAL_CREDS + { + int one = 1; + (void) setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); + } +#endif + + unlink(un.sun_path); + + if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) { + close(fd); + return errno; + } + + if (listen(fd, SOMAXCONN) < 0) { + close(fd); + return errno; + } + + (void) chmod(un.sun_path, 0666); + + ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC, + callback, user, ctx); + if (ret == 0) { + struct client *c = (*ctx)->mech; + c->flags |= UNIX_SOCKET; + } + + return ret; +} + +#ifdef HAVE_DOOR_CREATE +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "heim_threads.h" + +static HEIMDAL_thread_key door_key; + +struct door_call { + heim_idata in; + door_desc_t *dp; + heim_icred cred; +}; + +struct door_reply { + int returnvalue; + size_t length; + unsigned char data[1]; +}; + +static int +door_release(heim_sipc ctx) +{ + struct client *c = ctx->mech; + return 0; +} + +static void +door_reply_destroy(void *data) +{ + free(data); +} + +static void +door_key_create(void *key) +{ + int ret; + + HEIMDAL_key_create((HEIMDAL_thread_key *)key, door_reply_destroy, ret); +} + +static void +door_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; + struct door_call *cs = (struct door_call *)ctx; + size_t rlen; + struct door_reply *r = NULL; + union { + struct door_reply reply; + char buffer[offsetof(struct door_reply, data) + BUFSIZ]; + } replyBuf; + + heim_base_once_f(&once, &door_key, door_key_create); + + /* door_return() doesn't return; don't leak cred */ + heim_ipc_free_cred(cs->cred); + +error_reply: + rlen = offsetof(struct door_reply, data); + if (returnvalue == 0) + rlen += reply->length; + + /* long replies (> BUFSIZ) are allocated from the heap */ + if (rlen > BUFSIZ) { + int ret; + + /* door_return() doesn't return, so stash reply buffer in TLS */ + r = realloc(HEIMDAL_getspecific(door_key), rlen); + if (r == NULL) { + returnvalue = EAGAIN; /* don't leak ENOMEM to caller */ + goto error_reply; + } + + HEIMDAL_setspecific(door_key, r, ret); + } else { + r = &replyBuf.reply; + } + + r->returnvalue = returnvalue; + if (r->returnvalue == 0) { + r->length = reply->length; + memcpy(r->data, reply->data, reply->length); + } else { + r->length = 0; + } + + door_return((char *)r, rlen, NULL, 0); +} + +static void +door_callback(void *cookie, + char *argp, + size_t arg_size, + door_desc_t *dp, + uint_t n_desc) +{ + heim_sipc c = (heim_sipc)cookie; + struct door_call cs = { 0 }; + ucred_t *peercred = NULL; + + if (door_ucred(&peercred) < 0) + return; + + _heim_ipc_create_cred(ucred_geteuid(peercred), + ucred_getegid(peercred), + ucred_getpid(peercred), + -1, + &cs.cred); + ucred_free(peercred); + + cs.dp = dp; + cs.in.data = argp; + cs.in.length = arg_size; + + c->callback(c->userctx, &cs.in, cs.cred, door_complete, (heim_sipc_call)&cs); +} + +int +heim_sipc_service_door(const char *service, + heim_ipc_callback callback, + void *user, heim_sipc *ctx) +{ + char path[PATH_MAX]; + int fd = -1, dfd = -1, ret; + heim_sipc ct = NULL; + struct client *c = NULL; + + ct = calloc(1, sizeof(*ct)); + if (ct == NULL) { + ret = ENOMEM; + goto cleanup; + } + ct->release = door_release; + ct->userctx = user; + ct->callback = callback; + + if (snprintf(path, sizeof(path), "/var/run/.heim_%s-door", + service) >= sizeof(path) + sizeof("-d") - 1) { + ret = ENAMETOOLONG; + goto cleanup; + } + fd = door_create(door_callback, ct, DOOR_REFUSE_DESC | DOOR_NO_CANCEL); + if (fd < 0) { + ret = errno; + goto cleanup; + } + + fdetach(path); + dfd = open(path, O_RDWR | O_CREAT, 0666); + if (dfd < 0) { + ret = errno; + goto cleanup; + } + (void) fchmod(dfd, 0666); /* XXX */ + + if (fattach(fd, path) < 0) { + ret = errno; + goto cleanup; + } + + c = add_new_socket(fd, DOOR_FD, callback, user); + ct->mech = c; + + *ctx = ct; + ret = 0; + +cleanup: + if (ret != 0) { + free(ct); + free(c); + if (fd != -1) + close(fd); + } + if (dfd != -1) + close(dfd); + + return ret; +} +#endif /* HAVE_DOOR_CREATE */ + +/** + * Set the idle timeout value + + * The timeout event handler is triggered recurrently every idle + * period `t'. The default action is rather draconian and just calls + * exit(0), so you might want to change this to something more + * graceful using heim_sipc_set_timeout_handler(). + */ + +void +heim_sipc_timeout(time_t t) +{ +#ifdef HAVE_GCD + static dispatch_once_t timeoutonce; + init_globals(); + dispatch_sync(timerq, ^{ + timeoutvalue = t; + set_timer(); + }); + dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); }); +#else + abort(); +#endif +} + +/** + * Set the timeout event handler + * + * Replaces the default idle timeout action. + */ + +void +heim_sipc_set_timeout_handler(void (*func)(void)) +{ +#ifdef HAVE_GCD + init_globals(); + dispatch_sync(timerq, ^{ timer_ev = func; }); +#else + abort(); +#endif +} + + +void +heim_sipc_free_context(heim_sipc ctx) +{ + (ctx->release)(ctx); +} + +void +heim_ipc_main(void) +{ +#ifdef HAVE_GCD + dispatch_main(); +#else + process_loop(); +#endif +} diff --git a/third_party/heimdal/lib/ipc/tc.c b/third_party/heimdal/lib/ipc/tc.c new file mode 100644 index 0000000..e366f17 --- /dev/null +++ b/third_party/heimdal/lib/ipc/tc.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static int help_flag; +static int version_flag; + +static struct getargs args[] = { + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, ""); + exit (ret); +} + +static void +reply(void *ctx, int errorcode, heim_idata *rep, heim_icred cred) +{ + printf("got reply errorcode %d, rep %.*s\n", errorcode, + rep->length < INT_MAX ? (int)rep->length : INT_MAX, + (char *)rep->data); + heim_ipc_semaphore_signal((heim_isemaphore)ctx); /* tell caller we are done */ +} + +static void +test_ipc(const char *service) +{ + heim_isemaphore s; + heim_idata req, rep; + heim_ipc ipc; + int ret; + char buf[128]; + + snprintf(buf, sizeof(buf), "testing heim IPC via %s", service); + + printf("%s\n", buf); + + ret = heim_ipc_init_context(service, &ipc); + if (ret) + errx(1, "heim_ipc_init_context: %d", ret); + + req.length = strlen(buf); + req.data = buf; + + ret = heim_ipc_call(ipc, &req, &rep, NULL); + if (ret) + errx(1, "heim_ipc_call: %d", ret); + + s = heim_ipc_semaphore_create(0); + if (s == NULL) + errx(1, "heim_ipc_semaphore_create"); + + ret = heim_ipc_async(ipc, &req, s, reply); + if (ret) + errx(1, "heim_ipc_async: %d", ret); + + heim_ipc_semaphore_wait(s, HEIM_IPC_WAIT_FOREVER); /* wait for reply to complete the work */ + + heim_ipc_free_context(ipc); +} + + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage(0); + + if (version_flag) { + print_version(NULL); + exit(0); + } + +#ifdef __APPLE__ + test_ipc("MACH:org.h5l.test-ipc"); +#endif + test_ipc("ANY:org.h5l.test-ipc"); + test_ipc("UNIX:org.h5l.test-ipc"); +#ifdef HAVE_DOOR_CREATE + test_ipc("DOOR:org.h5l.test-ipc"); +#endif + + return 0; +} diff --git a/third_party/heimdal/lib/ipc/ts-http.c b/third_party/heimdal/lib/ipc/ts-http.c new file mode 100644 index 0000000..c3c3ce5 --- /dev/null +++ b/third_party/heimdal/lib/ipc/ts-http.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +static int help_flag; +static int version_flag; + +static struct getargs args[] = { + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, ""); + exit (ret); +} + +static void +test_service(void *ctx, const heim_idata *req, + const heim_icred cred, + heim_ipc_complete complete, + heim_sipc_call cctx) +{ + heim_idata rep; + printf("got request\n"); + rep.length = 3; + rep.data = strdup("hej"); + (*complete)(cctx, 0, &rep); +} + + +static void +setup_sockets(void) +{ + struct addrinfo hints, *res, *res0; + int ret, s; + heim_sipc u; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + ret = getaddrinfo(NULL, "8080", &hints, &res0); + if (ret) + errx(1, "%s", gai_strerror(ret)); + + for (res = res0; res ; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s < 0) { + warn("socket"); + continue; + } + socket_set_reuseaddr(s, 1); + socket_set_ipv6only(s, 1); + + if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { + warn("bind"); + close(s); + continue; + } + listen(s, 5); + ret = heim_sipc_stream_listener(s, HEIM_SIPC_TYPE_HTTP, + test_service, NULL, &u); + if (ret) + errx(1, "heim_sipc_stream_listener: %d", ret); + } + freeaddrinfo(res0); +} + + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage(0); + + if (version_flag) { + print_version(NULL); + exit(0); + } + + setup_sockets(); + + heim_ipc_main(); + + return 0; +} diff --git a/third_party/heimdal/lib/ipc/ts.c b/third_party/heimdal/lib/ipc/ts.c new file mode 100644 index 0000000..3ba5d65 --- /dev/null +++ b/third_party/heimdal/lib/ipc/ts.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +static int help_flag; +static int version_flag; + +static struct getargs args[] = { + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, ""); + exit (ret); +} + +static void +test_service(void *ctx, const heim_idata *req, + const heim_icred cred, + heim_ipc_complete complete, + heim_sipc_call cctx) +{ + heim_idata rep; + char buf[128]; + + printf("got request via %s\n", (const char *)ctx); + snprintf(buf, sizeof(buf), "Hello back via %s\n", (const char *)ctx); + rep.data = buf; + rep.length = strlen(buf); + (*complete)(cctx, 0, &rep); +} + + +int +main(int argc, char **argv) +{ + heim_sipc u; + int optidx = 0; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage(0); + + if (version_flag) { + print_version(NULL); + exit(0); + } + +#if __APPLE__ + { + heim_sipc mach; + heim_sipc_launchd_mach_init("org.h5l.test-ipc", + test_service, "MACH", &mach); + } +#endif + heim_sipc_service_unix("org.h5l.test-ipc", + test_service, "UNIX", &u); +#ifdef HAVE_DOOR_CREATE + { + heim_sipc door; + heim_sipc_service_door("org.h5l.test-ipc", + test_service, "DOOR", &door); + } +#endif + heim_ipc_main(); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/ChangeLog b/third_party/heimdal/lib/kadm5/ChangeLog new file mode 100644 index 0000000..5016827 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ChangeLog @@ -0,0 +1,1389 @@ +2008-04-23 Love Hörnquist Åstrand + + * ipropd_master.c: Only log "sending AYT" once, pointed out by Dr + A V Le Blanc. + + +2008-01-21 Love Hörnquist Åstrand + + * default_keys.c: Use hdb_free_keys(). + +2008-01-11 Love Hörnquist Åstrand + + * Makefile.am: add check-cracklib.pl, flush.c, + sample_passwd_check.c + +2007-12-07 Love Hörnquist Åstrand + + * use hdb_db_dir() and hdb_default_db() + +2007-10-18 Love + + * init_c.c: We are getting default_client, not client. this way + the user can override the result. + +2007-09-29 Love Hörnquist Åstrand + + * iprop.8: fix spelling, From Antoine Jacoutt. + +2007-08-16 Love Hörnquist Åstrand + + * version-script.map: export _kadm5_unmarshal_params, + _kadm5_acl_check_permission + + * version-script.map: export kadm5_log_ symbols. + + * log.c: Unexport the specific log replay operations. + +2007-08-10 Love Hörnquist Åstrand + + * Makefile.am: build sample_passwd_check.la as part of noinst. + + * sample_passwd_check.c: Add missing prototype for check_length(). + +2007-08-07 Love Hörnquist Åstrand + + * log.c: Sprinkle krb5_set_error_string(). + + * ipropd_slave.c: Provide better error why kadm5_log_replay + failed. + +2007-08-06 Love Hörnquist Åstrand + + * ipropd_master.c: - don't push whole database to the new client + every time. - make slaves get the whole new database if they have + a newer log the the master (and thus have them go back in time). + +2007-08-03 Love Hörnquist Åstrand + + * ipropd_slave.c: make more sane. + + * ipropd_slave.c: more paranoid check that the log entires are + self consistant + + * log.c (kadm5_log_foreach): check that the postamble contains the + right data. + + * ipropd_master.c: Sprinkle more info about what versions the + master thinks about the client versions. + + * ipropd_master.c: Start the server at the current version, not 0. + +2007-08-02 Love Hörnquist Åstrand + + * ipropd_master.c: Add more logging, to figure out what is + happening in the master. + +2007-08-01 Love Hörnquist Åstrand + + * Makefile.am: add version-script for libkadm5srv.la + + * version-script.map: version script fro kadm5 server libary. + + * log.c: only free the orignal entries extentions if there was + any. Bug reported by Peter Meinecke. + + * add configuration for signal file and acl file, let user select + hostname, catch signals and print why we are quiting, make nop + cause one new version, not two + +2007-07-30 Love Hörnquist Åstrand + + * ipropd_master.c (send_diffs): make current slave's version + uptodate when diff have been sent. + +2007-07-27 Love Hörnquist Åstrand + + * ipropd_slave.c: More comments and some more error checking. + +2007-07-26 Love Hörnquist Åstrand + + * init_c.c (get_cache_principal): make sure id is reset if we + fail. From Benjamin Bennet. + +2007-07-10 Love Hörnquist Åstrand + + * context_s.c (find_db_spec): match realm-less as the default + realm. + + * Makefile.am: New library version. + +2007-07-05 Love Hörnquist Åstrand + + * context_s.c: Use hdb_get_dbinfo to pick up configuration. + ctx->config.realm can be NULL, check for that, from Bjorn S. + +2007-07-04 Love Hörnquist Åstrand + + * init_c.c: Try harder to use the right principal. + +2007-06-20 Love Hörnquist Åstrand + + * ipropd_slave.c: Catch return value from krb5_program_setup. From + Steven Luo. + +2007-05-08 Love Hörnquist Åstrand + + * delete_s.c: Write log entry after store is successful, rename + out goto statments. + + * randkey_s.c: Write log entry after store is successful. + + * modify_s.c: Write log entry after store is successful. + + * rename_s.c: indent. + + * chpass_s.c: Write log entry after store is successful. + + * create_s.c: Write log entry after store is successful. + +2007-05-07 Love Hörnquist Åstrand + + * iprop-commands.in: Add default values to make this working + again. + + * iprop-log.c (iprop_replay): create the database with more + liberal mode. + + * log.c: make it slightly more working. + + * iprop-log.8: Document last-version. + + * iprop-log.c: (last_version): print last version of the log. + + * iprop-commands.in: new command last-version: print last version + of the log. + + * log.c (kadm5_log_previous): document assumptions and make less + broken. Bug report from Ronny Blomme. + +2007-02-17 Love Hörnquist Åstrand + + * admin.h: add support to get aliases + + * get_s.c: add support to get aliases + +2007-02-11 David Love + + * iprop-log.8: Small fixes, from David Love. + +2006-12-15 Love Hörnquist Åstrand + + * init_c.c: if the user have a kadmin/admin initial ticket, don't + ask for password, just use the credential instead. + +2006-12-06 Love Hörnquist Åstrand + + * ipropd_master.c: Use strcspn to remove \n from string returned + by fgets. From Björn Sandell + +2006-11-30 Love Hörnquist Åstrand + + * init_c.c (kadm_connect): clear error string before trying to + print a errno, this way we don't pick up a random failure code + +2006-11-20 Love Hörnquist Åstrand + + * ipropd_slave.c: Make krb5_get_init_creds_opt_free take a context + argument. + + * init_c.c: Make krb5_get_init_creds_opt_free take a context + argument. + +2006-10-22 Love Hörnquist Åstrand + + * ent_setup.c: Try to not leak memory. + +2006-10-07 Love Hörnquist Åstrand + + * Makefile.am: split build files into dist_ and noinst_ SOURCES + +2006-08-24 Love Hörnquist Åstrand + + * get_s.c: Add KRB5_KDB_ALLOW_DIGEST + + * ent_setup.c: Add KRB5_KDB_ALLOW_DIGEST + + * admin.h: Add KRB5_KDB_ALLOW_DIGEST + +2006-06-16 Love Hörnquist Åstrand + + * check-cracklib.pl: Add password reuse checking. From Harald + Barth. + +2006-06-14 Love Hörnquist Åstrand + + * ent_setup.c (attr_to_flags): Add KRB5_KDB_ALLOW_KERBEROS4 + + * get_s.c (kadm5_s_get_principal): Add KRB5_KDB_ALLOW_KERBEROS4 + + * admin.h: Add KRB5_KDB_ALLOW_KERBEROS4 + +2006-06-06 Love Hörnquist Åstrand + + * ent_setup.c (attr_to_flags): Add KRB5_KDB_TRUSTED_FOR_DELEGATION + +2006-05-30 Love Hörnquist Åstrand + + * password_quality.c (kadm5_check_password_quality): set error + message in context. + +2006-05-13 Love Hörnquist Åstrand + + * iprop-log.c: Avoid shadowing. + + * rename_s.c: Avoid shadowing. + +2006-05-08 Love Hörnquist Åstrand + + * privs_c.c (kadm5_c_get_privs): privs is a uint32_t, let copy it + that way. + +2006-05-05 Love Hörnquist Åstrand + + * Rename u_intXX_t to uintXX_t + +2006-04-27 Love Hörnquist Åstrand + + * chpass_s.c,delete_s.c,get_s.c,log.c,modify_s.c,randkey_s.c,rename_s.c: + Pass in HDB_F_GET_ANY to all ->hdb fetch to hint what entries we are looking for + + * send_recv.c: set and clear error string + + * rename_s.c: Break out the that we request from principal from + the entry and pass it in as a separate argument. + + * randkey_s.c: Break out the that we request from principal from + the entry and pass it in as a separate argument. + + * modify_s.c: Break out the that we request from principal from + the entry and pass it in as a separate argument. + + * log.c: Break out the that we request from principal from the + entry and pass it in as a separate argument. + + * get_s.c: Break out the that we request from principal from the + entry and pass it in as a separate argument. + + * delete_s.c: Break out the that we request from principal from + the entry and pass it in as a separate argument. + + * chpass_s.c: Break out the that we request from principal from + the entry and pass it in as a separate argument. + +2006-04-25 Love Hörnquist Åstrand + + * create_s.c (create_principal*): If client doesn't send kvno, + make sure to set it to 1. + +2006-04-10 Love Hörnquist Åstrand + + * log.c: (kadm5_log_rename): handle errors better + Fixes Coverity, NetBSD CID#628 + + * log.c (kadm5_log_delete): add error handling Coverity, NetBSD + CID#626 + (kadm5_log_modify): add error handling Coverity, NetBSD CID#627 + + * init_c.c (_kadm5_c_get_cred_cache): handle ccache case better in + case no client name was passed in. Coverity, NetBSD CID#919 + + * init_c.c (_kadm5_c_get_cred_cache): Free client principal in + case of error. Coverity NetBSD CID#1908 + +2006-02-02 Love Hörnquist Åstrand + + * kadm5_err.et: (PASS_REUSE): Spelling, + from Václav H?la + +2006-01-25 Love Hörnquist Åstrand + + * send_recv.c: Clear error-string when introducing new errors. + + * *_c.c: Clear error-string when introducing new errors. + +2006-01-15 Love Hörnquist Åstrand + + * Makefile.am (libkadm5clnt.la) doesn't depend on libhdb, remove + dependency + +2005-12-13 Love Hörnquist Åstrand + + * memset hdb_entry_ex before use + +2005-12-12 Love Hörnquist Åstrand + + * Wrap hdb_entry with hdb_entry_ex, patch originally + from Andrew Bartlet + +2005-11-30 Love Hörnquist Åstrand + + * context_s.c (set_field): try another way to calculate the path + to the database/logfile/signal-socket + + * log.c (kadm5_log_init): set error string on failures + +2005-09-08 Love Hörnquist Åstrand + + * Constify password. + + * admin.h: Add KRB5_TL_PKINIT_ACL. + + * marshall.c (_kadm5_unmarshal_params): avoid signed-ness warnings + + * get_s.c (kadm5_s_get_principal): clear error string + +2005-08-25 Love Hörnquist Åstrand + + * iprop-log.8: More text about iprop-log. + +2005-08-24 Love Hörnquist Åstrand + + * iprop.8: SEE ALSO iprop-log. + + * Makefile.am: man_MANS += iprop-log.8 + + * iprop-log.8: Basic for documentation of iprop-log. + + * remove replay_log.c, dump_log.c, and truncate_log.c, folded into + iprop-log. + + * log.c (kadm5_log_foreach): add a context variable and pass it + down to `func´. + + * iprop-commands.in: Move truncate_log and replay_log into + iprop-log. + + * iprop-log.c: Move truncate_log and replay_log into iprop-log. + + * Makefile.am: Move truncate_log and replay_log into iprop-log. + + * Makefile.am: Make this work with a clean directory. + + * ipropd_master.c: Make compile. + + * ipropd_master.c: Update to new signature of kadm5_log_previous. + + * log.c (kadm5_log_previous): catch errors instead of asserting + and set error string. + + * iprop-commands.in: New program iprop-log that incorperates + dump_log as a subcommand, truncate_log and replay_log soon to come + after. + + * iprop-log.c: New program iprop-log that incorperates dump_log as + a subcommand, truncate_log and replay_log soon to come after. + + * Makefile.am: New program iprop-log that incorperates dump_log as + a subcommand, truncate_log and replay_log soon to come after. + +2005-08-11 Love Hörnquist Åstrand + + * get_s.c: Implement KADM5_LAST_PWD_CHANGE. + + * set_keys.c: Set and clear password where appropriate. + + * randkey_s.c: Operation modifies tl_data. + + * log.c (kadm5_log_replay_modify): Check return values of + malloc(), replace all extensions. + + * kadm5_err.et: Make BAD_TL_TYPE error more helpful. + + * get_s.c: Expose KADM5_TL_DATA options to the client. + + * ent_setup.c: Merge in KADM5_TL_DATA in the database. + + * chpass_s.c: Operations modify extensions, mark that with + TL_DATA. + + * admin.h: Add more TL types (password and extension). + +2005-06-17 Love Hörnquist Åstrand + + * constify + + * ipropd_slave.c: avoid shadowing + + * ipropd_master.c: rename local variable slave to s, optind -> + optidx + + * get_princs_c.c: rename variable exp to expression + + * ad.c: rename variable exp to expression + + * log.c: rename shadowing len to num + + * get_princs_s.c: rename variable exp to expression + + * context_s.c: const poison + + * common_glue.c: rename variable exp to expression + +2005-05-30 Love Hörnquist Åstrand + + * ent_setup.c (attr_to_flags): check for KRB5_KDB_OK_AS_DELEGATE + + * get_s.c (kadm5_s_get_principal): set KRB5_KDB_OK_AS_DELEGATE + + * admin.h: add KRB5_KDB_OK_AS_DELEGATE, sync KRB5_TL_ flags + +2005-05-25 Love Hörnquist Åstrand + + * kadm5_pwcheck.3: please mdoclint + +2005-05-25 Dave Love + + * kadm5_pwcheck.3: document kadm5_add_passwd_quality_verifier, + improve text + +2005-05-24 Dave Love + + * iprop.8: Added some info about defaults, fixed some markup. + +2005-05-23 Dave Love + + * ipropd_slave.c: Don't test HAVE_DAEMON since roken supplies it. + + * ipropd_master.c: Don't test HAVE_DAEMON since roken supplies it. + +2005-05-13 Love Hörnquist Åstrand + + * init_c.c (_kadm5_c_init_context): fix memory leak in case of + failure + +2005-05-09 Dave Love + + * password_quality.c (find_func): Fix off-by-one and logic error. + (external_passwd_quality): Improve messages. + + * test_pw_quality.c (main): Call kadm5_setup_passwd_quality_check + and kadm5_add_passwd_quality_verifier. + +2005-04-30 Love Hörnquist Åstrand + + * default_keys.c: #include , only print salt it its longer + then 0, use krb5_err instead of errx where appropriate + +2005-04-25 Love Hörnquist Åstrand + + * ipropd_slave.c: add the documented option --port + + * ipropd_master.c: add the documented option --port + + * dump_log.c: use the newly generated units function + +2005-04-24 Love Hörnquist Åstrand + + * dump_log.c: use strlcpy + + * password_quality.c: don't use sizeof(pointer) + +2005-04-15 Love Hörnquist Åstrand + + * check-cracklib.pl: external password verifier sample + + * password_quality.c (kadm5_add_passwd_quality_verifier): if NULL + is passed in, load defaults + +2005-04-14 Love Hörnquist Åstrand + + * password_quality.c: add an end tag to the external password + quality check protocol + +2005-04-13 Love Hörnquist Åstrand + + * password_quality.c: add external passsword quality check builtin + module + + [password_quality] + policies = external-check + external-program = /bin/false + + To approve password a, make the test program return APPROVED on + stderr and fail with exit code 0. + +2004-10-12 Love Hörnquist Åstrand + + * Makefile.am: bump version to 7:7:0 and 6:5:2 + + * default_keys.c (parse_file): use hdb_generate_key_set + + * keys.c,set_keys.c: Move keyset parsing and password based keyset + generation into hdb. Requested by Andrew Bartlett + for hdb-ldb backend. + +2004-09-23 Johan Danielsson + + * ipropd_master.c: add help strings to some options + +2004-09-12 Love Hörnquist Åstrand + + * chpass_s.c: deal with changed prototype for _kadm5_free_keys + + * keys.c (_kadm5_free_keys): change prototype, make it use + krb5_context instead of a kadm5_server_context + + * set_keys.c (parse_key_set): do way with static returning + (function) static variable and returned allocated memory + (_kadm5_generate_key_set): free enctypes returned by parse_key_set + +2004-09-06 Love Hörnquist Åstrand + + * set_keys.c: Fix memory leak, don't return stack variables From + Andrew Bartlett + + * set_keys.c: make all_etypes const and move outside function to + avoid returning data on stack + +2004-08-26 Love Hörnquist Åstrand + + * acl.c (fetch_acl): use " \t\n" instead of just "\n" for the + delim of the third element, this is so we can match + "foo@REALMall*@REALM", before it just matched + "foo@REALMall*@REALM", but that is kind of lucky since + what really happen was that the last was stamped out, and + the it never strtok_r never needed to parse over it. + +2004-08-25 Love Hörnquist Åstrand + + * set_keys.c (_kadm5_generate_key_set): since arcfour-hmac-md5 is + without salting, some people tries to add the string + "arcfour-hmac-md5" when they really should have used + "arcfour-hmac-md5:pw-salt", help them and add glue for that + +2004-08-18 Johan Danielsson + + * ipropd_slave.c: add --detach + +2004-07-06 Love Hörnquist Åstrand + + * ad.c: use new tsasl interface remove debug printf add upn to + computer-accounts + +2004-06-28 Love Hörnquist Åstrand + + * ad.c: implement kadm5_ad_init_with_password_ctx set more error + strings + +2004-06-21 Love Hörnquist Åstrand + + * Makefile.am: man_MANS = kadm5_pwcheck.3 + + * kadm5_pwcheck.3: document new password quality api + + * password_quality.c: new password check interface (old still + supported) + + * kadm5-pwcheck.h: new password check interface + +2004-06-08 Love Hörnquist Åstrand + + * ipropd_master.c (main): process all slaves, not just up to the + last slave sending data + (bug report from Björn Sandell ) + (*): only send one ARE_YOU_THERE + +2004-06-02 Love Hörnquist Åstrand + + * ad.c: use krb5_set_password_using_ccache + +2004-06-01 Love Hörnquist Åstrand + + * ad.c: try handle spn's better + +2004-05-31 Love Hörnquist Åstrand + + * ad.c: add expiration time + + * ad.c: add modify operations + + * ad.c: handle create and delete + +2004-05-27 Love Hörnquist Åstrand + + * ad.c: more code for get, handle attributes + + * ad.c: more code for get, handle time stamps and bad password + counter + + * ad.c: more code for get, only fetches kvno for now + +2004-05-26 Love Hörnquist Åstrand + + * ad.c: add support for tsasl + + * private.h: add kadm5_ad_context + + * ipropd_master.c (prop_one): store the opcode in the begining of + the blob, not the end + + * ad.c: try all ldap servers in dns, generate a random password, + base64(random_block(64)), XXX must make it support other then + ARCFOUR + + * ad.c: framework for windows AD backend + +2004-03-07 Love Hörnquist Åstrand + + * create_s.c (kadm5_s_create_principal): remove old XXX command + and related code, _kadm5_set_keys will do all this now + +2004-02-29 Love Hörnquist Åstrand + + * set_keys.c (_kadm5_set_keys_randomly): make sure enctype to copy + enctype for des keys From: Andrew Bartlett + + * create_s.c (kadm5_s_create_principal_with_key): don't call + _kadm5_set_keys2, create_principal will do that for us. Set kvno + to 1. + + * chpass_s.c (change): bump kvno + (kadm5_s_chpass_principal_with_key): bump kvno + + * randkey_s.c (kadm5_s_randkey_principal): bump kvno + + * set_keys.c (_kadm5_set_*): don't change the kvno, let the callee + to that + +2003-12-30 Love Hörnquist Åstrand + + * chpass_s.c (change): fix same-password-again by decrypting keys + and setting an error code From: Buck Huppmann + +2003-12-21 Love Hörnquist Åstrand + + * init_c.c (_kadm5_c_init_context): catch errors from strdup and + other krb5_ functions + +2003-12-08 Love Hörnquist Åstrand + + * rename_s.c (kadm5_s_rename_principal): allow principal to change + realm From Panasas Inc + +2003-12-07 Love Hörnquist Åstrand + + * destroy_c.c (kadm5_c_destroy): fix memory leaks, From Panasas, + Inc + +2003-11-23 Love Hörnquist Åstrand + + * iprop.h: don't include + + * ipropd_slave.c: stop using krb5 lib private byte-frobbing + functions and replace them with with krb5_storage + + * ipropd_master.c: stop using krb5 lib private byte-frobbing + functions and replace them with with krb5_storage + +2003-11-19 Love Hörnquist Åstrand + + * ipropd_slave.c (receive_loop): when seeking over the entries we + already have, skip over the trailer. From: Jeffrey Hutzelman + + + * dump_log.c,ipropd_master.c,ipropd_slave.c, + replay_log.c,truncate_log.c: parse kdc.conf + From: Jeffrey Hutzelman + +2003-10-10 Love Hörnquist Åstrand + + * Makefile.am: += test_pw_quality + + * test_pw_quality.c: test program for verifying password quality + function + +2003-09-03 Love Hörnquist Åstrand + + * Makefile.am: add and enable check program default_keys + + * default_keys.c: test program for _kadm5_generate_key_set + + * init_c.c: use + krb5_get_init_creds_opt_alloc/krb5_get_init_creds_opt_free + +2003-08-17 Love Hörnquist Åstrand + + * set_keys.c (_kadm5_set_keys_randomly): remove dup return + + * ipropd_master.c (main): make sure current_version is initialized + +2003-08-15 Love Hörnquist Åstrand + + * set_keys.c: use default_keys for the both random keys and + password derived keys if its defined + +2003-07-24 Love Hörnquist Åstrand + + * ipropd_slave.c (receive_everything): switch close and rename + From: Alf Wachsmann + +2003-07-03 Love Hörnquist Åstrand + + * iprop.h, ipropd_master.c, ipropd_slave.c: + Add probing from the server that the client is still there, also + make the client check that the server is probing. + +2003-07-02 Love Hörnquist Åstrand + + * truncate_log.c (main): add missing ``if (ret)'' + +2003-06-26 Love Hörnquist Åstrand + + * set_keys.c (make_keys): add AES support + + * set_keys.c: fix off by one in the aes case, pointed out by Ken + Raeburn + +2003-04-30 Love Hörnquist Åstrand + + * set_keys.c (_kadm5_set_keys_randomly): add + ETYPE_AES256_CTS_HMAC_SHA1_96 key when configuried with aes + support + +2003-04-16 Love Hörnquist Åstrand + + * send_recv.c: check return values from krb5_data_alloc + * log.c: check return values from krb5_data_alloc + +2003-04-16 Love Hörnquist Åstrand + + * dump_log.c (print_entry): check return values from + krb5_data_alloc + +2003-04-01 Love Hörnquist Åstrand + + * init_c.c (kadm_connect): if a context realm was passed in, use + that to form the kadmin/admin principal + +2003-03-19 Love Hörnquist Åstrand + + * ipropd_master.c (main): make sure we don't consider dead slave + for select processing + (write_stats): use slave_stats_file variable, + check return value of strftime + (args): allow specifying slave stats file + (slave_dead): close the fd when the slave dies + +2002-10-21 Johan Danielsson + + * ipropd_slave.c (from Derrick Brashear): Propagating a large + database without this means the slave kdcs can get erroneous + HDB_NOENTRY and return the resulting errors. This creates a new db + handle, populates it, and moves it into place. + +2002-08-26 Assar Westerlund + + * ipropd_slave.c (receive_everything): type-correctness calling + _krb5_get_int + + * context_s.c (find_db_spec): const-correctness in parameters to + krb5_config_get_next + +2002-08-16 Johan Danielsson + + * private.h: rename header file flag macro + + * Makefile.am: generate kadm5-{protos,private}.h + +2002-08-15 Johan Danielsson + + * ipropd_master.c: check return value of krb5_sockaddr2address + +2002-07-04 Johan Danielsson + + * ipropd_master.c: handle slaves that come and go; add status + reporting (both from Love) + + * iprop.h: KADM5_SLAVE_STATS + +2002-03-25 Jacques Vidrine + + * init_c.c (get_cred_cache): bug fix: the default credentials + cache was not being used if a client name was specified. + +2002-03-25 Johan Danielsson + + * init_c.c (get_cred_cache): when getting the default_client from + the cred cache, make sure the instance part is "admin"; this + should require fewer uses of -p + +2002-03-11 Assar Westerlund + + * Makefile.am (libkadm5srv_la_LDFLAGS): set version to 7:5:0 + (libkadm5clnt_la_LDFLAGS): set version to 6:3:2 + +2002-02-08 Johan Danielsson + + * init_c.c: we have to create our own param struct before + marshaling + +2001-09-05 Johan Danielsson + + * Makefile.am: link with LIB_pidfile + + * iprop.h: include util.h for pidfile + +2001-08-31 Assar Westerlund + + * ipropd_slave.c (main): syslog with the correct name + +2001-08-30 Jacques Vidrine + + * ipropd_slave.c, ipropd_master.c (main): call pidfile + +2001-08-28 Assar Westerlund + + * Makefile.am (libkadm5srv_la_LDFLAGS): set version to 7:4:0 + +2001-08-24 Assar Westerlund + + * acl.c (fetch_acl): do not return bogus flags and re-organize + function + + * Makefile.am: rename variable name to avoid error from current + automake + +2001-08-13 Johan Danielsson + + * set_keys.c: add easier afs configuration, defaulting to the + local realm in lower case; also try to remove duplicate salts + +2001-07-12 Assar Westerlund + + * Makefile.am: add required library dependencies + +2001-07-03 Assar Westerlund + + * Makefile.am (libkadm5clnt_la_LDFLAGS): set version to 6:2:2 + +2001-06-29 Johan Danielsson + + * init_c.c: call krb5_get_init_creds_opt_set_default_flags + +2001-02-19 Johan Danielsson + + * replay_log.c: add --{start-end}-version flags to replay just + part of the log + +2001-02-15 Assar Westerlund + + * ipropd_master.c (main): fix select-loop to decrement ret + correctly. from "Brandon S. Allbery KF8NH" + +2001-01-30 Assar Westerlund + + * Makefile.am: bump versions + +2000-12-31 Assar Westerlund + + * init_s.c (*): handle krb5_init_context failure consistently + * init_c.c (init_context): handle krb5_init_context failure + consistently + +2000-12-11 Assar Westerlund + + * Makefile.am (libkadm5srv_la_LDFLAGS): bump version to 7:2:0 + +2000-11-16 Assar Westerlund + + * set_keys.c (make_keys): clean-up salting loop and try not to + leak memory + + * ipropd_master.c (main): check for fd's being too large to select + on + +2000-08-16 Assar Westerlund + + * Makefile.am (libkadm5srv_la_LDFLAGS): bump version to 7:1:0 + +2000-08-10 Assar Westerlund + + * acl.c (fetch_acl): fix wrong cases, use krb5_principal_match + +2000-08-07 Assar Westerlund + + * ipropd_master.c (main): ignore SIGPIPE + +2000-08-06 Assar Westerlund + + * ipropd_slave.c (receive_everything): make `fd' an int instead of + a pointer. From Derrick J Brashear + +2000-08-04 Johan Danielsson + + * admin.h: change void** to void* + +2000-07-25 Johan Danielsson + + * Makefile.am: bump versions to 7:0:0 and 6:0:2 + +2000-07-24 Assar Westerlund + + * log.c (kadm5_log_get_version): rename kadm5_log_get_version_fd + and make a new that takes a context + (kadm5_log_nop): add logging of missing lengths + (kadm5_log_truncate): new function + + * dump_log.c (print_entry): update and correct + * randkey_s.c: call _kadm5_bump_pw_expire + * truncate_log.c: new program for truncating the log + * Makefile.am (sbin_PROGRAMS): add truncate_log + (C_SOURCES): add bump_pw_expire.c + * bump_pw_expire.c: new function for extending password expiration + +2000-07-22 Assar Westerlund + + * keys.c: new file with _kadm5_free_keys, _kadm5_init_keys + + * set_keys.c (free_keys, init_keys): elevate to internal kadm5 + functions + + * chpass_s.c (kadm5_s_chpass_principal_cond): new function + * Makefile.am (C_SOURCES): add keys.c + * init_c.c: remove unused variable and handle some parameters + being NULL + +2000-07-22 Johan Danielsson + + * ipropd_slave.c: use krb5_read_priv_message + + * ipropd_master.c: use krb5_{read,write}_priv_message + + * init_c.c: use krb5_write_priv_message + +2000-07-11 Johan Danielsson + + * ipropd_slave.c: no need to call gethostname, since + sname_to_principal will + + * send_recv.c: assert that we have a connected socket + + * get_princs_c.c: call _kadm5_connect + + * rename_c.c: call _kadm5_connect + + * randkey_c.c: call _kadm5_connect + + * privs_c.c: call _kadm5_connect + + * modify_c.c: call _kadm5_connect + + * get_c.c: call _kadm5_connect + + * delete_c.c: call _kadm5_connect + + * create_c.c: call _kadm5_connect + + * chpass_c.c: call _kadm5_connect + + * private.h: add more fields to client context; remove prototypes + + * admin.h: remove prototypes + + * kadm5-protos.h: move public prototypes here + + * kadm5-private.h: move private prototypes here + + * init_c.c: break out connection code to separate function, and + defer calling it until we actually do something + +2000-07-07 Assar Westerlund + + * set_keys.c (make_keys): also support `[kadmin]use_v4_salt' for + backwards compatability + +2000-06-26 Johan Danielsson + + * set_keys.c (_kadm5_set_keys): rewrite this to be more easily + adaptable to different salts + +2000-06-19 Johan Danielsson + + * get_s.c: pa_* -> KRB5_PADATA_* + +2000-06-16 Assar Westerlund + + * ipropd_slave.c: change default keytab to default keytab (as in + typically FILE:/etc/krb5.keytab) + +2000-06-08 Assar Westerlund + + * ipropd_slave.c: bug fixes, for actually writing the full dump to + the database. based on a patch from Love + +2000-06-07 Assar Westerlund + + * acl.c: add support for patterns of principals + * log.c (kadm5_log_replay_create): handle more NULL pointers + (should they really happen?) + * log.c (kadm5_log_replay_modify): handle max_life == NULL and + max_renew == NULL + + * ipropd_master.c: use syslog. be less verbose + * ipropd_slave.c: use syslog + +2000-06-05 Assar Westerlund + + * private.h (kadm_ops): add kadm_nop more prototypes + * log.c (kadm5_log_set_version, kadm5_log_reinit, kadm5_log_nop, + kadm5_log_replay_nop): add + * ipropd_slave.c: and some more improvements + * ipropd_master.c: lots of improvements + * iprop.h (IPROP_PORT, IPROP_SERVICE): add + (iprop_cmd): add new commands + + * dump_log.c: add nop + +2000-05-15 Assar Westerlund + + * Makefile.am (libkadm5clnt_la_LDFLAGS): set version to 5:1:1 + +2000-05-12 Assar Westerlund + + * get_s.c (kadm5_s_get_principal): set life, rlife to INT_MAX as a + fallback. handle not having any creator. + * destroy_s.c (kadm5_s_destroy): free all allocated memory + * context_s.c (set_field): free variable if it's already set + (find_db_spec): malloc space for all strings + +2000-04-05 Assar Westerlund + + * Makefile.am (LDADD): add LIB_openldap + +2000-04-03 Assar Westerlund + + * Makefile.am (libkadm5srv_la_LDFLAGS): set version to 6:0:1 + (libkadm5clnt_la_LDFLAGS): set version to 5:0:1 + +2000-03-24 Assar Westerlund + + * set_keys.c (_kadm5_set_keys2): rewrite + (_kadm5_set_keys3): add + + * private.h (struct kadm_func): add chpass_principal_with_key + * init_c.c (set_funcs): add chpass_principal_with_key + +2000-03-23 Assar Westerlund + + * context_s.c (set_funcs): add chpass_principal_with_key + * common_glue.c (kadm5_chpass_principal_with_key): add + * chpass_s.c: comment-ize and change calling convention for + _kadm5_set_keys* + * chpass_c.c (kadm5_c_chpass_principal_with_key): add + +2000-02-07 Assar Westerlund + + * Makefile.am (libkadm5clnt_la_LDFLAGS): set version to 4:2:0 + +2000-01-28 Assar Westerlund + + * init_c.c (get_new_cache): make sure to request non-forwardable, + non-proxiable + +2000-01-06 Assar Westerlund + + * Makefile.am (libkadm5srv.la): bump version to 5:1:0 + + * context_s.c (_kadm5_s_init_context): handle params == NULL + +1999-12-26 Assar Westerlund + + * get_s.c (kadm5_s_get_principal): handle modified_by->principal + == NULL + +1999-12-20 Assar Westerlund + + * Makefile.am (libkadm5clnt_la_LDFLAGS): bump version to 4:1:0 + + * init_c.c (_kadm5_c_init_context): handle getting back port + number from admin host + (kadm5_c_init_with_context): remove `proto/' part before doing + getaddrinfo() + +1999-12-06 Assar Westerlund + + * Makefile.am: bump version to 5:0:0 and 4:0:0 + + * init_c.c (kadm5_c_init_with_context): don't use unitialized + stuff + +1999-12-04 Assar Westerlund + + * replay_log.c: adapt to changed kadm5_log_foreach + + * log.c (kadm5_log_foreach): change to take a + `kadm5_server_context' + + * init_c.c: use krb5_warn{,x} + + * dump_log.c: adapt to changed kadm5_log_foreach + + * init_c.c: re-write to use getaddrinfo + * Makefile.am (install-build-headers): add dependency + +1999-12-03 Johan Danielsson + + * log.c (kadm5_log_foreach): pass context + + * dump_log.c: print more interesting things + +1999-12-02 Johan Danielsson + + * ipropd_master.c (process_msg): check for short reads + +1999-11-25 Assar Westerlund + + * modify_s.c (kadm5_s_modify_principal): support key_data + (kadm5_s_modify_principal_with_key): remove + + * admin.h (kadm5_s_modify_principal_with_key): remove + +1999-11-20 Assar Westerlund + + * context_s.c (find_db_spec): ugly cast work-around. + +1999-11-14 Assar Westerlund + + * context_s.c (_kadm5_s_init_context): call krb5_add_et_list so + that we aren't dependent on the layout of krb5_context_data + * init_c.c (_kadm5_c_init_context): call krb5_add_et_list so that + we aren't dependent on the layout of krb5_context_data + +1999-11-13 Assar Westerlund + + * password_quality.c (kadm5_setup_passwd_quality_check): use + correct types for function pointers + +1999-11-09 Johan Danielsson + + * randkey_s.c: always bail out if the fetch fails + + * admin.h (kadm5_config_params): remove fields we're not using + + * ipropd_slave.c: allow passing a realm + + * ipropd_master.c: allow passing a realm + + * dump_log.c: allow passing a realm + + * acl.c: correctly get acl file + + * private.h (kadm5_server_context): add config_params struct and + remove acl_file; bump protocol version number + + * marshall.c: marshalling of config parameters + + * init_c.c (kadm5_c_init_with_context): try to cope with old + servers + + * init_s.c (kadm5_s_init_with_context): actually use some passed + values + + * context_s.c (_kadm5_s_init_context): get dbname, acl_file, and + stash_file from the config parameters, try to figure out these if + they're not provided + +1999-11-05 Assar Westerlund + + * Makefile.am (install-build-headers): use `cp' instead of + INSTALL_DATA + +1999-11-04 Assar Westerlund + + * Makefile.am: bump version to 4:0:0 and 3:0:0 (they access fields + directly in libkrb5's context - bad functions) + + * set_keys.c (_kadm5_set_keys_randomly): set enctypes correctly in + the copied keys + +1999-10-20 Assar Westerlund + + * Makefile.am: set version of kadm5srv to 3:0:2 (new password + quality functions). + set version of kdam5clnt to 2:1:1 (no interface changes) + + * Makefile.am (LDADD): add $(LIB_dlopen) + +1999-10-17 Assar Westerlund + + * randkey_s.c (kadm5_s_randkey_principal): use + _kadm5_set_keys_randomly + + * set_keys.c (free_keys): free more memory + (_kadm5_set_keys): a little bit more generic + (_kadm5_set_keys_randomly): new function for setting random keys. + +1999-10-14 Assar Westerlund + + * set_keys.c (_kadm5_set_keys): ignore old keys when setting new + ones and always add 3 DES keys and one 3DES key + +1999-10-03 Assar Westerlund + + * init_c.c (_kadm5_c_init_context): use `krb5_get_krb_admin_hst'. + check return value from strdup + +1999-09-26 Assar Westerlund + + * acl.c (_kadm5_privs_to_string): forgot one strcpy_truncate -> + strlcpy + +1999-09-24 Johan Danielsson + + * dump_log.c: remove unused `optind' + + * replay_log.c: remove unused `optind' + +1999-09-13 Assar Westerlund + + * chpass_c.c (kadm5_c_chpass_principal): new _kadm5_client_recv + + * send_recv.c (_kadm5_client_recv): return result in a `krb5_data' + so that we avoid copying it and don't need to dimension in + advance. change all callers. + +1999-09-10 Assar Westerlund + + * password_quality.c: new file + + * admin.h + (kadm5_setup_passwd_quality_check,kadm5_check_password_quality): + add prototypes + + * Makefile.am (S_SOURCES): add password_quality.c + +1999-07-26 Assar Westerlund + + * Makefile.am: update versions to 2:0:1 + +1999-07-24 Assar Westerlund + + * ent_setup.c (_kadm5_setup_entry): make princ_expire_time == 0 + and pw_expiration == 0 mean never + +1999-07-22 Assar Westerlund + + * log.c (kadm5_log_flush): extra cast + +1999-07-07 Assar Westerlund + + * marshall.c (store_principal_ent): encoding princ_expire_time and + pw_expiration in correct order + +1999-06-28 Assar Westerlund + + * randkey_s.c (kadm5_s_randkey_principal): nuke old mkvno, + otherwise hdb will think that the new random keys are already + encrypted which will cause lots of confusion later. + +1999-06-23 Assar Westerlund + + * ent_setup.c (_kadm5_setup_entry): handle 0 == unlimited + correctly. From Michal Vocu + +1999-06-15 Assar Westerlund + + * init_c.c (get_cred_cache): use get_default_username + +1999-05-23 Assar Westerlund + + * create_s.c (create_principal): if there's no default entry the + mask should be zero. + +1999-05-21 Assar Westerlund + + * init_c.c (get_cred_cache): use $USERNAME + +1999-05-17 Johan Danielsson + + * init_c.c (get_cred_cache): figure out principal + +1999-05-05 Johan Danielsson + + * send_recv.c: cleanup _kadm5_client_{send,recv} + +1999-05-04 Assar Westerlund + + * set_keys.c (_kadm5_set_keys2): don't check the recently created + memory for NULL pointers + + * private.h (_kadm5_setup_entry): change prototype + + * modify_s.c: call new _kadm5_setup_entry + + * ent_setup.c (_kadm5_setup_entry): change so that it takes three + masks, one for what bits to set and one for each of principal and + def containing the bits that are set there. + + * create_s.c: call new _kadm5_setup_entry + + * create_s.c (get_default): check return value + (create_principal): send wider mask to _kadm5_setup_entry + +1999-05-04 Johan Danielsson + + * send_recv.c (_kadm5_client_recv): handle arbitrarily sized + packets, check for errors + + * get_c.c: check for failure from _kadm5_client_{send,recv} + +1999-05-04 Assar Westerlund + + * init_c.c (get_new_cache): don't abort when interrupted from + password prompt + + * destroy_c.c (kadm5_c_destroy): check if we should destroy the + auth context + +1999-05-03 Johan Danielsson + + * chpass_s.c: fix arguments to _kadm5_set_keys2 + + * private.h: proto + + * set_keys.c: clear mkvno + + * rename_s.c: add flags to fetch and store; seal keys before + logging + + * randkey_s.c: add flags to fetch and store; seal keys before + logging + + * modify_s.c: add flags to fetch and store; seal keys before + logging + + * log.c: add flags to fetch and store; seal keys before logging + + * get_s.c: add flags to fetch and store; seal keys before logging + + * get_princs_s.c: add flags to fetch and store; seal keys before + logging + + * delete_s.c: add flags to fetch and store; seal keys before + logging + + * create_s.c: add flags to fetch and store; seal keys before + logging + + * chpass_s.c: add flags to fetch and store; seal keys before + logging + + * Makefile.am: remove server.c + + * admin.h: add prototypes + + * ent_setup.c (_kadm5_setup_entry): set key_data + + * set_keys.c: add _kadm5_set_keys2 to sey keys from key_data + + * modify_s.c: add kadm5_s_modify_principal_with_key + + * create_s.c: add kadm5_s_create_principal_with_key + + * chpass_s.c: add kadm5_s_chpass_principal_with_key + + * kadm5_locl.h: move stuff to private.h + + * private.h: move stuff from kadm5_locl.h + diff --git a/third_party/heimdal/lib/kadm5/Makefile.am b/third_party/heimdal/lib/kadm5/Makefile.am new file mode 100644 index 0000000..6b58c5f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/Makefile.am @@ -0,0 +1,233 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +libkadm5srv_la_CPPFLAGS = -I$(srcdir)/../krb5 +libkadm5clnt_la_CPPFLAGS = -I$(srcdir)/../krb5 + +lib_LTLIBRARIES = libkadm5srv.la libkadm5clnt.la +libkadm5srv_la_LDFLAGS = -version-info 8:1:0 +libkadm5clnt_la_LDFLAGS = -version-info 7:1:0 + +if versionscript +libkadm5clnt_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script-client.map +libkadm5srv_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +sbin_PROGRAMS = iprop-log +check_PROGRAMS = default_keys test_marshall +noinst_PROGRAMS = test_pw_quality + +noinst_LTLIBRARIES = sample_passwd_check.la sample_hook.la + +sample_passwd_check_la_SOURCES = sample_passwd_check.c +sample_passwd_check_la_LDFLAGS = -module + +sample_hook_la_SOURCES = sample_hook.c +sample_hook_la_LDFLAGS = -module + +libkadm5srv_la_LIBADD = \ + $(LIB_com_err) ../krb5/libkrb5.la \ + ../hdb/libhdb.la $(LIBADD_roken) +libkadm5clnt_la_LIBADD = \ + $(LIB_com_err) ../krb5/libkrb5.la $(LIBADD_roken) + +libexec_PROGRAMS = ipropd-master ipropd-slave + +default_keys_SOURCES = default_keys.c +default_keys_CPPFLAGS = -I$(srcdir)/../krb5 + +test_marshall_SOURCES = marshall.c +test_marshall_CPPFLAGS = -I$(srcdir)/../krb5 -DTEST + +kadm5includedir = $(includedir)/kadm5 +buildkadm5include = $(buildinclude)/kadm5 + +dist_kadm5include_HEADERS = admin.h private.h kadm5-hook.h kadm5-pwcheck.h +dist_kadm5include_HEADERS += $(srcdir)/kadm5-protos.h $(srcdir)/kadm5-private.h + +nodist_kadm5include_HEADERS = kadm5_err.h + +install-build-headers:: $(dist_kadm5include_HEADERS) $(nodist_kadm5include_HEADERS) + @foo='$(dist_kadm5include_HEADERS) $(nodist_kadm5include_HEADERS)'; \ + for f in $$foo; do \ + f=`basename $$f`; \ + if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \ + else file="$$f"; fi; \ + if cmp -s $$file $(buildkadm5include)/$$f 2> /dev/null ; then \ + : ; else \ + echo "cp $$file $(buildkadm5include)/$$f";\ + cp $$file $(buildkadm5include)/$$f; \ + fi ; \ + done + +dist_libkadm5clnt_la_SOURCES = \ + ad.c \ + chpass_c.c \ + client_glue.c \ + common_glue.c \ + create_c.c \ + delete_c.c \ + destroy_c.c \ + flush_c.c \ + free.c \ + get_c.c \ + get_princs_c.c \ + init_c.c \ + kadm5_locl.h \ + marshall.c \ + modify_c.c \ + private.h \ + privs_c.c \ + prune_c.c \ + randkey_c.c \ + rename_c.c \ + send_recv.c \ + admin.h + +nodist_libkadm5clnt_la_SOURCES = \ + kadm5_err.c \ + kadm5_err.h + +dist_libkadm5srv_la_SOURCES = \ + acl.c \ + admin.h \ + bump_pw_expire.c \ + chpass_s.c \ + common_glue.c \ + context_s.c \ + create_s.c \ + delete_s.c \ + destroy_s.c \ + ent_setup.c \ + error.c \ + flush_s.c \ + free.c \ + get_princs_s.c \ + get_s.c \ + init_s.c \ + kadm5_locl.h \ + keys.c \ + log.c \ + marshall.c \ + modify_s.c \ + password_quality.c \ + private.h \ + privs_s.c \ + prune_s.c \ + randkey_s.c \ + rename_s.c \ + server_glue.c \ + server_hooks.c \ + setkey3_s.c \ + set_keys.c \ + set_modifier.c \ + admin.h + +nodist_libkadm5srv_la_SOURCES = \ + kadm5_err.c \ + kadm5_err.h + +libkadm5srv_la_DEPENDENCIES = \ + version-script.map + +dist_iprop_log_SOURCES = iprop-log.c +nodist_iprop_log_SOURCES = iprop-commands.c + +ipropd_master_SOURCES = ipropd_master.c ipropd_common.c iprop.h kadm5_locl.h +ipropd_master_CPPFLAGS = -I$(srcdir)/../krb5 + +ipropd_slave_SOURCES = ipropd_slave.c ipropd_common.c iprop.h kadm5_locl.h +ipropd_slave_CPPFLAGS = -I$(srcdir)/../krb5 + +man_MANS = kadm5_pwcheck.3 iprop.8 iprop-log.8 + +LDADD = \ + libkadm5srv.la \ + $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_hcrypto) \ + $(LIB_roken) \ + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) \ + $(LIB_dlopen) \ + $(LIB_pidfile) + + +iprop_log_LDADD = \ + libkadm5srv.la \ + $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_hcrypto) \ + $(top_builddir)/lib/sl/libsl.la \ + $(LIB_readline) \ + $(LIB_roken) \ + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) \ + $(LIB_dlopen) \ + $(LIB_pidfile) + +iprop_log_CPPFLAGS = -I$(srcdir)/../krb5 + +iprop-commands.c iprop-commands.h: iprop-commands.in + $(SLC) $(srcdir)/iprop-commands.in + +$(libkadm5srv_la_OBJECTS): kadm5_err.h +$(libkadm5clnt_la_OBJECTS): kadm5_err.h +$(iprop_log_OBJECTS): iprop-commands.h + +client_glue.lo server_glue.lo: $(srcdir)/common_glue.c + +CLEANFILES = kadm5_err.c kadm5_err.h iprop-commands.h iprop-commands.c + +# to help stupid solaris make + +kadm5_err.h: kadm5_err.et + +ALL_OBJECTS = $(libkadm5clnt_la_OBJECTS) +ALL_OBJECTS += $(libkadm5srv_la_OBJECTS) +ALL_OBJECTS += $(ipropd_master_OBJECTS) +ALL_OBJECTS += $(ipropd_slave_OBJECTS) +ALL_OBJECTS += $(iprop_log_OBJECTS) +ALL_OBJECTS += $(test_pw_quality_OBJECTS) +ALL_OBJECTS += $(sample_passwd_check_la_OBJECTS) +ALL_OBJECTS += $(sample_hook_la_OBJECTS) +ALL_OBJECTS += $(default_keys_OBJECTS) + +$(ALL_OBJECTS): $(srcdir)/kadm5-protos.h $(srcdir)/kadm5-private.h +$(ALL_OBJECTS): kadm5_err.h + +KADM5_PROTOS_SRCS = $(dist_libkadm5clnt_la_SOURCES) +KADM5_PROTOS_SRCS += $(dist_libkadm5srv_la_SOURCES) + +proto_opts = -q -R '^(_|kadm5_c_|kadm5_s_|kadm5_log)' -P comment +$(srcdir)/kadm5-protos.h: $(KADM5_PROTOS_SRCS) + cd $(srcdir); perl ../../cf/make-proto.pl $(proto_opts) \ + -o kadm5-protos.h \ + $(dist_libkadm5clnt_la_SOURCES) \ + $(dist_libkadm5srv_la_SOURCES) \ + || rm -f kadm5-protos.h + +$(srcdir)/kadm5-private.h: $(KADM5_PROTOS_SRCS) + cd $(srcdir); perl ../../cf/make-proto.pl $(proto_opts) \ + -p kadm5-private.h \ + $(dist_libkadm5clnt_la_SOURCES) \ + $(dist_libkadm5srv_la_SOURCES) \ + || rm -f kadm5-private.h + +EXTRA_DIST = \ + NTMakefile \ + iprop-log-version.rc \ + ipropd-master-version.rc \ + ipropd-slave-version.rc \ + libkadm5srv-version.rc \ + libkadm5srv-exports.def \ + kadm5_err.et \ + iprop-commands.in \ + $(man_MANS) \ + check-cracklib.pl \ + flush.c \ + sample_passwd_check.c \ + sample_hook.c \ + version-script.map \ + version-script-client.map diff --git a/third_party/heimdal/lib/kadm5/NTMakefile b/third_party/heimdal/lib/kadm5/NTMakefile new file mode 100644 index 0000000..9357a7f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/NTMakefile @@ -0,0 +1,296 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\kadm5 + +!include ../../windows/NTMakefile.w32 + +dist_libkadm5clnt_la_SOURCES = \ + ad.c \ + chpass_c.c \ + client_glue.c \ + common_glue.c \ + create_c.c \ + delete_c.c \ + destroy_c.c \ + flush_c.c \ + free.c \ + get_c.c \ + get_princs_c.c \ + init_c.c \ + kadm5_locl.h \ + marshall.c \ + modify_c.c \ + private.h \ + privs_c.c \ + prune_c.c \ + randkey_c.c \ + rename_c.c \ + send_recv.c \ + kadm5-pwcheck.h \ + admin.h \ + kadm5-hook.h + +dist_libkadm5srv_la_SOURCES = \ + acl.c \ + admin.h \ + bump_pw_expire.c \ + chpass_s.c \ + common_glue.c \ + context_s.c \ + create_s.c \ + delete_s.c \ + destroy_s.c \ + ent_setup.c \ + error.c \ + flush_s.c \ + free.c \ + get_princs_s.c \ + get_s.c \ + init_s.c \ + kadm5_locl.h \ + keys.c \ + log.c \ + marshall.c \ + modify_s.c \ + password_quality.c \ + private.h \ + privs_s.c \ + prune_s.c \ + randkey_s.c \ + rename_s.c \ + server_glue.c \ + server_hooks.c \ + set_keys.c \ + setkey3_s.c \ + set_modifier.c \ + kadm5-pwcheck.h \ + admin.h \ + kadm5-hook.h + +LIBKADM5CLNT_OBJS= \ + $(OBJ)\ad.obj \ + $(OBJ)\chpass_c.obj \ + $(OBJ)\client_glue.obj \ + $(OBJ)\common_glue.obj \ + $(OBJ)\create_c.obj \ + $(OBJ)\delete_c.obj \ + $(OBJ)\destroy_c.obj \ + $(OBJ)\flush_c.obj \ + $(OBJ)\free.obj \ + $(OBJ)\get_c.obj \ + $(OBJ)\get_princs_c.obj \ + $(OBJ)\init_c.obj \ + $(OBJ)\marshall.obj \ + $(OBJ)\modify_c.obj \ + $(OBJ)\privs_c.obj \ + $(OBJ)\prune_c.obj \ + $(OBJ)\randkey_c.obj \ + $(OBJ)\rename_c.obj \ + $(OBJ)\send_recv.obj \ + $(OBJ)\kadm5_err.obj + +LIBKADM5SRV_OBJS= \ + $(OBJ)\acl.obj \ + $(OBJ)\bump_pw_expire.obj \ + $(OBJ)\chpass_s.obj \ + $(OBJ)\common_glue.obj \ + $(OBJ)\context_s.obj \ + $(OBJ)\create_s.obj \ + $(OBJ)\delete_s.obj \ + $(OBJ)\destroy_s.obj \ + $(OBJ)\ent_setup.obj \ + $(OBJ)\error.obj \ + $(OBJ)\flush_s.obj \ + $(OBJ)\free.obj \ + $(OBJ)\get_princs_s.obj \ + $(OBJ)\get_s.obj \ + $(OBJ)\init_s.obj \ + $(OBJ)\keys.obj \ + $(OBJ)\log.obj \ + $(OBJ)\marshall.obj \ + $(OBJ)\modify_s.obj \ + $(OBJ)\password_quality.obj \ + $(OBJ)\privs_s.obj \ + $(OBJ)\prune_s.obj \ + $(OBJ)\randkey_s.obj \ + $(OBJ)\rename_s.obj \ + $(OBJ)\server_glue.obj \ + $(OBJ)\server_hooks.obj \ + $(OBJ)\set_keys.obj \ + $(OBJ)\setkey3_s.obj \ + $(OBJ)\set_modifier.obj \ + $(OBJ)\kadm5_err.obj + + +proto_opts = -q -R "^(_|kadm5_c_|kadm5_s_|kadm5_log)" -P remove + +$(OBJ)\kadm5-protos.h: $(dist_libkadm5srv_la_SOURCES) $(dist_libkadm5clnt_la_SOURCES) + $(PERL) ..\..\cf\make-proto.pl $(proto_opts) \ + -o $@ \ + $(dist_libkadm5srv_la_SOURCES) \ + $(dist_libkadm5clnt_la_SOURCES) \ + || $(RM) $@ + +$(OBJ)\kadm5-private.h: $(dist_libkadm5srv_la_SOURCES) $(dist_libkadm5clnt_la_SOURCES) + $(PERL) ..\..\cf\make-proto.pl $(proto_opts) \ + -p $@ \ + $(dist_libkadm5srv_la_SOURCES) \ + $(dist_libkadm5clnt_la_SOURCES) \ + || $(RM) $@ + +$(OBJ)\iprop-commands.c $(OBJ)\iprop-commands.h: iprop-commands.in + cd $(OBJ) + $(CP) $(SRCDIR)\iprop-commands.in $(OBJ) + $(BINDIR)\slc.exe iprop-commands.in + cd $(SRCDIR) + +$(OBJ)\kadm5_err.h $(OBJ)kadm5_err.c: kadm5_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\kadm5_err.et + cd $(SRCDIR) + +$(KADM5INCDIR)\kadm5_err.h: $(OBJ)\kadm5_err.h + +KADM5INCDIR=$(INCDIR)\kadm5 + +INCFILES=\ + $(KADM5INCDIR)\kadm5_err.h \ + $(KADM5INCDIR)\admin.h \ + $(KADM5INCDIR)\private.h \ + $(KADM5INCDIR)\kadm5-hook.h \ + $(KADM5INCDIR)\kadm5-protos.h \ + $(KADM5INCDIR)\kadm5-private.h \ + $(OBJ)\iprop-commands.h + +SBINPROGRAMS=$(SBINDIR)\iprop-log.exe + +LIBEXECPROGRAMS=$(LIBEXECDIR)\ipropd-master.exe $(LIBEXECDIR)\ipropd-slave.exe + +EXELIBDEPS= \ + $(LIBKADM5SRV) \ + $(LIBROKEN) \ + $(LIBHEIMDAL) \ + $(LIBHDB) \ + $(LIBSQLITE) \ + $(LIBSL) \ + $(LIBCOMERR) \ + $(LIBVERS) + +$(SBINDIR)\iprop-log.exe: $(OBJ)\iprop-log.obj $(OBJ)\iprop-commands.obj $(EXELIBDEPS) \ + $(OBJ)\iprop-log-version.res + $(EXECONLINK) + $(EXEPREP) + +$(LIBEXECDIR)\ipropd-master.exe: $(OBJ)\ipropd_master.obj $(OBJ)\ipropd_common.obj \ + $(EXELIBDEPS) $(OBJ)\ipropd-master-version.res + $(EXECONLINK) + $(EXEPREP) + +$(LIBEXECDIR)\ipropd-slave.exe: $(OBJ)\ipropd_slave.obj $(OBJ)\ipropd_common.obj \ + $(EXELIBDEPS) $(OBJ)\ipropd-slave-version.res + $(EXECONLINK) + $(EXEPREP) + +$(LIBKADM5CLNT): $(LIBKADM5CLNT_OBJS) + $(LIBCON) + +LIBKADM5SRVRES=$(OBJ)\libkadm5srv-version.res + +$(LIBKADM5SRV): $(BINDIR)\libkadm5srv.dll + +$(BINDIR)\libkadm5srv.dll: $(LIBKADM5SRV_OBJS) $(LIBHEIMDAL) $(LIBROKEN) $(LIBHDB) $(LIBCOMERR) $(LIBSQLITE) $(LIBKADM5SRVRES) $(LIBHEIMBASE) + $(DLLGUILINK) -implib:$(LIBKADM5SRV) -def:libkadm5srv-exports.def + $(DLLPREP_NODIST) + +all:: $(INCFILES) $(LIBKADM5SRV) $(LIBKADM5CLNT) + +all-tools:: $(SBINPROGRAMS) $(LIBEXECPROGRAMS) + +clean:: + -$(RM) $(INCFILES) + -$(RM) $(LIBKADM5CLNT) + -$(RM) $(LIBKADM5SRV) + -$(RM) $(BINDIR)\libkadm5srv.* + -$(RM) $(SBINPROGRAMS:.exe=.*) + -$(RM) $(LIBEXECPROGRAMS:.exe=.*) + +test:: test-binaries test-run + +test-binaries: \ + $(OBJ)\default_keys.exe \ + $(OBJ)\test_pw_quality.exe \ + $(OBJ)\sample_passwd_check.dll \ + $(OBJ)\sample_hook.dll + +$(OBJ)\default_keys.exe: $(OBJ)\default_keys.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBHDB) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_pw_quality.exe: $(OBJ)\test_pw_quality.obj \ + $(LIBROKEN) $(LIBKADM5SRV) $(LIBVERS) $(LIBHEIMDAL) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\sample_passwd_check.dll: $(OBJ)\sample_passwd_check.obj $(LIBHEIMDAL) + $(DLLGUILINK) /DEF:<< +EXPORTS + version DATA + check_length +<< + $(DLLPREP_NODIST) + +$(OBJ)\sample_hook.dll: $(OBJ)\sample_hook.obj $(LIBKADM5SRV) $(LIBHEIMDAL) + $(DLLGUILINK) /DEF:<< +EXPORTS + kadm5_hook_plugin_load +<< + $(DLLPREP_NODIST) + +test-run: + cd $(OBJ) + -default_keys.exe + -test_pw_quality.exe + cd $(SRCDIR) + +{$(OBJ)}.h{$(KADM5INCDIR)}.h: + $(CP) $< $@ + +{}.h{$(KADM5INCDIR)}.h: + $(CP) $< $@ + +{}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -I$(OBJ) -I$(KADM5INCDIR) + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libkadm5srv-exports.def + +test:: test-exports diff --git a/third_party/heimdal/lib/kadm5/acl.c b/third_party/heimdal/lib/kadm5/acl.c new file mode 100644 index 0000000..f71ed99 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/acl.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +static struct units acl_units[] = { + { "all", KADM5_PRIV_ALL }, + { "change-password",KADM5_PRIV_CPW }, + { "cpw", KADM5_PRIV_CPW }, + { "list", KADM5_PRIV_LIST }, + { "delete", KADM5_PRIV_DELETE }, + { "modify", KADM5_PRIV_MODIFY }, + { "add", KADM5_PRIV_ADD }, + { "get", KADM5_PRIV_GET }, + { "get-keys", KADM5_PRIV_GET_KEYS }, + { NULL, 0 } +}; + +kadm5_ret_t +_kadm5_string_to_privs(const char *s, uint32_t* privs) +{ + int flags; + flags = parse_flags(s, acl_units, 0); + if(flags < 0) + return KADM5_FAILURE; + *privs = flags; + return 0; +} + +kadm5_ret_t +_kadm5_privs_to_string(uint32_t privs, char *string, size_t len) +{ + if(privs == 0) + strlcpy(string, "none", len); + else + unparse_flags(privs, acl_units + 1, string, len); + return 0; +} + +/* + * retrieve the right for the current caller on `princ' (NULL means all) + * and store them in `ret_flags' + * return 0 or an error. + */ + +static kadm5_ret_t +fetch_acl (kadm5_server_context *context, + krb5_const_principal princ, + unsigned *ret_flags) +{ + FILE *f; + krb5_error_code ret = 0; + char buf[256]; + + *ret_flags = 0; + + /* no acl file -> no rights */ + f = fopen(context->config.acl_file, "r"); + if (f == NULL) + return 0; + + while(fgets(buf, sizeof(buf), f) != NULL) { + char *foo = NULL, *p; + krb5_principal this_princ; + unsigned flags = 0; + + p = strtok_r(buf, " \t\n", &foo); + if(p == NULL) + continue; + if (*p == '#') /* comment */ + continue; + ret = krb5_parse_name(context->context, p, &this_princ); + if(ret) + break; + if(!krb5_principal_compare(context->context, + context->caller, this_princ)) { + krb5_free_principal(context->context, this_princ); + continue; + } + krb5_free_principal(context->context, this_princ); + p = strtok_r(NULL, " \t\n", &foo); + if(p == NULL) + continue; + ret = _kadm5_string_to_privs(p, &flags); + if (ret) + break; + p = strtok_r(NULL, " \t\n", &foo); + if (p == NULL) { + *ret_flags = flags; + break; + } + if (princ != NULL) { + krb5_principal pattern_princ; + krb5_boolean match; + const char *c0 = krb5_principal_get_comp_string(context->context, + princ, 0); + const char *pat_c0; + + ret = krb5_parse_name(context->context, p, &pattern_princ); + if (ret) + break; + pat_c0 = krb5_principal_get_comp_string(context->context, + pattern_princ, 0); + match = krb5_principal_match(context->context, + princ, pattern_princ); + + /* + * If `princ' is a WELLKNOWN name, then require the WELLKNOWN label + * be matched exactly. + * + * FIXME: We could do something similar for krbtgt and kadmin other + * principal types. + */ + if (match && c0 && strcmp(c0, "WELLKNOWN") == 0 && + (!pat_c0 || strcmp(pat_c0, "WELLKNOWN") != 0)) + match = FALSE; + krb5_free_principal(context->context, pattern_princ); + if (match) { + *ret_flags = flags; + break; + } + } + } + fclose(f); + return ret; +} + +krb5_boolean +_kadm5_is_kadmin_service_p(kadm5_server_context *context) +{ + krb5_boolean ret; + krb5_principal princ; + + if (krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ) != 0) + return FALSE; + + ret = krb5_principal_compare(context->context, context->caller, princ); + krb5_free_principal(context->context, princ); + + return ret; +} + +/* + * set global acl flags in `context' for the current caller. + * return 0 on success or an error + */ + +kadm5_ret_t +_kadm5_acl_init(kadm5_server_context *context) +{ + if (_kadm5_is_kadmin_service_p(context)) { + context->acl_flags = KADM5_PRIV_ALL; + return 0; + } + + return fetch_acl (context, NULL, &context->acl_flags); +} + +/* + * check if `flags' allows `op' + * return 0 if OK or an error + */ + +static kadm5_ret_t +check_flags (unsigned op, + unsigned flags) +{ + unsigned res = ~flags & op; + + if(res & KADM5_PRIV_GET) + return KADM5_AUTH_GET; + if(res & KADM5_PRIV_GET_KEYS) + return KADM5_AUTH_GET_KEYS; + if(res & KADM5_PRIV_ADD) + return KADM5_AUTH_ADD; + if(res & KADM5_PRIV_MODIFY) + return KADM5_AUTH_MODIFY; + if(res & KADM5_PRIV_DELETE) + return KADM5_AUTH_DELETE; + if(res & KADM5_PRIV_CPW) + return KADM5_AUTH_CHANGEPW; + if(res & KADM5_PRIV_LIST) + return KADM5_AUTH_LIST; + if(res) + return KADM5_AUTH_INSUFFICIENT; + return 0; +} + +/* + * return 0 if the current caller in `context' is allowed to perform + * `op' on `princ' and otherwise an error + * princ == NULL if it's not relevant. + */ + +kadm5_ret_t +_kadm5_acl_check_permission(kadm5_server_context *context, + unsigned op, + krb5_const_principal princ) +{ + kadm5_ret_t ret; + unsigned princ_flags; + + ret = check_flags (op, context->acl_flags); + if (ret == 0) + return ret; + ret = fetch_acl (context, princ, &princ_flags); + if (ret) + return ret; + return check_flags (op, princ_flags); +} diff --git a/third_party/heimdal/lib/kadm5/ad.c b/third_party/heimdal/lib/kadm5/ad.c new file mode 100644 index 0000000..b9b9c90 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ad.c @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define HAVE_TSASL 1 + +#include "kadm5_locl.h" +#if 1 +#undef OPENLDAP +#undef HAVE_TSASL +#endif +#ifdef OPENLDAP +#include +#ifdef HAVE_TSASL +#include +#endif +#include +#include +#endif + +RCSID("$Id$"); + +#ifdef OPENLDAP + +#define CTX2LP(context) ((LDAP *)((context)->ldap_conn)) +#define CTX2BASE(context) ((context)->base_dn) + +/* + * userAccountControl + */ + +#define UF_SCRIPT 0x00000001 +#define UF_ACCOUNTDISABLE 0x00000002 +#define UF_UNUSED_0 0x00000004 +#define UF_HOMEDIR_REQUIRED 0x00000008 +#define UF_LOCKOUT 0x00000010 +#define UF_PASSWD_NOTREQD 0x00000020 +#define UF_PASSWD_CANT_CHANGE 0x00000040 +#define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080 +#define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100 +#define UF_NORMAL_ACCOUNT 0x00000200 +#define UF_UNUSED_1 0x00000400 +#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800 +#define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000 +#define UF_SERVER_TRUST_ACCOUNT 0x00002000 +#define UF_UNUSED_2 0x00004000 +#define UF_UNUSED_3 0x00008000 +#define UF_PASSWD_NOT_EXPIRE 0x00010000 +#define UF_MNS_LOGON_ACCOUNT 0x00020000 +#define UF_SMARTCARD_REQUIRED 0x00040000 +#define UF_TRUSTED_FOR_DELEGATION 0x00080000 +#define UF_NOT_DELEGATED 0x00100000 +#define UF_USE_DES_KEY_ONLY 0x00200000 +#define UF_DONT_REQUIRE_PREAUTH 0x00400000 +#define UF_UNUSED_4 0x00800000 +#define UF_UNUSED_5 0x01000000 +#define UF_UNUSED_6 0x02000000 +#define UF_UNUSED_7 0x04000000 +#define UF_UNUSED_8 0x08000000 +#define UF_UNUSED_9 0x10000000 +#define UF_UNUSED_10 0x20000000 +#define UF_UNUSED_11 0x40000000 +#define UF_UNUSED_12 0x80000000 + +/* + * + */ + +#ifndef HAVE_TSASL +static int +sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *interact) +{ + return LDAP_SUCCESS; +} +#endif + +#if 0 +static Sockbuf_IO ldap_tsasl_io = { + NULL, /* sbi_setup */ + NULL, /* sbi_remove */ + NULL, /* sbi_ctrl */ + NULL, /* sbi_read */ + NULL, /* sbi_write */ + NULL /* sbi_close */ +}; +#endif + +#ifdef HAVE_TSASL +static int +ldap_tsasl_bind_s(LDAP *ld, + LDAP_CONST char *dn, + LDAPControl **serverControls, + LDAPControl **clientControls, + const char *host) +{ + char *attrs[] = { "supportedSASLMechanisms", NULL }; + struct tsasl_peer *peer = NULL; + struct tsasl_buffer in, out; + struct berval ccred, *scred; + LDAPMessage *m, *m0; + const char *mech; + char **vals; + int ret, rc; + + ret = tsasl_peer_init(TSASL_FLAGS_INITIATOR | TSASL_FLAGS_CLEAR, + "ldap", host, &peer); + if (ret != TSASL_DONE) { + rc = LDAP_LOCAL_ERROR; + goto out; + } + + rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &m0); + if (rc != LDAP_SUCCESS) + goto out; + + m = ldap_first_entry(ld, m0); + if (m == NULL) { + ldap_msgfree(m0); + goto out; + } + + vals = ldap_get_values(ld, m, "supportedSASLMechanisms"); + if (vals == NULL) { + ldap_msgfree(m0); + goto out; + } + + ret = tsasl_find_best_mech(peer, vals, &mech); + if (ret) { + ldap_msgfree(m0); + goto out; + } + + ldap_msgfree(m0); + + ret = tsasl_select_mech(peer, mech); + if (ret != TSASL_DONE) { + rc = LDAP_LOCAL_ERROR; + goto out; + } + + in.tb_data = NULL; + in.tb_size = 0; + + do { + ret = tsasl_request(peer, &in, &out); + if (in.tb_size != 0) { + free(in.tb_data); + in.tb_data = NULL; + in.tb_size = 0; + } + if (ret != TSASL_DONE && ret != TSASL_CONTINUE) { + rc = LDAP_AUTH_UNKNOWN; + goto out; + } + + ccred.bv_val = out.tb_data; + ccred.bv_len = out.tb_size; + + rc = ldap_sasl_bind_s(ld, dn, mech, &ccred, + serverControls, clientControls, &scred); + tsasl_buffer_free(&out); + + if (rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS) { + if(scred && scred->bv_len) + ber_bvfree(scred); + goto out; + } + + in.tb_data = malloc(scred->bv_len); + if (in.tb_data == NULL) { + rc = LDAP_LOCAL_ERROR; + goto out; + } + memcpy(in.tb_data, scred->bv_val, scred->bv_len); + in.tb_size = scred->bv_len; + ber_bvfree(scred); + + } while (rc == LDAP_SASL_BIND_IN_PROGRESS); + + out: + if (rc == LDAP_SUCCESS) { +#if 0 + ber_sockbuf_add_io(ld->ld_conns->lconn_sb, &ldap_tsasl_io, + LBER_SBIOD_LEVEL_APPLICATION, peer); + +#endif + } else if (peer != NULL) + tsasl_peer_free(peer); + + return rc; +} +#endif /* HAVE_TSASL */ + + +static int +check_ldap(kadm5_ad_context *context, int ret) +{ + switch (ret) { + case LDAP_SUCCESS: + return 0; + case LDAP_SERVER_DOWN: { + LDAP *lp = CTX2LP(context); + ldap_unbind(lp); + context->ldap_conn = NULL; + free(context->base_dn); + context->base_dn = NULL; + return 1; + } + default: + return 1; + } +} + +/* + * + */ + +static void +laddattr(char ***al, int *attrlen, char *attr) +{ + char **a; + a = realloc(*al, (*attrlen + 2) * sizeof(**al)); + if (a == NULL) + return; + a[*attrlen] = attr; + a[*attrlen + 1] = NULL; + (*attrlen)++; + *al = a; +} + +static kadm5_ret_t +_kadm5_ad_connect(void *server_handle) +{ + kadm5_ad_context *context = server_handle; + struct { + char *server; + int port; + } *s, *servers = NULL; + int i, num_servers = 0; + + if (context->ldap_conn) + return 0; + + { + struct dns_reply *r; + struct resource_record *rr; + char *domain; + + asprintf(&domain, "_ldap._tcp.%s", context->realm); + if (domain == NULL) { + krb5_set_error_message(context->context, KADM5_NO_SRV, "malloc"); + return KADM5_NO_SRV; + } + + r = dns_lookup(domain, "SRV"); + free(domain); + if (r == NULL) { + krb5_set_error_message(context->context, KADM5_NO_SRV, "Didn't find ldap dns"); + return KADM5_NO_SRV; + } + + for (rr = r->head ; rr != NULL; rr = rr->next) { + if (rr->type != rk_ns_t_srv) + continue; + s = realloc(servers, sizeof(*servers) * (num_servers + 1)); + if (s == NULL) { + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "malloc"); + dns_free_data(r); + goto fail; + } + servers = s; + num_servers++; + servers[num_servers - 1].port = rr->u.srv->port; + servers[num_servers - 1].server = strdup(rr->u.srv->target); + } + dns_free_data(r); + } + + if (num_servers == 0) { + krb5_set_error_message(context->context, KADM5_NO_SRV, "No AD server found in DNS"); + return KADM5_NO_SRV; + } + + for (i = 0; i < num_servers; i++) { + int lret, version = LDAP_VERSION3; + LDAP *lp; + + lp = ldap_init(servers[i].server, servers[i].port); + if (lp == NULL) + continue; + + if (ldap_set_option(lp, LDAP_OPT_PROTOCOL_VERSION, &version)) { + ldap_unbind(lp); + continue; + } + + if (ldap_set_option(lp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF)) { + ldap_unbind(lp); + continue; + } + +#ifdef HAVE_TSASL + lret = ldap_tsasl_bind_s(lp, NULL, NULL, NULL, servers[i].server); + +#else + lret = ldap_sasl_interactive_bind_s(lp, NULL, NULL, NULL, NULL, + LDAP_SASL_QUIET, + sasl_interact, NULL); +#endif + if (lret != LDAP_SUCCESS) { + krb5_set_error_message(context->context, 0, + "Couldn't contact any AD servers: %s", + ldap_err2string(lret)); + ldap_unbind(lp); + continue; + } + + context->ldap_conn = lp; + break; + } + if (i >= num_servers) { + goto fail; + } + + { + LDAPMessage *m, *m0; + char **attr = NULL; + int attrlen = 0; + char **vals; + int ret; + + laddattr(&attr, &attrlen, "defaultNamingContext"); + + ret = ldap_search_s(CTX2LP(context), "", LDAP_SCOPE_BASE, + "objectclass=*", attr, 0, &m); + free(attr); + if (check_ldap(context, ret)) + goto fail; + + if (ldap_count_entries(CTX2LP(context), m) > 0) { + m0 = ldap_first_entry(CTX2LP(context), m); + if (m0 == NULL) { + krb5_set_error_message(context->context, KADM5_RPC_ERROR, + "Error in AD ldap responce"); + ldap_msgfree(m); + goto fail; + } + vals = ldap_get_values(CTX2LP(context), + m0, "defaultNamingContext"); + if (vals == NULL) { + krb5_set_error_message(context->context, KADM5_RPC_ERROR, + "No naming context found"); + goto fail; + } + context->base_dn = strdup(vals[0]); + } else + goto fail; + ldap_msgfree(m); + } + + for (i = 0; i < num_servers; i++) + free(servers[i].server); + free(servers); + + return 0; + + fail: + for (i = 0; i < num_servers; i++) + free(servers[i].server); + free(servers); + + if (context->ldap_conn) { + ldap_unbind(CTX2LP(context)); + context->ldap_conn = NULL; + } + return KADM5_RPC_ERROR; +} + +#define NTTIME_EPOCH 0x019DB1DED53E8000LL + +static time_t +nt2unixtime(const char *str) +{ + unsigned long long t; + t = strtoll(str, NULL, 10); + t = ((t - NTTIME_EPOCH) / (long long)10000000); + if (t > (((time_t)(~(long long)0)) >> 1)) + return 0; + return (time_t)t; +} + +static long long +unix2nttime(time_t unix_time) +{ + long long wt; + wt = unix_time * (long long)10000000 + (long long)NTTIME_EPOCH; + return wt; +} + +/* XXX create filter in a better way */ + +static int +ad_find_entry(kadm5_ad_context *context, + const char *fqdn, + const char *pn, + char **name) +{ + LDAPMessage *m, *m0; + char *attr[] = { "distinguishedName", NULL }; + char *filter; + int ret; + + if (name) + *name = NULL; + + if (fqdn) + asprintf(&filter, + "(&(objectClass=computer)(|(dNSHostName=%s)(servicePrincipalName=%s)))", + fqdn, pn); + else if(pn) + asprintf(&filter, "(&(objectClass=account)(userPrincipalName=%s))", pn); + else + return KADM5_RPC_ERROR; + + ret = ldap_search_s(CTX2LP(context), CTX2BASE(context), + LDAP_SCOPE_SUBTREE, + filter, attr, 0, &m); + free(filter); + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + + if (ldap_count_entries(CTX2LP(context), m) > 0) { + char **vals; + m0 = ldap_first_entry(CTX2LP(context), m); + vals = ldap_get_values(CTX2LP(context), m0, "distinguishedName"); + if (vals == NULL || vals[0] == NULL) { + ldap_msgfree(m); + return KADM5_RPC_ERROR; + } + if (name) + *name = strdup(vals[0]); + ldap_msgfree(m); + } else + return KADM5_UNK_PRINC; + + return 0; +} + +#endif /* OPENLDAP */ + +static kadm5_ret_t +ad_get_cred(kadm5_ad_context *context, const char *password) +{ + kadm5_ret_t ret; + krb5_ccache cc; + char *service; + int aret; + + if (context->ccache) + return 0; + + aret = asprintf(&service, "%s/%s@%s", KRB5_TGS_NAME, + context->realm, context->realm); + if (aret == -1 || service == NULL) + return krb5_enomem(context->context); + + ret = _kadm5_c_get_cred_cache(context->context, + context->client_name, + service, + password, krb5_prompter_posix, + NULL, NULL, &cc); + free(service); + if(ret) + return ret; /* XXX */ + context->ccache = cc; + return 0; +} + +static kadm5_ret_t +kadm5_ad_chpass_principal(void *server_handle, + krb5_principal principal, + int keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + kadm5_ad_context *context = server_handle; + krb5_data result_code_string, result_string; + int result_code; + kadm5_ret_t ret; + + if (keepold) + return KADM5_KEEPOLD_NOSUPP; + + if (n_ks_tuple > 0) + return KADM5_KS_TUPLE_NOSUPP; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + krb5_data_zero (&result_code_string); + krb5_data_zero (&result_string); + + ret = krb5_set_password_using_ccache (context->context, + context->ccache, + password, + principal, + &result_code, + &result_code_string, + &result_string); + + krb5_data_free (&result_code_string); + krb5_data_free (&result_string); + + /* XXX do mapping here on error codes */ + + return ret; +} + +#ifdef OPENLDAP +static const char * +get_fqdn(krb5_context context, const krb5_principal p) +{ + const char *s, *hosttypes[] = { "host", "ldap", "gc", "cifs", "dns" }; + int i; + + s = krb5_principal_get_comp_string(context, p, 0); + if (p == NULL) + return NULL; + + for (i = 0; i < sizeof(hosttypes)/sizeof(hosttypes[0]); i++) { + if (strcasecmp(s, hosttypes[i]) == 0) + return krb5_principal_get_comp_string(context, p, 1); + } + return 0; +} +#endif + + +static kadm5_ret_t +kadm5_ad_create_principal(void *server_handle, + kadm5_principal_ent_t entry, + uint32_t mask, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + kadm5_ad_context *context = server_handle; + + /* + * KADM5_PRINC_EXPIRE_TIME + * + * return 0 || KADM5_DUP; + */ + +#ifdef OPENLDAP + LDAPMod *attrs[8], rattrs[7], *a; + char *useraccvals[2] = { NULL, NULL }, + *samvals[2], *dnsvals[2], *spnvals[5], *upnvals[2], *tv[2]; + char *ocvals_spn[] = { "top", "person", "organizationalPerson", + "user", "computer", NULL}; + char *p, *realmless_p, *p_msrealm = NULL, *dn = NULL; + const char *fqdn; + char *s, *samname = NULL, *short_spn = NULL; + int ret, i; + int32_t uf_flags = 0; + + if ((mask & KADM5_PRINCIPAL) == 0) + return KADM5_BAD_MASK; + + /* + * We should get around to implementing this... At the moment, the + * the server side API is implemented but the wire protocol has not + * been updated. + */ + if (n_ks_tuple > 0) + return KADM5_KS_TUPLE_NOSUPP; + + for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++) + attrs[i] = &rattrs[i]; + attrs[i] = NULL; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + fqdn = get_fqdn(context->context, entry->principal); + + ret = krb5_unparse_name(context->context, entry->principal, &p); + if (ret) + return ret; + + if (ad_find_entry(context, fqdn, p, NULL) == 0) { + free(p); + return KADM5_DUP; + } + + if (mask & KADM5_ATTRIBUTES) { + if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX) + uf_flags |= UF_ACCOUNTDISABLE|UF_LOCKOUT; + if ((entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH) == 0) + uf_flags |= UF_DONT_REQUIRE_PREAUTH; + if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH) + uf_flags |= UF_SMARTCARD_REQUIRED; + } + + realmless_p = strdup(p); + if (realmless_p == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + s = strrchr(realmless_p, '@'); + if (s) + *s = '\0'; + + if (fqdn) { + /* create computer account */ + asprintf(&samname, "%s$", fqdn); + if (samname == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + s = strchr(samname, '.'); + if (s) { + s[0] = '$'; + s[1] = '\0'; + } + + short_spn = strdup(p); + if (short_spn == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + s = strchr(short_spn, '.'); + if (s) { + *s = '\0'; + } else { + free(short_spn); + short_spn = NULL; + } + + p_msrealm = strdup(p); + if (p_msrealm == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + s = strrchr(p_msrealm, '@'); + if (s) { + *s = '/'; + } else { + free(p_msrealm); + p_msrealm = NULL; + } + + asprintf(&dn, "cn=%s, cn=Computers, %s", fqdn, CTX2BASE(context)); + if (dn == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + + a = &rattrs[0]; + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "objectClass"; + a->mod_values = ocvals_spn; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "userAccountControl"; + a->mod_values = useraccvals; + asprintf(&useraccvals[0], "%d", + uf_flags | + UF_PASSWD_NOT_EXPIRE | + UF_WORKSTATION_TRUST_ACCOUNT); + useraccvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "sAMAccountName"; + a->mod_values = samvals; + samvals[0] = samname; + samvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "dNSHostName"; + a->mod_values = dnsvals; + dnsvals[0] = (char *)fqdn; + dnsvals[1] = NULL; + a++; + + /* XXX add even more spn's */ + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "servicePrincipalName"; + a->mod_values = spnvals; + i = 0; + spnvals[i++] = p; + spnvals[i++] = realmless_p; + if (short_spn) + spnvals[i++] = short_spn; + if (p_msrealm) + spnvals[i++] = p_msrealm; + spnvals[i++] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "userPrincipalName"; + a->mod_values = upnvals; + upnvals[0] = p; + upnvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "accountExpires"; + a->mod_values = tv; + tv[0] = "9223372036854775807"; /* "never" */ + tv[1] = NULL; + a++; + + } else { + /* create user account */ + + a = &rattrs[0]; + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "userAccountControl"; + a->mod_values = useraccvals; + asprintf(&useraccvals[0], "%d", + uf_flags | + UF_PASSWD_NOT_EXPIRE); + useraccvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "sAMAccountName"; + a->mod_values = samvals; + samvals[0] = realmless_p; + samvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "userPrincipalName"; + a->mod_values = upnvals; + upnvals[0] = p; + upnvals[1] = NULL; + a++; + + a->mod_op = LDAP_MOD_ADD; + a->mod_type = "accountExpires"; + a->mod_values = tv; + tv[0] = "9223372036854775807"; /* "never" */ + tv[1] = NULL; + a++; + } + + attrs[a - &rattrs[0]] = NULL; + + ret = ldap_add_s(CTX2LP(context), dn, attrs); + + out: + if (useraccvals[0]) + free(useraccvals[0]); + if (realmless_p) + free(realmless_p); + if (samname) + free(samname); + if (short_spn) + free(short_spn); + if (p_msrealm) + free(p_msrealm); + free(p); + + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + + return 0; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_delete_principal(void *server_handle, krb5_principal principal) +{ + kadm5_ad_context *context = server_handle; +#ifdef OPENLDAP + char *p, *dn = NULL; + const char *fqdn; + int ret; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + fqdn = get_fqdn(context->context, principal); + + ret = krb5_unparse_name(context->context, principal, &p); + if (ret) + return ret; + + if (ad_find_entry(context, fqdn, p, &dn) != 0) { + free(p); + return KADM5_UNK_PRINC; + } + + ret = ldap_delete_s(CTX2LP(context), dn); + + free(dn); + free(p); + + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + return 0; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_destroy(void *server_handle) +{ + kadm5_ad_context *context = server_handle; + + if (context->ccache) + krb5_cc_destroy(context->context, context->ccache); + +#ifdef OPENLDAP + { + LDAP *lp = CTX2LP(context); + if (lp) + ldap_unbind(lp); + if (context->base_dn) + free(context->base_dn); + } +#endif + free(context->realm); + free(context->client_name); + krb5_free_principal(context->context, context->caller); + if(context->my_context) + krb5_free_context(context->context); + return 0; +} + +static kadm5_ret_t +kadm5_ad_flush(void *server_handle) +{ + kadm5_ad_context *context = server_handle; + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +} + +static kadm5_ret_t +kadm5_ad_get_principal(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t entry, + uint32_t mask) +{ + kadm5_ad_context *context = server_handle; +#ifdef OPENLDAP + LDAPMessage *m, *m0; + char **attr = NULL; + int attrlen = 0; + char *filter, *p, *q, *u; + int ret; + + /* + * principal + * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES + */ + + /* + * return 0 || KADM5_DUP; + */ + + memset(entry, 0, sizeof(*entry)); + + if (mask & KADM5_KVNO) + laddattr(&attr, &attrlen, "msDS-KeyVersionNumber"); + + if (mask & KADM5_PRINCIPAL) { + laddattr(&attr, &attrlen, "userPrincipalName"); + laddattr(&attr, &attrlen, "servicePrincipalName"); + } + laddattr(&attr, &attrlen, "objectClass"); + laddattr(&attr, &attrlen, "lastLogon"); + laddattr(&attr, &attrlen, "badPwdCount"); + laddattr(&attr, &attrlen, "badPasswordTime"); + laddattr(&attr, &attrlen, "pwdLastSet"); + laddattr(&attr, &attrlen, "accountExpires"); + laddattr(&attr, &attrlen, "userAccountControl"); + + krb5_unparse_name_short(context->context, principal, &p); + krb5_unparse_name(context->context, principal, &u); + + /* replace @ in domain part with a / */ + q = strrchr(p, '@'); + if (q && (p != q && *(q - 1) != '\\')) + *q = '/'; + + asprintf(&filter, + "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))", + u, p, u); + free(p); + free(u); + + ret = ldap_search_s(CTX2LP(context), CTX2BASE(context), + LDAP_SCOPE_SUBTREE, + filter, attr, 0, &m); + free(attr); + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + + if (ldap_count_entries(CTX2LP(context), m) > 0) { + char **vals; + m0 = ldap_first_entry(CTX2LP(context), m); + if (m0 == NULL) { + ldap_msgfree(m); + goto fail; + } +#if 0 + vals = ldap_get_values(CTX2LP(context), m0, "servicePrincipalName"); + if (vals) + printf("servicePrincipalName %s\n", vals[0]); + vals = ldap_get_values(CTX2LP(context), m0, "userPrincipalName"); + if (vals) + printf("userPrincipalName %s\n", vals[0]); + vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl"); + if (vals) + printf("userAccountControl %s\n", vals[0]); +#endif + entry->princ_expire_time = 0; + if (mask & KADM5_PRINC_EXPIRE_TIME) { + vals = ldap_get_values(CTX2LP(context), m0, "accountExpires"); + if (vals) + entry->princ_expire_time = nt2unixtime(vals[0]); + } + entry->last_success = 0; + if (mask & KADM5_LAST_SUCCESS) { + vals = ldap_get_values(CTX2LP(context), m0, "lastLogon"); + if (vals) + entry->last_success = nt2unixtime(vals[0]); + } + if (mask & KADM5_LAST_FAILED) { + vals = ldap_get_values(CTX2LP(context), m0, "badPasswordTime"); + if (vals) + entry->last_failed = nt2unixtime(vals[0]); + } + if (mask & KADM5_LAST_PWD_CHANGE) { + vals = ldap_get_values(CTX2LP(context), m0, "pwdLastSet"); + if (vals) + entry->last_pwd_change = nt2unixtime(vals[0]); + } + if (mask & KADM5_FAIL_AUTH_COUNT) { + vals = ldap_get_values(CTX2LP(context), m0, "badPwdCount"); + if (vals) + entry->fail_auth_count = atoi(vals[0]); + } + if (mask & KADM5_ATTRIBUTES) { + vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl"); + if (vals) { + uint32_t i; + i = atoi(vals[0]); + if (i & (UF_ACCOUNTDISABLE|UF_LOCKOUT)) + entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX; + if ((i & UF_DONT_REQUIRE_PREAUTH) == 0) + entry->attributes |= KRB5_KDB_REQUIRES_PRE_AUTH; + if (i & UF_SMARTCARD_REQUIRED) + entry->attributes |= KRB5_KDB_REQUIRES_HW_AUTH; + if ((i & UF_WORKSTATION_TRUST_ACCOUNT) == 0) + entry->attributes |= KRB5_KDB_DISALLOW_SVR; + } + } + if (mask & KADM5_KVNO) { + vals = ldap_get_values(CTX2LP(context), m0, + "msDS-KeyVersionNumber"); + if (vals) + entry->kvno = atoi(vals[0]); + else + entry->kvno = 0; + } + ldap_msgfree(m); + } else { + return KADM5_UNK_PRINC; + } + + if (mask & KADM5_PRINCIPAL) + krb5_copy_principal(context->context, principal, &entry->principal); + + return 0; + fail: + return KADM5_RPC_ERROR; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_get_principals(void *server_handle, + const char *expression, + char ***principals, + int *count) +{ + kadm5_ad_context *context = server_handle; + + /* + * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES + */ + +#ifdef OPENLDAP + kadm5_ret_t ret; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + kadm5_ad_context *context = server_handle; + +#ifdef OPENLDAP + kadm5_ret_t ret; + + ret = ad_get_cred(context, NULL); + if (ret) + return ret; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_get_privs(void *server_handle, uint32_t*privs) +{ + kadm5_ad_context *context = server_handle; + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +} + +static kadm5_ret_t +kadm5_ad_modify_principal(void *server_handle, + kadm5_principal_ent_t entry, + uint32_t mask) +{ + kadm5_ad_context *context = server_handle; + + /* + * KADM5_ATTRIBUTES + * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO) + */ + +#ifdef OPENLDAP + LDAPMessage *m = NULL, *m0; + kadm5_ret_t ret; + char **attr = NULL; + int attrlen = 0; + char *p = NULL, *s = NULL, *q; + char **vals; + LDAPMod *attrs[4], rattrs[3], *a; + char *uaf[2] = { NULL, NULL }; + char *kvno[2] = { NULL, NULL }; + char *tv[2] = { NULL, NULL }; + char *filter, *dn; + int i; + + for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++) + attrs[i] = &rattrs[i]; + attrs[i] = NULL; + a = &rattrs[0]; + + ret = _kadm5_ad_connect(server_handle); + if (ret) + return ret; + + if (mask & KADM5_KVNO) + laddattr(&attr, &attrlen, "msDS-KeyVersionNumber"); + if (mask & KADM5_PRINC_EXPIRE_TIME) + laddattr(&attr, &attrlen, "accountExpires"); + if (mask & KADM5_ATTRIBUTES) + laddattr(&attr, &attrlen, "userAccountControl"); + laddattr(&attr, &attrlen, "distinguishedName"); + + krb5_unparse_name(context->context, entry->principal, &p); + + s = strdup(p); + + q = strrchr(s, '@'); + if (q && (p != q && *(q - 1) != '\\')) + *q = '\0'; + + asprintf(&filter, + "(|(userPrincipalName=%s)(servicePrincipalName=%s))", + s, s); + free(p); + free(s); + + ret = ldap_search_s(CTX2LP(context), CTX2BASE(context), + LDAP_SCOPE_SUBTREE, + filter, attr, 0, &m); + free(attr); + free(filter); + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + + if (ldap_count_entries(CTX2LP(context), m) <= 0) { + ret = KADM5_RPC_ERROR; + goto out; + } + + m0 = ldap_first_entry(CTX2LP(context), m); + + if (mask & KADM5_ATTRIBUTES) { + int32_t i; + + vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl"); + if (vals == NULL) { + ret = KADM5_RPC_ERROR; + goto out; + } + + i = atoi(vals[0]); + if (i == 0) + return KADM5_RPC_ERROR; + + if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX) + i |= (UF_ACCOUNTDISABLE|UF_LOCKOUT); + else + i &= ~(UF_ACCOUNTDISABLE|UF_LOCKOUT); + if (entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH) + i &= ~UF_DONT_REQUIRE_PREAUTH; + else + i |= UF_DONT_REQUIRE_PREAUTH; + if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH) + i |= UF_SMARTCARD_REQUIRED; + else + i &= ~UF_SMARTCARD_REQUIRED; + if (entry->attributes & KRB5_KDB_DISALLOW_SVR) + i &= ~UF_WORKSTATION_TRUST_ACCOUNT; + else + i |= UF_WORKSTATION_TRUST_ACCOUNT; + + asprintf(&uaf[0], "%d", i); + + a->mod_op = LDAP_MOD_REPLACE; + a->mod_type = "userAccountControl"; + a->mod_values = uaf; + a++; + } + + if (mask & KADM5_KVNO) { + vals = ldap_get_values(CTX2LP(context), m0, "msDS-KeyVersionNumber"); + if (vals == NULL) { + entry->kvno = 0; + } else { + asprintf(&kvno[0], "%d", entry->kvno); + + a->mod_op = LDAP_MOD_REPLACE; + a->mod_type = "msDS-KeyVersionNumber"; + a->mod_values = kvno; + a++; + } + } + + if (mask & KADM5_PRINC_EXPIRE_TIME) { + long long wt; + vals = ldap_get_values(CTX2LP(context), m0, "accountExpires"); + if (vals == NULL) { + ret = KADM5_RPC_ERROR; + goto out; + } + + wt = unix2nttime(entry->princ_expire_time); + + asprintf(&tv[0], "%llu", wt); + + a->mod_op = LDAP_MOD_REPLACE; + a->mod_type = "accountExpires"; + a->mod_values = tv; + a++; + } + + vals = ldap_get_values(CTX2LP(context), m0, "distinguishedName"); + if (vals == NULL) { + ret = KADM5_RPC_ERROR; + goto out; + } + dn = vals[0]; + + attrs[a - &rattrs[0]] = NULL; + + ret = ldap_modify_s(CTX2LP(context), dn, attrs); + if (check_ldap(context, ret)) + return KADM5_RPC_ERROR; + + out: + if (m) + ldap_msgfree(m); + if (uaf[0]) + free(uaf[0]); + if (kvno[0]) + free(kvno[0]); + if (tv[0]) + free(tv[0]); + return ret; +#else + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +/*ARGSUSED*/ +static kadm5_ret_t +kadm5_ad_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock **keys, + int *n_keys) +{ + kadm5_ad_context *context = server_handle; + + if (keepold) + return KADM5_KEEPOLD_NOSUPP; + + /* + * random key + */ + +#ifdef OPENLDAP + krb5_data result_code_string, result_string; + int result_code, plen; + kadm5_ret_t ret; + char *password; + + *keys = NULL; + *n_keys = 0; + + { + char p[64]; + krb5_generate_random_block(p, sizeof(p)); + plen = rk_base64_encode(p, sizeof(p), &password); + if (plen < 0) + return krb5_enomem(context->context); + } + + ret = ad_get_cred(context, NULL); + if (ret) { + free(password); + return ret; + } + + krb5_data_zero(&result_code_string); + krb5_data_zero(&result_string); + + ret = krb5_set_password_using_ccache(context->context, + context->ccache, + password, + principal, + &result_code, + &result_code_string, + &result_string); + krb5_data_free(&result_code_string); + krb5_data_free(&result_string); + + if (ret) + goto out; + + *keys = malloc(sizeof(**keys) * 1); + if (*keys == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + *n_keys = 1; + + ret = krb5_string_to_key(context->context, + ENCTYPE_ARCFOUR_HMAC_MD5, + password, + principal, + &(*keys)[0]); + if (ret) { + free(*keys); + *keys = NULL; + *n_keys = 0; + goto out; + } + + out: + memset(password, 0, plen); + free(password); + return ret; +#else + *keys = NULL; + *n_keys = 0; + + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +#endif +} + +static kadm5_ret_t +kadm5_ad_rename_principal(void *server_handle, + krb5_principal from, + krb5_principal to) +{ + kadm5_ad_context *context = server_handle; + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +} + +static kadm5_ret_t +kadm5_ad_chpass_principal_with_key(void *server_handle, + krb5_principal princ, + int keepold, + int n_key_data, + krb5_key_data *key_data) +{ + kadm5_ad_context *context = server_handle; + krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented"); + return KADM5_RPC_ERROR; +} + +static kadm5_ret_t +kadm5_ad_lock(void *server_handle) +{ + return ENOTSUP; +} + +static kadm5_ret_t +kadm5_ad_unlock(void *server_handle) +{ + return ENOTSUP; +} + +static void +set_funcs(kadm5_ad_context *c) +{ +#define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F +#define SETNOTIMP(C, F) (C)->funcs.F = 0 + SET(c, chpass_principal); + SET(c, chpass_principal_with_key); + SET(c, create_principal); + SET(c, delete_principal); + SET(c, destroy); + SET(c, flush); + SET(c, get_principal); + SET(c, get_principals); + SET(c, get_privs); + SET(c, modify_principal); + SET(c, randkey_principal); + SET(c, rename_principal); + SET(c, lock); + SET(c, unlock); + SETNOTIMP(c, setkey_principal_3); + SETNOTIMP(c, prune_principal); + SET(c, iter_principals); + SET(c, dup_context); +} + +kadm5_ret_t +kadm5_ad_init_with_password_ctx(krb5_context context, + const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + kadm5_ret_t ret; + kadm5_ad_context *ctx; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return krb5_enomem(context); + memset(ctx, 0, sizeof(*ctx)); + set_funcs(ctx); + + ctx->context = context; + krb5_add_et_list (context, initialize_kadm5_error_table_r); + + ret = krb5_parse_name(ctx->context, client_name, &ctx->caller); + if(ret) { + free(ctx); + return ret; + } + + if(realm_params->mask & KADM5_CONFIG_REALM) { + ret = 0; + ctx->realm = strdup(realm_params->realm); + if (ctx->realm == NULL) + ret = krb5_enomem(context); + } else + ret = krb5_get_default_realm(ctx->context, &ctx->realm); + if (ret) { + free(ctx); + return ret; + } + + ctx->client_name = strdup(client_name); + + if(password != NULL && *password != '\0') + ret = ad_get_cred(ctx, password); + else + ret = ad_get_cred(ctx, NULL); + if(ret) { + kadm5_ad_destroy(ctx); + free(ctx); + return ret; + } + +#ifdef OPENLDAP + ret = _kadm5_ad_connect(ctx); + if (ret) { + kadm5_ad_destroy(ctx); + free(ctx); + return ret; + } +#endif + + *server_handle = ctx; + return 0; +} + +kadm5_ret_t +kadm5_ad_dup_context(void *in, void **out) +{ + return ENOTSUP; +} + +kadm5_ret_t +kadm5_ad_init_with_password(const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + krb5_context context; + kadm5_ret_t ret; + kadm5_ad_context *ctx; + + ret = krb5_init_context(&context); + if (ret) + return ret; + ret = kadm5_ad_init_with_password_ctx(context, + client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); + if(ret) { + krb5_free_context(context); + return ret; + } + ctx = *server_handle; + ctx->my_context = 1; + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/admin.h b/third_party/heimdal/lib/kadm5/admin.h new file mode 100644 index 0000000..530070c --- /dev/null +++ b/third_party/heimdal/lib/kadm5/admin.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 1997-2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* $Id$ */ + +#ifndef __KADM5_ADMIN_H__ +#define __KADM5_ADMIN_H__ + +#define KADM5_API_VERSION_1 1 +#define KADM5_API_VERSION_2 2 + +#ifndef USE_KADM5_API_VERSION +#define USE_KADM5_API_VERSION KADM5_API_VERSION_2 +#endif + +#if USE_KADM5_API_VERSION != KADM5_API_VERSION_2 +#error No support for API versions other than 2 +#endif + +#define KADM5_STRUCT_VERSION 0 + +/* For kadm5_log_get_version_fd() */ +#define LOG_VERSION_LAST -1 +#define LOG_VERSION_FIRST 1 +#define LOG_VERSION_UBER 0 + +#include + +#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 +#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 +#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 +#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 +#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 +#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 +#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 +#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 +#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 +#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 +#define KRB5_KDB_DISALLOW_SVR 0x00001000 +#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 +#define KRB5_KDB_SUPPORT_DESMD5 0x00004000 +#define KRB5_KDB_NEW_PRINC 0x00008000 +#define KRB5_KDB_OK_AS_DELEGATE 0x00010000 /* 0x00100000 in MIT */ +#define KRB5_KDB_TRUSTED_FOR_DELEGATION 0x00020000 /* MIT has as 0x00200000 */ +#define KRB5_KDB_ALLOW_KERBEROS4 0x00040000 /* MIT doesn't have this; XXX remove */ +#define KRB5_KDB_ALLOW_DIGEST 0x00080000 /* MIT doesn't have this */ +#define KRB5_KDB_MATERIALIZE 0x00100000 /* MIT doesn't have this */ +#define KRB5_KDB_VIRTUAL_KEYS 0x00200000 /* MIT doesn't have this */ +#define KRB5_KDB_VIRTUAL 0x00400000 /* MIT doesn't have this */ +#define KRB5_KDB_DISALLOW_CLIENT 0x00800000 /* MIT doesn't have this */ +#define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x01000000 /* 0x00400000 in MIT */ +#define KRB5_KDB_AUTH_DATA_REQUIRED 0x02000000 + +/* + * MIT has: + * + * - Same as our KRB5_KDB_TRUSTED_FOR_DELEGATION: + * + * #define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE 0x00200000 // S4U2Self OK + * + * - Misc: + * + * #define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x00400000 // Don't lookup / add + * // authz data + * #define KRB5_KDB_LOCKDOWN_KEYS 0x00800000 // Don't allow + * // deletion of princ + */ + + +#define KADM5_PRINCIPAL 0x000001U +#define KADM5_PRINC_EXPIRE_TIME 0x000002U +#define KADM5_PW_EXPIRATION 0x000004U +#define KADM5_LAST_PWD_CHANGE 0x000008U +#define KADM5_ATTRIBUTES 0x000010U +#define KADM5_MAX_LIFE 0x000020U +#define KADM5_MOD_TIME 0x000040U +#define KADM5_MOD_NAME 0x000080U +#define KADM5_KVNO 0x000100U +#define KADM5_MKVNO 0x000200U +#define KADM5_AUX_ATTRIBUTES 0x000400U +#define KADM5_POLICY 0x000800U +#define KADM5_POLICY_CLR 0x001000U +#define KADM5_MAX_RLIFE 0x002000U +#define KADM5_LAST_SUCCESS 0x004000U +#define KADM5_LAST_FAILED 0x008000U +#define KADM5_FAIL_AUTH_COUNT 0x010000U +#define KADM5_KEY_DATA 0x020000U +#define KADM5_TL_DATA 0x040000U + +#define KADM5_PRINCIPAL_NORMAL_MASK (~(KADM5_KEY_DATA | KADM5_TL_DATA)) + +#define KADM5_PW_MAX_LIFE 0x004000 +#define KADM5_PW_MIN_LIFE 0x008000 +#define KADM5_PW_MIN_LENGTH 0x010000 +#define KADM5_PW_MIN_CLASSES 0x020000 +#define KADM5_PW_HISTORY_NUM 0x040000 +#define KADM5_REF_COUNT 0x080000 + +#define KADM5_POLICY_NORMAL_MASK (~0) + +#define KADM5_ADMIN_SERVICE "kadmin/admin" +#define KADM5_HIST_PRINCIPAL "kadmin/history" +#define KADM5_CHANGEPW_SERVICE "kadmin/changepw" + +typedef struct { + int16_t key_data_ver; /* Version */ + int16_t key_data_kvno; /* Key Version */ + int16_t key_data_type[2]; /* Array of types */ + int16_t key_data_length[2]; /* Array of lengths */ + void* key_data_contents[2];/* Array of pointers */ +} krb5_key_data; + +typedef struct _krb5_keysalt { + int16_t type; + krb5_data data; /* Length, data */ +} krb5_keysalt; + +typedef struct _krb5_tl_data { + struct _krb5_tl_data* tl_data_next; + int16_t tl_data_type; + int16_t tl_data_length; + void* tl_data_contents; +} krb5_tl_data; + +#define KRB5_TL_LAST_PWD_CHANGE 0x0001 +#define KRB5_TL_MOD_PRINC 0x0002 +#define KRB5_TL_KADM_DATA 0x0003 +#define KRB5_TL_KADM5_E_DATA 0x0004 +#define KRB5_TL_RB1_CHALLENGE 0x0005 +#define KRB5_TL_SECURID_STATE 0x0006 +#define KRB5_TL_PASSWORD 0x0007 +#define KRB5_TL_EXTENSION 0x0008 +#define KRB5_TL_PKINIT_ACL 0x0009 +#define KRB5_TL_ALIASES 0x000a +#define KRB5_TL_HIST_KVNO_DIFF_CLNT 0x000b +#define KRB5_TL_HIST_KVNO_DIFF_SVC 0x000c +#define KRB5_TL_ETYPES 0x000d +#define KRB5_TL_KEY_ROTATION 0x000e +#define KRB5_TL_KRB5_CONFIG 0x000f + +typedef struct _kadm5_principal_ent_t { + krb5_principal principal; + + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + krb5_kvno mkvno; + + char * policy; + uint32_t aux_attributes; + + krb5_deltat max_renewable_life; + krb5_timestamp last_success; + krb5_timestamp last_failed; + krb5_kvno fail_auth_count; + int16_t n_key_data; + int16_t n_tl_data; + krb5_tl_data *tl_data; + krb5_key_data *key_data; +} kadm5_principal_ent_rec, *kadm5_principal_ent_t; + +typedef struct _kadm5_policy_ent_t { + char *policy; + + uint32_t pw_min_life; + uint32_t pw_max_life; + uint32_t pw_min_length; + uint32_t pw_min_classes; + uint32_t pw_history_num; + uint32_t policy_refcnt; +} kadm5_policy_ent_rec, *kadm5_policy_ent_t; + +#define KADM5_CONFIG_REALM (1 << 0) +#define KADM5_CONFIG_PROFILE (1 << 1) +#define KADM5_CONFIG_KADMIND_PORT (1 << 2) +#define KADM5_CONFIG_ADMIN_SERVER (1 << 3) +#define KADM5_CONFIG_DBNAME (1 << 4) +#define KADM5_CONFIG_ADBNAME (1 << 5) +#define KADM5_CONFIG_ADB_LOCKFILE (1 << 6) +#define KADM5_CONFIG_ACL_FILE (1 << 7) +#define KADM5_CONFIG_DICT_FILE (1 << 8) +#define KADM5_CONFIG_ADMIN_KEYTAB (1 << 9) +#define KADM5_CONFIG_MKEY_FROM_KEYBOARD (1 << 10) +#define KADM5_CONFIG_STASH_FILE (1 << 11) +#define KADM5_CONFIG_MKEY_NAME (1 << 12) +#define KADM5_CONFIG_ENCTYPE (1 << 13) +#define KADM5_CONFIG_MAX_LIFE (1 << 14) +#define KADM5_CONFIG_MAX_RLIFE (1 << 15) +#define KADM5_CONFIG_EXPIRATION (1 << 16) +#define KADM5_CONFIG_FLAGS (1 << 17) +#define KADM5_CONFIG_ENCTYPES (1 << 18) +#define KADM5_CONFIG_READONLY_ADMIN_SERVER (1 << 19) +#define KADM5_CONFIG_READONLY_KADMIN_PORT (1 << 20) + +#define KADM5_PRIV_GET (1 << 0) +#define KADM5_PRIV_ADD (1 << 1) +#define KADM5_PRIV_MODIFY (1 << 2) +#define KADM5_PRIV_DELETE (1 << 3) +#define KADM5_PRIV_LIST (1 << 4) +#define KADM5_PRIV_CPW (1 << 5) +#define KADM5_PRIV_GET_KEYS (1 << 6) + +/* Note: KADM5_PRIV_GET_KEYS not included */ +#define KADM5_PRIV_ALL (KADM5_PRIV_GET | KADM5_PRIV_ADD | KADM5_PRIV_MODIFY | KADM5_PRIV_DELETE | KADM5_PRIV_LIST | KADM5_PRIV_CPW) + +#define KADM5_BOGUS_KEY_DATA "\xe5\xe5\xe5\xe5" + +/* + * ABI NOTE: We can add fields at the end of this provided that we define new + * mask bits that must be set in the mask field when setting the new fields. + */ +typedef struct _kadm5_config_params { + uint32_t mask; + + /* Client and server fields */ + char *realm; + int kadmind_port; + + /* client fields */ + char *admin_server; + + /* server fields */ + char *dbname; + char *acl_file; + + /* server library (database) fields */ + char *stash_file; + + /* read-only kadmin server */ + char *readonly_admin_server; + int readonly_kadmind_port; +} kadm5_config_params; + +typedef krb5_error_code kadm5_ret_t; + +#include "kadm5-protos.h" + +#endif /* __KADM5_ADMIN_H__ */ diff --git a/third_party/heimdal/lib/kadm5/bump_pw_expire.c b/third_party/heimdal/lib/kadm5/bump_pw_expire.c new file mode 100644 index 0000000..1938c75 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/bump_pw_expire.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +/* + * extend password_expiration if it's defined + */ + +kadm5_ret_t +_kadm5_bump_pw_expire(kadm5_server_context *context, + hdb_entry *ent) +{ + if (ent->pw_end != NULL) { + time_t life; + + life = krb5_config_get_time_default(context->context, + NULL, + 365 * 24 * 60 * 60, + "kadmin", + "password_lifetime", + NULL); + + if (life != 0) + *(ent->pw_end) = time(NULL) + life; + else { + free(ent->pw_end); + ent->pw_end = NULL; + } + } + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/check-cracklib.pl b/third_party/heimdal/lib/kadm5/check-cracklib.pl new file mode 100644 index 0000000..a6fbd4c --- /dev/null +++ b/third_party/heimdal/lib/kadm5/check-cracklib.pl @@ -0,0 +1,112 @@ +#!/usr/pkg/bin/perl +# +# Sample password verifier for Heimdals external password +# verifier, see the chapter "Password changing" in the the info +# documentation for more information about the protocol used. +# +# Three checks +# 1. Check that password is not the principal name +# 2. Check that the password passes cracklib +# 3. Check that password isn't repeated for this principal +# +# The repeat check must be last because some clients ask +# twice when getting "no" back and thus the error message +# would be wrong. +# +# Prereqs (example versions): +# +# * perl (5.8.5) http://www.perl.org/ +# * cracklib (2.8.5) http://sourceforge.net/projects/cracklib +# * Crypt-Cracklib perlmodule (0.01) http://search.cpan.org/~daniel/ +# +# Sample dictionaries: +# cracklib-words (1.1) http://sourceforge.net/projects/cracklib +# miscfiles (1.4.2) http://directory.fsf.org/miscfiles.html +# +# Configuration for krb5.conf or kdc.conf +# +# [password_quality] +# policies = builtin:external-check +# external_program = /check-cracklib.pl +# +# $Id$ + +use strict; +use Crypt::Cracklib; +use Digest::MD5; + +# NEED TO CHANGE THESE TO MATCH YOUR SYSTEM +my $database = '/usr/lib/cracklib_dict'; +my $historydb = '/var/heimdal/historydb'; +# NEED TO CHANGE THESE TO MATCH YOUR SYSTEM + +# seconds password reuse allowed (to catch retries from clients) +my $reusetime = 60; + +my %params; + +sub check_basic +{ + my $principal = shift; + my $passwd = shift; + + if ($principal eq $passwd) { + return "Principal name as password is not allowed"; + } + return "ok"; +} + +sub check_repeat +{ + my $principal = shift; + my $passwd = shift; + my $result = 'Do not reuse passwords'; + my %DB; + my $md5context = new Digest::MD5; + my $timenow = scalar(time()); + + $md5context->reset(); + $md5context->add($principal, ":", $passwd); + + my $key=$md5context->hexdigest(); + + dbmopen(%DB,$historydb,0600) or die "Internal: Could not open $historydb"; + if (!$DB{$key} || ($timenow - $DB{$key} < $reusetime)) { + $result = "ok"; + $DB{$key}=$timenow; + } + dbmclose(%DB) or die "Internal: Could not close $historydb"; + return $result; +} + +sub badpassword +{ + my $reason = shift; + print "$reason\n"; + exit 0 +} + +while () { + last if /^end$/; + if (!/^([^:]+): (.+)$/) { + die "key value pair not correct: $_"; + } + $params{$1} = $2; +} + +die "missing principal" if (!defined $params{'principal'}); +die "missing password" if (!defined $params{'new-password'}); + +my $reason; + +$reason = check_basic($params{'principal'}, $params{'new-password'}); +badpassword($reason) if ($reason ne "ok"); + +$reason = fascist_check($params{'new-password'}, $database); +badpassword($reason) if ($reason ne "ok"); + +$reason = check_repeat($params{'principal'}, $params{'new-password'}); +badpassword($reason) if ($reason ne "ok"); + +print "APPROVED\n"; +exit 0 diff --git a/third_party/heimdal/lib/kadm5/chpass_c.c b/third_party/heimdal/lib/kadm5/chpass_c.c new file mode 100644 index 0000000..1036918 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/chpass_c.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1997-2000, 2005-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_chpass_principal(void *server_handle, + krb5_principal princ, + int keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + /* + * We should get around to implementing this... At the moment, the + * the server side API is implemented but the wire protocol has not + * been updated. + */ + if (n_ks_tuple > 0) + return KADM5_KS_TUPLE_NOSUPP; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_chpass); + if (ret) + goto out; + ret = krb5_store_principal(sp, princ); + if (ret) + goto out; + ret = krb5_store_string(sp, password); + if (ret) + goto out; + ret = krb5_store_int32(sp, keepold); /* extension */ + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} + +kadm5_ret_t +kadm5_c_chpass_principal_with_key(void *server_handle, + krb5_principal princ, + int keepold, + int n_key_data, + krb5_key_data *key_data) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + int i; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_chpass_with_key); + if (ret) + goto out; + ret = krb5_store_principal(sp, princ); + if (ret) + goto out; + ret = krb5_store_int32(sp, n_key_data); + if (ret) + goto out; + for (i = 0; i < n_key_data; ++i) { + ret = kadm5_store_key_data (sp, &key_data[i]); + if (ret) + goto out; + } + ret = krb5_store_int32(sp, keepold); /* extension */ + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data (&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/chpass_s.c b/third_party/heimdal/lib/kadm5/chpass_s.c new file mode 100644 index 0000000..c89448f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/chpass_s.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct chpass_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; + uint32_t flags; + size_t n_ks_tuple; + krb5_key_salt_tuple *ks_tuple; + const char *password; +}; + +static krb5_error_code KRB5_LIB_CALL +chpass_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct chpass_principal_hook_ctx *ctx = userctx; + + ret = ftable->chpass(context, hookctx, + ctx->stage, ctx->code, ctx->princ, + ctx->flags, ctx->n_ks_tuple, ctx->ks_tuple, + ctx->password); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "chpass", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +chpass_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + krb5_error_code ret; + struct chpass_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.flags = flags; + ctx.n_ks_tuple = n_ks_tuple; + ctx.ks_tuple = ks_tuple; + ctx.password = password; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, chpass_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +static kadm5_ret_t +change(void *server_handle, + krb5_principal princ, + int keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password, + int cond) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret; + Key *keys; + size_t num_keys; + int existsp = 0; + uint32_t hook_flags = 0; + + memset(&ent, 0, sizeof(ent)); + + if (krb5_principal_compare(context->context, princ, context->caller) || + _kadm5_enforce_pwqual_on_admin_set_p(context)) { + krb5_data pwd_data; + const char *pwd_reason; + + pwd_data.data = rk_UNCONST(password); + pwd_data.length = strlen(password); + + pwd_reason = kadm5_check_password_quality(context->context, + princ, &pwd_data); + if (pwd_reason != NULL) { + krb5_set_error_message(context->context, KADM5_PASS_Q_GENERIC, "%s", pwd_reason); + return KADM5_PASS_Q_GENERIC; + } + } + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret) + goto out2; + + if (keepold) + hook_flags |= KADM5_HOOK_FLAG_KEEPOLD; + if (cond) + hook_flags |= KADM5_HOOK_FLAG_CONDITIONAL; + ret = chpass_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, hook_flags, + n_ks_tuple, ks_tuple, password); + if (ret) + goto out3; + + if (keepold || cond) { + /* + * We save these for now so we can handle password history checking; + * we handle keepold further below. + */ + ret = hdb_add_current_keys_to_history(context->context, &ent); + if (ret) + goto out3; + } + + if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) { + ret = context->db->hdb_password(context->context, context->db, + &ent, password, cond); + if (ret) + goto out3; + } else { + + num_keys = ent.keys.len; + keys = ent.keys.val; + + ent.keys.len = 0; + ent.keys.val = NULL; + + ret = _kadm5_set_keys(context, &ent, n_ks_tuple, ks_tuple, + password); + if(ret) { + _kadm5_free_keys(context->context, num_keys, keys); + goto out3; + } + _kadm5_free_keys(context->context, num_keys, keys); + + if (cond) { + HDB_extension *ext; + + ext = hdb_find_extension(&ent, choice_HDB_extension_data_hist_keys); + if (ext != NULL) + existsp = _kadm5_exists_keys_hist(ent.keys.val, + ent.keys.len, + &ext->data.u.hist_keys); + } + + if (existsp) { + ret = KADM5_PASS_REUSE; + krb5_set_error_message(context->context, ret, + "Password reuse forbidden"); + goto out3; + } + } + ent.kvno++; + + ent.flags.require_pwchange = 0; + + if (!keepold) { + HDB_extension ext; + + memset(&ext, 0, sizeof (ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_keys; + ret = hdb_replace_extension(context->context, &ent, &ext); + if (ret) + goto out3; + } + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + + ret = _kadm5_set_modifier(context, &ent); + if(ret) + goto out3; + + ret = _kadm5_bump_pw_expire(context, &ent); + if (ret) + goto out3; + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_modify(context, &ent, + KADM5_ATTRIBUTES | KADM5_PRINCIPAL | + KADM5_MOD_NAME | KADM5_MOD_TIME | + KADM5_KEY_DATA | KADM5_KVNO | + KADM5_PW_EXPIRATION | KADM5_TL_DATA); + + (void) chpass_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, hook_flags, + n_ks_tuple, ks_tuple, password); + + out3: + hdb_free_entry(context->context, context->db, &ent); + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} + + + +/* + * change the password of `princ' to `password' if it's not already that. + */ + +kadm5_ret_t +kadm5_s_chpass_principal_cond(void *server_handle, + krb5_principal princ, + int keepold, + const char *password) +{ + return change (server_handle, princ, keepold, 0, NULL, password, 1); +} + +/* + * change the password of `princ' to `password' + */ + +kadm5_ret_t +kadm5_s_chpass_principal(void *server_handle, + krb5_principal princ, + int keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + return change (server_handle, princ, keepold, + n_ks_tuple, ks_tuple, password, 0); +} + +struct chpass_principal_with_key_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; + uint32_t flags; + size_t n_key_data; + krb5_key_data *key_data; +}; + +static krb5_error_code KRB5_LIB_CALL +chpass_principal_with_key_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct chpass_principal_with_key_hook_ctx *ctx = userctx; + + ret = ftable->chpass_with_key(context, hookctx, + ctx->stage, ctx->code, ctx->princ, + ctx->flags, ctx->n_key_data, ctx->key_data); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "chpass_with_key", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +chpass_principal_with_key_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_key_data, + krb5_key_data *key_data) +{ + krb5_error_code ret; + struct chpass_principal_with_key_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.flags = flags; + ctx.n_key_data = n_key_data; + ctx.key_data = key_data; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, chpass_principal_with_key_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +/* + * change keys for `princ' to `keys' + */ + +kadm5_ret_t +kadm5_s_chpass_principal_with_key(void *server_handle, + krb5_principal princ, + int keepold, + int n_key_data, + krb5_key_data *key_data) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret; + uint32_t hook_flags = 0; + + memset(&ent, 0, sizeof(ent)); + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); + if (ret == HDB_ERR_NOENTRY) + goto out2; + + if (keepold) + hook_flags |= KADM5_HOOK_FLAG_KEEPOLD; + ret = chpass_principal_with_key_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, hook_flags, + n_key_data, key_data); + if (ret) + goto out3; + + if (keepold) { + ret = hdb_add_current_keys_to_history(context->context, &ent); + if (ret) + goto out3; + } + ret = _kadm5_set_keys2(context, &ent, n_key_data, key_data); + if (ret) + goto out3; + ent.kvno++; + ret = _kadm5_set_modifier(context, &ent); + if (ret) + goto out3; + ret = _kadm5_bump_pw_expire(context, &ent); + if (ret) + goto out3; + + if (keepold) { + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + } else { + HDB_extension ext; + + memset(&ext, 0, sizeof (ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_keys; + ext.data.u.hist_keys.len = 0; + ext.data.u.hist_keys.val = NULL; + hdb_replace_extension(context->context, &ent, &ext); + } + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_modify(context, &ent, + KADM5_PRINCIPAL | KADM5_MOD_NAME | + KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | + KADM5_PW_EXPIRATION | KADM5_TL_DATA); + + (void) chpass_principal_with_key_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, hook_flags, + n_key_data, key_data); + + out3: + hdb_free_entry(context->context, context->db, &ent); + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} + +/* + * Returns TRUE if password quality should be checked when passwords are + * being set or changed by administrators. This includes principal creation. + */ +krb5_boolean +_kadm5_enforce_pwqual_on_admin_set_p(kadm5_server_context *contextp) +{ + if (_kadm5_is_kadmin_service_p(contextp)) + return FALSE; + + return krb5_config_get_bool_default(contextp->context, NULL, TRUE, + "password_quality", + "enforce_on_admin_set", NULL); +} diff --git a/third_party/heimdal/lib/kadm5/client_glue.c b/third_party/heimdal/lib/kadm5/client_glue.c new file mode 100644 index 0000000..2783a9a --- /dev/null +++ b/third_party/heimdal/lib/kadm5/client_glue.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_init_with_password(const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_password(client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_password_ctx(krb5_context context, + const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_password_ctx(context, + client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_skey(const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_skey(client_name, + keytab, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_skey_ctx(krb5_context context, + const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_skey_ctx(context, + client_name, + keytab, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_creds(const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_creds(client_name, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_creds_ctx(krb5_context context, + const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_creds_ctx(context, + client_name, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} diff --git a/third_party/heimdal/lib/kadm5/common_glue.c b/third_party/heimdal/lib/kadm5/common_glue.c new file mode 100644 index 0000000..210bf93 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/common_glue.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +#define __CALL(F, P) (*((kadm5_common_context*)server_handle)->funcs.F)P +#define __CALLABLE(F) (((kadm5_common_context*)server_handle)->funcs.F != 0) + +kadm5_ret_t +kadm5_dup_context(void *server_handle, void **dup_server_handle) +{ + return __CALL(dup_context, (server_handle, dup_server_handle)); +} + +kadm5_ret_t +kadm5_chpass_principal(void *server_handle, + krb5_principal princ, + const char *password) +{ + return __CALL(chpass_principal, (server_handle, princ, 0, + 0, NULL, password)); +} + +kadm5_ret_t +kadm5_chpass_principal_3(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + return __CALL(chpass_principal, (server_handle, princ, keepold, + n_ks_tuple, ks_tuple, password)); +} + +kadm5_ret_t +kadm5_chpass_principal_with_key(void *server_handle, + krb5_principal princ, + int n_key_data, + krb5_key_data *key_data) +{ + return __CALL(chpass_principal_with_key, + (server_handle, princ, 0, n_key_data, key_data)); +} + +kadm5_ret_t +kadm5_chpass_principal_with_key_3(void *server_handle, + krb5_principal princ, + int keepold, + int n_key_data, + krb5_key_data *key_data) +{ + return __CALL(chpass_principal_with_key, + (server_handle, princ, keepold, n_key_data, key_data)); +} + +kadm5_ret_t +kadm5_create_principal_3(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + char *password) +{ + return __CALL(create_principal, + (server_handle, princ, mask, n_ks_tuple, ks_tuple, password)); +} + +kadm5_ret_t +kadm5_create_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask, + const char *password) +{ + return __CALL(create_principal, + (server_handle, princ, mask, 0, NULL, password)); +} + +kadm5_ret_t +kadm5_delete_principal(void *server_handle, + krb5_principal princ) +{ + return __CALL(delete_principal, (server_handle, princ)); +} + +kadm5_ret_t +kadm5_destroy (void *server_handle) +{ + return __CALL(destroy, (server_handle)); +} + +kadm5_ret_t +kadm5_flush (void *server_handle) +{ + return __CALL(flush, (server_handle)); +} + +kadm5_ret_t +kadm5_get_principal(void *server_handle, + krb5_principal princ, + kadm5_principal_ent_t out, + uint32_t mask) +{ + return __CALL(get_principal, (server_handle, princ, out, mask)); +} + +/** + * Extract decrypted keys from kadm5_principal_ent_t object. Mostly a + * no-op for Heimdal because we fetch the entry with decrypted keys. + * Sadly this is not fully a no-op, as we have to allocate a copy. + * + * @server_handle is the kadm5 handle + * @entry is the HDB entry for the principal in question + * @ktype is the enctype to get a key for, or -1 to get the first one + * @stype is the salttype to get a key for, or -1 to get the first match + * @kvno is the kvno to search for, or -1 to get the first match (highest kvno) + * @keyblock is where the key will be placed + * @keysalt, if not NULL, is where the salt will be placed + * @kvnop, if not NULL, is where the selected kvno will be placed + */ +kadm5_ret_t +kadm5_decrypt_key(void *server_handle, + kadm5_principal_ent_t entry, + int32_t ktype, int32_t stype, + int32_t kvno, krb5_keyblock *keyblock, + krb5_keysalt *keysalt, int *kvnop) +{ + size_t i; + kadm5_server_context *context = server_handle; + + if (kvno < 1 || stype != -1) + return KADM5_DECRYPT_USAGE_NOSUPP; + + for (i = 0; i < entry->n_key_data; i++) { + if (ktype != entry->key_data[i].key_data_kvno) + continue; + + keyblock->keytype = ktype; + keyblock->keyvalue.length = entry->key_data[i].key_data_length[0]; + keyblock->keyvalue.data = malloc(keyblock->keyvalue.length); + if (keyblock->keyvalue.data == NULL) + return krb5_enomem(context->context); + memcpy(keyblock->keyvalue.data, + entry->key_data[i].key_data_contents[0], + keyblock->keyvalue.length); + } + + return 0; +} + +kadm5_ret_t +kadm5_modify_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + return __CALL(modify_principal, (server_handle, princ, mask)); +} + +kadm5_ret_t +kadm5_randkey_principal(void *server_handle, + krb5_principal princ, + krb5_keyblock **new_keys, + int *n_keys) +{ + return __CALL(randkey_principal, (server_handle, princ, FALSE, 0, NULL, + new_keys, n_keys)); +} + +kadm5_ret_t +kadm5_randkey_principal_3(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock **new_keys, + int *n_keys) +{ + return __CALL(randkey_principal, (server_handle, princ, keepold, + n_ks_tuple, ks_tuple, new_keys, n_keys)); +} + +kadm5_ret_t +kadm5_rename_principal(void *server_handle, + krb5_principal source, + krb5_principal target) +{ + return __CALL(rename_principal, (server_handle, source, target)); +} + +kadm5_ret_t +kadm5_get_principals(void *server_handle, + const char *expression, + char ***princs, + int *count) +{ + return __CALL(get_principals, (server_handle, expression, princs, count)); +} + +kadm5_ret_t +kadm5_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + return __CALL(iter_principals, (server_handle, expression, cb, cbdata)); +} + +kadm5_ret_t +kadm5_get_privs(void *server_handle, + uint32_t *privs) +{ + return __CALL(get_privs, (server_handle, privs)); +} + + +/** + * This function is allows the caller to set new keys for a principal. + * This is a trivial wrapper around kadm5_setkey_principal_3(). + */ +kadm5_ret_t +kadm5_setkey_principal(void *server_handle, + krb5_principal princ, + krb5_keyblock *new_keys, + int n_keys) +{ + return kadm5_setkey_principal_3(server_handle, princ, 0, 0, NULL, + new_keys, n_keys); +} + +/** + * This function is allows the caller to set new keys for a principal. + * This is a simple wrapper around kadm5_get_principal() and + * kadm5_modify_principal(). + */ +kadm5_ret_t +kadm5_setkey_principal_3(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, + krb5_keyblock *keyblocks, + int n_keys) +{ + kadm5_principal_ent_rec princ_ent; + kadm5_ret_t ret; + krb5_key_data *new_key_data = NULL; + size_t i; + kadm5_server_context *context = server_handle; + + if (n_keys < 1) + return EINVAL; + if (n_ks_tuple > 0 && n_ks_tuple != n_keys) + return KADM5_SETKEY3_ETYPE_MISMATCH; + + /* + * If setkey_principal_3 is defined in the server handle, use that. + */ + if (__CALLABLE(setkey_principal_3)) + return __CALL(setkey_principal_3, + (server_handle, princ, keepold, n_ks_tuple, ks_tuple, + keyblocks, n_keys)); + + /* + * Otherwise, simulate it via a get, update, modify sequence. + */ + ret = kadm5_get_principal(server_handle, princ, &princ_ent, + KADM5_KVNO | KADM5_PRINCIPAL | KADM5_KEY_DATA); + if (ret) + return ret; + + if (keepold) { + new_key_data = calloc((n_keys + princ_ent.n_key_data), + sizeof(*new_key_data)); + if (new_key_data == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + + memcpy(&new_key_data[n_keys], &princ_ent.key_data[0], + princ_ent.n_key_data * sizeof (princ_ent.key_data[0])); + } else { + new_key_data = calloc(n_keys, sizeof(*new_key_data)); + if (new_key_data == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + + princ_ent.kvno++; + for (i = 0; i < n_keys; i++) { + new_key_data[i].key_data_ver = 2; + + /* Key */ + new_key_data[i].key_data_kvno = princ_ent.kvno; + new_key_data[i].key_data_type[0] = keyblocks[i].keytype; + new_key_data[i].key_data_length[0] = keyblocks[i].keyvalue.length; + new_key_data[i].key_data_contents[0] = + malloc(keyblocks[i].keyvalue.length); + if (new_key_data[i].key_data_contents[0] == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + memcpy(new_key_data[i].key_data_contents[0], + keyblocks[i].keyvalue.data, + keyblocks[i].keyvalue.length); + + /* + * Salt (but there's no salt, just salttype, which is kinda + * silly -- what's the point of setkey_3() then, besides + * keepold?!) + */ + new_key_data[i].key_data_type[1] = 0; + if (n_ks_tuple > 0) { + if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) { + ret = KADM5_SETKEY3_ETYPE_MISMATCH; + goto out; + } + new_key_data[i].key_data_type[1] = ks_tuple[i].ks_salttype; + } + new_key_data[i].key_data_length[1] = 0; + new_key_data[i].key_data_contents[1] = NULL; + } + + /* Free old keys */ + if (!keepold) { + for (i = 0; i < princ_ent.n_key_data; i++) { + free(princ_ent.key_data[i].key_data_contents[0]); + free(princ_ent.key_data[i].key_data_contents[1]); + } + } + free(princ_ent.key_data); + princ_ent.key_data = new_key_data; + princ_ent.n_key_data = n_keys + (keepold ? princ_ent.n_key_data : 0); + new_key_data = NULL; + + /* Modify the principal */ + ret = kadm5_modify_principal(server_handle, &princ_ent, KADM5_KVNO | KADM5_KEY_DATA); + +out: + if (new_key_data != NULL) { + for (i = 0; i < n_keys; i++) { + free(new_key_data[i].key_data_contents[0]); + free(new_key_data[i].key_data_contents[1]); + } + free(new_key_data); + } + kadm5_free_principal_ent(server_handle, &princ_ent); + return ret; +} + + +kadm5_ret_t +kadm5_lock(void *server_handle) +{ + return __CALL(lock, (server_handle)); +} + +kadm5_ret_t +kadm5_unlock(void *server_handle) +{ + return __CALL(unlock, (server_handle)); +} + + +kadm5_ret_t +kadm5_create_policy(void *server_handle, + kadm5_policy_ent_t policy, long mask) +{ + return KADM5_POLICY_OP_NOSUPP; +} + +kadm5_ret_t +kadm5_delete_policy(void *server_handle, char *name) +{ + return KADM5_POLICY_OP_NOSUPP; +} + + +kadm5_ret_t +kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t policy, + uint32_t mask) +{ + return KADM5_POLICY_OP_NOSUPP; +} + +kadm5_ret_t +kadm5_get_policy(void *server_handle, char *policy, kadm5_policy_ent_t ent) +{ + memset(ent, 0, sizeof (*ent)); + return KADM5_POLICY_OP_NOSUPP; +} + + +kadm5_ret_t +kadm5_get_policies(void *server_handle, char *exp, char ***pols, int *count) +{ + *count = 0; + *pols = NULL; + + return KADM5_POLICY_OP_NOSUPP; +} + +kadm5_ret_t +kadm5_free_policy_ent(kadm5_policy_ent_t ent) +{ + if (ent->policy) + free(ent->policy); + /* + * Not clear if we should free ent or not. It might be an automatic + * struct, so we don't free it for now, just in case. + */ + return 0; +} + +kadm5_ret_t +kadm5_prune_principal(void *server_handle, + krb5_principal princ, + int kvno) +{ + return __CALL(prune_principal, (server_handle, princ, kvno)); +} diff --git a/third_party/heimdal/lib/kadm5/context_s.c b/third_party/heimdal/lib/kadm5/context_s.c new file mode 100644 index 0000000..5c9b3e3 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/context_s.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +static kadm5_ret_t +kadm5_s_lock(void *server_handle) +{ + kadm5_server_context *context = server_handle; + kadm5_ret_t ret; + + if (context->keep_open) { + /* + * We open/close around every operation, but we retain the DB + * open if the DB was locked with a prior call to kadm5_lock(), + * so if it's open here that must be because the DB is locked. + */ + heim_assert(context->db->lock_count > 0, + "Internal error in tracking HDB locks"); + return KADM5_ALREADY_LOCKED; + } + + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if (ret) + return ret; + + ret = context->db->hdb_lock(context->context, context->db, HDB_WLOCK); + if (ret) { + (void) context->db->hdb_close(context->context, context->db); + return ret; + } + + /* + * Attempt to recover the log. This will generally fail on slaves, + * and we can't tell if we're on a slave here. + * + * Perhaps we could set a flag in the kadm5_server_context to + * indicate whether a read has been done without recovering the log, + * in which case we could fail any subsequent writes. + */ + if (kadm5_log_init(context) == 0) + (void) kadm5_log_end(context); + + context->keep_open = 1; + return 0; +} + +static kadm5_ret_t +kadm5_s_unlock(void *server_handle) +{ + kadm5_server_context *context = server_handle; + kadm5_ret_t ret; + + if (!context->keep_open) + return KADM5_NOT_LOCKED; + + context->keep_open = 0; + ret = context->db->hdb_unlock(context->context, context->db); + (void) context->db->hdb_close(context->context, context->db); + return ret; +} + +static void +set_funcs(kadm5_server_context *c) +{ +#define SET(C, F) (C)->funcs.F = kadm5_s_ ## F + SET(c, chpass_principal); + SET(c, chpass_principal_with_key); + SET(c, create_principal); + SET(c, delete_principal); + SET(c, destroy); + SET(c, flush); + SET(c, get_principal); + SET(c, get_principals); + SET(c, get_privs); + SET(c, modify_principal); + SET(c, prune_principal); + SET(c, randkey_principal); + SET(c, rename_principal); + SET(c, lock); + SET(c, unlock); + SET(c, setkey_principal_3); + SET(c, iter_principals); + SET(c, dup_context); +} + +#ifndef NO_UNIX_SOCKETS + +static void +set_socket_name(krb5_context context, struct sockaddr_un *un) +{ + const char *fn = kadm5_log_signal_socket(context); + + memset(un, 0, sizeof(*un)); + un->sun_family = AF_UNIX; + strlcpy (un->sun_path, fn, sizeof(un->sun_path)); + +} +#else + +static void +set_socket_info(krb5_context context, struct addrinfo **info) +{ + kadm5_log_signal_socket_info(context, 0, info); +} + +#endif + +static kadm5_ret_t +find_db_spec(kadm5_server_context *ctx) +{ + krb5_context context = ctx->context; + struct hdb_dbinfo *info, *d; + krb5_error_code ret; + int aret; + + if (ctx->config.realm) { + /* fetch the databases */ + ret = hdb_get_dbinfo(context, &info); + if (ret) + return ret; + + d = NULL; + while ((d = hdb_dbinfo_get_next(info, d)) != NULL) { + const char *p = hdb_dbinfo_get_realm(context, d); + + /* match default (realm-less) */ + if(p != NULL && strcmp(ctx->config.realm, p) != 0) + continue; + + p = hdb_dbinfo_get_dbname(context, d); + if (p) { + ctx->config.dbname = strdup(p); + if (ctx->config.dbname == NULL) { + hdb_free_dbinfo(context, &info); + return krb5_enomem(context); + } + } + + p = hdb_dbinfo_get_acl_file(context, d); + if (p) { + ctx->config.acl_file = strdup(p); + if (ctx->config.acl_file == NULL) { + hdb_free_dbinfo(context, &info); + return krb5_enomem(context); + } + } + + p = hdb_dbinfo_get_mkey_file(context, d); + if (p) { + ctx->config.stash_file = strdup(p); + if (ctx->config.stash_file == NULL) { + hdb_free_dbinfo(context, &info); + return krb5_enomem(context); + } + } + + p = hdb_dbinfo_get_log_file(context, d); + if (p) { + ctx->log_context.log_file = strdup(p); + if (ctx->log_context.log_file == NULL) { + hdb_free_dbinfo(context, &info); + return krb5_enomem(context); + } + } + break; + } + hdb_free_dbinfo(context, &info); + } + + /* If any of the values was unset, pick up the default value */ + + if (ctx->config.dbname == NULL) { + ctx->config.dbname = strdup(hdb_default_db(context)); + if (ctx->config.dbname == NULL) + return krb5_enomem(context); + } + if (ctx->config.acl_file == NULL) { + aret = asprintf(&ctx->config.acl_file, "%s/kadmind.acl", + hdb_db_dir(context)); + if (aret == -1) + return krb5_enomem(context); + } + if (ctx->config.stash_file == NULL) { + aret = asprintf(&ctx->config.stash_file, "%s/m-key", + hdb_db_dir(context)); + if (aret == -1) + return krb5_enomem(context); + } + if (ctx->log_context.log_file == NULL) { + aret = asprintf(&ctx->log_context.log_file, "%s/log", + hdb_db_dir(context)); + if (aret == -1) + return krb5_enomem(context); + } + +#ifndef NO_UNIX_SOCKETS + set_socket_name(context, &ctx->log_context.socket_name); +#else + set_socket_info(context, &ctx->log_context.socket_info); +#endif + + return 0; +} + +kadm5_ret_t +_kadm5_s_init_context(kadm5_server_context **ctx, + kadm5_config_params *params, + krb5_context context) +{ + kadm5_ret_t ret = 0; + + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) + return krb5_enomem(context); + (*ctx)->log_context.socket_fd = rk_INVALID_SOCKET; + + set_funcs(*ctx); + (*ctx)->context = context; + krb5_add_et_list (context, initialize_kadm5_error_table_r); + +#define is_set(M) (params && params->mask & KADM5_CONFIG_ ## M) + if (params) + (*ctx)->config.mask = params->mask; + if (is_set(REALM)) { + (*ctx)->config.realm = strdup(params->realm); + if ((*ctx)->config.realm == NULL) + return krb5_enomem(context); + } else { + ret = krb5_get_default_realm(context, &(*ctx)->config.realm); + if (ret) + return ret; + } + if (is_set(DBNAME)) { + (*ctx)->config.dbname = strdup(params->dbname); + if ((*ctx)->config.dbname == NULL) + return krb5_enomem(context); + } + if (is_set(ACL_FILE)) { + (*ctx)->config.acl_file = strdup(params->acl_file); + if ((*ctx)->config.acl_file == NULL) + return krb5_enomem(context); + } + if (is_set(STASH_FILE)) { + (*ctx)->config.stash_file = strdup(params->stash_file); + if ((*ctx)->config.stash_file == NULL) + return krb5_enomem(context); + } + + ret = find_db_spec(*ctx); + if (ret == 0) + ret = _kadm5_s_init_hooks(*ctx); + if (ret != 0) { + kadm5_s_destroy(*ctx); + *ctx = NULL; + return ret; + } + + /* PROFILE can't be specified for now */ + /* KADMIND_PORT is supposed to be used on the server also, + but this doesn't make sense */ + /* ADMIN_SERVER is client only */ + /* ADNAME is not used at all (as far as I can tell) */ + /* ADB_LOCKFILE ditto */ + /* DICT_FILE */ + /* ADMIN_KEYTAB */ + /* MKEY_FROM_KEYBOARD is not supported */ + /* MKEY_NAME neither */ + /* ENCTYPE */ + /* MAX_LIFE */ + /* MAX_RLIFE */ + /* EXPIRATION */ + /* FLAGS */ + /* ENCTYPES */ + + return 0; +} + +HDB * +_kadm5_s_get_db(void *server_handle) +{ + kadm5_server_context *context = server_handle; + return context->db; +} diff --git a/third_party/heimdal/lib/kadm5/create_c.c b/third_party/heimdal/lib/kadm5/create_c.c new file mode 100644 index 0000000..c239beb --- /dev/null +++ b/third_party/heimdal/lib/kadm5/create_c.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1997-2000, 2005-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_create_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + /* + * We should get around to implementing this... At the moment, the + * the server side API is implemented but the wire protocol has not + * been updated. + * + * Well, we have the etypes extension, which the kadmin ank command now + * adds, but that doesn't include salt types. We could, perhaps, make it + * so if the password is "" or NULL, we send the etypes but not the salt + * type, and then have the server side create random keys of just the + * etypes. + */ + if (n_ks_tuple > 0) + return KADM5_KS_TUPLE_NOSUPP; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + ret = krb5_store_int32(sp, kadm_create); + if (ret) + goto out; + ret = kadm5_store_principal_ent(sp, princ); + if (ret) + goto out; + ret = krb5_store_int32(sp, mask); + if (ret) + goto out; + ret = krb5_store_string(sp, password); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} + diff --git a/third_party/heimdal/lib/kadm5/create_s.c b/third_party/heimdal/lib/kadm5/create_s.c new file mode 100644 index 0000000..26e4e4c --- /dev/null +++ b/third_party/heimdal/lib/kadm5/create_s.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 1997-2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +static kadm5_ret_t +get_default(kadm5_server_context *context, krb5_principal princ, + kadm5_principal_ent_t def) +{ + kadm5_ret_t ret; + krb5_principal def_principal; + krb5_const_realm realm = krb5_principal_get_realm(context->context, princ); + + ret = krb5_make_principal(context->context, &def_principal, + realm, "default", NULL); + if (ret) + return ret; + ret = kadm5_s_get_principal(context, def_principal, def, + KADM5_PRINCIPAL_NORMAL_MASK); + krb5_free_principal (context->context, def_principal); + + if (ret) { + /* Copy defaults from kadmin/init.c */ + memset(def, 0, sizeof(*def)); + def->max_life = 24 * 60 * 60; + def->max_renewable_life = 7 * def->max_life; + def->attributes = KRB5_KDB_DISALLOW_ALL_TIX; + } + return ret; +} + +static kadm5_ret_t +create_principal(kadm5_server_context *context, + kadm5_principal_ent_t princ, + uint32_t mask, + hdb_entry *ent, + uint32_t required_mask, + uint32_t forbidden_mask) +{ + kadm5_ret_t ret; + kadm5_principal_ent_rec defrec, *defent; + uint32_t def_mask; + + memset(ent, 0, sizeof(*ent)); + if((mask & required_mask) != required_mask) + return KADM5_BAD_MASK; + if((mask & forbidden_mask)) + return KADM5_BAD_MASK; + if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) + /* XXX no real policies for now */ + return KADM5_UNK_POLICY; + ret = krb5_copy_principal(context->context, princ->principal, + &ent->principal); + if(ret) + return ret; + + defent = &defrec; + ret = get_default(context, princ->principal, defent); + if(ret) { + defent = NULL; + def_mask = 0; + } else { + def_mask = KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE; + } + + ret = _kadm5_setup_entry(context, + ent, mask | def_mask, + princ, mask, + defent, def_mask); + if(defent) + kadm5_free_principal_ent(context, defent); + if (ret) + return ret; + + ent->created_by.time = time(NULL); + + return krb5_copy_principal(context->context, context->caller, + &ent->created_by.principal); +} + +struct create_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + kadm5_principal_ent_t princ; + uint32_t mask; + const char *password; +}; + +static krb5_error_code KRB5_LIB_CALL +create_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct create_principal_hook_ctx *ctx = userctx; + + ret = ftable->create(context, hookctx, + ctx->stage, ctx->code, ctx->princ, + ctx->mask, ctx->password); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "create", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +create_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t princ, + uint32_t mask, + const char *password) +{ + krb5_error_code ret; + struct create_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.mask = mask; + ctx.password = password; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, create_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +kadm5_ret_t +kadm5_s_create_principal_with_key(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + kadm5_ret_t ret; + hdb_entry ent; + kadm5_server_context *context = server_handle; + + if ((mask & KADM5_KVNO) == 0) { + /* create_principal() through _kadm5_setup_entry(), will need this */ + princ->kvno = 1; + mask |= KADM5_KVNO; + } + + ret = create_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, mask, NULL); + if (ret) + return ret; + + ret = create_principal(context, princ, mask, &ent, + KADM5_PRINCIPAL | KADM5_KEY_DATA, + KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME + | KADM5_MOD_NAME | KADM5_MKVNO + | KADM5_AUX_ATTRIBUTES + | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS + | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); + if (ret) + return ret; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if (ret) { + hdb_free_entry(context->context, context->db, &ent); + return ret; + } + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out2; + + /* + * This logs the change for iprop and writes to the HDB. + * + * Creation of would-be virtual principals w/o the materialize flag will be + * rejected in kadm5_log_create(). + */ + ret = kadm5_log_create(context, &ent); + + (void) create_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, mask, NULL); + + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + hdb_free_entry(context->context, context->db, &ent); + return _kadm5_error_code(ret); +} + + +kadm5_ret_t +kadm5_s_create_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + kadm5_ret_t ret; + hdb_entry ent; + kadm5_server_context *context = server_handle; + int use_pw = 1; + + if ((mask & KADM5_ATTRIBUTES) && + (princ->attributes & (KRB5_KDB_VIRTUAL_KEYS | KRB5_KDB_VIRTUAL)) && + !(princ->attributes & KRB5_KDB_MATERIALIZE)) { + return _kadm5_error_code(KADM5_DUP); /* XXX More like EINVAL */ + } + if ((mask & KADM5_ATTRIBUTES) && + (princ->attributes & KRB5_KDB_VIRTUAL_KEYS) && + (princ->attributes & KRB5_KDB_VIRTUAL)) { + return _kadm5_error_code(KADM5_DUP); /* XXX More like EINVAL */ + } + + if ((mask & KADM5_ATTRIBUTES) && + (princ->attributes & KRB5_KDB_VIRTUAL) && + (princ->attributes & KRB5_KDB_MATERIALIZE)) + princ->attributes &= ~(KRB5_KDB_MATERIALIZE | KRB5_KDB_VIRTUAL); + + if (password[0] == '\0' && (mask & KADM5_KEY_DATA) && princ->n_key_data && + !kadm5_all_keys_are_bogus(princ->n_key_data, princ->key_data)) + use_pw = 0; + + if (use_pw && _kadm5_enforce_pwqual_on_admin_set_p(context)) { + krb5_data pwd_data; + const char *pwd_reason; + + pwd_data.data = rk_UNCONST(password); + pwd_data.length = strlen(password); + + pwd_reason = kadm5_check_password_quality(context->context, + princ->principal, &pwd_data); + if (pwd_reason != NULL) { + krb5_set_error_message(context->context, KADM5_PASS_Q_DICT, "%s", pwd_reason); + return KADM5_PASS_Q_DICT; + } + } + + if ((mask & KADM5_KVNO) == 0) { + /* create_principal() through _kadm5_setup_entry(), will need this */ + princ->kvno = 1; + mask |= KADM5_KVNO; + } + + ret = create_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, mask, password); + if (ret) + return ret; + + if (use_pw) + ret = create_principal(context, princ, mask, &ent, + KADM5_PRINCIPAL, + KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME + | KADM5_MOD_NAME | KADM5_MKVNO + | KADM5_AUX_ATTRIBUTES | KADM5_KEY_DATA + | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS + | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); + else + ret = create_principal(context, princ, mask, &ent, + KADM5_PRINCIPAL | KADM5_KEY_DATA, + KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME + | KADM5_MOD_NAME | KADM5_MKVNO + | KADM5_AUX_ATTRIBUTES + | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS + | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); + if (ret) + return ret; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if (ret) { + hdb_free_entry(context->context, context->db, &ent); + return ret; + } + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + free_Keys(&ent.keys); + + if (use_pw) { + ret = _kadm5_set_keys(context, &ent, n_ks_tuple, ks_tuple, password); + if (ret) + goto out2; + } + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out2; + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_create(context, &ent); + + (void) create_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, mask, password); + + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + hdb_free_entry(context->context, context->db, &ent); + return _kadm5_error_code(ret); +} + diff --git a/third_party/heimdal/lib/kadm5/default_keys.c b/third_party/heimdal/lib/kadm5/default_keys.c new file mode 100644 index 0000000..c3494e5 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/default_keys.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include + +RCSID("$Id$"); + +static void +print_keys(krb5_context context, Key *keys, size_t nkeys) +{ + krb5_error_code ret; + char *str; + int i; + + printf("keys:\n"); + + for (i = 0; i < nkeys; i++) { + + ret = krb5_enctype_to_string(context, keys[i].key.keytype, &str); + if (ret) + krb5_err(context, ret, 1, "krb5_enctype_to_string: %d\n", + (int)keys[i].key.keytype); + + printf("\tenctype %s", str); + free(str); + + if (keys[i].salt) { + printf(" salt: "); + + switch (keys[i].salt->type) { + case KRB5_PW_SALT: + printf("pw-salt:"); + break; + case KRB5_AFS3_SALT: + printf("afs3-salt:"); + break; + default: + printf("unknown salt: %d", keys[i].salt->type); + break; + } + if (keys[i].salt->salt.length) + printf("%.*s", (int)keys[i].salt->salt.length, + (char *)keys[i].salt->salt.data); + } + printf("\n"); + } + printf("end keys:\n"); +} + +static void +parse_file(krb5_context context, krb5_principal principal, int no_salt) +{ + krb5_error_code ret; + size_t nkeys; + Key *keys; + + ret = hdb_generate_key_set(context, principal, NULL, 0, &keys, &nkeys, + no_salt); + if (ret) + krb5_err(context, 1, ret, "hdb_generate_key_set"); + + print_keys(context, keys, nkeys); + + hdb_free_keys(context, nkeys, keys); +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + krb5_principal principal; + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context"); + + ret = krb5_parse_name(context, "lha@SU.SE", &principal); + if (ret) + krb5_err(context, ret, 1, "krb5_parse_name"); + + parse_file(context, principal, 0); + parse_file(context, principal, 1); + + krb5_free_principal(context, principal); + + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/delete_c.c b/third_party/heimdal/lib/kadm5/delete_c.c new file mode 100644 index 0000000..cf06b6f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/delete_c.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_delete_principal(void *server_handle, krb5_principal princ) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_delete); + if (ret) + goto out; + ret = krb5_store_principal(sp, princ); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/delete_s.c b/third_party/heimdal/lib/kadm5/delete_s.c new file mode 100644 index 0000000..aa9fdb4 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/delete_s.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1997 - 2001, 2003, 2005 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct delete_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; +}; + +static krb5_error_code KRB5_LIB_CALL +delete_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct delete_principal_hook_ctx *ctx = userctx; + + ret = ftable->delete(context, hookctx, + ctx->stage, ctx->code, ctx->princ); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "delete", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +delete_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ) +{ + krb5_error_code ret; + struct delete_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, delete_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +kadm5_ret_t +kadm5_s_delete_principal(void *server_handle, krb5_principal princ) +{ + kadm5_server_context *context = server_handle; + kadm5_ret_t ret; + hdb_entry ent; + + memset(&ent, 0, sizeof(ent)); + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) { + krb5_warn(context->context, ret, "opening database"); + return ret; + } + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret == HDB_ERR_NOENTRY) + goto out2; + if (ent.flags.immutable) { + ret = KADM5_PROTECT_PRINCIPAL; + goto out3; + } + + ret = delete_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, 0, princ); + if (ret) + goto out3; + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_delete(context, princ); + + (void) delete_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ); + + out3: + hdb_free_entry(context->context, context->db, &ent); + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/destroy_c.c b/third_party/heimdal/lib/kadm5/destroy_c.c new file mode 100644 index 0000000..5ed85f7 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/destroy_c.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_destroy(void *server_handle) +{ + kadm5_client_context *context = server_handle; + + free(context->realm); + free(context->readonly_admin_server); + free(context->admin_server); + if (context->sock != rk_INVALID_SOCKET) + rk_closesocket(context->sock); + if (context->client_name) + free(context->client_name); + if (context->service_name) + free(context->service_name); + if (context->ac != NULL) + krb5_auth_con_free(context->context, context->ac); + if(context->my_context) + krb5_free_context(context->context); + free(context); + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/destroy_s.c b/third_party/heimdal/lib/kadm5/destroy_s.c new file mode 100644 index 0000000..0558b45 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/destroy_s.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +/* + * dealloc a `kadm5_config_params' + */ + +static void +destroy_config (kadm5_config_params *c) +{ + if (!c) + return; + free(c->realm); + free(c->dbname); + free(c->acl_file); + free(c->stash_file); +} + +/* + * dealloc a kadm5_log_context + */ + +static void +destroy_kadm5_log_context (kadm5_log_context *c) +{ + if (!c) + return; + free(c->log_file); + if (c->socket_fd != rk_INVALID_SOCKET) + rk_closesocket(c->socket_fd); +#ifdef NO_UNIX_SOCKETS + if (c->socket_info) { + freeaddrinfo(c->socket_info); + c->socket_info = NULL; + } +#endif +} + +/* + * destroy a kadm5 handle + */ + +kadm5_ret_t +kadm5_s_destroy(void *server_handle) +{ + kadm5_ret_t ret = 0; + kadm5_server_context *context = server_handle; + krb5_context kcontext = context->context; + + _kadm5_s_free_hooks(context); + if (context->db != NULL) + ret = context->db->hdb_destroy(kcontext, context->db); + destroy_kadm5_log_context(&context->log_context); + destroy_config(&context->config); + krb5_free_principal(kcontext, context->caller); + if (context->my_context) + krb5_free_context(kcontext); + free(context); + + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/ent_setup.c b/third_party/heimdal/lib/kadm5/ent_setup.c new file mode 100644 index 0000000..03c4fb1 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ent_setup.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +#define set_value(X, V) do { if((X) == NULL) (X) = malloc(sizeof(*(X))); *(X) = V; } while(0) +#define set_null(X) do { if((X) != NULL) free((X)); (X) = NULL; } while (0) + +static void +attr_to_flags(unsigned attr, HDBFlags *flags) +{ + flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); + flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); + flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); + flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); + flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); + /* DUP_SKEY */ + flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); + flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); + flags->require_pwchange = !!(attr & KRB5_KDB_REQUIRES_PWCHANGE); + /* HW_AUTH */ + flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); + flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); + flags->client = !(attr & KRB5_KDB_DISALLOW_CLIENT); + flags->ok_as_delegate = !!(attr & KRB5_KDB_OK_AS_DELEGATE); + flags->trusted_for_delegation = !!(attr & KRB5_KDB_TRUSTED_FOR_DELEGATION); + flags->allow_kerberos4 = !!(attr & KRB5_KDB_ALLOW_KERBEROS4); + flags->allow_digest = !!(attr & KRB5_KDB_ALLOW_DIGEST); + flags->materialize = !!(attr & KRB5_KDB_MATERIALIZE); + flags->virtual_keys = !!(attr & KRB5_KDB_VIRTUAL_KEYS); + flags->virtual = !!(attr & KRB5_KDB_VIRTUAL); + flags->no_auth_data_reqd = !!(attr & KRB5_KDB_NO_AUTH_DATA_REQUIRED); + flags->auth_data_reqd = !!(attr & KRB5_KDB_AUTH_DATA_REQUIRED); + + if (flags->no_auth_data_reqd && flags->auth_data_reqd) + flags->auth_data_reqd = 0; +} + +/* + * Modify the `ent' according to `tl_data'. + */ + +static kadm5_ret_t +perform_tl_data(krb5_context context, + HDB *db, + hdb_entry *ent, + const krb5_tl_data *tl_data) +{ + kadm5_ret_t ret = 0; + + if (tl_data->tl_data_type == KRB5_TL_PASSWORD) { + heim_utf8_string pw = tl_data->tl_data_contents; + + if (pw[tl_data->tl_data_length] != '\0') + return KADM5_BAD_TL_TYPE; + + ret = hdb_entry_set_password(context, db, ent, pw); + + } else if (tl_data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) { + unsigned long t; + unsigned char *s; + + if (tl_data->tl_data_length != 4) + return KADM5_BAD_TL_TYPE; + + s = tl_data->tl_data_contents; + + (void) _krb5_get_int(s, &t, tl_data->tl_data_length); + ret = hdb_entry_set_pw_change_time(context, ent, t); + + } else if (tl_data->tl_data_type == KRB5_TL_KEY_ROTATION) { + HDB_Ext_KeyRotation *prev_kr = 0; + HDB_extension *prev_ext; + HDB_extension ext; + + ext.mandatory = 0; + ext.data.element = choice_HDB_extension_data_key_rotation; + prev_ext = hdb_find_extension(ent, ext.data.element); + if (prev_ext) + prev_kr = &prev_ext->data.u.key_rotation; + ret = decode_HDB_Ext_KeyRotation(tl_data->tl_data_contents, + tl_data->tl_data_length, + &ext.data.u.key_rotation, NULL); + if (ret == 0) + ret = hdb_validate_key_rotations(context, prev_kr, + &ext.data.u.key_rotation); + if (ret == 0) + ret = hdb_replace_extension(context, ent, &ext); + free_HDB_extension(&ext); + } else if (tl_data->tl_data_type == KRB5_TL_EXTENSION) { + HDB_extension ext; + + ret = decode_HDB_extension(tl_data->tl_data_contents, + tl_data->tl_data_length, + &ext, + NULL); + if (ret) + return KADM5_BAD_TL_TYPE; + + if (ext.data.element == choice_HDB_extension_data_key_rotation) { + HDB_extension *prev_ext = hdb_find_extension(ent, + ext.data.element); + HDB_Ext_KeyRotation *prev_kr = 0; + + if (prev_ext) + prev_kr = &prev_ext->data.u.key_rotation; + ret = hdb_validate_key_rotations(context, prev_kr, + &ext.data.u.key_rotation); + } + if (ret) + ret = KADM5_BAD_TL_TYPE; /* XXX Need new error code */ + if (ret == 0) + ret = hdb_replace_extension(context, ent, &ext); + free_HDB_extension(&ext); + } else if (tl_data->tl_data_type == KRB5_TL_ETYPES) { + if (!ent->etypes && + (ent->etypes = calloc(1, + sizeof(ent->etypes[0]))) == NULL) + ret = krb5_enomem(context); + if (ent->etypes) + free_HDB_EncTypeList(ent->etypes); + if (ret == 0) + ret = decode_HDB_EncTypeList(tl_data->tl_data_contents, + tl_data->tl_data_length, + ent->etypes, NULL); + if (ret) + return KADM5_BAD_TL_TYPE; + } else if (tl_data->tl_data_type == KRB5_TL_ALIASES) { + return 0; + } else { + return KADM5_BAD_TL_TYPE; + } + return ret; +} + +static void +default_flags(hdb_entry *ent) +{ + ent->flags.client = 1; + ent->flags.server = 1; + ent->flags.forwardable = 1; + ent->flags.proxiable = 1; + ent->flags.renewable = 1; + ent->flags.postdate = 1; +} + + +/* + * Create the hdb entry `ent' based on data from `princ' with + * `princ_mask' specifying what fields to be gotten from there and + * `mask' specifying what fields we want filled in. + */ + +kadm5_ret_t +_kadm5_setup_entry(kadm5_server_context *context, + hdb_entry *ent, + uint32_t mask, + kadm5_principal_ent_t princ, + uint32_t princ_mask, + kadm5_principal_ent_t def, + uint32_t def_mask) +{ + if(mask & KADM5_PRINC_EXPIRE_TIME + && princ_mask & KADM5_PRINC_EXPIRE_TIME) { + if (princ->princ_expire_time) + set_value(ent->valid_end, princ->princ_expire_time); + else + set_null(ent->valid_end); + } + if(mask & KADM5_PW_EXPIRATION + && princ_mask & KADM5_PW_EXPIRATION) { + if (princ->pw_expiration) + set_value(ent->pw_end, princ->pw_expiration); + else + set_null(ent->pw_end); + } + if(mask & KADM5_ATTRIBUTES) { + if (princ_mask & KADM5_ATTRIBUTES) { + attr_to_flags(princ->attributes, &ent->flags); + } else if(def_mask & KADM5_ATTRIBUTES) { + attr_to_flags(def->attributes, &ent->flags); + ent->flags.invalid = 0; + } else { + default_flags(ent); + } + } + + if(mask & KADM5_MAX_LIFE) { + if(princ_mask & KADM5_MAX_LIFE) { + if(princ->max_life) + set_value(ent->max_life, princ->max_life); + else + set_null(ent->max_life); + } else if(def_mask & KADM5_MAX_LIFE) { + if(def->max_life) + set_value(ent->max_life, def->max_life); + else + set_null(ent->max_life); + } + } + if(mask & KADM5_KVNO + && (princ_mask & KADM5_KVNO)) { + krb5_error_code ret; + + ret = hdb_change_kvno(context->context, princ->kvno, ent); + if (ret && ret != HDB_ERR_KVNO_NOT_FOUND) + return ret; + ent->kvno = princ->kvno; /* force it */ + } + if(mask & KADM5_MAX_RLIFE) { + if(princ_mask & KADM5_MAX_RLIFE) { + if(princ->max_renewable_life) + set_value(ent->max_renew, princ->max_renewable_life); + else + set_null(ent->max_renew); + } else if(def_mask & KADM5_MAX_RLIFE) { + if(def->max_renewable_life) + set_value(ent->max_renew, def->max_renewable_life); + else + set_null(ent->max_renew); + } + } + if(mask & KADM5_KEY_DATA + && princ_mask & KADM5_KEY_DATA) { + _kadm5_set_keys2(context, ent, + princ->n_key_data, princ->key_data); + } + if(mask & KADM5_TL_DATA) { + krb5_tl_data *tl; + + for (tl = princ->tl_data; tl != NULL; tl = tl->tl_data_next) { + kadm5_ret_t ret; + ret = perform_tl_data(context->context, context->db, ent, tl); + if (ret) + return ret; + } + } + if(mask & KADM5_FAIL_AUTH_COUNT) { + /* XXX */ + } + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/error.c b/third_party/heimdal/lib/kadm5/error.c new file mode 100644 index 0000000..e6a6dec --- /dev/null +++ b/third_party/heimdal/lib/kadm5/error.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +_kadm5_error_code(kadm5_ret_t code) +{ + switch(code){ + case HDB_ERR_EXISTS: + return KADM5_DUP; + case HDB_ERR_NOENTRY: + return KADM5_UNK_PRINC; + } + return code; +} diff --git a/third_party/heimdal/lib/kadm5/flush.c b/third_party/heimdal/lib/kadm5/flush.c new file mode 100644 index 0000000..4409fe6 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/flush.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_s_flush(void *server_handle) +{ + return 0; +} + +kadm5_ret_t +kadm5_c_flush(void *server_handle) +{ + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/flush_c.c b/third_party/heimdal/lib/kadm5/flush_c.c new file mode 100644 index 0000000..c1a2a0a --- /dev/null +++ b/third_party/heimdal/lib/kadm5/flush_c.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_flush(void *server_handle) +{ + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/flush_s.c b/third_party/heimdal/lib/kadm5/flush_s.c new file mode 100644 index 0000000..9a52458 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/flush_s.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_s_flush(void *server_handle) +{ + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/free.c b/third_party/heimdal/lib/kadm5/free.c new file mode 100644 index 0000000..e8bb0f9 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/free.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +void +kadm5_free_key_data(void *server_handle, + int16_t *n_key_data, + krb5_key_data *key_data) +{ + int i; + for(i = 0; i < *n_key_data; i++){ + if(key_data[i].key_data_contents[0]){ + memset(key_data[i].key_data_contents[0], + 0, + key_data[i].key_data_length[0]); + free(key_data[i].key_data_contents[0]); + } + if(key_data[i].key_data_contents[1]) + free(key_data[i].key_data_contents[1]); + } + *n_key_data = 0; +} + + +void +kadm5_free_principal_ent(void *server_handle, + kadm5_principal_ent_t princ) +{ + kadm5_server_context *context = server_handle; + + if (princ->principal) + krb5_free_principal(context->context, princ->principal); + if (princ->mod_name) + krb5_free_principal(context->context, princ->mod_name); + kadm5_free_key_data(server_handle, &princ->n_key_data, princ->key_data); + while (princ->n_tl_data && princ->tl_data) { + krb5_tl_data *tp; + tp = princ->tl_data; + princ->tl_data = tp->tl_data_next; + princ->n_tl_data--; + memset(tp->tl_data_contents, 0, tp->tl_data_length); + free(tp->tl_data_contents); + free(tp); + } + free(princ->key_data); + free(princ->policy); +} + +void +kadm5_free_name_list(void *server_handle, + char **names, + int *count) +{ + int i; + for(i = 0; i < *count; i++) + free(names[i]); + free(names); + *count = 0; +} diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent0.bin b/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent0.bin new file mode 100644 index 0000000..2c5f72c Binary files /dev/null and b/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent0.bin differ diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent1.bin b/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent1.bin new file mode 100644 index 0000000..ff0b705 Binary files /dev/null and b/third_party/heimdal/lib/kadm5/fuzz-inputs-bin/test_marshall-ent1.bin differ diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent0.bin b/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent0.bin new file mode 100644 index 0000000..645fea7 Binary files /dev/null and b/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent0.bin differ diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent1.bin b/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent1.bin new file mode 100644 index 0000000..e64ec5a Binary files /dev/null and b/third_party/heimdal/lib/kadm5/fuzz-inputs-packed/test_marshall-ent1.bin differ diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt b/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt new file mode 100644 index 0000000..9d78e8d --- /dev/null +++ b/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt @@ -0,0 +1,101 @@ +# The body of this file contains a representation of a very small and contrived +# kadm5_principal_ent_rec meant for fuzzing. For fuzzing purposes, the smaller +# the input, the better. +# +# To compile this input into a binary input file suitable for fuzzing: +# +# cd build +# make -j4 +# cd lib/kadm5 +# make test_marshall +# ./test_marshall --in-text --byte-order-in=packed \ +# --byte-order-out=packed \ +# --out-hex \ +# kadm5_principal_ent_rec \ +# ../../../lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt +# +# then decode the hex (e.g., with xxd -r -p) and save it in a file. +# +# Currently we have that saved in lib/kadm5/fuzz-inputs-packed/. +# +# To build and fuzz with this input: +# +# cd build +# AFL_HARDEN=1 make -j4 CC=afl-clang all +# cd lib/kadm5 +# AFL_HARDEN=1 make -j4 CC=afl-clang test_marshall +# rm -rf f; mkdir f +# ../../libtool --mode=execute afl-fuzz \ +# -i ../../../lib/kadm5/fuzz-inputs-packed \ +# -o $PWD/f \ +# ./test_marshall --byte-order-in=packed \ +# --byte-order-out=packed \ +# --out-hex \ +# kadm5_principal_ent_rec '@@' +# +# A kadm5_principal_ent_rec follows: +# +# principal name +int32 0 +int32 1 +string T +string f +# expiration +int32 2 +# pw expiration +int32 3 +# last pw change +int32 4 +# max life +int32 5 +# mod name optional (boolean, principal name) +int32 1 +int32 0 +int32 1 +string T +string b +# mod time +int32 6 +# attrs +int32 7 +# kvno +int32 8 +# master kvno +int32 9 +# policy (boolean, string) +int32 1 +string default +# aux attrs +int32 10 +# max renew life +int32 11 +# last success +int32 12 +# last fail +int32 13 +# fail count +int32 14 +# nkeydata +int32 2 +# keydata[0] (ver, kvno, type, data, type, data) +int32 15 +int32 16 +int32 17 +data 1122 +int32 18 +data 2233 +# keydata[1] +int32 19 +int32 21 +int32 22 +data 3344 +int32 23 +data 4455 +# ntldata +int32 2 +# ntldata[0] (type, data) +int32 24 +data 5566 +# ntldata[1] +int32 25 +data 6677 diff --git a/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent1.txt b/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent1.txt new file mode 100644 index 0000000..332c759 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/fuzz-inputs-txt/test_marshall-ent1.txt @@ -0,0 +1,54 @@ +# See lib/kadm5/fuzz-inputs-txt/test_marshall-ent0.txt for instructions on how +# to fuzz krb5/kadm5 marshalling. +# +# A truncated kadm5_principal_ent_rec follows: +# +# principal name +int32 0 +int32 1 +string T +string f +# expiration +int32 2 +# pw expiration +int32 3 +# last pw change +int32 4 +# max life +int32 5 +# mod name optional (boolean, principal name) +int32 1 +int32 0 +int32 1 +string T +string b +# mod time +int32 6 +# attrs +int32 7 +# kvno +int32 8 +# master kvno +int32 9 +# policy (boolean, string) +int32 1 +string default +# aux attrs +int32 10 +# max renew life +int32 11 +# last success +int32 12 +# last fail +int32 13 +# fail count +int32 14 +# nkeydata +int32 2 +# keydata[0] (ver, kvno, type, data, type, data) +int32 15 +int32 16 +int32 17 +data 1122 +int32 18 +data 2233 diff --git a/third_party/heimdal/lib/kadm5/get_c.c b/third_party/heimdal/lib/kadm5/get_c.c new file mode 100644 index 0000000..1c1fd9d --- /dev/null +++ b/third_party/heimdal/lib/kadm5/get_c.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1997 - 2000, 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_get_principal(void *server_handle, + krb5_principal princ, + kadm5_principal_ent_t ent, + uint32_t mask) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + ret = _kadm5_connect(server_handle, 0 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_get); + if (ret) + goto out; + ret = krb5_store_principal(sp, princ); + if (ret) + goto out; + ret = krb5_store_int32(sp, mask); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + if (ret == 0) + ret = kadm5_ret_principal_ent(sp, ent); + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/get_princs_c.c b/third_party/heimdal/lib/kadm5/get_princs_c.c new file mode 100644 index 0000000..be86cfa --- /dev/null +++ b/third_party/heimdal/lib/kadm5/get_princs_c.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_get_principals(void *server_handle, + const char *expression, + char ***princs, + int *count) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + int i; + + *count = 0; + *princs = NULL; + + ret = _kadm5_connect(server_handle, 0 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_get_princs); + if (ret) + goto out; + ret = krb5_store_int32(sp, expression != NULL ? 1 : 0); + if (ret) + goto out; + if (expression) { + ret = krb5_store_string(sp, expression); + if (ret) + goto out; + } + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data (&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + if (ret) + goto out; + + ret = krb5_ret_int32(sp, &tmp); + if (ret) + goto out; + + *princs = calloc(tmp + 1, sizeof(**princs)); + if (*princs == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + for (i = 0; i < tmp; i++) { + ret = krb5_ret_string(sp, &(*princs)[i]); + if (ret) + goto out; + } + *count = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} + +kadm5_ret_t +kadm5_c_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + size_t i; + int stop = 0; + + ret = _kadm5_connect(server_handle, 0 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_get_princs); + if (ret) + goto out; + + /* + * Our protocol has an int boolean for this operation to indicate whether + * there's an expression. What we'll do here is that instead of sending + * just false or trueish, for online iteration we'll send a number other + * than 0 or 1 -- a magic value > 0 and < INT_MAX. + * + * In response we'll expect multiple replies, each with up to some small + * number of principal names. See kadmin/server.c. + */ + ret = krb5_store_int32(sp, 0x55555555); + if (ret) + goto out; + ret = krb5_store_string(sp, expression ? expression : ""); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data (&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + if (ret) + goto out; + + ret = krb5_ret_int32(sp, &tmp); + if (ret) + goto out; + + if (tmp < 0) { + size_t n = -tmp; + int more = 1; + + /* The server supports online iteration, hooray! */ + + while (more) { + /* + * We expect any number of chunks, each having `n' names, except + * the last one would have fewer than `n' (possibly zero, even). + * + * After that we expect one more reply with just a final return + * code. + */ + krb5_data_free(&reply); + krb5_storage_free(sp); + sp = NULL; + ret = _kadm5_client_recv(context, &reply); + if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL) + ret = krb5_enomem(context->context); + if (ret) + goto out; + + /* Every chunk begins with a status code */ + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (ret) + goto out; + + /* We expect up to -tmp principals per reply */ + for (i = 0; i < n; i++) { + char *princ = NULL; + + ret = krb5_ret_string(sp, &princ); + if (ret == HEIM_ERR_EOF) { + /* This was the last reply */ + more = 0; + ret = 0; + break; + } + if (ret) + goto out; + if (!stop) { + stop = cb(cbdata, princ); + if (stop) { + /* + * Tell the server to stop. + * + * We use a NOP for this, but with a payload that says + * "don't reply to the NOP" just in case the NOP + * arrives and is processed _after_ the LISTing has + * finished. + */ + krb5_storage_free(sp); + if ((sp = krb5_storage_emem()) && + krb5_store_int32(sp, kadm_nop) == 0 && + krb5_store_int32(sp, 0)) + (void) _kadm5_client_send(context, sp); + } + } + free(princ); + } + } + /* Get the final result code */ + krb5_data_free(&reply); + krb5_storage_free(sp); + sp = NULL; + ret = _kadm5_client_recv(context, &reply); + if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL) + ret = krb5_enomem(context->context); + if (ret) + goto out; + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (!stop) { + /* + * Send our "interrupt" after the last chunk if we hand't + * interrupted already. + */ + krb5_storage_free(sp); + if ((sp = krb5_storage_emem()) && + krb5_store_int32(sp, kadm_nop) == 0) + (void) _kadm5_client_send(context, sp); + } + } else { + size_t n = tmp; + + /* Old server -- listing not online */ + for (i = 0; i < n; i++) { + char *princ = NULL; + + ret = krb5_ret_string(sp, &princ); + if (ret) + goto out; + cb(cbdata, princ); + free(princ); + } + } + +out: + krb5_clear_error_message(context->context); + +out_keep_error: + if (stop) + ret = stop; + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/get_princs_s.c b/third_party/heimdal/lib/kadm5/get_princs_s.c new file mode 100644 index 0000000..14d3907 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/get_princs_s.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct foreach_data { + const char *exp; + char *exp2; + char **princs; + size_t nalloced; + size_t count; +}; + +static krb5_error_code +add_princ(krb5_context context, struct foreach_data *d, char *princ) +{ + + if (d->count == INT_MAX) + return ERANGE; + if (d->nalloced == d->count) { + size_t n = d->nalloced + (d->nalloced >> 1) + 128; /* No O(N^2) pls */ + char **tmp; + + if (SIZE_MAX / sizeof(*tmp) <= n) + return ERANGE; + if ((tmp = realloc(d->princs, n * sizeof(*tmp))) == NULL) + return krb5_enomem(context); + d->princs = tmp; + d->nalloced = n; + } + d->princs[d->count++] = princ; + return 0; +} + +static krb5_error_code +foreach(krb5_context context, HDB *db, hdb_entry *ent, void *data) +{ + struct foreach_data *d = data; + char *princ; + krb5_error_code ret; + ret = krb5_unparse_name(context, ent->principal, &princ); + if(ret) + return ret; + if(d->exp){ + if(fnmatch(d->exp, princ, 0) == 0 || fnmatch(d->exp2, princ, 0) == 0) + ret = add_princ(context, d, princ); + else + free(princ); + }else{ + ret = add_princ(context, d, princ); + } + if(ret) + free(princ); + return ret; +} + +kadm5_ret_t +kadm5_s_get_principals(void *server_handle, + const char *expression, + char ***princs, + int *count) +{ + struct foreach_data d; + kadm5_server_context *context = server_handle; + kadm5_ret_t ret = 0; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); + if (ret) { + krb5_warn(context->context, ret, "opening database"); + return ret; + } + } + d.exp = expression; + d.exp2 = NULL; + if (expression) { + krb5_realm r; + int aret; + + ret = krb5_get_default_realm(context->context, &r); + if (ret == 0) { + aret = asprintf(&d.exp2, "%s@%s", expression, r); + free(r); + if (aret == -1 || d.exp2 == NULL) + ret = krb5_enomem(context->context); + } + } + d.princs = NULL; + d.nalloced = 0; + d.count = 0; + if (ret == 0) + ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, + foreach, &d); + + if (ret == 0) + ret = add_princ(context->context, &d, NULL); + if (d.count >= INT_MAX) + *count = INT_MAX; + else + *count = d.count - 1; + if (ret == 0) + *princs = d.princs; + else + kadm5_free_name_list(context, d.princs, count); + free(d.exp2); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return _kadm5_error_code(ret); +} + +struct foreach_online_data { + const char *exp; + char *exp2; + int (*cb)(void *, const char *); + void *cbdata; +}; + +static krb5_error_code +foreach_online(krb5_context context, HDB *db, hdb_entry *ent, void *data) +{ + struct foreach_online_data *d = data; + krb5_error_code ret; + char *princ = NULL; + + ret = krb5_unparse_name(context, ent->principal, &princ); + if (ret == 0) { + if (!d->exp || + fnmatch(d->exp, princ, 0) == 0 || fnmatch(d->exp2, princ, 0) == 0) + ret = d->cb(d->cbdata, princ); + free(princ); + } + return ret; +} + +kadm5_ret_t +kadm5_s_iter_principals(void *server_handle, + const char *expression, + int (*cb)(void *, const char *), + void *cbdata) +{ + struct foreach_online_data d; + kadm5_server_context *context = server_handle; + kadm5_ret_t ret = 0; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); + if (ret) { + krb5_warn(context->context, ret, "opening database"); + return ret; + } + } + d.exp = expression; + d.exp2 = NULL; + d.cb = cb; + d.cbdata = cbdata; + if (expression) { + krb5_realm r; + int aret; + + ret = krb5_get_default_realm(context->context, &r); + if (ret == 0) { + aret = asprintf(&d.exp2, "%s@%s", expression, r); + free(r); + if (aret == -1 || d.exp2 == NULL) + ret = krb5_enomem(context->context); + } + } + if (ret == 0) + ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, + foreach_online, &d); + free(d.exp2); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/get_s.c b/third_party/heimdal/lib/kadm5/get_s.c new file mode 100644 index 0000000..c231366 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/get_s.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include "kadm5_locl.h" +#include + +RCSID("$Id$"); + +static kadm5_ret_t +add_tl_data(kadm5_principal_ent_t ent, int16_t type, + const void *data, size_t size) +{ + krb5_tl_data *tl; + + tl = calloc(1, sizeof(*tl)); + if (tl == NULL) + return _kadm5_error_code(ENOMEM); + + tl->tl_data_type = type; + tl->tl_data_length = size; + tl->tl_data_contents = malloc(size); + if (tl->tl_data_contents == NULL && size != 0) { + free(tl); + return _kadm5_error_code(ENOMEM); + } + memcpy(tl->tl_data_contents, data, size); + + tl->tl_data_next = ent->tl_data; + ent->tl_data = tl; + ent->n_tl_data++; + + return 0; +} + +static +krb5_error_code +copy_keyset_to_kadm5(kadm5_server_context *context, krb5_kvno kvno, + size_t n_keys, Key *keys, krb5_salt *salt, + kadm5_principal_ent_t out) +{ + size_t i; + Key *key; + krb5_key_data *kd; + krb5_data *sp; + krb5_error_code ret = 0; + + for (i = 0; i < n_keys; i++) { + key = &keys[i]; + kd = &out->key_data[out->n_key_data]; + kd->key_data_ver = 2; + kd->key_data_kvno = kvno; + kd->key_data_type[0] = key->key.keytype; + if(key->salt) + kd->key_data_type[1] = key->salt->type; + else + kd->key_data_type[1] = KRB5_PADATA_PW_SALT; + /* setup key */ + kd->key_data_length[0] = key->key.keyvalue.length; + kd->key_data_contents[0] = malloc(kd->key_data_length[0]); + if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){ + ret = krb5_enomem(context->context); + break; + } + memcpy(kd->key_data_contents[0], key->key.keyvalue.data, + kd->key_data_length[0]); + /* setup salt */ + if(key->salt) + sp = &key->salt->salt; + else + sp = &salt->saltvalue; + kd->key_data_length[1] = sp->length; + kd->key_data_contents[1] = malloc(kd->key_data_length[1]); + if(kd->key_data_length[1] != 0 + && kd->key_data_contents[1] == NULL) { + memset(kd->key_data_contents[0], 0, kd->key_data_length[0]); + ret = krb5_enomem(context->context); + break; + } + memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]); + out->n_key_data++; + } + + return ret; +} + +kadm5_ret_t +kadm5_s_get_principal(void *server_handle, + krb5_principal princ, + kadm5_principal_ent_t out, + uint32_t mask) +{ + kadm5_server_context *context = server_handle; + kadm5_ret_t ret; + hdb_entry ent; + unsigned int flags = HDB_F_GET_ANY | HDB_F_ADMIN_DATA; + + if ((mask & KADM5_KEY_DATA) || (mask & KADM5_KVNO)) + flags |= HDB_F_ALL_KVNOS | HDB_F_DECRYPT; + + memset(&ent, 0, sizeof(ent)); + memset(out, 0, sizeof(*out)); + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); + if (ret) + return ret; + } + + /* + * We may want to attempt to recover the log on read operations, but we + * because the HDB/log lock order is reversed on slaves, in order to avoid + * lock contention from kadm5srv apps we need to make sure that the the HDB + * open for read-write is optimistic and attempts only a non-blocking lock, + * and if it doesn't get it then it should fallback to read-only. But we + * don't have that option in the hdb_open() interface at this time. + * + * For now we won't attempt to recover the log. + */ + + ret = hdb_fetch_kvno(context->context, context->db, princ, flags, + 0 /*timestamp*/, 0/*etype*/, 0/*kvno*/, &ent); + + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + if(ret) + return _kadm5_error_code(ret); + + if(mask & KADM5_PRINCIPAL) + ret = krb5_copy_principal(context->context, ent.principal, + &out->principal); + if(ret) + goto out; + if(mask & KADM5_PRINC_EXPIRE_TIME && ent.valid_end) + out->princ_expire_time = *ent.valid_end; + if(mask & KADM5_PW_EXPIRATION && ent.pw_end) + out->pw_expiration = *ent.pw_end; + if(mask & KADM5_LAST_PWD_CHANGE) + hdb_entry_get_pw_change_time(&ent, &out->last_pwd_change); + if(mask & KADM5_ATTRIBUTES){ + out->attributes |= ent.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; + out->attributes |= ent.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; + out->attributes |= ent.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; + out->attributes |= ent.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; + out->attributes |= ent.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; + out->attributes |= ent.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; + out->attributes |= ent.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; + out->attributes |= ent.flags.require_pwchange ? KRB5_KDB_REQUIRES_PWCHANGE : 0; + out->attributes |= ent.flags.client ? 0 : KRB5_KDB_DISALLOW_CLIENT; + out->attributes |= ent.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; + out->attributes |= ent.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; + out->attributes |= ent.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; + out->attributes |= ent.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; + out->attributes |= ent.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; + out->attributes |= ent.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; + out->attributes |= ent.flags.virtual_keys ? KRB5_KDB_VIRTUAL_KEYS : 0; + out->attributes |= ent.flags.virtual ? KRB5_KDB_VIRTUAL : 0; + out->attributes |= ent.flags.no_auth_data_reqd ? KRB5_KDB_NO_AUTH_DATA_REQUIRED : 0; + out->attributes |= ent.flags.auth_data_reqd ? KRB5_KDB_AUTH_DATA_REQUIRED : 0; + } + if(mask & KADM5_MAX_LIFE) { + if(ent.max_life) + out->max_life = *ent.max_life; + else + out->max_life = INT_MAX; + } + if(mask & KADM5_MOD_TIME) { + if(ent.modified_by) + out->mod_date = ent.modified_by->time; + else + out->mod_date = ent.created_by.time; + } + if(mask & KADM5_MOD_NAME) { + if(ent.modified_by) { + if (ent.modified_by->principal != NULL) + ret = krb5_copy_principal(context->context, + ent.modified_by->principal, + &out->mod_name); + } else if(ent.created_by.principal != NULL) + ret = krb5_copy_principal(context->context, + ent.created_by.principal, + &out->mod_name); + else + out->mod_name = NULL; + } + if(ret) + goto out; + + if(mask & KADM5_KVNO) + out->kvno = ent.kvno; + if(mask & KADM5_MKVNO) { + size_t n; + out->mkvno = 0; /* XXX */ + for(n = 0; n < ent.keys.len; n++) + if(ent.keys.val[n].mkvno) { + out->mkvno = *ent.keys.val[n].mkvno; /* XXX this isn't right */ + break; + } + } +#if 0 /* XXX implement */ + if(mask & KADM5_AUX_ATTRIBUTES) + ; + if(mask & KADM5_LAST_SUCCESS) + ; + if(mask & KADM5_LAST_FAILED) + ; + if(mask & KADM5_FAIL_AUTH_COUNT) + ; +#endif + if(mask & KADM5_POLICY) { + HDB_extension *ext; + + ext = hdb_find_extension(&ent, choice_HDB_extension_data_policy); + if (ext == NULL) { + out->policy = strdup("default"); + /* It's OK if we retun NULL instead of "default" */ + } else { + out->policy = strdup(ext->data.u.policy); + if (out->policy == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + } + if(mask & KADM5_MAX_RLIFE) { + if(ent.max_renew) + out->max_renewable_life = *ent.max_renew; + else + out->max_renewable_life = INT_MAX; + } + if(mask & KADM5_KEY_DATA){ + size_t i; + size_t n_keys = ent.keys.len; + krb5_salt salt; + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys = NULL; + + /* Don't return stale keys to kadm5 clients */ + ret = hdb_prune_keys(context->context, &ent); + if (ret) + goto out; + ext = hdb_find_extension(&ent, choice_HDB_extension_data_hist_keys); + if (ext != NULL) + hist_keys = &ext->data.u.hist_keys; + + krb5_get_pw_salt(context->context, ent.principal, &salt); + for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) + n_keys += hist_keys->val[i].keys.len; + out->key_data = malloc(n_keys * sizeof(*out->key_data)); + if (out->key_data == NULL && n_keys != 0) { + ret = krb5_enomem(context->context); + goto out; + } + out->n_key_data = 0; + ret = copy_keyset_to_kadm5(context, ent.kvno, ent.keys.len, + ent.keys.val, &salt, out); + if (ret) + goto out; + for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) { + ret = copy_keyset_to_kadm5(context, hist_keys->val[i].kvno, + hist_keys->val[i].keys.len, + hist_keys->val[i].keys.val, + &salt, out); + if (ret) + goto out; + } + krb5_free_salt(context->context, salt); + assert( out->n_key_data == n_keys ); + } + assert(ret == 0); + if(mask & KADM5_TL_DATA) { + time_t last_pw_expire; + const HDB_Ext_PKINIT_acl *acl; + const HDB_Ext_Aliases *aliases; + const HDB_Ext_KeyRotation *kr; + heim_octet_string krb5_config; + + if (ent.etypes) { + krb5_data buf; + size_t len; + + ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length, + ent.etypes, &len, ret); + if (ret == 0) { + ret = add_tl_data(out, KRB5_TL_ETYPES, buf.data, buf.length); + free(buf.data); + } + if (ret) + goto out; + } + + ret = hdb_entry_get_pw_change_time(&ent, &last_pw_expire); + if (ret == 0 && last_pw_expire) { + unsigned char buf[4]; + _krb5_put_int(buf, last_pw_expire, sizeof(buf)); + ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); + if (ret) + goto out; + } + + ret = hdb_entry_get_krb5_config(&ent, &krb5_config); + if (ret == 0 && krb5_config.length) { + ret = add_tl_data(out, KRB5_TL_KRB5_CONFIG, krb5_config.data, + krb5_config.length); + if (ret) + goto out; + } + /* + * If the client was allowed to get key data, let it have the + * password too. + */ + if (mask & KADM5_KEY_DATA) { + heim_utf8_string pw; + + /* XXX But not if the client doesn't have ext-keys */ + ret = hdb_entry_get_password(context->context, + context->db, &ent, &pw); + if (ret == 0) { + ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); + free(pw); + if (ret) + goto out; + } + krb5_clear_error_message(context->context); + } + + ret = hdb_entry_get_pkinit_acl(&ent, &acl); + if (ret == 0 && acl) { + krb5_data buf; + size_t len; + + ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, + acl, &len, ret); + if (ret) + goto out; + if (len != buf.length) + krb5_abortx(context->context, + "internal ASN.1 encoder error"); + ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); + free(buf.data); + if (ret) + goto out; + } + + ret = hdb_entry_get_aliases(&ent, &aliases); + if (ret == 0 && aliases) { + krb5_data buf; + size_t len; + + ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, + aliases, &len, ret); + if (ret) + goto out; + if (len != buf.length) + krb5_abortx(context->context, + "internal ASN.1 encoder error"); + ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); + free(buf.data); + if (ret) + goto out; + } + + ret = hdb_entry_get_key_rotation(context->context, &ent, &kr); + if (ret == 0 && kr) { + krb5_data buf; + size_t len; + + ASN1_MALLOC_ENCODE(HDB_Ext_KeyRotation, buf.data, buf.length, + kr, &len, ret); + if (ret == 0) + ret = add_tl_data(out, KRB5_TL_KEY_ROTATION, buf.data, buf.length); + free(buf.data); + } + } + + out: + if (ret) + kadm5_free_principal_ent(context, out); + hdb_free_entry(context->context, context->db, &ent); + + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/init_c.c b/third_party/heimdal/lib/kadm5/init_c.c new file mode 100644 index 0000000..ffbb639 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/init_c.c @@ -0,0 +1,920 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +RCSID("$Id$"); + +static kadm5_ret_t +kadm5_c_lock(void *server_handle) +{ + return ENOTSUP; +} + +static kadm5_ret_t +kadm5_c_unlock(void *server_handle) +{ + return ENOTSUP; +} + +static void +set_funcs(kadm5_client_context *c) +{ +#define SET(C, F) (C)->funcs.F = kadm5 ## _c_ ## F +#define SETNOTIMP(C, F) (C)->funcs.F = 0 + SET(c, chpass_principal); + SET(c, chpass_principal_with_key); + SET(c, create_principal); + SET(c, delete_principal); + SET(c, destroy); + SET(c, flush); + SET(c, get_principal); + SET(c, get_principals); + SET(c, get_privs); + SET(c, modify_principal); + SET(c, prune_principal); + SET(c, randkey_principal); + SET(c, rename_principal); + SET(c, lock); + SET(c, unlock); + SETNOTIMP(c, setkey_principal_3); + SET(c, iter_principals); + SET(c, dup_context); +} + +kadm5_ret_t +_kadm5_c_init_context(kadm5_client_context **ctx, + kadm5_config_params *params, + krb5_context context) +{ + krb5_error_code ret; + char *colon; + + *ctx = malloc(sizeof(**ctx)); + if (*ctx == NULL) + return krb5_enomem(context); + memset(*ctx, 0, sizeof(**ctx)); + krb5_add_et_list(context, initialize_kadm5_error_table_r); + set_funcs(*ctx); + (*ctx)->context = context; + if (params->mask & KADM5_CONFIG_REALM) { + ret = 0; + (*ctx)->realm = strdup(params->realm); + if ((*ctx)->realm == NULL) + ret = krb5_enomem(context); + } else + ret = krb5_get_default_realm((*ctx)->context, &(*ctx)->realm); + if (ret) { + free(*ctx); + return ret; + } + + /* + * FIXME: If we have a hostlist, we should use the hostlist so that if we + * can't reach one server we try another. + */ + if (params->mask & KADM5_CONFIG_ADMIN_SERVER) + (*ctx)->admin_server = strdup(params->admin_server); + else { + char **hostlist; + + ret = krb5_get_krb_admin_hst(context, &(*ctx)->realm, &hostlist); + if (ret) { + free((*ctx)->realm); + free(*ctx); + return ret; + } + (*ctx)->admin_server = strdup(*hostlist); + krb5_free_krbhst(context, hostlist); + } + + if ((*ctx)->admin_server == NULL) { + free((*ctx)->realm); + free(*ctx); + return krb5_enomem(context); + } + colon = strchr((*ctx)->admin_server, ':'); + if (colon != NULL) + *colon++ = '\0'; + + (*ctx)->kadmind_port = 0; + + if (params->mask & KADM5_CONFIG_KADMIND_PORT) + (*ctx)->kadmind_port = params->kadmind_port; + else if (colon != NULL) { + char *end; + + (*ctx)->kadmind_port = htons(strtol(colon, &end, 0)); + } + if ((*ctx)->kadmind_port == 0) + (*ctx)->kadmind_port = krb5_getportbyname(context, "kerberos-adm", + "tcp", 749); + + if (params->mask & KADM5_CONFIG_READONLY_ADMIN_SERVER) { + (*ctx)->readonly_admin_server = strdup(params->readonly_admin_server); + if ((*ctx)->readonly_admin_server == NULL) { + free((*ctx)->realm); + free(*ctx); + return krb5_enomem(context); + } + } else { + char **hostlist; + + ret = krb5_get_krb_readonly_admin_hst(context, &(*ctx)->realm, + &hostlist); + if (ret == 0) { + (*ctx)->readonly_admin_server = strdup(*hostlist); + krb5_free_krbhst(context, hostlist); + if ((*ctx)->readonly_admin_server == NULL) { + free((*ctx)->realm); + free(*ctx); + return krb5_enomem(context); + } + } + } + if ((*ctx)->readonly_admin_server) { + colon = strchr((*ctx)->readonly_admin_server, ':'); + if (colon != NULL) + *colon++ = '\0'; + + } else { + colon = NULL; + } + + (*ctx)->readonly_kadmind_port = 0; + if (params->mask & KADM5_CONFIG_READONLY_KADMIN_PORT) + (*ctx)->readonly_kadmind_port = params->readonly_kadmind_port; + else if (colon != NULL) { + char *end; + + (*ctx)->readonly_kadmind_port = htons(strtol(colon, &end, 0)); + } + if ((*ctx)->readonly_kadmind_port == 0) + (*ctx)->readonly_kadmind_port = (*ctx)->kadmind_port; + return 0; +} + +kadm5_ret_t +kadm5_c_dup_context(void *vin, void **out) +{ + krb5_error_code ret; + kadm5_client_context *in = vin; + krb5_context context = in->context; + kadm5_client_context *ctx; + + *out = NULL; + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return krb5_enomem(in->context); + + + memset(ctx, 0, sizeof(*ctx)); + set_funcs(ctx); + ctx->readonly_kadmind_port = in->readonly_kadmind_port; + ctx->kadmind_port = in->kadmind_port; + + ret = krb5_copy_context(context, &(ctx->context)); + if (ret == 0) { + ctx->my_context = TRUE; + ret = krb5_add_et_list(ctx->context, initialize_kadm5_error_table_r); + } + if (ret == 0 && (ctx->realm = strdup(in->realm)) == NULL) + ret = krb5_enomem(context); + if (ret == 0 && + (ctx->admin_server = strdup(in->admin_server)) == NULL) + ret = krb5_enomem(context); + if (in->readonly_admin_server && + (ctx->readonly_admin_server = strdup(in->readonly_admin_server)) == NULL) + ret = krb5_enomem(context); + if (in->keytab && (ctx->keytab = strdup(in->keytab)) == NULL) + ret = krb5_enomem(context); + if (in->ccache) { + char *fullname = NULL; + + ret = krb5_cc_get_full_name(context, in->ccache, &fullname); + if (ret == 0) + ret = krb5_cc_resolve(context, fullname, &ctx->ccache); + free(fullname); + } + ctx->sock = -1; + if (ret == 0) + *out = ctx; + else + kadm5_c_destroy(ctx); + return ret; +} + +static krb5_error_code +get_kadm_ticket(krb5_context context, + krb5_ccache id, + krb5_principal client, + const char *server_name) +{ + krb5_error_code ret; + krb5_creds in, *out; + + memset(&in, 0, sizeof(in)); + in.client = client; + ret = krb5_parse_name(context, server_name, &in.server); + if(ret) + return ret; + ret = krb5_get_credentials(context, 0, id, &in, &out); + if(ret == 0) + krb5_free_creds(context, out); + krb5_free_principal(context, in.server); + return ret; +} + +static krb5_error_code +get_new_cache(krb5_context context, + krb5_principal client, + const char *password, + krb5_prompter_fct prompter, + const char *keytab, + const char *server_name, + krb5_ccache *ret_cache) +{ + krb5_error_code ret; + krb5_creds cred; + krb5_get_init_creds_opt *opt; + krb5_ccache id; + + ret = krb5_get_init_creds_opt_alloc (context, &opt); + if (ret) + return ret; + + krb5_get_init_creds_opt_set_default_flags(context, "kadmin", + krb5_principal_get_realm(context, + client), + opt); + + + krb5_get_init_creds_opt_set_forwardable (opt, FALSE); + krb5_get_init_creds_opt_set_proxiable (opt, FALSE); + + if(password == NULL && prompter == NULL) { + krb5_keytab kt; + if(keytab == NULL) + ret = krb5_kt_default(context, &kt); + else + ret = krb5_kt_resolve(context, keytab, &kt); + if(ret) { + krb5_get_init_creds_opt_free(context, opt); + return ret; + } + ret = krb5_get_init_creds_keytab (context, + &cred, + client, + kt, + 0, + server_name, + opt); + krb5_kt_close(context, kt); + } else { + ret = krb5_get_init_creds_password (context, + &cred, + client, + password, + prompter, + NULL, + 0, + server_name, + opt); + } + krb5_get_init_creds_opt_free(context, opt); + switch(ret){ + case 0: + break; + case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + case KRB5KRB_AP_ERR_MODIFIED: + return KADM5_BAD_PASSWORD; + default: + return ret; + } + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); + if(ret) + return ret; + ret = krb5_cc_initialize (context, id, cred.client); + if (ret) + return ret; + ret = krb5_cc_store_cred (context, id, &cred); + if (ret) + return ret; + krb5_free_cred_contents (context, &cred); + *ret_cache = id; + return 0; +} + +/* + * Check the credential cache `id´ to figure out what principal to use + * when talking to the kadmind. If there is a initial kadmin/admin@ + * credential in the cache, use that client principal. Otherwise, use + * the client principals first component and add /admin to the + * principal. + */ + +static krb5_error_code +get_cache_principal(krb5_context context, + krb5_ccache *id, + krb5_principal *client) +{ + krb5_error_code ret; + const char *name, *inst; + krb5_principal p1, p2; + + ret = krb5_cc_default(context, id); + if(ret) { + *id = NULL; + return ret; + } + + ret = krb5_cc_get_principal(context, *id, &p1); + if(ret) { + krb5_cc_close(context, *id); + *id = NULL; + return ret; + } + + ret = krb5_make_principal(context, &p2, NULL, + "kadmin", "admin", NULL); + if (ret) { + krb5_cc_close(context, *id); + *id = NULL; + krb5_free_principal(context, p1); + return ret; + } + + { + krb5_creds in, *out; + krb5_kdc_flags flags; + + flags.i = 0; + memset(&in, 0, sizeof(in)); + + in.client = p1; + in.server = p2; + + /* check for initial ticket kadmin/admin */ + ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags, + *id, &in, &out); + krb5_free_principal(context, p2); + if (ret == 0) { + if (out->flags.b.initial) { + *client = p1; + krb5_free_creds(context, out); + return 0; + } + krb5_free_creds(context, out); + } + } + krb5_cc_close(context, *id); + *id = NULL; + + name = krb5_principal_get_comp_string(context, p1, 0); + inst = krb5_principal_get_comp_string(context, p1, 1); + if(inst == NULL || strcmp(inst, "admin") != 0) { + ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL); + krb5_free_principal(context, p1); + if(ret != 0) + return ret; + + *client = p2; + return 0; + } + + *client = p1; + + return 0; +} + +krb5_error_code +_kadm5_c_get_cred_cache(krb5_context context, + const char *client_name, + const char *server_name, + const char *password, + krb5_prompter_fct prompter, + const char *keytab, + krb5_ccache ccache, + krb5_ccache *ret_cache) +{ + krb5_error_code ret; + krb5_ccache id = NULL; + krb5_principal default_client = NULL, client = NULL; + + /* treat empty password as NULL */ + if(password && *password == '\0') + password = NULL; + if(server_name == NULL) + server_name = KADM5_ADMIN_SERVICE; + + if(client_name != NULL) { + ret = krb5_parse_name(context, client_name, &client); + if(ret) + return ret; + } + + if(ccache != NULL) { + id = ccache; + ret = krb5_cc_get_principal(context, id, &client); + if(ret) + return ret; + } else { + /* get principal from default cache, ok if this doesn't work */ + + ret = get_cache_principal(context, &id, &default_client); + if (ret) { + /* + * No client was specified by the caller and we cannot + * determine the client from a credentials cache. + */ + char userbuf[128]; + const char *user = NULL; + +#ifndef WIN32 + if (geteuid() == 0) + user = roken_get_loginname(userbuf, sizeof(userbuf)); +#endif + if (user == NULL) + user = roken_get_username(userbuf, sizeof(userbuf)); + if (user == NULL) { + krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name"); + krb5_free_principal(context, client); + return KADM5_FAILURE; + } + ret = krb5_make_principal(context, &default_client, + NULL, user, "admin", NULL); + if (ret) { + krb5_free_principal(context, client); + return ret; + } + } + } + + + /* + * No client was specified by the caller, but we have a client + * from the default credentials cache. + */ + if (client == NULL && default_client != NULL) + client = default_client; + + + if(id && client && (default_client == NULL || + krb5_principal_compare(context, client, default_client) != 0)) { + ret = get_kadm_ticket(context, id, client, server_name); + if(ret == 0) { + *ret_cache = id; + krb5_free_principal(context, default_client); + if (default_client != client) + krb5_free_principal(context, client); + return 0; + } + if(ccache != NULL) + /* couldn't get ticket from cache */ + return -1; + } + /* get creds via AS request */ + if(id && (id != ccache)) + krb5_cc_close(context, id); + if (client != default_client) + krb5_free_principal(context, default_client); + + ret = get_new_cache(context, client, password, prompter, keytab, + server_name, ret_cache); + krb5_free_principal(context, client); + return ret; +} + +static kadm5_ret_t +kadm_connect(kadm5_client_context *ctx) +{ + kadm5_ret_t ret; + krb5_principal server = NULL; + krb5_ccache cc = NULL; + rk_socket_t s = rk_INVALID_SOCKET; + struct addrinfo *ai, *a; + struct addrinfo hints; + int free_ai = 0; + int error; + int kadmin_port = 0; + const char *admin_server = NULL; + char portstr[NI_MAXSERV]; + const char *hostname, *slash; + char *service_name = NULL; + krb5_context context = ctx->context; + int writable = 0; + + if (ctx->ac) + krb5_auth_con_free(context, ctx->ac); + ctx->ac = NULL; + + if (!ctx->want_write) { + admin_server = ctx->readonly_admin_server; + kadmin_port = ctx->readonly_kadmind_port; + } + if (admin_server == NULL) { + admin_server = ctx->admin_server; + writable = 1; + } + if (kadmin_port < 1) + kadmin_port = ctx->kadmind_port; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + snprintf(portstr, sizeof(portstr), "%u", ntohs(kadmin_port)); + + hostname = admin_server; + slash = strchr(hostname, '/'); + if (slash != NULL) + hostname = slash + 1; + + error = getaddrinfo(hostname, portstr, &hints, &ai); + if (error) { + ret = KADM5_BAD_SERVER_NAME; + goto out; + } + + free_ai = 1; + for (a = ai; a != NULL; a = a->ai_next) { + s = socket(a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) + continue; + if (connect(s, a->ai_addr, a->ai_addrlen) < 0) { + krb5_warn(context, errno, "connect(%s)", hostname); + rk_closesocket(s); + s = rk_INVALID_SOCKET; + continue; + } + break; + } + if (a == NULL) { + krb5_set_error_message(context, ret = KADM5_FAILURE, + "failed to contact %s", hostname); + goto out; + } + ret = _kadm5_c_get_cred_cache(context, + ctx->client_name, + ctx->service_name, + NULL, ctx->prompter, ctx->keytab, + ctx->ccache, &cc); + if (ret) + goto out; + + if (ctx->realm) + error = asprintf(&service_name, "%s@%s", KADM5_ADMIN_SERVICE, + ctx->realm); + else + error = asprintf(&service_name, "%s", KADM5_ADMIN_SERVICE); + + if (error == -1 || service_name == NULL) { + ret = krb5_enomem(context); + goto out; + } + + ret = krb5_parse_name(context, service_name, &server); + if (ret) + goto out; + + ret = krb5_sendauth(context, &ctx->ac, &s, + KADMIN_APPL_VERSION, NULL, + server, AP_OPTS_MUTUAL_REQUIRED, + NULL, NULL, cc, NULL, NULL, NULL); + if (ret == 0) { + krb5_data params; + kadm5_config_params p; + memset(&p, 0, sizeof(p)); + if(ctx->realm) { + p.mask |= KADM5_CONFIG_REALM; + p.realm = ctx->realm; + } + ret = _kadm5_marshal_params(context, &p, ¶ms); + if (ret == 0) { + ret = krb5_write_priv_message(context, ctx->ac, &s, ¶ms); + krb5_data_free(¶ms); + } + } + + if (ret == 0) { + ctx->sock = s; + ctx->connected_to_writable = !!writable; + } + +out: + free(service_name); + krb5_cc_close(context, cc); + krb5_free_principal(context, server); + if (free_ai) + freeaddrinfo(ai); + if (ret) { + if (s != rk_INVALID_SOCKET) + rk_closesocket(s); + krb5_auth_con_free(context, ctx->ac); + ctx->ac = NULL; + } + return ret; +} + +kadm5_ret_t +_kadm5_connect(void *handle, int want_write) +{ + kadm5_client_context *ctx = handle; + + /* + * Reconnect? Note that we don't reconnect to read-only kadmin servers if + * we're already connected to a writable kadmin server because we sometimes + * get a principal record after writing it. We really need the application + * upstairs to tell us when to stop hogging writable kadmin servers. + * + * FIXME: Add an API for marking a kadm5_client_context as not needing to + * connect to writable kadmin servers. + */ + ctx->want_write = !!want_write; + if (ctx->sock != rk_INVALID_SOCKET && want_write && + !ctx->connected_to_writable) { + rk_closesocket(ctx->sock); + ctx->sock = rk_INVALID_SOCKET; + } + if (ctx->sock == rk_INVALID_SOCKET) + return kadm_connect(ctx); + return 0; +} + +static kadm5_ret_t +kadm5_c_init_with_context(krb5_context context, + const char *client_name, + const char *password, + krb5_prompter_fct prompter, + const char *keytab, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + kadm5_ret_t ret; + kadm5_client_context *ctx = NULL; + krb5_ccache cc; + + ret = _kadm5_c_init_context(&ctx, realm_params, context); + if (ret) + return ret; + + if (password != NULL && *password != '\0') { + ret = _kadm5_c_get_cred_cache(context, + client_name, + service_name, + password, prompter, keytab, ccache, &cc); + if (ret) { + kadm5_c_destroy(ctx); + return ret; + } + ccache = cc; + } + + + if (client_name != NULL) + ctx->client_name = strdup(client_name); + else + ctx->client_name = NULL; + if (service_name != NULL) + ctx->service_name = strdup(service_name); + else + ctx->service_name = NULL; + ctx->prompter = prompter; + ctx->keytab = keytab; + ctx->ccache = ccache; + /* maybe we should copy the params here */ + ctx->sock = -1; + + *server_handle = ctx; + return 0; +} + +static kadm5_ret_t +init_context(const char *client_name, + const char *password, + krb5_prompter_fct prompter, + const char *keytab, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + krb5_context context; + kadm5_ret_t ret; + kadm5_server_context *ctx; + + ret = krb5_init_context(&context); + if (ret) + return ret; + ret = kadm5_c_init_with_context(context, + client_name, + password, + prompter, + keytab, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); + if(ret){ + krb5_free_context(context); + return ret; + } + ctx = *server_handle; + ctx->my_context = 1; + return 0; +} + +kadm5_ret_t +kadm5_c_init_with_password_ctx(krb5_context context, + const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_context(context, + client_name, + password, + krb5_prompter_posix, + NULL, + NULL, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_c_init_with_password(const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return init_context(client_name, + password, + krb5_prompter_posix, + NULL, + NULL, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_c_init_with_skey_ctx(krb5_context context, + const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_context(context, + client_name, + NULL, + NULL, + keytab, + NULL, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + + +kadm5_ret_t +kadm5_c_init_with_skey(const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return init_context(client_name, + NULL, + NULL, + keytab, + NULL, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_c_init_with_creds_ctx(krb5_context context, + const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_c_init_with_context(context, + client_name, + NULL, + NULL, + NULL, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_c_init_with_creds(const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return init_context(client_name, + NULL, + NULL, + NULL, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +#if 0 +kadm5_ret_t +kadm5_init(char *client_name, char *pass, + char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ +} +#endif + diff --git a/third_party/heimdal/lib/kadm5/init_s.c b/third_party/heimdal/lib/kadm5/init_s.c new file mode 100644 index 0000000..35402d8 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/init_s.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include + + +static kadm5_ret_t +kadm5_s_init_with_context(krb5_context context, + const char *client_name, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + kadm5_ret_t ret; + kadm5_server_context *ctx = NULL; + char *dbname; + char *stash_file; + + *server_handle = NULL; + ret = _kadm5_s_init_context(&ctx, realm_params, context); + if (ret) { + kadm5_s_destroy(ctx); + return ret; + } + + if (realm_params->mask & KADM5_CONFIG_DBNAME) + dbname = realm_params->dbname; + else + dbname = ctx->config.dbname; + + if (realm_params->mask & KADM5_CONFIG_STASH_FILE) + stash_file = realm_params->stash_file; + else + stash_file = ctx->config.stash_file; + + assert(dbname != NULL); + assert(stash_file != NULL); + assert(ctx->config.acl_file != NULL); + assert(ctx->log_context.log_file != NULL); +#ifndef NO_UNIX_SOCKETS + assert(ctx->log_context.socket_name.sun_path[0] != '\0'); +#else + assert(ctx->log_context.socket_info != NULL); +#endif + + ret = hdb_create(ctx->context, &ctx->db, dbname); + if (ret == 0) + ret = hdb_set_master_keyfile(ctx->context, + ctx->db, stash_file); + if (ret) { + kadm5_s_destroy(ctx); + return ret; + } + + ctx->log_context.log_fd = -1; + +#ifndef NO_UNIX_SOCKETS + ctx->log_context.socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0); +#else + ctx->log_context.socket_fd = socket(ctx->log_context.socket_info->ai_family, + ctx->log_context.socket_info->ai_socktype, + ctx->log_context.socket_info->ai_protocol); +#endif + + if (ctx->log_context.socket_fd != rk_INVALID_SOCKET) + socket_set_nonblocking(ctx->log_context.socket_fd, 1); + + ret = krb5_parse_name(ctx->context, client_name, &ctx->caller); + if (ret == 0) + ret = _kadm5_acl_init(ctx); + if (ret) + kadm5_s_destroy(ctx); + else + *server_handle = ctx; + return ret; +} + +kadm5_ret_t +kadm5_s_dup_context(void *vin, void **out) +{ + kadm5_server_context *in = vin; + kadm5_ret_t ret; + char *p = NULL; + + ret = krb5_unparse_name(in->context, in->caller, &p); + if (ret == 0) + ret = kadm5_s_init_with_context(in->context, p, NULL, + &in->config, 0, 0, out); + free(p); + return ret; +} + +kadm5_ret_t +kadm5_s_init_with_password_ctx(krb5_context context, + const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_context(context, + client_name, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_s_init_with_password(const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + krb5_context context; + kadm5_ret_t ret; + kadm5_server_context *ctx; + + ret = krb5_init_context(&context); + if (ret) + return ret; + ret = kadm5_s_init_with_password_ctx(context, + client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); + if(ret){ + krb5_free_context(context); + return ret; + } + ctx = *server_handle; + ctx->my_context = 1; + return 0; +} + +kadm5_ret_t +kadm5_s_init_with_skey_ctx(krb5_context context, + const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_context(context, + client_name, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_s_init_with_skey(const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + krb5_context context; + kadm5_ret_t ret; + kadm5_server_context *ctx; + + ret = krb5_init_context(&context); + if (ret) + return ret; + ret = kadm5_s_init_with_skey_ctx(context, + client_name, + keytab, + service_name, + realm_params, + struct_version, + api_version, + server_handle); + if(ret){ + krb5_free_context(context); + return ret; + } + ctx = *server_handle; + ctx->my_context = 1; + return 0; +} + +kadm5_ret_t +kadm5_s_init_with_creds_ctx(krb5_context context, + const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_context(context, + client_name, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_s_init_with_creds(const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + krb5_context context; + kadm5_ret_t ret; + kadm5_server_context *ctx; + + ret = krb5_init_context(&context); + if (ret) + return ret; + ret = kadm5_s_init_with_creds_ctx(context, + client_name, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); + if(ret){ + krb5_free_context(context); + return ret; + } + ctx = *server_handle; + ctx->my_context = 1; + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/iprop-commands.in b/third_party/heimdal/lib/kadm5/iprop-commands.in new file mode 100644 index 0000000..5b59e5a --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop-commands.in @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* $Id$ */ + +command = { + name = "dump" + option = { + long = "config-file" + short = "c" + type = "string" + help = "configuration file" + argument = "file" + } + option = { + long = "no-lock" + short = "n" + type = "flag" + help = "don't lock iprop log" + } + option = { + long = "reverse" + short = "R" + type = "flag" + help = "dump the log in reverse order" + } + option = { + long = "realm" + short = "r" + type = "string" + help = "realm" + } + function = "iprop_dump" + help = "Prints the iprop transaction log in text." + max_args = "1" +} +command = { + name = "truncate" + option = { + long = "config-file" + short = "c" + type = "string" + help = "configuration file" + argument = "file" + } + option = { + long = "realm" + short = "r" + type = "string" + help = "realm" + } + option = { + long = "keep-entries" + short = "K" + type = "integer" + help = "number of entries to keep" + default = "-1" + } + option = { + long = "max-bytes" + short = "B" + type = "integer" + help = "keep entries that fit in the given number of bytes" + default = "-1" + } + option = { + long = "reset" + short = "R" + type = "flag" + help = "reset the log to version 1; forces full propagation" + default = "0"; + } + function = "iprop_truncate" + help = "Truncate the log, preserve the version number. Keeps 100 entries by default." + max_args = "1" +} +command = { + name = "replay" + option = { + long = "start-version" + type = "integer" + help = "start replay with this version" + argument = "version-number" + default = "-1" + } + option = { + long = "end-version" + type = "integer" + help = "end replay with this version" + argument = "version-number" + default = "-1" + } + option = { + long = "config-file" + short = "c" + type = "string" + help = "configuration file" + argument = "file" + } + option = { + long = "realm" + short = "r" + type = "string" + help = "realm" + } + function = "iprop_replay" + help = "Replay the log on the database." + max_args = "1" +} +command = { + name = "last-version" + option = { + long = "config-file" + short = "c" + type = "string" + help = "configuration file" + argument = "file" + } + option = { + long = "no-lock" + short = "n" + type = "flag" + help = "don't lock iprop log" + } + option = { + long = "realm" + short = "r" + type = "string" + help = "realm" + } + function = "last_version" + help = "Print the last version of the log-file." +} +command = { + name = "signal" + option = { + long = "config-file" + short = "c" + type = "string" + help = "configuration file" + argument = "file" + } + option = { + long = "realm" + short = "r" + type = "string" + help = "realm" + } + function = "signal_master" + help = "Print the last version of the log-file." + max_args = "0" +} +command = { + name = "help" + argument = "command" + max_args = "1" + function = "help" +} diff --git a/third_party/heimdal/lib/kadm5/iprop-log-version.rc b/third_party/heimdal/lib/kadm5/iprop-log-version.rc new file mode 100644 index 0000000..b8a2295 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop-log-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "IProp Log Tool" +#define RC_FILE_ORIG_0409 "iprop-log.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/kadm5/iprop-log.8 b/third_party/heimdal/lib/kadm5/iprop-log.8 new file mode 100644 index 0000000..f34d800 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop-log.8 @@ -0,0 +1,254 @@ +.\" $Id$ +.\" +.\" Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 18, 2007 +.Dt IPROP-LOG 8 +.Os +.Sh NAME +.Nm iprop-log +.Nd examine and maintain the iprop log file +.Sh SYNOPSIS +.Nm +.Op Fl Fl version +.Op Fl h | Fl Fl help +.Ar command +.Pp +.Nm iprop-log truncate +.Oo Fl c Ar file \*(Ba Xo +.Fl Fl config-file= Ns Ar file +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Oo Fl K Ar integer \*(Ba Xo +.Fl Fl keep-entries= Ns Ar integer +.Xc +.Oc +.Oo Fl B Ar integer \*(Ba Xo +.Fl Fl max-bytes= Ns Ar integer +.Xc +.Oc +.Oo Fl R \*(Ba Xo +.Fl Fl reset +.Xc +.Oc +.Op Fl h | Fl Fl help +.Op Ar log-file +.Pp +.Nm iprop-log dump +.Oo Fl c Ar file \*(Ba Xo +.Fl Fl config-file= Ns Ar file +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Oo Fl n \*(Ba Xo +.Fl Fl no-lock +.Xc +.Oc +.Oo Fl R \*(Ba Xo +.Fl Fl reverse +.Xc +.Oc +.Op Fl h | Fl Fl help +.Op Ar log-file +.Pp +.Nm iprop-log replay +.Op Fl Fl start-version= Ns Ar version-number +.Op Fl Fl end-version= Ns Ar version-number +.Oo Fl c Ar file \*(Ba Xo +.Fl Fl config-file= Ns Ar file +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Op Fl h | Fl Fl help +.Op Ar log-file +.Pp +.Nm iprop-log last-version +.Oo Fl c Ar file \*(Ba Xo +.Fl Fl config-file= Ns Ar file +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Oo Fl n \*(Ba Xo +.Fl Fl no-lock +.Xc +.Oc +.Op Fl h | Fl Fl help +.Op Ar log-files +.Pp +.Nm iprop-log signal +.Oo Fl c Ar file \*(Ba Xo +.Fl Fl config-file= Ns Ar file +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Op Fl h | Fl Fl help +.Pp +.Sh DESCRIPTION +Supported options: +.Bl -tag -width Ds +.It Fl Fl version +.It Fl h , Fl Fl help +.El +.Pp +command can be one of the following: +.Bl -tag -width truncate +.It truncate +.Bl -tag -width Ds +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +configuration file +.It Fl r Ar string , Fl Fl realm= Ns Ar string +realm +.It Xo +.Fl K Ar integer , +.Fl Fl keep-entries= Ns Ar integer +.Xc +.It Xo +.Fl B Ar integer , +.Fl Fl max-bytes= Ns Ar integer +.Xc +.It Xo +.Fl R , +.Fl Fl reset +.Xc +.El +.Pp +If +.Fl Fl reset +is given, then the given, configured, or default log file will be +truncated and will start at version 1. This forces full propagations to +all slave KDCs. +.Pp +Otherwise the log will be truncated but some entries will be preserved, +as specified by the +.Fl Fl keep-entries +and/or +.Fl Fl max-bytes +options. The largest number of +.Fl Fl keep-entries +entries that are available and fit in the given +.Fl Fl max-bytes +option will be used. The +.Fl Fl keep-entries option defaults to 100, and the +.Fl Fl max-bytes +option defaults to the +.Ar log-max-size +parameter in the configuration. +.Pp +.It dump +.Bl -tag -width Ds +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +configuration file +.It Xo +.Fl r Ar string , +.Fl Fl realm= Ns Ar string +.Xc +realm +.It Xo +.Fl n Ar string , +.Fl Fl no-lock +.Xc +.It Xo +.Fl R Ar string , +.Fl Fl reverse +.Xc +.El +.Pp +Print out all entries in the given, configured, or default log file to +standard output. If the +.Fl n +option is used then don't lock the iprop log file. If the +.Fl R +option is used, then print the entries in reverse order +(this can be useful when the log is very large). +.It replay +.Bl -tag -width Ds +.It Fl Fl start-version= Ns Ar version-number +start replay with this version +.It Xo +.Fl Fl end-version= Ns Ar version-number +.Xc +end replay with this version +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +configuration file +.It Fl r Ar string , Fl Fl realm= Ns Ar string +realm +.El +.Pp +Replay the changes from specified entries (or all if none is specified) +in the given, configured, or default transaction log file to the +database. +.It last-version +.Bl -tag -width Ds +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +configuration file +.It Fl r Ar string , Fl Fl realm= Ns Ar string +realm +.It Xo +.Fl n Ar string , +.Fl Fl no-lock +.Xc +.El +.Pp +prints the version of the last record in each of the given log files, or +the configured, or the default log file if none is given. +.It signal +.Bl -tag -width Ds +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +configuration file +.It Fl r Ar string , Fl Fl realm= Ns Ar string +realm +.El +.Pp +Signals the ipropd-master daemon to send updates to slaves. Normally +kadmin does this every time it writes to the database, so this should +rarely be needed. +.El +.Sh SEE ALSO +.Xr iprop 8 diff --git a/third_party/heimdal/lib/kadm5/iprop-log.c b/third_party/heimdal/lib/kadm5/iprop-log.c new file mode 100644 index 0000000..a2ad51e --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop-log.c @@ -0,0 +1,653 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "iprop.h" +#include +#include +#include "iprop-commands.h" + +RCSID("$Id$"); + +static krb5_context context; + +static kadm5_server_context * +get_kadmin_context(const char *config_file, char *realm) +{ + kadm5_config_params conf; + krb5_error_code ret; + void *kadm_handle; + char *file = NULL; + char **files; + int aret; + + if (config_file == NULL) { + aret = asprintf(&file, "%s/kdc.conf", hdb_db_dir(context)); + if (aret == -1 || file == NULL) + errx(1, "out of memory"); + config_file = file; + } + + ret = krb5_prepend_config_files_default(config_file, &files); + free(file); + if (ret) + krb5_err(context, 1, ret, "getting configuration files"); + + ret = krb5_set_config_files(context, files); + krb5_free_config_files(files); + if (ret) + krb5_err(context, 1, ret, "reading configuration files"); + + memset(&conf, 0, sizeof(conf)); + if(realm) { + conf.mask |= KADM5_CONFIG_REALM; + conf.realm = realm; + } + + ret = kadm5_init_with_password_ctx (context, + KADM5_ADMIN_SERVICE, + NULL, + KADM5_ADMIN_SERVICE, + &conf, 0, 0, + &kadm_handle); + if (ret) + krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); + + return (kadm5_server_context *)kadm_handle; +} + +/* + * dump log + */ + +static const char *op_names[] = { + "get", + "delete", + "create", + "rename", + "chpass", + "modify", + "randkey", + "get_privs", + "get_princs", + "chpass_with_key", + "nop" +}; + +static kadm5_ret_t +print_entry(kadm5_server_context *server_context, + uint32_t ver, + time_t timestamp, + enum kadm_ops op, + uint32_t len, + krb5_storage *sp, + void *ctx) +{ + char t[256]; + const char *entry_kind = ctx; + int32_t mask; + int32_t nop_time; + uint32_t nop_ver; + hdb_entry ent; + krb5_principal source; + char *name1, *name2; + krb5_data data; + krb5_context scontext = server_context->context; + krb5_error_code ret; + + krb5_data_zero(&data); + + strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + + if((int)op < (int)kadm_get || (int)op > (int)kadm_nop) { + printf("unknown op: %d\n", op); + return 0; + } + + printf ("%s%s: ver = %u, timestamp = %s, len = %u\n", + entry_kind, op_names[op], ver, t, len); + switch(op) { + case kadm_delete: + ret = krb5_ret_principal(sp, &source); + if (ret == 0) + ret = krb5_unparse_name(scontext, source, &name1); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a delete record"); + printf(" %s\n", name1); + free(name1); + krb5_free_principal(scontext, source); + break; + case kadm_rename: + ret = krb5_data_alloc(&data, len); + if (ret == 0) + ret = krb5_ret_principal(sp, &source); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); + if (ret == 0) + ret = krb5_unparse_name(scontext, source, &name1); + if (ret == 0) + ret = krb5_unparse_name(scontext, ent.principal, &name2); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a rename record"); + printf(" %s -> %s\n", name1, name2); + free(name1); + free(name2); + krb5_free_principal(scontext, source); + free_hdb_entry(&ent); + break; + case kadm_create: + ret = krb5_data_alloc(&data, len); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a create record"); + mask = ~0; + goto foo; + case kadm_modify: + ret = krb5_data_alloc(&data, len); + if (ret == 0) + ret = krb5_ret_int32(sp, &mask); + if (ret == 0 && krb5_storage_read(sp, data.data, data.length) == -1) + ret = errno; + if (ret == 0) + ret = hdb_value2entry(scontext, &data, &ent); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a modify record"); + foo: + if(ent.principal /* mask & KADM5_PRINCIPAL */) { + ret = krb5_unparse_name(scontext, ent.principal, &name1); + if (ret) + krb5_err(scontext, 1, ret, + "Failed to process a create or modify record"); + printf(" principal = %s\n", name1); + free(name1); + } + if(mask & KADM5_PRINC_EXPIRE_TIME) { + if(ent.valid_end == NULL) { + strlcpy(t, "never", sizeof(t)); + } else { + strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", + localtime(ent.valid_end)); + } + printf(" expires = %s\n", t); + } + if(mask & KADM5_PW_EXPIRATION) { + if(ent.pw_end == NULL) { + strlcpy(t, "never", sizeof(t)); + } else { + strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", + localtime(ent.pw_end)); + } + printf(" password exp = %s\n", t); + } + if(mask & KADM5_LAST_PWD_CHANGE) { + } + if(mask & KADM5_ATTRIBUTES) { + unparse_flags(HDBFlags2int(ent.flags), + asn1_HDBFlags_units(), t, sizeof(t)); + printf(" attributes = %s\n", t); + } + if(mask & KADM5_MAX_LIFE) { + if(ent.max_life == NULL) + strlcpy(t, "for ever", sizeof(t)); + else + unparse_time(*ent.max_life, t, sizeof(t)); + printf(" max life = %s\n", t); + } + if(mask & KADM5_MAX_RLIFE) { + if(ent.max_renew == NULL) + strlcpy(t, "for ever", sizeof(t)); + else + unparse_time(*ent.max_renew, t, sizeof(t)); + printf(" max rlife = %s\n", t); + } + if(mask & KADM5_MOD_TIME) { + printf(" mod time\n"); + } + if(mask & KADM5_MOD_NAME) { + printf(" mod name\n"); + } + if(mask & KADM5_KVNO) { + printf(" kvno = %d\n", ent.kvno); + } + if(mask & KADM5_MKVNO) { + printf(" mkvno\n"); + } + if(mask & KADM5_AUX_ATTRIBUTES) { + printf(" aux attributes\n"); + } + if(mask & KADM5_POLICY) { + printf(" policy\n"); + } + if(mask & KADM5_POLICY_CLR) { + printf(" mod time\n"); + } + if(mask & KADM5_LAST_SUCCESS) { + printf(" last success\n"); + } + if(mask & KADM5_LAST_FAILED) { + printf(" last failed\n"); + } + if(mask & KADM5_FAIL_AUTH_COUNT) { + printf(" fail auth count\n"); + } + if(mask & KADM5_KEY_DATA) { + printf(" key data\n"); + } + if(mask & KADM5_TL_DATA) { + printf(" tl data\n"); + } + free_hdb_entry(&ent); + break; + case kadm_nop : + if (len == 16) { + uint64_t off; + ret = krb5_ret_uint64(sp, &off); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a no-op record"); + printf("uberblock offset %llu ", (unsigned long long)off); + } else { + printf("nop"); + } + if (len == 16 || len == 8) { + ret = krb5_ret_int32(sp, &nop_time); + if (ret == 0) + ret = krb5_ret_uint32(sp, &nop_ver); + if (ret) + krb5_err(scontext, 1, ret, "Failed to read a no-op record"); + + timestamp = nop_time; + strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + printf("timestamp %s version %u", t, nop_ver); + } + printf("\n"); + break; + default: + krb5_errx(scontext, 1, "Unknown record type"); + } + krb5_data_free(&data); + + return 0; +} + +int +iprop_dump(struct dump_options *opt, int argc, char **argv) +{ + kadm5_server_context *server_context; + krb5_error_code ret; + enum kadm_iter_opts iter_opts_1st = 0; + enum kadm_iter_opts iter_opts_2nd = 0; + char *desc_1st = ""; + char *desc_2nd = ""; + + server_context = get_kadmin_context(opt->config_file_string, + opt->realm_string); + + if (argc > 0) { + free(server_context->log_context.log_file); + server_context->log_context.log_file = strdup(argv[0]); + if (server_context->log_context.log_file == NULL) + krb5_err(context, 1, errno, "strdup"); + } + + if (opt->reverse_flag) { + iter_opts_1st = kadm_backward | kadm_unconfirmed; + iter_opts_2nd = kadm_backward | kadm_confirmed; + desc_1st = "unconfirmed "; + } else { + iter_opts_1st = kadm_forward | kadm_confirmed; + iter_opts_2nd = kadm_forward | kadm_unconfirmed; + desc_2nd = "unconfirmed"; + } + + if (opt->no_lock_flag) { + ret = kadm5_log_init_sharedlock(server_context, LOCK_NB); + if (ret == EAGAIN || ret == EWOULDBLOCK) { + warnx("Not locking the iprop log"); + ret = kadm5_log_init_nolock(server_context); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init_nolock"); + } + } else { + warnx("If this command appears to block, try the --no-lock option"); + ret = kadm5_log_init_sharedlock(server_context, 0); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init_sharedlock"); + } + + ret = kadm5_log_foreach(server_context, iter_opts_1st, + NULL, print_entry, desc_1st); + if (ret) + krb5_warn(context, ret, "kadm5_log_foreach"); + + ret = kadm5_log_foreach(server_context, iter_opts_2nd, + NULL, print_entry, desc_2nd); + if (ret) + krb5_warn(context, ret, "kadm5_log_foreach"); + + ret = kadm5_log_end (server_context); + if (ret) + krb5_warn(context, ret, "kadm5_log_end"); + + kadm5_destroy(server_context); + return 0; +} + +int +iprop_truncate(struct truncate_options *opt, int argc, char **argv) +{ + kadm5_server_context *server_context; + krb5_error_code ret; + + server_context = get_kadmin_context(opt->config_file_string, + opt->realm_string); + + if (argc > 0) { + free(server_context->log_context.log_file); + server_context->log_context.log_file = strdup(argv[0]); + if (server_context->log_context.log_file == NULL) + krb5_err(context, 1, errno, "strdup"); + } + + if (opt->keep_entries_integer < 0 && + opt->max_bytes_integer < 0) { + opt->keep_entries_integer = 100; + opt->max_bytes_integer = 0; + } + if (opt->keep_entries_integer < 0) + opt->keep_entries_integer = 0; + if (opt->max_bytes_integer < 0) + opt->max_bytes_integer = 0; + + if (opt->reset_flag) { + /* First recover unconfirmed records */ + ret = kadm5_log_init(server_context); + if (ret == 0) + ret = kadm5_log_reinit(server_context, 0); + } else { + ret = kadm5_log_init(server_context); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init"); + ret = kadm5_log_truncate(server_context, opt->keep_entries_integer, + opt->max_bytes_integer); + } + if (ret) + krb5_err(context, 1, ret, "kadm5_log_truncate"); + + kadm5_log_signal_master(server_context); + + kadm5_destroy(server_context); + return 0; +} + +int +last_version(struct last_version_options *opt, int argc, char **argv) +{ + kadm5_server_context *server_context; + char *alt_argv[2] = { NULL, NULL }; + krb5_error_code ret; + uint32_t version; + size_t i; + + server_context = get_kadmin_context(opt->config_file_string, + opt->realm_string); + + if (argc == 0) { + alt_argv[0] = strdup(server_context->log_context.log_file); + if (alt_argv[0] == NULL) + krb5_err(context, 1, errno, "strdup"); + argv = alt_argv; + argc = 1; + } + + for (i = 0; i < argc; i++) { + free(server_context->log_context.log_file); + server_context->log_context.log_file = strdup(argv[i]); + if (server_context->log_context.log_file == NULL) + krb5_err(context, 1, errno, "strdup"); + + if (opt->no_lock_flag) { + ret = kadm5_log_init_sharedlock(server_context, LOCK_NB); + if (ret == EAGAIN || ret == EWOULDBLOCK) { + warnx("Not locking the iprop log"); + ret = kadm5_log_init_nolock(server_context); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init_nolock"); + } + } else { + warnx("If this command appears to block, try the " + "--no-lock option"); + ret = kadm5_log_init_sharedlock(server_context, 0); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init_sharedlock"); + } + + ret = kadm5_log_get_version (server_context, &version); + if (ret) + krb5_err (context, 1, ret, "kadm5_log_get_version"); + + ret = kadm5_log_end (server_context); + if (ret) + krb5_warn(context, ret, "kadm5_log_end"); + + printf("version: %lu\n", (unsigned long)version); + } + + kadm5_destroy(server_context); + free(alt_argv[0]); + return 0; +} + +int +signal_master(struct signal_options *opt, int argc, char **argv) +{ + kadm5_server_context *server_context; + + server_context = get_kadmin_context(opt->config_file_string, + opt->realm_string); + + kadm5_log_signal_master(server_context); + + kadm5_destroy(server_context); + return 0; +} + +/* + * Replay log + */ + +int start_version = -1; +int end_version = -1; + +static kadm5_ret_t +apply_entry(kadm5_server_context *server_context, + uint32_t ver, + time_t timestamp, + enum kadm_ops op, + uint32_t len, + krb5_storage *sp, + void *ctx) +{ + struct replay_options *opt = ctx; + krb5_error_code ret; + + if((opt->start_version_integer != -1 && ver < (uint32_t)opt->start_version_integer) || + (opt->end_version_integer != -1 && ver > (uint32_t)opt->end_version_integer)) { + /* XXX skip this entry */ + return 0; + } + printf ("ver %u... ", ver); + fflush (stdout); + + ret = kadm5_log_replay(server_context, op, ver, len, sp); + if (ret) + krb5_warn (server_context->context, ret, "kadm5_log_replay"); + + printf ("done\n"); + + return 0; +} + +int +iprop_replay(struct replay_options *opt, int argc, char **argv) +{ + kadm5_server_context *server_context; + krb5_error_code ret; + + server_context = get_kadmin_context(opt->config_file_string, + opt->realm_string); + + if (argc > 0) { + free(server_context->log_context.log_file); + server_context->log_context.log_file = strdup(argv[0]); + if (server_context->log_context.log_file == NULL) + krb5_err(context, 1, errno, "strdup"); + } + + ret = server_context->db->hdb_open(context, + server_context->db, + O_RDWR | O_CREAT, 0600); + if (ret) + krb5_err (context, 1, ret, "db->open"); + + ret = kadm5_log_init (server_context); + if (ret) + krb5_err (context, 1, ret, "kadm5_log_init"); + + ret = kadm5_log_foreach(server_context, + kadm_forward | kadm_confirmed | kadm_unconfirmed, + NULL, apply_entry, opt); + if(ret) + krb5_warn(context, ret, "kadm5_log_foreach"); + ret = kadm5_log_end (server_context); + if (ret) + krb5_warn(context, ret, "kadm5_log_end"); + ret = server_context->db->hdb_close (context, server_context->db); + if (ret) + krb5_err (context, 1, ret, "db->close"); + + kadm5_destroy(server_context); + return 0; +} + +static int help_flag; +static int version_flag; + +static struct getargs args[] = { + { "version", 0, arg_flag, &version_flag, + NULL, NULL + }, + { "help", 'h', arg_flag, &help_flag, + NULL, NULL + } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +int +help(void *opt, int argc, char **argv) +{ + if(argc == 0) { + sl_help(commands, 1, argv - 1 /* XXX */); + } else { + SL_cmd *c = sl_match (commands, argv[0], 0); + if(c == NULL) { + fprintf (stderr, "No such command: %s. " + "Try \"help\" for a list of commands\n", + argv[0]); + } else { + if(c->func) { + static char shelp[] = "--help"; + char *fake[3]; + fake[0] = argv[0]; + fake[1] = shelp; + fake[2] = NULL; + (*c->func)(2, fake); + fprintf(stderr, "\n"); + } + if(c->help && *c->help) + fprintf (stderr, "%s\n", c->help); + if((++c)->name && c->func == NULL) { + int f = 0; + fprintf (stderr, "Synonyms:"); + while (c->name && c->func == NULL) { + fprintf (stderr, "%s%s", f ? ", " : " ", (c++)->name); + f = 1; + } + fprintf (stderr, "\n"); + } + } + } + return 0; +} + +static void +usage(int status) +{ + arg_printusage(args, num_args, NULL, "command"); + exit(status); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + krb5_error_code ret; + + setprogname(argv[0]); + + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + argc -= optidx; + argv += optidx; + if(argc == 0) + usage(1); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context failed with: %d\n", ret); + + ret = sl_command(commands, argc, argv); + if(ret == -1) + warnx ("unrecognized command: %s", argv[0]); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/iprop.8 b/third_party/heimdal/lib/kadm5/iprop.8 new file mode 100644 index 0000000..41aac06 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop.8 @@ -0,0 +1,246 @@ +.\" $Id$ +.\" +.\" Copyright (c) 2005 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 24, 2005 +.Dt IPROP 8 +.Os +.Sh NAME +.Nm iprop , +.Nm ipropd-master , +.Nm ipropd-slave +.Nd propagate transactions from a Heimdal Kerberos master KDC to slave KDCs +.Sh SYNOPSIS +.Nm ipropd-master +.Oo Fl c Ar string \*(Ba Xo +.Fl Fl config-file= Ns Ar string +.Xc +.Oc +.Oo Fl r Ar string \*(Ba Xo +.Fl Fl realm= Ns Ar string +.Xc +.Oc +.Oo Fl k Ar kspec \*(Ba Xo +.Fl Fl keytab= Ns Ar kspec +.Xc +.Oc +.Oo Fl d Ar file \*(Ba Xo +.Fl Fl database= Ns Ar file +.Xc +.Oc +.Op Fl Fl slave-stats-file= Ns Ar file +.Op Fl Fl time-missing= Ns Ar time +.Op Fl Fl time-gone= Ns Ar time +.Op Fl Fl detach +.Op Fl Fl version +.Op Fl Fl help +.Nm ipropd-slave +.Oo Fl c Ar string \*(Ba Xo Fl Fl config-file= Ns Ar string Xc Oc +.Oo Fl r Ar string \*(Ba Xo Fl Fl realm= Ns Ar string Xc Oc +.Oo Fl d Ar file \*(Ba Xo Fl Fl database= Ns Ar file Xc Oc +.Oo Fl k Ar kspec \*(Ba Xo Fl Fl keytab= Ns Ar kspec Xc Oc +.Oo Xo Fl Fl no-keytab Xc Oc +.Oo Xo Fl Fl cache= Ns Ar cspec Xc Oc +.Op Fl Fl statusfile= Ns Ar file +.Op Fl Fl hostname= Ns Ar hostname +.Op Fl Fl port= Ns Ar port +.Op Fl Fl time-lost= Ns Ar time +.Op Fl Fl async-hdb +.Op Fl Fl detach +.Op Fl Fl version +.Op Fl Fl help +.Ar master +.Sh DESCRIPTION +.Nm ipropd-master +is used to propagate changes to a Heimdal Kerberos database from the +master Kerberos server on which it runs to slave Kerberos servers +running +.Nm ipropd-slave . +.Pp +The slaves are specified by the contents of the +.Pa slaves +file in the KDC's database directory, e.g.\& +.Pa /var/heimdal/slaves . +This has principals one per-line of the form +.Dl iprop/ Ns Ar slave Ns @ Ns Ar REALM +where +.Ar slave +is the hostname of the slave server in the given +.Ar REALM , +e.g.\& +.Dl iprop/kerberos-1.example.com@EXAMPLE.COM +On a slave, the argument +.Fa master +specifies the hostname of the master server from which to receive updates. +.Pp +In contrast to +.Xr hprop 8 , +which sends the whole database to the slaves regularly, +.Nm +normally sends only the changes as they happen on the master. +The master keeps track of all the changes by assigning a version +number to every transaction to the database. +The slaves know which was the latest version they saw, and in this +way it can be determined if they are in sync or not. +A log of all the transactions is kept on the master. +When a slave is at an older version than the oldest one in the log, +the whole database has to be sent. +.Pp +The log of transactions is also used to implement a two-phase commit +(with roll-forward for recovery) method of updating the HDB. +Transactions are first recorded in the log, then in the HDB, then +the log is updated to mark the transaction as committed. +.Pp +The changes are propagated over a secure channel (on port 2121 by +default). +This should normally be defined as +.Dq iprop/tcp +in +.Pa /etc/services +or another source of the services database. +.Pp +The +.Nm ipropd-master +and +.Nm ipropd-slave +programs require acceptor and initiator credentials, +respectively, for host-based principals for the +.Ar iprop +service and the fully-qualified hostnames of the hosts on which +they run. +.Pp +The +.Nm ipropd-master +program uses, by default, the HDB-backed keytab +.Ar HDBGET: , +though a file-based keytab can also be specified. +.Pp +The +.Nm ipropd-slave +program uses the default keytab, which is specified by the +.Ev KRB5_KTNAME +environment variable, or the value of the +.Ar default_keytab_name +configuration parameter in the +.Ar [libdefaults] +section. +However, if the +.Fl Fl no-keytab +option is given, then +.Nm ipropd-slave +will use the given or default credentials cache, and it will +expect that cache to be kept fresh externally (such as by the +.Nm kinit +program). +.Pp +There is a keep-alive feature logged in the master's +.Pa slave-stats +file (e.g.\& +.Pa /var/heimdal/slave-stats ) . +.Pp +Note that hierarchical replication is supported by running +an +.Nm ipropd-master +on the same KDC as an +.Nm ipropd-slave . +.Pp +Supported options for +.Nm ipropd-master : +.Bl -tag -width Ds +.It Fl c Ar string , Fl Fl config-file= Ns Ar string +.It Fl r Ar string , Fl Fl realm= Ns Ar string +.It Fl k Ar kspec , Fl Fl keytab= Ns Ar kspec +Keytab for authenticating +.Nm ipropd-slave +clients. +.It Fl Fl cache= Ns Ar cspec +If the keytab given is the empty string then credentials will be +used from the default credentials cache, or from the +.Ar cspec +if given. +.It Fl d Ar file , Fl Fl database= Ns Ar file +Database (default per KDC) +.It Fl Fl slave-stats-file= Ns Ar file +File for slave status information. +.It Fl Fl time-missing= Ns Ar time +Time before slave is polled for presence (default 2 min). +.It Fl Fl time-gone= Ns Ar time +Time of inactivity after which a slave is considered gone (default 5 min). +.It Fl Fl detach +Detach from console. +.It Fl Fl version +.It Fl Fl help +.El +.Pp +Supported options for +.Nm ipropd-slave : +.Bl -tag -width Ds +.It Fl c Ar string , Fl Fl config-file= Ns Ar string +.It Fl r Ar string , Fl Fl realm= Ns Ar string +.It Fl d Ar file , Fl Fl database= Ns Ar file +Database (default per KDC) +.It Fl k Ar kspec , Fl Fl keytab= Ns Ar kspec +Keytab with client credentials for authenticating to +.Nm ipropd-master . +.It Fl Fl status-file= Ns Ar file +.It Fl Fl hostname= Ns Ar hostname +Hostname for client principal if different from actual hostname. +.It Fl Fl port= Ns Ar port +.It Fl Fl time-lost= Ns Ar time +time before server is considered lost (default 5 min) +.It Fl Fl async-hdb +Use asynchronous writes. +This is very useful for very busy sites or sites with very large +HDBs. +.It Fl Fl detach +Detach from console. +.It Fl Fl version +.It Fl Fl help +.El +Time arguments for the relevant options above may be specified in forms +like 5 min, 300 s, or simply a number of seconds. +.Sh FILES +.Pa slaves , +.Pa slave-stats +in the database directory. +.Pa ipropd-master.pid , +.Pa ipropd-slave.pid +in the database directory, or in the directory named by the +.Ev HEIM_PIDFILE_DIR +environment variable. +.Sh SEE ALSO +.Xr kinit 1 , +.Xr krb5.conf 5 , +.Xr hprop 8 , +.Xr hpropd 8 , +.Xr iprop-log 8 , +.Xr kdc 8 . diff --git a/third_party/heimdal/lib/kadm5/iprop.h b/third_party/heimdal/lib/kadm5/iprop.h new file mode 100644 index 0000000..945fb90 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/iprop.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1998-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __IPROP_H__ +#define __IPROP_H__ + +#include "kadm5_locl.h" +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif + +#include + +#define IPROP_VERSION "iprop-0.0" + +#define IPROP_NAME "iprop" + +#define IPROP_SERVICE "iprop" + +#define IPROP_PORT 2121 + +enum iprop_cmd { I_HAVE = 1, + FOR_YOU = 2, + TELL_YOU_EVERYTHING = 3, + ONE_PRINC = 4, + NOW_YOU_HAVE = 5, + ARE_YOU_THERE = 6, + I_AM_HERE = 7, + YOU_HAVE_LAST_VERSION = 8 +}; + +extern sig_atomic_t exit_flag; +void setup_signal(void); + +enum ipropd_exit_code { + IPROPD_DONE = 0, + IPROPD_RESTART = 1, + IPROPD_RESTART_SLOW = 2, + IPROPD_FATAL = 3, +}; + +int restarter(krb5_context, size_t *); + +#endif /* __IPROP_H__ */ diff --git a/third_party/heimdal/lib/kadm5/ipropd-master-version.rc b/third_party/heimdal/lib/kadm5/ipropd-master-version.rc new file mode 100644 index 0000000..f51a891 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ipropd-master-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "IProp Master" +#define RC_FILE_ORIG_0409 "ipropd-master.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/kadm5/ipropd-slave-version.rc b/third_party/heimdal/lib/kadm5/ipropd-slave-version.rc new file mode 100644 index 0000000..a1cee87 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ipropd-slave-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "IProp Slave" +#define RC_FILE_ORIG_0409 "ipropd-slave.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/kadm5/ipropd_common.c b/third_party/heimdal/lib/kadm5/ipropd_common.c new file mode 100644 index 0000000..1decfe3 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ipropd_common.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "iprop.h" + +#if defined(HAVE_FORK) && defined(HAVE_WAITPID) +#include +#include +#endif + +sig_atomic_t exit_flag; + +static RETSIGTYPE +sigterm(int sig) +{ + exit_flag = sig; +} + +void +setup_signal(void) +{ +#ifdef HAVE_SIGACTION + { + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = 0; + sa.sa_handler = sigterm; + sigemptyset(&sa.sa_mask); + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGXCPU, &sa, NULL); + + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, NULL); + } +#else + signal(SIGINT, sigterm); + signal(SIGTERM, sigterm); +#ifndef NO_SIGXCPU + signal(SIGXCPU, sigterm); +#endif +#ifndef NO_SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif +#endif +} + +/* + * Fork a child to run the service, and restart it if it dies. + * + * Returns -1 if not supported, else a file descriptor that the service + * should select() for. Any events on that file descriptor should cause + * the caller to exit immediately, as that means that the restarter + * exited. + * + * The service's normal exit status values should be should be taken + * from enum ipropd_exit_code. IPROPD_FATAL causes the restarter to + * stop restarting the service and to exit. + * + * A count of restarts is output via the `countp' argument, if it is + * non-NULL. This is useful for testing this function (e.g., kill the + * restarter after N restarts and check that the child gets the signal + * sent to it). + * + * This requires fork() and waitpid() (otherwise returns -1). Ignoring + * SIGCHLD, of course, would be bad. + * + * We could support this on Windows by spawning a child with mostly the + * same arguments as the restarter process. + */ +int +restarter(krb5_context context, size_t *countp) +{ +#if defined(HAVE_FORK) && defined(HAVE_WAITPID) + struct timeval tmout; + pid_t pid = -1; + pid_t wpid = -1; + int status; + int fds[2]; + int fds2[2]; + size_t count = 0; + fd_set readset; + + fds[0] = -1; + fds[1] = -1; + fds2[0] = -1; + fds2[1] = -1; + + signal(SIGCHLD, SIG_DFL); + + while (!exit_flag) { + /* Close the pipe ends we keep open */ + if (fds[1] != -1) + (void) close(fds[1]); + if (fds2[0] != -1) + (void) close(fds2[1]); + + /* A pipe so the child can detect the parent's death */ + if (pipe(fds) == -1) { + krb5_err(context, 1, errno, + "Could not setup pipes in service restarter"); + } + + /* A pipe so the parent can detect the child's death */ + if (pipe(fds2) == -1) { + krb5_err(context, 1, errno, + "Could not setup pipes in service restarter"); + } + + fflush(stdout); + fflush(stderr); + + pid = fork(); + if (pid == -1) + krb5_err(context, 1, errno, "Could not fork in service restarter"); + if (pid == 0) { + if (countp != NULL) + *countp = count; + (void) close(fds[1]); + (void) close(fds2[0]); + return fds[0]; + } + + count++; + + (void) close(fds[0]); + (void) close(fds2[1]); + + do { + wpid = waitpid(pid, &status, 0); + } while (wpid == -1 && errno == EINTR && !exit_flag); + if (wpid == -1 && errno == EINTR) + break; /* We were signaled; gotta kill the child and exit */ + if (wpid == -1) { + if (errno != ECHILD) { + warn("waitpid() failed; killing restarter's child process"); + kill(pid, SIGTERM); + } + krb5_err(context, 1, errno, "restarter failed waiting for child"); + } + + assert(wpid == pid); + wpid = -1; + pid = -1; + if (WIFEXITED(status)) { + switch (WEXITSTATUS(status)) { + case IPROPD_DONE: + exit(0); + case IPROPD_RESTART_SLOW: + if (exit_flag) + exit(1); + krb5_warnx(context, "Waiting 2 minutes to restart"); + sleep(120); + continue; + case IPROPD_FATAL: + krb5_errx(context, WEXITSTATUS(status), + "Sockets and pipes not supported for " + "iprop log files"); + case IPROPD_RESTART: + default: + if (exit_flag) + exit(1); + /* Add exponential backoff (with max backoff)? */ + krb5_warnx(context, "Waiting 30 seconds to restart"); + sleep(30); + continue; + } + } + /* else */ + krb5_warnx(context, "Child was killed; waiting 30 seconds to restart"); + sleep(30); + } + + if (pid == -1) + exit(0); /* No dead child to reap; done */ + + assert(pid > 0); + if (wpid != pid) { + warnx("Interrupted; killing child (pid %ld) with %d", + (long)pid, exit_flag); + krb5_warnx(context, "Interrupted; killing child (pid %ld) with %d", + (long)pid, exit_flag); + kill(pid, exit_flag); + + /* Wait up to one second for the child */ + tmout.tv_sec = 1; + tmout.tv_usec = 0; + FD_ZERO(&readset); + FD_SET(fds2[0], &readset); + /* We don't care why select() returns */ + (void) select(fds2[0] + 1, &readset, NULL, NULL, &tmout); + /* + * We haven't reaped the child yet; if it's a zombie, then + * SIGKILLing it won't hurt. If it's not a zombie yet, well, + * we're out of patience. + */ + kill(pid, SIGKILL); + do { + wpid = waitpid(pid, &status, 0); + } while (wpid != pid && errno == EINTR); + if (wpid == -1) + krb5_err(context, 1, errno, "restarter failed waiting for child"); + } + + /* Finally, the child is dead and reaped */ + if (WIFEXITED(status)) + exit(WEXITSTATUS(status)); + if (WIFSIGNALED(status)) { + switch (WTERMSIG(status)) { + case SIGTERM: + case SIGXCPU: + case SIGINT: + exit(0); + default: + /* + * Attempt to set the same exit status for the parent as for + * the child. + */ + kill(getpid(), WTERMSIG(status)); + /* + * We can get past the self-kill if we inherited a SIG_IGN + * disposition that the child reset to SIG_DFL. + */ + } + } + exit(1); +#else + if (countp != NULL) + *countp = 0; + errno = ENOTSUP; + return -1; +#endif +} + diff --git a/third_party/heimdal/lib/kadm5/ipropd_master.c b/third_party/heimdal/lib/kadm5/ipropd_master.c new file mode 100644 index 0000000..3d693bd --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ipropd_master.c @@ -0,0 +1,1890 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "iprop.h" +#include + +static krb5_log_facility *log_facility; + +static int verbose; + +static const char *slave_stats_file; +static const char *slave_stats_temp_file; +static const char *slave_time_missing = "2 min"; +static const char *slave_time_gone = "5 min"; + +static int time_before_missing; +static int time_before_gone; + +const char *master_hostname; +const char *pidfile_basename; +static char hostname[128]; + +static krb5_socket_t +make_signal_socket (krb5_context context) +{ +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un addr; + const char *fn; + krb5_socket_t fd; + + fn = kadm5_log_signal_socket(context); + + fd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) + krb5_err (context, 1, errno, "socket AF_UNIX"); + memset (&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strlcpy (addr.sun_path, fn, sizeof(addr.sun_path)); + unlink (addr.sun_path); + if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + krb5_err (context, 1, errno, "bind %s", addr.sun_path); + return fd; +#else + struct addrinfo *ai = NULL; + krb5_socket_t fd; + + kadm5_log_signal_socket_info(context, 1, &ai); + + fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (rk_IS_BAD_SOCKET(fd)) + krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF=%d", ai->ai_family); + + if (rk_IS_SOCKET_ERROR( bind (fd, ai->ai_addr, ai->ai_addrlen) )) + krb5_err (context, 1, rk_SOCK_ERRNO, "bind"); + return fd; +#endif +} + +static krb5_socket_t +make_listen_socket (krb5_context context, const char *port_str) +{ + krb5_socket_t fd; + int one = 1; + struct sockaddr_in addr; + + fd = socket (AF_INET, SOCK_STREAM, 0); + if (rk_IS_BAD_SOCKET(fd)) + krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF_INET"); + (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + + if (port_str) { + addr.sin_port = krb5_getportbyname (context, + port_str, "tcp", + 0); + if (addr.sin_port == 0) { + char *ptr; + long port; + + port = strtol (port_str, &ptr, 10); + if (port == 0 && ptr == port_str) + krb5_errx (context, 1, "bad port `%s'", port_str); + addr.sin_port = htons(port); + } + } else { + addr.sin_port = krb5_getportbyname (context, IPROP_SERVICE, + "tcp", IPROP_PORT); + } + if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + krb5_err (context, 1, errno, "bind"); + if (listen(fd, SOMAXCONN) < 0) + krb5_err (context, 1, errno, "listen"); + return fd; +} + + +struct slave { + krb5_socket_t fd; + struct sockaddr_in addr; + char *name; + krb5_auth_context ac; + uint32_t version; + uint32_t version_tstamp; + uint32_t version_ack; + time_t seen; + unsigned long flags; +#define SLAVE_F_DEAD 0x1 +#define SLAVE_F_AYT 0x2 +#define SLAVE_F_READY 0x4 + /* + * We'll use non-blocking I/O so no slave can hold us back. + * + * We call the state left over from a partial write a "tail". + * + * The krb5_data holding an KRB-PRIV will be the write buffer. + */ + struct { + /* Every message we send is a KRB-PRIV with a 4-byte length prefixed */ + uint8_t header_buf[4]; + krb5_data header; + krb5_data packet; + size_t packet_off; + /* For send_complete() we need an sp as part of the tail */ + krb5_storage *dump; + uint32_t vno; + } tail; + struct { + uint8_t header_buf[4]; + krb5_data packet; + size_t offset; + int hlen; + } input; + /* + * Continuation for fair diff sending we send N entries at a time. + */ + struct { + off_t off_next_version; /* offset in log of next diff */ + uint32_t initial_version; /* at time of previous diff */ + uint32_t initial_tstamp; /* at time of previous diff */ + uint32_t last_version_sent; + int more; /* need to send more diffs */ + } next_diff; + struct slave *next; +}; + +typedef struct slave slave; + +static int +check_acl (krb5_context context, const char *name) +{ + const char *fn; + FILE *fp; + char buf[256]; + int ret = 1; + char *slavefile = NULL; + + if (asprintf(&slavefile, "%s/slaves", hdb_db_dir(context)) == -1 + || slavefile == NULL) + errx(1, "out of memory"); + + fn = krb5_config_get_string_default(context, + NULL, + slavefile, + "kdc", + "iprop-acl", + NULL); + + fp = fopen (fn, "r"); + free(slavefile); + if (fp == NULL) + return 1; + while (fgets(buf, sizeof(buf), fp) != NULL) { + buf[strcspn(buf, "\r\n")] = '\0'; + if (strcmp (buf, name) == 0) { + ret = 0; + break; + } + } + fclose (fp); + return ret; +} + +static void +slave_seen(slave *s) +{ + s->flags &= ~SLAVE_F_AYT; + s->seen = time(NULL); +} + +static int +slave_missing_p (slave *s) +{ + if (time(NULL) > s->seen + time_before_missing) + return 1; + return 0; +} + +static int +slave_gone_p (slave *s) +{ + if (time(NULL) > s->seen + time_before_gone) + return 1; + return 0; +} + +static void +slave_dead(krb5_context context, slave *s) +{ + krb5_warnx(context, "slave %s dead", s->name); + + if (!rk_IS_BAD_SOCKET(s->fd)) { + rk_closesocket (s->fd); + s->fd = rk_INVALID_SOCKET; + } + s->flags |= SLAVE_F_DEAD; + slave_seen(s); +} + +static void +remove_slave (krb5_context context, slave *s, slave **root) +{ + slave **p; + + if (!rk_IS_BAD_SOCKET(s->fd)) + rk_closesocket (s->fd); + if (s->name) + free (s->name); + if (s->ac) + krb5_auth_con_free (context, s->ac); + + /* Free any pending input/output state */ + krb5_data_free(&s->input.packet); + krb5_data_free(&s->tail.packet); + krb5_storage_free(s->tail.dump); + + for (p = root; *p; p = &(*p)->next) + if (*p == s) { + *p = s->next; + break; + } + free (s); +} + +static void +add_slave (krb5_context context, krb5_keytab keytab, slave **root, + krb5_socket_t fd) +{ + krb5_principal server = NULL; + krb5_error_code ret; + slave *s; + socklen_t addr_len; + krb5_ticket *ticket = NULL; + + s = calloc(1, sizeof(*s)); + if (s == NULL) { + krb5_warnx (context, "add_slave: no memory"); + return; + } + s->name = NULL; + s->ac = NULL; + s->input.packet.data = NULL; + s->tail.header.data = NULL; + s->tail.packet.data = NULL; + s->tail.dump = NULL; + + addr_len = sizeof(s->addr); + s->fd = accept (fd, (struct sockaddr *)&s->addr, &addr_len); + if (rk_IS_BAD_SOCKET(s->fd)) { + krb5_warn (context, rk_SOCK_ERRNO, "accept"); + goto error; + } + + /* + * We write message lengths separately from the payload, and may do + * back-to-back small writes when flushing pending input and then a new + * update. Avoid Nagle delays. + */ +#if defined(IPPROTO_TCP) && defined(TCP_NODELAY) + { + int nodelay = 1; + (void) setsockopt(s->fd, IPPROTO_TCP, TCP_NODELAY, + (void *)&nodelay, sizeof(nodelay)); + } +#endif + + ret = krb5_sname_to_principal (context, hostname, IPROP_NAME, + KRB5_NT_SRV_HST, &server); + if (ret) { + krb5_warn (context, ret, "krb5_sname_to_principal"); + goto error; + } + + ret = krb5_recvauth (context, &s->ac, &s->fd, + IPROP_VERSION, server, 0, keytab, &ticket); + + /* + * We'll be doing non-blocking I/O only after authentication. We don't + * want to get stuck talking to any one slave. + * + * If we get a partial write, we'll finish writing when the socket becomes + * writable. + * + * Partial reads will be treated as EOF, causing the slave to be marked + * dead. + * + * To do non-blocking I/O for authentication we'll have to implement our + * own krb5_recvauth(). + */ + socket_set_nonblocking(s->fd, 1); + + if (ret) { + krb5_warn (context, ret, "krb5_recvauth"); + goto error; + } + ret = krb5_unparse_name (context, ticket->client, &s->name); + if (ret) { + krb5_warn (context, ret, "krb5_unparse_name"); + goto error; + } + if (check_acl (context, s->name)) { + krb5_warnx (context, "%s not in acl", s->name); + goto error; + } + + { + slave *l = *root; + + while (l) { + if (strcmp(l->name, s->name) == 0) + break; + l = l->next; + } + if (l) { + if (l->flags & SLAVE_F_DEAD) { + remove_slave(context, l, root); + } else { + krb5_warnx (context, "second connection from %s", s->name); + goto error; + } + } + } + + krb5_free_principal(context, server); + krb5_free_ticket(context, ticket); + krb5_warnx (context, "connection from %s", s->name); + + s->version = 0; + s->version_ack = 0; + s->flags = 0; + slave_seen(s); + s->next = *root; + *root = s; + return; +error: + remove_slave(context, s, root); + krb5_free_principal(context, server); + if (ticket) + krb5_free_ticket(context, ticket); +} + +static int +dump_one (krb5_context context, HDB *db, hdb_entry *entry, void *v) +{ + krb5_error_code ret; + krb5_storage *dump = (krb5_storage *)v; + krb5_storage *sp; + krb5_data data; + + ret = hdb_entry2value (context, entry, &data); + if (ret) + return ret; + ret = krb5_data_realloc (&data, data.length + 4); + if (ret) + goto done; + memmove ((char *)data.data + 4, data.data, data.length - 4); + sp = krb5_storage_from_data(&data); + if (sp == NULL) { + ret = krb5_enomem(context); + goto done; + } + ret = krb5_store_uint32(sp, ONE_PRINC); + krb5_storage_free(sp); + + if (ret == 0) + ret = krb5_store_data(dump, data); + +done: + krb5_data_free (&data); + return ret; +} + +static int +write_dump (krb5_context context, krb5_storage *dump, + const char *database, uint32_t current_version) +{ + krb5_error_code ret; + krb5_storage *sp; + HDB *db; + krb5_data data; + char buf[8]; + + /* we assume that the caller has obtained an exclusive lock */ + + ret = krb5_storage_truncate(dump, 0); + if (ret) + return ret; + + if (krb5_storage_seek(dump, 0, SEEK_SET) != 0) + return errno; + + /* + * First we store zero as the HDB version, this will indicate to a + * later reader that the dumpfile is invalid. We later write the + * correct version in the file after we have written all of the + * messages. A dump with a zero version will not be considered + * to be valid. + */ + + ret = krb5_store_uint32(dump, 0); + if (ret) + return ret; + + ret = hdb_create (context, &db, database); + if (ret) + krb5_err (context, IPROPD_RESTART, ret, "hdb_create: %s", database); + ret = db->hdb_open (context, db, O_RDONLY, 0); + if (ret) + krb5_err (context, IPROPD_RESTART, ret, "db->open"); + + sp = krb5_storage_from_mem (buf, 4); + if (sp == NULL) + krb5_errx (context, IPROPD_RESTART, "krb5_storage_from_mem"); + krb5_store_uint32 (sp, TELL_YOU_EVERYTHING); + krb5_storage_free (sp); + + data.data = buf; + data.length = 4; + + ret = krb5_store_data(dump, data); + if (ret) { + krb5_warn (context, ret, "write_dump"); + return ret; + } + + ret = hdb_foreach (context, db, HDB_F_ADMIN_DATA, dump_one, dump); + if (ret) { + krb5_warn (context, ret, "write_dump: hdb_foreach"); + return ret; + } + + (*db->hdb_close)(context, db); + (*db->hdb_destroy)(context, db); + + sp = krb5_storage_from_mem (buf, 8); + if (sp == NULL) + krb5_errx (context, IPROPD_RESTART, "krb5_storage_from_mem"); + ret = krb5_store_uint32(sp, NOW_YOU_HAVE); + if (ret == 0) + krb5_store_uint32(sp, current_version); + krb5_storage_free (sp); + + data.length = 8; + + if (ret == 0) + ret = krb5_store_data(dump, data); + + /* + * We must ensure that the entire valid dump is written to disk + * before we write the current version at the front thus making + * it a valid dump file. If we crash around here, this can be + * important upon reboot. + */ + + if (ret == 0) + ret = krb5_storage_fsync(dump); + + if (ret == 0 && krb5_storage_seek(dump, 0, SEEK_SET) == -1) + ret = errno; + + /* Write current version at the front making the dump valid */ + + if (ret == 0) + ret = krb5_store_uint32(dump, current_version); + + /* + * We don't need to fsync(2) after the real version is written as + * it is not a disaster if it doesn't make it to disk if we crash. + * After all, we'll just create a new dumpfile. + */ + + if (ret == 0) + krb5_warnx(context, "wrote new dumpfile (version %u)", + current_version); + else + krb5_warn(context, ret, "failed to write new dumpfile (version %u)", + current_version); + + return ret; +} + +static int +mk_priv_tail(krb5_context context, slave *s, krb5_data *data) +{ + uint32_t len; + int ret; + + ret = krb5_mk_priv(context, s->ac, data, &s->tail.packet, NULL); + if (ret) + return ret; + + len = s->tail.packet.length; + _krb5_put_int(s->tail.header_buf, len, sizeof(s->tail.header_buf)); + s->tail.header.length = sizeof(s->tail.header_buf); + s->tail.header.data = s->tail.header_buf; + return 0; +} + +static int +have_tail(slave *s) +{ + return s->tail.header.length || s->tail.packet.length || s->tail.dump; +} + +static int +more_diffs(slave *s) +{ + return s->next_diff.more; +} + +#define SEND_COMPLETE_MAX_RECORDS 50 +#define SEND_DIFFS_MAX_RECORDS 50 + +static int +send_tail(krb5_context context, slave *s) +{ + krb5_data data; + ssize_t bytes = 0; + size_t rem = 0; + size_t n; + int ret; + + if (! have_tail(s)) + return 0; + + /* + * For the case where we're continuing a send_complete() send up to + * SEND_COMPLETE_MAX_RECORDS records now, and the rest asynchronously + * later. This ensures that sending a complete dump to a slow-to-drain + * client does not prevent others from getting serviced. + */ + for (n = 0; n < SEND_COMPLETE_MAX_RECORDS; n++) { + if (! have_tail(s)) + return 0; + + if (s->tail.header.length) { + bytes = krb5_net_write(context, &s->fd, + s->tail.header.data, + s->tail.header.length); + if (bytes < 0) + goto err; + + s->tail.header.length -= bytes; + s->tail.header.data = (char *)s->tail.header.data + bytes; + rem = s->tail.header.length; + if (rem) + goto ewouldblock; + } + + if (s->tail.packet.length) { + bytes = krb5_net_write(context, &s->fd, + (char *)s->tail.packet.data + s->tail.packet_off, + s->tail.packet.length - s->tail.packet_off); + if (bytes < 0) + goto err; + s->tail.packet_off += bytes; + if (bytes) + slave_seen(s); + rem = s->tail.packet.length - s->tail.packet_off; + if (rem) + goto ewouldblock; + + krb5_data_free(&s->tail.packet); + s->tail.packet_off = 0; + } + + if (s->tail.dump == NULL) + return 0; + + /* + * We're in the middle of a send_complete() that was interrupted by + * EWOULDBLOCK. Continue the sending of the dump. + */ + ret = krb5_ret_data(s->tail.dump, &data); + if (ret == HEIM_ERR_EOF) { + krb5_storage_free(s->tail.dump); + s->tail.dump = NULL; + s->version = s->tail.vno; + return 0; + } + + if (ret) { + krb5_warn(context, ret, "failed to read entry from dump!"); + } else { + ret = mk_priv_tail(context, s, &data); + krb5_data_free(&data); + if (ret == 0) + continue; + krb5_warn(context, ret, "failed to make and send a KRB-PRIV to %s", + s->name); + } + + slave_dead(context, s); + return ret; + } + + if (ret == 0 && s->tail.dump != NULL) + return EWOULDBLOCK; + +err: + if (errno != EAGAIN && errno != EWOULDBLOCK) { + krb5_warn(context, ret = errno, + "error sending diffs to now-dead slave %s", s->name); + slave_dead(context, s); + return ret; + } + +ewouldblock: + if (verbose) + krb5_warnx(context, "would block writing %llu bytes to slave %s", + (unsigned long long)rem, s->name); + return EWOULDBLOCK; +} + +static int +send_complete(krb5_context context, slave *s, const char *database, + uint32_t current_version, uint32_t oldest_version, + uint32_t initial_log_tstamp) +{ + krb5_error_code ret; + krb5_storage *dump = NULL; + uint32_t vno = 0; + int fd = -1; + struct stat st; + char *dfn; + + ret = asprintf(&dfn, "%s/ipropd.dumpfile", hdb_db_dir(context)); + if (ret == -1 || !dfn) + return krb5_enomem(context); + + fd = open(dfn, O_CREAT|O_RDWR, 0600); + if (fd == -1) { + ret = errno; + krb5_warn(context, ret, "Cannot open/create iprop dumpfile %s", dfn); + free(dfn); + return ret; + } + free(dfn); + + dump = krb5_storage_from_fd(fd); + if (!dump) { + ret = errno; + krb5_warn(context, ret, "krb5_storage_from_fd"); + goto done; + } + + for (;;) { + ret = flock(fd, LOCK_SH); + if (ret == -1) { + ret = errno; + krb5_warn(context, ret, "flock(fd, LOCK_SH)"); + goto done; + } + + if (krb5_storage_seek(dump, 0, SEEK_SET) == (off_t)-1) { + ret = errno; + krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); + goto done; + } + + vno = 0; + ret = krb5_ret_uint32(dump, &vno); + if (ret && ret != HEIM_ERR_EOF) { + krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); + goto done; + } + + if (fstat(fd, &st) == -1) { + ret = errno; + krb5_warn(context, ret, "send_complete: could not stat dump file"); + goto done; + } + + /* + * If the current dump has an appropriate version, then we can + * break out of the loop and send the file below. + */ + if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && + vno >= oldest_version && vno <= current_version) + break; + + if (verbose) + krb5_warnx(context, "send_complete: dumping HDB"); + + /* + * Otherwise, we may need to write a new dump file. We + * obtain an exclusive lock on the fd. Because this is + * not guaranteed to be an upgrade of our existing shared + * lock, someone else may have written a new dumpfile while + * we were waiting and so we must first check the vno of + * the dump to see if that happened. If it did, we need + * to go back to the top of the loop so that we can downgrade + * our lock to a shared one. + */ + + ret = flock(fd, LOCK_EX); + if (ret == -1) { + ret = errno; + krb5_warn(context, ret, "flock(fd, LOCK_EX)"); + goto done; + } + + ret = krb5_storage_seek(dump, 0, SEEK_SET); + if (ret == -1) { + ret = errno; + krb5_warn(context, ret, "krb5_storage_seek(dump, 0, SEEK_SET)"); + goto done; + } + + vno = 0; + ret = krb5_ret_uint32(dump, &vno); + if (ret && ret != HEIM_ERR_EOF) { + krb5_warn(context, ret, "krb5_ret_uint32(dump, &vno)"); + goto done; + } + + if (fstat(fd, &st) == -1) { + ret = errno; + krb5_warn(context, ret, "send_complete: could not stat dump file"); + goto done; + } + + /* check if someone wrote a better version for us */ + if (ret == 0 && vno != 0 && st.st_mtime > initial_log_tstamp && + vno >= oldest_version && vno <= current_version) + continue; + + /* Now, we know that we must write a new dump file. */ + + ret = write_dump(context, dump, database, current_version); + if (ret) + goto done; + + /* + * And we must continue to the top of the loop so that we can + * downgrade to a shared lock. + */ + } + + /* + * Leaving the above loop, dump should have a ptr right after the initial + * 4 byte DB version number and we should have a shared lock on the file + * (which we may have just created), so we are reading to start sending + * the data down the wire. + * + * Note: (krb5_storage_from_fd() dup()'s the fd) + */ + + s->tail.dump = dump; + s->tail.vno = vno; + dump = NULL; + ret = send_tail(context, s); + +done: + if (fd != -1) + close(fd); + if (dump) + krb5_storage_free(dump); + return ret; +} + +static int +send_are_you_there (krb5_context context, slave *s) +{ + krb5_storage *sp; + krb5_data data; + char buf[4]; + int ret; + + if (s->flags & (SLAVE_F_DEAD|SLAVE_F_AYT)) + return 0; + + /* + * Write any remainder of previous write, if we can. If we'd block we'll + * return EWOULDBLOCK. + */ + ret = send_tail(context, s); + if (ret) + return ret; + + krb5_warnx(context, "slave %s missing, sending AYT", s->name); + + s->flags |= SLAVE_F_AYT; + + data.data = buf; + data.length = 4; + + sp = krb5_storage_from_mem (buf, 4); + if (sp == NULL) { + krb5_warnx (context, "are_you_there: krb5_data_alloc"); + slave_dead(context, s); + return ENOMEM; + } + ret = krb5_store_uint32(sp, ARE_YOU_THERE); + krb5_storage_free (sp); + + if (ret == 0) + ret = mk_priv_tail(context, s, &data); + if (ret == 0) + ret = send_tail(context, s); + if (ret && ret != EWOULDBLOCK) { + krb5_warn(context, ret, "are_you_there"); + slave_dead(context, s); + } + return ret; +} + +static int +diffready(krb5_context context, slave *s) +{ + /* + * Don't send any diffs until slave has sent an I_HAVE telling us the + * initial version number! + */ + if ((s->flags & SLAVE_F_READY) == 0) + return 0; + + if (s->flags & SLAVE_F_DEAD) { + if (verbose) + krb5_warnx(context, "not sending diffs to dead slave %s", s->name); + return 0; + } + + /* Write any remainder of previous write, if we can. */ + if (send_tail(context, s) != 0) + return 0; + + return 1; +} + +static int +nodiffs(krb5_context context, slave *s, uint32_t current_version) +{ + krb5_storage *sp; + krb5_data data; + int ret; + + if (s->version < current_version) + return 0; + + /* + * If we had sent a partial diff, and now they're caught up, then there's + * no more. + */ + s->next_diff.more = 0; + + if (verbose) + krb5_warnx(context, "slave %s version %ld already sent", s->name, + (long)s->version); + sp = krb5_storage_emem(); + if (sp == NULL) + krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_mem"); + + ret = krb5_store_uint32(sp, YOU_HAVE_LAST_VERSION); + if (ret == 0) { + krb5_data_zero(&data); + ret = krb5_storage_to_data(sp, &data); + } + krb5_storage_free(sp); + if (ret == 0) { + ret = mk_priv_tail(context, s, &data); + krb5_data_free(&data); + } + if (ret == 0) + send_tail(context, s); + + return 1; +} + +/* + * Lock the log and return initial version and timestamp + */ +static int +get_first(kadm5_server_context *server_context, int log_fd, + uint32_t *initial_verp, uint32_t *initial_timep) +{ + krb5_context context = server_context->context; + int ret; + + /* + * We don't want to perform tight retry loops on log access errors, so on + * error mark the slave dead. The slave reconnect after a delay... + */ + if (flock(log_fd, LOCK_SH) == -1) { + krb5_warn(context, errno, "could not obtain shared lock on log file"); + return -1; + } + + ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST, + initial_verp, initial_timep); + if (ret == HEIM_ERR_EOF) + ret = kadm5_log_get_version_fd(server_context, log_fd, + LOG_VERSION_UBER, initial_verp, + initial_timep); + if (ret != 0) { + flock(log_fd, LOCK_UN); + krb5_warn(context, ret, "could not read initial log entry"); + return -1; + } + + return 0; +} + +/*- + * Find the left end of the diffs in the log we want to send. + * + * - On success, return a positive offset to the first new entry, retaining + * a read lock on the log file. + * - On error, return a negative offset, with the lock released. + * - If we simply find no successor entry in the log, return zero + * with the lock released, which indicates that fallback to send_complete() + * is needed. + */ +static off_t +get_left(kadm5_server_context *server_context, slave *s, krb5_storage *sp, + int log_fd, uint32_t current_version, + uint32_t *initial_verp, uint32_t *initial_timep) +{ + krb5_context context = server_context->context; + off_t pos; + off_t left; + int ret; + + for (;;) { + uint32_t ver = s->version; + + /* This acquires a read lock on success */ + ret = get_first(server_context, log_fd, + initial_verp, initial_timep); + if (ret != 0) + return -1; + + /* When the slave version is out of range, send the whole database. */ + if (ver == 0 || ver < *initial_verp || ver > current_version) { + flock(log_fd, LOCK_UN); + return 0; + } + + /* Avoid seeking past the last committed record */ + if (kadm5_log_goto_end(server_context, sp) != 0 || + (pos = krb5_storage_seek(sp, 0, SEEK_CUR)) < 0) + goto err; + + /* + * First try to see if we can find it quickly by seeking to the right + * end of the previous diff sent. + */ + if (s->next_diff.last_version_sent > 0 && + s->next_diff.off_next_version > 0 && + s->next_diff.off_next_version < pos && + s->next_diff.initial_version == *initial_verp && + s->next_diff.initial_tstamp == *initial_timep) { + /* + * Sanity check that the left version matches what we wanted, the + * log may have been truncated since. + */ + left = s->next_diff.off_next_version; + if (krb5_storage_seek(sp, left, SEEK_SET) != left) + goto err; + if (kadm5_log_next(context, sp, &ver, NULL, NULL, NULL) == 0 && + ver == s->next_diff.last_version_sent + 1) + return left; + } + + if (krb5_storage_seek(sp, pos, SEEK_SET) != pos) + goto err; + + /* + * Drop the lock and try to find the left entry by seeking backward + * from the end of the end of the log. If we succeed, re-acquire the + * lock, update "next_diff", and retry the fast-path. + */ + flock(log_fd, LOCK_UN); + + /* Slow path: seek backwards, entry by entry, from the end */ + for (;;) { + enum kadm_ops op; + uint32_t len; + + ret = kadm5_log_previous(context, sp, &ver, NULL, &op, &len); + if (ret) + return -1; + left = krb5_storage_seek(sp, -16, SEEK_CUR); + if (left < 0) + return left; + if (ver == s->version + 1) + break; + + /* + * We don't expect to reach the slave's version, unless the log + * has been modified after we released the lock. + */ + if (ver == s->version) { + krb5_warnx(context, "iprop log truncated while sending diffs " + "to slave?? ver = %lu", (unsigned long)ver); + return -1; + } + + /* If we've reached the uber record, send the complete database */ + if (left == 0 || (ver == 0 && op == kadm_nop)) + return 0; + } + assert(ver == s->version + 1); + + /* Set up the fast-path pre-conditions */ + s->next_diff.last_version_sent = s->version; + s->next_diff.off_next_version = left; + s->next_diff.initial_version = *initial_verp; + s->next_diff.initial_tstamp = *initial_timep; + + /* + * If we loop then we're hoping to hit the fast path so we can return a + * non-zero, positive left offset with the lock held. + * + * We just updated the fast path pre-conditions, so unless a log + * truncation event happens between the point where we dropped the lock + * and the point where we rearcuire it above, we will hit the fast + * path. + */ + } + + err: + flock(log_fd, LOCK_UN); + return -1; +} + +static off_t +get_right(krb5_context context, int log_fd, krb5_storage *sp, + int lastver, slave *s, off_t left, uint32_t *verp) +{ + int ret = 0; + int i = 0; + uint32_t ver = s->version; + off_t right = krb5_storage_seek(sp, left, SEEK_SET); + + if (right <= 0) { + flock(log_fd, LOCK_UN); + return -1; + } + + /* The "lastver" bound should preclude us reaching EOF */ + for (; ret == 0 && i < SEND_DIFFS_MAX_RECORDS && ver < lastver; ++i) { + uint32_t logver; + + ret = kadm5_log_next(context, sp, &logver, NULL, NULL, NULL); + if (logver != ++ver) + ret = KADM5_LOG_CORRUPT; + } + + if (ret == 0) + right = krb5_storage_seek(sp, 0, SEEK_CUR); + else + right = -1; + if (right <= 0) { + flock(log_fd, LOCK_UN); + return -1; + } + *verp = ver; + return right; +} + +static void +send_diffs(kadm5_server_context *server_context, slave *s, int log_fd, + const char *database, uint32_t current_version) +{ + krb5_context context = server_context->context; + krb5_storage *sp; + uint32_t initial_version; + uint32_t initial_tstamp; + uint32_t ver = 0; + off_t left = 0; + off_t right = 0; + krb5_ssize_t bytes; + krb5_data data; + int ret = 0; + + if (!diffready(context, s) || nodiffs(context, s, current_version)) + return; + + if (verbose) + krb5_warnx(context, "sending diffs to live-seeming slave %s", s->name); + + sp = krb5_storage_from_fd(log_fd); + if (sp == NULL) + krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, + "send_diffs: out of memory"); + + left = get_left(server_context, s, sp, log_fd, current_version, + &initial_version, &initial_tstamp); + if (left < 0) { + krb5_storage_free(sp); + slave_dead(context, s); + return; + } + + if (left == 0) { + /* Slave's version is not in the log, fall back on send_complete() */ + krb5_storage_free(sp); + send_complete(context, s, database, current_version, + initial_version, initial_tstamp); + return; + } + + /* We still hold the read lock, if right > 0 */ + right = get_right(server_context->context, log_fd, sp, current_version, + s, left, &ver); + if (right == left) { + flock(log_fd, LOCK_UN); + krb5_storage_free(sp); + return; + } + if (right < left) { + assert(right < 0); + krb5_storage_free(sp); + slave_dead(context, s); + return; + } + + if (krb5_storage_seek(sp, left, SEEK_SET) != left) { + ret = errno ? errno : EIO; + flock(log_fd, LOCK_UN); + krb5_warn(context, ret, "send_diffs: krb5_storage_seek"); + krb5_storage_free(sp); + slave_dead(context, s); + return; + } + + ret = krb5_data_alloc(&data, right - left + 4); + if (ret) { + flock(log_fd, LOCK_UN); + krb5_warn(context, ret, "send_diffs: krb5_data_alloc"); + krb5_storage_free(sp); + slave_dead(context, s); + return; + } + + bytes = krb5_storage_read(sp, (char *)data.data + 4, data.length - 4); + flock(log_fd, LOCK_UN); + krb5_storage_free(sp); + if (bytes != data.length - 4) + krb5_errx(context, IPROPD_RESTART, "locked log truncated???"); + + sp = krb5_storage_from_data(&data); + if (sp == NULL) { + krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "out of memory"); + return; + } + ret = krb5_store_uint32(sp, FOR_YOU); + krb5_storage_free(sp); + + if (ret == 0) + ret = mk_priv_tail(context, s, &data); + krb5_data_free(&data); + if (ret == 0) { + /* Save the fast-path continuation */ + s->next_diff.last_version_sent = ver; + s->next_diff.off_next_version = right; + s->next_diff.initial_version = initial_version; + s->next_diff.initial_tstamp = initial_tstamp; + s->next_diff.more = ver < current_version; + ret = send_tail(context, s); + + krb5_warnx(context, + "syncing slave %s from version %lu to version %lu", + s->name, (unsigned long)s->version, + (unsigned long)ver); + s->version = ver; + } + + if (ret && ret != EWOULDBLOCK) { + krb5_warn(context, ret, "send_diffs: making or sending " + "KRB-PRIV message"); + slave_dead(context, s); + return; + } + slave_seen(s); + return; +} + +/* Sensible bound on slave message size */ +#define SLAVE_MSG_MAX 65536 + +static int +fill_input(krb5_context context, slave *s) +{ + krb5_error_code ret; + + if (s->input.hlen < 4) { + uint8_t *buf = s->input.header_buf + s->input.hlen; + size_t len = 4 - s->input.hlen; + krb5_ssize_t bytes = krb5_net_read(context, &s->fd, buf, len); + + if (bytes == 0) + return HEIM_ERR_EOF; + if (bytes < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return EWOULDBLOCK; + return errno ? errno : EIO; + } + s->input.hlen += bytes; + if (bytes < len) + return EWOULDBLOCK; + + buf = s->input.header_buf; + len = ((unsigned long)buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; + if (len > SLAVE_MSG_MAX) + return EINVAL; + ret = krb5_data_alloc(&s->input.packet, len); + if (ret != 0) + return ret; + } + + if (s->input.offset < s->input.packet.length) { + u_char *buf = (u_char *)s->input.packet.data + s->input.offset; + size_t len = s->input.packet.length - s->input.offset; + krb5_ssize_t bytes = krb5_net_read(context, &s->fd, buf, len); + + if (bytes == 0) + return HEIM_ERR_EOF; + if (bytes < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return EWOULDBLOCK; + return errno ? errno : EIO; + } + s->input.offset += bytes; + if (bytes != len) + return EWOULDBLOCK; + } + return 0; +} + +static int +read_msg(krb5_context context, slave *s, krb5_data *out) +{ + int ret = fill_input(context, s); + + if (ret != 0) + return ret; + + ret = krb5_rd_priv(context, s->ac, &s->input.packet, out, NULL); + + /* Prepare for next packet */ + krb5_data_free(&s->input.packet); + s->input.offset = 0; + s->input.hlen = 0; + + return ret; +} + +static int +process_msg(kadm5_server_context *server_context, slave *s, int log_fd, + const char *database, uint32_t current_version) +{ + krb5_context context = server_context->context; + int ret = 0; + krb5_data out; + krb5_storage *sp; + uint32_t tmp; + + ret = read_msg(context, s, &out); + if (ret) { + if (ret != EWOULDBLOCK) + krb5_warn(context, ret, "error reading message from %s", s->name); + return ret; + } + + sp = krb5_storage_from_mem(out.data, out.length); + if (sp == NULL) { + krb5_warnx(context, "process_msg: no memory"); + krb5_data_free(&out); + return 1; + } + if (krb5_ret_uint32(sp, &tmp) != 0) { + krb5_warnx(context, "process_msg: client send too short command"); + krb5_data_free(&out); + return 1; + } + switch (tmp) { + case I_HAVE : + ret = krb5_ret_uint32(sp, &tmp); + if (ret != 0) { + krb5_warnx(context, "process_msg: client send too little I_HAVE data"); + break; + } + /* + * XXX Make the slave send the timestamp as well, and try to get it + * here, and pass it to send_diffs(). + */ + /* + * New slave whose version number we've not yet seen. If the version + * number is zero, the slave has no data, and we'll send a complete + * database (that happens in send_diffs()). Otherwise, we'll record a + * non-zero initial version and attempt an incremental update. + * + * NOTE!: Once the slave is "ready" (its first I_HAVE has conveyed its + * initial version), we MUST NOT update s->version to the slave's + * I_HAVE version, since we may already have sent later updates, and + * MUST NOT send them again, otherwise we can get further and further + * out of sync resending larger and larger diffs. The "not yet ready" + * is an essential precondition for setting s->version to the value + * in the I_HAVE message. This happens only once when the slave + * first connects. + */ + if (!(s->flags & SLAVE_F_READY)) { + if (current_version < tmp) { + krb5_warnx(context, "Slave %s (version %u) has later version " + "than the master (version %u) OUT OF SYNC", + s->name, tmp, current_version); + /* Force send_complete() */ + tmp = 0; + } + /* + * Mark the slave as ready for updates based on incoming signals. + * Prior to the initial I_HAVE, we don't know the slave's version + * number, and MUST not send it anything, since we'll needlessly + * attempt to send the whole database! + */ + s->version = tmp; + s->flags |= SLAVE_F_READY; + if (verbose) + krb5_warnx(context, "slave %s ready for updates from version %u", + s->name, tmp); + } + if ((s->version_ack = tmp) < s->version) + break; + send_diffs(server_context, s, log_fd, database, current_version); + break; + case I_AM_HERE : + if (verbose) + krb5_warnx(context, "slave %s is there", s->name); + break; + case ARE_YOU_THERE: + case FOR_YOU : + default : + krb5_warnx(context, "Ignoring command %d", tmp); + break; + } + + krb5_data_free(&out); + krb5_storage_free(sp); + + slave_seen(s); + + return ret; +} + +#define SLAVE_NAME "Name" +#define SLAVE_ADDRESS "Address" +#define SLAVE_VERSION "Version" +#define SLAVE_STATUS "Status" +#define SLAVE_SEEN "Last Seen" + +static void +init_stats_names(krb5_context context) +{ + const char *fn = NULL; + char *buf = NULL; + + if (slave_stats_file) + fn = slave_stats_file; + else if ((fn = krb5_config_get_string(context, NULL, "kdc", + "iprop-stats", NULL)) == NULL) { + if (asprintf(&buf, "%s/slaves-stats", hdb_db_dir(context)) != -1 + && buf != NULL) + fn = buf; + buf = NULL; + } + if (fn != NULL) { + slave_stats_file = fn; + if (asprintf(&buf, "%s.tmp", fn) != -1 && buf != NULL) + slave_stats_temp_file = buf; + } +} + +static void +write_master_down(krb5_context context) +{ + char str[100]; + time_t t = time(NULL); + FILE *fp = NULL; + + if (slave_stats_temp_file != NULL) + fp = fopen(slave_stats_temp_file, "w"); + if (fp == NULL) + return; + if (krb5_format_time(context, t, str, sizeof(str), TRUE) == 0) + fprintf(fp, "master down at %s\n", str); + else + fprintf(fp, "master down\n"); + + if (fclose(fp) != EOF) + (void) rk_rename(slave_stats_temp_file, slave_stats_file); +} + +static void +write_stats(krb5_context context, slave *slaves, uint32_t current_version) +{ + char str[100]; + rtbl_t tbl; + time_t t = time(NULL); + FILE *fp = NULL; + + if (slave_stats_temp_file != NULL) + fp = fopen(slave_stats_temp_file, "w"); + if (fp == NULL) + return; + + if (krb5_format_time(context, t, str, sizeof(str), TRUE)) + snprintf(str, sizeof(str), ""); + fprintf(fp, "Status for slaves, last updated: %s\n\n", str); + + fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version); + + tbl = rtbl_create(); + if (tbl == NULL) { + fclose(fp); + return; + } + + rtbl_add_column(tbl, SLAVE_NAME, 0); + rtbl_add_column(tbl, SLAVE_ADDRESS, 0); + rtbl_add_column(tbl, SLAVE_VERSION, RTBL_ALIGN_RIGHT); + rtbl_add_column(tbl, SLAVE_STATUS, 0); + rtbl_add_column(tbl, SLAVE_SEEN, 0); + + rtbl_set_prefix(tbl, " "); + rtbl_set_column_prefix(tbl, SLAVE_NAME, ""); + + while (slaves) { + krb5_address addr; + krb5_error_code ret; + rtbl_add_column_entry(tbl, SLAVE_NAME, slaves->name); + ret = krb5_sockaddr2address (context, + (struct sockaddr*)&slaves->addr, &addr); + if(ret == 0) { + krb5_print_address(&addr, str, sizeof(str), NULL); + krb5_free_address(context, &addr); + rtbl_add_column_entry(tbl, SLAVE_ADDRESS, str); + } else + rtbl_add_column_entry(tbl, SLAVE_ADDRESS, ""); + + snprintf(str, sizeof(str), "%u", (unsigned)slaves->version_ack); + rtbl_add_column_entry(tbl, SLAVE_VERSION, str); + + if (slaves->flags & SLAVE_F_DEAD) + rtbl_add_column_entry(tbl, SLAVE_STATUS, "Down"); + else + rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up"); + + ret = krb5_format_time(context, slaves->seen, str, sizeof(str), TRUE); + if (ret) + rtbl_add_column_entry(tbl, SLAVE_SEEN, ""); + else + rtbl_add_column_entry(tbl, SLAVE_SEEN, str); + + slaves = slaves->next; + } + + rtbl_format(tbl, fp); + rtbl_destroy(tbl); + + if (fclose(fp) != EOF) + (void) rk_rename(slave_stats_temp_file, slave_stats_file); +} + + +static char sHDB[] = "HDBGET:"; +static char *realm; +static int version_flag; +static int help_flag; +static char *keytab_str = sHDB; +static char *database; +static char *config_file; +static char *port_str; +static int detach_from_console; +static int daemon_child = -1; + +static struct getargs args[] = { + { "config-file", 'c', arg_string, &config_file, NULL, NULL }, + { "realm", 'r', arg_string, &realm, NULL, NULL }, + { "keytab", 'k', arg_string, &keytab_str, + "keytab to get authentication from", "kspec" }, + { "database", 'd', arg_string, &database, "database", "file"}, + { "slave-stats-file", 0, arg_string, rk_UNCONST(&slave_stats_file), + "file for slave status information", "file"}, + { "time-missing", 0, arg_string, rk_UNCONST(&slave_time_missing), + "time before slave is polled for presence", "time"}, + { "time-gone", 0, arg_string, rk_UNCONST(&slave_time_gone), + "time of inactivity after which a slave is considered gone", "time"}, + { "port", 0, arg_string, &port_str, + "port ipropd will listen to", "port"}, + { "detach", 0, arg_flag, &detach_from_console, + "detach from console", NULL }, + { "daemon-child", 0, arg_integer, &daemon_child, + "private argument, do not use", NULL }, + { "pidfile-basename", 0, arg_string, &pidfile_basename, + "basename of pidfile; private argument for testing", "NAME" }, + { "hostname", 0, arg_string, rk_UNCONST(&master_hostname), + "hostname of master (if not same as hostname)", "hostname" }, + { "verbose", 0, arg_flag, &verbose, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +static int num_args = sizeof(args) / sizeof(args[0]); + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + void *kadm_handle; + kadm5_server_context *server_context; + kadm5_config_params conf; + krb5_socket_t signal_fd, listen_fd; + int log_fd; + slave *slaves = NULL; + uint32_t current_version = 0, old_version = 0; + krb5_keytab keytab; + char **files; + int aret; + int optidx = 0; + int restarter_fd = -1; + struct stat st; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &optidx)) + krb5_std_usage(1, args, num_args); + + if (help_flag) + krb5_std_usage(0, args, num_args); + + if (version_flag) { + print_version(NULL); + exit(0); + } + + memset(hostname, 0, sizeof(hostname)); + + if (master_hostname && + strlcpy(hostname, master_hostname, + sizeof(hostname)) >= sizeof(hostname)) { + errx(1, "Hostname too long: %s", master_hostname); + } else if (master_hostname == NULL) { + if (gethostname(hostname, sizeof(hostname)) == -1) + err(1, "Could not get hostname"); + if (hostname[sizeof(hostname) - 1] != '\0') + errx(1, "Hostname too long %.*s...", + (int)sizeof(hostname), hostname); + } + + if (detach_from_console && daemon_child == -1) + daemon_child = roken_detach_prep(argc, argv, "--daemon-child"); + rk_pidfile(pidfile_basename); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context failed: %d", ret); + + setup_signal(); + + if (config_file == NULL) { + aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); + if (aret == -1 || config_file == NULL) + errx(1, "out of memory"); + } + + ret = krb5_prepend_config_files_default(config_file, &files); + if (ret) + krb5_err(context, 1, ret, "getting configuration files"); + + ret = krb5_set_config_files(context, files); + krb5_free_config_files(files); + if (ret) + krb5_err(context, 1, ret, "reading configuration files"); + + init_stats_names(context); + + time_before_gone = parse_time (slave_time_gone, "s"); + if (time_before_gone < 0) + krb5_errx (context, 1, "couldn't parse time: %s", slave_time_gone); + time_before_missing = parse_time (slave_time_missing, "s"); + if (time_before_missing < 0) + krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing); + + krb5_openlog(context, "ipropd-master", &log_facility); + krb5_set_warn_dest(context, log_facility); + + ret = krb5_kt_register(context, &hdb_get_kt_ops); + if(ret) + krb5_err(context, 1, ret, "krb5_kt_register"); + + ret = krb5_kt_resolve(context, keytab_str, &keytab); + if(ret) + krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str); + + memset(&conf, 0, sizeof(conf)); + if(realm) { + conf.mask |= KADM5_CONFIG_REALM; + conf.realm = realm; + } + ret = kadm5_init_with_skey_ctx (context, + KADM5_ADMIN_SERVICE, + NULL, + KADM5_ADMIN_SERVICE, + &conf, 0, 0, + &kadm_handle); + if (ret) + krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); + + server_context = (kadm5_server_context *)kadm_handle; + + log_fd = open (server_context->log_context.log_file, O_RDONLY, 0); + if (log_fd < 0) + krb5_err (context, 1, errno, "open %s", + server_context->log_context.log_file); + + if (fstat(log_fd, &st) == -1) + krb5_err(context, 1, errno, "stat %s", + server_context->log_context.log_file); + + if (flock(log_fd, LOCK_SH) == -1) + krb5_err(context, 1, errno, "shared flock %s", + server_context->log_context.log_file); + kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, + ¤t_version, NULL); + flock(log_fd, LOCK_UN); + + signal_fd = make_signal_socket (context); + listen_fd = make_listen_socket (context, port_str); + + krb5_warnx(context, "ipropd-master started at version: %lu", + (unsigned long)current_version); + + roken_detach_finish(NULL, daemon_child); + restarter_fd = restarter(context, NULL); + + while (exit_flag == 0){ + slave *p; + fd_set readset, writeset; + int max_fd = 0; + struct timeval to = {30, 0}; + uint32_t vers; + struct stat st2;; + +#ifndef NO_LIMIT_FD_SETSIZE + if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE || + restarter_fd >= FD_SETSIZE) + krb5_errx (context, IPROPD_RESTART, "fd too large"); +#endif + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_SET(signal_fd, &readset); + max_fd = max(max_fd, signal_fd); + FD_SET(listen_fd, &readset); + max_fd = max(max_fd, listen_fd); + if (restarter_fd > -1) { + FD_SET(restarter_fd, &readset); + max_fd = max(max_fd, restarter_fd); + } + + for (p = slaves; p != NULL; p = p->next) { + if (p->flags & SLAVE_F_DEAD) + continue; + FD_SET(p->fd, &readset); + if (have_tail(p) || more_diffs(p)) + FD_SET(p->fd, &writeset); + max_fd = max(max_fd, p->fd); + } + + ret = select(max_fd + 1, &readset, &writeset, NULL, &to); + if (ret < 0) { + if (errno == EINTR) + continue; + else + krb5_err (context, IPROPD_RESTART, errno, "select"); + } + + if (stat(server_context->log_context.log_file, &st2) == -1) { + krb5_warn(context, errno, "could not stat log file by path"); + st2 = st; + } + + if (st2.st_dev != st.st_dev || st2.st_ino != st.st_ino) { + (void) close(log_fd); + + log_fd = open(server_context->log_context.log_file, O_RDONLY, 0); + if (log_fd < 0) + krb5_err(context, IPROPD_RESTART_SLOW, errno, "open %s", + server_context->log_context.log_file); + + if (fstat(log_fd, &st) == -1) + krb5_err(context, IPROPD_RESTART_SLOW, errno, "stat %s", + server_context->log_context.log_file); + + if (flock(log_fd, LOCK_SH) == -1) + krb5_err(context, IPROPD_RESTART, errno, "shared flock %s", + server_context->log_context.log_file); + kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, + ¤t_version, NULL); + flock(log_fd, LOCK_UN); + } + + if (ret == 0) { + /* Recover from failed transactions */ + if (kadm5_log_init_nb(server_context) == 0) + kadm5_log_end(server_context); + + if (flock(log_fd, LOCK_SH) == -1) + krb5_err(context, IPROPD_RESTART, errno, + "could not lock log file"); + kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, + ¤t_version, NULL); + flock(log_fd, LOCK_UN); + + if (current_version > old_version) { + if (verbose) + krb5_warnx(context, + "Missed a signal, updating slaves %lu to %lu", + (unsigned long)old_version, + (unsigned long)current_version); + for (p = slaves; p != NULL; p = p->next) { + if (p->flags & SLAVE_F_DEAD) + continue; + send_diffs(server_context, p, log_fd, database, + current_version); + } + old_version = current_version; + } + } + + if (ret && FD_ISSET(restarter_fd, &readset)) { + exit_flag = SIGTERM; + break; + } + + if (ret && FD_ISSET(signal_fd, &readset)) { +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un peer_addr; +#else + struct sockaddr_storage peer_addr; +#endif + socklen_t peer_len = sizeof(peer_addr); + + if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0, + (struct sockaddr *)&peer_addr, &peer_len) < 0) { + krb5_warn (context, errno, "recvfrom"); + continue; + } + --ret; + assert(ret >= 0); + old_version = current_version; + if (flock(log_fd, LOCK_SH) == -1) + krb5_err(context, IPROPD_RESTART, errno, "shared flock %s", + server_context->log_context.log_file); + kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST, + ¤t_version, NULL); + flock(log_fd, LOCK_UN); + if (current_version != old_version) { + /* + * If current_version < old_version then the log got + * truncated and we'll end up doing full propagations. + * + * Truncating the log when the current version is + * numerically small can lead to race conditions. + * Ideally we should identify log versions as + * {init_or_trunc_time, vno}, then we could not have any + * such race conditions, but this would either require + * breaking backwards compatibility for the protocol or + * adding new messages to it. + */ + if (verbose) + krb5_warnx(context, + "Got a signal, updating slaves %lu to %lu", + (unsigned long)old_version, + (unsigned long)current_version); + for (p = slaves; p != NULL; p = p->next) { + if (p->flags & SLAVE_F_DEAD) + continue; + send_diffs(server_context, p, log_fd, database, + current_version); + } + } else { + if (verbose) + krb5_warnx(context, + "Got a signal, but no update in log version %lu", + (unsigned long)current_version); + } + } + + for (p = slaves; p != NULL; p = p->next) { + if (!(p->flags & SLAVE_F_DEAD) && + FD_ISSET(p->fd, &writeset) && + ((have_tail(p) && send_tail(context, p) == 0) || + (!have_tail(p) && more_diffs(p)))) { + send_diffs(server_context, p, log_fd, database, + current_version); + } + } + + for(p = slaves; p != NULL; p = p->next) { + if (p->flags & SLAVE_F_DEAD) + continue; + if (ret && FD_ISSET(p->fd, &readset)) { + --ret; + assert(ret >= 0); + ret = process_msg(server_context, p, log_fd, database, + current_version); + if (ret && ret != EWOULDBLOCK) + slave_dead(context, p); + } else if (slave_gone_p (p)) + slave_dead(context, p); + else if (slave_missing_p (p)) + send_are_you_there (context, p); + } + + if (ret && FD_ISSET(listen_fd, &readset)) { + add_slave (context, keytab, &slaves, listen_fd); + --ret; + assert(ret >= 0); + } + write_stats(context, slaves, current_version); + } + + if(exit_flag == SIGINT || exit_flag == SIGTERM) + krb5_warnx(context, "%s terminated", getprogname()); +#ifdef SIGXCPU + else if(exit_flag == SIGXCPU) + krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); +#endif + else + krb5_warnx(context, "%s unexpected exit reason: %ld", + getprogname(), (long)exit_flag); + + write_master_down(context); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/ipropd_slave.c b/third_party/heimdal/lib/kadm5/ipropd_slave.c new file mode 100644 index 0000000..e572bff --- /dev/null +++ b/third_party/heimdal/lib/kadm5/ipropd_slave.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "iprop.h" + +RCSID("$Id$"); + +static const char *config_name = "ipropd-slave"; + +static int verbose; +static int async_hdb = 0; +static int no_keytab_flag; +static char *ccache_str; +static char *keytab_str; + +static krb5_log_facility *log_facility; +static char five_min[] = "5 min"; +static char *server_time_lost = five_min; +static int time_before_lost; +static const char *slave_str; +static const char *pidfile_basename; +static char *realm; + +static int +connect_to_master (krb5_context context, const char *master, + const char *port_str) +{ + char port[NI_MAXSERV]; + struct addrinfo *ai, *a; + struct addrinfo hints; + int error; + int one = 1; + int s = -1; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + + if (port_str == NULL) { + snprintf(port, sizeof(port), "%u", IPROP_PORT); + port_str = port; + } + + error = getaddrinfo(master, port_str, &hints, &ai); + if (error) { + krb5_warnx(context, "Failed to get address of to %s: %s", + master, gai_strerror(error)); + return -1; + } + + for (a = ai; a != NULL; a = a->ai_next) { + char node[NI_MAXHOST]; + error = getnameinfo(a->ai_addr, a->ai_addrlen, + node, sizeof(node), NULL, 0, NI_NUMERICHOST); + if (error) + strlcpy(node, "[unknown-addr]", sizeof(node)); + + s = socket(a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) + continue; + if (connect(s, a->ai_addr, a->ai_addrlen) < 0) { + krb5_warn(context, errno, "connection failed to %s[%s]", + master, node); + close(s); + continue; + } + krb5_warnx(context, "connection successful " + "to master: %s[%s]", master, node); + break; + } + freeaddrinfo(ai); + + if (a == NULL) + return -1; + + if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)) < 0) + krb5_warn(context, errno, "setsockopt(SO_KEEPALIVE) failed"); + + /* + * We write message lengths separately from the payload, avoid Nagle + * delays. + */ +#if defined(IPPROTO_TCP) && defined(TCP_NODELAY) + (void) setsockopt(s, IPPROTO_TCP, TCP_NODELAY, + (void *)&one, sizeof(one)); +#endif + + return s; +} + +static void +get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost) +{ + krb5_keytab keytab; + krb5_principal client; + krb5_error_code ret; + krb5_get_init_creds_opt *init_opts; + krb5_creds creds; + char *server; + char keytab_buf[256]; + int aret; + + if (no_keytab_flag) { + /* We're using an externally refreshed ccache */ + if (*cache == NULL) { + if (ccache_str == NULL) + ret = krb5_cc_default(context, cache); + else + ret = krb5_cc_resolve(context, ccache_str, cache); + if (ret) + krb5_err(context, 1, ret, "Could not resolve the default cache"); + } + return; + } + + if (keytab_str == NULL) { + ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); + if (ret == 0) { + keytab_str = keytab_buf; + } else { + krb5_warn(context, ret, "Using HDBGET: as the default keytab"); + keytab_str = "HDBGET:"; + } + } + + if (*cache) + krb5_cc_destroy(context, *cache); + *cache = NULL; + + ret = krb5_kt_resolve(context, keytab_str, &keytab); + if(ret) + krb5_err(context, 1, ret, "%s", keytab_str); + + ret = krb5_sname_to_principal(context, slave_str, IPROP_NAME, + KRB5_NT_SRV_HST, &client); + if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); + if (realm) + ret = krb5_principal_set_realm(context, client, realm); + if (ret) krb5_err(context, 1, ret, "krb5_principal_set_realm"); + + ret = krb5_get_init_creds_opt_alloc(context, &init_opts); + if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); + + aret = asprintf (&server, "%s/%s", IPROP_NAME, serverhost); + if (aret == -1 || server == NULL) + krb5_errx (context, 1, "malloc: no memory"); + + ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, + 0, server, init_opts); + free (server); + krb5_get_init_creds_opt_free(context, init_opts); + if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); + + ret = krb5_kt_close(context, keytab); + if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); + + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); + if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); + + ret = krb5_cc_initialize(context, *cache, creds.client); + if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); + + ret = krb5_cc_store_cred(context, *cache, &creds); + if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); + + krb5_free_cred_contents(context, &creds); + krb5_free_principal(context, client); +} + +static krb5_error_code +ihave(krb5_context context, krb5_auth_context auth_context, + int fd, uint32_t version) +{ + int ret; + u_char buf[8]; + krb5_storage *sp; + krb5_data data; + + sp = krb5_storage_from_mem(buf, 8); + if (sp == NULL) + krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "Out of memory"); + ret = krb5_store_uint32(sp, I_HAVE); + if (ret == 0) + ret = krb5_store_uint32(sp, version); + krb5_storage_free(sp); + data.length = 8; + data.data = buf; + + if (ret == 0) { + if (verbose) + krb5_warnx(context, "telling master we are at %u", version); + + ret = krb5_write_priv_message(context, auth_context, &fd, &data); + if (ret) + krb5_warn(context, ret, "krb5_write_message"); + } + return ret; +} + +#ifndef EDQUOT +/* There's no EDQUOT on WIN32, for example */ +#define EDQUOT ENOSPC +#endif + +static int +append_to_log_file(krb5_context context, + kadm5_server_context *server_context, + krb5_storage *sp, off_t start, ssize_t slen) +{ + size_t len; + ssize_t sret; + off_t log_off; + int ret, ret2; + void *buf; + + if (verbose) + krb5_warnx(context, "appending diffs to log"); + + if (slen == 0) + return 0; + if (slen < 0) + return EINVAL; + len = slen; + if (len != slen) + return EOVERFLOW; + + buf = malloc(len); + if (buf == NULL && len != 0) + return krb5_enomem(context); + + if (krb5_storage_seek(sp, start, SEEK_SET) != start) { + krb5_errx(context, IPROPD_RESTART, + "krb5_storage_seek() failed"); /* can't happen */ + } + sret = krb5_storage_read(sp, buf, len); + if (sret < 0) + return errno; + if (len != (size_t)sret) { + /* Can't happen */ + krb5_errx(context, IPROPD_RESTART, + "short krb5_storage_read() from memory buffer"); + } + log_off = lseek(server_context->log_context.log_fd, 0, SEEK_CUR); + if (log_off == -1) + return errno; + + /* + * Use net_write() so we get an errno if less that len bytes were + * written. + */ + sret = net_write(server_context->log_context.log_fd, buf, len); + free(buf); + if (sret != slen) + ret = errno; + else + ret = fsync(server_context->log_context.log_fd); + if (ret == 0) + return 0; + krb5_warn(context, ret, + "Failed to write iprop log fd %d %llu bytes at offset %lld: %d", + server_context->log_context.log_fd, (unsigned long long)len, + (long long)log_off, ret); + + /* + * Attempt to recover from this. First, truncate the log file + * and reset the fd offset. Failure to do this -> unlink the + * log file and re-create it. Since we're the slave, we ought to be + * able to recover from the log being unlinked... + */ + if (ftruncate(server_context->log_context.log_fd, log_off) == -1 || + lseek(server_context->log_context.log_fd, log_off, SEEK_SET) == -1) { + (void) kadm5_log_end(server_context); + if (unlink(server_context->log_context.log_file) == -1) { + krb5_err(context, IPROPD_FATAL, errno, + "Failed to recover from failure to write log " + "entries from master to disk"); + } + ret2 = kadm5_log_init(server_context); + if (ret2) { + krb5_err(context, IPROPD_RESTART_SLOW, ret2, + "Failed to initialize log to recover from " + "failure to write log entries from master to disk"); + } + } + if (ret == ENOSPC || ret == EDQUOT || ret == EFBIG) { + /* Unlink the file in these cases. */ + krb5_warn(context, IPROPD_RESTART_SLOW, + "Failed to write log entries from master to disk"); + (void) kadm5_log_end(server_context); + if (unlink(server_context->log_context.log_file) == -1) { + krb5_err(context, IPROPD_FATAL, errno, + "Failed to recover from failure to write log " + "entries from master to disk"); + } + ret2 = kadm5_log_init(server_context); + if (ret2) { + krb5_err(context, IPROPD_RESTART_SLOW, ret2, + "Failed to initialize log to recover from " + "failure to write log entries from master to disk"); + } + return ret; + } + /* + * All other errors we treat as fatal here. This includes, for + * example, EIO and EPIPE (sorry, can't log to pipes nor sockets). + */ + krb5_err(context, IPROPD_FATAL, ret, + "Failed to write log entries from master to disk"); +} + +static int +receive_loop(krb5_context context, + krb5_storage *sp, + kadm5_server_context *server_context) +{ + int ret; + off_t left, right, off; + uint32_t len, vers; + + if (verbose) + krb5_warnx(context, "receiving diffs"); + + ret = kadm5_log_exclusivelock(server_context); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, + "Failed to lock iprop log for writes"); + + /* + * Seek to the first entry in the message from the master that is + * past the current version of the local database. + */ + do { + uint32_t timestamp; + uint32_t op; + + if ((ret = krb5_ret_uint32(sp, &vers)) == HEIM_ERR_EOF) { + krb5_warnx(context, "master sent no new iprop entries"); + return 0; + } + + /* + * TODO We could do more to validate the entries from the master + * here. And we could use/reuse more kadm5_log_*() code here. + * + * Alternatively we should trust that the master sent us exactly + * what we needed and just write this to the log file and let + * kadm5_log_recover() do the rest. + */ + if (ret || krb5_ret_uint32(sp, ×tamp) != 0 || + krb5_ret_uint32(sp, &op) != 0 || + krb5_ret_uint32(sp, &len) != 0) { + + /* + * This shouldn't happen. Reconnecting probably won't help + * if it does happen, but by reconnecting we get a chance to + * connect to a new master if a new one is configured. + */ + krb5_warnx(context, "iprop entries from master were truncated"); + return EINVAL; + } + if (vers > server_context->log_context.version) { + break; + } + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (krb5_storage_seek(sp, len + 8, SEEK_CUR) != off + len + 8) { + krb5_warnx(context, "iprop entries from master were truncated"); + return EINVAL; + } + if (verbose) { + krb5_warnx(context, "diff contains old log record version " + "%u %lld %u length %u", + vers, (long long)timestamp, op, len); + } + } while(vers <= server_context->log_context.version); + + /* + * Read the remaining entries into memory... + */ + /* SEEK_CUR is a header into the first entry we care about */ + left = krb5_storage_seek(sp, -16, SEEK_CUR); + right = krb5_storage_seek(sp, 0, SEEK_END); + if (right - left < 24 + len) { + krb5_warnx(context, "iprop entries from master were truncated"); + return EINVAL; + } + + /* + * ...and then write them out to the on-disk log. + */ + + ret = append_to_log_file(context, server_context, sp, left, right - left); + if (ret) + return ret; + + /* + * Replay the new entries. + */ + if (verbose) + krb5_warnx(context, "replaying entries from master"); + ret = kadm5_log_recover(server_context, kadm_recover_replay); + if (ret) { + krb5_warn(context, ret, "replay failed"); + return ret; + } + + ret = kadm5_log_get_version(server_context, &vers); + if (ret) { + krb5_warn(context, ret, + "could not get log version after applying diffs!"); + return ret; + } + if (verbose) + krb5_warnx(context, "slave at version %u", vers); + + if (vers != server_context->log_context.version) { + krb5_warnx(context, "slave's log_context version (%u) is " + "inconsistent with log's version (%u)", + server_context->log_context.version, vers); + } + + return 0; +} + +static int +receive(krb5_context context, + krb5_storage *sp, + kadm5_server_context *server_context) +{ + krb5_error_code ret, ret2; + HDB *mydb = server_context->db; + + ret = mydb->hdb_open(context, server_context->db, O_RDWR | O_CREAT, 0600); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->open"); + + (void) mydb->hdb_set_sync(context, mydb, !async_hdb); + ret2 = receive_loop(context, sp, server_context); + if (ret2) + krb5_warn(context, ret2, "receive from ipropd-master had errors"); + + ret = mydb->hdb_close(context, server_context->db); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); + + (void) kadm5_log_sharedlock(server_context); + if (verbose) + krb5_warnx(context, "downgraded iprop log lock to shared"); + kadm5_log_signal_master(server_context); + if (verbose) + krb5_warnx(context, "signaled master for hierarchical iprop"); + return ret2; +} + +static void +send_im_here(krb5_context context, int fd, + krb5_auth_context auth_context) +{ + krb5_storage *sp; + krb5_data data; + krb5_error_code ret; + + ret = krb5_data_alloc(&data, 4); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, "send_im_here"); + + sp = krb5_storage_from_data (&data); + if (sp == NULL) + krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_data"); + ret = krb5_store_uint32(sp, I_AM_HERE); + krb5_storage_free(sp); + + if (ret == 0) { + ret = krb5_write_priv_message(context, auth_context, &fd, &data); + krb5_data_free(&data); + + if (ret) + krb5_err(context, IPROPD_RESTART, ret, "krb5_write_priv_message"); + + if (verbose) + krb5_warnx(context, "pinged master"); + } + + return; +} + +static void +reinit_log(krb5_context context, + kadm5_server_context *server_context, + uint32_t vno) +{ + krb5_error_code ret; + + if (verbose) + krb5_warnx(context, "truncating log on slave"); + + ret = kadm5_log_reinit(server_context, vno); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "kadm5_log_reinit"); + (void) kadm5_log_sharedlock(server_context); + if (verbose) + krb5_warnx(context, "downgraded iprop log lock to shared"); +} + + +static krb5_error_code +receive_everything(krb5_context context, int fd, + kadm5_server_context *server_context, + krb5_auth_context auth_context) +{ + int ret; + krb5_data data; + uint32_t vno = 0; + uint32_t opcode; + krb5_storage *sp; + + char *dbname; + HDB *mydb; + + krb5_warnx(context, "receive complete database"); + + ret = kadm5_log_exclusivelock(server_context); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, + "Failed to lock iprop log for writes"); + if (server_context->db->hdb_method_name) { + ret = asprintf(&dbname, "%.*s:%s-NEW", + (int) strlen(server_context->db->hdb_method_name) - 1, + server_context->db->hdb_method_name, + server_context->db->hdb_name); + } else { + ret = asprintf(&dbname, "%s-NEW", server_context->db->hdb_name); + } + if (ret == -1) + krb5_err(context, IPROPD_RESTART, ENOMEM, "asprintf"); + ret = hdb_create(context, &mydb, dbname); + if(ret) + krb5_err(context, IPROPD_RESTART, ret, "hdb_create"); + free(dbname); + + ret = hdb_set_master_keyfile(context, + mydb, server_context->config.stash_file); + if(ret) + krb5_err(context, IPROPD_RESTART, ret, "hdb_set_master_keyfile"); + + /* I really want to use O_EXCL here, but given that I can't easily clean + up on error, I won't */ + ret = mydb->hdb_open(context, mydb, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, "db->open"); + + (void) mydb->hdb_set_sync(context, mydb, 0); + + sp = NULL; + krb5_data_zero(&data); + do { + ret = krb5_read_priv_message(context, auth_context, &fd, &data); + + if (ret) { + krb5_warn(context, ret, "krb5_read_priv_message"); + goto cleanup; + } + + sp = krb5_storage_from_data(&data); + if (sp == NULL) + krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_data"); + krb5_ret_uint32(sp, &opcode); + if (opcode == ONE_PRINC) { + krb5_data fake_data; + hdb_entry entry; + + krb5_storage_free(sp); + + fake_data.data = (char *)data.data + 4; + fake_data.length = data.length - 4; + + memset(&entry, 0, sizeof(entry)); + + ret = hdb_value2entry(context, &fake_data, &entry); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, "hdb_value2entry"); + ret = mydb->hdb_store(server_context->context, + mydb, + 0, &entry); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "hdb_store"); + + hdb_free_entry(context, mydb, &entry); + krb5_data_free(&data); + } else if (opcode == NOW_YOU_HAVE) + ; + else + krb5_errx(context, 1, "strange opcode %d", opcode); + } while (opcode == ONE_PRINC); + + if (opcode != NOW_YOU_HAVE) + krb5_errx(context, IPROPD_RESTART_SLOW, + "receive_everything: strange %d", opcode); + + krb5_ret_uint32(sp, &vno); + krb5_storage_free(sp); + + reinit_log(context, server_context, vno); + + ret = mydb->hdb_set_sync(context, mydb, !async_hdb); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "failed to sync the received HDB"); + ret = mydb->hdb_close(context, mydb); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); + + ret = mydb->hdb_rename(context, mydb, server_context->db->hdb_name); + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->rename"); + + + return 0; + + cleanup: + krb5_data_free(&data); + + if (ret) + krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close"); + + ret = mydb->hdb_destroy(context, mydb); + if (ret) + krb5_err(context, IPROPD_RESTART, ret, "db->destroy"); + + krb5_warnx(context, "receive complete database, version %ld", (long)vno); + return ret; +} + +static void +slave_status(krb5_context context, + const char *file, + const char *status, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + + +static void +slave_status(krb5_context context, + const char *file, + const char *fmt, ...) +{ + char *status; + char *fmt2; + va_list args; + int len; + + if (asprintf(&fmt2, "%s\n", fmt) == -1 || fmt2 == NULL) { + (void) unlink(file); + return; + } + va_start(args, fmt); + len = vasprintf(&status, fmt2, args); + free(fmt2); + va_end(args); + if (len < 0 || status == NULL) { + (void) unlink(file); + return; + } + rk_dumpdata(file, status, len); + krb5_warnx(context, "slave status change: %s", status); + free(status); +} + +static void +is_up_to_date(krb5_context context, const char *file, + kadm5_server_context *server_context) +{ + krb5_error_code ret; + char buf[80]; + ret = krb5_format_time(context, time(NULL), buf, sizeof(buf), 1); + if (ret) { + unlink(file); + return; + } + slave_status(context, file, "up-to-date with version: %lu at %s", + (unsigned long)server_context->log_context.version, buf); +} + +static char *database; +static char *status_file; +static char *config_file; +static int version_flag; +static int help_flag; +static char *port_str; +static int detach_from_console; +static int daemon_child = -1; + +static struct getargs args[] = { + { "config-file", 'c', arg_string, &config_file, NULL, NULL }, + { "realm", 'r', arg_string, &realm, NULL, NULL }, + { "database", 'd', arg_string, &database, "database", "file"}, + { "no-keytab", 0, arg_flag, &no_keytab_flag, + "use externally refreshed cache", NULL }, + { "ccache", 0, arg_string, &ccache_str, + "client credentials", "CCACHE" }, + { "keytab", 'k', arg_string, &keytab_str, + "client credentials keytab", "KEYTAB" }, + { "time-lost", 0, arg_string, &server_time_lost, + "time before server is considered lost", "time" }, + { "status-file", 0, arg_string, &status_file, + "file to write out status into", "file" }, + { "port", 0, arg_string, &port_str, + "port ipropd-slave will connect to", "port"}, + { "detach", 0, arg_flag, &detach_from_console, + "detach from console", NULL }, + { "daemon-child", 0, arg_integer, &daemon_child, + "private argument, do not use", NULL }, + { "pidfile-basename", 0, arg_string, &pidfile_basename, + "basename of pidfile; private argument for testing", "NAME" }, + { "async-hdb", 'a', arg_flag, &async_hdb, NULL, NULL }, + { "hostname", 0, arg_string, rk_UNCONST(&slave_str), + "hostname of slave (if not same as hostname)", "hostname" }, + { "verbose", 0, arg_flag, &verbose, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int status) +{ + arg_printusage(args, num_args, NULL, "master"); + exit(status); +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret, ret2; + krb5_context context; + krb5_auth_context auth_context; + void *kadm_handle; + kadm5_server_context *server_context; + kadm5_config_params conf; + int master_fd; + krb5_ccache ccache = NULL; + krb5_principal server; + char **files; + int optidx = 0; + time_t reconnect_min; + time_t backoff; + time_t reconnect_max; + time_t reconnect; + time_t before = 0; + int restarter_fd = -1; + + const char *master; + + setprogname(argv[0]); + + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage(0); + + if (version_flag) { + print_version(NULL); + exit(0); + } + + if (detach_from_console && daemon_child == -1) + daemon_child = roken_detach_prep(argc, argv, "--daemon-child"); + rk_pidfile(pidfile_basename); + + ret = krb5_init_context(&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + setup_signal(); + + if (config_file == NULL) { + if (asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)) == -1 + || config_file == NULL) + errx(1, "out of memory"); + } + + ret = krb5_prepend_config_files_default(config_file, &files); + if (ret) + krb5_err(context, 1, ret, "getting configuration files"); + + ret = krb5_set_config_files(context, files); + krb5_free_config_files(files); + if (ret) + krb5_err(context, 1, ret, "reading configuration files"); + + argc -= optidx; + argv += optidx; + + if (argc != 1) + usage(1); + + master = argv[0]; + + if (status_file == NULL) { + if (asprintf(&status_file, "%s/ipropd-slave-status", hdb_db_dir(context)) < 0 || status_file == NULL) + krb5_errx(context, 1, "can't allocate status file buffer"); + } + + krb5_openlog(context, "ipropd-slave", &log_facility); + krb5_set_warn_dest(context, log_facility); + + slave_status(context, status_file, "bootstrapping"); + + ret = krb5_kt_register(context, &hdb_get_kt_ops); + if(ret) + krb5_err(context, 1, ret, "krb5_kt_register"); + + time_before_lost = parse_time (server_time_lost, "s"); + if (time_before_lost < 0) + krb5_errx (context, 1, "couldn't parse time: %s", server_time_lost); + + slave_status(context, status_file, "getting credentials from keytab/database"); + + memset(&conf, 0, sizeof(conf)); + if(realm) { + conf.mask |= KADM5_CONFIG_REALM; + conf.realm = realm; + } + if (database) { + conf.mask |= KADM5_CONFIG_DBNAME; + conf.dbname = database; + } + ret = kadm5_init_with_password_ctx (context, + KADM5_ADMIN_SERVICE, + NULL, + KADM5_ADMIN_SERVICE, + &conf, 0, 0, + &kadm_handle); + if (ret) + krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); + + server_context = (kadm5_server_context *)kadm_handle; + + slave_status(context, status_file, "creating log file"); + + ret = server_context->db->hdb_open(context, + server_context->db, + O_RDWR | O_CREAT, 0600); + if (ret) + krb5_err (context, 1, ret, "db->open"); + + ret = kadm5_log_init(server_context); + if (ret) + krb5_err(context, 1, ret, "kadm5_log_init"); + (void) kadm5_log_sharedlock(server_context); + if (verbose) + krb5_warnx(context, "downgraded iprop log lock to shared"); + + ret = server_context->db->hdb_close(context, server_context->db); + if (ret) + krb5_err(context, 1, ret, "db->close"); + + get_creds(context, &ccache, master); + + ret = krb5_sname_to_principal (context, master, IPROP_NAME, + KRB5_NT_SRV_HST, &server); + if (ret) + krb5_err (context, 1, ret, "krb5_sname_to_principal"); + + auth_context = NULL; + master_fd = -1; + + krb5_appdefault_time(context, config_name, NULL, "reconnect-min", + 10, &reconnect_min); + krb5_appdefault_time(context, config_name, NULL, "reconnect-max", + 300, &reconnect_max); + krb5_appdefault_time(context, config_name, NULL, "reconnect-backoff", + 10, &backoff); + reconnect = reconnect_min; + + slave_status(context, status_file, "ipropd-slave started"); + + roken_detach_finish(NULL, daemon_child); + restarter_fd = restarter(context, NULL); + + while (!exit_flag) { + struct timeval to; + time_t now, elapsed; + fd_set readset; + int connected = FALSE; + +#ifndef NO_LIMIT_FD_SETSIZE + if (restarter_fd >= FD_SETSIZE) + krb5_errx(context, IPROPD_RESTART, "fd too large"); +#endif + + FD_ZERO(&readset); + if (restarter_fd > -1) + FD_SET(restarter_fd, &readset); + + now = time(NULL); + elapsed = now - before; + + if (elapsed < reconnect) { + time_t left = reconnect - elapsed; + krb5_warnx(context, "sleeping %d seconds before " + "retrying to connect", (int)left); + to.tv_sec = left; + to.tv_usec = 0; + if (select(restarter_fd + 1, &readset, NULL, NULL, &to) == 1) { + exit_flag = SIGTERM; + continue; + } + } + before = now; + + slave_status(context, status_file, "connecting to master: %s\n", master); + + master_fd = connect_to_master (context, master, port_str); + if (master_fd < 0) + goto retry; + + reconnect = reconnect_min; + + if (auth_context) { + krb5_auth_con_free(context, auth_context); + auth_context = NULL; + } + get_creds(context, &ccache, master); + if (verbose) + krb5_warnx(context, "authenticating to master"); + ret = krb5_sendauth (context, &auth_context, &master_fd, + IPROP_VERSION, NULL, server, + AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, + ccache, NULL, NULL, NULL); + if (ret) { + krb5_warn (context, ret, "krb5_sendauth"); + goto retry; + } + + krb5_warnx(context, "ipropd-slave started at version: %ld", + (long)server_context->log_context.version); + + ret = ihave(context, auth_context, master_fd, + server_context->log_context.version); + if (ret) + goto retry; + + connected = TRUE; + + if (verbose) + krb5_warnx(context, "connected to master"); + + slave_status(context, status_file, "connected to master, waiting instructions"); + + while (connected && !exit_flag) { + krb5_data out; + krb5_storage *sp; + uint32_t tmp; + int max_fd; + +#ifndef NO_LIMIT_FD_SETSIZE + if (master_fd >= FD_SETSIZE) + krb5_errx(context, IPROPD_RESTART, "fd too large"); + if (restarter_fd >= FD_SETSIZE) + krb5_errx(context, IPROPD_RESTART, "fd too large"); + max_fd = max(restarter_fd, master_fd); +#endif + + FD_ZERO(&readset); + FD_SET(master_fd, &readset); + if (restarter_fd != -1) + FD_SET(restarter_fd, &readset); + + to.tv_sec = time_before_lost; + to.tv_usec = 0; + + ret = select (max_fd + 1, + &readset, NULL, NULL, &to); + if (ret < 0) { + if (errno == EINTR) + continue; + else + krb5_err (context, 1, errno, "select"); + } + if (ret == 0) { + krb5_warnx(context, "server didn't send a message " + "in %d seconds", time_before_lost); + connected = FALSE; + continue; + } + + if (restarter_fd > -1 && FD_ISSET(restarter_fd, &readset)) { + if (verbose) + krb5_warnx(context, "slave restarter exited"); + exit_flag = SIGTERM; + } + + if (!FD_ISSET(master_fd, &readset)) + continue; + + if (verbose) + krb5_warnx(context, "message from master"); + + ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); + if (ret) { + krb5_warn(context, ret, "krb5_read_priv_message"); + connected = FALSE; + continue; + } + + sp = krb5_storage_from_mem (out.data, out.length); + if (sp == NULL) + krb5_err(context, IPROPD_RESTART, errno, "krb5_storage_from_mem"); + ret = krb5_ret_uint32(sp, &tmp); + if (ret == HEIM_ERR_EOF) { + krb5_warn(context, ret, "master sent zero-length message"); + connected = FALSE; + continue; + } + if (ret != 0) { + krb5_warn(context, ret, "couldn't read master's message"); + connected = FALSE; + continue; + } + + /* + * It's unclear why we open th HDB and call kadm5_log_init() here. + * + * We don't need it to process the log entries we receive in the + * FOR_YOU case: we already call kadm5_log_recover() in receive() / + * receive_loop(). Maybe it's just just in case, though at the + * cost of synchronization with ipropd-master if we're running one + * for hierarchical iprop. + */ + ret = server_context->db->hdb_open(context, + server_context->db, + O_RDWR | O_CREAT, 0600); + if (ret) + krb5_err (context, 1, ret, "db->open while handling a " + "message from the master"); + ret = kadm5_log_init(server_context); + if (ret) { + krb5_err(context, IPROPD_RESTART, ret, "kadm5_log_init while " + "handling a message from the master"); + } + (void) kadm5_log_sharedlock(server_context); + if (verbose) + krb5_warnx(context, "downgraded iprop log lock to shared"); + + ret = server_context->db->hdb_close (context, server_context->db); + if (ret) + krb5_err (context, 1, ret, "db->close while handling a " + "message from the master"); + + switch (tmp) { + case FOR_YOU : + if (verbose) + krb5_warnx(context, "master sent us diffs"); + ret2 = receive(context, sp, server_context); + if (ret2) + krb5_warn(context, ret2, + "receive from ipropd-master had errors"); + ret = ihave(context, auth_context, master_fd, + server_context->log_context.version); + if (ret || ret2) + connected = FALSE; + + /* + * If it returns an error, receive() may nonetheless + * have committed some entries successfully, so we must + * update the slave_status even if there were errors. + */ + is_up_to_date(context, status_file, server_context); + break; + case TELL_YOU_EVERYTHING : + if (verbose) + krb5_warnx(context, "master sent us a full dump"); + ret = receive_everything(context, master_fd, server_context, + auth_context); + (void) kadm5_log_sharedlock(server_context); + if (ret == 0) { + ret = ihave(context, auth_context, master_fd, + server_context->log_context.version); + } + if (ret) + connected = FALSE; + else + is_up_to_date(context, status_file, server_context); + if (verbose) + krb5_warnx(context, "downgraded iprop log lock to shared"); + kadm5_log_signal_master(server_context); + if (verbose) + krb5_warnx(context, "signaled master for hierarchical iprop"); + break; + case ARE_YOU_THERE : + if (verbose) + krb5_warnx(context, "master sent us a ping"); + is_up_to_date(context, status_file, server_context); + /* + * We used to send an I_HAVE here. But the master may send + * ARE_YOU_THERE messages in response to local, possibly- + * transient errors, and if that happens and we respond with an + * I_HAVE then we'll loop hard if the error was not transient. + * + * So we don't ihave() here. + */ + send_im_here(context, master_fd, auth_context); + break; + case YOU_HAVE_LAST_VERSION: + if (verbose) + krb5_warnx(context, "master tells us we are up to date"); + is_up_to_date(context, status_file, server_context); + break; + case NOW_YOU_HAVE : + case I_HAVE : + case ONE_PRINC : + case I_AM_HERE : + default : + krb5_warnx (context, "Ignoring command %d", tmp); + break; + } + krb5_storage_free (sp); + krb5_data_free (&out); + + } + + slave_status(context, status_file, "disconnected from master"); + retry: + if (connected == FALSE) + krb5_warnx (context, "disconnected for server"); + + if (exit_flag) + krb5_warnx (context, "got an exit signal"); + + if (master_fd >= 0) + close(master_fd); + + reconnect += backoff; + if (reconnect > reconnect_max) { + slave_status(context, status_file, "disconnected from master for a long time"); + reconnect = reconnect_max; + } + } + + if (status_file) { + /* XXX It'd be better to leave it saying we're not here */ + unlink(status_file); + } + + if (0); +#ifndef NO_SIGXCPU + else if(exit_flag == SIGXCPU) + krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); +#endif + else if(exit_flag == SIGINT || exit_flag == SIGTERM) + krb5_warnx(context, "%s terminated", getprogname()); + else + krb5_warnx(context, "%s unexpected exit reason: %ld", + getprogname(), (long)exit_flag); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/kadm5-hook.h b/third_party/heimdal/lib/kadm5/kadm5-hook.h new file mode 100644 index 0000000..7d47f55 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/kadm5-hook.h @@ -0,0 +1,151 @@ +/* + * Copyright 2010 + * The Board of Trustees of the Leland Stanford Junior University + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef KADM5_HOOK_H +#define KADM5_HOOK_H 1 + +#define KADM5_HOOK_VERSION_V1 1 + +#include + +/* + * Each hook is called before the operation using KADM5_STAGE_PRECOMMIT and + * then after the operation using KADM5_STAGE_POSTCOMMIT. If the hook returns + * failure during precommit, the operation is aborted without changes to the + * database. All post-commit hook are invoked if the operation was attempted. + * + * Note that unlike libkrb5 plugins, returning success does not prevent other + * plugins being called (i.e. it is equivalent to KRB5_PLUGIN_NO_HANDLE). + */ +enum kadm5_hook_stage { + KADM5_HOOK_STAGE_PRECOMMIT, + KADM5_HOOK_STAGE_POSTCOMMIT +}; + +#define KADM5_HOOK_FLAG_KEEPOLD 0x1 /* keep old password */ +#define KADM5_HOOK_FLAG_CONDITIONAL 0x2 /* only change password if different */ + +typedef struct kadm5_hook_ftable { + HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context); + + const char *name; + const char *vendor; + + /* + * Hook functions; NULL functions are ignored. code is only valid on + * post-commit hooks and represents the result of the commit. Post- + * commit hooks are not called if a pre-commit hook aborted the call. + */ + krb5_error_code (KRB5_CALLCONV *chpass)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password); + + krb5_error_code (KRB5_CALLCONV *chpass_with_key)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_key_data, + krb5_key_data *key_data); + + krb5_error_code (KRB5_CALLCONV *create)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t ent, + uint32_t mask, + const char *password); + + krb5_error_code (KRB5_CALLCONV *modify)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t ent, + uint32_t mask); + + krb5_error_code (KRB5_CALLCONV *delete)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ); + + krb5_error_code (KRB5_CALLCONV *randkey)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ); + + krb5_error_code (KRB5_CALLCONV *rename)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal source, + krb5_const_principal target); + + krb5_error_code (KRB5_CALLCONV *set_keys)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + size_t n_keys, + krb5_keyblock *keyblocks); + + krb5_error_code (KRB5_CALLCONV *prune)(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + int kvno); + +} kadm5_hook_ftable; + +/* + * libkadm5srv expects a symbol named kadm5_hook_plugin_load that must be a + * function of type kadm5_hook_plugin_load_t. + */ +typedef krb5_error_code +(KRB5_CALLCONV *kadm5_hook_plugin_load_t)(krb5_context context, + krb5_get_instance_func_t *func, + size_t *n_hooks, + const kadm5_hook_ftable *const **hooks); + +#endif /* !KADM5_HOOK_H */ diff --git a/third_party/heimdal/lib/kadm5/kadm5-pwcheck.h b/third_party/heimdal/lib/kadm5/kadm5-pwcheck.h new file mode 100644 index 0000000..70cbae5 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/kadm5-pwcheck.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef KADM5_PWCHECK_H +#define KADM5_PWCHECK_H 1 + + +#define KADM5_PASSWD_VERSION_V0 0 +#define KADM5_PASSWD_VERSION_V1 1 + +typedef const char* (*kadm5_passwd_quality_check_func_v0)(krb5_context, + krb5_principal, + krb5_data*); + +/* + * The 4th argument, is a tuning parameter for the quality check + * function, the lib/caller will providing it for the password quality + * module. + */ + +typedef int +(*kadm5_passwd_quality_check_func)(krb5_context context, + krb5_principal principal, + krb5_data *password, + const char *tuning, + char *message, + size_t length); + +struct kadm5_pw_policy_check_func { + const char *name; + kadm5_passwd_quality_check_func func; +}; + +struct kadm5_pw_policy_verifier { + const char *name; + int version; + const char *vendor; + const struct kadm5_pw_policy_check_func *funcs; +}; + +#endif /* KADM5_PWCHECK_H */ diff --git a/third_party/heimdal/lib/kadm5/kadm5_err.et b/third_party/heimdal/lib/kadm5/kadm5_err.et new file mode 100644 index 0000000..e9a3a0b --- /dev/null +++ b/third_party/heimdal/lib/kadm5/kadm5_err.et @@ -0,0 +1,114 @@ +# +# Error messages for the kadm5 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table ovk kadm5 + +prefix KADM5 +error_code FAILURE, "Operation failed for unspecified reason" +error_code AUTH_GET, "Operation requires `get' privilege" +error_code AUTH_ADD, "Operation requires `add' privilege" +error_code AUTH_MODIFY, "Operation requires `modify' privilege" +error_code AUTH_DELETE, "Operation requires `delete' privilege" +error_code AUTH_INSUFFICIENT, "Insufficient authorization for operation" +error_code BAD_DB, "Database inconsistency detected" +error_code DUP, "Principal or policy already exists" +error_code RPC_ERROR, "Communication failure with server" +error_code NO_SRV, "No administration server found for realm" +error_code BAD_HIST_KEY, "Password history principal key version mismatch" +error_code NOT_INIT, "Connection to server not initialized" +error_code UNK_PRINC, "Principal does not exist" +error_code UNK_POLICY, "Policy does not exist" +error_code BAD_MASK, "Invalid field mask for operation" +error_code BAD_CLASS, "Invalid number of character classes" +error_code BAD_LENGTH, "Invalid password length" +error_code BAD_POLICY, "Invalid policy name" +error_code BAD_PRINCIPAL, "Invalid principal name." +error_code BAD_AUX_ATTR, "Invalid auxillary attributes" +error_code BAD_HISTORY, "Invalid password history count" +error_code BAD_MIN_PASS_LIFE, "Password minimum life is greater than password maximum life" +error_code PASS_Q_TOOSHORT, "Password is too short" +error_code PASS_Q_CLASS, "Password does not contain enough character classes" +error_code PASS_Q_DICT, "Password is in the password dictionary" +error_code PASS_REUSE, "Can't reuse password" +error_code PASS_TOOSOON, "Current password's minimum life has not expired" +error_code POLICY_REF, "Policy is in use" +error_code INIT, "Connection to server already initialized" +error_code BAD_PASSWORD, "Incorrect password" +error_code PROTECT_PRINCIPAL, "Can't change protected principal" +error_code BAD_SERVER_HANDLE, "Programmer error! Bad Admin server handle" +error_code BAD_STRUCT_VERSION, "Programmer error! Bad API structure version" +error_code OLD_STRUCT_VERSION, "API structure version specified by application is no longer supported" +error_code NEW_STRUCT_VERSION, "API structure version specified by application is unknown to libraries" +error_code BAD_API_VERSION, "Programmer error! Bad API version" +error_code OLD_LIB_API_VERSION, "API version specified by application is no longer supported by libraries" +error_code OLD_SERVER_API_VERSION,"API version specified by application is no longer supported by server" +error_code NEW_LIB_API_VERSION, "API version specified by application is unknown to libraries" +error_code NEW_SERVER_API_VERSION,"API version specified by application is unknown to server" +error_code SECURE_PRINC_MISSING,"Database error! Required principal missing" +error_code NO_RENAME_SALT, "The salt type of the specified principal does not support renaming" +error_code BAD_CLIENT_PARAMS, "Invalid configuration parameter for remote KADM5 client" +error_code BAD_SERVER_PARAMS, "Invalid configuration parameter for local KADM5 client." +error_code AUTH_LIST, "Operation requires `list' privilege" +error_code AUTH_CHANGEPW, "Operation requires `change-password' privilege" +error_code BAD_TL_TYPE, "Invalid tagged data list element type" +error_code MISSING_CONF_PARAMS, "Required parameters in kdc.conf missing" +error_code BAD_SERVER_NAME, "Bad krb5 admin server hostname" +error_code KS_TUPLE_NOSUPP, "Key/salt tuples not supported by this function" +error_code SETKEY3_ETYPE_MISMATCH, "Key/salt tuples don't match keys" +error_code DECRYPT_USAGE_NOSUPP, "Given usage of kadm5_decrypt() not supported" +error_code POLICY_OP_NOSUPP, "Policy operations not supported" +error_code KEEPOLD_NOSUPP, "Keep old keys option not supported" +error_code AUTH_GET_KEYS, "Operation requires `get-keys' privilege" +error_code ALREADY_LOCKED, "Database already locked" +error_code NOT_LOCKED, "Database not locked" +error_code LOG_CORRUPT, "Incremental propagation log got corrupted" +error_code LOG_NEEDS_UPGRADE, "Incremental propagation log must be upgraded" +error_code BAD_SERVER_HOOK, "Bad KADM5 server hook" +error_code SERVER_HOOK_NOT_FOUND, "Cannot find KADM5 server hook" +error_code OLD_SERVER_HOOK_VERSION, "KADM5 server hook is too old for this version of Heimdal" +error_code NEW_SERVER_HOOK_VERSION, "KADM5 server hook is too new for this version of Heimdal" +error_code READ_ONLY, "Database is read-only; try primary server" +error_code PASS_Q_GENERIC, "Unspecified password quality failure" + + +# MIT has: +# +# - GSS_ERROR sandwiched by AUTH_CHANGEPW and BAD_TL_TYPE +# error_code GSS_ERROR, "GSS-API (or Kerberos) error" + +# - AUTH_SETKEY, SETKEY_DUP_ENCTYPES, and SETV4KEY_INVAL_ENCTYPE, sandwiched by +# BAD_SERVER_NAME and SETKEY3_ETYPE_MISMATCH +# error_code AUTH_SETKEY, "Operation requires ``set-key'' privilege" +# error_code SETKEY_DUP_ENCTYPES, "Multiple values for single or folded enctype" +# error_code SETV4KEY_INVAL_ENCTYPE, "Invalid enctype for setv4key" + +# - all of the following after SETKEY3_ETYPE_MISMATCH +# error_code MISSING_KRB5_CONF_PARAMS, "Missing parameters in krb5.conf required for kadmin client" +# error_code XDR_FAILURE, "XDR encoding error" +# error_code CANT_RESOLVE, "Cannot resolve network address for admin server in requested realm" +# error_code BAD_KEYSALTS, "Invalid key/salt tuples" +# error_code SETKEY_BAD_KVNO, "Invalid multiple or duplicate kvnos in setkey operation" +# error_code AUTH_EXTRACT, "Operation requires ``extract-keys'' privilege" +# error_code PROTECT_KEYS, "Principal keys are locked down" +# error_code AUTH_INITIAL, "Operation requires initial ticket" + +# AUTH_EXTRACT is the same as our AUTH_GET_KEYS +# MISSING_KRB5_CONF_PARAMS is the same as our MISSING_CONF_PARAMS + +# We have a number of errors not in MIT: +# - KS_TUPLE_NOSUPP (no longer relevant) +# - DECRYPT_USAGE_NOSUPP (could be replaced with some other, no?) +# - POLICY_OP_NOSUPP (could be made irrelevant) +# - ALREADY_LOCKED (in MIT KDB locks are recursive) +# - NOT_LOCKED (KRB5_KDB_NOTLOCKED in MIT) +# - LOG_CORRUPT (unique to Heimdal) +# - LOG_NEEDS_UPGRADE (unique to Heimdal) +# - BAD_SERVER_HOOK (unique to Heimdal, not used in-tree) +# - SERVER_HOOK_NOT_FOUND (unique to Heimdal, not used in-tree) +# - OLD_SERVER_HOOK_VERSION (unique to Heimdal, not used in-tree) +# - NEW_SERVER_HOOK_VERSION (unique to Heimdal, not used in-tree) +# - READ_ONLY (should not be unique to Heimdal, but is) diff --git a/third_party/heimdal/lib/kadm5/kadm5_locl.h b/third_party/heimdal/lib/kadm5/kadm5_locl.h new file mode 100644 index 0000000..cb0b1b4 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/kadm5_locl.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1997-2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __KADM5_LOCL_H__ +#define __KADM5_LOCL_H__ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#include +#include +#include "admin.h" +#include "kadm5_err.h" +#include +#include +#include +#include "private.h" + +#endif /* __KADM5_LOCL_H__ */ diff --git a/third_party/heimdal/lib/kadm5/kadm5_pwcheck.3 b/third_party/heimdal/lib/kadm5/kadm5_pwcheck.3 new file mode 100644 index 0000000..5174d9b --- /dev/null +++ b/third_party/heimdal/lib/kadm5/kadm5_pwcheck.3 @@ -0,0 +1,159 @@ +.\" Copyright (c) 2003 - 2004 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 29, 2004 +.Dt KADM5_PWCHECK 3 +.Os HEIMDAL +.Sh NAME +.Nm krb5_pwcheck , +.Nm kadm5_setup_passwd_quality_check , +.Nm kadm5_add_passwd_quality_verifier , +.Nm kadm5_check_password_quality +.Nd Heimdal warning and error functions +.Sh LIBRARY +Kerberos 5 Library (libkadm5srv, -lkadm5srv) +.Sh SYNOPSIS +.In kadm5-protos.h +.In kadm5-pwcheck.h +.Ft void +.Fo kadm5_setup_passwd_quality_check +.Fa "krb5_context context" +.Fa "const char *check_library" +.Fa "const char *check_function" +.Fc +.Ft "krb5_error_code" +.Fo kadm5_add_passwd_quality_verifier +.Fa "krb5_context context" +.Fa "const char *check_library" +.Fc +.Ft "const char *" +.Fo kadm5_check_password_quality +.Fa "krb5_context context" +.Fa "krb5_principal principal" +.Fa "krb5_data *pwd_data" +.Fc +.Ft int +.Fo "(*kadm5_passwd_quality_check_func)" +.Fa "krb5_context context" +.Fa "krb5_principal principal" +.Fa "krb5_data *password" +.Fa "const char *tuning" +.Fa "char *message" +.Fa "size_t length" +.Fc +.Sh DESCRIPTION +These functions perform the quality check for the heimdal database +library. +.Pp +There are two versions of the shared object API; the old version (0) +is deprecated, but still supported. The new version (1) supports +multiple password quality checking policies in the same shared object. +See below for details. +.Pp +The password quality checker will run all policies that are +configured by the user. If any policy rejects the password, the password +will be rejected. +.Pp +Policy names are of the form +.Ql module-name:policy-name +or, if the the policy name is unique enough, just +.Ql policy-name . +.Sh IMPLEMENTING A PASSWORD QUALITY CHECKING SHARED OBJECT +(This refers to the version 1 API only.) +.Pp +Module shared objects may conveniently be compiled and linked with +.Xr libtool 1 . +An object needs to export a symbol called +.Ql kadm5_password_verifier +of the type +.Ft "struct kadm5_pw_policy_verifier" . +.Pp +Its +.Ft name +and +.Ft vendor +fields should contain the obvious information. +.Ft name +must match the +.Ql module-name +portion of the policy name (the part before the colon), if the policy name +contains a colon, or the policy will not be run. +.Ft version +should be +.Dv KADM5_PASSWD_VERSION_V1 . +.Pp +.Ft funcs +contains an array of +.Ft "struct kadm5_pw_policy_check_func" +structures that is terminated with an entry whose +.Ft name +component is +.Dv NULL . +The +.Ft name +field of the array must match the +.Ql policy-name +portion of a policy name (the part after the colon, or the complete policy +name if there is no colon) specified by the user or the policy will not be +run. The +.Ft func +fields of the array elements are functions that are exported by the +module to be called to check the password. They get the following +arguments: the Kerberos context, principal, password, a tuning parameter, and +a pointer to a message buffer and its length. The tuning parameter +for the quality check function is currently always +.Dv NULL . +If the password is acceptable, the function returns zero. Otherwise +it returns non-zero and fills in the message buffer with an +appropriate explanation. +.Sh RUNNING THE CHECKS +.Nm kadm5_setup_passwd_quality_check +sets up type 0 checks. It sets up all type 0 checks defined in +.Xr krb5.conf 5 +if called with the last two arguments null. +.Pp +.Nm kadm5_add_passwd_quality_verifier +sets up type 1 checks. It sets up all type 1 tests defined in +.Xr krb5.conf 5 +if called with a null second argument. +.Nm kadm5_check_password_quality +runs the checks in the order in which they are defined in +.Xr krb5.conf 5 +and the order in which they occur in a +module's +.Ft funcs +array until one returns non-zero. +.Sh SEE ALSO +.Xr libtool 1 , +.Xr krb5 3 , +.Xr krb5.conf 5 diff --git a/third_party/heimdal/lib/kadm5/keys.c b/third_party/heimdal/lib/kadm5/keys.c new file mode 100644 index 0000000..ed7cc83 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/keys.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +/* + * free all the memory used by (len, keys) + */ + +void +_kadm5_free_keys (krb5_context context, + int len, Key *keys) +{ + hdb_free_keys(context, len, keys); +} + +/* + * null-ify `len', `keys' + */ + +void +_kadm5_init_keys (Key *keys, int len) +{ + int i; + + for (i = 0; i < len; ++i) { + keys[i].mkvno = NULL; + keys[i].salt = NULL; + keys[i].key.keyvalue.length = 0; + keys[i].key.keyvalue.data = NULL; + } +} + + +/* + * return 1 if any key in `keys1, len1' exists in `keys2, len2' + */ +static int +_kadm5_exists_keys(Key *keys1, int len1, Key *keys2, int len2) +{ + size_t i, j; + size_t optimize; + + for (i = 0; i < len1; ++i) { + optimize = 0; + for (j = 0; j < len2; j++) { + if ((keys1[i].salt != NULL && keys2[j].salt == NULL) + || (keys1[i].salt == NULL && keys2[j].salt != NULL)) + continue; + + if (keys1[i].salt != NULL) { + if (keys1[i].salt->type != keys2[j].salt->type) + continue; + if (keys1[i].salt->salt.length != keys2[j].salt->salt.length) + continue; + if (memcmp (keys1[i].salt->salt.data, keys2[j].salt->salt.data, + keys1[i].salt->salt.length) != 0) + continue; + } + if (keys1[i].key.keytype != keys2[j].key.keytype) + continue; + optimize = 1; + if (keys1[i].key.keyvalue.length != keys2[j].key.keyvalue.length) + continue; + if (memcmp (keys1[i].key.keyvalue.data, keys2[j].key.keyvalue.data, + keys1[i].key.keyvalue.length) != 0) + continue; + + return 1; + } + + /* + * Optimization: no need to check all of keys1[] if one there + * was one key in keys2[] with matching enctype and salt but not + * matching key. Assumption: all keys in keys1[] and keys2[] + * are output by string2key. + */ + if (optimize) + return 0; + } + return 0; +} + +/* + * return 1 if any key in `keys1, len1' exists in hist_keys + */ +int +_kadm5_exists_keys_hist(Key *keys1, int len1, HDB_Ext_KeySet *hist_keys) +{ + size_t i; + + for (i = 0; i < hist_keys->len; i++) { + if (_kadm5_exists_keys(keys1, len1, + hist_keys->val[i].keys.val, + hist_keys->val[i].keys.len)) + return 1; + } + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def b/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def new file mode 100644 index 0000000..56366ae --- /dev/null +++ b/third_party/heimdal/lib/kadm5/libkadm5srv-exports.def @@ -0,0 +1,93 @@ +EXPORTS +;! kadm5_ad_init_with_password +;! kadm5_ad_init_with_password_ctx + kadm5_add_passwd_quality_verifier + kadm5_all_keys_are_bogus + kadm5_check_password_quality + kadm5_chpass_principal + kadm5_chpass_principal_3 + kadm5_chpass_principal_with_key + kadm5_chpass_principal_with_key_3 + kadm5_create_policy + kadm5_create_principal + kadm5_create_principal_3 + kadm5_decrypt_key + kadm5_delete_policy + kadm5_delete_principal + kadm5_destroy + kadm5_dup_context + kadm5_flush + kadm5_free_key_data + kadm5_free_name_list + kadm5_free_policy_ent + kadm5_free_principal_ent + kadm5_get_instance + kadm5_get_policies + kadm5_get_policy + kadm5_get_principal + kadm5_get_principals + kadm5_get_privs + kadm5_init_with_creds + kadm5_init_with_creds_ctx + kadm5_init_with_password + kadm5_init_with_password_ctx + kadm5_init_with_skey + kadm5_init_with_skey_ctx + kadm5_iter_principals + kadm5_lock + kadm5_modify_policy + kadm5_modify_principal + kadm5_prune_principal + kadm5_randkey_principal + kadm5_randkey_principal_3 + kadm5_rename_principal + kadm5_ret_key_data + kadm5_ret_principal_ent + kadm5_ret_principal_ent_mask + kadm5_ret_tl_data + kadm5_setkey_principal + kadm5_setkey_principal_3 + kadm5_setup_passwd_quality_check + kadm5_some_keys_are_bogus + kadm5_store_key_data + kadm5_store_principal_ent + kadm5_store_principal_ent_mask + kadm5_store_principal_ent_nokeys + kadm5_store_tl_data + kadm5_unlock + kadm5_s_init_with_password_ctx + kadm5_s_init_with_password + kadm5_s_init_with_skey_ctx + kadm5_s_init_with_skey + kadm5_s_init_with_creds_ctx + kadm5_s_init_with_creds + kadm5_s_chpass_principal_cond + kadm5_s_create_principal_with_key + kadm5_log_exclusivelock + kadm5_log_set_version + kadm5_log_sharedlock + kadm5_log_signal_master +;! kadm5_log_signal_socket + kadm5_log_signal_socket_info ;! + kadm5_log_previous + kadm5_log_goto_first + kadm5_log_goto_end + kadm5_log_foreach + kadm5_log_get_version_fd + kadm5_log_get_version + kadm5_log_recover + kadm5_log_replay + kadm5_log_end + kadm5_log_reinit + kadm5_log_init + kadm5_log_init_nb + kadm5_log_init_nolock + kadm5_log_init_sharedlock + kadm5_log_next + kadm5_log_nop + kadm5_log_truncate + kadm5_log_modify + _kadm5_acl_check_permission + _kadm5_unmarshal_params + _kadm5_s_get_db + _kadm5_privs_to_string diff --git a/third_party/heimdal/lib/kadm5/libkadm5srv-version.rc b/third_party/heimdal/lib/kadm5/libkadm5srv-version.rc new file mode 100644 index 0000000..065c18f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/libkadm5srv-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_DLL +#define RC_FILE_DESC_0409 "Heimdal Kerberos v5 Administration Library" +#define RC_FILE_ORIG_0409 "libkadm5srv.dll" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/kadm5/log.c b/third_party/heimdal/lib/kadm5/log.c new file mode 100644 index 0000000..96d063e --- /dev/null +++ b/third_party/heimdal/lib/kadm5/log.c @@ -0,0 +1,2756 @@ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include "heim_threads.h" + +RCSID("$Id$"); + +/* + * A log consists of a sequence of records of this form: + * + * version number 4 bytes -\ + * time in seconds 4 bytes +> preamble --+> header + * operation (enum kadm_ops) 4 bytes -/ / + * n, length of payload 4 bytes --------------+ + * PAYLOAD DATA... n bytes + * n, length of payload 4 bytes ----------------+> trailer + * version number 4 bytes ->postamble ---/ + * + * I.e., records have a header and a trailer so that knowing the offset + * of an record's start or end one can traverse the log forwards and + * backwards. + * + * The log always starts with a nop record (uber record) that contains the + * offset (8 bytes) of the first unconfirmed record (typically EOF), and the + * version number and timestamp of the preceding last confirmed record: + * + * offset of next new record 8 bytes + * last record time 4 bytes + * last record version number 4 bytes + * + * When an iprop slave receives a complete database, it saves that version as + * the last confirmed version, without writing any other records to the log. We + * use that version as the basis for further updates. + * + * kadm5 write operations are done in this order: + * + * - replay unconfirmed log records + * - write (append) and fsync() the log record for the kadm5 update + * - update the HDB (which includes fsync() or moral equivalent) + * - update the log uber record to mark the log record written as + * confirmed (not fsync()ed) + * + * This makes it possible and safe to seek to the logical end of the log + * (that is, the end of the last confirmed record) without traversing + * the whole log forward from offset zero. Unconfirmed records (which + * -currently- should never be more than one) can then be found (and + * rolled forward) by traversing forward from the logical end of the + * log. The trailers make it possible to traverse the log backwards + * from the logical end. + * + * This also makes the log + the HDB a two-phase commit with + * roll-forward system. + * + * HDB entry exists and HDB entry does not exist errors occurring during + * replay of unconfirmed records are ignored. This is because the + * corresponding HDB update might have completed. But also because a + * change to add aliases to a principal can fail because we don't check + * for alias conflicts before going ahead with the write operation. + * + * Non-sensical and incomplete log records found during roll-forward are + * truncated. A log record is non-sensical if its header and trailer + * don't match. + * + * Recovery (by rolling forward) occurs at the next read or write by a + * kadm5 API reader (e.g., kadmin), but not by an hdb API reader (e.g., + * the KDC). This means that, e.g., a principal rename could fail in + * between the store and the delete, and recovery might not take place + * until the next write operation. + * + * The log record payload format for create is: + * + * DER-encoded HDB_entry n bytes + * + * The log record payload format for update is: + * + * mask 4 bytes + * DER-encoded HDB_entry n-4 bytes + * + * The log record payload format for delete is: + * + * krb5_store_principal n bytes + * + * The log record payload format for rename is: + * + * krb5_store_principal m bytes (old principal name) + * DER-encoded HDB_entry n-m bytes (new record) + * + * The log record payload format for nop varies: + * + * - The zeroth record in new logs is a nop with a 16 byte payload: + * + * offset of end of last confirmed record 8 bytes + * timestamp of last confirmed record 4 bytes + * version number of last confirmed record 4 bytes + * + * - New non-zeroth nop records: + * + * nop type 4 bytes + * + * - Old nop records: + * + * version number 4 bytes + * timestamp 4 bytes + * + * Upon initialization, the log's uber record will have version 1, and + * will be followed by a nop record with version 2. The version numbers + * of additional records will be monotonically increasing. + * + * Truncation (kadm5_log_truncate()) takes some N > 0 records from the + * tail of the log and writes them to the beginning of the log after an + * uber record whose version will then be one less than the first of + * those records. + * + * On masters the log should never have more than one unconfirmed + * record, but slaves append all of a master's "diffs" and then call + * kadm5_log_recover() to recover. + */ + +/* + * HDB and log lock order on the master: + * + * 1) open and lock the HDB + * 2) open and lock the log + * 3) do something + * 4) unlock and close the log + * 5) repeat (2)..(4) if desired + * 6) unlock and close the HDB + * + * The kadmin -l lock command can be used to hold the HDB open and + * locked for multiple operations. + * + * HDB and log lock order on the slave: + * + * 1) open and lock the log + * 2) open and lock the HDB + * 3) replay entries + * 4) unlock and close the HDB + * 5) repeat (2)..(4) until signaled + * 6) unlock and close the HDB + * + * The slave doesn't want to allow other local writers, after all, thus + * the order is reversed. This means that using "kadmin -l" on a slave + * will deadlock with ipropd-slave -- don't do that. + */ + +#define LOG_HEADER_SZ ((off_t)(sizeof(uint32_t) * 4)) +#define LOG_TRAILER_SZ ((off_t)(sizeof(uint32_t) * 2)) +#define LOG_WRAPPER_SZ ((off_t)(LOG_HEADER_SZ + LOG_TRAILER_SZ)) +#define LOG_UBER_LEN ((off_t)(sizeof(uint64_t) + sizeof(uint32_t) * 2)) +#define LOG_UBER_SZ ((off_t)(LOG_WRAPPER_SZ + LOG_UBER_LEN)) + +#define LOG_NOPEEK 0 +#define LOG_DOPEEK 1 + +/* + * Read the header of the record starting at the current offset into sp. + * + * Preserves sp's offset on success if `peek', else skips the header. + * + * Preserves sp's offset on failure where possible. + */ +static kadm5_ret_t +get_header(krb5_storage *sp, int peek, uint32_t *verp, uint32_t *tstampp, + enum kadm_ops *opp, uint32_t *lenp) +{ + krb5_error_code ret; + uint32_t tstamp, op, len; + off_t off, new_off; + + if (tstampp == NULL) + tstampp = &tstamp; + if (lenp == NULL) + lenp = &len; + + *verp = 0; + *tstampp = 0; + if (opp != NULL) + *opp = kadm_nop; + *lenp = 0; + + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off < 0) + return errno; + ret = krb5_ret_uint32(sp, verp); + if (ret == HEIM_ERR_EOF) { + (void) krb5_storage_seek(sp, off, SEEK_SET); + return HEIM_ERR_EOF; + } + if (ret) + goto log_corrupt; + ret = krb5_ret_uint32(sp, tstampp); + if (ret) + goto log_corrupt; + + /* Note: sizeof(*opp) might not == sizeof(op) */ + ret = krb5_ret_uint32(sp, &op); + if (ret) + goto log_corrupt; + if (opp != NULL) + *opp = op; + + ret = krb5_ret_uint32(sp, lenp); + if (ret) + goto log_corrupt; + + /* Restore offset if requested */ + if (peek == LOG_DOPEEK) { + new_off = krb5_storage_seek(sp, off, SEEK_SET); + if (new_off == -1) + return errno; + if (new_off != off) + return EIO; + } + + return 0; + +log_corrupt: + (void) krb5_storage_seek(sp, off, SEEK_SET); + return KADM5_LOG_CORRUPT; +} + +/* + * Seek to the start of the preceding record's header and returns its + * offset. If sp is at offset zero this sets *verp = 0 and returns 0. + * + * Does not verify the header of the previous entry. + * + * On error returns -1, setting errno (possibly to a kadm5_ret_t or + * krb5_error_code value) and preserves sp's offset where possible. + */ +static off_t +seek_prev(krb5_storage *sp, uint32_t *verp, uint32_t *lenp) +{ + krb5_error_code ret; + uint32_t len, ver; + off_t off_len; + off_t off, new_off; + + if (lenp == NULL) + lenp = &len; + if (verp == NULL) + verp = &ver; + + *verp = 0; + *lenp = 0; + + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off < 0) + return off; + if (off == 0) + return 0; + + /* Check that `off' allows for the record's header and trailer */ + if (off < LOG_WRAPPER_SZ) + goto log_corrupt; + + /* Get the previous entry's length and version from its trailer */ + new_off = krb5_storage_seek(sp, -8, SEEK_CUR); + if (new_off == -1) + return -1; + if (new_off != off - 8) { + errno = EIO; + return -1; + } + ret = krb5_ret_uint32(sp, lenp); + if (ret) + goto log_corrupt; + + /* Check for overflow/sign extension */ + off_len = (off_t)*lenp; + if (off_len < 0 || *lenp != (uint32_t)off_len) + goto log_corrupt; + + ret = krb5_ret_uint32(sp, verp); + if (ret) + goto log_corrupt; + + /* Check that `off' allows for the record */ + if (off < LOG_WRAPPER_SZ + off_len) + goto log_corrupt; + + /* Seek backwards to the entry's start */ + new_off = krb5_storage_seek(sp, -(LOG_WRAPPER_SZ + off_len), SEEK_CUR); + if (new_off == -1) + return -1; + if (new_off != off - (LOG_WRAPPER_SZ + off_len)) { + errno = EIO; + return -1; + } + return new_off; + +log_corrupt: + (void) krb5_storage_seek(sp, off, SEEK_SET); + errno = KADM5_LOG_CORRUPT; + return -1; +} + +/* + * Seek to the start of the next entry's header. + * + * On error returns -1 and preserves sp's offset. + */ +static off_t +seek_next(krb5_storage *sp) +{ + krb5_error_code ret; + uint32_t ver, ver2, len, len2; + enum kadm_ops op; + uint32_t tstamp; + off_t off, off_len, new_off; + + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off < 0) + return off; + + errno = get_header(sp, LOG_NOPEEK, &ver, &tstamp, &op, &len); + if (errno) + return -1; + + /* Check for overflow */ + off_len = len; + if (off_len < 0) + goto log_corrupt; + + new_off = krb5_storage_seek(sp, off_len, SEEK_CUR); + if (new_off == -1) { + (void) krb5_storage_seek(sp, off, SEEK_SET); + return -1; + } + if (new_off != off + LOG_HEADER_SZ + off_len) + goto log_corrupt; + ret = krb5_ret_uint32(sp, &len2); + if (ret || len2 != len) + goto log_corrupt; + ret = krb5_ret_uint32(sp, &ver2); + if (ret || ver2 != ver) + goto log_corrupt; + new_off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (new_off == -1) { + (void) krb5_storage_seek(sp, off, SEEK_SET); + return -1; + } + if (new_off != off + off_len + LOG_WRAPPER_SZ) + goto log_corrupt; + + return off + off_len + LOG_WRAPPER_SZ; + +log_corrupt: + (void) krb5_storage_seek(sp, off, SEEK_SET); + errno = KADM5_LOG_CORRUPT; + return -1; +} + +/* + * Get the version of the entry ending at the current offset into sp. + * If it is the uber record, return its nominal version instead. + * + * Returns HEIM_ERR_EOF if sp is at offset zero. + * + * Preserves sp's offset. + */ +static kadm5_ret_t +get_version_prev(krb5_storage *sp, uint32_t *verp, uint32_t *tstampp) +{ + krb5_error_code ret; + uint32_t ver, ver2, len, len2; + off_t off, prev_off, new_off; + + *verp = 0; + if (tstampp != NULL) + *tstampp = 0; + + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off < 0) + return errno; + if (off == 0) + return HEIM_ERR_EOF; + + /* Read the trailer and seek back */ + prev_off = seek_prev(sp, &ver, &len); + if (prev_off == -1) + return errno; + + /* Uber record? Return nominal version. */ + if (prev_off == 0 && len == LOG_UBER_LEN && ver == 0) { + /* Skip 8 byte offset and 4 byte time */ + if (krb5_storage_seek(sp, LOG_HEADER_SZ + 12, SEEK_SET) + != LOG_HEADER_SZ + 12) + return errno; + ret = krb5_ret_uint32(sp, verp); + if (krb5_storage_seek(sp, 0, SEEK_SET) != 0) + return errno; + if (ret != 0) + return ret; + } else { + *verp = ver; + } + + /* Verify that the trailer matches header */ + ret = get_header(sp, LOG_NOPEEK, &ver2, tstampp, NULL, &len2); + if (ret || ver != ver2 || len != len2) + goto log_corrupt; + + /* Preserve offset */ + new_off = krb5_storage_seek(sp, off, SEEK_SET); + if (new_off == -1) + return errno; + if (new_off != off) { + errno = EIO; + return errno; + } + return 0; + +log_corrupt: + (void) krb5_storage_seek(sp, off, SEEK_SET); + return KADM5_LOG_CORRUPT; +} + +static size_t +get_max_log_size(krb5_context context) +{ + off_t n; + + /* Use database-label-specific lookup? No, ETOOHARD. */ + /* Default to 50MB max log size */ + n = krb5_config_get_int_default(context, NULL, 52428800, + "kdc", + "log-max-size", + NULL); + if (n >= 4 * (LOG_UBER_LEN + LOG_WRAPPER_SZ) && n == (size_t)n) + return (size_t)n; + return 0; +} + +static kadm5_ret_t truncate_if_needed(kadm5_server_context *); + +/* + * Get the version and timestamp metadata of either the first, or last + * confirmed entry in the log. + * + * If `which' is LOG_VERSION_UBER, then this gets the version number of the uber + * uber record which must be 0, or else we need to upgrade the log. + * + * If `which' is LOG_VERSION_FIRST, then this gets the metadata for the + * logically first entry past the uberblock, or returns HEIM_ERR_EOF if + * only the uber record is present. + * + * If `which' is LOG_VERSION_LAST, then this gets metadata for the last + * confirmed entry's version and timestamp. If only the uber record is present, + * then the version will be its "nominal" version, which may differ from its + * actual version (0). + * + * The `fd''s offset will be set to the start of the header of the entry + * identified by `which'. + */ +kadm5_ret_t +kadm5_log_get_version_fd(kadm5_server_context *server_context, int fd, + int which, uint32_t *ver, uint32_t *tstamp) +{ + kadm5_ret_t ret = 0; + krb5_storage *sp; + enum kadm_ops op = kadm_get; + uint32_t len = 0; + uint32_t tmp; + + if (fd == -1) + return 0; /* /dev/null */ + + if (tstamp == NULL) + tstamp = &tmp; + + *ver = 0; + *tstamp = 0; + + sp = krb5_storage_from_fd(fd); + if (sp == NULL) + return errno ? errno : ENOMEM; + + switch (which) { + case LOG_VERSION_LAST: + ret = kadm5_log_goto_end(server_context, sp); + if (ret == 0) + ret = get_version_prev(sp, ver, tstamp); + break; + case LOG_VERSION_FIRST: + ret = kadm5_log_goto_first(server_context, sp); + if (ret == 0) + ret = get_header(sp, LOG_DOPEEK, ver, tstamp, NULL, NULL); + break; + case LOG_VERSION_UBER: + if (krb5_storage_seek(sp, 0, SEEK_SET) == 0) + ret = get_header(sp, LOG_DOPEEK, ver, tstamp, &op, &len); + else + ret = errno; + if (ret == 0 && (op != kadm_nop || len != LOG_UBER_LEN || *ver != 0)) + ret = KADM5_LOG_NEEDS_UPGRADE; + break; + default: + ret = ENOTSUP; + break; + } + + krb5_storage_free(sp); + return ret; +} + +/* Get the version of the last confirmed entry in the log */ +kadm5_ret_t +kadm5_log_get_version(kadm5_server_context *server_context, uint32_t *ver) +{ + return kadm5_log_get_version_fd(server_context, + server_context->log_context.log_fd, + LOG_VERSION_LAST, ver, NULL); +} + +/* Sets the version in the context, but NOT in the log */ +kadm5_ret_t +kadm5_log_set_version(kadm5_server_context *context, uint32_t vno) +{ + kadm5_log_context *log_context = &context->log_context; + + log_context->version = vno; + return 0; +} + +/* + * Open the log and setup server_context->log_context + */ +static kadm5_ret_t +log_open(kadm5_server_context *server_context, int lock_mode) +{ + int fd = -1; + int lock_it = 0; + int lock_nb = 0; + int oflags = O_RDWR; + kadm5_ret_t ret; + kadm5_log_context *log_context = &server_context->log_context; + + if (lock_mode & LOCK_NB) { + lock_mode &= ~LOCK_NB; + lock_nb = LOCK_NB; + } + + if (lock_mode == log_context->lock_mode && log_context->log_fd != -1) + return 0; + + if (strcmp(log_context->log_file, "/dev/null") == 0) { + /* log_context->log_fd should be -1 here */ + return 0; + } + + if (log_context->log_fd != -1) { + /* Lock or change lock */ + fd = log_context->log_fd; + if (lseek(fd, 0, SEEK_SET) == -1) + return errno; + lock_it = (lock_mode != log_context->lock_mode); + } else { + /* Open and lock */ + if (lock_mode != LOCK_UN) + oflags |= O_CREAT; + fd = open(log_context->log_file, oflags, 0600); + if (fd < 0) { + ret = errno; + krb5_set_error_message(server_context->context, ret, + "log_open: open %s", log_context->log_file); + return ret; + } + lock_it = (lock_mode != LOCK_UN); + } + if (lock_it && flock(fd, lock_mode | lock_nb) < 0) { + ret = errno; + krb5_set_error_message(server_context->context, ret, + "log_open: flock %s", log_context->log_file); + if (fd != log_context->log_fd) + (void) close(fd); + return ret; + } + + log_context->log_fd = fd; + log_context->lock_mode = lock_mode; + log_context->read_only = (lock_mode != LOCK_EX); + + return 0; +} + +/* + * Open the log and setup server_context->log_context + */ +static kadm5_ret_t +log_init(kadm5_server_context *server_context, int lock_mode) +{ + int fd; + struct stat st; + uint32_t vno; + size_t maxbytes = get_max_log_size(server_context->context); + kadm5_ret_t ret; + kadm5_log_context *log_context = &server_context->log_context; + + if (strcmp(log_context->log_file, "/dev/null") == 0) { + /* log_context->log_fd should be -1 here */ + return 0; + } + + ret = log_open(server_context, lock_mode); + if (ret) + return ret; + + fd = log_context->log_fd; + if (!log_context->read_only) { + if (fstat(fd, &st) == -1) + ret = errno; + if (ret == 0 && st.st_size == 0) { + /* Write first entry */ + log_context->version = 0; + ret = kadm5_log_nop(server_context, kadm_nop_plain); + if (ret == 0) + return 0; /* no need to truncate_if_needed(): it's not */ + } + if (ret == 0) { + ret = kadm5_log_get_version_fd(server_context, fd, + LOG_VERSION_UBER, &vno, NULL); + + /* Upgrade the log if it was an old-style log */ + if (ret == KADM5_LOG_NEEDS_UPGRADE) + ret = kadm5_log_truncate(server_context, 0, maxbytes / 4); + } + if (ret == 0) + ret = kadm5_log_recover(server_context, kadm_recover_replay); + } + + if (ret == 0) { + ret = kadm5_log_get_version_fd(server_context, fd, LOG_VERSION_LAST, + &log_context->version, NULL); + if (ret == HEIM_ERR_EOF) + ret = 0; + } + + if (ret == 0) + ret = truncate_if_needed(server_context); + + if (ret != 0) + (void) kadm5_log_end(server_context); + return ret; +} + +/* Open the log with an exclusive lock */ +kadm5_ret_t +kadm5_log_init(kadm5_server_context *server_context) +{ + return log_init(server_context, LOCK_EX); +} + +/* Upgrade log lock to exclusive */ +kadm5_ret_t +kadm5_log_exclusivelock(kadm5_server_context *server_context) +{ + kadm5_log_context *log_context = &server_context->log_context; + + if (log_context->lock_mode == LOCK_EX) + return 0; + if (log_context->log_fd == -1) + return EINVAL; + if (flock(log_context->log_fd, LOCK_EX) < 0) + return errno; + log_context->read_only = 0; + log_context->lock_mode = LOCK_EX; + return 0; +} + +/* Downgrade log lock to shared */ +kadm5_ret_t +kadm5_log_sharedlock(kadm5_server_context *server_context) +{ + kadm5_log_context *log_context = &server_context->log_context; + + if (log_context->lock_mode == LOCK_SH) + return 0; + if (log_context->log_fd == -1) + return EINVAL; + if (flock(log_context->log_fd, LOCK_SH) < 0) + return errno; + log_context->read_only = 1; + log_context->lock_mode = LOCK_SH; + return 0; +} + +/* Open the log with an exclusive non-blocking lock */ +kadm5_ret_t +kadm5_log_init_nb(kadm5_server_context *server_context) +{ + return log_init(server_context, LOCK_EX | LOCK_NB); +} + +/* Open the log with no locks */ +kadm5_ret_t +kadm5_log_init_nolock(kadm5_server_context *server_context) +{ + return log_init(server_context, LOCK_UN); +} + +/* Open the log with a shared lock */ +kadm5_ret_t +kadm5_log_init_sharedlock(kadm5_server_context *server_context, int lock_flags) +{ + return log_init(server_context, LOCK_SH | lock_flags); +} + +/* + * Reinitialize the log and open it + */ +kadm5_ret_t +kadm5_log_reinit(kadm5_server_context *server_context, uint32_t vno) +{ + int ret; + kadm5_log_context *log_context = &server_context->log_context; + + ret = log_open(server_context, LOCK_EX); + if (ret) + return ret; + if (log_context->log_fd != -1) { + if (ftruncate(log_context->log_fd, 0) < 0) { + ret = errno; + return ret; + } + if (lseek(log_context->log_fd, 0, SEEK_SET) < 0) { + ret = errno; + return ret; + } + } + + /* Write uber entry and truncation nop with version `vno` */ + log_context->version = vno; + return kadm5_log_nop(server_context, kadm_nop_plain); +} + +/* Close the server_context->log_context. */ +kadm5_ret_t +kadm5_log_end(kadm5_server_context *server_context) +{ + kadm5_log_context *log_context = &server_context->log_context; + kadm5_ret_t ret = 0; + int fd = log_context->log_fd; + + if (fd != -1) { + if (log_context->lock_mode != LOCK_UN) { + if (flock(fd, LOCK_UN) == -1 && errno == EBADF) + ret = errno; + } + if (ret != EBADF && close(fd) == -1) + ret = errno; + } + log_context->log_fd = -1; + log_context->lock_mode = LOCK_UN; + return ret; +} + +/* + * Write the version, timestamp, and op for a new entry. + * + * Note that the sp should be a krb5_storage_emem(), not a file. + * + * On success the sp's offset will be where the length of the payload + * should be written. + */ +static kadm5_ret_t +kadm5_log_preamble(kadm5_server_context *context, + krb5_storage *sp, + enum kadm_ops op, + uint32_t vno) +{ + kadm5_log_context *log_context = &context->log_context; + time_t now = time(NULL); + kadm5_ret_t ret; + + ret = krb5_store_uint32(sp, vno); + if (ret) + return ret; + ret = krb5_store_uint32(sp, now); + if (ret) + return ret; + log_context->last_time = now; + + if (op < kadm_first || op > kadm_last) + return ERANGE; + return krb5_store_uint32(sp, op); +} + +/* Writes the version part of the trailer */ +static kadm5_ret_t +kadm5_log_postamble(kadm5_log_context *context, + krb5_storage *sp, + uint32_t vno) +{ + return krb5_store_uint32(sp, vno); +} + +/* + * Signal the ipropd-master about changes to the log. + */ +/* + * XXX Get rid of the ifdef by having a sockaddr in log_context in both + * cases. + * + * XXX Better yet, just connect to the master's socket that slaves + * connect to, and then disconnect. The master should then check the + * log on every connection accepted. Then we wouldn't need IPC to + * signal the master. + */ +void +kadm5_log_signal_master(kadm5_server_context *context) +{ + kadm5_log_context *log_context = &context->log_context; +#ifndef NO_UNIX_SOCKETS + (void) sendto(log_context->socket_fd, + (void *)&log_context->version, + sizeof(log_context->version), + 0, + (struct sockaddr *)&log_context->socket_name, + sizeof(log_context->socket_name)); +#else + (void) sendto(log_context->socket_fd, + (void *)&log_context->version, + sizeof(log_context->version), + 0, + log_context->socket_info->ai_addr, + log_context->socket_info->ai_addrlen); +#endif +} + +/* + * Write sp's contents (which must be a fully formed record, complete + * with header, payload, and trailer) to the log and fsync the log. + * + * Does not free sp. + */ + +static kadm5_ret_t +kadm5_log_flush(kadm5_server_context *context, krb5_storage *sp) +{ + kadm5_log_context *log_context = &context->log_context; + kadm5_ret_t ret; + krb5_data data; + size_t len; + krb5_ssize_t bytes; + uint32_t new_ver, prev_ver; + off_t off, end; + + if (strcmp(log_context->log_file, "/dev/null") == 0) + return 0; + + if (log_context->read_only) + return EROFS; + + if (krb5_storage_seek(sp, 0, SEEK_SET) == -1) + return errno; + + ret = get_header(sp, LOG_DOPEEK, &new_ver, NULL, NULL, NULL); + if (ret) + return ret; + + ret = krb5_storage_to_data(sp, &data); + if (ret) + return ret; + + /* Abandon the emem storage reference */ + sp = krb5_storage_from_fd(log_context->log_fd); + if (sp == NULL) { + krb5_data_free(&data); + return krb5_enomem(context->context); + } + + /* Check that we are at the end of the log and fail if not */ + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off == -1) { + krb5_data_free(&data); + krb5_storage_free(sp); + return errno; + } + end = krb5_storage_seek(sp, 0, SEEK_END); + if (end == -1) { + krb5_data_free(&data); + krb5_storage_free(sp); + return errno; + } + if (end != off) { + krb5_data_free(&data); + krb5_storage_free(sp); + return KADM5_LOG_CORRUPT; + } + + /* Enforce monotonically incremented versioning of records */ + if (seek_prev(sp, &prev_ver, NULL) == -1 || + krb5_storage_seek(sp, end, SEEK_SET) == -1) { + ret = errno; + krb5_data_free(&data); + krb5_storage_free(sp); + return ret; + } + + if (prev_ver != 0 && prev_ver != log_context->version) + return EINVAL; /* Internal error, really; just a consistency check */ + + if (prev_ver != 0 && new_ver != prev_ver + 1) { + krb5_warnx(context->context, "refusing to write a log record " + "with non-monotonic version (new: %u, old: %u)", + new_ver, prev_ver); + return KADM5_LOG_CORRUPT; + } + + len = data.length; + bytes = krb5_storage_write(sp, data.data, len); + krb5_data_free(&data); + if (bytes != len) { + krb5_storage_free(sp); + ret = bytes == -1 ? errno : KADM5_LOG_CORRUPT; + krb5_warn(context->context, ret, "short write to iprop log file"); + return ret; + } + if (bytes != (krb5_ssize_t)len) { + krb5_storage_free(sp); + return EIO; + } + + ret = krb5_storage_fsync(sp); + krb5_storage_free(sp); + if (ret) + return ret; + + /* Retain the nominal database version when flushing the uber record */ + if (new_ver != 0) + log_context->version = new_ver; + return 0; +} + +/* + * Add a `create' operation to the log and perform the create against the HDB. + */ +kadm5_ret_t +kadm5_log_create(kadm5_server_context *context, hdb_entry *entry) +{ + krb5_storage *sp; + krb5_ssize_t bytes; + kadm5_ret_t ret; + krb5_data value; + hdb_entry ent, existing; + kadm5_log_context *log_context = &context->log_context; + + memset(&existing, 0, sizeof(existing)); + memset(&ent, 0, sizeof(ent)); + ent = *entry; + + /* + * Do not allow creation of concrete entries within namespaces unless + * explicitly requested. + */ + ret = hdb_fetch_kvno(context->context, context->db, entry->principal, 0, + 0, 0, 0, &existing); + if (ret != 0 && ret != HDB_ERR_NOENTRY) + return ret; + if (ret == 0 && !ent.flags.materialize && + (existing.flags.virtual || existing.flags.virtual_keys)) { + hdb_free_entry(context->context, context->db, &existing); + return HDB_ERR_EXISTS; + } + if (ret == 0) + hdb_free_entry(context->context, context->db, &existing); + ent.flags.materialize = 0; /* Clear in stored entry */ + + /* + * If we're not logging then we can't recover-to-perform, so just + * perform. + */ + if (strcmp(log_context->log_file, "/dev/null") == 0) + return context->db->hdb_store(context->context, context->db, 0, &ent); + + /* + * Test for any conflicting entries before writing the log. If we commit + * to the log we'll end-up rolling forward on recovery, but that would be + * wrong if the initial create is rejected. + */ + ret = context->db->hdb_store(context->context, context->db, + HDB_F_PRECHECK, &ent); + if (ret == 0) + ret = hdb_entry2value(context->context, entry, &value); + if (ret) + return ret; + sp = krb5_storage_emem(); + if (sp == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = kadm5_log_preamble(context, sp, kadm_create, + log_context->version + 1); + if (ret == 0) + ret = krb5_store_uint32(sp, value.length); + if (ret == 0) { + bytes = krb5_storage_write(sp, value.data, value.length); + if (bytes != (krb5_ssize_t)value.length) + ret = bytes == -1 ? errno : krb5_enomem(context->context); + } + if (ret == 0) + ret = krb5_store_uint32(sp, value.length); + if (ret == 0) + ret = kadm5_log_postamble(log_context, sp, + log_context->version + 1); + if (ret == 0) + ret = kadm5_log_flush(context, sp); + krb5_storage_free(sp); + krb5_data_free(&value); + if (ret == 0) + ret = kadm5_log_recover(context, kadm_recover_commit); + return ret; +} + +/* + * Read the data of a create log record from `sp' and change the + * database. + */ +static kadm5_ret_t +kadm5_log_replay_create(kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + krb5_error_code ret; + krb5_data data; + hdb_entry ent; + + memset(&ent, 0, sizeof(ent)); + + ret = krb5_data_alloc(&data, len); + if (ret) { + krb5_set_error_message(context->context, ret, "out of memory"); + return ret; + } + krb5_storage_read(sp, data.data, len); + ret = hdb_value2entry(context->context, &data, &ent); + krb5_data_free(&data); + if (ret) { + krb5_set_error_message(context->context, ret, + "Unmarshaling hdb entry in log failed, " + "version: %ld", (long)ver); + return ret; + } + ret = context->db->hdb_store(context->context, context->db, 0, &ent); + hdb_free_entry(context->context, context->db, &ent); + return ret; +} + +/* + * Add a `delete' operation to the log. + */ +kadm5_ret_t +kadm5_log_delete(kadm5_server_context *context, + krb5_principal princ) +{ + kadm5_ret_t ret; + kadm5_log_context *log_context = &context->log_context; + krb5_storage *sp; + uint32_t len = 0; /* So dumb compilers don't warn */ + off_t end_off = 0; /* Ditto; this allows de-indentation by two levels */ + off_t off; + + if (strcmp(log_context->log_file, "/dev/null") == 0) + return context->db->hdb_remove(context->context, context->db, 0, + princ); + ret = context->db->hdb_remove(context->context, context->db, + HDB_F_PRECHECK, princ); + if (ret) + return ret; + sp = krb5_storage_emem(); + if (sp == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = kadm5_log_preamble(context, sp, kadm_delete, + log_context->version + 1); + if (ret) { + krb5_storage_free(sp); + return ret; + } + + /* + * Write a 0 length which we overwrite once we know the length of + * the principal name payload. + */ + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, 0); + if (ret == 0) + ret = krb5_store_principal(sp, princ); + if (ret == 0) { + end_off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (end_off == -1) + ret = errno; + else if (end_off < off) + ret = KADM5_LOG_CORRUPT; + } + if (ret == 0) { + /* We wrote sizeof(uint32_t) + payload length bytes */ + len = (uint32_t)(end_off - off); + if (end_off - off != len || len < sizeof(len)) + ret = KADM5_LOG_CORRUPT; + else + len -= sizeof(len); + } + if (ret == 0 && krb5_storage_seek(sp, off, SEEK_SET) == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0 && krb5_storage_seek(sp, end_off, SEEK_SET) == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0) + ret = kadm5_log_postamble(log_context, sp, + log_context->version + 1); + if (ret == 0) + ret = kadm5_log_flush(context, sp); + if (ret == 0) + ret = kadm5_log_recover(context, kadm_recover_commit); + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `delete' log operation from `sp' and apply it. + */ +static kadm5_ret_t +kadm5_log_replay_delete(kadm5_server_context *context, + uint32_t ver, uint32_t len, krb5_storage *sp) +{ + krb5_error_code ret; + krb5_principal principal; + + ret = krb5_ret_principal(sp, &principal); + if (ret) { + krb5_set_error_message(context->context, ret, "Failed to read deleted " + "principal from log version: %ld", (long)ver); + return ret; + } + + ret = context->db->hdb_remove(context->context, context->db, 0, principal); + krb5_free_principal(context->context, principal); + return ret; +} + +static kadm5_ret_t kadm5_log_replay_rename(kadm5_server_context *, + uint32_t, uint32_t, + krb5_storage *); + +/* + * Add a `rename' operation to the log. + */ +kadm5_ret_t +kadm5_log_rename(kadm5_server_context *context, + krb5_principal source, + hdb_entry *entry) +{ + krb5_storage *sp; + krb5_ssize_t bytes; + kadm5_ret_t ret; + uint32_t len = 0; /* So dumb compilers don't warn */ + off_t end_off = 0; /* Ditto; this allows de-indentation by two levels */ + off_t off; + krb5_data value; + hdb_entry ent; + kadm5_log_context *log_context = &context->log_context; + + memset(&ent, 0, sizeof(ent)); + ent = *entry; + + if (strcmp(log_context->log_file, "/dev/null") == 0) { + ret = context->db->hdb_store(context->context, context->db, 0, &ent); + if (ret == 0) + return context->db->hdb_remove(context->context, context->db, 0, + source); + return ret; + } + + /* + * Pre-check that the transaction will succeed. + * + * Note that rename doesn't work to swap a principal's canonical + * name with one of its aliases. To make that work would require + * adding an hdb_rename() method for renaming principals (there's an + * hdb_rename() method already, but for renaming the HDB), which is + * ETOOMUCHWORK for the time being. + */ + ret = context->db->hdb_store(context->context, context->db, + HDB_F_PRECHECK, &ent); + if (ret == 0) + ret = context->db->hdb_remove(context->context, context->db, + HDB_F_PRECHECK, source); + if (ret) + return ret; + + sp = krb5_storage_emem(); + krb5_data_zero(&value); + if (sp == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = kadm5_log_preamble(context, sp, kadm_rename, + log_context->version + 1); + if (ret == 0) + ret = hdb_entry2value(context->context, entry, &value); + if (ret) { + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; + } + + /* + * Write a zero length which we'll overwrite once we know the length of the + * payload. + */ + off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (off == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, 0); + if (ret == 0) + ret = krb5_store_principal(sp, source); + if (ret == 0) { + errno = 0; + bytes = krb5_storage_write(sp, value.data, value.length); + if (bytes != (krb5_ssize_t)value.length) + ret = bytes == -1 ? errno : krb5_enomem(context->context); + } + if (ret == 0) { + end_off = krb5_storage_seek(sp, 0, SEEK_CUR); + if (end_off == -1) + ret = errno; + else if (end_off < off) + ret = KADM5_LOG_CORRUPT; + } + if (ret == 0) { + /* We wrote sizeof(uint32_t) + payload length bytes */ + len = (uint32_t)(end_off - off); + if (end_off - off != len || len < sizeof(len)) + ret = KADM5_LOG_CORRUPT; + else + len -= sizeof(len); + if (ret == 0 && krb5_storage_seek(sp, off, SEEK_SET) == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0 && krb5_storage_seek(sp, end_off, SEEK_SET) == -1) + ret = errno; + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0) + ret = kadm5_log_postamble(log_context, sp, + log_context->version + 1); + if (ret == 0) + ret = kadm5_log_flush(context, sp); + if (ret == 0) + ret = kadm5_log_recover(context, kadm_recover_commit); + } + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `rename' log operation from `sp' and apply it. + */ + +static kadm5_ret_t +kadm5_log_replay_rename(kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + krb5_error_code ret; + krb5_principal source; + hdb_entry target_ent; + krb5_data value; + off_t off; + size_t princ_len, data_len; + + memset(&target_ent, 0, sizeof(target_ent)); + + off = krb5_storage_seek(sp, 0, SEEK_CUR); + ret = krb5_ret_principal(sp, &source); + if (ret) { + krb5_set_error_message(context->context, ret, "Failed to read renamed " + "principal in log, version: %ld", (long)ver); + return ret; + } + princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; + data_len = len - princ_len; + ret = krb5_data_alloc(&value, data_len); + if (ret) { + krb5_free_principal (context->context, source); + return ret; + } + krb5_storage_read(sp, value.data, data_len); + ret = hdb_value2entry(context->context, &value, &target_ent); + krb5_data_free(&value); + if (ret) { + krb5_free_principal(context->context, source); + return ret; + } + ret = context->db->hdb_store(context->context, context->db, + 0, &target_ent); + hdb_free_entry(context->context, context->db, &target_ent); + if (ret) { + krb5_free_principal(context->context, source); + return ret; + } + ret = context->db->hdb_remove(context->context, context->db, 0, source); + krb5_free_principal(context->context, source); + + return ret; +} + +/* + * Add a `modify' operation to the log. + */ +kadm5_ret_t +kadm5_log_modify(kadm5_server_context *context, + hdb_entry *entry, + uint32_t mask) +{ + krb5_storage *sp; + krb5_ssize_t bytes; + kadm5_ret_t ret; + krb5_data value; + uint32_t len; + hdb_entry ent; + kadm5_log_context *log_context = &context->log_context; + + memset(&ent, 0, sizeof(ent)); + ent = *entry; + + if (strcmp(log_context->log_file, "/dev/null") == 0) + return context->db->hdb_store(context->context, context->db, + HDB_F_REPLACE, &ent); + + ret = context->db->hdb_store(context->context, context->db, + HDB_F_PRECHECK | HDB_F_REPLACE, &ent); + if (ret) + return ret; + + sp = krb5_storage_emem(); + krb5_data_zero(&value); + if (sp == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = hdb_entry2value(context->context, entry, &value); + if (ret) { + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; + } + + len = value.length + sizeof(len); + if (value.length > len || len > INT32_MAX) + ret = E2BIG; + if (ret == 0) + ret = kadm5_log_preamble(context, sp, kadm_modify, + log_context->version + 1); + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0) + ret = krb5_store_uint32(sp, mask); + if (ret == 0) { + bytes = krb5_storage_write(sp, value.data, value.length); + if (bytes != (krb5_ssize_t)value.length) + ret = bytes == -1 ? errno : krb5_enomem(context->context); + } + if (ret == 0) + ret = krb5_store_uint32(sp, len); + if (ret == 0) + ret = kadm5_log_postamble(log_context, sp, + log_context->version + 1); + if (ret == 0) + ret = kadm5_log_flush(context, sp); + if (ret == 0) + ret = kadm5_log_recover(context, kadm_recover_commit); + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `modify' log operation from `sp' and apply it. + */ +static kadm5_ret_t +kadm5_log_replay_modify(kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + krb5_error_code ret; + uint32_t mask; + krb5_data value; + hdb_entry ent, log_ent; + + memset(&log_ent, 0, sizeof(log_ent)); + + ret = krb5_ret_uint32(sp, &mask); + if (ret) + return ret; + len -= 4; + ret = krb5_data_alloc (&value, len); + if (ret) { + krb5_set_error_message(context->context, ret, "out of memory"); + return ret; + } + errno = 0; + if (krb5_storage_read (sp, value.data, len) != (krb5_ssize_t)len) { + ret = errno ? errno : EIO; + return ret; + } + ret = hdb_value2entry (context->context, &value, &log_ent); + krb5_data_free(&value); + if (ret) + return ret; + + memset(&ent, 0, sizeof(ent)); + /* NOTE: We do not use hdb_fetch_kvno() here */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, + log_ent.principal, + HDB_F_DECRYPT|HDB_F_ALL_KVNOS| + HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); + if (ret) + goto out; + if (mask & KADM5_PRINC_EXPIRE_TIME) { + if (log_ent.valid_end == NULL) { + ent.valid_end = NULL; + } else { + if (ent.valid_end == NULL) { + ent.valid_end = malloc(sizeof(*ent.valid_end)); + if (ent.valid_end == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + *ent.valid_end = *log_ent.valid_end; + } + } + if (mask & KADM5_PW_EXPIRATION) { + if (log_ent.pw_end == NULL) { + ent.pw_end = NULL; + } else { + if (ent.pw_end == NULL) { + ent.pw_end = malloc(sizeof(*ent.pw_end)); + if (ent.pw_end == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + *ent.pw_end = *log_ent.pw_end; + } + } + if (mask & KADM5_LAST_PWD_CHANGE) { + krb5_warnx (context->context, + "Unimplemented mask KADM5_LAST_PWD_CHANGE"); + } + if (mask & KADM5_ATTRIBUTES) { + ent.flags = log_ent.flags; + } + if (mask & KADM5_MAX_LIFE) { + if (log_ent.max_life == NULL) { + ent.max_life = NULL; + } else { + if (ent.max_life == NULL) { + ent.max_life = malloc (sizeof(*ent.max_life)); + if (ent.max_life == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + *ent.max_life = *log_ent.max_life; + } + } + if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { + if (ent.modified_by == NULL) { + ent.modified_by = malloc(sizeof(*ent.modified_by)); + if (ent.modified_by == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } else + free_Event(ent.modified_by); + ret = copy_Event(log_ent.modified_by, ent.modified_by); + if (ret) { + ret = krb5_enomem(context->context); + goto out; + } + } + if (mask & KADM5_KVNO) { + ent.kvno = log_ent.kvno; + } + if (mask & KADM5_MKVNO) { + krb5_warnx(context->context, "Unimplemented mask KADM5_KVNO"); + } + if (mask & KADM5_AUX_ATTRIBUTES) { + krb5_warnx(context->context, + "Unimplemented mask KADM5_AUX_ATTRIBUTES"); + } + if (mask & KADM5_POLICY_CLR) { + krb5_warnx(context->context, "Unimplemented mask KADM5_POLICY_CLR"); + } + if (mask & KADM5_MAX_RLIFE) { + if (log_ent.max_renew == NULL) { + ent.max_renew = NULL; + } else { + if (ent.max_renew == NULL) { + ent.max_renew = malloc (sizeof(*ent.max_renew)); + if (ent.max_renew == NULL) { + ret = krb5_enomem(context->context); + goto out; + } + } + *ent.max_renew = *log_ent.max_renew; + } + } + if (mask & KADM5_LAST_SUCCESS) { + krb5_warnx(context->context, "Unimplemented mask KADM5_LAST_SUCCESS"); + } + if (mask & KADM5_LAST_FAILED) { + krb5_warnx(context->context, "Unimplemented mask KADM5_LAST_FAILED"); + } + if (mask & KADM5_FAIL_AUTH_COUNT) { + krb5_warnx(context->context, + "Unimplemented mask KADM5_FAIL_AUTH_COUNT"); + } + if (mask & KADM5_KEY_DATA) { + size_t num; + size_t i; + + /* + * We don't need to do anything about key history here because + * the log entry contains a complete entry, including hdb + * extensions. We do need to make sure that KADM5_TL_DATA is in + * the mask though, since that's what it takes to update the + * extensions (see below). + */ + mask |= KADM5_TL_DATA; + + for (i = 0; i < ent.keys.len; ++i) + free_Key(&ent.keys.val[i]); + free (ent.keys.val); + + num = log_ent.keys.len; + + ent.keys.len = num; + ent.keys.val = malloc(len * sizeof(*ent.keys.val)); + if (ent.keys.val == NULL) { + krb5_enomem(context->context); + goto out; + } + for (i = 0; i < ent.keys.len; ++i) { + ret = copy_Key(&log_ent.keys.val[i], + &ent.keys.val[i]); + if (ret) { + krb5_set_error_message(context->context, ret, "out of memory"); + goto out; + } + } + } + if ((mask & KADM5_TL_DATA) && log_ent.etypes) { + if (ent.etypes) + free_HDB_EncTypeList(ent.etypes); + free(ent.etypes); + ent.etypes = calloc(1, sizeof(*ent.etypes)); + if (ent.etypes == NULL) + ret = ENOMEM; + if (ret == 0) + ret = copy_HDB_EncTypeList(log_ent.etypes, ent.etypes); + if (ret) { + ret = krb5_enomem(context->context); + free(ent.etypes); + ent.etypes = NULL; + goto out; + } + } + + if ((mask & KADM5_TL_DATA) && log_ent.extensions) { + if (ent.extensions) { + free_HDB_extensions(ent.extensions); + free(ent.extensions); + ent.extensions = NULL; + } + + ent.extensions = calloc(1, sizeof(*ent.extensions)); + if (ent.extensions == NULL) + ret = ENOMEM; + + if (ret == 0) + ret = copy_HDB_extensions(log_ent.extensions, + ent.extensions); + if (ret) { + ret = krb5_enomem(context->context); + free(ent.extensions); + ent.extensions = NULL; + goto out; + } + } + ret = context->db->hdb_store(context->context, context->db, + HDB_F_REPLACE, &ent); + out: + hdb_free_entry(context->context, context->db, &ent); + hdb_free_entry(context->context, context->db, &log_ent); + return ret; +} + +/* + * Update the first entry (which should be a `nop'), the "uber-entry". + */ +static kadm5_ret_t +log_update_uber(kadm5_server_context *context, off_t off) +{ + kadm5_log_context *log_context = &context->log_context; + kadm5_ret_t ret = 0; + krb5_storage *sp, *mem_sp; + krb5_data data; + uint32_t op, len; + ssize_t bytes; + + if (strcmp(log_context->log_file, "/dev/null") == 0) + return 0; + + if (log_context->read_only) + return EROFS; + + krb5_data_zero(&data); + + mem_sp = krb5_storage_emem(); + if (mem_sp == NULL) + return krb5_enomem(context->context); + + sp = krb5_storage_from_fd(log_context->log_fd); + if (sp == NULL) { + krb5_storage_free(mem_sp); + return krb5_enomem(context->context); + } + + /* Skip first entry's version and timestamp */ + if (krb5_storage_seek(sp, 8, SEEK_SET) == -1) { + ret = errno; + goto out; + } + + /* If the first entry is not a nop, there's nothing we can do here */ + ret = krb5_ret_uint32(sp, &op); + if (ret || op != kadm_nop) + goto out; + + /* If the first entry is not a 16-byte nop, ditto */ + ret = krb5_ret_uint32(sp, &len); + if (ret || len != LOG_UBER_LEN) + goto out; + + /* + * Try to make the writes here as close to atomic as possible: a + * single write() call. + */ + ret = krb5_store_uint64(mem_sp, off); + if (ret) + goto out; + ret = krb5_store_uint32(mem_sp, log_context->last_time); + if (ret) + goto out; + ret = krb5_store_uint32(mem_sp, log_context->version); + if (ret) + goto out; + + krb5_storage_to_data(mem_sp, &data); + bytes = krb5_storage_write(sp, data.data, data.length); + if (bytes < 0) + ret = errno; + else if (bytes != data.length) + ret = EIO; + + /* + * We don't fsync() this write because we can recover if the write + * doesn't complete, though for now we don't have code for properly + * dealing with the offset not getting written completely. + * + * We should probably have two copies of the offset so we can use + * one copy to verify the other, and when they don't match we could + * traverse the whole log forwards, replaying just the last entry. + */ + +out: + if (ret == 0) + kadm5_log_signal_master(context); + krb5_data_free(&data); + krb5_storage_free(sp); + krb5_storage_free(mem_sp); + if (lseek(log_context->log_fd, off, SEEK_SET) == -1) + ret = ret ? ret : errno; + + return ret; +} + +/* + * Add a `nop' operation to the log. Does not close the log. + */ +kadm5_ret_t +kadm5_log_nop(kadm5_server_context *context, enum kadm_nop_type nop_type) +{ + krb5_storage *sp; + kadm5_ret_t ret; + kadm5_log_context *log_context = &context->log_context; + off_t off; + uint32_t vno = log_context->version; + + if (strcmp(log_context->log_file, "/dev/null") == 0) + return 0; + + off = lseek(log_context->log_fd, 0, SEEK_CUR); + if (off == -1) + return errno; + + sp = krb5_storage_emem(); + if (sp == NULL) + return krb5_enomem(context->context); + + ret = kadm5_log_preamble(context, sp, kadm_nop, off == 0 ? 0 : vno + 1); + if (ret) + goto out; + + if (off == 0) { + /* + * First entry (uber-entry) gets room for offset of next new + * entry and time and version of last entry. + */ + ret = krb5_store_uint32(sp, LOG_UBER_LEN); + /* These get overwritten with the same values below */ + if (ret == 0) + ret = krb5_store_uint64(sp, LOG_UBER_SZ); + if (ret == 0) + ret = krb5_store_uint32(sp, log_context->last_time); + if (ret == 0) + ret = krb5_store_uint32(sp, vno); + if (ret == 0) + ret = krb5_store_uint32(sp, LOG_UBER_LEN); + } else if (nop_type == kadm_nop_plain) { + ret = krb5_store_uint32(sp, 0); + if (ret == 0) + ret = krb5_store_uint32(sp, 0); + } else { + ret = krb5_store_uint32(sp, sizeof(uint32_t)); + if (ret == 0) + ret = krb5_store_uint32(sp, nop_type); + if (ret == 0) + ret = krb5_store_uint32(sp, sizeof(uint32_t)); + } + + if (ret == 0) + ret = kadm5_log_postamble(log_context, sp, off == 0 ? 0 : vno + 1); + if (ret == 0) + ret = kadm5_log_flush(context, sp); + + if (ret == 0 && off == 0 && nop_type != kadm_nop_plain) + ret = kadm5_log_nop(context, nop_type); + + if (ret == 0 && off != 0) + ret = kadm5_log_recover(context, kadm_recover_commit); + +out: + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `nop' log operation from `sp' and "apply" it (there's nothing + * to do). + * + * FIXME Actually, if the nop payload is 4 bytes and contains an enum + * kadm_nop_type value of kadm_nop_trunc then we should truncate the + * log, and if it contains a kadm_nop_close then we should rename a new + * log into place. However, this is not implemented yet. + */ +static kadm5_ret_t +kadm5_log_replay_nop(kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + return 0; +} + +struct replay_cb_data { + size_t count; + uint32_t ver; + enum kadm_recover_mode mode; +}; + + +/* + * Recover or perform the initial commit of an unconfirmed log entry + */ +static kadm5_ret_t +recover_replay(kadm5_server_context *context, + uint32_t ver, time_t timestamp, enum kadm_ops op, + uint32_t len, krb5_storage *sp, void *ctx) +{ + struct replay_cb_data *data = ctx; + kadm5_ret_t ret; + off_t off; + + /* On initial commit there must be just one pending unconfirmed entry */ + if (data->count > 0 && data->mode == kadm_recover_commit) + return KADM5_LOG_CORRUPT; + + /* We're at the start of the payload; compute end of entry offset */ + off = krb5_storage_seek(sp, 0, SEEK_CUR) + len + LOG_TRAILER_SZ; + + /* We cannot perform log recovery on LDAP and such backends */ + if (data->mode == kadm_recover_replay && + (context->db->hdb_capability_flags & HDB_CAP_F_SHARED_DIRECTORY)) + ret = 0; + else + ret = kadm5_log_replay(context, op, ver, len, sp); + switch (ret) { + case HDB_ERR_NOENTRY: + case HDB_ERR_EXISTS: + if (data->mode != kadm_recover_replay) + return ret; + case 0: + break; + case KADM5_LOG_CORRUPT: + return -1; + default: + krb5_warn(context->context, ret, "unexpected error while replaying"); + return -1; + } + data->count++; + data->ver = ver; + + /* + * With replay we may be making multiple HDB changes. We must sync the + * confirmation of each one before moving on to the next. Otherwise, we + * might attempt to replay multiple already applied updates, and this may + * introduce unintended intermediate states or fail to yield the same final + * result. + */ + kadm5_log_set_version(context, ver); + ret = log_update_uber(context, off); + if (ret == 0 && data->mode != kadm_recover_commit) + ret = krb5_storage_fsync(sp); + return ret; +} + + +kadm5_ret_t +kadm5_log_recover(kadm5_server_context *context, enum kadm_recover_mode mode) +{ + kadm5_ret_t ret; + krb5_storage *sp; + struct replay_cb_data replay_data; + + replay_data.count = 0; + replay_data.ver = 0; + replay_data.mode = mode; + + sp = krb5_storage_from_fd(context->log_context.log_fd); + if (sp == NULL) + return errno ? errno : EIO; + ret = kadm5_log_goto_end(context, sp); + + if (ret == 0) + ret = kadm5_log_foreach(context, kadm_forward | kadm_unconfirmed, + NULL, recover_replay, &replay_data); + if (ret == 0 && mode == kadm_recover_commit && replay_data.count != 1) + ret = KADM5_LOG_CORRUPT; + krb5_storage_free(sp); + return ret; +} + +/* + * Call `func' for each log record in the log in `context'. + * + * `func' is optional. + * + * If `func' returns -1 then log traversal terminates and this returns 0. + * Otherwise `func''s return is returned if there are no other errors. + */ +kadm5_ret_t +kadm5_log_foreach(kadm5_server_context *context, + enum kadm_iter_opts iter_opts, + off_t *off_lastp, + kadm5_ret_t (*func)(kadm5_server_context *server_context, + uint32_t ver, time_t timestamp, + enum kadm_ops op, uint32_t len, + krb5_storage *sp, void *ctx), + void *ctx) +{ + kadm5_ret_t ret = 0; + int fd = context->log_context.log_fd; + krb5_storage *sp; + off_t off_last; + off_t this_entry = 0; + off_t log_end = 0; + + if (strcmp(context->log_context.log_file, "/dev/null") == 0) + return 0; + + if (off_lastp == NULL) + off_lastp = &off_last; + *off_lastp = -1; + + if (((iter_opts & kadm_forward) && (iter_opts & kadm_backward)) || + (!(iter_opts & kadm_confirmed) && !(iter_opts & kadm_unconfirmed))) + return EINVAL; + + if ((iter_opts & kadm_forward) && (iter_opts & kadm_confirmed) && + (iter_opts & kadm_unconfirmed)) { + /* + * We want to traverse all log entries, confirmed or not, from + * the start, then there's no need to kadm5_log_goto_end() + * -- no reason to try to find the end. + */ + sp = krb5_storage_from_fd(fd); + if (sp == NULL) + return errno ? errno : ENOMEM; + + log_end = krb5_storage_seek(sp, 0, SEEK_END); + if (log_end == -1 || + krb5_storage_seek(sp, 0, SEEK_SET) == -1) { + ret = errno; + krb5_storage_free(sp); + return ret; + } + } else { + /* Get the end of the log based on the uber entry */ + sp = krb5_storage_from_fd(fd); + if (sp == NULL) + return errno ? errno : ENOMEM; + ret = kadm5_log_goto_end(context, sp); + if (ret != 0) + return ret; + log_end = krb5_storage_seek(sp, 0, SEEK_CUR); + } + + *off_lastp = log_end; + + if ((iter_opts & kadm_forward) && (iter_opts & kadm_confirmed)) { + /* Start at the beginning */ + if (krb5_storage_seek(sp, 0, SEEK_SET) == -1) { + ret = errno; + krb5_storage_free(sp); + return ret; + } + } else if ((iter_opts & kadm_backward) && (iter_opts & kadm_unconfirmed)) { + /* + * We're at the confirmed end but need to be at the unconfirmed + * end. Skip forward to the real end, re-entering to do it. + */ + ret = kadm5_log_foreach(context, kadm_forward | kadm_unconfirmed, + &log_end, NULL, NULL); + if (ret) + return ret; + if (krb5_storage_seek(sp, log_end, SEEK_SET) == -1) { + ret = errno; + krb5_storage_free(sp); + return ret; + } + } + + for (;;) { + uint32_t ver, ver2, len, len2; + uint32_t tstamp; + time_t timestamp; + enum kadm_ops op; + + if ((iter_opts & kadm_backward)) { + off_t o; + + o = krb5_storage_seek(sp, 0, SEEK_CUR); + if (o == 0 || + ((iter_opts & kadm_unconfirmed) && o <= *off_lastp)) + break; + ret = kadm5_log_previous(context->context, sp, &ver, + ×tamp, &op, &len); + if (ret) + break; + + /* Offset is now at payload of current entry */ + + o = krb5_storage_seek(sp, 0, SEEK_CUR); + if (o == -1) { + ret = errno; + break; + } + this_entry = o - LOG_HEADER_SZ; + if (this_entry < 0) { + ret = KADM5_LOG_CORRUPT; + break; + } + } else { + /* Offset is now at start of current entry, read header */ + this_entry = krb5_storage_seek(sp, 0, SEEK_CUR); + if (!(iter_opts & kadm_unconfirmed) && this_entry == log_end) + break; + ret = get_header(sp, LOG_NOPEEK, &ver, &tstamp, &op, &len); + if (ret == HEIM_ERR_EOF) { + ret = 0; + break; + } + timestamp = tstamp; + if (ret) + break; + /* Offset is now at payload of current entry */ + } + + /* Validate trailer before calling the callback */ + if (krb5_storage_seek(sp, len, SEEK_CUR) == -1) { + ret = errno; + break; + } + + ret = krb5_ret_uint32(sp, &len2); + if (ret) + break; + ret = krb5_ret_uint32(sp, &ver2); + if (ret) + break; + if (len != len2 || ver != ver2) { + ret = KADM5_LOG_CORRUPT; + break; + } + + /* Rewind to start of payload and call callback if we have one */ + if (krb5_storage_seek(sp, this_entry + LOG_HEADER_SZ, + SEEK_SET) == -1) { + ret = errno; + break; + } + + if (func != NULL) { + ret = (*func)(context, ver, timestamp, op, len, sp, ctx); + if (ret) { + /* Callback signals desire to stop by returning -1 */ + if (ret == -1) + ret = 0; + break; + } + } + if ((iter_opts & kadm_forward)) { + off_t o; + + o = krb5_storage_seek(sp, this_entry+LOG_WRAPPER_SZ+len, SEEK_SET); + if (o == -1) { + ret = errno; + break; + } + if (o > log_end) + *off_lastp = o; + } else if ((iter_opts & kadm_backward)) { + /* + * Rewind to the start of this entry so kadm5_log_previous() + * can find the previous one. + */ + if (krb5_storage_seek(sp, this_entry, SEEK_SET) == -1) { + ret = errno; + break; + } + } + } + if ((ret == HEIM_ERR_EOF || ret == KADM5_LOG_CORRUPT) && + (iter_opts & kadm_forward) && + context->log_context.lock_mode == LOCK_EX) { + /* + * Truncate partially written last log entry so we can write + * again. + */ + ret = krb5_storage_truncate(sp, this_entry); + if (ret == 0 && + krb5_storage_seek(sp, this_entry, SEEK_SET) == -1) + ret = errno; + krb5_warnx(context->context, "Truncating log at partial or " + "corrupt %s entry", + this_entry > log_end ? "unconfirmed" : "confirmed"); + } + krb5_storage_free(sp); + return ret; +} + +/* + * Go to the first record, which, if we have an uber record, will be + * the second record. + */ +kadm5_ret_t +kadm5_log_goto_first(kadm5_server_context *server_context, krb5_storage *sp) +{ + enum kadm_ops op; + uint32_t ver, len; + kadm5_ret_t ret; + + if (krb5_storage_seek(sp, 0, SEEK_SET) == -1) + return KADM5_LOG_CORRUPT; + + ret = get_header(sp, LOG_DOPEEK, &ver, NULL, &op, &len); + if (ret) + return ret; + if (op == kadm_nop && len == LOG_UBER_LEN && seek_next(sp) == -1) + return KADM5_LOG_CORRUPT; + return 0; +} + +/* + * Go to end of log. + */ +kadm5_ret_t +kadm5_log_goto_end(kadm5_server_context *server_context, krb5_storage *sp) +{ + krb5_error_code ret = 0; + enum kadm_ops op; + uint32_t ver, len; + uint32_t tstamp; + uint64_t off; + + if (krb5_storage_seek(sp, 0, SEEK_SET) == -1) + return errno; + ret = get_header(sp, LOG_NOPEEK, &ver, &tstamp, &op, &len); + if (ret == HEIM_ERR_EOF) { + (void) krb5_storage_seek(sp, 0, SEEK_SET); + return 0; + } + if (ret == KADM5_LOG_CORRUPT) + goto truncate; + if (ret) + return ret; + + if (op == kadm_nop && len == LOG_UBER_LEN) { + /* New style log */ + ret = krb5_ret_uint64(sp, &off); + if (ret) + goto truncate; + + if (krb5_storage_seek(sp, off, SEEK_SET) == -1) + return ret; + + if (off >= LOG_UBER_SZ) { + ret = get_version_prev(sp, &ver, NULL); + if (ret == 0) + return 0; + } + /* Invalid offset in uber entry */ + goto truncate; + } + + /* Old log with no uber entry */ + if (krb5_storage_seek(sp, 0, SEEK_END) == -1) { + static int warned = 0; + if (!warned) { + warned = 1; + krb5_warnx(server_context->context, + "Old log found; truncate it to upgrade"); + } + } + ret = get_version_prev(sp, &ver, NULL); + if (ret) + goto truncate; + return 0; + +truncate: + /* If we can, truncate */ + if (server_context->log_context.lock_mode == LOCK_EX) { + ret = kadm5_log_reinit(server_context, 0); + if (ret == 0) { + krb5_warn(server_context->context, ret, + "Invalid log; truncating to recover"); + if (krb5_storage_seek(sp, 0, SEEK_END) >= 0) + return 0; + } + } + ret = KADM5_LOG_CORRUPT; + krb5_warn(server_context->context, ret, + "Invalid log; truncate to recover"); + return ret; +} + +/* + * Return the next log entry. + * + * The pointer in `sp' is assumed to be at the end of an entry. On success, + * the `sp' pointer is set to the next entry (not the data portion). In case + * of error, it's not changed at all. + */ +kadm5_ret_t +kadm5_log_next(krb5_context context, + krb5_storage *sp, + uint32_t *verp, + time_t *tstampp, + enum kadm_ops *opp, + uint32_t *lenp) +{ + uint32_t len = 0; + uint32_t len2 = 0; + uint32_t ver = verp ? *verp : 0; + uint32_t ver2; + uint32_t tstamp = tstampp ? *tstampp : 0; + enum kadm_ops op = kadm_nop; + off_t off = krb5_storage_seek(sp, 0, SEEK_CUR); + kadm5_ret_t ret = get_header(sp, LOG_NOPEEK, &ver, &tstamp, &op, &len); + + /* Validate the trailer */ + if (ret == 0 && krb5_storage_seek(sp, len, SEEK_CUR) == -1) + ret = errno; + + if (ret == 0) + ret = krb5_ret_uint32(sp, &len2); + if (ret == 0) + ret = krb5_ret_uint32(sp, &ver2); + if (ret == 0 && (len != len2 || ver != ver2)) + ret = KADM5_LOG_CORRUPT; + if (ret != 0) { + (void) krb5_storage_seek(sp, off, SEEK_SET); + return ret; + } + + if (verp) + *verp = ver; + if (tstampp) + *tstampp = tstamp; + if (opp) + *opp = op; + if (lenp) + *lenp = len; + return 0; +} + +/* + * Return previous log entry. + * + * The pointer in `sp' is assumed to be at the top of the entry after + * previous entry (e.g., at EOF). On success, the `sp' pointer is set to + * data portion of previous entry. In case of error, it's not changed + * at all. + */ +kadm5_ret_t +kadm5_log_previous(krb5_context context, + krb5_storage *sp, + uint32_t *verp, + time_t *tstampp, + enum kadm_ops *opp, + uint32_t *lenp) +{ + krb5_error_code ret; + off_t oldoff; + uint32_t ver2, len2; + uint32_t tstamp; + + oldoff = krb5_storage_seek(sp, 0, SEEK_CUR); + if (oldoff == -1) + goto log_corrupt; + + /* This reads the physical version of the uber record */ + if (seek_prev(sp, verp, lenp) == -1) + goto log_corrupt; + + ret = get_header(sp, LOG_NOPEEK, &ver2, &tstamp, opp, &len2); + if (ret) { + (void) krb5_storage_seek(sp, oldoff, SEEK_SET); + return ret; + } + if (tstampp) + *tstampp = tstamp; + if (ver2 != *verp || len2 != *lenp) + goto log_corrupt; + + return 0; + +log_corrupt: + (void) krb5_storage_seek(sp, oldoff, SEEK_SET); + return KADM5_LOG_CORRUPT; +} + +/* + * Replay a record from the log + */ + +kadm5_ret_t +kadm5_log_replay(kadm5_server_context *context, + enum kadm_ops op, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + switch (op) { + case kadm_create : + return kadm5_log_replay_create(context, ver, len, sp); + case kadm_delete : + return kadm5_log_replay_delete(context, ver, len, sp); + case kadm_rename : + return kadm5_log_replay_rename(context, ver, len, sp); + case kadm_modify : + return kadm5_log_replay_modify(context, ver, len, sp); + case kadm_nop : + return kadm5_log_replay_nop(context, ver, len, sp); + default : + /* + * FIXME This default arm makes it difficult to add new kadm_ops + * values. + */ + krb5_set_error_message(context->context, KADM5_FAILURE, + "Unsupported replay op %d", (int)op); + (void) krb5_storage_seek(sp, len, SEEK_CUR); + return KADM5_FAILURE; + } +} + +struct load_entries_data { + krb5_data *entries; + unsigned char *p; + uint32_t first; + uint32_t last; + size_t bytes; + size_t nentries; + size_t maxbytes; + size_t maxentries; +}; + + +/* + * Prepend one entry with header and trailer to the entry buffer, stopping when + * we've reached either of the byte or entry-count limits (if non-zero). + * + * This is a two-pass algorithm: + * + * In the first pass, when entries->entries == NULL, we compute the space + * required, and count the entries that fit up from zero. + * + * In the second pass we fill the buffer, and count the entries back down to + * zero. The space used must be an exact fit, and the number of entries must + * reach zero at that point or an error is returned. + * + * The caller MUST check that entries->nentries == 0 at the end of the second + * pass. + */ +static kadm5_ret_t +load_entries_cb(kadm5_server_context *server_context, + uint32_t ver, + time_t timestamp, + enum kadm_ops op, + uint32_t len, + krb5_storage *sp, + void *ctx) +{ + struct load_entries_data *entries = ctx; + kadm5_ret_t ret; + ssize_t bytes; + size_t entry_len = len + LOG_WRAPPER_SZ; + unsigned char *base; + + if (entries->entries == NULL) { + size_t total = entries->bytes + entry_len; + + /* + * First run: find the size of krb5_data buffer needed. + * + * If the log was huge we'd have to perhaps open a temp file for this. + * For now KISS. + */ + if ((op == kadm_nop && entry_len == LOG_UBER_SZ) || + entry_len < len /*overflow?*/ || + (entries->maxbytes > 0 && total > entries->maxbytes) || + total < entries->bytes /*overflow?*/ || + (entries->maxentries > 0 && entries->nentries == entries->maxentries)) + return -1; /* stop iteration */ + entries->bytes = total; + entries->first = ver; + if (entries->nentries++ == 0) + entries->last = ver; + return 0; + } + + /* Second run: load the data into memory */ + base = (unsigned char *)entries->entries->data; + if (entries->p - base < entry_len && entries->p != base) { + /* + * This can't happen normally: we stop the log record iteration + * above before we get here. This could happen if someone wrote + * garbage to the log while we were traversing it. We return an + * error instead of asserting. + */ + return KADM5_LOG_CORRUPT; + } + + /* + * sp here is a krb5_storage_from_fd() of the log file, and the + * offset pointer points at the current log record payload. + * + * Seek back to the start of the record poayload so we can read the + * whole record. + */ + if (krb5_storage_seek(sp, -LOG_HEADER_SZ, SEEK_CUR) == -1) + return errno; + + /* + * We read the header, payload, and trailer into the buffer we have, that + * many bytes before the previous record we read. + */ + errno = 0; + bytes = krb5_storage_read(sp, entries->p - entry_len, entry_len); + ret = errno; + if (bytes < 0 || bytes != entry_len) + return ret ? ret : EIO; + + entries->first = ver; + --entries->nentries; + entries->p -= entry_len; + return (entries->p == base) ? -1 : 0; +} + + +/* + * Serialize a tail fragment of the log as a krb5_data, this is constrained to + * at most `maxbytes' bytes and to at most `maxentries' entries if not zero. + */ +static kadm5_ret_t +load_entries(kadm5_server_context *context, krb5_data *p, + size_t maxentries, size_t maxbytes, + uint32_t *first, uint32_t *last) +{ + struct load_entries_data entries; + kadm5_ret_t ret; + unsigned char *base; + + krb5_data_zero(p); + + *first = 0; + + memset(&entries, 0, sizeof(entries)); + entries.entries = NULL; + entries.p = NULL; + entries.maxentries = maxentries; + entries.maxbytes = maxbytes; + + /* Figure out how many bytes it will take */ + ret = kadm5_log_foreach(context, kadm_backward | kadm_confirmed, + NULL, load_entries_cb, &entries); + if (ret) + return ret; + + /* + * If no entries fit our limits, we do not truncate, instead the caller can + * call kadm5_log_reinit() if desired. + */ + if (entries.bytes == 0) + return 0; + + ret = krb5_data_alloc(p, entries.bytes); + if (ret) + return ret; + + *first = entries.first; + *last = entries.last; + entries.entries = p; + base = (unsigned char *)entries.entries->data; + entries.p = base + entries.bytes; + + ret = kadm5_log_foreach(context, kadm_backward | kadm_confirmed, + NULL, load_entries_cb, &entries); + if (ret == 0 && + (entries.nentries || entries.p != base || entries.first != *first)) + ret = KADM5_LOG_CORRUPT; + if (ret) + krb5_data_free(p); + return ret; +} + +/* + * Truncate the log, retaining at most `keep' entries and at most `maxbytes'. + * If `maxbytes' is zero, keep at most the default log size limit. + */ +kadm5_ret_t +kadm5_log_truncate(kadm5_server_context *context, size_t keep, size_t maxbytes) +{ + kadm5_ret_t ret; + uint32_t first, last, last_tstamp; + time_t now = time(NULL); + krb5_data entries; + krb5_storage *sp; + ssize_t bytes; + uint64_t sz; + off_t off; + + if (maxbytes == 0) + maxbytes = get_max_log_size(context->context); + + if (strcmp(context->log_context.log_file, "/dev/null") == 0) + return 0; + + if (context->log_context.read_only) + return EROFS; + + /* Get the desired records. */ + krb5_data_zero(&entries); + ret = load_entries(context, &entries, keep, maxbytes, &first, &last); + if (ret) + return ret; + + if (first == 0) { + /* + * No records found/fit within resource limits. The caller should call + * kadm5_log_reinit(context) to truly truncate and reset the log to + * version 0, else call again with better limits. + */ + krb5_data_free(&entries); + return EINVAL; + } + + /* Check that entries.length won't overflow off_t */ + sz = LOG_UBER_SZ + entries.length; + off = (off_t)sz; + if (off < 0 || off != sz || sz < entries.length) { + krb5_data_free(&entries); + return EOVERFLOW; /* caller should ask for fewer entries */ + } + + /* Truncate to zero size and seek to zero offset */ + if (ftruncate(context->log_context.log_fd, 0) < 0 || + lseek(context->log_context.log_fd, 0, SEEK_SET) < 0) { + krb5_data_free(&entries); + return errno; + } + + /* + * Write the uber record and then the records loaded. Confirm the entries + * after writing them. + * + * If we crash then the log may not have all the entries we want, and + * replaying only some of the entries will leave us in a bad state. + * Additionally, we don't have mathematical proof that replaying the last + * N>1 entries is always idempotent. And though we believe we can make + * such replays idempotent, they would still leave the HDB with + * intermediate states that would not have occurred on the master. + * + * By initially setting the offset in the uber record to 0, the log will be + * seen as invalid should we crash here, thus the only + * harm will be that we'll reinitialize the log and force full props. + * + * We can't use the normal kadm5_log_*() machinery for this because + * we must set specific version numbers and timestamps. To keep + * things simple we don't try to do a single atomic write here as we + * do in kadm5_log_flush(). + * + * We really do want to keep the new first entry's version and + * timestamp so we don't trip up iprop. + * + * Keep this in sync with kadm5_log_nop(). + */ + sp = krb5_storage_from_fd(context->log_context.log_fd); + if (sp == NULL) { + ret = errno; + krb5_warn(context->context, ret, "Unable to keep entries"); + krb5_data_free(&entries); + return errno; + } + ret = krb5_store_uint32(sp, 0); + if (ret == 0) + ret = krb5_store_uint32(sp, now); + if (ret == 0) + ret = krb5_store_uint32(sp, kadm_nop); /* end of preamble */ + if (ret == 0) + ret = krb5_store_uint32(sp, LOG_UBER_LEN); /* end of header */ + if (ret == 0) + ret = krb5_store_uint64(sp, LOG_UBER_SZ); + if (ret == 0) + ret = krb5_store_uint32(sp, now); + if (ret == 0) + ret = krb5_store_uint32(sp, last); + if (ret == 0) + ret = krb5_store_uint32(sp, LOG_UBER_LEN); + if (ret == 0) + ret = krb5_store_uint32(sp, 0); /* end of trailer */ + if (ret == 0) { + bytes = krb5_storage_write(sp, entries.data, entries.length); + if (bytes != entries.length) + ret = bytes == -1 ? errno : EIO; + } + if (ret == 0) + ret = krb5_storage_fsync(sp); + /* Confirm all the records now */ + if (ret == 0) { + if (krb5_storage_seek(sp, LOG_HEADER_SZ, SEEK_SET) == -1) + ret = errno; + } + if (ret == 0) + ret = krb5_store_uint64(sp, off); + krb5_data_free(&entries); + krb5_storage_free(sp); + + if (ret) { + krb5_warn(context->context, ret, "Unable to keep entries"); + (void) ftruncate(context->log_context.log_fd, LOG_UBER_SZ); + (void) lseek(context->log_context.log_fd, 0, SEEK_SET); + return ret; + } + + /* Done. Now rebuild the log_context state. */ + (void) lseek(context->log_context.log_fd, off, SEEK_SET); + sp = krb5_storage_from_fd(context->log_context.log_fd); + if (sp == NULL) + return errno ? errno : krb5_enomem(context->context); + ret = kadm5_log_goto_end(context, sp); + if (ret == 0) { + ret = get_version_prev(sp, &context->log_context.version, &last_tstamp); + if (ret == 0) + context->log_context.last_time = last_tstamp; + } + krb5_storage_free(sp); + return ret; +} + +/* + * "Truncate" the log if not read only and over the desired maximum size. We + * attempt to retain 1/4 of the existing storage. + * + * Called after successful log recovery, so at this point we must have no + * unconfirmed entries in the log. + */ +static kadm5_ret_t +truncate_if_needed(kadm5_server_context *context) +{ + kadm5_ret_t ret = 0; + kadm5_log_context *log_context = &context->log_context; + size_t maxbytes; + struct stat st; + + if (log_context->log_fd == -1 || log_context->read_only) + return 0; + if (strcmp(context->log_context.log_file, "/dev/null") == 0) + return 0; + + maxbytes = get_max_log_size(context->context); + if (maxbytes <= 0) + return 0; + + if (fstat(log_context->log_fd, &st) == -1) + return errno; + if (st.st_size == (size_t)st.st_size && (size_t)st.st_size <= maxbytes) + return 0; + + /* Shrink the log by a factor of 4 */ + ret = kadm5_log_truncate(context, 0, maxbytes/4); + return ret == EINVAL ? 0 : ret; +} + +#ifndef NO_UNIX_SOCKETS + +static char *default_signal = NULL; +static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER; + +const char * +kadm5_log_signal_socket(krb5_context context) +{ + int ret = 0; + + HEIMDAL_MUTEX_lock(&signal_mutex); + if (!default_signal) + ret = asprintf(&default_signal, "%s/signal", hdb_db_dir(context)); + if (ret == -1) + default_signal = NULL; + HEIMDAL_MUTEX_unlock(&signal_mutex); + + return krb5_config_get_string_default(context, + NULL, + default_signal, + "kdc", + "signal_socket", + NULL); +} + +#else /* NO_UNIX_SOCKETS */ + +#define SIGNAL_SOCKET_HOST "127.0.0.1" +#define SIGNAL_SOCKET_PORT "12701" + +kadm5_ret_t +kadm5_log_signal_socket_info(krb5_context context, + int server_end, + struct addrinfo **ret_addrs) +{ + struct addrinfo hints; + struct addrinfo *addrs = NULL; + kadm5_ret_t ret = KADM5_FAILURE; + int wsret; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_NUMERICHOST; + if (server_end) + hints.ai_flags |= AI_PASSIVE; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + wsret = getaddrinfo(SIGNAL_SOCKET_HOST, + SIGNAL_SOCKET_PORT, + &hints, &addrs); + + if (wsret != 0) { + krb5_set_error_message(context, KADM5_FAILURE, + "%s", gai_strerror(wsret)); + goto done; + } + + if (addrs == NULL) { + krb5_set_error_message(context, KADM5_FAILURE, + "getaddrinfo() failed to return address list"); + goto done; + } + + *ret_addrs = addrs; + addrs = NULL; + ret = 0; + + done: + if (addrs) + freeaddrinfo(addrs); + return ret; +} + +#endif diff --git a/third_party/heimdal/lib/kadm5/marshall.c b/third_party/heimdal/lib/kadm5/marshall.c new file mode 100644 index 0000000..849698f --- /dev/null +++ b/third_party/heimdal/lib/kadm5/marshall.c @@ -0,0 +1,962 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +#define CHECK(e) do { if ((ret = e)) goto out; } while (0) + +int +kadm5_some_keys_are_bogus(size_t n_keys, krb5_key_data *keys) +{ + size_t i; + + for (i = 0; i < n_keys; i++) { + krb5_key_data *key = &keys[i]; + if (key->key_data_length[0] == sizeof(KADM5_BOGUS_KEY_DATA) - 1 && + ct_memcmp(key->key_data_contents[1], KADM5_BOGUS_KEY_DATA, + key->key_data_length[0]) == 0) + return 1; + } + return 0; +} + +int +kadm5_all_keys_are_bogus(size_t n_keys, krb5_key_data *keys) +{ + size_t i; + + if (n_keys == 0) + return 0; + + for (i = 0; i < n_keys; i++) { + krb5_key_data *key = &keys[i]; + if (key->key_data_length[0] != sizeof(KADM5_BOGUS_KEY_DATA) - 1 || + ct_memcmp(key->key_data_contents[1], KADM5_BOGUS_KEY_DATA, + key->key_data_length[0]) != 0) + return 0; + } + return 1; +} + +kadm5_ret_t +kadm5_store_key_data(krb5_storage *sp, + krb5_key_data *key) +{ + kadm5_ret_t ret; + krb5_data c; + + CHECK(krb5_store_int32(sp, key->key_data_ver)); + CHECK(krb5_store_int32(sp, key->key_data_kvno)); + CHECK(krb5_store_int32(sp, key->key_data_type[0])); + c.length = key->key_data_length[0]; + c.data = key->key_data_contents[0]; + CHECK(krb5_store_data(sp, c)); + CHECK(krb5_store_int32(sp, key->key_data_type[1])); + c.length = key->key_data_length[1]; + c.data = key->key_data_contents[1]; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; +} + +kadm5_ret_t +kadm5_store_fake_key_data(krb5_storage *sp, + krb5_key_data *key) +{ + kadm5_ret_t ret; + krb5_data c; + + CHECK(krb5_store_int32(sp, key->key_data_ver)); + CHECK(krb5_store_int32(sp, key->key_data_kvno)); + CHECK(krb5_store_int32(sp, key->key_data_type[0])); + + /* + * This is the key contents. We want it to be obvious to the client + * (if it really did want the keys) that the key won't work. + * 32-bit keys are no good for any enctype, so that should do. + * Clients that didn't need keys will ignore this, and clients that + * did want keys will either fail or they'll, say, create bogus + * keytab entries that will subsequently fail to be useful. + */ + c.length = sizeof (KADM5_BOGUS_KEY_DATA) - 1; + c.data = KADM5_BOGUS_KEY_DATA; + CHECK(krb5_store_data(sp, c)); + + /* This is the salt -- no need to send garbage */ + CHECK(krb5_store_int32(sp, key->key_data_type[1])); + c.length = key->key_data_length[1]; + c.data = key->key_data_contents[1]; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; +} + +kadm5_ret_t +kadm5_ret_key_data(krb5_storage *sp, + krb5_key_data *key) +{ + kadm5_ret_t ret; + krb5_data c; + int32_t tmp; + + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) { + key->key_data_ver = tmp; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_kvno = tmp; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_type[0] = tmp; + ret = krb5_ret_data(sp, &c); + } + if (ret == 0) { + key->key_data_length[0] = c.length; + key->key_data_contents[0] = c.data; + ret = krb5_ret_int32(sp, &tmp); + } + if (ret == 0) { + key->key_data_type[1] = tmp; + ret = krb5_ret_data(sp, &c); + } + if (ret == 0) { + key->key_data_length[1] = c.length; + key->key_data_contents[1] = c.data; + return 0; + } + return KADM5_FAILURE; +} + +kadm5_ret_t +kadm5_store_tl_data(krb5_storage *sp, + krb5_tl_data *tl) +{ + kadm5_ret_t ret; + krb5_data c; + + CHECK(krb5_store_int32(sp, tl->tl_data_type)); + c.length = tl->tl_data_length; + c.data = tl->tl_data_contents; + CHECK(krb5_store_data(sp, c)); + +out: + return ret; +} + +kadm5_ret_t +kadm5_ret_tl_data(krb5_storage *sp, + krb5_tl_data *tl) +{ + kadm5_ret_t ret; + krb5_data c; + int32_t tmp; + + CHECK(krb5_ret_int32(sp, &tmp)); + tl->tl_data_type = tmp; + CHECK(krb5_ret_data(sp, &c)); + tl->tl_data_length = c.length; + tl->tl_data_contents = c.data; + +out: + return ret; +} + +static kadm5_ret_t +store_principal_ent(krb5_storage *sp, + kadm5_principal_ent_t princ, + uint32_t mask, int wkeys) +{ + kadm5_ret_t ret = 0; + int i; + + if (mask & KADM5_PRINCIPAL) + CHECK(krb5_store_principal(sp, princ->principal)); + if (mask & KADM5_PRINC_EXPIRE_TIME) + CHECK(krb5_store_int32(sp, princ->princ_expire_time)); + if (mask & KADM5_PW_EXPIRATION) + CHECK(krb5_store_int32(sp, princ->pw_expiration)); + if (mask & KADM5_LAST_PWD_CHANGE) + CHECK(krb5_store_int32(sp, princ->last_pwd_change)); + if (mask & KADM5_MAX_LIFE) + CHECK(krb5_store_int32(sp, princ->max_life)); + if (mask & KADM5_MOD_NAME) { + CHECK(krb5_store_int32(sp, princ->mod_name != NULL)); + if(princ->mod_name) + CHECK(krb5_store_principal(sp, princ->mod_name)); + } + if (mask & KADM5_MOD_TIME) + CHECK(krb5_store_int32(sp, princ->mod_date)); + if (mask & KADM5_ATTRIBUTES) + CHECK(krb5_store_int32(sp, princ->attributes)); + if (mask & KADM5_KVNO) + CHECK(krb5_store_int32(sp, princ->kvno)); + if (mask & KADM5_MKVNO) + CHECK(krb5_store_int32(sp, princ->mkvno)); + if (mask & KADM5_POLICY) { + CHECK(krb5_store_int32(sp, princ->policy != NULL)); + if(princ->policy) + CHECK(krb5_store_string(sp, princ->policy)); + } + if (mask & KADM5_AUX_ATTRIBUTES) + CHECK(krb5_store_int32(sp, princ->aux_attributes)); + if (mask & KADM5_MAX_RLIFE) + CHECK(krb5_store_int32(sp, princ->max_renewable_life)); + if (mask & KADM5_LAST_SUCCESS) + CHECK(krb5_store_int32(sp, princ->last_success)); + if (mask & KADM5_LAST_FAILED) + CHECK(krb5_store_int32(sp, princ->last_failed)); + if (mask & KADM5_FAIL_AUTH_COUNT) + CHECK(krb5_store_int32(sp, princ->fail_auth_count)); + if (mask & KADM5_KEY_DATA) { + CHECK(krb5_store_int32(sp, princ->n_key_data)); + for(i = 0; i < princ->n_key_data; i++) { + if (wkeys) + CHECK(kadm5_store_key_data(sp, &princ->key_data[i])); + else + CHECK(kadm5_store_fake_key_data(sp, &princ->key_data[i])); + } + } + if (mask & KADM5_TL_DATA) { + krb5_tl_data *tp; + + CHECK(krb5_store_int32(sp, princ->n_tl_data)); + for (tp = princ->tl_data; tp; tp = tp->tl_data_next) + CHECK(kadm5_store_tl_data(sp, tp)); + } + +out: + return ret; +} + + +kadm5_ret_t +kadm5_store_principal_ent(krb5_storage *sp, + kadm5_principal_ent_t princ) +{ + return store_principal_ent (sp, princ, ~0, 1); +} + +kadm5_ret_t +kadm5_store_principal_ent_nokeys(krb5_storage *sp, + kadm5_principal_ent_t princ) +{ + return store_principal_ent (sp, princ, ~0, 0); +} + +kadm5_ret_t +kadm5_store_principal_ent_mask(krb5_storage *sp, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + kadm5_ret_t ret; + + ret = krb5_store_int32(sp, mask); + if (ret == 0) + ret = store_principal_ent(sp, princ, mask, 1); + return ret; +} + +static kadm5_ret_t +ret_principal_ent(krb5_storage *sp, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + kadm5_ret_t ret = 0; + int i; + int32_t tmp; + + if (mask & KADM5_PRINCIPAL) + CHECK(krb5_ret_principal(sp, &princ->principal)); + + if (mask & KADM5_PRINC_EXPIRE_TIME) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->princ_expire_time = tmp; + } + if (mask & KADM5_PW_EXPIRATION) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->pw_expiration = tmp; + } + if (mask & KADM5_LAST_PWD_CHANGE) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->last_pwd_change = tmp; + } + if (mask & KADM5_MAX_LIFE) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->max_life = tmp; + } + if (mask & KADM5_MOD_NAME) { + CHECK(krb5_ret_int32(sp, &tmp)); + if(tmp) + CHECK(krb5_ret_principal(sp, &princ->mod_name)); + else + princ->mod_name = NULL; + } + if (mask & KADM5_MOD_TIME) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->mod_date = tmp; + } + if (mask & KADM5_ATTRIBUTES) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->attributes = tmp; + } + if (mask & KADM5_KVNO) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->kvno = tmp; + } + if (mask & KADM5_MKVNO) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->mkvno = tmp; + } + if (mask & KADM5_POLICY) { + CHECK(krb5_ret_int32(sp, &tmp)); + if(tmp) + CHECK(krb5_ret_string(sp, &princ->policy)); + else + princ->policy = NULL; + } + if (mask & KADM5_AUX_ATTRIBUTES) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->aux_attributes = tmp; + } + if (mask & KADM5_MAX_RLIFE) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->max_renewable_life = tmp; + } + if (mask & KADM5_LAST_SUCCESS) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->last_success = tmp; + } + if (mask & KADM5_LAST_FAILED) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->last_failed = tmp; + } + if (mask & KADM5_FAIL_AUTH_COUNT) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->fail_auth_count = tmp; + } + if (mask & KADM5_KEY_DATA) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->n_key_data = tmp; + princ->key_data = calloc(princ->n_key_data, sizeof(*princ->key_data)); + if (princ->key_data == NULL && princ->n_key_data != 0) + return ENOMEM; + for(i = 0; i < princ->n_key_data; i++) + CHECK(kadm5_ret_key_data(sp, &princ->key_data[i])); + } + if (mask & KADM5_TL_DATA) { + CHECK(krb5_ret_int32(sp, &tmp)); + princ->n_tl_data = tmp; + princ->tl_data = NULL; + for(i = 0; i < princ->n_tl_data; i++){ + krb5_tl_data *tp = malloc(sizeof(*tp)); + if (tp == NULL) { + ret = ENOMEM; + goto out; + } + ret = kadm5_ret_tl_data(sp, tp); + if (ret == 0) { + tp->tl_data_next = princ->tl_data; + princ->tl_data = tp; + } else { + free(tp); + goto out; + } + } + } + +out: + /* Can't free princ here -- we don't have a context */ + return ret; +} + +kadm5_ret_t +kadm5_ret_principal_ent(krb5_storage *sp, + kadm5_principal_ent_t princ) +{ + return ret_principal_ent (sp, princ, ~0); +} + +kadm5_ret_t +kadm5_ret_principal_ent_mask(krb5_storage *sp, + kadm5_principal_ent_t princ, + uint32_t *mask) +{ + kadm5_ret_t ret; + int32_t tmp; + + ret = krb5_ret_int32 (sp, &tmp); + if (ret) { + *mask = 0; + return ret; + } + *mask = tmp; + return ret_principal_ent (sp, princ, *mask); +} + +kadm5_ret_t +_kadm5_marshal_params(krb5_context context, + kadm5_config_params *params, + krb5_data *out) +{ + kadm5_ret_t ret; + + krb5_storage *sp = krb5_storage_emem(); + if (sp == NULL) + return krb5_enomem(context); + + ret = krb5_store_int32(sp, params->mask & (KADM5_CONFIG_REALM)); + if (ret == 0 && (params->mask & KADM5_CONFIG_REALM)) + ret = krb5_store_string(sp, params->realm); + if (ret == 0) + ret = krb5_storage_to_data(sp, out); + krb5_storage_free(sp); + return ret; +} + +kadm5_ret_t +_kadm5_unmarshal_params(krb5_context context, + krb5_data *in, + kadm5_config_params *params) +{ + kadm5_ret_t ret; + krb5_storage *sp; + int32_t mask; + + sp = krb5_storage_from_data(in); + if (sp == NULL) + return ENOMEM; + + ret = krb5_ret_int32(sp, &mask); + if (ret) + goto out; + params->mask = mask; + + if(params->mask & KADM5_CONFIG_REALM) + ret = krb5_ret_string(sp, ¶ms->realm); + out: + krb5_storage_free(sp); + + return ret; +} + +#ifdef TEST +#include +#include +#include + +static int version_flag; +static int help_flag; +static int verbose_flag; +static int in_text_flag = 0; +static int in_binary_flag = 0; +static int out_hex_flag = 0; +static int out_binary_flag = 0; +static int must_round_trip_flag = 0; +static char *byteorder_string_in_string; +static char *byteorder_string_out_string; +static struct getargs args[] = { + { "version", '\0', arg_flag, &version_flag, + "Version", NULL }, + { "help", '\0', arg_flag, &help_flag, + "Show this message", NULL }, + { "verbose", 'v', arg_flag, &verbose_flag, NULL, NULL }, + { "in-text", '\0', arg_flag, &in_text_flag, + "Input is a text \"recipe\"", NULL }, + { "in-binary", '\0', arg_flag, &in_binary_flag, + "Input is binary", NULL }, + { "out-hex", '\0', arg_flag, &out_hex_flag, + "Output hex", NULL }, + { "out-binary", '\0', arg_flag, &out_binary_flag, + "Output binary", NULL }, + { "must-round-trip", '\0', arg_flag, &must_round_trip_flag, + "Check that encoding and decoding round-trip", NULL }, + { "byte-order-out", '\0', arg_string, &byteorder_string_out_string, + "Output byte order", "host, network, be, or le" }, + { "byte-order-in", '\0', arg_string, &byteorder_string_in_string, + "Input byte order", "host, network, packed, be, or le" }, +}; + +#define DO_TYPE1(t, r, s) \ + if (strcmp(type, #t) == 0) { \ + t v; \ + ret = r(in, &v); \ + if (ret == 0) \ + ret = s(out, v); \ + return ret; \ + } + +#define DO_TYPE2(t, r, s) \ + if (strcmp(type, #t) == 0) { \ + t v; \ + ret = r(in, &v); \ + if (ret == 0) \ + ret = s(out, &v); \ + return ret; \ + } + +static krb5_error_code +reencode(const char *type, krb5_storage *in, krb5_storage *out) +{ + krb5_error_code ret; + + krb5_storage_seek(in, 0, SEEK_SET); + + /* + * TODO: When --verbose print a visual representation of the value. + * + * We have functionality in lib/krb5 for that for krb5_principal and + * krb5_address, but not any of the others. Adding krb5_print_*() + * and kadm5_print_*() functions just for this program to use seems + * annoying. + */ + DO_TYPE1(krb5_keyblock, krb5_ret_keyblock, krb5_store_keyblock); + DO_TYPE1(krb5_principal, krb5_ret_principal, krb5_store_principal); + DO_TYPE1(krb5_times, krb5_ret_times, krb5_store_times); + DO_TYPE1(krb5_address, krb5_ret_address, krb5_store_address); + DO_TYPE1(krb5_addresses, krb5_ret_addrs, krb5_store_addrs); + DO_TYPE1(krb5_authdata, krb5_ret_authdata, krb5_store_authdata); + + DO_TYPE2(krb5_creds, krb5_ret_creds, krb5_store_creds); + DO_TYPE2(krb5_key_data, kadm5_ret_key_data, kadm5_store_key_data); + DO_TYPE2(krb5_tl_data, kadm5_ret_tl_data, kadm5_store_tl_data); + DO_TYPE2(kadm5_principal_ent_rec, kadm5_ret_principal_ent, + kadm5_store_principal_ent); + + return ENOTSUP; +} + +static krb5_error_code +eval_recipe1(krb5_storage *sp, const char *typ, const char *val) +{ + krb5_error_code ret; + uint64_t vu = 0; + int64_t vi = 0; + int consumed = 0; + + if (strncmp(typ, "int", sizeof("int") - 1) == 0) { + if (sscanf(val, "%"PRIi64"%n", &vi, &consumed) != 1) + return EINVAL; + if (consumed < 1) + return EINVAL; + while (isspace((unsigned char)val[consumed])) + consumed++; + if (val[consumed] != '\0') + return EINVAL; + } else if (strncmp(typ, "uint", sizeof("uint") - 1) == 0) { + /* There's no equally-useful equivalent of %i for unsigned */ + if (val[0] == '0') { + if (val[1] == 'x') { + if (sscanf(val, "%"PRIx64"%n", &vu, &consumed) != 1) + return EINVAL; + } else { + if (sscanf(val, "%"PRIo64"%n", &vu, &consumed) != 1) + return EINVAL; + } + } else { + if (sscanf(val, "%"PRIu64"%n", &vu, &consumed) != 1) + return EINVAL; + } + if (consumed < 1) + return EINVAL; + while (isspace((unsigned char)val[consumed])) + consumed++; + if (val[consumed] != '\0') + return EINVAL; + vi = (int64_t)vu; + } +#define DO_INTn(n) \ + if (strcmp(typ, "int" #n) == 0) { \ + if (n < 64 && vi < INT ## n ## _MIN) \ + return EOVERFLOW; \ + if (n < 64 && vi > INT ## n ## _MAX) \ + return EOVERFLOW; \ + return krb5_store_int ## n (sp, vi); \ + } + DO_INTn(8); + DO_INTn(16); + DO_INTn(32); + DO_INTn(64); +#define DO_UINTn(n) \ + if (strcmp(typ, "uint" #n) == 0) { \ + if (n < 64 && vu > INT ## n ## _MAX) \ + return EOVERFLOW; \ + return krb5_store_int ## n (sp, vi); \ + } + DO_UINTn(8); + DO_UINTn(16); + DO_UINTn(32); + DO_UINTn(64); + if (strcmp(typ, "string") == 0) + return krb5_store_string(sp, val); + if (strcmp(typ, "stringz") == 0) + return krb5_store_stringz(sp, val); + if (strcmp(typ, "stringnl") == 0) + return krb5_store_stringnl(sp, val); + if (strcmp(typ, "data") == 0) { + ssize_t dsz = strlen(val); + krb5_data d; + + /* + * 'data' as in 'krb5_data'. + * + * krb5_store_data() stores the length then the data. + */ + if (krb5_data_alloc(&d, dsz)) + return ENOMEM; + dsz = hex_decode(val, d.data, d.length); + if (dsz < 0) + return EINVAL; + d.length = dsz; + ret = krb5_store_data(sp, d); + krb5_data_free(&d); + return ret; + } + if (strcmp(typ, "rawdata") == 0) { + ssize_t dsz = strlen(val); + void *d; + + /* Store the data w/o a length prefix */ + d = malloc(dsz); + if (d == NULL) + return ENOMEM; + dsz = hex_decode(val, d, dsz); + if (dsz < 0) + return EINVAL; + ret = krb5_store_datalen(sp, d, dsz); + free(d); + return ret; + } + return ENOTSUP; +} + +static krb5_storage * +eval_recipe(char *r, int spflags) +{ + krb5_error_code ret; + krb5_storage *sp; + unsigned int lineno = 0; + char *nxt = NULL; + char *p; + + sp = krb5_storage_emem(); + if (sp == NULL) + errx(1, "Out of memory"); + krb5_storage_set_flags(sp, spflags); + + for (p = r; p && *p; p = nxt) { + char *typ; + char *val; + + lineno++; + + /* Terminate p at \n */ + nxt = p; + do { + nxt = strpbrk(nxt, "\r\n"); + if (nxt && *nxt == '\r') { + if (*(++nxt) != '\n') + continue; + } + if (nxt && *nxt == '\n') { + *(nxt++) = '\0'; + break; + } + } while (nxt); + + while (isspace((unsigned char)*p)) + p++; + if (*p == '#') { + p = nxt; + continue; + } + if (*p == '\0') + continue; + typ = p; + val = strpbrk(p, " \t"); + if (val) { + *(val++) = '\0'; + while (isspace((unsigned char)*val)) + val++; + } + ret = eval_recipe1(sp, typ, val); + if (ret) + krb5_err(NULL, 1, ret, "Error at line %u", lineno); + } + return sp; +} + +static void +usage(int code) +{ + if (code) + dup2(STDERR_FILENO, STDOUT_FILENO); + + arg_printusage(args, sizeof(args) / sizeof(args[0]), "test_marshall", + "Usage: test_marshal [options] TYPE-NAME INPUT-FILE " + "[OUTPUT-FILE]\n" + "\tText inputs must be of the form:\n\n" + "\t\tsimpletype literalvalue\n\n" + "\twhere {simpletype} is one of:\n\n" + "\t\tint8\n" + "\t\tint16\n" + "\t\tint32\n" + "\t\tint64\n" + "\t\tuint8\n" + "\t\tuint16\n" + "\t\tuint32\n" + "\t\tuint64\n" + "\t\tstring\n" + "\t\tstringz\n" + "\t\tstringnl\n" + "\t\tdata\n" + "\t\trawdata\n\n" + "\tand {literalvalue} is as appropriate for the {simpletype}:\n\n" + "\t - For int types the value can be decimal, octal, or hexadecimal.\n" + "\t - For string types the string ends at the end of the line.\n" + "\t - For {data} the value is hex and will be encoded as a 32-bit\n" + "\t length then the raw binary data.\n" + "\t - For {rawdata} the value is hex and will be encoded as just the\n" + "\t raw binary data.\n\n" + "\tThe {TYPE} must be one of: krb5_keyblock, krb5_principal,\n" + "\tkrb5_times, krb5_address, krb5_addresses, krb5_authdata,\n" + "\tkrb5_creds, krb5_key_data, krb5_tl_data, or\n" + "\tkadm5_principal_ent_rec.\n\n" + "Options:\n"); + exit(code); +} + +static krb5_flags +byteorder_flags(const char *s) +{ + if (s == NULL) + return KRB5_STORAGE_BYTEORDER_BE; + if (strcasecmp(s, "packed") == 0) + return KRB5_STORAGE_BYTEORDER_PACKED; + if (strcasecmp(s, "host") == 0) + return KRB5_STORAGE_BYTEORDER_HOST; + if (strcasecmp(s, "network") == 0) + return KRB5_STORAGE_BYTEORDER_BE; + if (strcasecmp(s, "be") == 0) + return KRB5_STORAGE_BYTEORDER_BE; + if (strcasecmp(s, "le") == 0) + return KRB5_STORAGE_BYTEORDER_LE; + return 0; +} + +/* + * This program is intended to make fuzzing of krb5_ret_*() and kadm5_ret_*() + * possible. + * + * Inputs are either binary encodings or simplistic textual representations of + * XDR-ish data structures normally coded with {kadm5,krb5}_{ret,store}_*() + * functions. + * + * A textual representation of these structures looks like: + * + * type value + * .. + * + * where type is one of char, int32, etc., and where value is an appropriate + * literal for type. + */ +int +main(int argc, char **argv) +{ + krb5_error_code ret = 0; + krb5_storage *insp = NULL; + krb5_storage *insp2 = NULL; + krb5_storage *outsp = NULL; + krb5_flags spflags_in = 0; + krb5_flags spflags_out = 0; + krb5_data i, i2, o; + size_t insz = 0; + char *hexout = NULL; + char *hexin = NULL; + char *intxt = NULL; + void *inbin = NULL; + int optidx = 0; + + if (getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage(0); + + argc -= optidx; + argv += optidx; + + if (argc < 1) + errx(1, "Missing type name argument"); + if (argc < 2) + errx(1, "Missing input file argument"); + if (argc > 3) + errx(1, "Too many arguments"); + + if ((in_text_flag && in_binary_flag) || + (!in_text_flag && !in_binary_flag)) + errx(1, "One and only one of --in-text and --in-binary must be given"); + if (out_hex_flag && out_binary_flag) + errx(1, "At most one of --out-text and --out-binary must be given"); + + if (!out_hex_flag && !out_binary_flag) { + if (isatty(STDOUT_FILENO)) { + warnx("Will output hex because stdout is a terminal"); + out_hex_flag = 1; + } else { + warnx("Will output binary"); + out_binary_flag = 1; + } + } + + spflags_in |= byteorder_flags(byteorder_string_in_string); + spflags_out |= byteorder_flags(byteorder_string_out_string); + + /* Read the input */ + if (in_text_flag) + errno = rk_undumptext(argv[1], &intxt, NULL); + else + errno = rk_undumpdata(argv[1], &inbin, &insz); + if (errno) + err(1, "Could not read %s", argv[1]); + + /* If the input is a recipe, evaluate it */ + if (intxt) + insp = eval_recipe(intxt, spflags_in); + else + insp = krb5_storage_from_mem(inbin, insz); + if (insp == NULL) + errx(1, "Out of memory"); + krb5_storage_set_flags(insp, spflags_in); + + ret = krb5_storage_to_data(insp, &i); + if (ret) + krb5_err(NULL, 1, ret, "Could not check round-tripping"); + + if (out_hex_flag) { + char *hexstr = NULL; + + if (hex_encode(i.data, i.length, &hexstr) == -1) + err(1, "Could not hex-encode output"); + if (argv[2]) { + FILE *f; + + f = fopen(argv[2], "w"); + if (f == NULL) + err(1, "Could not open %s for writing", argv[2]); + if (fprintf(f, "%s\n", hexstr) < 0 || fclose(f)) + err(1, "Could write to %s", argv[2]); + } else { + if (printf("%s\n", hexstr) < 0) + err(1, "Could not write to stdout"); + } + free(hexstr); + } else { + if (argv[2]) { + rk_dumpdata(argv[2], i.data, i.length); + } else { + if (fwrite(i.data, i.length, 1, stdout) != 1 || + fflush(stdout) != 0) + err(1, "Could not output encoding"); + } + } + + outsp = krb5_storage_emem(); + if (outsp == NULL) + errx(1, "Out of memory"); + krb5_storage_set_flags(outsp, spflags_out); + + ret = reencode(argv[0], insp, outsp); + if (ret) + krb5_err(NULL, 1, ret, "Could not decode and re-encode"); + + if (i.length == o.length && memcmp(i.data, o.data, i.length) == 0) { + if (verbose_flag) + fprintf(stderr, "Encoding round-trips!\n"); + goto out; + } + + ret = krb5_storage_to_data(outsp, &o); + if (ret) + krb5_err(NULL, 1, ret, "Out of memory"); + + /* + * The encoding did not round trip. Sadly kadm5_ret_principal_ent() + * reverses the TL data list. So try to re-encode one more time. + */ + + if (strcmp(argv[0], "kadm5_principal_ent_rec") == 0) { + insp2 = krb5_storage_emem(); + if (insp2 == NULL) + errx(1, "Out of memory"); + + krb5_storage_set_flags(insp2, spflags_in); + ret = reencode(argv[0], outsp, insp2); + if (ret == 0) + ret = krb5_storage_to_data(insp2, &i2); + if (ret) + krb5_err(NULL, 1, ret, "Could not decode and re-encode"); + if (i.length == i2.length && memcmp(i.data, i2.data, i.length) == 0) { + if (verbose_flag) + fprintf(stderr, "Encoding round-trips!\n"); + goto out; + } + } + if (hex_encode(i.data, i.length, &hexin) < 0) + errx(1, "Out of memory"); + if (hex_encode(o.data, o.length, &hexout) < 0) + errx(1, "Out of memory"); + if (must_round_trip_flag) { + errx(1, "Encoding does not round-trip\n(in: %s)\n(out: %s)", hexin, + hexout); + } else { + warnx("Encoding does not round-trip\n(in: %s)\n(out: %s)", hexin, + hexout); + } + +out: + + free(hexin); + free(hexout); + krb5_data_free(&o); + krb5_data_free(&i); + krb5_data_free(&i2); + krb5_storage_free(insp); + krb5_storage_free(outsp); + krb5_storage_free(insp2); + return ret; +} +#endif diff --git a/third_party/heimdal/lib/kadm5/modify_c.c b/third_party/heimdal/lib/kadm5/modify_c.c new file mode 100644 index 0000000..a38cb33 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/modify_c.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_modify_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_modify); + if (ret) + goto out; + ret = kadm5_store_principal_ent(sp, princ); + if (ret) + goto out; + ret = krb5_store_int32(sp, mask); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/modify_s.c b/third_party/heimdal/lib/kadm5/modify_s.c new file mode 100644 index 0000000..2159caf --- /dev/null +++ b/third_party/heimdal/lib/kadm5/modify_s.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1997-2001, 2003, 2005-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct modify_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + kadm5_principal_ent_t princ; + uint32_t mask; +}; + +static krb5_error_code KRB5_LIB_CALL +modify_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct modify_principal_hook_ctx *ctx = userctx; + + ret = ftable->modify(context, hookctx, ctx->stage, + ctx->code, ctx->princ, ctx->mask); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "modify", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +modify_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + krb5_error_code ret; + struct modify_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.mask = mask; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, modify_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +static kadm5_ret_t +modify_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask, + uint32_t forbidden_mask) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret; + + memset(&ent, 0, sizeof(ent)); + + if((mask & forbidden_mask)) + return KADM5_BAD_MASK; + if((mask & KADM5_POLICY) && strcmp(princ->policy, "default") != 0) + return KADM5_UNK_POLICY; + + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + /* + * NOTE: We do not use hdb_fetch_kvno() here, which means we'll + * automatically reject modifications of would-be virtual principals. + */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, + princ->principal, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret) + goto out2; + + ret = modify_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, mask); + if (ret) + goto out3; + /* + * XXX Make sure that _kadm5_setup_entry() checks that the time of last + * change in `ent' matches the one in `princ'. + */ + ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0); + if (ret) + goto out3; + ret = _kadm5_set_modifier(context, &ent); + if (ret) + goto out3; + + /* + * If any keys are bogus, disallow the modify. If the keys were + * bogus as stored in the HDB we could allow those through, but + * distinguishing that case from a pre-1.6 client using add_enctype + * without the get-keys privilege requires more work (mainly: checking that + * the bogus keys in princ->key_data[] have corresponding bogus keys in ent + * before calling _kadm5_setup_entry()). + */ + if ((mask & KADM5_KEY_DATA) && + kadm5_some_keys_are_bogus(princ->n_key_data, princ->key_data)) { + ret = KADM5_AUTH_GET_KEYS; /* Not quite appropriate, but it'll do */ + goto out3; + } + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + + if ((mask & KADM5_POLICY)) { + HDB_extension ext; + + memset(&ext, 0, sizeof(ext)); + /* XXX should be TRUE, but we don't yet support policies */ + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_policy; + ext.data.u.policy = strdup(princ->policy); + if (ext.data.u.policy == NULL) { + ret = krb5_enomem(context->context); + goto out3; + } + /* This calls free_HDB_extension(), freeing ext.data.u.policy */ + ret = hdb_replace_extension(context->context, &ent, &ext); + free(ext.data.u.policy); + if (ret) + goto out3; + } + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_modify(context, &ent, + mask | KADM5_MOD_NAME | KADM5_MOD_TIME); + + (void) modify_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, mask); + + out3: + hdb_free_entry(context->context, context->db, &ent); + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} + + +kadm5_ret_t +kadm5_s_modify_principal(void *server_handle, + kadm5_principal_ent_t princ, + uint32_t mask) +{ + return modify_principal(server_handle, princ, mask, + KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME + | KADM5_MOD_NAME | KADM5_MKVNO + | KADM5_AUX_ATTRIBUTES | KADM5_LAST_SUCCESS + | KADM5_LAST_FAILED); +} diff --git a/third_party/heimdal/lib/kadm5/password_quality.c b/third_party/heimdal/lib/kadm5/password_quality.c new file mode 100644 index 0000000..84c1d39 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/password_quality.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 1997-2000, 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include "kadm5-pwcheck.h" + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +static int +min_length_passwd_quality (krb5_context context, + krb5_principal principal, + krb5_data *pwd, + const char *opaque, + char *message, + size_t length) +{ + uint32_t min_length = krb5_config_get_int_default(context, NULL, 6, + "password_quality", + "min_length", + NULL); + + if (pwd->length < min_length) { + strlcpy(message, "Password too short", length); + return 1; + } else + return 0; +} + +static const char * +min_length_passwd_quality_v0 (krb5_context context, + krb5_principal principal, + krb5_data *pwd) +{ + static char message[1024]; + int ret; + + message[0] = '\0'; + + ret = min_length_passwd_quality(context, principal, pwd, NULL, + message, sizeof(message)); + if (ret) + return message; + return NULL; +} + + +static int +char_class_passwd_quality (krb5_context context, + krb5_principal principal, + krb5_data *pwd, + const char *opaque, + char *message, + size_t length) +{ + const char *classes[] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "1234567890", + " !\"#$%&'()*+,-./:;<=>?@\\]^_`{|}~" + }; + int counter = 0, req_classes; + size_t i, len; + char *pw; + + req_classes = krb5_config_get_int_default(context, NULL, 3, + "password_quality", + "min_classes", + NULL); + + len = pwd->length + 1; + pw = malloc(len); + if (pw == NULL) { + strlcpy(message, "out of memory", length); + return 1; + } + strlcpy(pw, pwd->data, len); + len = strlen(pw); + + for (i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) { + if (strcspn(pw, classes[i]) < len) + counter++; + } + memset(pw, 0, pwd->length + 1); + free(pw); + if (counter < req_classes) { + snprintf(message, length, + "Password doesn't meet complexity requirement.\n" + "Add more characters from at least %d of the\n" + "following classes:\n" + "1. English uppercase characters (A through Z)\n" + "2. English lowercase characters (a through z)\n" + "3. Base 10 digits (0 through 9)\n" + "4. Nonalphanumeric characters (e.g., !, $, #, %%)", req_classes); + return 1; + } + return 0; +} + +static int +external_passwd_quality (krb5_context context, + krb5_principal principal, + krb5_data *pwd, + const char *opaque, + char *message, + size_t length) +{ + krb5_error_code ret; + const char *program; + char *p; + pid_t child; + int status; + char reply[1024]; + FILE *in = NULL, *out = NULL, *error = NULL; + + if (memchr(pwd->data, '\n', pwd->length) != NULL) { + snprintf(message, length, "password contains newline, " + "not valid for external test"); + return 1; + } + + program = krb5_config_get_string(context, NULL, + "password_quality", + "external_program", + NULL); + if (program == NULL) { + snprintf(message, length, "external password quality " + "program not configured"); + return 1; + } + + ret = krb5_unparse_name(context, principal, &p); + if (ret) { + strlcpy(message, "out of memory", length); + return 1; + } + + child = pipe_execv(&in, &out, &error, program, program, p, NULL); + if (child < 0) { + snprintf(message, length, "external password quality " + "program failed to execute for principal %s", p); + free(p); + return 1; + } + + fprintf(in, "principal: %s\n" + "new-password: %.*s\n" + "end\n", + p, (int)pwd->length, (char *)pwd->data); + + fclose(in); + + if (fgets(reply, sizeof(reply), out) == NULL) { + + if (fgets(reply, sizeof(reply), error) == NULL) { + snprintf(message, length, "external password quality " + "program failed without error"); + + } else { + reply[strcspn(reply, "\n")] = '\0'; + snprintf(message, length, "External password quality " + "program failed: %s", reply); + } + + fclose(out); + fclose(error); + wait_for_process(child); + free(p); + return 1; + } + reply[strcspn(reply, "\n")] = '\0'; + + fclose(out); + fclose(error); + + status = wait_for_process(child); + + if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0) { + snprintf(message, length, "external program failed: %s", reply); + free(p); + return 1; + } + + if (strcmp(reply, "APPROVED") != 0) { + snprintf(message, length, "%s", reply); + free(p); + return 1; + } + + free(p); + + return 0; +} + + +static kadm5_passwd_quality_check_func_v0 passwd_quality_check = + min_length_passwd_quality_v0; + +struct kadm5_pw_policy_check_func builtin_funcs[] = { + { "minimum-length", min_length_passwd_quality }, + { "character-class", char_class_passwd_quality }, + { "external-check", external_passwd_quality }, + { NULL, NULL } +}; +struct kadm5_pw_policy_verifier builtin_verifier = { + "builtin", + KADM5_PASSWD_VERSION_V1, + "Heimdal builtin", + builtin_funcs +}; + +static struct kadm5_pw_policy_verifier **verifiers; +static int num_verifiers; + +/* + * setup the password quality hook + */ + +void +kadm5_setup_passwd_quality_check(krb5_context context, + const char *check_library, + const char *check_function) +{ +#ifdef HAVE_DLOPEN + void *handle; + void *sym; + int *version; + const char *tmp; + + if(check_library == NULL) { + tmp = krb5_config_get_string(context, NULL, + "password_quality", + "check_library", + NULL); + if(tmp != NULL) + check_library = tmp; + } + if(check_function == NULL) { + tmp = krb5_config_get_string(context, NULL, + "password_quality", + "check_function", + NULL); + if(tmp != NULL) + check_function = tmp; + } + if(check_library != NULL && check_function == NULL) + check_function = "passwd_check"; + + if(check_library == NULL) + return; + handle = dlopen(check_library, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); + if(handle == NULL) { + krb5_warnx(context, "failed to open `%s'", check_library); + return; + } + version = (int *) dlsym(handle, "version"); + if(version == NULL) { + krb5_warnx(context, + "didn't find `version' symbol in `%s'", check_library); + dlclose(handle); + return; + } + if(*version != KADM5_PASSWD_VERSION_V0) { + krb5_warnx(context, + "version of loaded library is %d (expected %d)", + *version, KADM5_PASSWD_VERSION_V0); + dlclose(handle); + return; + } + sym = dlsym(handle, check_function); + if(sym == NULL) { + krb5_warnx(context, + "didn't find `%s' symbol in `%s'", + check_function, check_library); + dlclose(handle); + return; + } + passwd_quality_check = (kadm5_passwd_quality_check_func_v0) sym; +#endif /* HAVE_DLOPEN */ +} + +#ifdef HAVE_DLOPEN + +static krb5_error_code +add_verifier(krb5_context context, const char *check_library) +{ + struct kadm5_pw_policy_verifier *v, **tmp; + void *handle; + int i; + + handle = dlopen(check_library, RTLD_NOW | RTLD_LOCAL | RTLD_GROUP); + if(handle == NULL) { + krb5_warnx(context, "failed to open `%s'", check_library); + return ENOENT; + } + v = (struct kadm5_pw_policy_verifier *) dlsym(handle, "kadm5_password_verifier"); + if(v == NULL) { + krb5_warnx(context, + "didn't find `kadm5_password_verifier' symbol " + "in `%s'", check_library); + dlclose(handle); + return ENOENT; + } + if(v->version != KADM5_PASSWD_VERSION_V1) { + krb5_warnx(context, + "version of loaded library is %d (expected %d)", + v->version, KADM5_PASSWD_VERSION_V1); + dlclose(handle); + return EINVAL; + } + for (i = 0; i < num_verifiers; i++) { + if (strcmp(v->name, verifiers[i]->name) == 0) + break; + } + if (i < num_verifiers) { + krb5_warnx(context, "password verifier library `%s' is already loaded", + v->name); + dlclose(handle); + return 0; + } + + tmp = realloc(verifiers, (num_verifiers + 1) * sizeof(*verifiers)); + if (tmp == NULL) { + krb5_warnx(context, "out of memory"); + dlclose(handle); + return 0; + } + verifiers = tmp; + verifiers[num_verifiers] = v; + num_verifiers++; + + return 0; +} + +#endif + +krb5_error_code +kadm5_add_passwd_quality_verifier(krb5_context context, + const char *check_library) +{ +#ifdef HAVE_DLOPEN + + if(check_library == NULL) { + krb5_error_code ret = 0; + char **strs; + char **tmp; + + strs = krb5_config_get_strings(context, NULL, + "password_quality", + "policy_libraries", + NULL); + if (strs == NULL) + return 0; + + for (tmp = strs; *tmp; tmp++) { + ret = add_verifier(context, *tmp); + if (ret) + break; + } + krb5_config_free_strings(strs); + return ret; + } else { + return add_verifier(context, check_library); + } +#else + return 0; +#endif /* HAVE_DLOPEN */ +} + +/* + * + */ + +static const struct kadm5_pw_policy_check_func * +find_func(krb5_context context, const char *name) +{ + const struct kadm5_pw_policy_check_func *f; + char *module = NULL; + const char *p, *func; + int i; + + p = strchr(name, ':'); + if (p) { + size_t len = p - name + 1; + func = p + 1; + module = malloc(len); + if (module == NULL) + return NULL; + strlcpy(module, name, len); + } else + func = name; + + /* Find module in loaded modules first */ + for (i = 0; i < num_verifiers; i++) { + if (module && strcmp(module, verifiers[i]->name) != 0) + continue; + for (f = verifiers[i]->funcs; f->name ; f++) + if (strcmp(func, f->name) == 0) { + if (module) + free(module); + return f; + } + } + /* Lets try try the builtin modules */ + if (module == NULL || strcmp(module, "builtin") == 0) { + for (f = builtin_verifier.funcs; f->name ; f++) + if (strcmp(func, f->name) == 0) { + if (module) + free(module); + return f; + } + } + if (module) + free(module); + return NULL; +} + +const char * +kadm5_check_password_quality (krb5_context context, + krb5_principal principal, + krb5_data *pwd_data) +{ + const struct kadm5_pw_policy_check_func *proc; + static char error_msg[1024]; + const char *msg; + char **v, **vp; + int ret; + + /* + * Check if we should use the old version of policy function. + */ + + v = krb5_config_get_strings(context, NULL, + "password_quality", + "policies", + NULL); + if (v == NULL) { + msg = (*passwd_quality_check) (context, principal, pwd_data); + if (msg) + krb5_set_error_message(context, 0, "password policy failed: %s", msg); + return msg; + } + + error_msg[0] = '\0'; + + msg = NULL; + for(vp = v; *vp; vp++) { + proc = find_func(context, *vp); + if (proc == NULL) { + msg = "failed to find password verifier function"; + krb5_set_error_message(context, 0, "Failed to find password policy " + "function: %s", *vp); + break; + } + ret = (proc->func)(context, principal, pwd_data, NULL, + error_msg, sizeof(error_msg)); + if (ret) { + krb5_set_error_message(context, 0, "Password policy " + "%s failed with %s", + proc->name, error_msg); + msg = error_msg; + break; + } + } + krb5_config_free_strings(v); + + /* If the default quality check isn't used, lets check that the + * old quality function the user have set too */ + if (msg == NULL && passwd_quality_check != min_length_passwd_quality_v0) { + msg = (*passwd_quality_check) (context, principal, pwd_data); + if (msg) + krb5_set_error_message(context, 0, "(old) password policy " + "failed with %s", msg); + + } + return msg; +} diff --git a/third_party/heimdal/lib/kadm5/private.h b/third_party/heimdal/lib/kadm5/private.h new file mode 100644 index 0000000..1cb8e39 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/private.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 1997-2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __kadm5_privatex_h__ +#define __kadm5_privatex_h__ + +#include "kadm5-hook.h" + +#ifdef HAVE_SYS_UN_H +#include +#endif + +struct kadm_func { + kadm5_ret_t (*chpass_principal) (void *, krb5_principal, int, + int, krb5_key_salt_tuple*, const char*); + kadm5_ret_t (*create_principal) (void*, kadm5_principal_ent_t, uint32_t, + int, krb5_key_salt_tuple *, + const char*); + kadm5_ret_t (*delete_principal) (void*, krb5_principal); + kadm5_ret_t (*destroy) (void*); + kadm5_ret_t (*flush) (void*); + kadm5_ret_t (*get_principal) (void*, krb5_principal, + kadm5_principal_ent_t, uint32_t); + kadm5_ret_t (*get_principals) (void*, const char*, char***, int*); + kadm5_ret_t (*get_privs) (void*, uint32_t*); + kadm5_ret_t (*modify_principal) (void*, kadm5_principal_ent_t, uint32_t); + kadm5_ret_t (*randkey_principal) (void*, krb5_principal, krb5_boolean, int, + krb5_key_salt_tuple*, krb5_keyblock**, + int*); + kadm5_ret_t (*rename_principal) (void*, krb5_principal, krb5_principal); + kadm5_ret_t (*chpass_principal_with_key) (void *, krb5_principal, int, + int, krb5_key_data *); + kadm5_ret_t (*lock) (void *); + kadm5_ret_t (*unlock) (void *); + kadm5_ret_t (*setkey_principal_3) (void *, krb5_principal, krb5_boolean, + int, krb5_key_salt_tuple *, + krb5_keyblock *, int); + kadm5_ret_t (*prune_principal) (void *, krb5_principal, int); + kadm5_ret_t (*iter_principals) (void*, const char*, int (*)(void *, const char *), void *); + kadm5_ret_t (*dup_context) (void*, void **); +}; + +typedef struct kadm5_hook_context { + void *dsohandle; + const kadm5_hook_ftable *hook; + void *data; +} kadm5_hook_context; + +/* XXX should be integrated */ +typedef struct kadm5_common_context { + krb5_context context; + krb5_boolean my_context; + struct kadm_func funcs; + void *data; +} kadm5_common_context; + +typedef struct kadm5_log_peer { + int fd; + char *name; + krb5_auth_context ac; + struct kadm5_log_peer *next; +} kadm5_log_peer; + +typedef struct kadm5_log_context { + char *log_file; + int log_fd; + int read_only; + int lock_mode; + uint32_t version; + time_t last_time; +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un socket_name; +#else + struct addrinfo *socket_info; +#endif + krb5_socket_t socket_fd; +} kadm5_log_context; + +typedef struct kadm5_server_context { + krb5_context context; + krb5_boolean my_context; + struct kadm_func funcs; + /* */ + kadm5_config_params config; + HDB *db; + int keep_open; + krb5_principal caller; + unsigned acl_flags; + kadm5_log_context log_context; + size_t num_hooks; + kadm5_hook_context **hooks; +} kadm5_server_context; + +typedef struct kadm5_client_context { + krb5_context context; + krb5_boolean my_context; + struct kadm_func funcs; + /* */ + krb5_auth_context ac; + char *realm; + char *admin_server; + int kadmind_port; + krb5_socket_t sock; + char *client_name; + char *service_name; + krb5_prompter_fct prompter; + const char *keytab; + krb5_ccache ccache; + kadm5_config_params *realm_params; + char *readonly_admin_server; + int readonly_kadmind_port; + unsigned int want_write:1; + unsigned int connected_to_writable:1; +} kadm5_client_context; + +typedef struct kadm5_ad_context { + krb5_context context; + krb5_boolean my_context; + struct kadm_func funcs; + /* */ + kadm5_config_params config; + krb5_principal caller; + krb5_ccache ccache; + char *client_name; + char *realm; + void *ldap_conn; + char *base_dn; +} kadm5_ad_context; + +/* + * This enum is used in the iprop log file and on the wire in the iprop + * protocol. DO NOT CHANGE, except to add new op types at the end, and + * look for places in lib/kadm5/log.c to update. + */ +enum kadm_ops { + kadm_get, + kadm_delete, + kadm_create, + kadm_rename, + kadm_chpass, + kadm_modify, + kadm_randkey, + kadm_get_privs, + kadm_get_princs, + kadm_chpass_with_key, + kadm_nop, + kadm_prune, + kadm_first = kadm_get, + kadm_last = kadm_prune +}; + +/* FIXME nop types are currently not implemented */ +enum kadm_nop_type { + kadm_nop_plain, /* plain nop, not relevance except as uberblock */ + kadm_nop_trunc, /* indicates that the master truncated the log */ + kadm_nop_close /* indicates that the master closed this log */ +}; + +enum kadm_iter_opts { + kadm_forward = 1, + kadm_backward = 2, + kadm_confirmed = 4, + kadm_unconfirmed = 8 +}; + +enum kadm_recover_mode { + kadm_recover_commit, + kadm_recover_replay +}; + +#define KADMIN_APPL_VERSION "KADM0.1" +#define KADMIN_OLD_APPL_VERSION "KADM0.0" + +extern struct heim_plugin_data kadm5_hook_plugin_data; + +#include "kadm5-private.h" + +#endif /* __kadm5_privatex_h__ */ diff --git a/third_party/heimdal/lib/kadm5/privs_c.c b/third_party/heimdal/lib/kadm5/privs_c.c new file mode 100644 index 0000000..b6879cf --- /dev/null +++ b/third_party/heimdal/lib/kadm5/privs_c.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_get_privs(void *server_handle, uint32_t *privs) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + *privs = 0; + + ret = _kadm5_connect(server_handle, 0 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_store_int32(sp, kadm_get_privs); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (ret == 0) + krb5_ret_uint32(sp, privs); + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free (&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/privs_s.c b/third_party/heimdal/lib/kadm5/privs_s.c new file mode 100644 index 0000000..bfe298d --- /dev/null +++ b/third_party/heimdal/lib/kadm5/privs_s.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_s_get_privs(void *server_handle, uint32_t *privs) +{ + kadm5_server_context *context = server_handle; + *privs = context->acl_flags; + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/prune_c.c b/third_party/heimdal/lib/kadm5/prune_c.c new file mode 100644 index 0000000..70a1dcb --- /dev/null +++ b/third_party/heimdal/lib/kadm5/prune_c.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 Cesnet z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_prune_principal(void *server_handle, krb5_principal princ, int kvno) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret, ret2; + krb5_storage *sp = NULL; + unsigned char buf[1024]; + krb5_data reply; + + krb5_data_zero(&reply); + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret == 0 && (sp = krb5_storage_from_mem(buf, sizeof(buf))) == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = krb5_store_int32(sp, kadm_prune); + if (ret == 0) + ret = krb5_store_principal(sp, princ); + if (ret == 0) + ret = krb5_store_int32(sp, kvno); + if (ret == 0) + ret = _kadm5_client_send(context, sp); + if (ret == 0) + ret = _kadm5_client_recv(context, &reply); + krb5_storage_free(sp); + sp = NULL; + if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL) + ret = krb5_enomem(context->context); + if (ret == 0) + ret = krb5_ret_int32(sp, &ret2); + if (ret == 0) { + krb5_clear_error_message(context->context); + ret = ret2; + } + krb5_data_free(&reply); + krb5_storage_free(sp); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/prune_s.c b/third_party/heimdal/lib/kadm5/prune_s.c new file mode 100644 index 0000000..96133f2 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/prune_s.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018 Cesnet z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct prune_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; + int kvno; +}; + +static krb5_error_code KRB5_LIB_CALL +prune_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct prune_principal_hook_ctx *ctx = userctx; + + ret = ftable->prune(context, hookctx, + ctx->stage, ctx->code, ctx->princ, ctx->kvno); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "prune", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +prune_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + int kvno) +{ + krb5_error_code ret; + struct prune_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.kvno = kvno; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, prune_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +kadm5_ret_t +kadm5_s_prune_principal(void *server_handle, + krb5_principal princ, + int kvno) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret; + + memset(&ent, 0, sizeof(ent)); + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + /* NOTE: We do not use hdb_fetch_kvno() here */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret) + goto out2; + + ret = prune_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, princ, kvno); + if (ret) + goto out3; + + ret = hdb_prune_keys_kvno(context->context, &ent, kvno); + if (ret) + goto out3; + + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + + ret = kadm5_log_modify(context, &ent, KADM5_KEY_DATA); + + (void) prune_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, princ, kvno); + +out3: + hdb_free_entry(context->context, context->db, &ent); +out2: + (void) kadm5_log_end(context); +out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/randkey_c.c b/third_party/heimdal/lib/kadm5/randkey_c.c new file mode 100644 index 0000000..cb0ec86 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/randkey_c.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_randkey_principal(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock **new_keys, + int *n_keys) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1536]; + int32_t tmp; + size_t i; + krb5_data reply; + krb5_keyblock *k; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + + /* + * NOTE WELL: This message is extensible. It currently consists of: + * + * - opcode (kadm_randkey) + * - principal name (princ) + * + * followed by optional items, each of which must be present if + * there are any items following them that are also present: + * + * - keepold boolean (whether to delete old kvnos) + * - number of key/salt type tuples + * - array of {enctype, salttype} + * + * Eventually we may add: + * + * - opaque string2key parameters (salt, rounds, ...) + */ + ret = krb5_store_int32(sp, kadm_randkey); + if (ret == 0) + ret = krb5_store_principal(sp, princ); + + if (ret == 0 && (keepold == TRUE || n_ks_tuple > 0)) + ret = krb5_store_uint32(sp, keepold); + if (ret == 0 && n_ks_tuple > 0) + ret = krb5_store_uint32(sp, n_ks_tuple); + for (i = 0; ret == 0 && i < n_ks_tuple; i++) { + ret = krb5_store_int32(sp, ks_tuple[i].ks_enctype); + if (ret == 0) + ret = krb5_store_int32(sp, ks_tuple[i].ks_salttype); + } + /* Future extensions go here */ + if (ret) + goto out; + + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + if (ret) + goto out; + + ret = krb5_ret_int32(sp, &tmp); + if (ret) + goto out; + if (tmp < 0) { + ret = EOVERFLOW; + goto out; + } + k = calloc(tmp, sizeof(*k)); + if (k == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + for (i = 0; ret == 0 && i < tmp; i++) { + ret = krb5_ret_keyblock(sp, &k[i]); + if (ret) + break; + } + if (ret == 0 && n_keys && new_keys) { + *n_keys = tmp; + *new_keys = k; + } else { + krb5_free_keyblock_contents(context->context, &k[i]); + for (; i > 0; i--) + krb5_free_keyblock_contents(context->context, &k[i - 1]); + free(k); + } + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/randkey_s.c b/third_party/heimdal/lib/kadm5/randkey_s.c new file mode 100644 index 0000000..cb36967 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/randkey_s.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 1997-2001, 2003-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct randkey_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; +}; + +static krb5_error_code KRB5_LIB_CALL +randkey_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct randkey_principal_hook_ctx *ctx = userctx; + + ret = ftable->randkey(context, hookctx, + ctx->stage, ctx->code, ctx->princ); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "randkey", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +randkey_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ) +{ + krb5_error_code ret; + struct randkey_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, randkey_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +/* + * Set the keys of `princ' to random values, returning the random keys + * in `new_keys', `n_keys'. + */ + +kadm5_ret_t +kadm5_s_randkey_principal(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock **new_keys, + int *n_keys) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret; + size_t i; + + memset(&ent, 0, sizeof(ent)); + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + /* NOTE: We do not use hdb_fetch_kvno() here (maybe we should) */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if(ret) + goto out2; + + ret = randkey_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, 0, princ); + if (ret) + goto out3; + + if (keepold) { + ret = hdb_add_current_keys_to_history(context->context, &ent); + if (ret == 0 && keepold == 1) + ret = hdb_prune_keys_kvno(context->context, &ent, 0); + if (ret) + goto out3; + } else { + /* Remove all key history */ + ret = hdb_clear_extension(context->context, &ent, + choice_HDB_extension_data_hist_keys); + if (ret) + goto out3; + } + + ret = _kadm5_set_keys_randomly(context, &ent, n_ks_tuple, ks_tuple, + new_keys, n_keys); + if (ret) + goto out3; + ent.kvno++; + + ent.flags.require_pwchange = 0; + + ret = _kadm5_set_modifier(context, &ent); + if(ret) + goto out4; + ret = _kadm5_bump_pw_expire(context, &ent); + if (ret) + goto out4; + + if (keepold) { + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out4; + } else { + HDB_extension ext; + + memset(&ext, 0, sizeof (ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_keys; + ext.data.u.hist_keys.len = 0; + ext.data.u.hist_keys.val = NULL; + hdb_replace_extension(context->context, &ent, &ext); + } + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_modify(context, &ent, + KADM5_ATTRIBUTES | KADM5_PRINCIPAL | + KADM5_MOD_NAME | KADM5_MOD_TIME | + KADM5_KEY_DATA | KADM5_KVNO | + KADM5_PW_EXPIRATION | KADM5_TL_DATA); + + (void) randkey_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, princ); + + out4: + if (ret) { + for (i = 0; i < *n_keys; ++i) + krb5_free_keyblock_contents(context->context, &(*new_keys)[i]); + free (*new_keys); + *new_keys = NULL; + *n_keys = 0; + } + out3: + hdb_free_entry(context->context, context->db, &ent); + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/rename_c.c b/third_party/heimdal/lib/kadm5/rename_c.c new file mode 100644 index 0000000..fb2cdc5 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/rename_c.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_c_rename_principal(void *server_handle, + krb5_principal source, + krb5_principal target) +{ + kadm5_client_context *context = server_handle; + kadm5_ret_t ret; + krb5_storage *sp; + unsigned char buf[1024]; + int32_t tmp; + krb5_data reply; + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + return ret; + + krb5_data_zero(&reply); + + sp = krb5_storage_from_mem(buf, sizeof(buf)); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + + ret = krb5_store_int32(sp, kadm_rename); + if (ret) + goto out; + ret = krb5_store_principal(sp, source); + if (ret) + goto out; + ret = krb5_store_principal(sp, target); + if (ret) + goto out; + ret = _kadm5_client_send(context, sp); + if (ret) + goto out_keep_error; + ret = _kadm5_client_recv(context, &reply); + if (ret) + goto out_keep_error; + krb5_storage_free(sp); + sp = krb5_storage_from_data(&reply); + if (sp == NULL) { + ret = krb5_enomem(context->context); + goto out_keep_error; + } + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0) + ret = tmp; + + out: + krb5_clear_error_message(context->context); + + out_keep_error: + krb5_storage_free(sp); + krb5_data_free(&reply); + return ret; +} diff --git a/third_party/heimdal/lib/kadm5/rename_s.c b/third_party/heimdal/lib/kadm5/rename_s.c new file mode 100644 index 0000000..9143318 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/rename_s.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1997 - 2001, 2003, 2005 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +struct rename_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal source, target; +}; + +static krb5_error_code KRB5_LIB_CALL +rename_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct rename_principal_hook_ctx *ctx = userctx; + + ret = ftable->rename(context, hookctx, + ctx->stage, ctx->code, + ctx->source, ctx->target); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "rename", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +rename_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal source, + krb5_const_principal target) +{ + krb5_error_code ret; + struct rename_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.source = source; + ctx.target = target; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, rename_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +kadm5_ret_t +kadm5_s_rename_principal(void *server_handle, + krb5_principal source, + krb5_principal target) +{ + kadm5_server_context *context = server_handle; + kadm5_ret_t ret; + hdb_entry ent; + krb5_principal oldname; + size_t i; + + memset(&ent, 0, sizeof(ent)); + if (krb5_principal_compare(context->context, source, target)) + return KADM5_DUP; /* XXX is this right? */ + if (!context->keep_open) { + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if(ret) + return ret; + } + + ret = kadm5_log_init(context); + if (ret) + goto out; + + /* NOTE: We do not use hdb_fetch_kvno() here */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, + source, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret) + goto out2; + oldname = ent.principal; + + ret = rename_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, + 0, source, target); + if (ret) + goto out3; + + ret = _kadm5_set_modifier(context, &ent); + if (ret) + goto out3; + { + /* fix salt */ + Salt salt; + krb5_salt salt2; + memset(&salt, 0, sizeof(salt)); + ret = krb5_get_pw_salt(context->context, source, &salt2); + if (ret) + goto out3; + salt.type = hdb_pw_salt; + salt.salt = salt2.saltvalue; + for(i = 0; i < ent.keys.len; i++){ + if(ent.keys.val[i].salt == NULL){ + ent.keys.val[i].salt = + malloc(sizeof(*ent.keys.val[i].salt)); + if (ent.keys.val[i].salt == NULL) + ret = krb5_enomem(context->context); + else + ret = copy_Salt(&salt, ent.keys.val[i].salt); + if (ret) + break; + } + } + krb5_free_salt(context->context, salt2); + } + if (ret) + goto out3; + + /* Borrow target */ + ent.principal = target; + ret = hdb_seal_keys(context->context, context->db, &ent); + if (ret) + goto out3; + + /* This logs the change for iprop and writes to the HDB */ + ret = kadm5_log_rename(context, source, &ent); + + (void) rename_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, + ret, source, target); + + out3: + ent.principal = oldname; /* Unborrow target */ + hdb_free_entry(context->context, context->db, &ent); + + out2: + (void) kadm5_log_end(context); + out: + if (!context->keep_open) { + kadm5_ret_t ret2; + ret2 = context->db->hdb_close(context->context, context->db); + if (ret == 0 && ret2 != 0) + ret = ret2; + } + return _kadm5_error_code(ret); +} + diff --git a/third_party/heimdal/lib/kadm5/sample_hook.c b/third_party/heimdal/lib/kadm5/sample_hook.c new file mode 100644 index 0000000..03ac32b --- /dev/null +++ b/third_party/heimdal/lib/kadm5/sample_hook.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2018-2019, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include + +#include "admin.h" +#include "kadm5-hook.h" + +/* + * Sample kadm5 hook plugin that just logs when it is called. Install it + * somewhere and configure the path in the [kadmin] section of krb5.conf. + * e.g. + * + * [kadmin] + * plugin_dir = /usr/local/heimdal/lib/plugin/kadm5 + * + */ + +static char sample_data_1, sample_data_2; + +static krb5_error_code +sample_log(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + const char *tag, + krb5_error_code code, + krb5_const_principal princ) +{ + char *p = NULL; + int which = 0; + + /* verify we get called with the right contex tpointer */ + if (data == &sample_data_1) + which = 1; + else if (data == &sample_data_2) + which = 2; + + assert(which != 0); + + /* code should always be zero on pre-commit */ + assert(code == 0 || stage == KADM5_HOOK_STAGE_POSTCOMMIT); + + if (princ) + (void) krb5_unparse_name(context, princ, &p); + + krb5_warn(context, code, "sample_hook_%d: %s %s hook princ '%s'", which, tag, + stage == KADM5_HOOK_STAGE_PRECOMMIT ? "pre-commit" : "post-commit", + p != NULL ? p : ""); + + krb5_xfree(p); + + /* returning zero and KRB5_PLUGIN_NO_HANDLE are the same for hook plugins */ + return 0; +} + +static krb5_error_code KRB5_CALLCONV +sample_init_1(krb5_context context, void **data) +{ + *data = &sample_data_1; + krb5_warn(context, 0, "sample_hook_1: initializing"); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +sample_init_2(krb5_context context, void **data) +{ + *data = &sample_data_2; + krb5_warn(context, 0, "sample_hook_2: initializing"); + return 0; +} + +static void KRB5_CALLCONV +sample_fini(void *data) +{ + krb5_warn(NULL, 0, "sample_fini: finalizing"); +} + +static krb5_error_code KRB5_CALLCONV +sample_chpass_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + return sample_log(context, data, stage, "chpass", code, princ); +} + +static krb5_error_code KRB5_CALLCONV +sample_chpass_with_key_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_key_data, + krb5_key_data *key_data) +{ + return sample_log(context, data, stage, "chpass_with_key", code, princ); +} + +static krb5_error_code KRB5_CALLCONV +sample_create_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t ent, + uint32_t mask, + const char *password) +{ + return sample_log(context, data, stage, "create", code, ent->principal); +} + +static krb5_error_code KRB5_CALLCONV +sample_modify_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + kadm5_principal_ent_t ent, + uint32_t mask) +{ + return sample_log(context, data, stage, "modify", code, ent->principal); +} + +static krb5_error_code KRB5_CALLCONV +sample_delete_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ) +{ + return sample_log(context, data, stage, "delete", code, princ); +} + +static krb5_error_code KRB5_CALLCONV +sample_randkey_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ) +{ + return sample_log(context, data, stage, "randkey", code, princ); +} + +static krb5_error_code KRB5_CALLCONV +sample_rename_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal source, + krb5_const_principal target) +{ + return sample_log(context, data, stage, "rename", code, source); +} + +static krb5_error_code KRB5_CALLCONV +sample_set_keys_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + size_t n_keys, + krb5_keyblock *keyblocks) +{ + return sample_log(context, data, stage, "set_keys", code, princ); +} + +static krb5_error_code KRB5_CALLCONV +sample_prune_hook(krb5_context context, + void *data, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + int kvno) +{ + return sample_log(context, data, stage, "prune", code, princ); +} + + +static const kadm5_hook_ftable sample_hook_1 = { + KADM5_HOOK_VERSION_V1, + sample_init_1, + sample_fini, + "sample_hook_1", + "Heimdal", + sample_chpass_hook, + sample_chpass_with_key_hook, + sample_create_hook, + sample_modify_hook, + sample_delete_hook, + sample_randkey_hook, + sample_rename_hook, + sample_set_keys_hook, + sample_prune_hook, +}; + +static const kadm5_hook_ftable sample_hook_2 = { + KADM5_HOOK_VERSION_V1, + sample_init_2, + sample_fini, + "sample_hook_2", + "Heimdal", + sample_chpass_hook, + sample_chpass_with_key_hook, + sample_create_hook, + sample_modify_hook, + sample_delete_hook, + sample_randkey_hook, + sample_rename_hook, + sample_set_keys_hook, + sample_prune_hook, +}; + +/* Arrays of pointers, because hooks may be different versions/sizes */ +static const kadm5_hook_ftable *const sample_hooks[] = { + &sample_hook_1, + &sample_hook_2, +}; + +krb5_error_code +kadm5_hook_plugin_load(krb5_context context, + krb5_get_instance_func_t *get_instance, + size_t *num_hooks, + const kadm5_hook_ftable *const **hooks); + +static uintptr_t KRB5_LIB_CALL +sample_hook_get_instance(const char *libname) +{ + if (strcmp(libname, "kadm5") == 0) + return kadm5_get_instance(libname); + else if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} + +krb5_error_code +kadm5_hook_plugin_load(krb5_context context, + krb5_get_instance_func_t *get_instance, + size_t *num_hooks, + const kadm5_hook_ftable *const **hooks) +{ + *get_instance = sample_hook_get_instance; + *num_hooks = sizeof(sample_hooks) / sizeof(sample_hooks[0]); + *hooks = sample_hooks; + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/sample_passwd_check.c b/third_party/heimdal/lib/kadm5/sample_passwd_check.c new file mode 100644 index 0000000..6df9513 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/sample_passwd_check.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* $Id$ */ + +#include +#include +#include + +const char* check_length(krb5_context, krb5_principal, krb5_data *); + +/* specify the api-version this library conforms to */ + +int version = 0; + +/* just check the length of the password, this is what the default + check does, but this lets you specify the minimum length in + krb5.conf */ +const char* +check_length(krb5_context context, + krb5_principal prinipal, + krb5_data *password) +{ + int min_length = krb5_config_get_int_default(context, NULL, 6, + "password_quality", + "min_length", + NULL); + if(password->length < min_length) + return "Password too short"; + return NULL; +} + +#ifdef DICTPATH + +/* use cracklib to check password quality; this requires a patch for + cracklib that can be found at + ftp://ftp.pdc.kth.se/pub/krb/src/cracklib.patch */ + +const char* +check_cracklib(krb5_context context, + krb5_principal principal, + krb5_data *password) +{ + char *s = malloc(password->length + 1); + char *msg; + char *strings[2]; + if(s == NULL) + return NULL; /* XXX */ + strings[0] = principal->name.name_string.val[0]; /* XXX */ + strings[1] = NULL; + memcpy(s, password->data, password->length); + s[password->length] = '\0'; + msg = FascistCheck(s, DICTPATH, strings); + memset(s, 0, password->length); + free(s); + return msg; +} +#endif diff --git a/third_party/heimdal/lib/kadm5/send_recv.c b/third_party/heimdal/lib/kadm5/send_recv.c new file mode 100644 index 0000000..cf52fcd --- /dev/null +++ b/third_party/heimdal/lib/kadm5/send_recv.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1997-2003, 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +_kadm5_client_send(kadm5_client_context *context, krb5_storage *sp) +{ + krb5_data msg, out; + krb5_error_code ret; + size_t len; + krb5_storage *sock; + + assert(context->sock != rk_INVALID_SOCKET); + + len = krb5_storage_seek(sp, 0, SEEK_CUR); + ret = krb5_data_alloc(&msg, len); + if (ret) { + krb5_clear_error_message(context->context); + return ret; + } + krb5_storage_seek(sp, 0, SEEK_SET); + krb5_storage_read(sp, msg.data, msg.length); + + ret = krb5_mk_priv(context->context, context->ac, &msg, &out, NULL); + krb5_data_free(&msg); + if(ret) + return ret; + + sock = krb5_storage_from_socket(context->sock); + if(sock == NULL) { + krb5_data_free(&out); + return krb5_enomem(context->context); + } + + ret = krb5_store_data(sock, out); + if (ret) + krb5_clear_error_message(context->context); + krb5_storage_free(sock); + krb5_data_free(&out); + return ret; +} + +kadm5_ret_t +_kadm5_client_recv(kadm5_client_context *context, krb5_data *reply) +{ + krb5_error_code ret; + krb5_data data; + krb5_storage *sock; + + sock = krb5_storage_from_socket(context->sock); + if (sock == NULL) + return krb5_enomem(context->context); + ret = krb5_ret_data(sock, &data); + + krb5_storage_free(sock); + krb5_clear_error_message(context->context); + if(ret == KRB5_CC_END) + return KADM5_RPC_ERROR; + else if(ret) + return ret; + + ret = krb5_rd_priv(context->context, context->ac, &data, reply, NULL); + krb5_data_free(&data); + return ret; +} + diff --git a/third_party/heimdal/lib/kadm5/server_glue.c b/third_party/heimdal/lib/kadm5/server_glue.c new file mode 100644 index 0000000..4b430b6 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/server_glue.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +kadm5_init_with_password(const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_password(client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_password_ctx(krb5_context context, + const char *client_name, + const char *password, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_password_ctx(context, + client_name, + password, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_skey(const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_skey(client_name, + keytab, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_skey_ctx(krb5_context context, + const char *client_name, + const char *keytab, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_skey_ctx(context, + client_name, + keytab, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_creds(const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_creds(client_name, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} + +kadm5_ret_t +kadm5_init_with_creds_ctx(krb5_context context, + const char *client_name, + krb5_ccache ccache, + const char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +{ + return kadm5_s_init_with_creds_ctx(context, + client_name, + ccache, + service_name, + realm_params, + struct_version, + api_version, + server_handle); +} diff --git a/third_party/heimdal/lib/kadm5/server_hooks.c b/third_party/heimdal/lib/kadm5/server_hooks.c new file mode 100644 index 0000000..0973382 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/server_hooks.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "kadm5_locl.h" + +static const char *kadm5_hook_plugin_deps[] = { + "kadm5", + "krb5", + NULL +}; + +struct heim_plugin_data kadm5_hook_plugin_data = { + "kadm5", + "kadm5_hook", + KADM5_HOOK_VERSION_V1, + kadm5_hook_plugin_deps, + kadm5_get_instance +}; + +void +_kadm5_s_set_hook_error_message(kadm5_server_context *context, + krb5_error_code ret, + const char *op, + const struct kadm5_hook_ftable *hook, + enum kadm5_hook_stage stage) +{ + assert(ret != 0); + + krb5_set_error_message(context->context, ret, + "%s hook `%s' failed %s-commit", + op, hook->name, + stage == KADM5_HOOK_STAGE_PRECOMMIT ? "pre" : "post"); +} + +kadm5_ret_t +_kadm5_s_init_hooks(kadm5_server_context *ctx) +{ + krb5_context context = ctx->context; + char **dirs; + + dirs = krb5_config_get_strings(context, NULL, "kadmin", + "plugin_dir", NULL); + if (dirs == NULL) + return 0; + + _krb5_load_plugins(context, "kadm5", (const char **)dirs); + krb5_config_free_strings(dirs); + + return 0; +} + +void +_kadm5_s_free_hooks(kadm5_server_context *ctx) +{ + _krb5_unload_plugins(ctx->context, "kadm5"); +} + +uintptr_t KRB5_LIB_CALL +kadm5_get_instance(const char *libname) +{ + static const char *instance = "libkadm5"; + + if (strcmp(libname, "kadm5") == 0) + return (uintptr_t)instance; + else if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/set_keys.c b/third_party/heimdal/lib/kadm5/set_keys.c new file mode 100644 index 0000000..c30c5d8 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/set_keys.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 1997 - 2001, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +/* + * Set the keys of `ent' to the string-to-key of `password' + */ + +kadm5_ret_t +_kadm5_set_keys(kadm5_server_context *context, + hdb_entry *ent, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + const char *password) +{ + Key *keys; + size_t num_keys; + kadm5_ret_t ret; + + ret = hdb_generate_key_set_password_with_ks_tuple(context->context, + ent->principal, + password, + ks_tuple, n_ks_tuple, + &keys, &num_keys); + if (ret) + return ret; + + _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); + ent->keys.val = keys; + ent->keys.len = num_keys; + + hdb_entry_set_pw_change_time(context->context, ent, 0); + + if (krb5_config_get_bool_default(context->context, NULL, FALSE, + "kadmin", "save-password", NULL)) + { + ret = hdb_entry_set_password(context->context, context->db, + ent, password); + if (ret) + return ret; + } + + return 0; +} + +static void +setup_Key(Key *k, Salt *s, krb5_key_data *kd, size_t kd_offset) +{ + memset(k, 0, sizeof (*k)); /* sets mkvno and salt */ + k->key.keytype = kd[kd_offset].key_data_type[0]; + k->key.keyvalue.length = kd[kd_offset].key_data_length[0]; + k->key.keyvalue.data = kd[kd_offset].key_data_contents[0]; + + if(kd[kd_offset].key_data_ver == 2) { + memset(s, 0, sizeof (*s)); + s->type = kd[kd_offset].key_data_type[1]; + s->salt.length = kd[kd_offset].key_data_length[1]; + s->salt.data = kd[kd_offset].key_data_contents[1]; + k->salt = s; + } +} + +/* + * Set the keys of `ent' to (`n_key_data', `key_data') + */ + +kadm5_ret_t +_kadm5_set_keys2(kadm5_server_context *context, + hdb_entry *ent, + int16_t n_key_data, + krb5_key_data *key_data) +{ + krb5_error_code ret; + size_t i, k; + HDB_extension ext; + HDB_extension *extp = NULL; + HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys; + Key key; + Salt salt; + Keys keys; + hdb_keyset hkset; + krb5_kvno kvno = -1; + int one_key_set = 1; + int replace_hist_keys = 0; + + if (n_key_data == 0) { + /* Clear all keys! */ + ret = hdb_clear_extension(context->context, ent, + choice_HDB_extension_data_hist_keys); + if (ret) + return ret; + free_Keys(&ent->keys); + return 0; + } + + memset(&keys, 0, sizeof (keys)); + memset(&hkset, 0, sizeof (hkset)); /* set set_time */ + memset(&ext, 0, sizeof (ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_hist_keys; + memset(hist_keys, 0, sizeof (*hist_keys)); + + for (i = 0; i < n_key_data; i++) { + if (kvno != -1 && kvno != key_data[i].key_data_kvno) { + one_key_set = 0; + break; + } + kvno = key_data[i].key_data_kvno; + } + if (one_key_set) { + /* + * If we're updating KADM5_KEY_DATA with a single keyset then we + * assume we must be setting the principal's kvno as well! + * + * Just have to be careful about old clients that might have + * sent 0 as the kvno... This may seem ugly, but it's the price + * of backwards compatibility with pre-multi-kvno kadmin clients + * (besides, who's to say that updating KADM5_KEY_DATA requires + * updating the entry's kvno?) + * + * Note that we do nothing special for the case where multiple + * keysets are given but the entry's kvno is not set and not in + * the given set of keysets. If this happens we'll just update + * the key history only and leave the current keyset alone. + */ + if (kvno == 0) { + /* Force kvno to 1 if it was 0; (ank would do this anyways) */ + if (ent->kvno == 0) + ent->kvno = 1; + /* Below we need key_data[*].kvno to be reasonable */ + for (i = 0; i < n_key_data; i++) + key_data[i].key_data_kvno = ent->kvno; + } else { + /* + * Or force the entry's kvno to match the one from the new, + * singular keyset + */ + ent->kvno = kvno; + } + } + + for (i = 0; i < n_key_data; i++) { + if (key_data[i].key_data_kvno == ent->kvno) { + /* A current key; add to current key set */ + setup_Key(&key, &salt, key_data, i); + ret = add_Keys(&keys, &key); + if (ret) + goto out; + continue; + } + + /* + * This kvno is historical. Build an hdb_keyset for keys of + * this enctype and add them to the new key history. + */ + for (k = 0; k < hist_keys->len; k++) { + if (hist_keys->val[k].kvno == key_data[i].key_data_kvno) + break; + } + if (hist_keys->len > k && + hist_keys->val[k].kvno == key_data[i].key_data_kvno) + /* We've added all keys of this kvno already (see below) */ + continue; + + memset(&hkset, 0, sizeof (hkset)); /* set set_time */ + hkset.kvno = key_data[i].key_data_kvno; + for (k = 0; k < n_key_data; k++) { + /* Find all keys of this kvno and add them to the new keyset */ + if (key_data[k].key_data_kvno != hkset.kvno) + continue; + + setup_Key(&key, &salt, key_data, k); + ret = add_Keys(&hkset.keys, &key); + if (ret) { + free_hdb_keyset(&hkset); + goto out; + } + } + ret = add_HDB_Ext_KeySet(hist_keys, &hkset); + free_hdb_keyset(&hkset); + if (ret) + goto out; + replace_hist_keys = 1; + } + + if (replace_hist_keys) + /* No key history given -> leave it alone */ + extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (extp != NULL) { + HDB_Ext_KeySet *old_hist_keys; + + /* + * Try to keep the very useful set_time values from the old hist + * keys. kadm5 loses this info, so this heuristic is the best we + * can do. + */ + old_hist_keys = &extp->data.u.hist_keys; + for (i = 0; i < old_hist_keys->len; i++) { + if (old_hist_keys->val[i].set_time == NULL) + continue; + for (k = 0; k < hist_keys->len; k++) { + if (hist_keys->val[k].kvno != old_hist_keys->val[k].kvno) + continue; + hist_keys->val[k].set_time = old_hist_keys->val[k].set_time; + old_hist_keys->val[k].set_time = NULL; + } + } + } + + if (replace_hist_keys) { + /* If hist keys not given in key_data then don't blow away hist_keys */ + ret = hdb_replace_extension(context->context, ent, &ext); + if (ret) + goto out; + } + + /* + * A structure copy is more efficient here than this would be: + * + * copy_Keys(&keys, &ent->keys); + * free_Keys(&keys); + * + * Of course, the above hdb_replace_extension() is not at all efficient... + */ + free_HDB_extension(&ext); + free_Keys(&ent->keys); + free_hdb_keyset(&hkset); + ent->keys = keys; + hdb_entry_set_pw_change_time(context->context, ent, 0); + hdb_entry_clear_password(context->context, ent); + + return 0; + +out: + free_Keys(&keys); + free_HDB_extension(&ext); + return ret; +} + +/* + * Set the keys of `ent' to `n_keys, keys' + */ + +kadm5_ret_t +_kadm5_set_keys3(kadm5_server_context *context, + hdb_entry *ent, + int n_keys, + krb5_keyblock *keyblocks) +{ + krb5_error_code ret; + int i; + unsigned len; + Key *keys; + + len = n_keys; + keys = malloc (len * sizeof(*keys)); + if (keys == NULL && len != 0) + return krb5_enomem(context->context); + + _kadm5_init_keys (keys, len); + + for(i = 0; i < n_keys; i++) { + keys[i].mkvno = NULL; + ret = krb5_copy_keyblock_contents (context->context, + &keyblocks[i], + &keys[i].key); + if(ret) + goto out; + keys[i].salt = NULL; + } + _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); + ent->keys.len = len; + ent->keys.val = keys; + + hdb_entry_set_pw_change_time(context->context, ent, 0); + hdb_entry_clear_password(context->context, ent); + + return 0; + out: + _kadm5_free_keys (context->context, len, keys); + return ret; +} + +/* + * + */ + +static int +is_des_key_p(int keytype) +{ + return keytype == ETYPE_DES_CBC_CRC || + keytype == ETYPE_DES_CBC_MD4 || + keytype == ETYPE_DES_CBC_MD5; +} + + +/* + * Set the keys of `ent' to random keys and return them in `n_keys' + * and `new_keys'. + */ + +kadm5_ret_t +_kadm5_set_keys_randomly (kadm5_server_context *context, + hdb_entry *ent, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock **new_keys, + int *n_keys) +{ + krb5_keyblock *kblock = NULL; + kadm5_ret_t ret = 0; + int des_keyblock; + size_t i, num_keys; + Key *keys; + + ret = hdb_generate_key_set(context->context, ent->principal, + ks_tuple, n_ks_tuple, &keys, &num_keys, 1); + if (ret) + return ret; + + kblock = malloc(num_keys * sizeof(kblock[0])); + if (kblock == NULL) { + ret = krb5_enomem(context->context); + _kadm5_free_keys (context->context, num_keys, keys); + return ret; + } + memset(kblock, 0, num_keys * sizeof(kblock[0])); + + des_keyblock = -1; + for (i = 0; i < num_keys; i++) { + + /* + * To make sure all des keys are the the same we generate only + * the first one and then copy key to all other des keys. + */ + + if (des_keyblock != -1 && is_des_key_p(keys[i].key.keytype)) { + ret = krb5_copy_keyblock_contents (context->context, + &kblock[des_keyblock], + &kblock[i]); + if (ret) + goto out; + kblock[i].keytype = keys[i].key.keytype; + } else { + ret = krb5_generate_random_keyblock (context->context, + keys[i].key.keytype, + &kblock[i]); + if (ret) + goto out; + + if (is_des_key_p(keys[i].key.keytype)) + des_keyblock = i; + } + + ret = krb5_copy_keyblock_contents (context->context, + &kblock[i], + &keys[i].key); + if (ret) + goto out; + } + +out: + if(ret) { + for (i = 0; i < num_keys; ++i) + krb5_free_keyblock_contents(context->context, &kblock[i]); + free(kblock); + _kadm5_free_keys(context->context, num_keys, keys); + return ret; + } + + _kadm5_free_keys(context->context, ent->keys.len, ent->keys.val); + ent->keys.val = keys; + ent->keys.len = num_keys; + if (n_keys && new_keys) { + *new_keys = kblock; + *n_keys = num_keys; + } else { + for (i = 0; i < num_keys; ++i) + krb5_free_keyblock_contents(context->context, &kblock[i]); + free(kblock); + } + + hdb_entry_set_pw_change_time(context->context, ent, 0); + hdb_entry_clear_password(context->context, ent); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/set_modifier.c b/third_party/heimdal/lib/kadm5/set_modifier.c new file mode 100644 index 0000000..dd0e427 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/set_modifier.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +RCSID("$Id$"); + +kadm5_ret_t +_kadm5_set_modifier(kadm5_server_context *context, + hdb_entry *ent) +{ + kadm5_ret_t ret; + if(ent->modified_by == NULL){ + ent->modified_by = malloc(sizeof(*ent->modified_by)); + if(ent->modified_by == NULL) + return krb5_enomem(context->context); + } else + free_Event(ent->modified_by); + ent->modified_by->time = time(NULL); + ret = krb5_copy_principal(context->context, context->caller, + &ent->modified_by->principal); + return ret; +} + diff --git a/third_party/heimdal/lib/kadm5/setkey3_s.c b/third_party/heimdal/lib/kadm5/setkey3_s.c new file mode 100644 index 0000000..584c194 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/setkey3_s.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1997-2001, 2003, 2005-2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" + +struct setkey_principal_hook_ctx { + kadm5_server_context *context; + enum kadm5_hook_stage stage; + krb5_error_code code; + krb5_const_principal princ; + uint32_t flags; + size_t n_ks_tuple; + krb5_key_salt_tuple *ks_tuple; + size_t n_keys; + krb5_keyblock *keys; +}; + +static krb5_error_code KRB5_LIB_CALL +setkey_principal_hook_cb(krb5_context context, + const void *hook, + void *hookctx, + void *userctx) +{ + krb5_error_code ret; + const struct kadm5_hook_ftable *ftable = hook; + struct setkey_principal_hook_ctx *ctx = userctx; + + ret = ftable->set_keys(context, hookctx, + ctx->stage, ctx->code, + ctx->princ, ctx->flags, + ctx->n_ks_tuple, ctx->ks_tuple, + ctx->n_keys, ctx->keys); + if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE) + _kadm5_s_set_hook_error_message(ctx->context, ret, "setkey", + hook, ctx->stage); + + /* only pre-commit plugins can abort */ + if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT) + ret = KRB5_PLUGIN_NO_HANDLE; + + return ret; +} + +static kadm5_ret_t +setkey_principal_hook(kadm5_server_context *context, + enum kadm5_hook_stage stage, + krb5_error_code code, + krb5_const_principal princ, + uint32_t flags, + size_t n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + size_t n_keys, + krb5_keyblock *keyblocks) +{ + krb5_error_code ret; + struct setkey_principal_hook_ctx ctx; + + ctx.context = context; + ctx.stage = stage; + ctx.code = code; + ctx.princ = princ; + ctx.flags = flags; + ctx.n_ks_tuple = n_ks_tuple; + ctx.ks_tuple = ks_tuple; + ctx.n_keys = n_keys; + ctx.keys = keyblocks; + + ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data, + 0, &ctx, setkey_principal_hook_cb); + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} + +/** + * Server-side function to set new keys for a principal. + */ +kadm5_ret_t +kadm5_s_setkey_principal_3(void *server_handle, + krb5_principal princ, + krb5_boolean keepold, + int n_ks_tuple, + krb5_key_salt_tuple *ks_tuple, + krb5_keyblock *keyblocks, int n_keys) +{ + kadm5_server_context *context = server_handle; + hdb_entry ent; + kadm5_ret_t ret = 0; + size_t i; + + memset(&ent, 0, sizeof(ent)); + if (!context->keep_open) + ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); + if (ret) + return ret; + + ret = kadm5_log_init(context); + if (ret) { + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return ret; + } + + /* NOTE: We do not use hdb_fetch_kvno() here (maybe we should?) */ + ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, + HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, + 0, &ent); + if (ret) { + (void) kadm5_log_end(context); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return ret; + } + + ret = setkey_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, 0, + princ, keepold ? KADM5_HOOK_FLAG_KEEPOLD : 0, + n_ks_tuple, ks_tuple, n_keys, keyblocks); + if (ret) { + (void) kadm5_log_end(context); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return ret; + } + + if (keepold) { + ret = hdb_add_current_keys_to_history(context->context, &ent); + } else + ret = hdb_clear_extension(context->context, &ent, + choice_HDB_extension_data_hist_keys); + + /* + * Though in practice all real calls to this function will pass an empty + * ks_tuple, and cannot in any case employ any salts that require + * additional data, we go the extra mile to set any requested salt type + * along with a zero length salt value. While we're at it we check that + * each ks_tuple's enctype matches the corresponding key enctype. + */ + if (ret == 0) { + free_Keys(&ent.keys); + for (i = 0; i < n_keys; ++i) { + Key k; + Salt s; + + k.mkvno = 0; + k.key = keyblocks[i]; + if (n_ks_tuple == 0) + k.salt = 0; + else { + if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) { + ret = KADM5_SETKEY3_ETYPE_MISMATCH; + break; + } + s.type = ks_tuple[i].ks_salttype; + s.salt.data = 0; + s.opaque = 0; + k.salt = &s; + } + if ((ret = add_Keys(&ent.keys, &k)) != 0) + break; + } + } + + if (ret == 0) { + ent.kvno++; + ent.flags.require_pwchange = 0; + hdb_entry_set_pw_change_time(context->context, &ent, 0); + hdb_entry_clear_password(context->context, &ent); + + if ((ret = hdb_seal_keys(context->context, context->db, + &ent)) == 0 + && (ret = _kadm5_set_modifier(context, &ent)) == 0 + && (ret = _kadm5_bump_pw_expire(context, &ent)) == 0) + ret = kadm5_log_modify(context, &ent, + KADM5_ATTRIBUTES | KADM5_PRINCIPAL | + KADM5_MOD_NAME | KADM5_MOD_TIME | + KADM5_KEY_DATA | KADM5_KVNO | + KADM5_PW_EXPIRATION | KADM5_TL_DATA); + } + + (void) setkey_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret, + princ, keepold, n_ks_tuple, ks_tuple, + n_keys, keyblocks); + + hdb_free_entry(context->context, context->db, &ent); + (void) kadm5_log_end(context); + if (!context->keep_open) + context->db->hdb_close(context->context, context->db); + return _kadm5_error_code(ret); +} diff --git a/third_party/heimdal/lib/kadm5/test_pw_quality.c b/third_party/heimdal/lib/kadm5/test_pw_quality.c new file mode 100644 index 0000000..6544afd --- /dev/null +++ b/third_party/heimdal/lib/kadm5/test_pw_quality.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2003, 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include "admin.h" + +static int version_flag; +static int help_flag; +static char *principal; +static char *password; + +static struct getargs args[] = { + { "principal", 0, arg_string, &principal, NULL, NULL }, + { "password", 0, arg_string, &password, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + krb5_principal p; + const char *s; + krb5_data pw_data; + + krb5_program_setup(&context, argc, argv, args, num_args, NULL); + + if(help_flag) + krb5_std_usage(0, args, num_args); + if(version_flag) { + print_version(NULL); + exit(0); + } + + if (principal == NULL) + krb5_errx(context, 1, "no principal given"); + if (password == NULL) + krb5_errx(context, 1, "no password given"); + + ret = krb5_parse_name(context, principal, &p); + if (ret) + krb5_errx(context, 1, "krb5_parse_name: %s", principal); + + pw_data.data = password; + pw_data.length = strlen(password); + + kadm5_setup_passwd_quality_check (context, NULL, NULL); + ret = kadm5_add_passwd_quality_verifier(context, NULL); + if (ret) + krb5_errx(context, 1, "kadm5_add_passwd_quality_verifier"); + + s = kadm5_check_password_quality (context, p, &pw_data); + if (s) + krb5_errx(context, 1, "kadm5_check_password_quality:\n%s", s); + + krb5_free_principal(context, p); + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/kadm5/version-script-client.map b/third_party/heimdal/lib/kadm5/version-script-client.map new file mode 100644 index 0000000..56a4ff3 --- /dev/null +++ b/third_party/heimdal/lib/kadm5/version-script-client.map @@ -0,0 +1,69 @@ +HEIMDAL_KADM5_CLIENT_1.0 { + global: + et_kadm5_error_table; + initialize_kadm5_error_table; + initialize_kadm5_error_table_r; + kadm5_ad_init_with_password; + kadm5_ad_init_with_password_ctx; + kadm5_all_keys_are_bogus; + kadm5_c_chpass_principal; + kadm5_c_chpass_principal_with_key; + kadm5_c_create_principal; + kadm5_c_delete_principal; + kadm5_c_destroy; + kadm5_c_dup_context; + kadm5_c_flush; + kadm5_c_get_principal; + kadm5_c_get_principals; + kadm5_c_get_privs; + kadm5_c_init_with_creds; + kadm5_c_init_with_creds_ctx; + kadm5_c_init_with_password; + kadm5_c_init_with_password_ctx; + kadm5_c_init_with_skey; + kadm5_c_init_with_skey_ctx; + kadm5_c_iter_principals; + kadm5_c_get_privs; + kadm5_c_modify_principal; + kadm5_c_prune_principal; + kadm5_c_randkey_principal; + kadm5_c_rename_principal; + kadm5_chpass_principal; + kadm5_chpass_principal_with_key; + kadm5_create_principal; + kadm5_delete_principal; + kadm5_destroy; + kadm5_dup_context; + kadm5_flush; + kadm5_free_key_data; + kadm5_free_name_list; + kadm5_free_principal_ent; + kadm5_get_principal; + kadm5_get_principals; + kadm5_get_privs; + kadm5_init_with_creds; + kadm5_init_with_creds_ctx; + kadm5_init_with_password; + kadm5_init_with_password_ctx; + kadm5_init_with_skey; + kadm5_init_with_skey_ctx; + kadm5_iter_principals; + kadm5_modify_principal; + kadm5_randkey_principal; + kadm5_randkey_principal_3; + kadm5_rename_principal; + kadm5_ret_key_data; + kadm5_ret_principal_ent; + kadm5_ret_principal_ent_mask; + kadm5_ret_tl_data; + kadm5_some_keys_are_bogus; + kadm5_store_key_data; + kadm5_store_principal_ent; + kadm5_store_principal_ent_mask; + kadm5_store_tl_data; + _kadm5_client_recv; + _kadm5_client_send; + _kadm5_connect; + local: + *; +}; diff --git a/third_party/heimdal/lib/kadm5/version-script.map b/third_party/heimdal/lib/kadm5/version-script.map new file mode 100644 index 0000000..6de88fc --- /dev/null +++ b/third_party/heimdal/lib/kadm5/version-script.map @@ -0,0 +1,98 @@ +# $Id$ + +HEIMDAL_KAMD5_SERVER_1.0 { + global: + kadm5_ad_init_with_password; + kadm5_ad_init_with_password_ctx; + kadm5_all_keys_are_bogus; + kadm5_add_passwd_quality_verifier; + kadm5_check_password_quality; + kadm5_chpass_principal; + kadm5_chpass_principal_3; + kadm5_chpass_principal_with_key; + kadm5_chpass_principal_with_key_3; + kadm5_create_policy; + kadm5_create_principal; + kadm5_create_principal_3; + kadm5_delete_principal; + kadm5_destroy; + kadm5_dup_context; + kadm5_decrypt_key; + kadm5_delete_policy; + kadm5_flush; + kadm5_free_key_data; + kadm5_free_name_list; + kadm5_free_policy_ent; + kadm5_free_principal_ent; + kadm5_get_instance; + kadm5_get_policy; + kadm5_get_policies; + kadm5_get_principal; + kadm5_get_principals; + kadm5_get_privs; + kadm5_init_with_creds; + kadm5_init_with_creds_ctx; + kadm5_init_with_password; + kadm5_init_with_password_ctx; + kadm5_init_with_skey; + kadm5_init_with_skey_ctx; + kadm5_iter_principals; + kadm5_lock; + kadm5_modify_principal; + kadm5_modify_policy; + kadm5_prune_principal; + kadm5_randkey_principal; + kadm5_randkey_principal_3; + kadm5_rename_principal; + kadm5_ret_key_data; + kadm5_ret_principal_ent; + kadm5_ret_principal_ent_mask; + kadm5_ret_tl_data; + kadm5_setup_passwd_quality_check; + kadm5_setkey_principal; + kadm5_setkey_principal_3; + kadm5_some_keys_are_bogus; + kadm5_store_key_data; + kadm5_store_principal_ent; + kadm5_store_principal_ent_mask; + kadm5_store_principal_ent_nokeys; + kadm5_store_tl_data; + kadm5_unlock; + kadm5_s_init_with_password_ctx; + kadm5_s_init_with_password; + kadm5_s_init_with_skey_ctx; + kadm5_s_init_with_skey; + kadm5_s_init_with_creds_ctx; + kadm5_s_init_with_creds; + kadm5_s_chpass_principal_cond; + kadm5_s_create_principal_with_key; + kadm5_log_exclusivelock; + kadm5_log_set_version; + kadm5_log_sharedlock; + kadm5_log_signal_master; + kadm5_log_signal_socket; + kadm5_log_previous; + kadm5_log_goto_first; + kadm5_log_goto_end; + kadm5_log_foreach; + kadm5_log_get_version_fd; + kadm5_log_get_version; + kadm5_log_recover; + kadm5_log_replay; + kadm5_log_end; + kadm5_log_reinit; + kadm5_log_init; + kadm5_log_init_nb; + kadm5_log_init_nolock; + kadm5_log_init_sharedlock; + kadm5_log_next; + kadm5_log_nop; + kadm5_log_truncate; + kadm5_log_modify; + _kadm5_acl_check_permission; + _kadm5_unmarshal_params; + _kadm5_s_get_db; + _kadm5_privs_to_string; + local: + *; +}; diff --git a/third_party/heimdal/lib/kafs/ChangeLog b/third_party/heimdal/lib/kafs/ChangeLog new file mode 100644 index 0000000..302146a --- /dev/null +++ b/third_party/heimdal/lib/kafs/ChangeLog @@ -0,0 +1,572 @@ +2008-07-17 Love Hörnquist Åstrand + + * common.c: Try afs/cell@REALM before afs@REALM since that is what + OpenAFS folks have been saying is best pratices for some time + now. Patch from Derrick Brashear. + +2008-04-15 Love Hörnquist Åstrand + * afssys.c: Avoid using entry points depending on _IOWR if there + is no _IOWR (on cygwin). + +2007-07-10 Love Hörnquist Åstrand + + * Makefile.am: New library version. + +2007-05-10 Love Hörnquist Åstrand + + * kafs.h: Add VIOCSETTOK2 + +2006-10-21 Love Hörnquist Åstrand + + * Makefile.am: unbreak previous + + * Makefile.am: split dist and nodist sources + +2006-10-20 Love Hörnquist Åstrand + + * Makefile.am: add more files + +2006-05-01 Love Hörnquist Åstrand + + * kafs.3: Spelling, from Björn Sandell. + +2006-04-11 Love Hörnquist Åstrand + + * afssys.c: use afs_ioctlnum, From Tomas Olsson + +2006-04-10 Love Hörnquist Åstrand + + * afssys.c: Try harder to get the pioctl to work via the /proc or + /dev interface, OpenAFS choose to reuse the same ioctl number, + while Arla didn't. Also, try new ioctl before the the old + syscalls. + + * afskrb5.c (afslog_uid_int): use the simpler + krb5_principal_get_realm function. + +2005-12-21 Love Hörnquist Åstrand + + * Makefile.am: Remove dependency on config.h, breaks IRIX build, + could depend on libkafs_la_OBJECTS, but that is just asking for + trubble. + +2005-10-20 Love Hörnquist Åstrand + + * afssys.c (k_hasafs_recheck): new function, allow rechecking if + AFS client have started now, internaly it resets the internal + state from k_hasafs() and retry retry the probing. The problem + with calling k_hasaf() is that is plays around with signals, and + that cases problem for some systems/applications. + +2005-10-02 Love Hörnquist Åstrand + + * kafs_locl.h: Maybe include . + + * afssys.c: Mac OS X 10.4 needs a runtime check if we are going to + use the syscall, there is no cpp define to use to check the + version. Every after 10.0 (darwin 8.0) uses the /dev/ version of + the pioctl. + +2005-10-01 Love Hörnquist Åstrand + + * afssys.c: Support the new MacOS X 10.4 ioctl interface that is a + device node. Patched from Tomas Olson . + +2005-08-26 Love Hörnquist Åstrand + + * afskrb5.c: Default to use 2b tokens. + +2005-06-17 Love Hörnquist Åstrand + + * common.c: rename index to idx + + * afssys.c (k_afs_cell_of_file): unconst path + +2005-06-02 Love Hörnquist Åstrand + + * use struct kafs_data everywhere, don't mix with the typedef + kafs_data + + * roken_rename.h: rename more resolve.c symbols + + * afssys.c: Don't building map_syscall_name_to_number where its + not used. + +2005-02-24 Love Hörnquist Åstrand + + * Makefile.am: bump version to 4:1:4 + +2005-02-03 Love Hörnquist Åstrand + + * kafs.h: de-__P + +2004-12-06 Love Hörnquist Åstrand + + * afskrb5.c: s/KEYTYPE_DES/ETYPE_DES_CBC_CRC/ + +2004-08-09 Love Hörnquist Åstrand + + * afssysdefs.h: ifdef protect AFS_SYSCALL for DragonFly since they + still define __FreeBSD__ (and __FreeBSD_version), but claim that + they will stop doing it some time... + + * afssysdefs.h: dragonflybsd uses 339 just like freebsd5 + +2004-06-22 Love Hörnquist Åstrand + + * afssys.c: s/arla/nnpfs/ + + * afssys.c: support the linux /proc/fs/mumel/afs_ioctl afs + "syscall" interface + +2004-01-22 Love Hörnquist Åstrand + + * common.c: search paths for AFS configuration files for the + OpenAFS MacOS X, fix comment + + * kafs.h: search paths for AFS configuration files for the OpenAFS + MacOS X + +2003-12-02 Love Hörnquist Åstrand + + * common.c: add _PATH_ARLA_OPENBSD & c/o + + * kafs.h: add _PATH_ARLA_OPENBSD & c/o + +2003-11-14 Love Hörnquist Åstrand + + * common.c: typo, Bruno Rohee + +2003-11-08 Love Hörnquist Åstrand + + * kafs.3: spelling, partly from jmc + +2003-09-30 Love Hörnquist Åstrand + + * afskrb5.c (krb5_afslog_uid_home): be even more friendly to the + user and fetch context and id ourself + +2003-09-23 Love Hörnquist Åstrand + + * afskrb5.c (afslog_uid_int): just belive that realm hint the user + passed us + +2003-07-23 Love Hörnquist Åstrand + + * Makefile.am: always include v4 symbols + + * afskrb.c: provide dummy krb_ function to there is no need to + bump major + +2003-06-22 Love Hörnquist Åstrand + + * afskrb5.c (v5_convert): rename one of the two c to cred4 + +2003-04-23 Love Hörnquist Åstrand + + * common.c, kafs.h: drop the int argument (the error code) from + the logging function + +2003-04-22 Johan Danielsson + + * afskrb5.c (v5_convert): better match what other functions do + with values from krb5.conf, like case insensitivity + +2003-04-16 Love Hörnquist Åstrand + + * kafs.3: Change .Fd #include to .In header.h + from Thomas Klausner + +2003-04-14 Love Hörnquist Åstrand + + * Makefile.am: (libkafs_la_LDFLAGS): update version + + * Makefile.am (ROKEN_SRCS): drop strupr.c + + * kafs.3: document kafs_set_verbose + + * common.c (kafs_set_verbose): add function that (re)sets the + logging function + (_kafs_try_get_cred): add function that does (krb_data->get_cred) to + make logging easier (that is now done in this function) + (*): use _kafs_try_get_cred + + * afskrb5.c (get_cred): handle that inst can be the empty string too + (v5_convert): use _kafs_foldup + (krb5_afslog_uid_home): set name + (krb5_afslog_uid_home): ditto + + * afskrb.c (krb_afslog_uid_home): set name + (krb_afslog_uid_home): ditto + + * kafs_locl.h (kafs_data): add name + (_kafs_foldup): internally export + +2003-04-11 Love Hörnquist Åstrand + + * kafs.3: tell that cell-name is uppercased + + * Makefile.am: add INCLUDE_krb4 when using krb4, add INCLUDE_des + when using krb5, add strupr.c + + * afskrb5.c: Check the cell part of the name, not the realm part + when checking if 2b should be used. The reson is afs@REALM might + have updated their servers but not afs/cell@REALM. Add constant + KAFS_RXKAD_2B_KVNO. + +2003-04-06 Love Hörnquist Åstrand + + * kafs.3: s/kerberos/Kerberos/ + +2003-03-19 Love Hörnquist Åstrand + + * kafs.3: spelling, from + + * kafs.3: document the kafs_settoken functions write about the + krb5_appdefault option for kerberos 5 afs tokens fix prototypes + +2003-03-18 Love Hörnquist Åstrand + + * afskrb5.c (kafs_settoken5): change signature to include a + krb5_context, use v5_convert + (v5_convert): new function, converts a krb5_ccreds to a kafs_token in + three diffrent ways, not at all, local 524/2b, and using 524 + (v5_to_kt): add code to do local 524/2b + (get_cred): use v5_convert + + + * kafs.h (kafs_settoken5): change signature to include a + krb5_context + + * Makefile.am: always build the libkafs library now that the + kerberos 5 can stand on their own + + * kafs.3: expose the krb5 functions + + * common.c (kafs_settoken_rxkad): move all content kerberos + version from kafs_settoken to kafs_settoken_rxkad + (_kafs_fixup_viceid): move the fixup the timestamp to make client + happy code here. + (_kafs_v4_to_kt): move all the kerberos 4 dependant parts from + kafs_settoken here. + (*): adapt to kafs_token + + * afskrb5.c (kafs_settoken5): new function, inserts a krb5_creds + into kernel + (v5_to_kt): new function, stores a krb5_creds in struct kafs_token + (get_cred): add a appdefault boolean ("libkafs", realm, "afs-use-524") + that can used to toggle if there should v5 token should be used + directly or converted via 524 first. + + * afskrb.c: move kafs_settoken here, use struct kafs_token + + * kafs_locl.h: include krb5-v4compat.h if needed, define an + internal structure struct kafs_token that carries around for rxkad + data that is independant of kerberos version + +2003-02-18 Love Hörnquist Åstrand + + * dlfcn.h: s/intialize/initialize, from + + +2003-02-08 Assar Westerlund + + * afssysdefs.h: fix FreeBSD section + +2003-02-06 Love Hörnquist Åstrand + + * afssysdefs.h: use syscall 208 on openbsd (all version) use + syscall 339 on freebsd 5.0 and later, use 210 on 4.x and earlier + +2002-08-28 Johan Danielsson + + * kafs.3: move around sections (from NetBSD) + +2002-05-31 Assar Westerlund + + * common.c: remove the trial of afs@REALM for cell != realm, it + tries to use the wrong key for foreign cells + +2002-05-20 Johan Danielsson + + * Makefile.am: version number + +2002-04-18 Johan Danielsson + + * common.c (find_cells): make file parameter const + +2001-11-01 Assar Westerlund + + * add strsep, and bump version to 3:3:3 + +2001-10-27 Assar Westerlund + + * Makefile.am (libkafs_la_LDFLAGS): set version to 3:2:3 + +2001-10-24 Assar Westerlund + + * afskrb.c (afslog_uid_int): handle krb_get_tf_fullname that + cannot take NULLs + (such as the MIT one) + +2001-10-22 Assar Westerlund + + * Makefile.am (ROKEN_SRCS): add strlcpy.c + +2001-10-09 Assar Westerlund + + * Makefile.am (ROKEN_SRCS): add strtok_r.c + * roken_rename.h (dns_srv_order): rename correctly + (strtok_r): add renaming + +2001-09-10 Assar Westerlund + + * kafs.h, common.c: look for configuration files in /etc/arla (the + location in debian's arla package) + +2001-08-26 Assar Westerlund + + * Makefile.am: handle both krb5 and krb4 cases + +2001-07-19 Assar Westerlund + + * Makefile.am (libkafs_la_LDFLAGS): set version to 3:0:3 + +2001-07-12 Assar Westerlund + + * common.c: look in /etc/openafs for debian openafs + * kafs.h: add paths for openafs debian (/etc/openafs) + + * Makefile.am: add required library dependencies + +2001-07-03 Assar Westerlund + + * Makefile.am (libkafs_la_LDFLAGS): set versoin to 2:4:2 + +2001-06-19 Assar Westerlund + + * common.c (_kafs_realm_of_cell): changed to first try exact match + in CellServDB, then exact match in DNS, and finally in-exact match + in CellServDB + +2001-05-18 Johan Danielsson + + * Makefile.am: only build resolve.c if doing renaming + +2001-02-12 Assar Westerlund + + * Makefile.am, roken_rename.h: add rename of dns functions + +2000-12-11 Assar Westerlund + + * Makefile.am (libkafs_la_LDFLAGS): set version to 2:3:2 + +2000-11-17 Assar Westerlund + + * afssysdefs.h: solaris 8 apperently uses 65 + +2000-09-19 Assar Westerlund + + * Makefile.am (libkafs_la_LDFLAGS): bump version to 2:2:2 + +2000-09-12 Johan Danielsson + + * dlfcn.c: correct arguments to some snprintf:s + +2000-07-25 Johan Danielsson + + * Makefile.am: bump version to 2:1:2 + +2000-04-03 Assar Westerlund + + * Makefile.am: set version to 2:0:2 + +2000-03-20 Assar Westerlund + + * afssysdefs.h: make versions later than 5.7 of solaris also use + 73 + +2000-03-16 Assar Westerlund + + * afskrb.c (afslog_uid_int): use krb_get_tf_fullname instead of + krb_get_default_principal + +2000-03-15 Assar Westerlund + + * afssys.c (map_syscall_name_to_number): ignore # at + beginning-of-line + +2000-03-13 Assar Westerlund + + * afssysdefs.h: add 230 for MacOS X per information from + + +1999-12-06 Assar Westerlund + + * Makefile.am: set version to 1:2:1 + +1999-11-22 Assar Westerlund + + * afskrb5.c (afslog_uid_int): handle d->realm == NULL + +1999-11-17 Assar Westerlund + + * afskrb5.c (afslog_uid_int): don't look at the local realm at + all. just use the realm from the ticket file. + +1999-10-20 Assar Westerlund + + * Makefile.am: set version to 1:1:1 + + * afskrb5.c (get_cred): always request a DES key + +Mon Oct 18 17:40:21 1999 Bjoern Groenvall + + * common.c (find_cells): Trim trailing whitespace from + cellname. Lines starting with # are regarded as comments. + +Fri Oct 8 18:17:22 1999 Bjoern Groenvall + + * afskrb.c, common.c : Change code to make a clear distinction + between hinted realm and ticket realm. + + * kafs_locl.h: Added argument realm_hint. + + * common.c (_kafs_get_cred): Change code to acquire the ``best'' + possible ticket. Use cross-cell authentication only as method of + last resort. + + * afskrb.c (afslog_uid_int): Add realm_hint argument and extract + realm from ticket file. + + * afskrb5.c (afslog_uid_int): Added argument realm_hint. + +1999-10-03 Assar Westerlund + + * afskrb5.c (get_cred): update to new krb524_convert_creds_kdc + +1999-08-12 Johan Danielsson + + * Makefile.am: ignore the comlicated aix construct if !krb4 + +1999-07-26 Assar Westerlund + + * Makefile.am: set version to 1:0:1 + +1999-07-22 Assar Westerlund + + * afssysdefs.h: define AFS_SYSCALL to 73 for Solaris 2.7 + +1999-07-07 Assar Westerlund + + * afskrb5.c (krb5_realm_of_cell): new function + + * afskrb.c (krb_realm_of_cell): new function + (afslog_uid_int): call krb_get_lrealm correctly + +1999-06-15 Assar Westerlund + + * common.c (realm_of_cell): rename to _kafs_realm_of_cell and + un-staticize + +Fri Mar 19 14:52:29 1999 Johan Danielsson + + * Makefile.am: add version-info + +Thu Mar 18 11:24:02 1999 Johan Danielsson + + * Makefile.am: include Makefile.am.common + +Sat Feb 27 19:46:21 1999 Johan Danielsson + + * Makefile.am: remove EXTRA_DATA (as of autoconf 2.13/automake + 1.4) + +Thu Feb 11 22:57:37 1999 Johan Danielsson + + * Makefile.am: set AIX_SRC also if !AIX + +Tue Dec 1 14:45:15 1998 Johan Danielsson + + * Makefile.am: fix AIX linkage + +Sun Nov 22 10:40:44 1998 Assar Westerlund + + * Makefile.in (WFLAGS): set + +Sat Nov 21 16:55:19 1998 Johan Danielsson + + * afskrb5.c: add homedir support + +Sun Sep 6 20:16:27 1998 Assar Westerlund + + * add new functionality for specifying the homedir to krb_afslog + et al + +Thu Jul 16 01:27:19 1998 Assar Westerlund + + * afssys.c: reorganize order of definitions. + (try_one, try_two): conditionalize + +Thu Jul 9 18:31:52 1998 Johan Danielsson + + * common.c (realm_of_cell): make the dns fallback work + +Wed Jul 8 01:39:44 1998 Assar Westerlund + + * afssys.c (map_syscall_name_to_number): new function for finding + the number of a syscall given the name on solaris + (k_hasafs): try using map_syscall_name_to_number + +Tue Jun 30 17:19:00 1998 Assar Westerlund + + * afssys.c: rewrite and add support for environment variable + AFS_SYSCALL + + * Makefile.in (distclean): don't remove roken_rename.h + +Fri May 29 19:03:20 1998 Assar Westerlund + + * Makefile.in (roken_rename.h): remove dependency + +Mon May 25 05:25:54 1998 Assar Westerlund + + * Makefile.in (clean): try to remove shared library debris + +Sun Apr 19 09:58:40 1998 Assar Westerlund + + * Makefile.in: add symlink magic for linux + +Sat Apr 4 15:08:48 1998 Assar Westerlund + + * kafs.h: add arla paths + + * common.c (_kafs_afslog_all_local_cells): Try _PATH_ARLA_* + (_realm_of_cell): Try _PATH_ARLA_CELLSERVDB + +Thu Feb 19 14:50:22 1998 Johan Danielsson + + * common.c: Don't store expired tokens (this broke when using + pag-less rsh-sessions, and `non-standard' ticket files). + +Thu Feb 12 11:20:15 1998 Johan Danielsson + + * Makefile.in: Install/uninstall one library at a time. + +Thu Feb 12 05:38:58 1998 Assar Westerlund + + * Makefile.in (install): one library at a time. + +Mon Feb 9 23:40:32 1998 Assar Westerlund + + * common.c (find_cells): ignore empty lines + +Tue Jan 6 04:25:58 1998 Assar Westerlund + + * afssysdefs.h (AFS_SYSCALL): add FreeBSD + +Fri Jan 2 17:08:24 1998 Assar Westerlund + + * kafs.h: new VICEIOCTL's. From + + * afssysdefs.h: Add OpenBSD diff --git a/third_party/heimdal/lib/kafs/Makefile.am b/third_party/heimdal/lib/kafs/Makefile.am new file mode 100644 index 0000000..50d4878 --- /dev/null +++ b/third_party/heimdal/lib/kafs/Makefile.am @@ -0,0 +1,96 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_CPPFLAGS += $(AFS_EXTRA_DEFS) $(ROKEN_RENAME) + +if KRB5 +DEPLIB_krb5 = ../krb5/libkrb5.la $(LIB_hcrypto) +krb5_am_workaround = -I$(top_srcdir)/lib/krb5 +else +DEPLIB_krb5 = +krb5_am_workaround = +endif # KRB5 +AM_CPPFLAGS += $(krb5_am_workaround) + + +if AIX +AFSL_EXP = $(srcdir)/afsl.exp + +if AIX4 +AFS_EXTRA_LD = -bnoentry +else +AFS_EXTRA_LD = -e _nostart +endif + +if AIX_DYNAMIC_AFS +AIX_SRC = +AFS_EXTRA_LIBS = afslib.so +AFS_EXTRA_DEFS = +else +AIX_SRC = afslib.c +AFS_EXTRA_LIBS = +AFS_EXTRA_DEFS = -DSTATIC_AFS +endif + +else +AFSL_EXP = +AIX_SRC = +endif # AIX + +libkafs_la_LIBADD = $(DEPLIB_krb5) $(LIBADD_roken) + +lib_LTLIBRARIES = libkafs.la +libkafs_la_LDFLAGS = -version-info 5:1:5 +foodir = $(libdir) +foo_DATA = $(AFS_EXTRA_LIBS) +# EXTRA_DATA = afslib.so + +CLEANFILES= $(AFS_EXTRA_LIBS) $(ROKEN_SRCS) + +include_HEADERS = kafs.h + +if KRB5 +afskrb5_c = +endif + +if do_roken_rename +ROKEN_SRCS = resolve.c strtok_r.c strlcpy.c strsep.c +endif + +dist_libkafs_la_SOURCES = \ + afssys.c \ + afskrb5.c \ + rxkad_kdf.c \ + common.c \ + $(AIX_SRC) \ + kafs_locl.h \ + afssysdefs.h \ + roken_rename.h + +nodist_libkafs_la_SOURCES = $(ROKEN_SRCS) + +EXTRA_libkafs_la_SOURCES = afskrb5.c afslib.c + +EXTRA_DIST = NTMakefile afsl.exp afslib.exp $(man_MANS) + +man_MANS = kafs.3 + +# AIX: this almost works with gcc, but somehow it fails to use the +# correct ld, use ld instead +afslib.so: afslib.o + ld -o $@ -bM:SRE -bI:$(srcdir)/afsl.exp -bE:$(srcdir)/afslib.exp $(AFS_EXTRA_LD) afslib.o -lc + +resolve.c: + $(LN_S) $(srcdir)/../roken/resolve.c . + +strtok_r.c: + $(LN_S) $(srcdir)/../roken/strtok_r.c . + +strlcpy.c: + $(LN_S) $(srcdir)/../roken/strlcpy.c . + +strsep.c: + $(LN_S) $(srcdir)/../roken/strsep.c . diff --git a/third_party/heimdal/lib/kafs/NTMakefile b/third_party/heimdal/lib/kafs/NTMakefile new file mode 100644 index 0000000..4cff342 --- /dev/null +++ b/third_party/heimdal/lib/kafs/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\kafs + +!include ../../windows/NTMakefile.w32 + diff --git a/third_party/heimdal/lib/kafs/afskrb5.c b/third_party/heimdal/lib/kafs/afskrb5.c new file mode 100644 index 0000000..0077016 --- /dev/null +++ b/third_party/heimdal/lib/kafs/afskrb5.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kafs_locl.h" + +struct krb5_kafs_data { + krb5_context context; + krb5_ccache id; + krb5_const_realm realm; +}; + +enum { + KAFS_RXKAD_2B_KVNO = 213, + KAFS_RXKAD_K5_KVNO = 256 +}; + +static int +v5_to_kt(krb5_creds *cred, uid_t uid, struct kafs_token *kt, int local524) +{ + int kvno, ret; + + kt->ticket = NULL; + + if (local524) { + Ticket t; + unsigned char *buf; + size_t buf_len; + size_t len; + + kvno = KAFS_RXKAD_2B_KVNO; + + ret = decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); + if (ret) + return ret; + if (t.tkt_vno != 5) + return -1; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_len, &t.enc_part, + &len, ret); + free_Ticket(&t); + if (ret) + return ret; + if(buf_len != len) { + free(buf); + return KRB5KRB_ERR_GENERIC; + } + + kt->ticket = buf; + kt->ticket_len = buf_len; + + } else { + kvno = KAFS_RXKAD_K5_KVNO; + kt->ticket = malloc(cred->ticket.length); + if (kt->ticket == NULL) + return ENOMEM; + kt->ticket_len = cred->ticket.length; + memcpy(kt->ticket, cred->ticket.data, kt->ticket_len); + } + + + /* + * Build a struct ClearToken + */ + + ret = _kafs_derive_des_key(cred->session.keytype, + cred->session.keyvalue.data, + cred->session.keyvalue.length, + kt->ct.HandShakeKey); + if (ret) { + free(kt->ticket); + kt->ticket = NULL; + return ret; + } + kt->ct.AuthHandle = kvno; + kt->ct.ViceId = uid; + kt->ct.BeginTimestamp = cred->times.starttime; + kt->ct.EndTimestamp = cred->times.endtime; + + _kafs_fixup_viceid(&kt->ct, uid); + + return 0; +} + +static krb5_error_code +v5_convert(krb5_context context, krb5_ccache id, + krb5_creds *cred, uid_t uid, + const char *cell, + struct kafs_token *kt) +{ + krb5_error_code ret; + char *c, *val; + + c = strdup(cell); + if (c == NULL) + return ENOMEM; + _kafs_foldup(c, c); + krb5_appdefault_string (context, "libkafs", + c, + "afs-use-524", "2b", &val); + free(c); + + if (strcasecmp(val, "local") == 0 || + strcasecmp(val, "2b") == 0) + ret = v5_to_kt(cred, uid, kt, 1); + else + ret = v5_to_kt(cred, uid, kt, 0); + + free(val); + return ret; +} + + +/* + * + */ + +static int +get_cred(struct kafs_data *data, const char *name, const char *inst, + const char *realm, uid_t uid, struct kafs_token *kt) +{ + krb5_error_code ret; + krb5_creds in_creds, *out_creds; + struct krb5_kafs_data *d = data->data; + int invalid; + + memset(&in_creds, 0, sizeof(in_creds)); + + ret = krb5_make_principal(d->context, &in_creds.server, + realm, name, inst, NULL); + if(ret) + return ret; + ret = krb5_cc_get_principal(d->context, d->id, &in_creds.client); + if(ret){ + krb5_free_principal(d->context, in_creds.server); + return ret; + } + + /* check if des is disable, and in that case enable it for afs */ + invalid = krb5_enctype_valid(d->context, ETYPE_DES_CBC_CRC); + if (invalid) + krb5_enctype_enable(d->context, ETYPE_DES_CBC_CRC); + + ret = krb5_get_credentials(d->context, 0, d->id, &in_creds, &out_creds); + + if (invalid) + krb5_enctype_disable(d->context, ETYPE_DES_CBC_CRC); + + krb5_free_principal(d->context, in_creds.server); + krb5_free_principal(d->context, in_creds.client); + if(ret) + return ret; + + ret = v5_convert(d->context, d->id, out_creds, uid, + (inst != NULL && inst[0] != '\0') ? inst : realm, kt); + krb5_free_creds(d->context, out_creds); + + return ret; +} + +static const char * +get_error(struct kafs_data *data, int error) +{ + struct krb5_kafs_data *d = data->data; + return krb5_get_error_message(d->context, error); +} + +static void +free_error(struct kafs_data *data, const char *str) +{ + struct krb5_kafs_data *d = data->data; + krb5_free_error_message(d->context, str); +} + +static krb5_error_code +afslog_uid_int(struct kafs_data *data, const char *cell, const char *rh, + uid_t uid, const char *homedir) +{ + krb5_error_code ret; + struct kafs_token kt; + krb5_principal princ; + const char *trealm; /* ticket realm */ + struct krb5_kafs_data *d = data->data; + + if (cell == 0 || cell[0] == 0) + return _kafs_afslog_all_local_cells (data, uid, homedir); + + ret = krb5_cc_get_principal (d->context, d->id, &princ); + if (ret) + return ret; + + trealm = krb5_principal_get_realm (d->context, princ); + + kt.ticket = NULL; + ret = _kafs_get_cred(data, cell, d->realm, trealm, uid, &kt); + krb5_free_principal (d->context, princ); + + if(ret == 0) { + ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len); + free(kt.ticket); + } + return ret; +} + +static char * +get_realm(struct kafs_data *data, const char *host) +{ + struct krb5_kafs_data *d = data->data; + krb5_realm *realms; + char *r; + if(krb5_get_host_realm(d->context, host, &realms)) + return NULL; + r = strdup(realms[0]); + krb5_free_host_realm(d->context, realms); + return r; +} + +krb5_error_code +krb5_afslog_uid_home(krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + uid_t uid, + const char *homedir) +{ + struct kafs_data kd; + struct krb5_kafs_data d; + krb5_error_code ret; + + kd.name = "krb5"; + kd.afslog_uid = afslog_uid_int; + kd.get_cred = get_cred; + kd.get_realm = get_realm; + kd.get_error = get_error; + kd.free_error = free_error; + kd.data = &d; + if (context == NULL) { + ret = krb5_init_context(&d.context); + if (ret) + return ret; + } else + d.context = context; + if (id == NULL) { + ret = krb5_cc_default(d.context, &d.id); + if (ret) + goto out; + } else + d.id = id; + d.realm = realm; + ret = afslog_uid_int(&kd, cell, 0, uid, homedir); + if (id == NULL) + krb5_cc_close(context, d.id); + out: + if (context == NULL) + krb5_free_context(d.context); + return ret; +} + +krb5_error_code +krb5_afslog_uid(krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + uid_t uid) +{ + return krb5_afslog_uid_home (context, id, cell, realm, uid, NULL); +} + +krb5_error_code +krb5_afslog(krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm) +{ + return krb5_afslog_uid (context, id, cell, realm, getuid()); +} + +krb5_error_code +krb5_afslog_home(krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + const char *homedir) +{ + return krb5_afslog_uid_home (context, id, cell, realm, getuid(), homedir); +} + +/* + * + */ + +krb5_error_code +krb5_realm_of_cell(const char *cell, char **realm) +{ + struct kafs_data kd; + + kd.name = "krb5"; + kd.get_realm = get_realm; + kd.get_error = get_error; + kd.free_error = free_error; + return _kafs_realm_of_cell(&kd, cell, realm); +} + +/* + * + */ + +int +kafs_settoken5(krb5_context context, const char *cell, uid_t uid, + krb5_creds *cred) +{ + struct kafs_token kt; + int ret; + + ret = v5_convert(context, NULL, cred, uid, cell, &kt); + if (ret) + return ret; + + ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len); + + free(kt.ticket); + + return ret; +} diff --git a/third_party/heimdal/lib/kafs/afsl.exp b/third_party/heimdal/lib/kafs/afsl.exp new file mode 100644 index 0000000..4d2b00e --- /dev/null +++ b/third_party/heimdal/lib/kafs/afsl.exp @@ -0,0 +1,6 @@ +#!/unix + +* This mumbo jumbo creates entry points to syscalls in _AIX + +lpioctl syscall +lsetpag syscall diff --git a/third_party/heimdal/lib/kafs/afslib.c b/third_party/heimdal/lib/kafs/afslib.c new file mode 100644 index 0000000..f2ef848 --- /dev/null +++ b/third_party/heimdal/lib/kafs/afslib.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is only used with AIX + */ + +#include "kafs_locl.h" + +int +aix_pioctl(char *a_path, + int o_opcode, + struct ViceIoctl *a_paramsP, + int a_followSymlinks) +{ + return lpioctl(a_path, o_opcode, a_paramsP, a_followSymlinks); +} + +int +aix_setpag(void) +{ + return lsetpag(); +} diff --git a/third_party/heimdal/lib/kafs/afslib.exp b/third_party/heimdal/lib/kafs/afslib.exp new file mode 100644 index 0000000..f288717 --- /dev/null +++ b/third_party/heimdal/lib/kafs/afslib.exp @@ -0,0 +1,3 @@ +#! +aix_pioctl +aix_setpag diff --git a/third_party/heimdal/lib/kafs/afssys.c b/third_party/heimdal/lib/kafs/afssys.c new file mode 100644 index 0000000..b400626 --- /dev/null +++ b/third_party/heimdal/lib/kafs/afssys.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) 1995 - 2000, 2002, 2004, 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kafs_locl.h" + +struct procdata { + unsigned long param4; + unsigned long param3; + unsigned long param2; + unsigned long param1; + unsigned long syscall; +}; +#ifdef __GNU__ +#define _IOT_procdata _IOT(_IOTS(long), 5, 0, 0, 0, 0) +#define VIOC_SYSCALL_PROC _IOW('C', 1, struct procdata) +#else +#define VIOC_SYSCALL_PROC _IOW('C', 1, void *) +#endif + +struct devdata { + unsigned long syscall; + unsigned long param1; + unsigned long param2; + unsigned long param3; + unsigned long param4; + unsigned long param5; + unsigned long param6; + unsigned long retval; +}; +#ifdef __GNU__ +#define _IOT_devdata _IOT(_IOTS(long), 8, 0, 0, 0, 0) +#endif +#ifdef _IOWR +#define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata) +#define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata) +#endif + +#ifdef _IOW +#ifdef _ILP32 +struct sundevdata { + uint32_t param6; + uint32_t param5; + uint32_t param4; + uint32_t param3; + uint32_t param2; + uint32_t param1; + uint32_t syscall; +}; +#define VIOC_SUN_SYSCALL_DEV _IOW('C', 2, struct sundevdata) +#else +struct sundevdata { + uint64_t param6; + uint64_t param5; + uint64_t param4; + uint64_t param3; + uint64_t param2; + uint64_t param1; + uint64_t syscall; +}; +#define VIOC_SUN_SYSCALL_DEV _IOW('C', 1, struct sundevdata) +#endif +#endif /* _IOW */ + + +int _kafs_debug; /* this should be done in a better way */ + +#define UNKNOWN_ENTRY_POINT (-1) +#define NO_ENTRY_POINT 0 +#define SINGLE_ENTRY_POINT 1 +#define MULTIPLE_ENTRY_POINT 2 +#define SINGLE_ENTRY_POINT2 3 +#define SINGLE_ENTRY_POINT3 4 +#define LINUX_PROC_POINT 5 +#define AIX_ENTRY_POINTS 6 +#define MACOS_DEV_POINT 7 +#define SUN_PROC_POINT 8 + +static int afs_entry_point = UNKNOWN_ENTRY_POINT; +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) || defined(AFS_PIOCTL) +static int afs_syscalls[2]; +#endif +static char *afs_ioctlpath; +static unsigned long afs_ioctlnum; + +/* Magic to get AIX syscalls to work */ +#ifdef _AIX + +static int (*Pioctl)(char*, int, struct ViceIoctl*, int); +static int (*Setpag)(void); + +#include "dlfcn.h" + +/* + * + */ + +static int +try_aix(void) +{ +#ifdef STATIC_AFS_SYSCALLS + Pioctl = aix_pioctl; + Setpag = aix_setpag; +#else + void *ptr; + char path[MaxPathLen], *p; + /* + * If we are root or running setuid don't trust AFSLIBPATH! + */ + if (getuid() != 0 && (p = secure_getenv("AFSLIBPATH")) != NULL) + strlcpy(path, p, sizeof(path)); + else + snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR); + + ptr = dlopen(path, RTLD_NOW); + if(ptr == NULL) { + if(_kafs_debug) { + if(errno == ENOEXEC && (p = dlerror()) != NULL) + fprintf(stderr, "dlopen(%s): %s\n", path, p); + else if (errno != ENOENT) + fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno)); + } + return 1; + } + Setpag = (int (*)(void))dlsym(ptr, "aix_setpag"); + Pioctl = (int (*)(char*, int, + struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl"); +#endif + afs_entry_point = AIX_ENTRY_POINTS; + return 0; +} +#endif /* _AIX */ + +/* + * This probably only works under Solaris and could get confused if + * there's a /etc/name_to_sysnum file. + */ + +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) + +#define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum" + +static int +map_syscall_name_to_number (const char *str, int *res) +{ + FILE *f; + char buf[256]; + size_t str_len = strlen (str); + + f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r"); + if (f == NULL) + return -1; + while (fgets (buf, sizeof(buf), f) != NULL) { + if (buf[0] == '#') + continue; + + if (strncmp (str, buf, str_len) == 0) { + char *begptr = buf + str_len; + char *endptr; + long val = strtol (begptr, &endptr, 0); + + if (val != 0 && endptr != begptr) { + fclose (f); + *res = val; + return 0; + } + } + } + fclose (f); + return -1; +} +#endif + +static int +try_ioctlpath(const char *path, unsigned long ioctlnum, int entrypoint) +{ + int fd, ret, saved_errno; + + fd = open(path, O_RDWR); + if (fd < 0) + return 1; + switch (entrypoint) { + case LINUX_PROC_POINT: { + struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL }; + data.param2 = (unsigned long)VIOCGETTOK; + ret = ioctl(fd, ioctlnum, &data); + break; + } + case MACOS_DEV_POINT: { + struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 }; + data.param2 = (unsigned long)VIOCGETTOK; + ret = ioctl(fd, ioctlnum, &data); + break; + } + case SUN_PROC_POINT: { + struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL }; + data.param2 = (unsigned long)VIOCGETTOK; + ret = ioctl(fd, ioctlnum, &data); + break; + } + default: + abort(); + } + saved_errno = errno; + close(fd); + /* + * Be quite liberal in what error are ok, the first is the one + * that should trigger given that params is NULL. + */ + if (ret && + (saved_errno != EFAULT && + saved_errno != EDOM && + saved_errno != ENOTCONN)) + return 1; + afs_ioctlnum = ioctlnum; + afs_ioctlpath = strdup(path); + if (afs_ioctlpath == NULL) + return 1; + afs_entry_point = entrypoint; + return 0; +} + +static int +do_ioctl(void *data) +{ + int fd, ret, saved_errno; + fd = open(afs_ioctlpath, O_RDWR); + if (fd < 0) { + errno = EINVAL; + return -1; + } + ret = ioctl(fd, afs_ioctlnum, data); + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} + +int +k_pioctl(char *a_path, + int o_opcode, + struct ViceIoctl *a_paramsP, + int a_followSymlinks) +{ +#ifndef NO_AFS + switch(afs_entry_point){ +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) + case SINGLE_ENTRY_POINT: + case SINGLE_ENTRY_POINT2: + case SINGLE_ENTRY_POINT3: + return syscall(afs_syscalls[0], AFSCALL_PIOCTL, + a_path, o_opcode, a_paramsP, a_followSymlinks); +#endif +#if defined(AFS_PIOCTL) + case MULTIPLE_ENTRY_POINT: + return syscall(afs_syscalls[0], + a_path, o_opcode, a_paramsP, a_followSymlinks); +#endif + case LINUX_PROC_POINT: { + struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL }; + data.param1 = (unsigned long)a_path; + data.param2 = (unsigned long)o_opcode; + data.param3 = (unsigned long)a_paramsP; + data.param4 = (unsigned long)a_followSymlinks; + return do_ioctl(&data); + } + case MACOS_DEV_POINT: { + struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 }; + int ret; + + data.param1 = (unsigned long)a_path; + data.param2 = (unsigned long)o_opcode; + data.param3 = (unsigned long)a_paramsP; + data.param4 = (unsigned long)a_followSymlinks; + + ret = do_ioctl(&data); + if (ret) + return ret; + + return data.retval; + } + case SUN_PROC_POINT: { + struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL }; + data.param1 = (unsigned long)a_path; + data.param2 = (unsigned long)o_opcode; + data.param3 = (unsigned long)a_paramsP; + data.param4 = (unsigned long)a_followSymlinks; + return do_ioctl(&data); + } +#ifdef _AIX + case AIX_ENTRY_POINTS: + return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks); +#endif + } + errno = ENOSYS; +#ifdef SIGSYS + kill(getpid(), SIGSYS); /* You lose! */ +#endif +#endif /* NO_AFS */ + return -1; +} + +int +k_afs_cell_of_file(const char *path, char *cell, int len) +{ + struct ViceIoctl parms; + parms.in = NULL; + parms.in_size = 0; + parms.out = cell; + parms.out_size = len; + return k_pioctl(rk_UNCONST(path), VIOC_FILE_CELL_NAME, &parms, 1); +} + +int +k_unlog(void) +{ + struct ViceIoctl parms; + memset(&parms, 0, sizeof(parms)); + return k_pioctl(0, VIOCUNLOG, &parms, 0); +} + +int +k_setpag(void) +{ +#ifndef NO_AFS + switch(afs_entry_point){ +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) + case SINGLE_ENTRY_POINT: + case SINGLE_ENTRY_POINT2: + case SINGLE_ENTRY_POINT3: + return syscall(afs_syscalls[0], AFSCALL_SETPAG); +#endif +#if defined(AFS_PIOCTL) + case MULTIPLE_ENTRY_POINT: + return syscall(afs_syscalls[1]); +#endif + case LINUX_PROC_POINT: { + struct procdata data = { 0, 0, 0, 0, AFSCALL_SETPAG }; + return do_ioctl(&data); + } + case MACOS_DEV_POINT: { + struct devdata data = { AFSCALL_SETPAG, 0, 0, 0, 0, 0, 0, 0 }; + int ret = do_ioctl(&data); + if (ret) + return ret; + return data.retval; + } + case SUN_PROC_POINT: { + struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_SETPAG }; + return do_ioctl(&data); + } +#ifdef _AIX + case AIX_ENTRY_POINTS: + return Setpag(); +#endif + } + + errno = ENOSYS; +#ifdef SIGSYS + kill(getpid(), SIGSYS); /* You lose! */ +#endif +#endif /* NO_AFS */ + return -1; +} + +static jmp_buf catch_SIGSYS; + +#ifdef SIGSYS + +static RETSIGTYPE +SIGSYS_handler(int sig) +{ + errno = 0; + signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */ + longjmp(catch_SIGSYS, 1); +} + +#endif + +/* + * Try to see if `syscall' is a pioctl. Return 0 iff succesful. + */ + +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) +static int +try_one (int syscall_num) +{ + struct ViceIoctl parms; + memset(&parms, 0, sizeof(parms)); + + if (setjmp(catch_SIGSYS) == 0) { + syscall(syscall_num, AFSCALL_PIOCTL, + 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (errno == EINVAL) { + afs_entry_point = SINGLE_ENTRY_POINT; + afs_syscalls[0] = syscall_num; + return 0; + } + } + return 1; +} +#endif + +/* + * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff + * succesful. + * + */ + +#ifdef AFS_PIOCTL +static int +try_two (int syscall_pioctl, int syscall_setpag) +{ + struct ViceIoctl parms; + memset(&parms, 0, sizeof(parms)); + + if (setjmp(catch_SIGSYS) == 0) { + syscall(syscall_pioctl, + 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (errno == EINVAL) { + afs_entry_point = MULTIPLE_ENTRY_POINT; + afs_syscalls[0] = syscall_pioctl; + afs_syscalls[1] = syscall_setpag; + return 0; + } + } + return 1; +} +#endif + +int +k_hasafs(void) +{ +#if !defined(NO_AFS) && defined(SIGSYS) + RETSIGTYPE (*saved_func)(int); +#endif + int saved_errno, ret; + char *env = NULL; + + env = secure_getenv("AFS_SYSCALL"); + + /* + * Already checked presence of AFS syscalls? + */ + if (afs_entry_point != UNKNOWN_ENTRY_POINT) + return afs_entry_point != NO_ENTRY_POINT; + + /* + * Probe kernel for AFS specific syscalls, + * they (currently) come in two flavors. + * If the syscall is absent we recive a SIGSYS. + */ + afs_entry_point = NO_ENTRY_POINT; + + saved_errno = errno; +#ifndef NO_AFS +#ifdef SIGSYS + saved_func = signal(SIGSYS, SIGSYS_handler); +#endif + if (env && strstr(env, "..") == NULL) { + + if (strncmp("/proc/", env, 6) == 0) { + if (try_ioctlpath(env, VIOC_SYSCALL_PROC, LINUX_PROC_POINT) == 0) + goto done; + } + if (strncmp("/dev/", env, 5) == 0) { +#ifdef VIOC_SYSCALL_DEV + if (try_ioctlpath(env, VIOC_SYSCALL_DEV, MACOS_DEV_POINT) == 0) + goto done; +#endif +#ifdef VIOC_SYSCALL_DEV_OPENAFS + if (try_ioctlpath(env,VIOC_SYSCALL_DEV_OPENAFS,MACOS_DEV_POINT) ==0) + goto done; +#endif + } + } + + ret = try_ioctlpath("/proc/fs/openafs/afs_ioctl", + VIOC_SYSCALL_PROC, LINUX_PROC_POINT); + if (ret == 0) + goto done; + ret = try_ioctlpath("/proc/fs/nnpfs/afs_ioctl", + VIOC_SYSCALL_PROC, LINUX_PROC_POINT); + if (ret == 0) + goto done; + +#ifdef VIOC_SYSCALL_DEV_OPENAFS + ret = try_ioctlpath("/dev/openafs_ioctl", + VIOC_SYSCALL_DEV_OPENAFS, MACOS_DEV_POINT); + if (ret == 0) + goto done; +#endif +#ifdef VIOC_SYSCALL_DEV + ret = try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV, MACOS_DEV_POINT); + if (ret == 0) + goto done; +#endif +#ifdef VIOC_SUN_SYSCALL_DEV + ret = try_ioctlpath("/dev/afs", VIOC_SUN_SYSCALL_DEV, SUN_PROC_POINT); + if (ret == 0) + goto done; +#endif + + +#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) + { + int tmp; + + if (env != NULL) { + if (sscanf (env, "%d", &tmp) == 1) { + if (try_one (tmp) == 0) + goto done; + } else { + char *end = NULL; + char *p; + char *s = strdup (env); + + if (s != NULL) { + for (p = strtok_r (s, ",", &end); + p != NULL; + p = strtok_r (NULL, ",", &end)) { + if (map_syscall_name_to_number (p, &tmp) == 0) + if (try_one (tmp) == 0) { + free (s); + goto done; + } + } + free (s); + } + } + } + } +#endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */ + +#ifdef AFS_SYSCALL + if (try_one (AFS_SYSCALL) == 0) + goto done; +#endif /* AFS_SYSCALL */ + +#ifdef AFS_PIOCTL + { + int tmp[2]; + + if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2) + if (try_two (tmp[0], tmp[1]) == 2) + goto done; + } +#endif /* AFS_PIOCTL */ + +#ifdef AFS_PIOCTL + if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0) + goto done; +#endif /* AFS_PIOCTL */ + +#ifdef AFS_SYSCALL2 + if (try_one (AFS_SYSCALL2) == 0) + goto done; +#endif /* AFS_SYSCALL2 */ + +#ifdef AFS_SYSCALL3 + if (try_one (AFS_SYSCALL3) == 0) + goto done; +#endif /* AFS_SYSCALL3 */ + +#ifdef _AIX +#if 0 + if (env != NULL) { + char *pos = NULL; + char *pioctl_name; + char *setpag_name; + + pioctl_name = strtok_r (env, ", \t", &pos); + if (pioctl_name != NULL) { + setpag_name = strtok_r (NULL, ", \t", &pos); + if (setpag_name != NULL) + if (try_aix (pioctl_name, setpag_name) == 0) + goto done; + } + } +#endif + + if(try_aix() == 0) + goto done; +#endif + + +done: +#ifdef SIGSYS + signal(SIGSYS, saved_func); +#endif +#endif /* NO_AFS */ + errno = saved_errno; + return afs_entry_point != NO_ENTRY_POINT; +} + +int +k_hasafs_recheck(void) +{ + afs_entry_point = UNKNOWN_ENTRY_POINT; + return k_hasafs(); +} diff --git a/third_party/heimdal/lib/kafs/afssysdefs.h b/third_party/heimdal/lib/kafs/afssysdefs.h new file mode 100644 index 0000000..18734e3 --- /dev/null +++ b/third_party/heimdal/lib/kafs/afssysdefs.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +/* + * This section is for machines using single entry point AFS syscalls! + * and/or + * This section is for machines using multiple entry point AFS syscalls! + * + * SunOS 4 is an example of single entry point and sgi of multiple + * entry point syscalls. + */ + +#if SunOS == 40 +#define AFS_SYSCALL 31 +#endif + +#if SunOS >= 50 && SunOS < 57 +#define AFS_SYSCALL 105 +#endif + +#if SunOS == 57 +#define AFS_SYSCALL 73 +#endif + +#if SunOS >= 58 +#define AFS_SYSCALL 65 +#endif + +#if defined(__hpux) +#define AFS_SYSCALL 50 +#define AFS_SYSCALL2 49 +#define AFS_SYSCALL3 48 +#endif + +#if defined(_AIX) +/* _AIX is too weird */ +#endif + +#if defined(__sgi) +#define AFS_PIOCTL (64+1000) +#define AFS_SETPAG (65+1000) +#endif + +#if defined(__osf__) +#define AFS_SYSCALL 232 +#define AFS_SYSCALL2 258 +#endif + +#if defined(__ultrix) +#define AFS_SYSCALL 31 +#endif + +#if defined(__FreeBSD__) +#if __FreeBSD_version >= 500000 +#define AFS_SYSCALL 339 +#else +#define AFS_SYSCALL 210 +#endif +#endif /* __FreeBSD__ */ + +#ifdef __DragonFly__ +#ifndef AFS_SYSCALL +#define AFS_SYSCALL 339 +#endif +#endif + +#ifdef __OpenBSD__ +#define AFS_SYSCALL 208 +#endif + +#if defined(__NetBSD__) +#define AFS_SYSCALL 210 +#endif + +#ifdef SYS_afs_syscall +#define AFS_SYSCALL3 SYS_afs_syscall +#endif diff --git a/third_party/heimdal/lib/kafs/common.c b/third_party/heimdal/lib/kafs/common.c new file mode 100644 index 0000000..ff42cf7 --- /dev/null +++ b/third_party/heimdal/lib/kafs/common.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kafs_locl.h" + +#define AUTH_SUPERUSER "afs" + +/* + * Here only ASCII characters are relevant. + */ + +#define IsAsciiLower(c) ('a' <= (c) && (c) <= 'z') + +#define ToAsciiUpper(c) ((c) - 'a' + 'A') + +static void (*kafs_verbose)(void *, const char *); +static void *kafs_verbose_ctx; + +void +_kafs_foldup(char *a, const char *b) +{ + for (; *b; a++, b++) + if (IsAsciiLower(*b)) + *a = ToAsciiUpper(*b); + else + *a = *b; + *a = '\0'; +} + +void +kafs_set_verbose(void (*f)(void *, const char *), void *ctx) +{ + if (f) { + kafs_verbose = f; + kafs_verbose_ctx = ctx; + } +} + +int +kafs_settoken_rxkad(const char *cell, struct ClearToken *ct, + void *ticket, size_t ticket_len) +{ + struct ViceIoctl parms; + char buf[2048], *t; + int32_t sizeof_x; + + t = buf; + /* + * length of secret token followed by secret token + */ + sizeof_x = ticket_len; + memcpy(t, &sizeof_x, sizeof(sizeof_x)); + t += sizeof(sizeof_x); + memcpy(t, ticket, sizeof_x); + t += sizeof_x; + /* + * length of clear token followed by clear token + */ + sizeof_x = sizeof(*ct); + memcpy(t, &sizeof_x, sizeof(sizeof_x)); + t += sizeof(sizeof_x); + memcpy(t, ct, sizeof_x); + t += sizeof_x; + + /* + * do *not* mark as primary cell + */ + sizeof_x = 0; + memcpy(t, &sizeof_x, sizeof(sizeof_x)); + t += sizeof(sizeof_x); + /* + * follow with cell name + */ + sizeof_x = strlen(cell) + 1; + memcpy(t, cell, sizeof_x); + t += sizeof_x; + + /* + * Build argument block + */ + parms.in = buf; + parms.in_size = t - buf; + parms.out = 0; + parms.out_size = 0; + + return k_pioctl(0, VIOCSETTOK, &parms, 0); +} + +void +_kafs_fixup_viceid(struct ClearToken *ct, uid_t uid) +{ +#define ODD(x) ((x) & 1) + /* According to Transarc conventions ViceId is valid iff + * (EndTimestamp - BeginTimestamp) is odd. By decrementing EndTime + * the transformations: + * + * (issue_date, life) -> (StartTime, EndTime) -> (issue_date, life) + * preserves the original values. + */ + if (uid != 0) /* valid ViceId */ + { + if (!ODD(ct->EndTimestamp - ct->BeginTimestamp)) + ct->EndTimestamp--; + } + else /* not valid ViceId */ + { + if (ODD(ct->EndTimestamp - ct->BeginTimestamp)) + ct->EndTimestamp--; + } +} + +/* Try to get a db-server for an AFS cell from a AFSDB record */ + +static int +dns_find_cell(const char *cell, char *dbserver, size_t len) +{ + struct rk_dns_reply *r; + int ok = -1; + r = rk_dns_lookup(cell, "afsdb"); + if(r){ + struct rk_resource_record *rr = r->head; + while(rr){ + if(rr->type == rk_ns_t_afsdb && rr->u.afsdb->preference == 1){ + strlcpy(dbserver, + rr->u.afsdb->domain, + len); + ok = 0; + break; + } + rr = rr->next; + } + rk_dns_free_data(r); + } + return ok; +} + + +/* + * Try to find the cells we should try to klog to in "file". + */ +static void +find_cells(const char *file, char ***cells, int *idx) +{ + FILE *f; + char cell[64]; + int i; + int ind = *idx; + + f = fopen(file, "r"); + if (f == NULL) + return; + while (fgets(cell, sizeof(cell), f)) { + char *t; + t = cell + strlen(cell); + for (; t >= cell; t--) + if (*t == '\n' || *t == '\t' || *t == ' ') + *t = 0; + if (cell[0] == '\0' || cell[0] == '#') + continue; + for(i = 0; i < ind; i++) + if(strcmp((*cells)[i], cell) == 0) + break; + if(i == ind){ + char **tmp; + + tmp = realloc(*cells, (ind + 1) * sizeof(**cells)); + if (tmp == NULL) + break; + *cells = tmp; + (*cells)[ind] = strdup(cell); + if ((*cells)[ind] == NULL) + break; + ++ind; + } + } + fclose(f); + *idx = ind; +} + +/* + * Get tokens for all cells[] + */ +static int +afslog_cells(struct kafs_data *data, char **cells, int max, uid_t uid, + const char *homedir) +{ + int ret = 0; + int i; + for (i = 0; i < max; i++) { + int er = (*data->afslog_uid)(data, cells[i], 0, uid, homedir); + if (er) + ret = er; + } + return ret; +} + +int +_kafs_afslog_all_local_cells(struct kafs_data *data, + uid_t uid, const char *homedir) +{ + int ret; + char **cells = NULL; + int idx = 0; + + if (homedir == NULL) + homedir = getenv("HOME"); + if (homedir != NULL) { + char home[MaxPathLen]; + snprintf(home, sizeof(home), "%s/.TheseCells", homedir); + find_cells(home, &cells, &idx); + } + find_cells(_PATH_THESECELLS, &cells, &idx); + find_cells(_PATH_THISCELL, &cells, &idx); + find_cells(_PATH_ARLA_THESECELLS, &cells, &idx); + find_cells(_PATH_ARLA_THISCELL, &cells, &idx); + find_cells(_PATH_OPENAFS_DEBIAN_THESECELLS, &cells, &idx); + find_cells(_PATH_OPENAFS_DEBIAN_THISCELL, &cells, &idx); + find_cells(_PATH_OPENAFS_MACOSX_THESECELLS, &cells, &idx); + find_cells(_PATH_OPENAFS_MACOSX_THISCELL, &cells, &idx); + find_cells(_PATH_ARLA_DEBIAN_THESECELLS, &cells, &idx); + find_cells(_PATH_ARLA_DEBIAN_THISCELL, &cells, &idx); + find_cells(_PATH_ARLA_OPENBSD_THESECELLS, &cells, &idx); + find_cells(_PATH_ARLA_OPENBSD_THISCELL, &cells, &idx); + + ret = afslog_cells(data, cells, idx, uid, homedir); + while(idx > 0) + free(cells[--idx]); + free(cells); + return ret; +} + + +static int +file_find_cell(struct kafs_data *data, + const char *cell, char **realm, int exact) +{ + FILE *F; + char buf[1024]; + char *p; + int ret = -1; + + if ((F = fopen(_PATH_CELLSERVDB, "r")) + || (F = fopen(_PATH_ARLA_CELLSERVDB, "r")) + || (F = fopen(_PATH_OPENAFS_DEBIAN_CELLSERVDB, "r")) + || (F = fopen(_PATH_OPENAFS_MACOSX_CELLSERVDB, "r")) + || (F = fopen(_PATH_ARLA_DEBIAN_CELLSERVDB, "r"))) { + while (fgets(buf, sizeof(buf), F)) { + int cmp; + + if (buf[0] != '>') + continue; /* Not a cell name line, try next line */ + p = buf; + strsep(&p, " \t\n#"); + + if (exact) + cmp = strcmp(buf + 1, cell); + else + cmp = strncmp(buf + 1, cell, strlen(cell)); + + if (cmp == 0) { + /* + * We found the cell name we're looking for. + * Read next line on the form ip-address '#' hostname + */ + if (fgets(buf, sizeof(buf), F) == NULL) + break; /* Read failed, give up */ + p = strchr(buf, '#'); + if (p == NULL) + break; /* No '#', give up */ + p++; + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + *realm = (*data->get_realm)(data, p); + if (*realm && **realm != '\0') + ret = 0; + break; /* Won't try any more */ + } + } + fclose(F); + } + return ret; +} + +/* Find the realm associated with cell. Do this by opening CellServDB + file and getting the realm-of-host for the first VL-server for the + cell. + + This does not work when the VL-server is living in one realm, but + the cell it is serving is living in another realm. + + Return 0 on success, -1 otherwise. + */ + +int +_kafs_realm_of_cell(struct kafs_data *data, + const char *cell, char **realm) +{ + char buf[1024]; + int ret; + + ret = file_find_cell(data, cell, realm, 1); + if (ret == 0) + return ret; + if (dns_find_cell(cell, buf, sizeof(buf)) == 0) { + *realm = (*data->get_realm)(data, buf); + if(*realm != NULL) + return 0; + } + return file_find_cell(data, cell, realm, 0); +} + +static int +_kafs_try_get_cred(struct kafs_data *data, const char *user, const char *cell, + const char *realm, uid_t uid, struct kafs_token *kt) +{ + int ret; + + ret = (*data->get_cred)(data, user, cell, realm, uid, kt); + if (kafs_verbose) { + const char *estr = (*data->get_error)(data, ret); + char *str; + int aret; + + aret = asprintf(&str, "%s tried afs%s%s@%s -> %s (%d)", + data->name, cell ? "/" : "", + cell ? cell : "", realm, estr ? estr : "unknown", ret); + if (aret != -1) { + (*kafs_verbose)(kafs_verbose_ctx, str); + free(str); + } else { + (*kafs_verbose)(kafs_verbose_ctx, "out of memory"); + } + if (estr) + (*data->free_error)(data, estr); + } + + return ret; +} + + +int +_kafs_get_cred(struct kafs_data *data, + const char *cell, + const char *realm_hint, + const char *realm, + uid_t uid, + struct kafs_token *kt) +{ + int ret = -1; + char *vl_realm; + char CELL[64]; + + /* We're about to find the realm that holds the key for afs in + * the specified cell. The problem is that null-instance + * afs-principals are common and that hitting the wrong realm might + * yield the wrong afs key. The following assumptions were made. + * + * Any realm passed to us is preferred. + * + * If there is a realm with the same name as the cell, it is most + * likely the correct realm to talk to. + * + * In most (maybe even all) cases the database servers of the cell + * will live in the realm we are looking for. + * + * Try the local realm, but if the previous cases fail, this is + * really a long shot. + * + */ + + /* comments on the ordering of these tests */ + + /* If the user passes a realm, she probably knows something we don't + * know and we should try afs@realm_hint. + */ + + if (realm_hint) { + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + cell, realm_hint, uid, kt); + if (ret == 0) return 0; + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + NULL, realm_hint, uid, kt); + if (ret == 0) return 0; + } + + _kafs_foldup(CELL, cell); + + /* + * If the AFS servers have a file /usr/afs/etc/krb.conf containing + * REALM we still don't have to resort to cross-cell authentication. + * Try afs.cell@REALM. + */ + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + cell, realm, uid, kt); + if (ret == 0) return 0; + + /* + * If cell == realm we don't need no cross-cell authentication. + * Try afs@REALM. + */ + if (strcmp(CELL, realm) == 0) { + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + NULL, realm, uid, kt); + if (ret == 0) return 0; + } + + /* + * We failed to get ``first class tickets'' for afs, + * fall back to cross-cell authentication. + * Try afs@CELL. + * Try afs.cell@CELL. + */ + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + NULL, CELL, uid, kt); + if (ret == 0) return 0; + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + cell, CELL, uid, kt); + if (ret == 0) return 0; + + /* + * Perhaps the cell doesn't correspond to any realm? + * Use realm of first volume location DB server. + * Try afs.cell@VL_REALM. + * Try afs@VL_REALM??? + */ + if (_kafs_realm_of_cell(data, cell, &vl_realm) == 0 + && strcmp(vl_realm, realm) != 0 + && strcmp(vl_realm, CELL) != 0) { + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + cell, vl_realm, uid, kt); + if (ret) + ret = _kafs_try_get_cred(data, AUTH_SUPERUSER, + NULL, vl_realm, uid, kt); + free(vl_realm); + if (ret == 0) return 0; + } + + return ret; +} diff --git a/third_party/heimdal/lib/kafs/kafs.3 b/third_party/heimdal/lib/kafs/kafs.3 new file mode 100644 index 0000000..d44e35e --- /dev/null +++ b/third_party/heimdal/lib/kafs/kafs.3 @@ -0,0 +1,296 @@ +.\" Copyright (c) 1998 - 2006 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd May 1, 2006 +.Os HEIMDAL +.Dt KAFS 3 +.Sh NAME +.Nm k_hasafs , +.Nm k_hasafs_recheck , +.Nm k_pioctl , +.Nm k_unlog , +.Nm k_setpag , +.Nm k_afs_cell_of_file , +.Nm kafs_set_verbose , +.Nm kafs_settoken_rxkad , +.Nm kafs_settoken , +.Nm krb_afslog , +.Nm krb_afslog_uid , +.Nm kafs_settoken5 , +.Nm krb5_afslog , +.Nm krb5_afslog_uid +.Nd AFS library +.Sh LIBRARY +AFS cache manager access library (libkafs, -lkafs) +.Sh SYNOPSIS +.In kafs.h +.Ft int +.Fn k_afs_cell_of_file "const char *path" "char *cell" "int len" +.Ft int +.Fn k_hasafs "void" +.Ft int +.Fn k_hasafs_recheck "void" +.Ft int +.Fn k_pioctl "char *a_path" "int o_opcode" "struct ViceIoctl *a_paramsP" "int a_followSymlinks" +.Ft int +.Fn k_setpag "void" +.Ft int +.Fn k_unlog "void" +.Ft void +.Fn kafs_set_verbose "void (*func)(void *, const char *, int)" "void *" +.Ft int +.Fn kafs_settoken_rxkad "const char *cell" "struct ClearToken *token" "void *ticket" "size_t ticket_len" +.Ft int +.Fn kafs_settoken "const char *cell" "uid_t uid" "CREDENTIALS *c" +.Fn krb_afslog "char *cell" "char *realm" +.Ft int +.Fn krb_afslog_uid "char *cell" "char *realm" "uid_t uid" +.Ft krb5_error_code +.Fn krb5_afslog_uid "krb5_context context" "krb5_ccache id" "const char *cell" "krb5_const_realm realm" "uid_t uid" +.Ft int +.Fn kafs_settoken5 "const char *cell" "uid_t uid" "krb5_creds *c" +.Ft krb5_error_code +.Fn krb5_afslog "krb5_context context" "krb5_ccache id" "const char *cell" "krb5_const_realm realm" +.Sh DESCRIPTION +.Fn k_hasafs +initializes some library internal structures, and tests for the +presence of AFS in the kernel, none of the other functions should be +called before +.Fn k_hasafs +is called, or if it fails. +.Pp +.Fn k_hasafs_recheck +forces a recheck if a AFS client has started since last time +.Fn k_hasafs +or +.Fn k_hasafs_recheck +was called. +.Pp +.Fn kafs_set_verbose +set a log function that will be called each time the kafs library does +something important so that the application using libkafs can output +verbose logging. +Calling the function +.Fa kafs_set_verbose +with the function argument set to +.Dv NULL +will stop libkafs from calling the logging function (if set). +.Pp +.Fn kafs_settoken_rxkad +set +.Li rxkad +with the +.Fa token +and +.Fa ticket +(that have the length +.Fa ticket_len ) +for a given +.Fa cell . +.Pp +.Fn kafs_settoken +and +.Fn kafs_settoken5 +work the same way as +.Fn kafs_settoken_rxkad +but internally converts the Kerberos 4 or 5 credential to a afs +cleartoken and ticket. +.Pp +.Fn krb_afslog , +and +.Fn krb_afslog_uid +obtains new tokens (and possibly tickets) for the specified +.Fa cell +and +.Fa realm . +If +.Fa cell +is +.Dv NULL , +the local cell is used. If +.Fa realm +is +.Dv NULL , +the function tries to guess what realm to use. Unless you have some good knowledge of what cell or realm to use, you should pass +.Dv NULL . +.Fn krb_afslog +will use the real user-id for the +.Dv ViceId +field in the token, +.Fn krb_afslog_uid +will use +.Fa uid . +.Pp +.Fn krb5_afslog , +and +.Fn krb5_afslog_uid +are the Kerberos 5 equivalents of +.Fn krb_afslog , +and +.Fn krb_afslog_uid . +.Pp +.Fn krb5_afslog , +.Fn kafs_settoken5 +can be configured to behave differently via a +.Nm krb5_appdefault +option +.Li afs-use-524 +in +.Pa krb5.conf . +Possible values for +.Li afs-use-524 +are: +.Bl -tag -width local +.It yes +use the 524 server in the realm to convert the ticket +.It no +use the Kerberos 5 ticket directly, can be used with if the afs cell +support 2b token. +.It local, 2b +convert the Kerberos 5 credential to a 2b token locally (the same work +as a 2b 524 server should have done). +.El +.Pp +Example: +.Pp +.Bd -literal +[appdefaults] + SU.SE = { afs-use-524 = local } + PDC.KTH.SE = { afs-use-524 = yes } + afs-use-524 = yes +.Ed +.Pp +libkafs will use the +.Li libkafs +as application name when running the +.Nm krb5_appdefault +function call. +.Pp +The (uppercased) cell name is used as the realm to the +.Nm krb5_appdefault function. +.Pp +.\" The extra arguments are the ubiquitous context, and the cache id where +.\" to store any obtained tickets. Since AFS servers normally can't handle +.\" Kerberos 5 tickets directly, these functions will first obtain version +.\" 5 tickets for the requested cells, and then convert them to version 4 +.\" tickets, that can be stashed in the kernel. To convert tickets the +.\" .Fn krb524_convert_creds_kdc +.\" function will be used. +.\" .Pp +.Fn k_afs_cell_of_file +will in +.Fa cell +return the cell of a specified file, no more than +.Fa len +characters is put in +.Fa cell . +.Pp +.Fn k_pioctl +does a +.Fn pioctl +system call with the specified arguments. This function is equivalent to +.Fn lpioctl . +.Pp +.Fn k_setpag +initializes a new PAG. +.Pp +.Fn k_unlog +removes destroys all tokens in the current PAG. +.Sh RETURN VALUES +.Fn k_hasafs +returns 1 if AFS is present in the kernel, 0 otherwise. +.Fn krb_afslog +and +.Fn krb_afslog_uid +returns 0 on success, or a Kerberos error number on failure. +.Fn k_afs_cell_of_file , +.Fn k_pioctl , +.Fn k_setpag , +and +.Fn k_unlog +all return the value of the underlaying system call, 0 on success. +.Sh ENVIRONMENT +The following environment variable affect the mode of operation of +.Nm kafs : +.Bl -tag -width AFS_SYSCALL +.It Ev AFS_SYSCALL +Normally, +.Nm kafs +will try to figure out the correct system call(s) that are used by AFS +by itself. If it does not manage to do that, or does it incorrectly, +you can set this variable to the system call number or list of system +call numbers that should be used. +.El +.Sh EXAMPLES +The following code from +.Nm login +will obtain a new PAG and tokens for the local cell and the cell of +the users home directory. +.Bd -literal +if (k_hasafs()) { + char cell[64]; + k_setpag(); + if(k_afs_cell_of_file(pwd->pw_dir, cell, sizeof(cell)) == 0) + krb_afslog(cell, NULL); + krb_afslog(NULL, NULL); +} +.Ed +.Sh ERRORS +If any of these functions (apart from +.Fn k_hasafs ) +is called without AFS being present in the kernel, the process will +usually (depending on the operating system) receive a SIGSYS signal. +.Sh SEE ALSO +.Xr krb5_appdefault 3 , +.Xr krb5.conf 5 +.Rs +.%A Transarc Corporation +.%J AFS-3 Programmer's Reference +.%T File Server/Cache Manager Interface +.%D 1991 +.Re +.Sh FILES +libkafs will search for +.Pa ThisCell and +.Pa TheseCells +in the following locations: +.Pa /usr/vice/etc , +.Pa /etc/openafs , +.Pa /var/db/openafs/etc , +.Pa /usr/arla/etc , +.Pa /etc/arla , +and +.Pa /etc/afs +.Sh BUGS +.Ev AFS_SYSCALL +has no effect under AIX. diff --git a/third_party/heimdal/lib/kafs/kafs.h b/third_party/heimdal/lib/kafs/kafs.h new file mode 100644 index 0000000..6f6eb63 --- /dev/null +++ b/third_party/heimdal/lib/kafs/kafs.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1995 - 2001, 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __KAFS_H +#define __KAFS_H + +/* XXX must include krb5.h or krb.h */ + +/* sys/ioctl.h must be included manually before kafs.h */ + +/* + */ +#define AFSCALL_PIOCTL 20 +#define AFSCALL_SETPAG 21 + +#ifndef _VICEIOCTL +#ifdef __GNU__ +#define _IOT_ViceIoctl _IOT(_IOTS(caddr_t), 2, _IOTS(short), 2, 0, 0) +#endif +#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl)) +#define _AFSCIOCTL(id) ((unsigned int ) _IOW('C', id, struct ViceIoctl)) +#endif /* _VICEIOCTL */ + +#define VIOCSETAL _VICEIOCTL(1) +#define VIOCGETAL _VICEIOCTL(2) +#define VIOCSETTOK _VICEIOCTL(3) +#define VIOCGETVOLSTAT _VICEIOCTL(4) +#define VIOCSETVOLSTAT _VICEIOCTL(5) +#define VIOCFLUSH _VICEIOCTL(6) +#define VIOCGETTOK _VICEIOCTL(8) +#define VIOCUNLOG _VICEIOCTL(9) +#define VIOCCKSERV _VICEIOCTL(10) +#define VIOCCKBACK _VICEIOCTL(11) +#define VIOCCKCONN _VICEIOCTL(12) +#define VIOCWHEREIS _VICEIOCTL(14) +#define VIOCACCESS _VICEIOCTL(20) +#define VIOCUNPAG _VICEIOCTL(21) +#define VIOCGETFID _VICEIOCTL(22) +#define VIOCSETCACHESIZE _VICEIOCTL(24) +#define VIOCFLUSHCB _VICEIOCTL(25) +#define VIOCNEWCELL _VICEIOCTL(26) +#define VIOCGETCELL _VICEIOCTL(27) +#define VIOC_AFS_DELETE_MT_PT _VICEIOCTL(28) +#define VIOC_AFS_STAT_MT_PT _VICEIOCTL(29) +#define VIOC_FILE_CELL_NAME _VICEIOCTL(30) +#define VIOC_GET_WS_CELL _VICEIOCTL(31) +#define VIOC_AFS_MARINER_HOST _VICEIOCTL(32) +#define VIOC_GET_PRIMARY_CELL _VICEIOCTL(33) +#define VIOC_VENUSLOG _VICEIOCTL(34) +#define VIOC_GETCELLSTATUS _VICEIOCTL(35) +#define VIOC_SETCELLSTATUS _VICEIOCTL(36) +#define VIOC_FLUSHVOLUME _VICEIOCTL(37) +#define VIOC_AFS_SYSNAME _VICEIOCTL(38) +#define VIOC_EXPORTAFS _VICEIOCTL(39) +#define VIOCGETCACHEPARAMS _VICEIOCTL(40) +#define VIOC_GCPAGS _VICEIOCTL(48) + +#define VIOCGETTOK2 _AFSCIOCTL(7) +#define VIOCSETTOK2 _AFSCIOCTL(8) + +struct ViceIoctl { + caddr_t in, out; + unsigned short in_size; + unsigned short out_size; +}; + +struct ClearToken { + int32_t AuthHandle; + char HandShakeKey[8]; + int32_t ViceId; + int32_t BeginTimestamp; + int32_t EndTimestamp; +}; + +/* Use k_hasafs() to probe if the machine supports AFS syscalls. + The other functions will generate a SIGSYS if AFS is not supported */ + +int k_hasafs (void); +int k_hasafs_recheck (void); + +int krb_afslog (const char *cell, const char *realm); +int krb_afslog_uid (const char *cell, const char *realm, uid_t uid); +int krb_afslog_home (const char *cell, const char *realm, + const char *homedir); +int krb_afslog_uid_home (const char *cell, const char *realm, uid_t uid, + const char *homedir); + +int krb_realm_of_cell (const char *cell, char **realm); + +/* compat */ +#define k_afsklog krb_afslog +#define k_afsklog_uid krb_afslog_uid + +int k_pioctl (char *a_path, + int o_opcode, + struct ViceIoctl *a_paramsP, + int a_followSymlinks); +int k_unlog (void); +int k_setpag (void); +int k_afs_cell_of_file (const char *path, char *cell, int len); + + + +/* XXX */ +#ifdef KFAILURE +#define KRB_H_INCLUDED +#endif + +#ifdef KRB5_RECVAUTH_IGNORE_VERSION +#define KRB5_H_INCLUDED +#endif + +void kafs_set_verbose (void (*kafs_verbose)(void *, const char *), void *); +int kafs_settoken_rxkad (const char *, struct ClearToken *, + void *ticket, size_t ticket_len); +#ifdef KRB_H_INCLUDED +int kafs_settoken (const char*, uid_t, CREDENTIALS*); +#endif +#ifdef KRB5_H_INCLUDED +int kafs_settoken5 (krb5_context, const char*, uid_t, krb5_creds*); +#endif + + +#ifdef KRB5_H_INCLUDED +krb5_error_code krb5_afslog_uid (krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + uid_t uid); +krb5_error_code krb5_afslog (krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm); +krb5_error_code krb5_afslog_uid_home (krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + uid_t uid, + const char *homedir); + +krb5_error_code krb5_afslog_home (krb5_context context, + krb5_ccache id, + const char *cell, + krb5_const_realm realm, + const char *homedir); + +krb5_error_code krb5_realm_of_cell (const char *cell, char **realm); + +#endif + + +#define _PATH_VICE "/usr/vice/etc/" +#define _PATH_THISCELL _PATH_VICE "ThisCell" +#define _PATH_CELLSERVDB _PATH_VICE "CellServDB" +#define _PATH_THESECELLS _PATH_VICE "TheseCells" + +#define _PATH_ARLA_VICE "/usr/arla/etc/" +#define _PATH_ARLA_THISCELL _PATH_ARLA_VICE "ThisCell" +#define _PATH_ARLA_CELLSERVDB _PATH_ARLA_VICE "CellServDB" +#define _PATH_ARLA_THESECELLS _PATH_ARLA_VICE "TheseCells" + +#define _PATH_OPENAFS_DEBIAN_VICE "/etc/openafs/" +#define _PATH_OPENAFS_DEBIAN_THISCELL _PATH_OPENAFS_DEBIAN_VICE "ThisCell" +#define _PATH_OPENAFS_DEBIAN_CELLSERVDB _PATH_OPENAFS_DEBIAN_VICE "CellServDB" +#define _PATH_OPENAFS_DEBIAN_THESECELLS _PATH_OPENAFS_DEBIAN_VICE "TheseCells" + +#define _PATH_OPENAFS_MACOSX_VICE "/var/db/openafs/etc/" +#define _PATH_OPENAFS_MACOSX_THISCELL _PATH_OPENAFS_MACOSX_VICE "ThisCell" +#define _PATH_OPENAFS_MACOSX_CELLSERVDB _PATH_OPENAFS_MACOSX_VICE "CellServDB" +#define _PATH_OPENAFS_MACOSX_THESECELLS _PATH_OPENAFS_MACOSX_VICE "TheseCells" + +#define _PATH_ARLA_DEBIAN_VICE "/etc/arla/" +#define _PATH_ARLA_DEBIAN_THISCELL _PATH_ARLA_DEBIAN_VICE "ThisCell" +#define _PATH_ARLA_DEBIAN_CELLSERVDB _PATH_ARLA_DEBIAN_VICE "CellServDB" +#define _PATH_ARLA_DEBIAN_THESECELLS _PATH_ARLA_DEBIAN_VICE "TheseCells" + +#define _PATH_ARLA_OPENBSD_VICE "/etc/afs/" +#define _PATH_ARLA_OPENBSD_THISCELL _PATH_ARLA_OPENBSD_VICE "ThisCell" +#define _PATH_ARLA_OPENBSD_CELLSERVDB _PATH_ARLA_OPENBSD_VICE "CellServDB" +#define _PATH_ARLA_OPENBSD_THESECELLS _PATH_ARLA_OPENBSD_VICE "TheseCells" + +extern int _kafs_debug; + +#endif /* __KAFS_H */ diff --git a/third_party/heimdal/lib/kafs/kafs_locl.h b/third_party/heimdal/lib/kafs/kafs_locl.h new file mode 100644 index 0000000..f4e2f64 --- /dev/null +++ b/third_party/heimdal/lib/kafs/kafs_locl.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __KAFS_LOCL_H__ +#define __KAFS_LOCL_H__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40 +#include +#endif +#ifdef HAVE_SYS_FILIO_H +#include +#endif +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif + +#ifdef HAVE_SYS_SYSCALL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN6_H +#include +#endif +#ifdef HAVE_NETINET6_IN6_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif +#ifdef HAVE_RESOLV_H +#include +#endif +#include + +#ifdef KRB5 +#include +#endif +#ifdef KRB5 +#include "crypto-headers.h" +typedef struct credentials CREDENTIALS; +#endif /* KRB5 */ +#ifndef NO_AFS +#include +#endif + +#include + +#include "afssysdefs.h" + +struct kafs_data; +struct kafs_token; +typedef int (*afslog_uid_func_t)(struct kafs_data *, + const char *, + const char *, + uid_t, + const char *); + +typedef int (*get_cred_func_t)(struct kafs_data*, const char*, const char*, + const char*, uid_t, struct kafs_token *); + +typedef char* (*get_realm_func_t)(struct kafs_data*, const char*); + +struct kafs_data { + const char *name; + afslog_uid_func_t afslog_uid; + get_cred_func_t get_cred; + get_realm_func_t get_realm; + const char *(*get_error)(struct kafs_data *, int); + void (*free_error)(struct kafs_data *, const char *); + void *data; +}; + +struct kafs_token { + struct ClearToken ct; + void *ticket; + size_t ticket_len; +}; + +void _kafs_foldup(char *, const char *); + +int _kafs_afslog_all_local_cells(struct kafs_data*, uid_t, const char*); + +int _kafs_get_cred(struct kafs_data*, const char*, const char*, const char *, + uid_t, struct kafs_token *); + +int +_kafs_realm_of_cell(struct kafs_data *, const char *, char **); + +int +_kafs_v4_to_kt(CREDENTIALS *, uid_t, struct kafs_token *); + +void +_kafs_fixup_viceid(struct ClearToken *, uid_t); + +int +_kafs_derive_des_key(krb5_enctype, void *, size_t, char[8]); + +#ifdef _AIX +int aix_pioctl(char*, int, struct ViceIoctl*, int); +int aix_setpag(void); +#endif + +#endif /* __KAFS_LOCL_H__ */ diff --git a/third_party/heimdal/lib/kafs/roken_rename.h b/third_party/heimdal/lib/kafs/roken_rename.h new file mode 100644 index 0000000..26da265 --- /dev/null +++ b/third_party/heimdal/lib/kafs/roken_rename.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001-2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __roken_rename_h__ +#define __roken_rename_h__ + +/* + * Libroken routines that are added libkafs + */ + +#define _resolve_debug _kafs_resolve_debug + +#define rk_dns_free_data _kafs_dns_free_data +#define rk_dns_lookup _kafs_dns_lookup +#define rk_dns_string_to_type _kafs_dns_string_to_type +#define rk_dns_type_to_string _kafs_dns_type_to_string +#define rk_dns_srv_order _kafs_dns_srv_order +#define rk_dns_make_query _kafs_dns_make_query +#define rk_dns_free_query _kafs_dns_free_query +#define rk_dns_parse_reply _kafs_dns_parse_reply + +#ifndef HAVE_STRTOK_R +#define rk_strtok_r _kafs_strtok_r +#endif +#ifndef HAVE_STRLCPY +#define rk_strlcpy _kafs_strlcpy +#endif +#ifndef HAVE_STRSEP +#define rk_strsep _kafs_strsep +#endif + +#endif /* __roken_rename_h__ */ diff --git a/third_party/heimdal/lib/kafs/rxkad_kdf.c b/third_party/heimdal/lib/kafs/rxkad_kdf.c new file mode 100644 index 0000000..b542e89 --- /dev/null +++ b/third_party/heimdal/lib/kafs/rxkad_kdf.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2013-2014 Carnegie Mellon University + * All rights reserved. + * + * Portions Copyright (c) 2013 by the Massachusetts Institute of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define HC_DEPRECATED_CRYPTO +#include "kafs_locl.h" + +static int rxkad_derive_des_key(const void *, size_t, char[8]); +static int compress_parity_bits(void *, size_t *); + +/** + * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a + * des key from another type of key. + * + * L is 64, as we take 64 random bits and turn them into a 56-bit des key. + * The output of hmac_md5 is 128 bits; we take the first 64 only, so n + * properly should be 1. However, we apply a slight variation due to the + * possibility of producing a weak des key. If the output key is weak, do NOT + * simply correct it, instead, the counter is advanced and the next output + * used. As such, we code so as to have n be the full 255 permitted by our + * encoding of the counter i in an 8-bit field. L itself is encoded as a + * 32-bit field, big-endian. We use the constant string "rxkad" as a label + * for this key derivation, the standard NUL byte separator, and omit a + * key-derivation context. The input key is unique to the krb5 service ticket, + * which is unlikely to be used in an other location. If it is used in such + * a fashion, both locations will derive the same des key from the PRF, but + * this is no different from if a krb5 des key had been used in the same way, + * as traditional krb5 rxkad uses the ticket session key directly as the token + * key. + * + * @param[in] in pointer to input key data + * @param[in] insize length of input key data + * @param[out] out 8-byte buffer to hold the derived key + * + * @return Returns 0 to indicate success, or an error code. + * + * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all + * 255 possible counter values each produced weak DES keys. This input + * cannot be used to produce a usable key. + */ +static int +rxkad_derive_des_key(const void *in, size_t insize, char out[8]) +{ + unsigned char i; + static unsigned char label[] = "rxkad"; + /* bits of output, as 32 bit word, MSB first */ + static unsigned char Lbuf[4] = { 0, 0, 0, 64 }; + /* only needs to be 16 for md5, but lets be sure it fits */ + unsigned char tmp[64]; + unsigned int mdsize; + DES_cblock ktmp; + HMAC_CTX mctx; + + /* stop when 8 bit counter wraps to 0 */ + for (i = 1; i; i++) { + HMAC_CTX_init(&mctx); + if (HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL) == 0) { + HMAC_CTX_cleanup(&mctx); + return ENOMEM; + } + HMAC_Update(&mctx, &i, 1); + HMAC_Update(&mctx, label, sizeof(label)); /* includes label and separator */ + HMAC_Update(&mctx, Lbuf, 4); + mdsize = sizeof(tmp); + HMAC_Final(&mctx, tmp, &mdsize); + HMAC_CTX_cleanup(&mctx); + memcpy(ktmp, tmp, 8); + DES_set_odd_parity(&ktmp); + if (!DES_is_weak_key(&ktmp)) { + memcpy(out, ktmp, 8); + return 0; + } + } + return KRB5DES_WEAK_KEY; +} + +/** + * This is the inverse of the random-to-key for 3des specified in + * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing + * the bits of each 8th byte as the lsb of the previous 7 bytes. + * + * @param[in,out] buffer Buffer containing the key to be converted + * @param[in,out] bufsiz Points to the size of the key data. On + * return, this is updated to reflect the size of the compressed data. + * + * @return Returns 0 to indicate success, or an error code. + * + * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes. + */ +static int +compress_parity_bits(void *buffer, size_t *bufsiz) +{ + unsigned char *cb, tmp; + int i, j, nk; + + if (*bufsiz % 8 != 0) + return KRB5_BAD_KEYSIZE; + cb = (unsigned char *)buffer; + nk = *bufsiz / 8; + for (i = 0; i < nk; i++) { + tmp = cb[8 * i + 7] >> 1; + for (j = 0; j < 7; j++) { + cb[8 * i + j] &= 0xfe; + cb[8 * i + j] |= tmp & 0x1; + tmp >>= 1; + } + } + for (i = 1; i < nk; i++) + memmove(cb + 7 * i, cb + 8 * i, 7); + *bufsiz = 7 * nk; + return 0; +} + +/** + * Derive a DES key for use with rxkad and fcrypt from a given Kerberos + * key of (almost) any type. This function encodes enctype-specific + * knowledge about how to derive a DES key from a given key type. + * If given a des key, use it directly; otherwise, perform any parity + * fixup that may be needed and pass through to the hmad-md5 bits. + * + * @param[in] enctype Kerberos enctype of the input key + * @param[in] keydata Input key data + * @param[in] keylen Size of input key data + * @param[out] output 8-byte buffer to hold the derived key + * + * @return Returns 0 to indicate success, or an error code. + * + * @retval KRB5_PROG_ETYPE_NOSUPP The enctype is one for which rxkad-kdf + * is not supported. This includes several reserved enctypes, enctype + * values used in PKINIT to stand for CMS algorithm identifiers, and all + * private-use (negative) enctypes. + * + * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes + * (for 3DES key types), exactly 8 bytes (for DES key types), or at least + * 8 bytes (for other key types). + * + * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all + * 255 possible counter values each produced weak DES keys. This input + * cannot be used to produce a usable key. + */ +int +_kafs_derive_des_key(krb5_enctype enctype, void *keydata, size_t keylen, + char output[8]) +{ + int ret = 0; + + switch ((int)enctype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + if (keylen != 8) + return KRB5_BAD_KEYSIZE; + + /* Extract session key */ + memcpy(output, keydata, 8); + break; + case ETYPE_NULL: + case 4: + case 6: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + return KRB5_PROG_ETYPE_NOSUPP; + /*In order to become a "Cryptographic Key" as specified in + * SP800-108, it must be indistinguishable from a random bitstring. */ + case ETYPE_DES3_CBC_MD5: + case ETYPE_OLD_DES3_CBC_SHA1: + case ETYPE_DES3_CBC_SHA1: + ret = compress_parity_bits(keydata, &keylen); + if (ret) + return ret; + HEIM_FALLTHROUGH; + default: + if (enctype < 0) + return KRB5_PROG_ETYPE_NOSUPP; + if (keylen < 7) + return KRB5_BAD_KEYSIZE; + ret = rxkad_derive_des_key(keydata, keylen, output); + } + return ret; +} diff --git a/third_party/heimdal/lib/kdfs/ChangeLog b/third_party/heimdal/lib/kdfs/ChangeLog new file mode 100644 index 0000000..c4bc2a3 --- /dev/null +++ b/third_party/heimdal/lib/kdfs/ChangeLog @@ -0,0 +1,28 @@ +2002-08-12 Johan Danielsson + + * k5dfspag.c: don't use ## in string concatenation + +2002-03-11 Assar Westerlund + + * Makefile.am (libkdfs_la_LDFLAGS): set versoin to 0:2:0 + +2002-01-23 Assar Westerlund + + * k5dfspag.c: use SIG_DFL and not SIG_IGN for SIGCHLD. + from "Todd C. Miller" + +2001-02-07 Assar Westerlund + + * k5dfspag.c: add config.h + +2000-12-11 Assar Westerlund + + * Makefile.am (libkdfs_la_LDFLAGS): set version to 0:1:0 + +2000-07-02 Assar Westerlund + + * k5dfspag.c: use krb5.h instead of krb5_locl.h + + * initial import from Ake Sandgren + + diff --git a/third_party/heimdal/lib/kdfs/Makefile.am b/third_party/heimdal/lib/kdfs/Makefile.am new file mode 100644 index 0000000..e31b240 --- /dev/null +++ b/third_party/heimdal/lib/kdfs/Makefile.am @@ -0,0 +1,12 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +lib_LTLIBRARIES = libkdfs.la + +libkdfs_la_SOURCES = \ + k5dfspag.c + +libkdfs_la_LDFLAGS = -version-info 0:3:0 + +EXTRA_DIST = NTMakefile diff --git a/third_party/heimdal/lib/kdfs/NTMakefile b/third_party/heimdal/lib/kdfs/NTMakefile new file mode 100644 index 0000000..4ec8f31 --- /dev/null +++ b/third_party/heimdal/lib/kdfs/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\kdfs + +!include ../../windows/NTMakefile.w32 + diff --git a/third_party/heimdal/lib/kdfs/k5dfspag.c b/third_party/heimdal/lib/kdfs/k5dfspag.c new file mode 100644 index 0000000..9db2555 --- /dev/null +++ b/third_party/heimdal/lib/kdfs/k5dfspag.c @@ -0,0 +1,368 @@ +/* + * lib/krb5/os/k5dfspag.c + * + * New Kerberos module to issue the DFS PAG syscalls. + * It also contains the routine to fork and exec the + * k5dcecon routine to do most of the work. + * + * This file is designed to be as independent of DCE + * and DFS as possible. The only dependencies are on + * the syscall numbers. If DFS not running or not installed, + * the sig handlers will catch and the signal and + * will continue. + * + * krb5_dfs_newpag and krb5_dfs_getpag should not be real + * Kerberos routines, since they should be setpag and getpag + * in the DCE library, but without the DCE baggage. + * Thus they don't have context, and don't return a krb5 error. + * + * + * + * krb5_dfs_pag() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +RCSID("$Id$"); + +#include + +#ifdef DCE + +#include +#include +#include +#include +#include + +/* Only run this DFS PAG code on systems with POSIX + * All that we are interested in dor:, AIX 4.x, + * Solaris 2.5.x, HPUX 10.x Even SunOS 4.1.4, AIX 3.2.5 + * and SGI 5.3 are OK. This simplifies + * the build/configure which I don't want to change now. + * All of them also have waitpid as well. + */ + +#define POSIX_SETJMP +#define POSIX_SIGNALS +#define HAVE_WAITPID + +#include +#include +#ifndef POSIX_SETJMP +#undef sigjmp_buf +#undef sigsetjmp +#undef siglongjmp +#define sigjmp_buf jmp_buf +#define sigsetjmp(j,s) setjmp(j) +#define siglongjmp longjmp +#endif + +#ifdef POSIX_SIGNALS +typedef struct sigaction handler; +#define handler_init(H,F) (sigemptyset(&(H).sa_mask), \ + (H).sa_flags=0, \ + (H).sa_handler=(F)) +#define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD) +#define handler_set(S,OLD) sigaction(S, &OLD, NULL) +#else +typedef sigtype (*handler)(); +#define handler_init(H,F) ((H) = (F)) +#define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW))) +#define handler_set(S,OLD) (signal ((S), (OLD))) +#endif + +#define krb5_sigtype void +#define WAIT_USES_INT +typedef krb5_sigtype sigtype; + + +/* + * Need some syscall numbers based on different systems. + * These are based on: + * HPUX 10.10 /opt/dce/include/dcedfs/syscall.h + * Solaris 2.5 /opt/dcelocal/share/include/dcedfs/syscall.h + * AIX 4.2 - needs some funny games with load and kafs_syscall + * to get the kernel extentions. There should be a better way! + * + * DEE 5/27/97 + * + */ + + +#define AFSCALL_SETPAG 2 +#define AFSCALL_GETPAG 11 + +#if defined(sun) +#define AFS_SYSCALL 72 + +#elif defined(hpux) +/* assume HPUX 10 + or is it 50 */ +#define AFS_SYSCALL 326 + +#elif defined(_AIX) +#ifndef DPAGAIX +#define DPAGAIX LIBEXECDIR "/dpagaix" +#endif +int *load(); +static int (*dpagaix)(int, int, int, int, int, int) = 0; + +#elif defined(sgi) || defined(_sgi) +#define AFS_SYSCALL 206+1000 + +#else +#define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL) +#endif + + +#ifdef WAIT_USES_INT + int wait_status; +#else /* WAIT_USES_INT */ + union wait wait_status; +#endif /* WAIT_USES_INT */ + +#ifndef K5DCECON +#define K5DCECON LIBEXECDIR "/k5dcecon" +#endif + +/* + * mysig() + * + * signal handler if DFS not running + * + */ + +static sigjmp_buf setpag_buf; + +static sigtype mysig() +{ + siglongjmp(setpag_buf, 1); +} + +/* + * krb5_dfs_pag_syscall() + * + * wrapper for the syscall with signal handlers + * + */ + +static int krb5_dfs_pag_syscall(opt1,opt2) + int opt1; + int opt2; +{ + handler sa1, osa1; + handler sa2, osa2; + int pag = -2; + + handler_init (sa1, mysig); + handler_init (sa2, mysig); + handler_swap (SIGSYS, sa1, osa1); + handler_swap (SIGSEGV, sa2, osa2); + + if (sigsetjmp(setpag_buf, 1) == 0) { + +#if defined(_AIX) + if (!dpagaix) + dpagaix = load(DPAGAIX, 0, 0); + if (dpagaix) + pag = (*dpagaix)(opt1, opt2, 0, 0, 0, 0); +#else + pag = syscall(AFS_SYSCALL, opt1, opt2, 0, 0, 0, 0); +#endif + + handler_set (SIGSYS, osa1); + handler_set (SIGSEGV, osa2); + return(pag); + } + + /* syscall failed! return 0 */ + handler_set (SIGSYS, osa1); + handler_set (SIGSEGV, osa2); + return(-2); +} + +/* + * krb5_dfs_newpag() + * + * issue a DCE/DFS setpag system call to set the newpag + * for this process. This takes advantage of a currently + * undocumented feature of the Transarc port of DFS. + * Even in DCE 1.2.2 for which the source is available, + * (but no vendors have released), this feature is not + * there, but it should be, or could be added. + * If new_pag is zero, then the syscall will get a new pag + * and return its value. + */ + +int krb5_dfs_newpag(new_pag) + int new_pag; +{ + return(krb5_dfs_pag_syscall(AFSCALL_SETPAG, new_pag)); +} + +/* + * krb5_dfs_getpag() + * + * get the current PAG. Used mostly as a test. + */ + +int krb5_dfs_getpag() +{ + return(krb5_dfs_pag_syscall(AFSCALL_GETPAG, 0)); +} + +/* + * krb5_dfs_pag() + * + * Given a principal and local username, + * fork and exec the k5dcecon module to create + * refresh or join a new DCE/DFS + * Process Authentication Group (PAG) + * + * This routine should be called after krb5_kuserok has + * determined that this combination of local user and + * principal are acceptable for the local host. + * + * It should also be called after a forwarded ticket has + * been received, and the KRB5CCNAME environment variable + * has been set to point at it. k5dcecon will convert this + * to a new DCE context and a new pag and replace KRB5CCNAME + * in the environment. + * + * If there is no forwarded ticket, k5dcecon will attempt + * to join an existing PAG for the same principal and local + * user. + * + * And it should be called before access to the home directory + * as this may be in DFS, not accessible by root, and require + * the PAG to have been setup. + * + * The krb5_afs_pag can be called after this routine to + * use the the cache obtained by k5dcecon to get an AFS token. + * DEE - 7/97 + */ + +int krb5_dfs_pag(context, flag, principal, luser) + krb5_context context; + int flag; /* 1 if a forwarded TGT is to be used */ + krb5_principal principal; + const char *luser; + +{ + + struct stat stx; + int fd[2]; + int i,j; + int pid; + int new_pag; + int pag; + char newccname[MAXPATHLEN] = ""; + char *princ; + int err; + struct sigaction newsig, oldsig; + +#ifdef WAIT_USES_INT + int wait_status; +#else /* WAIT_USES_INT */ + union wait wait_status; +#endif /* WAIT_USES_INT */ + + if (krb5_unparse_name(context, principal, &princ)) + return(0); + + /* test if DFS is running or installed */ + if (krb5_dfs_getpag() == -2) + return(0); /* DFS not running, don't try */ + + if (pipe(fd) == -1) + return(0); + + /* Make sure that telnetd.c's SIGCHLD action don't happen right now... */ + memset((char *)&newsig, 0, sizeof(newsig)); + newsig.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &newsig, &oldsig); + + pid = fork(); + if (pid <0) + return(0); + + if (pid == 0) { /* child process */ + + close(1); /* close stdout */ + dup(fd[1]); /* point stdout at pipe here */ + close(fd[0]); /* don't use end of pipe here */ + close(fd[1]); /* pipe now as stdout */ + + execl(K5DCECON, "k5dcecon", + (flag) ? "-f" : "-s" , + "-l", luser, + "-p", princ, (char *)0); + + exit(127); /* incase execl fails */ + } + + /* parent, wait for child to finish */ + + close(fd[1]); /* don't need this end of pipe */ + +/* #if defined(sgi) || defined(_sgi) */ + /* wait_status.w_status = 0; */ + /* waitpid((pid_t) pid, &wait_status.w_status, 0); */ +/* #else */ + + + wait_status = 0; +#ifdef HAVE_WAITPID + err = waitpid((pid_t) pid, &wait_status, 0); +#else /* HAVE_WAITPID */ + err = wait4(pid, &wait_status, 0, (struct rusage *) NULL); +#endif /* HAVE_WAITPID */ +/* #endif */ + + sigaction(SIGCHLD, &oldsig, 0); + if (WIFEXITED(wait_status)){ + if (WEXITSTATUS(wait_status) == 0) { + i = 1; + j = 0; + while (i != 0) { + i = read(fd[0], &newccname[j], sizeof(newccname)-1-j); + if ( i > 0) + j += i; + if (j >= sizeof(newccname)-1) + i = 0; + } + close(fd[0]); + if (j > 0) { + newccname[j] = '\0'; + esetenv("KRB5CCNAME",newccname,1); + sscanf(&newccname[j-8],"%8x",&new_pag); + if (new_pag && strncmp("FILE:/opt/dcelocal/var/security/creds/dcecred_", newccname, 46) == 0) { + if((pag = krb5_dfs_newpag(new_pag)) != -2) { + return(pag); + } + } + } + } + } + return(0); /* something not right */ +} + +#else /* DCE */ + +/* + * krb5_dfs_pag - dummy version for the lib for systems + * which don't have DFS, or the needed setpag kernel code. + */ + +krb5_boolean +krb5_dfs_pag(context, principal, luser) + krb5_context context; + krb5_principal principal; + const char *luser; +{ + return(0); +} + +#endif /* DCE */ diff --git a/third_party/heimdal/lib/krb5/Makefile.am b/third_party/heimdal/lib/krb5/Makefile.am new file mode 100644 index 0000000..ecce461 --- /dev/null +++ b/third_party/heimdal/lib/krb5/Makefile.am @@ -0,0 +1,454 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_CPPFLAGS += -I../com_err -I$(srcdir)/../com_err -I../base -I$(srcdir)/../base $(INCLUDE_sqlite3) $(INCLUDE_libintl) $(INCLUDE_openssl_crypto) + +bin_PROGRAMS = verify_krb5_conf + +noinst_PROGRAMS = \ + krbhst-test \ + test_alname \ + test_crypto \ + test_forward \ + test_get_addrs \ + test_gic \ + test_kuserok \ + test_renew \ + test_rfc3961 + + +noinst_LTLIBRARIES = \ + librfc3961.la + +TESTS = \ + aes-test \ + derived-key-test \ + n-fold-test \ + parse-name-test \ + pseudo-random-test \ + store-test \ + string-to-key-test \ + test_acl \ + test_addr \ + test_cc \ + test_config \ + test_fx \ + test_prf \ + test_store \ + test_crypto_wrapping \ + test_keytab \ + test_mem \ + test_pac \ + test_plugin \ + test_princ \ + test_pkinit_dh2key \ + test_pknistkdf \ + test_time \ + test_expand_toks \ + test_x500 + +check_DATA = test_config_strings.out + +check_PROGRAMS = $(TESTS) test_hostname test_ap-req test_canon test_set_kvno0 \ + test_mkforwardable + +LDADD = libkrb5.la \ + $(LIB_hcrypto) \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(LIB_heimbase) $(LIB_roken) + +if HAVE_KEYUTILS +test_cc_LDADD = $(LDADD) -lkeyutils +else +test_cc_LDADD = $(LDADD) +endif + +if PKINIT +LIB_pkinit = ../hx509/libhx509.la +endif + +if have_scc +use_sqlite = $(LIB_sqlite3) +endif + +libkrb5_la_LIBADD = \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/ipc/libheim-ipcc.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(top_builddir)/lib/base/libheimbase.la \ + $(top_builddir)/lib/hx509/libhx509.la \ + $(LIB_openssl_crypto) \ + $(use_sqlite) \ + $(LIB_com_err) \ + $(LIB_hcrypto) \ + $(LIB_libintl) \ + $(LIBADD_roken) \ + $(PTHREAD_LIBADD) \ + $(LIB_add_key) \ + $(LIB_door_create) + +librfc3961_la_LIBADD = \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/ipc/libheim-ipcc.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(LIB_pkinit) \ + $(use_sqlite) \ + $(LIB_com_err) \ + $(LIB_hcrypto) \ + $(LIB_libintl) \ + $(LIBADD_roken) \ + $(PTHREAD_LIBADD) \ + $(LIB_add_key) \ + $(LIB_door_create) + +lib_LTLIBRARIES = libkrb5.la + +ERR_FILES = krb5_err.c krb_err.c k524_err.c k5e1_err.c kx509_err.c + +libkrb5_la_CPPFLAGS = \ + -DBUILD_KRB5_LIB \ + $(AM_CPPFLAGS) \ + -DHEIMDAL_LOCALEDIR='"$(localedir)"' + +librfc3961_la_CPPFLAGS = \ + -DBUILD_KRB5_LIB \ + $(AM_CPPFLAGS) \ + -DHEIMDAL_LOCALEDIR='"$(localedir)"' + +dist_libkrb5_la_SOURCES = \ + acache.c \ + acl.c \ + add_et_list.c \ + addr_families.c \ + an2ln_plugin.h \ + aname_to_localname.c \ + appdefault.c \ + asn1_glue.c \ + auth_context.c \ + authdata.c \ + build_ap_req.c \ + build_auth.c \ + cache.c \ + ccache_plugin.h \ + changepw.c \ + codec.c \ + config_file.c \ + convert_creds.c \ + constants.c \ + context.c \ + copy_host_realm.c \ + crc.c \ + creds.c \ + crypto.c \ + crypto.h \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ + crypto-algs.c \ + crypto-arcfour.c \ + crypto-des.c \ + crypto-des-common.c \ + crypto-des3.c \ + crypto-evp.c \ + crypto-null.c \ + crypto-pk.c \ + crypto-rand.c \ + doxygen.c \ + data.c \ + db_plugin.c \ + db_plugin.h \ + dcache.c \ + deprecated.c \ + digest.c \ + eai_to_heim_errno.c \ + enomem.c \ + error_string.c \ + expand_hostname.c \ + expand_path.c \ + fast.c \ + fcache.c \ + free.c \ + free_host_realm.c \ + generate_seq_number.c \ + generate_subkey.c \ + get_addrs.c \ + get_cred.c \ + get_default_principal.c \ + get_default_realm.c \ + get_for_creds.c \ + get_host_realm.c \ + get_in_tkt.c \ + get_port.c \ + init_creds.c \ + init_creds_pw.c \ + kcm.c \ + kcm.h \ + keyblock.c \ + keytab.c \ + keytab_any.c \ + keytab_file.c \ + keytab_keyfile.c \ + keytab_memory.c \ + krb5_locl.h \ + krcache.c \ + krbhst.c \ + kuserok.c \ + kuserok_plugin.h \ + kx509.c \ + log.c \ + mcache.c \ + misc.c \ + mk_cred.c \ + mk_error.c \ + mk_priv.c \ + mk_rep.c \ + mk_req.c \ + mk_req_ext.c \ + mk_safe.c \ + mit_glue.c \ + net_read.c \ + net_write.c \ + n-fold.c \ + pac.c \ + padata.c \ + pcache.c \ + pkinit.c \ + pkinit-ec.c \ + principal.c \ + prog_setup.c \ + prompter_posix.c \ + rd_cred.c \ + rd_error.c \ + rd_priv.c \ + rd_rep.c \ + rd_req.c \ + rd_safe.c \ + read_message.c \ + recvauth.c \ + replay.c \ + salt.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ + salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ + sp800-108-kdf.c \ + scache.c \ + send_to_kdc.c \ + sendauth.c \ + set_default_realm.c \ + sock_principal.c \ + store.c \ + store-int.c \ + store-int.h \ + store_emem.c \ + store_fd.c \ + store_mem.c \ + store_sock.c \ + store_stdio.c \ + plugin.c \ + ticket.c \ + time.c \ + transited.c \ + verify_init.c \ + verify_user.c \ + version.c \ + warn.c \ + write_message.c + +nodist_libkrb5_la_SOURCES = \ + $(ERR_FILES) + +libkrb5_la_DEPENDENCIES = \ + version-script.map + +libkrb5_la_LDFLAGS = -version-info 26:0:0 +if FRAMEWORK_COREFOUNDATION +libkrb5_la_LDFLAGS += -framework CoreFoundation +endif + +if versionscript +libkrb5_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + +ALL_OBJECTS = $(libkrb5_la_OBJECTS) +ALL_OBJECTS += $(verify_krb5_conf_OBJECTS) +ALL_OBJECTS += $(librfc3961_la_OBJECTS) +ALL_OBJECTS += $(librfc3961_la_OBJECTS) +ALL_OBJECTS += $(krbhst_test_OBJECTS) +ALL_OBJECTS += $(test_alname_OBJECTS) +ALL_OBJECTS += $(test_crypto_OBJECTS) +ALL_OBJECTS += $(test_forward_OBJECTS) +ALL_OBJECTS += $(test_get_addrs_OBJECTS) +ALL_OBJECTS += $(test_gic_OBJECTS) +ALL_OBJECTS += $(test_kuserok_OBJECTS) +ALL_OBJECTS += $(test_renew_OBJECTS) +ALL_OBJECTS += $(test_rfc3961_OBJECTS) + +$(ALL_OBJECTS): $(srcdir)/krb5-protos.h $(srcdir)/krb5-private.h +$(ALL_OBJECTS): krb5_err.h k524_err.h k5e1_err.h \ + krb_err.h k524_err.h kx509_err.h + +librfc3961_la_SOURCES = \ + crc.c \ + crypto.c \ + crypto.h \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ + crypto-algs.c \ + crypto-arcfour.c \ + crypto-des.c \ + crypto-des-common.c \ + crypto-des3.c \ + crypto-evp.c \ + crypto-null.c \ + crypto-pk.c \ + crypto-rand.c \ + crypto-stubs.c \ + data.c \ + enomem.c \ + error_string.c \ + keyblock.c \ + n-fold.c \ + salt.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ + salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ + sp800-108-kdf.c \ + store-int.c \ + warn.c + +test_rfc3961_LDADD = \ + librfc3961.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/wind/libwind.la \ + $(LIB_hcrypto) \ + $(LIB_roken) + +if DEVELOPER_MODE +headerdeps = $(dist_libkrb5_la_SOURCES) +endif + +$(srcdir)/krb5-protos.h: $(headerdeps) + @cd $(srcdir) && perl ../../cf/make-proto.pl -E KRB5_LIB -q -P comment -o krb5-protos.h $(dist_libkrb5_la_SOURCES) || rm -f krb5-protos.h + +$(srcdir)/krb5-private.h: $(headerdeps) + @cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p krb5-private.h $(dist_libkrb5_la_SOURCES) || rm -f krb5-private.h + +man_MANS = \ + kerberos.8 \ + krb5.conf.5 \ + krb5-plugin.7 \ + krb524_convert_creds_kdc.3 \ + krb5_425_conv_principal.3 \ + krb5_acl_match_file.3 \ + krb5_aname_to_localname.3 \ + krb5_appdefault.3 \ + krb5_auth_context.3 \ + krb5_c_make_checksum.3 \ + krb5_check_transited.3 \ + krb5_create_checksum.3 \ + krb5_creds.3 \ + krb5_digest.3 \ + krb5_eai_to_heim_errno.3 \ + krb5_encrypt.3 \ + krb5_find_padata.3 \ + krb5_generate_random_block.3 \ + krb5_get_all_client_addrs.3 \ + krb5_get_credentials.3 \ + krb5_get_creds.3 \ + krb5_get_forwarded_creds.3 \ + krb5_get_in_cred.3 \ + krb5_get_init_creds.3 \ + krb5_get_krbhst.3 \ + krb5_getportbyname.3 \ + krb5_init_context.3 \ + krb5_is_thread_safe.3 \ + krb5_krbhst_init.3 \ + krb5_mk_req.3 \ + krb5_mk_safe.3 \ + krb5_openlog.3 \ + krb5_parse_name.3 \ + krb5_principal.3 \ + krb5_rcache.3 \ + krb5_rd_error.3 \ + krb5_rd_safe.3 \ + krb5_set_default_realm.3 \ + krb5_set_password.3 \ + krb5_string_to_key.3 \ + krb5_timeofday.3 \ + krb5_verify_init_creds.3 \ + krb5_verify_user.3 \ + verify_krb5_conf.8 + +dist_include_HEADERS = \ + krb5.h \ + $(srcdir)/krb5-protos.h \ + krb5_ccapi.h + +noinst_HEADERS = $(srcdir)/krb5-private.h + + +nodist_include_HEADERS = krb5_err.h k524_err.h k5e1_err.h kx509_err.h + +# XXX use nobase_include_HEADERS = krb5/locate_plugin.h +krb5dir = $(includedir)/krb5 +krb5_HEADERS = \ + an2ln_plugin.h \ + ccache_plugin.h \ + db_plugin.h \ + kuserok_plugin.h \ + locate_plugin.h \ + send_to_kdc_plugin.h + +build_HEADERZ = \ + $(krb5_HEADERS) \ + krb_err.h + +CLEANFILES = \ + test_config_strings.out \ + test-store-data \ + krb5_err.c krb5_err.h \ + krb_err.c krb_err.h \ + k524_err.c k524_err.h \ + k5e1_err.c k5e1_err.h \ + kx509_err.c kx509_err.h + +$(libkrb5_la_OBJECTS): krb5_err.h krb_err.h k524_err.h k5e1_err.h kx509_err.h + +test_config_strings.out: test_config_strings.cfg + $(CP) $(srcdir)/test_config_strings.cfg test_config_strings.out + +EXTRA_DIST = \ + NTMakefile \ + dll.c \ + libkrb5-exports.def.in \ + verify_krb5_conf-version.rc \ + krb5_err.et \ + krb_err.et \ + k524_err.et \ + k5e1_err.et \ + kx509_err.et \ + $(man_MANS) \ + version-script.map \ + test_config_strings.cfg \ + krb5.moduli + +#sysconf_DATA = krb5.moduli + +# to help stupid solaris make + +krb5_err.h: krb5_err.et + +krb_err.h: krb_err.et + +k524_err.h: k524_err.et + +k5e1_err.h: k5e1_err.et + +kx509_err.h: kx509_err.et diff --git a/third_party/heimdal/lib/krb5/NTMakefile b/third_party/heimdal/lib/krb5/NTMakefile new file mode 100644 index 0000000..993e76f --- /dev/null +++ b/third_party/heimdal/lib/krb5/NTMakefile @@ -0,0 +1,542 @@ +######################################################################## +# +# Copyright (c) 2009 - 2017, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\krb5 + +intcflags=-I$(SRCDIR) -I$(SRCDIR)\..\com_err -I$(SRCDIR)\..\base + +!include ../../windows/NTMakefile.w32 + +libkrb5_OBJS = \ + $(OBJ)\acache.obj \ + $(OBJ)\acl.obj \ + $(OBJ)\add_et_list.obj \ + $(OBJ)\addr_families.obj \ + $(OBJ)\aname_to_localname.obj \ + $(OBJ)\appdefault.obj \ + $(OBJ)\asn1_glue.obj \ + $(OBJ)\auth_context.obj \ + $(OBJ)\authdata.obj \ + $(OBJ)\build_ap_req.obj \ + $(OBJ)\build_auth.obj \ + $(OBJ)\cache.obj \ + $(OBJ)\changepw.obj \ + $(OBJ)\codec.obj \ + $(OBJ)\config_file.obj \ + $(OBJ)\constants.obj \ + $(OBJ)\context.obj \ + $(OBJ)\convert_creds.obj \ + $(OBJ)\copy_host_realm.obj \ + $(OBJ)\crc.obj \ + $(OBJ)\creds.obj \ + $(OBJ)\crypto.obj \ + $(OBJ)\crypto-aes-sha1.obj \ + $(OBJ)\crypto-aes-sha2.obj \ + $(OBJ)\crypto-algs.obj \ + $(OBJ)\crypto-arcfour.obj \ + $(OBJ)\crypto-des-common.obj \ + $(OBJ)\crypto-des.obj \ + $(OBJ)\crypto-des3.obj \ + $(OBJ)\crypto-evp.obj \ + $(OBJ)\crypto-null.obj \ + $(OBJ)\crypto-pk.obj \ + $(OBJ)\crypto-rand.obj \ + $(OBJ)\data.obj \ + $(OBJ)\dcache.obj \ + $(OBJ)\db_plugin.obj \ + $(OBJ)\deprecated.obj \ + $(OBJ)\digest.obj \ + $(OBJ)\dll.obj \ + $(OBJ)\eai_to_heim_errno.obj \ + $(OBJ)\enomem.obj \ + $(OBJ)\error_string.obj \ + $(OBJ)\expand_hostname.obj \ + $(OBJ)\expand_path.obj \ + $(OBJ)\fast.obj \ + $(OBJ)\fcache.obj \ + $(OBJ)\free.obj \ + $(OBJ)\free_host_realm.obj \ + $(OBJ)\generate_seq_number.obj \ + $(OBJ)\generate_subkey.obj \ + $(OBJ)\get_addrs.obj \ + $(OBJ)\get_cred.obj \ + $(OBJ)\get_default_principal.obj \ + $(OBJ)\get_default_realm.obj \ + $(OBJ)\get_for_creds.obj \ + $(OBJ)\get_host_realm.obj \ + $(OBJ)\get_in_tkt.obj \ + $(OBJ)\get_port.obj \ + $(OBJ)\init_creds.obj \ + $(OBJ)\init_creds_pw.obj \ + $(OBJ)\kcm.obj \ + $(OBJ)\keyblock.obj \ + $(OBJ)\keytab.obj \ + $(OBJ)\keytab_any.obj \ + $(OBJ)\keytab_file.obj \ + $(OBJ)\keytab_keyfile.obj \ + $(OBJ)\keytab_memory.obj \ + $(OBJ)\krbhst.obj \ + $(OBJ)\kuserok.obj \ + $(OBJ)\kx509.obj \ + $(OBJ)\log.obj \ + $(OBJ)\mcache.obj \ + $(OBJ)\misc.obj \ + $(OBJ)\mit_glue.obj \ + $(OBJ)\mk_cred.obj \ + $(OBJ)\mk_error.obj \ + $(OBJ)\mk_priv.obj \ + $(OBJ)\mk_rep.obj \ + $(OBJ)\mk_req.obj \ + $(OBJ)\mk_req_ext.obj \ + $(OBJ)\mk_safe.obj \ + $(OBJ)\net_read.obj \ + $(OBJ)\net_write.obj \ + $(OBJ)\n-fold.obj \ + $(OBJ)\pac.obj \ + $(OBJ)\padata.obj \ + $(OBJ)\pcache.obj \ + $(OBJ)\pkinit.obj \ + $(OBJ)\pkinit-ec.obj \ + $(OBJ)\plugin.obj \ + $(OBJ)\principal.obj \ + $(OBJ)\prog_setup.obj \ + $(OBJ)\prompter_posix.obj \ + $(OBJ)\rd_cred.obj \ + $(OBJ)\rd_error.obj \ + $(OBJ)\rd_priv.obj \ + $(OBJ)\rd_rep.obj \ + $(OBJ)\rd_req.obj \ + $(OBJ)\rd_safe.obj \ + $(OBJ)\read_message.obj \ + $(OBJ)\recvauth.obj \ + $(OBJ)\replay.obj \ + $(OBJ)\salt-aes-sha1.obj \ + $(OBJ)\salt-aes-sha2.obj \ + $(OBJ)\salt-arcfour.obj \ + $(OBJ)\salt-des.obj \ + $(OBJ)\salt-des3.obj \ + $(OBJ)\salt.obj \ + $(OBJ)\scache.obj \ + $(OBJ)\send_to_kdc.obj \ + $(OBJ)\sendauth.obj \ + $(OBJ)\set_default_realm.obj \ + $(OBJ)\sock_principal.obj \ + $(OBJ)\sp800-108-kdf.obj \ + $(OBJ)\store.obj \ + $(OBJ)\store-int.obj \ + $(OBJ)\store_emem.obj \ + $(OBJ)\store_fd.obj \ + $(OBJ)\store_mem.obj \ + $(OBJ)\store_sock.obj \ + $(OBJ)\store_stdio.obj \ + $(OBJ)\ticket.obj \ + $(OBJ)\time.obj \ + $(OBJ)\transited.obj \ + $(OBJ)\verify_init.obj \ + $(OBJ)\verify_user.obj \ + $(OBJ)\version.obj \ + $(OBJ)\warn.obj \ + $(OBJ)\write_message.obj + +libkrb5_gen_OBJS= \ + $(OBJ)\krb5_err.obj \ + $(OBJ)\krb_err.obj \ + $(OBJ)\k524_err.obj \ + $(OBJ)\k5e1_err.obj + +INCFILES= \ + $(INCDIR)\k524_err.h \ + $(INCDIR)\k5e1_err.h \ + $(INCDIR)\kx509_err.h \ + $(INCDIR)\kcm.h \ + $(INCDIR)\krb_err.h \ + $(INCDIR)\krb5.h \ + $(INCDIR)\krb5_ccapi.h \ + $(INCDIR)\krb5_err.h \ + $(INCDIR)\krb5_locl.h \ + $(INCDIR)\krb5-protos.h \ + $(INCDIR)\krb5-private.h \ + $(INCDIR)\crypto.h \ + $(INCDIR)\an2ln_plugin.h \ + $(INCDIR)\ccache_plugin.h \ + $(INCDIR)\db_plugin.h \ + $(INCDIR)\kuserok_plugin.h \ + $(INCDIR)\locate_plugin.h \ + $(INCDIR)\send_to_kdc_plugin.h + +all:: $(INCFILES) + +clean:: + -$(RM) $(INCFILES) + +dist_libkrb5_la_SOURCES = \ + acache.c \ + acl.c \ + add_et_list.c \ + addr_families.c \ + aname_to_localname.c \ + appdefault.c \ + asn1_glue.c \ + auth_context.c \ + authdata.c \ + build_ap_req.c \ + build_auth.c \ + cache.c \ + changepw.c \ + codec.c \ + config_file.c \ + constants.c \ + context.c \ + copy_host_realm.c \ + crc.c \ + creds.c \ + crypto.c \ + crypto.h \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ + crypto-algs.c \ + crypto-arcfour.c \ + crypto-des.c \ + crypto-des-common.c \ + crypto-des3.c \ + crypto-evp.c \ + crypto-pk.c \ + crypto-rand.c \ + db_plugin.c \ + doxygen.c \ + data.c \ + dcache.c \ + deprecated.c \ + digest.c \ + eai_to_heim_errno.c \ + enomem.c \ + error_string.c \ + expand_hostname.c \ + expand_path.c \ + fast.c \ + fcache.c \ + free.c \ + free_host_realm.c \ + generate_seq_number.c \ + generate_subkey.c \ + get_addrs.c \ + get_cred.c \ + get_default_principal.c \ + get_default_realm.c \ + get_for_creds.c \ + get_host_realm.c \ + get_in_tkt.c \ + get_port.c \ + init_creds.c \ + init_creds_pw.c \ + kcm.c \ + kcm.h \ + keyblock.c \ + keytab.c \ + keytab_any.c \ + keytab_file.c \ + keytab_keyfile.c \ + keytab_memory.c \ + krb5_locl.h \ + krbhst.c \ + kuserok.c \ + kx509.c \ + log.c \ + mcache.c \ + misc.c \ + mk_cred.c \ + mk_error.c \ + mk_priv.c \ + mk_rep.c \ + mk_req.c \ + mk_req_ext.c \ + mk_safe.c \ + mit_glue.c \ + net_read.c \ + net_write.c \ + n-fold.c \ + pac.c \ + padata.c \ + pkinit.c \ + pkinit-ec.c \ + plugin.c \ + principal.c \ + prog_setup.c \ + prompter_posix.c \ + rd_cred.c \ + rd_error.c \ + rd_priv.c \ + rd_rep.c \ + rd_req.c \ + rd_safe.c \ + read_message.c \ + recvauth.c \ + replay.c \ + salt.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ + salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ + scache.c \ + send_to_kdc.c \ + sendauth.c \ + set_default_realm.c \ + sock_principal.c \ + sp800-108-kdf.c \ + store.c \ + store-int.c \ + store-int.h \ + store_emem.c \ + store_fd.c \ + store_mem.c \ + store_sock.c \ + store_stdio.c \ + pcache.c \ + plugin.c \ + ticket.c \ + time.c \ + transited.c \ + verify_init.c \ + verify_user.c \ + version.c \ + warn.c \ + write_message.c + +$(OBJ)\krb5-protos.h: $(dist_libkrb5_la_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -E KRB5_LIB -q -P remove -o $(OBJ)\krb5-protos.h $(dist_libkrb5_la_SOURCES) || $(RM) -f $(OBJ)\krb5-protos.h + +$(OBJ)\krb5-private.h: $(dist_libkrb5_la_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\krb5-private.h $(dist_libkrb5_la_SOURCES) || $(RM) -f $(OBJ)\krb5-private.h + +$(OBJ)\krb5_err.c $(OBJ)\krb5_err.h: krb5_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\krb5_err.et + cd $(SRCDIR) + +$(OBJ)\krb_err.c $(OBJ)\krb_err.h: krb_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\krb_err.et + cd $(SRCDIR) + +$(OBJ)\k524_err.c $(OBJ)\k524_err.h: k524_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\k524_err.et + cd $(SRCDIR) + +$(OBJ)\k5e1_err.c $(OBJ)\k5e1_err.h: k5e1_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\k5e1_err.et + cd $(SRCDIR) + +$(OBJ)\kx509_err.c $(OBJ)\kx509_err.h: kx509_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\kx509_err.et + cd $(SRCDIR) + +#---------------------------------------------------------------------- +# libkrb5 + +$(LIBKRB5): $(libkrb5_OBJS) $(libkrb5_gen_OBJS) + $(LIBCON_C) -OUT:$@ $(LIBHEIMBASE) $(LIB_openssl_crypto) @<< +$(libkrb5_OBJS: = +) +$(libkrb5_gen_OBJS: = +) +<< + +all:: $(LIBKRB5) + +clean:: + -$(RM) $(LIBKRB5) + +$(OBJ)\libkrb5-exports.def: libkrb5-exports.def.in $(INCDIR)\config.h + $(CPREPROCESSOUT) libkrb5-exports.def.in > $@ || $(RM) $@ + +all:: $(OBJ)\libkrb5-exports.def + +clean:: + -$(RM) $(OBJ)\libkrb5-exports.def + +#---------------------------------------------------------------------- +# librfc3961 + +librfc3961_OBJS=\ + $(OBJ)\crc.obj \ + $(OBJ)\crypto.obj \ + $(OBJ)\crypto-aes-sha1.obj \ + $(OBJ)\crypto-aes-sha2.obj \ + $(OBJ)\crypto-algs.obj \ + $(OBJ)\crypto-arcfour.obj \ + $(OBJ)\crypto-des.obj \ + $(OBJ)\crypto-des-common.obj \ + $(OBJ)\crypto-des3.obj \ + $(OBJ)\crypto-evp.obj \ + $(OBJ)\crypto-null.obj \ + $(OBJ)\crypto-pk.obj \ + $(OBJ)\crypto-rand.obj \ + $(OBJ)\crypto-stubs.obj \ + $(OBJ)\data.obj \ + $(OBJ)\error_string.obj \ + $(OBJ)\keyblock.obj \ + $(OBJ)\n-fold.obj \ + $(OBJ)\salt.obj \ + $(OBJ)\salt-aes-sha1.obj \ + $(OBJ)\salt-aes-sha2.obj \ + $(OBJ)\salt-arcfour.obj \ + $(OBJ)\salt-des.obj \ + $(OBJ)\salt-des3.obj \ + $(OBJ)\sp800-108-kdf.obj \ + $(OBJ)\store-int.obj \ + $(OBJ)\warn.obj + +$(LIBRFC3961): $(librfc3961_OBJS) + $(LIBCON) + +all:: $(LIBRFC3961) + +clean:: + -$(RM) $(LIBRFC3961) + +#---------------------------------------------------------------------- +# Tools + +all-tools:: $(BINDIR)\verify_krb5_conf.exe + +clean:: + -$(RM) $(BINDIR)\verify_krb5_conf.* + +$(BINDIR)\verify_krb5_conf.exe: $(OBJ)\verify_krb5_conf.obj $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS) $(OBJ)\verify_krb5_conf-version.res + $(EXECONLINK) + $(EXEPREP) + +{}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -DBUILD_KRB5_LIB -DASN1_LIB + +{$(OBJ)}.c{$(OBJ)}.obj:: + $(C2OBJ_P) -DBUILD_KRB5_LIB -DASN1_LIB + +#---------------------------------------------------------------------- +# Tests + +test:: test-binaries test-files test-run + +test_binaries = \ + $(OBJ)\aes-test.exe \ + $(OBJ)\derived-key-test.exe \ + $(OBJ)\krbhst-test.exe \ + $(OBJ)\n-fold-test.exe \ + $(OBJ)\parse-name-test.exe \ + $(OBJ)\pseudo-random-test.exe \ + $(OBJ)\store-test.exe \ + $(OBJ)\string-to-key-test.exe \ + $(OBJ)\test_acl.exe \ + $(OBJ)\test_addr.exe \ + $(OBJ)\test_alname.exe \ + $(OBJ)\test_cc.exe \ + $(OBJ)\test_config.exe \ + $(OBJ)\test_crypto.exe \ + $(OBJ)\test_crypto_wrapping.exe \ + $(OBJ)\test_forward.exe \ + $(OBJ)\test_get_addrs.exe \ + $(OBJ)\test_hostname.exe \ + $(OBJ)\test_keytab.exe \ + $(OBJ)\test_kuserok.exe \ + $(OBJ)\test_mem.exe \ + $(OBJ)\test_pac.exe \ + $(OBJ)\test_pkinit_dh2key.exe \ + $(OBJ)\test_pknistkdf.exe \ + $(OBJ)\test_plugin.exe \ + $(OBJ)\test_prf.exe \ + $(OBJ)\test_princ.exe \ + $(OBJ)\test_renew.exe \ + $(OBJ)\test_store.exe \ + $(OBJ)\test_time.exe \ + +test-binaries: $(test_binaries) $(OBJ)\test_rfc3961.exe + +test-files: $(OBJ)\test_config_strings.out + +$(OBJ)\test_config_strings.out: test_config_strings.cfg + $(CP) $** $@ + +test-run: + cd $(OBJ) + -aes-test.exe + -derived-key-test.exe + -krbhst-test.exe + -n-fold-test.exe + -parse-name-test.exe + -pseudo-random-test.exe + -store-test.exe + -string-to-key-test.exe + -test_acl.exe + -test_addr.exe +# Skip alname due to lack of .k5login and "root" +# -test_alname.exe + -test_cc.exe + -test_config.exe + -test_crypto.exe + -test_crypto_wrapping.exe +# Skip forward due to need for existing hostname +# -test_forward.exe + -test_get_addrs.exe + -test_hostname.exe + -test_keytab.exe +# Skip kuserok requires principal and localname +# -test_kuserok.exe + -test_mem.exe + -test_pac.exe + -test_pkinit_dh2key.exe + -test_pknistkdf.exe + -test_plugin.exe + -test_prf.exe + -test_renew.exe + -test_rfc3961.exe + -test_store.exe + -test_time.exe + cd $(SRCDIR) + +$(test_binaries): $$(@R).obj $(LIBHEIMDAL) $(LIBVERS) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\test_rfc3961.exe: $(OBJ)\test_rfc3961.obj $(LIBRFC3961) $(LIBHEIMDAL) $(LIBVERS) $(LIBCOMERR) $(LIBROKEN) $(LIBHEIMBASE) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(test_binaries:.exe=.obj): $$(@B).c + $(C2OBJ_C) -Fo$@ -Fd$(@D)\ $** -DBlah + +test-exports: + $(PERL) ..\..\cf\w32-check-exported-symbols.pl --vs version-script.map --def libkrb5-exports.def.in + +test:: test-exports diff --git a/third_party/heimdal/lib/krb5/acache.c b/third_party/heimdal/lib/krb5/acache.c new file mode 100644 index 0000000..72403d7 --- /dev/null +++ b/third_party/heimdal/lib/krb5/acache.c @@ -0,0 +1,1129 @@ +/* + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include + +#ifndef KCM_IS_API_CACHE + +static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; +static cc_initialize_func init_func; +static void (KRB5_CALLCONV *set_target_uid)(uid_t); +static void (KRB5_CALLCONV *clear_target)(void); + +#ifdef HAVE_DLOPEN +static void *cc_handle; +#endif + +typedef struct krb5_acc { + char *cache_name; + char *cache_subsidiary; + cc_context_t context; + cc_ccache_t ccache; +} krb5_acc; + +static krb5_error_code KRB5_CALLCONV acc_close(krb5_context, krb5_ccache); + +#define ACACHE(X) ((krb5_acc *)(X)->data.data) + +static const struct { + cc_int32 error; + krb5_error_code ret; +} cc_errors[] = { + { ccErrBadName, KRB5_CC_BADNAME }, + { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND }, + { ccErrCCacheNotFound, KRB5_FCC_NOFILE }, + { ccErrContextNotFound, KRB5_CC_NOTFOUND }, + { ccIteratorEnd, KRB5_CC_END }, + { ccErrNoMem, KRB5_CC_NOMEM }, + { ccErrServerUnavailable, KRB5_CC_NOSUPP }, + { ccErrInvalidCCache, KRB5_CC_BADNAME }, + { ccNoError, 0 } +}; + +static krb5_error_code +translate_cc_error(krb5_context context, cc_int32 error) +{ + size_t i; + krb5_clear_error_message(context); + for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++) + if (cc_errors[i].error == error) + return cc_errors[i].ret; + return KRB5_FCC_INTERNAL; +} + +static krb5_error_code +init_ccapi(krb5_context context) +{ + const char *lib = NULL; +#ifdef HAVE_DLOPEN + char *explib = NULL; +#endif + + HEIMDAL_MUTEX_lock(&acc_mutex); + if (init_func) { + HEIMDAL_MUTEX_unlock(&acc_mutex); + if (context) + krb5_clear_error_message(context); + return 0; + } + + if (context) + lib = krb5_config_get_string(context, NULL, + "libdefaults", "ccapi_library", + NULL); + if (lib == NULL) { +#ifdef __APPLE__ + lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos"; +#elif defined(_WIN32) + lib = "%{LIBDIR}/libkrb5_cc.dll"; +#else + lib = "%{LIBDIR}/libkrb5_cc.so"; +#endif + } + +#ifdef HAVE_DLOPEN + + if (_krb5_expand_path_tokens(context, lib, 0, &explib) == 0) { + cc_handle = dlopen(explib, RTLD_LAZY|RTLD_LOCAL|RTLD_GROUP); + free(explib); + } + + if (cc_handle == NULL) { + HEIMDAL_MUTEX_unlock(&acc_mutex); + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("Failed to load API cache module %s", "file"), + lib); + return KRB5_CC_NOSUPP; + } + + init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize"); + set_target_uid = (void (KRB5_CALLCONV *)(uid_t)) + dlsym(cc_handle, "krb5_ipc_client_set_target_uid"); + clear_target = (void (KRB5_CALLCONV *)(void)) + dlsym(cc_handle, "krb5_ipc_client_clear_target"); + HEIMDAL_MUTEX_unlock(&acc_mutex); + if (init_func == NULL) { + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("Failed to find cc_initialize" + "in %s: %s", "file, error"), lib, dlerror()); + dlclose(cc_handle); + return KRB5_CC_NOSUPP; + } + + return 0; +#else + HEIMDAL_MUTEX_unlock(&acc_mutex); + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("no support for shared object", "")); + return KRB5_CC_NOSUPP; +#endif +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_heim_krb5_ipc_client_set_target_uid(uid_t uid) +{ + init_ccapi(NULL); + if (set_target_uid != NULL) + (*set_target_uid)(uid); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_heim_krb5_ipc_client_clear_target(void) +{ + init_ccapi(NULL); + if (clear_target != NULL) + (*clear_target)(); +} + +static krb5_error_code +make_cred_from_ccred(krb5_context context, + const cc_credentials_v5_t *incred, + krb5_creds *cred) +{ + krb5_error_code ret; + unsigned int i; + + memset(cred, 0, sizeof(*cred)); + + ret = krb5_parse_name(context, incred->client, &cred->client); + if (ret) + goto fail; + + ret = krb5_parse_name(context, incred->server, &cred->server); + if (ret) + goto fail; + + cred->session.keytype = incred->keyblock.type; + cred->session.keyvalue.length = incred->keyblock.length; + cred->session.keyvalue.data = malloc(incred->keyblock.length); + if (cred->session.keyvalue.data == NULL) + goto nomem; + memcpy(cred->session.keyvalue.data, incred->keyblock.data, + incred->keyblock.length); + + cred->times.authtime = incred->authtime; + cred->times.starttime = incred->starttime; + cred->times.endtime = incred->endtime; + cred->times.renew_till = incred->renew_till; + + ret = krb5_data_copy(&cred->ticket, + incred->ticket.data, + incred->ticket.length); + if (ret) + goto nomem; + + ret = krb5_data_copy(&cred->second_ticket, + incred->second_ticket.data, + incred->second_ticket.length); + if (ret) + goto nomem; + + cred->authdata.val = NULL; + cred->authdata.len = 0; + + cred->addresses.val = NULL; + cred->addresses.len = 0; + + for (i = 0; incred->authdata && incred->authdata[i]; i++) + ; + + if (i) { + cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0])); + if (cred->authdata.val == NULL) + goto nomem; + cred->authdata.len = i; + for (i = 0; i < cred->authdata.len; i++) { + cred->authdata.val[i].ad_type = incred->authdata[i]->type; + ret = krb5_data_copy(&cred->authdata.val[i].ad_data, + incred->authdata[i]->data, + incred->authdata[i]->length); + if (ret) + goto nomem; + } + } + + for (i = 0; incred->addresses && incred->addresses[i]; i++) + ; + + if (i) { + cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0])); + if (cred->addresses.val == NULL) + goto nomem; + cred->addresses.len = i; + + for (i = 0; i < cred->addresses.len; i++) { + cred->addresses.val[i].addr_type = incred->addresses[i]->type; + ret = krb5_data_copy(&cred->addresses.val[i].address, + incred->addresses[i]->data, + incred->addresses[i]->length); + if (ret) + goto nomem; + } + } + + cred->flags.i = 0; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE) + cred->flags.b.forwardable = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED) + cred->flags.b.forwarded = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE) + cred->flags.b.proxiable = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY) + cred->flags.b.proxy = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE) + cred->flags.b.may_postdate = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED) + cred->flags.b.postdated = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID) + cred->flags.b.invalid = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE) + cred->flags.b.renewable = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL) + cred->flags.b.initial = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH) + cred->flags.b.pre_authent = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH) + cred->flags.b.hw_authent = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED) + cred->flags.b.transited_policy_checked = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE) + cred->flags.b.ok_as_delegate = 1; + if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS) + cred->flags.b.anonymous = 1; + + return 0; + +nomem: + ret = krb5_enomem(context); + +fail: + krb5_free_cred_contents(context, cred); + return ret; +} + +static void +free_ccred(cc_credentials_v5_t *cred) +{ + int i; + + if (cred->addresses) { + for (i = 0; cred->addresses[i] != 0; i++) { + if (cred->addresses[i]->data) + free(cred->addresses[i]->data); + free(cred->addresses[i]); + } + free(cred->addresses); + } + if (cred->server) + free(cred->server); + if (cred->client) + free(cred->client); + memset(cred, 0, sizeof(*cred)); +} + +static krb5_error_code +make_ccred_from_cred(krb5_context context, + const krb5_creds *incred, + cc_credentials_v5_t *cred) +{ + krb5_error_code ret; + size_t i; + + memset(cred, 0, sizeof(*cred)); + + ret = krb5_unparse_name(context, incred->client, &cred->client); + if (ret) + goto fail; + + ret = krb5_unparse_name(context, incred->server, &cred->server); + if (ret) + goto fail; + + cred->keyblock.type = incred->session.keytype; + cred->keyblock.length = incred->session.keyvalue.length; + cred->keyblock.data = incred->session.keyvalue.data; + + cred->authtime = incred->times.authtime; + cred->starttime = incred->times.starttime; + cred->endtime = incred->times.endtime; + cred->renew_till = incred->times.renew_till; + + cred->ticket.length = incred->ticket.length; + cred->ticket.data = incred->ticket.data; + + cred->second_ticket.length = incred->second_ticket.length; + cred->second_ticket.data = incred->second_ticket.data; + + /* XXX this one should also be filled in */ + cred->authdata = NULL; + + cred->addresses = calloc(incred->addresses.len + 1, + sizeof(cred->addresses[0])); + if (cred->addresses == NULL) { + + ret = ENOMEM; + goto fail; + } + + for (i = 0; i < incred->addresses.len; i++) { + cc_data *addr; + addr = malloc(sizeof(*addr)); + if (addr == NULL) { + ret = ENOMEM; + goto fail; + } + addr->type = incred->addresses.val[i].addr_type; + addr->length = incred->addresses.val[i].address.length; + addr->data = malloc(addr->length); + if (addr->data == NULL) { + free(addr); + ret = ENOMEM; + goto fail; + } + memcpy(addr->data, incred->addresses.val[i].address.data, + addr->length); + cred->addresses[i] = addr; + } + cred->addresses[i] = NULL; + + cred->ticket_flags = 0; + if (incred->flags.b.forwardable) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE; + if (incred->flags.b.forwarded) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED; + if (incred->flags.b.proxiable) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE; + if (incred->flags.b.proxy) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY; + if (incred->flags.b.may_postdate) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE; + if (incred->flags.b.postdated) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED; + if (incred->flags.b.invalid) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID; + if (incred->flags.b.renewable) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE; + if (incred->flags.b.initial) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL; + if (incred->flags.b.pre_authent) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH; + if (incred->flags.b.hw_authent) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH; + if (incred->flags.b.transited_policy_checked) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED; + if (incred->flags.b.ok_as_delegate) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE; + if (incred->flags.b.anonymous) + cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS; + + return 0; + +fail: + free_ccred(cred); + + krb5_clear_error_message(context); + return ret; +} + +static cc_int32 +get_cc_name(krb5_acc *a) +{ + cc_string_t name; + cc_int32 error; + + error = (*a->ccache->func->get_name)(a->ccache, &name); + if (error) + return error; + + a->cache_name = strdup(name->data); + (*name->func->release)(name); + if (a->cache_name == NULL) + return ccErrNoMem; + return ccNoError; +} + + +static krb5_error_code KRB5_CALLCONV +acc_get_name_2(krb5_context context, + krb5_ccache id, + const char **name, + const char **colname, + const char **subsidiary) +{ + krb5_error_code ret = 0; + krb5_acc *a = ACACHE(id); + int32_t error; + + if (name) + *name = NULL; + if (colname) + *colname = NULL; + if (subsidiary) + *subsidiary = NULL; + if (a->cache_subsidiary == NULL) { + krb5_principal principal = NULL; + + ret = _krb5_get_default_principal_local(context, &principal); + if (ret == 0) + ret = krb5_unparse_name(context, principal, &a->cache_subsidiary); + krb5_free_principal(context, principal); + if (ret) + return ret; + } + + if (a->cache_name == NULL) { + error = (*a->context->func->create_new_ccache)(a->context, + cc_credentials_v5, + a->cache_subsidiary, + &a->ccache); + if (error == ccNoError) + error = get_cc_name(a); + if (error != ccNoError) + ret = translate_cc_error(context, error); + } + if (name) + *name = a->cache_name; + if (colname) + *colname = ""; + if (subsidiary) + *subsidiary = a->cache_subsidiary; + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_alloc(krb5_context context, krb5_ccache *id) +{ + krb5_error_code ret; + cc_int32 error; + krb5_acc *a; + + ret = init_ccapi(context); + if (ret) + return ret; + + ret = krb5_data_alloc(&(*id)->data, sizeof(*a)); + if (ret) { + krb5_clear_error_message(context); + return ret; + } + + a = ACACHE(*id); + a->cache_subsidiary = NULL; + a->cache_name = NULL; + a->context = NULL; + a->ccache = NULL; + + error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL); + if (error) { + krb5_data_free(&(*id)->data); + return translate_cc_error(context, error); + } + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_resolve_2(krb5_context context, krb5_ccache *id, const char *res, const char *sub) +{ + krb5_error_code ret; + cc_time_t offset; + cc_int32 error; + krb5_acc *a; + char *s = NULL; + + ret = acc_alloc(context, id); + if (ret) + return ret; + + a = ACACHE(*id); + + if (sub) { + /* + * For API there's no such thing as a collection name, there's only the + * default collection. Though we could perhaps put a CCAPI shared + * object path in the collection name. + * + * So we'll treat (res && !sub) and (!res && sub) as the same cases. + * + * See also the KCM ccache type, where we have similar considerations. + */ + if (asprintf(&s, "%s%s%s", res && *res ? res : "", + res && *res ? ":" : "", sub) == -1 || s == NULL || + (a->cache_subsidiary = strdup(sub)) == NULL) { + acc_close(context, *id); + free(s); + return krb5_enomem(context); + } + res = s; + /* + * XXX With a bit of extra refactoring we could use the collection name + * as the path to the shared object implementing CCAPI... For now we + * ignore the collection name. + */ + } + + error = (*a->context->func->open_ccache)(a->context, res, &a->ccache); + if (error == ccErrCCacheNotFound) { + a->ccache = NULL; + a->cache_name = NULL; + free(s); + return 0; + } + if (error == ccNoError) + error = get_cc_name(a); + if (error != ccNoError) { + acc_close(context, *id); + *id = NULL; + free(s); + return translate_cc_error(context, error); + } + + error = (*a->ccache->func->get_kdc_time_offset)(a->ccache, + cc_credentials_v5, + &offset); + if (error == 0) + context->kdc_sec_offset = offset; + free(s); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_gen_new(krb5_context context, krb5_ccache *id) +{ + return acc_alloc(context, id); +} + +static krb5_error_code KRB5_CALLCONV +acc_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_acc *a = ACACHE(id); + krb5_error_code ret; + int32_t error; + char *name; + + ret = krb5_unparse_name(context, primary_principal, &name); + if (ret) + return ret; + + if (a->cache_name == NULL) { + error = (*a->context->func->create_new_ccache)(a->context, + cc_credentials_v5, + name, + &a->ccache); + free(name); + if (error == ccNoError) + error = get_cc_name(a); + } else { + cc_credentials_iterator_t iter; + cc_credentials_t ccred; + + error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); + if (error) { + free(name); + return translate_cc_error(context, error); + } + + while (1) { + error = (*iter->func->next)(iter, &ccred); + if (error) + break; + (*a->ccache->func->remove_credentials)(a->ccache, ccred); + (*ccred->func->release)(ccred); + } + (*iter->func->release)(iter); + + error = (*a->ccache->func->set_principal)(a->ccache, + cc_credentials_v5, + name); + } + + if (error == 0 && context->kdc_sec_offset) + error = (*a->ccache->func->set_kdc_time_offset)(a->ccache, + cc_credentials_v5, + context->kdc_sec_offset); + + return translate_cc_error(context, error); +} + +static krb5_error_code KRB5_CALLCONV +acc_close(krb5_context context, + krb5_ccache id) +{ + krb5_acc *a = ACACHE(id); + + if (a->ccache) { + (*a->ccache->func->release)(a->ccache); + a->ccache = NULL; + } + if (a->cache_name) { + free(a->cache_name); + a->cache_name = NULL; + } + if (a->context) { + (*a->context->func->release)(a->context); + a->context = NULL; + } + krb5_data_free(&id->data); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_destroy(krb5_context context, + krb5_ccache id) +{ + krb5_acc *a = ACACHE(id); + cc_int32 error = 0; + + if (a->ccache) { + error = (*a->ccache->func->destroy)(a->ccache); + a->ccache = NULL; + } + if (a->context) { + error = (a->context->func->release)(a->context); + a->context = NULL; + } + return translate_cc_error(context, error); +} + +static krb5_error_code KRB5_CALLCONV +acc_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + krb5_acc *a = ACACHE(id); + cc_credentials_union cred; + cc_credentials_v5_t v5cred; + krb5_error_code ret; + cc_int32 error; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + cred.version = cc_credentials_v5; + cred.credentials.credentials_v5 = &v5cred; + + ret = make_ccred_from_cred(context, + creds, + &v5cred); + if (ret) + return ret; + + error = (*a->ccache->func->store_credentials)(a->ccache, &cred); + if (error) + ret = translate_cc_error(context, error); + + free_ccred(&v5cred); + + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + krb5_acc *a = ACACHE(id); + krb5_error_code ret; + int32_t error; + cc_string_t name; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + error = (*a->ccache->func->get_principal)(a->ccache, + cc_credentials_v5, + &name); + if (error) + return translate_cc_error(context, error); + + ret = krb5_parse_name(context, name->data, principal); + + (*name->func->release)(name); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_get_first (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + cc_credentials_iterator_t iter; + krb5_acc *a = ACACHE(id); + int32_t error; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); + if (error) { + krb5_clear_error_message(context); + return ENOENT; + } + *cursor = iter; + return 0; +} + + +static krb5_error_code KRB5_CALLCONV +acc_get_next (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + cc_credentials_iterator_t iter = *cursor; + cc_credentials_t cred; + krb5_error_code ret; + int32_t error; + + while (1) { + error = (*iter->func->next)(iter, &cred); + if (error) + return translate_cc_error(context, error); + if (cred->data->version == cc_credentials_v5) + break; + (*cred->func->release)(cred); + } + + ret = make_cred_from_ccred(context, + cred->data->credentials.credentials_v5, + creds); + (*cred->func->release)(cred); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_end_get (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + cc_credentials_iterator_t iter = *cursor; + (*iter->func->release)(iter); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *cred) +{ + cc_credentials_iterator_t iter; + krb5_acc *a = ACACHE(id); + cc_credentials_t ccred; + krb5_error_code ret; + cc_int32 error; + char *client, *server; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + if (cred->client) { + ret = krb5_unparse_name(context, cred->client, &client); + if (ret) + return ret; + } else + client = NULL; + + ret = krb5_unparse_name(context, cred->server, &server); + if (ret) { + free(client); + return ret; + } + + error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); + if (error) { + free(server); + free(client); + return translate_cc_error(context, error); + } + + ret = KRB5_CC_NOTFOUND; + while (1) { + cc_credentials_v5_t *v5cred; + + error = (*iter->func->next)(iter, &ccred); + if (error) + break; + + if (ccred->data->version != cc_credentials_v5) + goto next; + + v5cred = ccred->data->credentials.credentials_v5; + + if (client && strcmp(v5cred->client, client) != 0) + goto next; + + if (strcmp(v5cred->server, server) != 0) + goto next; + + (*a->ccache->func->remove_credentials)(a->ccache, ccred); + ret = 0; + next: + (*ccred->func->release)(ccred); + } + + (*iter->func->release)(iter); + + if (ret) + krb5_set_error_message(context, ret, + N_("Can't find credential %s in cache", + "principal"), server); + free(server); + free(client); + + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + return 0; +} + +static int KRB5_CALLCONV +acc_get_version(krb5_context context, + krb5_ccache id) +{ + return 0; +} + +struct cache_iter { + cc_context_t context; + cc_ccache_iterator_t iter; +}; + +static krb5_error_code KRB5_CALLCONV +acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct cache_iter *iter; + krb5_error_code ret; + cc_int32 error; + + ret = init_ccapi(context); + if (ret) + return ret; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) + return krb5_enomem(context); + + error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL); + if (error) { + free(iter); + return translate_cc_error(context, error); + } + + error = (*iter->context->func->new_ccache_iterator)(iter->context, + &iter->iter); + if (error) { + free(iter); + krb5_clear_error_message(context); + return ENOENT; + } + *cursor = iter; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct cache_iter *iter = cursor; + cc_ccache_t cache; + krb5_acc *a; + krb5_error_code ret; + int32_t error; + + error = (*iter->iter->func->next)(iter->iter, &cache); + if (error) + return translate_cc_error(context, error); + + ret = _krb5_cc_allocate(context, &krb5_acc_ops, id); + if (ret) { + (*cache->func->release)(cache); + return ret; + } + + ret = acc_alloc(context, id); + if (ret) { + (*cache->func->release)(cache); + free(*id); + return ret; + } + + a = ACACHE(*id); + a->ccache = cache; + + error = get_cc_name(a); + if (error) { + acc_close(context, *id); + *id = NULL; + return translate_cc_error(context, error); + } + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct cache_iter *iter = cursor; + + (*iter->iter->func->release)(iter->iter); + iter->iter = NULL; + (*iter->context->func->release)(iter->context); + iter->context = NULL; + free(iter); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code ret; + krb5_acc *afrom = ACACHE(from); + krb5_acc *ato = ACACHE(to); + int32_t error; + + if (ato->ccache == NULL) { + cc_string_t name; + + error = (*afrom->ccache->func->get_principal)(afrom->ccache, + cc_credentials_v5, + &name); + if (error) + return translate_cc_error(context, error); + + error = (*ato->context->func->create_new_ccache)(ato->context, + cc_credentials_v5, + name->data, + &ato->ccache); + (*name->func->release)(name); + if (error) + return translate_cc_error(context, error); + } + + error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); + ret = translate_cc_error(context, error); + if (ret == 0) + krb5_cc_destroy(context, from); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +acc_get_default_name(krb5_context context, char **str) +{ + krb5_error_code ret; + cc_context_t cc; + cc_string_t name; + int32_t error; + + ret = init_ccapi(context); + if (ret) + return ret; + + error = (*init_func)(&cc, ccapi_version_3, NULL, NULL); + if (error) + return translate_cc_error(context, error); + + error = (*cc->func->get_default_ccache_name)(cc, &name); + if (error) { + (*cc->func->release)(cc); + return translate_cc_error(context, error); + } + + error = asprintf(str, "API:%s", name->data); + (*name->func->release)(name); + (*cc->func->release)(cc); + + if (error < 0 || *str == NULL) + return krb5_enomem(context); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_set_default(krb5_context context, krb5_ccache id) +{ + krb5_acc *a = ACACHE(id); + cc_int32 error; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + error = (*a->ccache->func->set_default)(a->ccache); + if (error) + return translate_cc_error(context, error); + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + krb5_acc *a = ACACHE(id); + cc_int32 error; + cc_time_t t; + + if (a->ccache == NULL) { + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("No API credential found", "")); + return KRB5_CC_NOTFOUND; + } + + error = (*a->ccache->func->get_change_time)(a->ccache, &t); + if (error) + return translate_cc_error(context, error); + + *mtime = t; + + return 0; +} + +/** + * Variable containing the API based credential cache implemention. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = { + KRB5_CC_OPS_VERSION_5, + "API", + NULL, + NULL, + acc_gen_new, + acc_initialize, + acc_destroy, + acc_close, + acc_store_cred, + NULL, /* acc_retrieve */ + acc_get_principal, + acc_get_first, + acc_get_next, + acc_end_get, + acc_remove_cred, + acc_set_flags, + acc_get_version, + acc_get_cache_first, + acc_get_cache_next, + acc_end_cache_get, + acc_move, + acc_get_default_name, + acc_set_default, + acc_lastchange, + NULL, + NULL, + acc_get_name_2, + acc_resolve_2 +}; + +#endif diff --git a/third_party/heimdal/lib/krb5/acl.c b/third_party/heimdal/lib/krb5/acl.c new file mode 100644 index 0000000..d319614 --- /dev/null +++ b/third_party/heimdal/lib/krb5/acl.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2000 - 2002, 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include + +struct acl_field { + enum { acl_string, acl_fnmatch, acl_retval } type; + union { + const char *cstr; + char **retv; + } u; + struct acl_field *next, **last; +}; + +static void +free_retv(struct acl_field *acl) +{ + while(acl != NULL) { + if (acl->type == acl_retval) { + if (*acl->u.retv) + free(*acl->u.retv); + *acl->u.retv = NULL; + } + acl = acl->next; + } +} + +static void +acl_free_list(struct acl_field *acl, int retv) +{ + struct acl_field *next; + if (retv) + free_retv(acl); + while(acl != NULL) { + next = acl->next; + free(acl); + acl = next; + } +} + +static krb5_error_code +acl_parse_format(krb5_context context, + struct acl_field **acl_ret, + const char *format, + va_list ap) +{ + const char *p; + struct acl_field *acl = NULL, *tmp; + + for(p = format; *p != '\0'; p++) { + tmp = malloc(sizeof(*tmp)); + if(tmp == NULL) { + acl_free_list(acl, 0); + return krb5_enomem(context); + } + if(*p == 's') { + tmp->type = acl_string; + tmp->u.cstr = va_arg(ap, const char*); + } else if(*p == 'f') { + tmp->type = acl_fnmatch; + tmp->u.cstr = va_arg(ap, const char*); + } else if(*p == 'r') { + tmp->type = acl_retval; + tmp->u.retv = va_arg(ap, char **); + *tmp->u.retv = NULL; + } else { + krb5_set_error_message(context, EINVAL, + N_("Unknown format specifier %c while " + "parsing ACL", "specifier"), *p); + acl_free_list(acl, 0); + free(tmp); + return EINVAL; + } + tmp->next = NULL; + if(acl == NULL) + acl = tmp; + else + *acl->last = tmp; + acl->last = &tmp->next; + } + *acl_ret = acl; + return 0; +} + +static krb5_boolean +acl_match_field(krb5_context context, + const char *string, + struct acl_field *field) +{ + if(field->type == acl_string) { + return strcmp(field->u.cstr, string) == 0; + } else if(field->type == acl_fnmatch) { + return !fnmatch(field->u.cstr, string, 0); + } else if(field->type == acl_retval) { + *field->u.retv = strdup(string); + return TRUE; + } + return FALSE; +} + +static krb5_boolean +acl_match_acl(krb5_context context, + struct acl_field *acl, + const char *string) +{ + char buf[256]; + while(strsep_copy(&string, " \t", buf, sizeof(buf)) != -1) { + if(buf[0] == '\0') + continue; /* skip ws */ + if (acl == NULL) + return FALSE; + if(!acl_match_field(context, buf, acl)) { + return FALSE; + } + acl = acl->next; + } + if (acl) + return FALSE; + return TRUE; +} + +/** + * krb5_acl_match_string matches ACL format against a string. + * + * The ACL format has three format specifiers: s, f, and r. Each + * specifier will retrieve one argument from the variable arguments + * for either matching or storing data. The input string is split up + * using " " (space) and "\t" (tab) as a delimiter; multiple and "\t" + * in a row are considered to be the same. + * + * List of format specifiers: + * - s Matches a string using strcmp(3) (case sensitive). + * - f Matches the string with fnmatch(3). Theflags + * argument (the last argument) passed to the fnmatch function is 0. + * - r Returns a copy of the string in the char ** passed in; the copy + * must be freed with free(3). There is no need to free(3) the + * string on error: the function will clean up and set the pointer + * to NULL. + * + * @param context Kerberos 5 context + * @param string string to match with + * @param format format to match + * @param ... parameter to format string + * + * @return Return an error code or 0. + * + * + * @code + * char *s; + * + * ret = krb5_acl_match_string(context, "foo", "s", "foo"); + * if (ret) + * krb5_errx(context, 1, "acl didn't match"); + * ret = krb5_acl_match_string(context, "foo foo baz/kaka", + * "ss", "foo", &s, "foo/\\*"); + * if (ret) { + * // no need to free(s) on error + * assert(s == NULL); + * krb5_errx(context, 1, "acl didn't match"); + * } + * free(s); + * @endcode + * + * @sa krb5_acl_match_file + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_acl_match_string(krb5_context context, + const char *string, + const char *format, + ...) +{ + krb5_error_code ret; + krb5_boolean found; + struct acl_field *acl; + + va_list ap; + va_start(ap, format); + ret = acl_parse_format(context, &acl, format, ap); + va_end(ap); + if(ret) + return ret; + + found = acl_match_acl(context, acl, string); + acl_free_list(acl, !found); + if (found) { + return 0; + } else { + krb5_set_error_message(context, EACCES, N_("ACL did not match", "")); + return EACCES; + } +} + +/** + * krb5_acl_match_file matches ACL format against each line in a file + * using krb5_acl_match_string(). Lines starting with # are treated + * like comments and ignored. + * + * @param context Kerberos 5 context. + * @param file file with acl listed in the file. + * @param format format to match. + * @param ... parameter to format string. + * + * @return Return an error code or 0. + * + * @sa krb5_acl_match_string + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_acl_match_file(krb5_context context, + const char *file, + const char *format, + ...) +{ + krb5_error_code ret; + struct acl_field *acl = NULL; + char buf[256]; + va_list ap; + FILE *f; + krb5_boolean found; + + f = fopen(file, "r"); + if(f == NULL) { + int save_errno = errno; + rk_strerror_r(save_errno, buf, sizeof(buf)); + krb5_set_error_message(context, save_errno, + N_("open(%s): %s", "file, errno"), + file, buf); + return save_errno; + } + rk_cloexec_file(f); + + va_start(ap, format); + ret = acl_parse_format(context, &acl, format, ap); + va_end(ap); + if(ret) { + fclose(f); + return ret; + } + + found = FALSE; + while(fgets(buf, sizeof(buf), f)) { + if(buf[0] == '#') + continue; + if(acl_match_acl(context, acl, buf)) { + found = TRUE; + break; + } + free_retv(acl); + } + + fclose(f); + acl_free_list(acl, !found); + if (found) { + return 0; + } else { + krb5_set_error_message(context, EACCES, N_("ACL did not match", "")); + return EACCES; + } +} diff --git a/third_party/heimdal/lib/krb5/add_et_list.c b/third_party/heimdal/lib/krb5/add_et_list.c new file mode 100644 index 0000000..1a289ee --- /dev/null +++ b/third_party/heimdal/lib/krb5/add_et_list.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Add a specified list of error messages to the et list in context. + * Call func (probably a comerr-generated function) with a pointer to + * the current et_list. + * + * @param context A kerberos context. + * @param func The generated com_err et function. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_add_et_list(krb5_context context, void (*func)(struct et_list **)) +{ + return heim_add_et_list(context->hcontext, func); +} diff --git a/third_party/heimdal/lib/krb5/addr_families.c b/third_party/heimdal/lib/krb5/addr_families.c new file mode 100644 index 0000000..7d13211 --- /dev/null +++ b/third_party/heimdal/lib/krb5/addr_families.c @@ -0,0 +1,1574 @@ +/* + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +struct addr_operations { + int af; + krb5_address_type atype; + size_t max_sockaddr_size; + krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); + krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); + void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, + krb5_socklen_t *sa_size, int port); + void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); + krb5_error_code (*h_addr2addr)(const char *, krb5_address *); + krb5_boolean (*uninteresting)(const struct sockaddr *); + krb5_boolean (*is_loopback)(const struct sockaddr *); + void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int); + int (*print_addr)(const krb5_address *, char *, size_t); + int (*parse_addr)(krb5_context, const char*, krb5_address *); + int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); + int (*free_addr)(krb5_context, krb5_address*); + int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); + int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long, + krb5_address*, krb5_address*); +}; + +/* + * AF_INET - aka IPv4 implementation + */ + +static krb5_error_code +ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) +{ + const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; + unsigned char buf[4]; + + a->addr_type = KRB5_ADDRESS_INET; + memcpy (buf, &sin4->sin_addr, 4); + return krb5_data_copy(&a->address, buf, 4); +} + +static krb5_error_code +ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) +{ + const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; + + *port = sin4->sin_port; + return 0; +} + +static void +ipv4_addr2sockaddr (const krb5_address *a, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + memcpy (&tmp.sin_addr, a->address.data, 4); + tmp.sin_port = port; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); +} + +static void +ipv4_h_addr2sockaddr(const char *addr, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + tmp.sin_port = port; + tmp.sin_addr = *((const struct in_addr *)addr); + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); +} + +static krb5_error_code +ipv4_h_addr2addr (const char *addr, + krb5_address *a) +{ + unsigned char buf[4]; + + a->addr_type = KRB5_ADDRESS_INET; + memcpy(buf, addr, 4); + return krb5_data_copy(&a->address, buf, 4); +} + +/* + * Are there any addresses that should be considered `uninteresting'? + */ + +static krb5_boolean +ipv4_uninteresting (const struct sockaddr *sa) +{ + const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; + + if (sin4->sin_addr.s_addr == INADDR_ANY) + return TRUE; + + return FALSE; +} + +static krb5_boolean +ipv4_is_loopback (const struct sockaddr *sa) +{ + const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; + + if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET) + return TRUE; + + return FALSE; +} + +static void +ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) +{ + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + tmp.sin_port = port; + tmp.sin_addr.s_addr = INADDR_ANY; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); +} + +static int +ipv4_print_addr (const krb5_address *addr, char *str, size_t len) +{ + struct in_addr ia; + + memcpy (&ia, addr->address.data, 4); + + return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); +} + +static int +ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) +{ + const char *p; + struct in_addr a; + + p = strchr(address, ':'); + if(p) { + p++; + if(strncasecmp(address, "ip:", p - address) != 0 && + strncasecmp(address, "ip4:", p - address) != 0 && + strncasecmp(address, "ipv4:", p - address) != 0 && + strncasecmp(address, "inet:", p - address) != 0) + return -1; + } else + p = address; + if(inet_aton(p, &a) == 0) + return -1; + addr->addr_type = KRB5_ADDRESS_INET; + if(krb5_data_alloc(&addr->address, 4) != 0) + return -1; + _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); + return 0; +} + +static int +ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr, + unsigned long len, krb5_address *low, krb5_address *high) +{ + unsigned long ia; + uint32_t l, h, m = 0xffffffff; + + if (len > 32) { + krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, + N_("IPv4 prefix too large (%ld)", "len"), len); + return KRB5_PROG_ATYPE_NOSUPP; + } + m = m << (32 - len); + + _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); + + l = ia & m; + h = l | ~m; + + low->addr_type = KRB5_ADDRESS_INET; + if(krb5_data_alloc(&low->address, 4) != 0) + return -1; + _krb5_put_int(low->address.data, l, low->address.length); + + high->addr_type = KRB5_ADDRESS_INET; + if(krb5_data_alloc(&high->address, 4) != 0) { + krb5_free_address(context, low); + return -1; + } + _krb5_put_int(high->address.data, h, high->address.length); + + return 0; +} + + +/* + * AF_INET6 - aka IPv6 implementation + */ + +#ifdef HAVE_IPV6 + +static krb5_error_code +ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + unsigned char buf[4]; + + a->addr_type = KRB5_ADDRESS_INET; +#ifndef IN6_ADDR_V6_TO_V4 +#ifdef IN6_EXTRACT_V4ADDR +#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) +#else +#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) +#endif +#endif + memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); + return krb5_data_copy(&a->address, buf, 4); + } else { + a->addr_type = KRB5_ADDRESS_INET6; + return krb5_data_copy(&a->address, + &sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + } +} + +static krb5_error_code +ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + + *port = sin6->sin6_port; + return 0; +} + +static void +ipv6_addr2sockaddr (const krb5_address *a, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + struct sockaddr_in6 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); + tmp.sin6_port = port; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); +} + +static void +ipv6_h_addr2sockaddr(const char *addr, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + struct sockaddr_in6 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + tmp.sin6_port = port; + tmp.sin6_addr = *((const struct in6_addr *)addr); + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); +} + +static krb5_error_code +ipv6_h_addr2addr (const char *addr, + krb5_address *a) +{ + a->addr_type = KRB5_ADDRESS_INET6; + return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); +} + +/* + * + */ + +static krb5_boolean +ipv6_uninteresting (const struct sockaddr *sa) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; + + return IN6_IS_ADDR_LINKLOCAL(in6) + || IN6_IS_ADDR_V4COMPAT(in6); +} + +static krb5_boolean +ipv6_is_loopback (const struct sockaddr *sa) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; + + return (IN6_IS_ADDR_LOOPBACK(in6)); +} + +static void +ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) +{ + struct sockaddr_in6 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + tmp.sin6_port = port; + tmp.sin6_addr = in6addr_any; + *sa_size = sizeof(tmp); +} + +static int +ipv6_print_addr (const krb5_address *addr, char *str, size_t len) +{ + char buf[128], buf2[3]; + if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) + { + /* XXX this is pretty ugly, but better than abort() */ + size_t i; + unsigned char *p = addr->address.data; + buf[0] = '\0'; + for(i = 0; i < addr->address.length; i++) { + snprintf(buf2, sizeof(buf2), "%02x", p[i]); + if(i > 0 && (i & 1) == 0) + strlcat(buf, ":", sizeof(buf)); + strlcat(buf, buf2, sizeof(buf)); + } + } + return snprintf(str, len, "IPv6:%s", buf); +} + +static int +ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) +{ + int ret; + struct in6_addr in6; + const char *p; + + p = strchr(address, ':'); + if(p) { + p++; + if(strncasecmp(address, "ip6:", p - address) == 0 || + strncasecmp(address, "ipv6:", p - address) == 0 || + strncasecmp(address, "inet6:", p - address) == 0) + address = p; + } + + ret = inet_pton(AF_INET6, address, &in6.s6_addr); + if(ret == 1) { + addr->addr_type = KRB5_ADDRESS_INET6; + ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); + if (ret) + return -1; + memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); + return 0; + } + return -1; +} + +static int +ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr, + unsigned long len, krb5_address *low, krb5_address *high) +{ + struct in6_addr addr, laddr, haddr; + uint32_t m; + int i, sub_len; + + if (len > 128) { + krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, + N_("IPv6 prefix too large (%ld)", "length"), len); + return KRB5_PROG_ATYPE_NOSUPP; + } + + if (inaddr->address.length != sizeof(addr)) { + krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, + N_("IPv6 addr bad length", "")); + return KRB5_PROG_ATYPE_NOSUPP; + } + + memcpy(&addr, inaddr->address.data, inaddr->address.length); + + for (i = 0; i < 16; i++) { + sub_len = min(8, len); + + m = 0xff << (8 - sub_len); + + laddr.s6_addr[i] = addr.s6_addr[i] & m; + haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m; + + if (len > 8) + len -= 8; + else + len = 0; + } + + low->addr_type = KRB5_ADDRESS_INET6; + if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0) + return -1; + memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr)); + + high->addr_type = KRB5_ADDRESS_INET6; + if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) { + krb5_free_address(context, low); + return -1; + } + memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr)); + + return 0; +} + +#endif /* IPv6 */ + +#ifndef HEIMDAL_SMALLER + +/* + * table + */ + +#define KRB5_ADDRESS_ARANGE (-100) + +struct arange { + krb5_address low; + krb5_address high; +}; + +static int +arange_parse_addr (krb5_context context, + const char *address, krb5_address *addr) +{ + char buf[1024], *p; + krb5_address low0, high0; + struct arange *a; + krb5_error_code ret; + + if(strncasecmp(address, "RANGE:", 6) != 0) + return -1; + + address += 6; + + p = strrchr(address, '/'); + if (p) { + krb5_addresses addrmask; + char *q; + long num; + + if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) + return -1; + buf[p - address] = '\0'; + ret = krb5_parse_address(context, buf, &addrmask); + if (ret) + return ret; + if(addrmask.len != 1) { + krb5_free_addresses(context, &addrmask); + return -1; + } + + address += p - address + 1; + + num = strtol(address, &q, 10); + if (q == address || *q != '\0' || num < 0) { + krb5_free_addresses(context, &addrmask); + return -1; + } + + ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num, + &low0, &high0); + krb5_free_addresses(context, &addrmask); + if (ret) + return ret; + + } else { + krb5_addresses low, high; + + strsep_copy(&address, "-", buf, sizeof(buf)); + ret = krb5_parse_address(context, buf, &low); + if(ret) + return ret; + if(low.len != 1) { + krb5_free_addresses(context, &low); + return -1; + } + + strsep_copy(&address, "-", buf, sizeof(buf)); + ret = krb5_parse_address(context, buf, &high); + if(ret) { + krb5_free_addresses(context, &low); + return ret; + } + + if(high.len != 1 || high.val[0].addr_type != low.val[0].addr_type) { + krb5_free_addresses(context, &low); + krb5_free_addresses(context, &high); + return -1; + } + + ret = krb5_copy_address(context, &high.val[0], &high0); + if (ret == 0) { + ret = krb5_copy_address(context, &low.val[0], &low0); + if (ret) + krb5_free_address(context, &high0); + } + krb5_free_addresses(context, &low); + krb5_free_addresses(context, &high); + if (ret) + return ret; + } + + ret = krb5_data_alloc(&addr->address, sizeof(*a)); + if (ret) { + krb5_free_address(context, &low0); + krb5_free_address(context, &high0); + return ret; + } + + addr->addr_type = KRB5_ADDRESS_ARANGE; + a = addr->address.data; + + if(krb5_address_order(context, &low0, &high0) < 0) { + a->low = low0; + a->high = high0; + } else { + a->low = high0; + a->high = low0; + } + return 0; +} + +static int +arange_free (krb5_context context, krb5_address *addr) +{ + struct arange *a; + a = addr->address.data; + krb5_free_address(context, &a->low); + krb5_free_address(context, &a->high); + krb5_data_free(&addr->address); + return 0; +} + + +static int +arange_copy (krb5_context context, const krb5_address *inaddr, + krb5_address *outaddr) +{ + krb5_error_code ret; + struct arange *i, *o; + + outaddr->addr_type = KRB5_ADDRESS_ARANGE; + ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); + if(ret) + return ret; + i = inaddr->address.data; + o = outaddr->address.data; + ret = krb5_copy_address(context, &i->low, &o->low); + if(ret) { + krb5_data_free(&outaddr->address); + return ret; + } + ret = krb5_copy_address(context, &i->high, &o->high); + if(ret) { + krb5_free_address(context, &o->low); + krb5_data_free(&outaddr->address); + return ret; + } + return 0; +} + +static int +arange_print_addr (const krb5_address *addr, char *str, size_t len) +{ + struct arange *a; + krb5_error_code ret; + size_t l, size, ret_len; + + a = addr->address.data; + + l = strlcpy(str, "RANGE:", len); + ret_len = l; + if (l > len) + l = len; + size = l; + + ret = krb5_print_address (&a->low, str + size, len - size, &l); + if (ret) + return ret; + ret_len += l; + if (len - size > l) + size += l; + else + size = len; + + l = strlcat(str + size, "-", len - size); + ret_len += l; + if (len - size > l) + size += l; + else + size = len; + + ret = krb5_print_address (&a->high, str + size, len - size, &l); + if (ret) + return ret; + ret_len += l; + + return ret_len; +} + +static int +arange_order_addr(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + int tmp1, tmp2, sign; + struct arange *a; + const krb5_address *a2; + + if(addr1->addr_type == KRB5_ADDRESS_ARANGE) { + a = addr1->address.data; + a2 = addr2; + sign = 1; + } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) { + a = addr2->address.data; + a2 = addr1; + sign = -1; + } else { + abort(); + UNREACHABLE(return 0); + } + + if(a2->addr_type == KRB5_ADDRESS_ARANGE) { + struct arange *b = a2->address.data; + tmp1 = krb5_address_order(context, &a->low, &b->low); + if(tmp1 != 0) + return sign * tmp1; + return sign * krb5_address_order(context, &a->high, &b->high); + } else if(a2->addr_type == a->low.addr_type) { + tmp1 = krb5_address_order(context, &a->low, a2); + if(tmp1 > 0) + return sign; + tmp2 = krb5_address_order(context, &a->high, a2); + if(tmp2 < 0) + return -sign; + return 0; + } else { + return sign * (addr1->addr_type - addr2->addr_type); + } +} + +#endif /* HEIMDAL_SMALLER */ + +static int +addrport_print_addr (const krb5_address *addr, char *str, size_t len) +{ + krb5_error_code ret; + krb5_address addr1, addr2; + uint16_t port = 0; + size_t ret_len = 0, l, size = 0; + krb5_storage *sp; + + sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); + if (sp == NULL) + return ENOMEM; + + /* for totally obscure reasons, these are not in network byteorder */ + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ + krb5_ret_address(sp, &addr1); + + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ + krb5_ret_address(sp, &addr2); + krb5_storage_free(sp); + if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { + unsigned long value; + _krb5_get_int(addr2.address.data, &value, 2); + port = value; + } + l = strlcpy(str, "ADDRPORT:", len); + ret_len += l; + if (len > l) + size += l; + else + size = len; + + ret = krb5_print_address(&addr1, str + size, len - size, &l); + if (ret) + return ret; + ret_len += l; + if (len - size > l) + size += l; + else + size = len; + + ret = snprintf(str + size, len - size, ",PORT=%u", port); + if (ret < 0) + return EINVAL; + ret_len += ret; + return ret_len; +} + +static const struct addr_operations at[] = { + { + AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), + ipv4_sockaddr2addr, + ipv4_sockaddr2port, + ipv4_addr2sockaddr, + ipv4_h_addr2sockaddr, + ipv4_h_addr2addr, + ipv4_uninteresting, + ipv4_is_loopback, + ipv4_anyaddr, + ipv4_print_addr, + ipv4_parse_addr, + NULL, + NULL, + NULL, + ipv4_mask_boundary + }, +#ifdef HAVE_IPV6 + { + AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), + ipv6_sockaddr2addr, + ipv6_sockaddr2port, + ipv6_addr2sockaddr, + ipv6_h_addr2sockaddr, + ipv6_h_addr2addr, + ipv6_uninteresting, + ipv6_is_loopback, + ipv6_anyaddr, + ipv6_print_addr, + ipv6_parse_addr, + NULL, + NULL, + NULL, + ipv6_mask_boundary + } , +#endif +#ifndef HEIMDAL_SMALLER + /* fake address type */ + { + KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + arange_print_addr, + arange_parse_addr, + arange_order_addr, + arange_free, + arange_copy, + NULL + }, +#endif + { + KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + addrport_print_addr, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +static const size_t num_addrs = sizeof(at) / sizeof(at[0]); + +static size_t max_sockaddr_size = 0; + +/* + * generic functions + */ + +static const struct addr_operations * +find_af(int af) +{ + size_t i; + + for (i = 0; i < num_addrs; i++) { + if (af == at[i].af) + return &at[i]; + } + return NULL; +} + +static const struct addr_operations * +find_atype(krb5_address_type atype) +{ + size_t i; + + for (i = 0; i < num_addrs; i++) { + if (atype == at[i].atype) + return &at[i]; + } + return NULL; +} + +/** + * krb5_sockaddr2address stores a address a "struct sockaddr" sa in + * the krb5_address addr. + * + * @param context a Keberos context + * @param sa a struct sockaddr to extract the address from + * @param addr an Kerberos 5 address to store the address in. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sockaddr2address (krb5_context context, + const struct sockaddr *sa, krb5_address *addr) +{ + const struct addr_operations *a = find_af(sa->sa_family); + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), + sa->sa_family); + return KRB5_PROG_ATYPE_NOSUPP; + } + return (*a->sockaddr2addr)(sa, addr); +} + +/** + * krb5_sockaddr2port extracts a port (if possible) from a "struct + * sockaddr. + * + * @param context a Keberos context + * @param sa a struct sockaddr to extract the port from + * @param port a pointer to an int16_t store the port in. + * + * @return Return an error code or 0. Will return + * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sockaddr2port (krb5_context context, + const struct sockaddr *sa, int16_t *port) +{ + const struct addr_operations *a = find_af(sa->sa_family); + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), + sa->sa_family); + return KRB5_PROG_ATYPE_NOSUPP; + } + return (*a->sockaddr2port)(sa, port); +} + +/** + * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr + * and port. The argument sa_size should initially contain the size of + * the sa and after the call, it will contain the actual length of the + * address. In case of the sa is too small to fit the whole address, + * the up to *sa_size will be stored, and then *sa_size will be set to + * the required length. + * + * @param context a Keberos context + * @param addr the address to copy the from + * @param sa the struct sockaddr that will be filled in + * @param sa_size pointer to length of sa, and after the call, it will + * contain the actual length of the address. + * @param port set port in sa. + * + * @return Return an error code or 0. Will return + * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_addr2sockaddr (krb5_context context, + const krb5_address *addr, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + const struct addr_operations *a = find_atype(addr->addr_type); + + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address type %d not supported", + "krb5_address type"), + addr->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + if (a->addr2sockaddr == NULL) { + krb5_set_error_message (context, + KRB5_PROG_ATYPE_NOSUPP, + N_("Can't convert address type %d to sockaddr", ""), + addr->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + (*a->addr2sockaddr)(addr, sa, sa_size, port); + return 0; +} + +/** + * krb5_max_sockaddr_size returns the max size of the .Li struct + * sockaddr that the Kerberos library will return. + * + * @return Return an size_t of the maximum struct sockaddr. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL +krb5_max_sockaddr_size (void) +{ + if (max_sockaddr_size == 0) { + size_t i; + + for (i = 0; i < num_addrs; i++) + max_sockaddr_size = max(max_sockaddr_size, at[i].max_sockaddr_size); + } + return max_sockaddr_size; +} + +/** + * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the + * kerberos library thinks are uninteresting. One example are link + * local addresses. + * + * @param sa pointer to struct sockaddr that might be interesting. + * + * @return Return a non zero for uninteresting addresses. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_sockaddr_uninteresting(const struct sockaddr *sa) +{ + const struct addr_operations *a = find_af(sa->sa_family); + if (a == NULL || a->uninteresting == NULL) + return TRUE; + return (*a->uninteresting)(sa); +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_sockaddr_is_loopback(const struct sockaddr *sa) +{ + const struct addr_operations *a = find_af(sa->sa_family); + if (a == NULL || a->is_loopback == NULL) + return TRUE; + return (*a->is_loopback)(sa); +} + +/** + * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and + * the "struct hostent" (see gethostbyname(3) ) h_addr_list + * component. The argument sa_size should initially contain the size + * of the sa, and after the call, it will contain the actual length of + * the address. + * + * @param context a Keberos context + * @param af addresses + * @param addr address + * @param sa returned struct sockaddr + * @param sa_size size of sa + * @param port port to set in sa. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_h_addr2sockaddr (krb5_context context, + int af, + const char *addr, struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + const struct addr_operations *a = find_af(af); + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + "Address family %d not supported", af); + return KRB5_PROG_ATYPE_NOSUPP; + } + (*a->h_addr2sockaddr)(addr, sa, sa_size, port); + return 0; +} + +/** + * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception + * that it operates on a krb5_address instead of a struct sockaddr. + * + * @param context a Keberos context + * @param af address family + * @param haddr host address from struct hostent. + * @param addr returned krb5_address. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_h_addr2addr (krb5_context context, + int af, + const char *haddr, krb5_address *addr) +{ + const struct addr_operations *a = find_af(af); + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), af); + return KRB5_PROG_ATYPE_NOSUPP; + } + return (*a->h_addr2addr)(haddr, addr); +} + +/** + * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to + * bind(2) to. The argument sa_size should initially contain the size + * of the sa, and after the call, it will contain the actual length + * of the address. + * + * @param context a Keberos context + * @param af address family + * @param sa sockaddr + * @param sa_size lenght of sa. + * @param port for to fill into sa. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_anyaddr (krb5_context context, + int af, + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) +{ + const struct addr_operations *a = find_af (af); + + if (a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), af); + return KRB5_PROG_ATYPE_NOSUPP; + } + + (*a->anyaddr)(sa, sa_size, port); + return 0; +} + +/** + * krb5_print_address prints the address in addr to the string string + * that have the length len. If ret_len is not NULL, it will be filled + * with the length of the string if size were unlimited (not including + * the final NUL) . + * + * @param addr address to be printed + * @param str pointer string to print the address into + * @param len length that will fit into area pointed to by "str". + * @param ret_len return length the str. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_print_address (const krb5_address *addr, + char *str, size_t len, size_t *ret_len) +{ + const struct addr_operations *a = find_atype(addr->addr_type); + int ret; + + if (a == NULL || a->print_addr == NULL) { + char *s; + int l; + size_t i; + + s = str; + l = snprintf(s, len, "TYPE_%d:", addr->addr_type); + if (l < 0 || (size_t)l >= len) + return EINVAL; + s += l; + len -= l; + for(i = 0; i < addr->address.length; i++) { + l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); + if (l < 0 || (size_t)l >= len) + return EINVAL; + len -= l; + s += l; + } + if(ret_len != NULL) + *ret_len = s - str; + return 0; + } + ret = (*a->print_addr)(addr, str, len); + if (ret < 0) + return EINVAL; + if(ret_len != NULL) + *ret_len = ret; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_parse_address_no_lookup(krb5_context context, + const char *string, + krb5_addresses *addresses) +{ + int i; + + addresses->len = 0; + addresses->val = NULL; + + for(i = 0; i < num_addrs; i++) { + if(at[i].parse_addr) { + krb5_address addr; + if((*at[i].parse_addr)(context, string, &addr) == 0) { + ALLOC_SEQ(addresses, 1); + if (addresses->val == NULL) + return krb5_enomem(context); + addresses->val[0] = addr; + return 0; + } + } + } + + return -1; +} + +/** + * krb5_parse_address returns the resolved hostname in string to the + * krb5_addresses addresses . + * + * @param context a Keberos context + * @param string + * @param addresses + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_parse_address(krb5_context context, + const char *string, + krb5_addresses *addresses) +{ + krb5_error_code ret; + int i, n; + struct addrinfo *ai, *a; + struct addrinfo hint; + int error; + int save_errno; + + addresses->len = 0; + addresses->val = NULL; + + ret = _krb5_parse_address_no_lookup(context, string, addresses); + if (ret == 0 || ret != -1) + return ret; + + /* if not parsed as numeric address, do a name lookup */ + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_UNSPEC; + error = getaddrinfo (string, NULL, &hint, &ai); + if (error) { + krb5_error_code ret2; + save_errno = errno; + ret2 = krb5_eai_to_heim_errno(save_errno, error); + krb5_set_error_message (context, ret2, "%s: %s", + string, gai_strerror(error)); + return ret2; + } + + n = 0; + for (a = ai; a != NULL; a = a->ai_next) + ++n; + + ALLOC_SEQ(addresses, n); + if (addresses->val == NULL) { + freeaddrinfo(ai); + return krb5_enomem(context); + } + + addresses->len = 0; + for (a = ai, i = 0; a != NULL; a = a->ai_next) { + if (krb5_sockaddr2address (context, a->ai_addr, &addresses->val[i])) + continue; + if(krb5_address_search(context, &addresses->val[i], addresses)) { + krb5_free_address(context, &addresses->val[i]); + continue; + } + i++; + addresses->len = i; + } + freeaddrinfo (ai); + return 0; +} + +/** + * krb5_address_order compares the addresses addr1 and addr2 so that + * it can be used for sorting addresses. If the addresses are the same + * address krb5_address_order will return 0. Behavies like memcmp(2). + * + * @param context a Keberos context + * @param addr1 krb5_address to compare + * @param addr2 krb5_address to compare + * + * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and + * addr2 is the same address, > 0 if addr2 is "less" then addr1. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_address_order(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + /* this sucks; what if both addresses have order functions, which + should we call? this works for now, though */ + const struct addr_operations *a; + a = find_atype(addr1->addr_type); + if(a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), + addr1->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + if(a->order_addr != NULL) + return (*a->order_addr)(context, addr1, addr2); + a = find_atype(addr2->addr_type); + if(a == NULL) { + krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d not supported", ""), + addr2->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + if(a->order_addr != NULL) + return (*a->order_addr)(context, addr1, addr2); + + if(addr1->addr_type != addr2->addr_type) + return addr1->addr_type - addr2->addr_type; + if(addr1->address.length != addr2->address.length) + return addr1->address.length - addr2->address.length; + return memcmp (addr1->address.data, + addr2->address.data, + addr1->address.length); +} + +/** + * krb5_address_compare compares the addresses addr1 and addr2. + * Returns TRUE if the two addresses are the same. + * + * @param context a Keberos context + * @param addr1 address to compare + * @param addr2 address to compare + * + * @return Return an TRUE is the address are the same FALSE if not + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_address_compare(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + return krb5_address_order (context, addr1, addr2) == 0; +} + +/** + * krb5_address_search checks if the address addr is a member of the + * address set list addrlist . + * + * @param context a Keberos context. + * @param addr address to search for. + * @param addrlist list of addresses to look in for addr. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_address_search(krb5_context context, + const krb5_address *addr, + const krb5_addresses *addrlist) +{ + size_t i; + + for (i = 0; i < addrlist->len; ++i) + if (krb5_address_compare (context, addr, &addrlist->val[i])) + return TRUE; + return FALSE; +} + +/** + * krb5_free_address frees the data stored in the address that is + * alloced with any of the krb5_address functions. + * + * @param context a Keberos context + * @param address addresss to be freed. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_address(krb5_context context, + krb5_address *address) +{ + const struct addr_operations *a = find_atype (address->addr_type); + if(a != NULL && a->free_addr != NULL) + return (*a->free_addr)(context, address); + krb5_data_free (&address->address); + memset(address, 0, sizeof(*address)); + return 0; +} + +/** + * krb5_free_addresses frees the data stored in the address that is + * alloced with any of the krb5_address functions. + * + * @param context a Keberos context + * @param addresses addressses to be freed. + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_addresses(krb5_context context, + krb5_addresses *addresses) +{ + free_HostAddresses(addresses); + return 0; +} + +/** + * krb5_copy_address copies the content of address + * inaddr to outaddr. + * + * @param context a Keberos context + * @param inaddr pointer to source address + * @param outaddr pointer to destination address + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_address(krb5_context context, + const krb5_address *inaddr, + krb5_address *outaddr) +{ + const struct addr_operations *a = find_af (inaddr->addr_type); + if(a != NULL && a->copy_addr != NULL) + return (*a->copy_addr)(context, inaddr, outaddr); + return copy_HostAddress(inaddr, outaddr); +} + +/** + * krb5_copy_addresses copies the content of addresses + * inaddr to outaddr. + * + * @param context a Keberos context + * @param inaddr pointer to source addresses + * @param outaddr pointer to destination addresses + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_addresses(krb5_context context, + const krb5_addresses *inaddr, + krb5_addresses *outaddr) +{ + size_t i; + ALLOC_SEQ(outaddr, inaddr->len); + if(inaddr->len > 0 && outaddr->val == NULL) + return krb5_enomem(context); + for(i = 0; i < inaddr->len; i++) + krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); + return 0; +} + +/** + * krb5_append_addresses adds the set of addresses in source to + * dest. While copying the addresses, duplicates are also sorted out. + * + * @param context a Keberos context + * @param dest destination of copy operation + * @param source adresses that are going to be added to dest + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_append_addresses(krb5_context context, + krb5_addresses *dest, + const krb5_addresses *source) +{ + krb5_address *tmp; + krb5_error_code ret; + size_t i; + if(source->len > 0) { + tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); + if (tmp == NULL) + return krb5_enomem(context); + dest->val = tmp; + for(i = 0; i < source->len; i++) { + /* skip duplicates */ + if(krb5_address_search(context, &source->val[i], dest)) + continue; + ret = krb5_copy_address(context, + &source->val[i], + &dest->val[dest->len]); + if(ret) + return ret; + dest->len++; + } + } + return 0; +} + +/** + * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) + * + * @param context a Keberos context + * @param res built address from addr/port + * @param addr address to use + * @param port port to use + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_make_addrport (krb5_context context, + krb5_address **res, const krb5_address *addr, int16_t port) +{ + krb5_error_code ret; + size_t len = addr->address.length + 2 + 4 * 4; + u_char *p; + + /* XXX Make this assume port == 0 -> port is absent */ + + *res = malloc (sizeof(**res)); + if (*res == NULL) + return krb5_enomem(context); + (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; + ret = krb5_data_alloc (&(*res)->address, len); + if (ret) { + free (*res); + *res = NULL; + return krb5_enomem(context); + } + p = (*res)->address.data; + *p++ = 0; + *p++ = 0; + *p++ = (addr->addr_type ) & 0xFF; + *p++ = (addr->addr_type >> 8) & 0xFF; + + *p++ = (addr->address.length ) & 0xFF; + *p++ = (addr->address.length >> 8) & 0xFF; + *p++ = (addr->address.length >> 16) & 0xFF; + *p++ = (addr->address.length >> 24) & 0xFF; + + memcpy (p, addr->address.data, addr->address.length); + p += addr->address.length; + + *p++ = 0; + *p++ = 0; + *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; + *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; + + *p++ = (2 ) & 0xFF; + *p++ = (2 >> 8) & 0xFF; + *p++ = (2 >> 16) & 0xFF; + *p++ = (2 >> 24) & 0xFF; + + memcpy (p, &port, 2); + + return 0; +} + +/** + * Calculate the boundary addresses of `inaddr'/`prefixlen' and store + * them in `low' and `high'. + * + * @param context a Keberos context + * @param inaddr address in prefixlen that the bondery searched + * @param prefixlen width of boundery + * @param low lowest address + * @param high highest address + * + * @return Return an error code or 0. + * + * @ingroup krb5_address + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_address_prefixlen_boundary(krb5_context context, + const krb5_address *inaddr, + unsigned long prefixlen, + krb5_address *low, + krb5_address *high) +{ + const struct addr_operations *a = find_atype (inaddr->addr_type); + if(a != NULL && a->mask_boundary != NULL) + return (*a->mask_boundary)(context, inaddr, prefixlen, low, high); + krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP, + N_("Address family %d doesn't support " + "address mask operation", ""), + inaddr->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; +} diff --git a/third_party/heimdal/lib/krb5/aes-test.c b/third_party/heimdal/lib/krb5/aes-test.c new file mode 100644 index 0000000..2d048e4 --- /dev/null +++ b/third_party/heimdal/lib/krb5/aes-test.c @@ -0,0 +1,1058 @@ +/* + * Copyright (c) 2003-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "krb5_locl.h" +#include +#include +#include + +static int verbose = 0; + +static void +hex_dump_data(const void *data, size_t length) +{ + char *p; + + hex_encode(data, length, &p); + printf("%s\n", p); + free(p); +} + +struct { + char *password; + char *salt; + int saltlen; + int iterations; + krb5_enctype enctype; + size_t keylen; + char *pbkdf2; + char *key; +} keys[] = { + { + "password", + "\x10\xDF\x9D\xD7\x83\xE5\xBC\x8A\xCE\xA1\x73\x0E\x74\x35\x5F\x61" + "ATHENA.MIT.EDUraeburn", + 37, + 32768, + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 16, + NULL, + "\x08\x9B\xCA\x48\xB1\x05\xEA\x6E\xA7\x7C\xA5\xD2\xF3\x9D\xC5\xE7" + }, + { + "password", + "\x10\xDF\x9D\xD7\x83\xE5\xBC\x8A\xCE\xA1\x73\x0E\x74\x35\x5F\x61" + "ATHENA.MIT.EDUraeburn", + 37, + 32768, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 32, + NULL, + "\x45\xBD\x80\x6D\xBF\x6A\x83\x3A\x9C\xFF\xC1\xC9\x45\x89\xA2\x22" + "\x36\x7A\x79\xBC\x21\xC4\x13\x71\x89\x06\xE9\xF5\x78\xA7\x84\x67" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 1, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15", + "\x42\x26\x3c\x6e\x89\xf4\xfc\x28\xb8\xdf\x68\xee\x09\x79\x9f\x15" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 1, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15" + "\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3\x33\xec\xc0\xe2\xe1\xf7\x08\x37", + "\xfe\x69\x7b\x52\xbc\x0d\x3c\xe1\x44\x32\xba\x03\x6a\x92\xe6\x5b" + "\xbb\x52\x28\x09\x90\xa2\xfa\x27\x88\x39\x98\xd7\x2a\xf3\x01\x61" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 2, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d", + "\xc6\x51\xbf\x29\xe2\x30\x0a\xc2\x7f\xa4\x69\xd6\x93\xbd\xda\x13" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 2, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d" + "\xa0\x53\x78\xb9\x32\x44\xec\x8f\x48\xa9\x9e\x61\xad\x79\x9d\x86", + "\xa2\xe1\x6d\x16\xb3\x60\x69\xc1\x35\xd5\xe9\xd2\xe2\x5f\x89\x61" + "\x02\x68\x56\x18\xb9\x59\x14\xb4\x67\xc6\x76\x22\x22\x58\x24\xff" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 1200, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b", + "\x4c\x01\xcd\x46\xd6\x32\xd0\x1e\x6d\xbe\x23\x0a\x01\xed\x64\x2a" + }, + { + "password", "ATHENA.MIT.EDUraeburn", -1, + 1200, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b" + "\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", + "\x55\xa6\xac\x74\x0a\xd1\x7b\x48\x46\x94\x10\x51\xe1\xe8\xb0\xa7" + "\x54\x8d\x93\xb0\xab\x30\xa8\xbc\x3f\xf1\x62\x80\x38\x2b\x8c\x2a" + }, + { + "password", "\x12\x34\x56\x78\x78\x56\x34\x12", 8, + 5, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49", + "\xe9\xb2\x3d\x52\x27\x37\x47\xdd\x5c\x35\xcb\x55\xbe\x61\x9d\x8e" + }, + { + "password", "\x12\x34\x56\x78\x78\x56\x34\x12", 8, + 5, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49" + "\x3f\x98\xd2\x03\xe6\xbe\x49\xa6\xad\xf4\xfa\x57\x4b\x6e\x64\xee", + "\x97\xa4\xe7\x86\xbe\x20\xd8\x1a\x38\x2d\x5e\xbc\x96\xd5\x90\x9c" + "\xab\xcd\xad\xc8\x7c\xa4\x8f\x57\x45\x04\x15\x9f\x16\xc3\x6e\x31" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", -1, + 1200, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9", + "\x59\xd1\xbb\x78\x9a\x82\x8b\x1a\xa5\x4e\xf9\xc2\x88\x3f\x69\xed" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", -1, + 1200, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9" + "\xc5\xec\x59\xf1\xa4\x52\xf5\xcc\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", + "\x89\xad\xee\x36\x08\xdb\x8b\xc7\x1f\x1b\xfb\xfe\x45\x94\x86\xb0" + "\x56\x18\xb7\x0c\xba\xe2\x20\x92\x53\x4e\x56\xc5\x53\xba\x4b\x34" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", -1, + 1200, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61", + "\xcb\x80\x05\xdc\x5f\x90\x17\x9a\x7f\x02\x10\x4c\x00\x18\x75\x1d" + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", -1, + 1200, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61" + "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a", + "\xd7\x8c\x5c\x9c\xb8\x72\xa8\xc9\xda\xd4\x69\x7f\x0b\xb5\xb2\xd2" + "\x14\x96\xc8\x2b\xeb\x2c\xae\xda\x21\x12\xfc\xee\xa0\x57\x40\x1b" + }, + { + "\xf0\x9d\x84\x9e" /* g-clef */, "EXAMPLE.COMpianist", -1, + 50, + ETYPE_AES128_CTS_HMAC_SHA1_96, 16, + "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39", + "\xf1\x49\xc1\xf2\xe1\x54\xa7\x34\x52\xd4\x3e\x7f\xe6\x2a\x56\xe5" + }, + { + "\xf0\x9d\x84\x9e" /* g-clef */, "EXAMPLE.COMpianist", -1, + 50, + ETYPE_AES256_CTS_HMAC_SHA1_96, 32, + "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39" + "\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2\x81\xff\x30\x69\xe1\xe9\x4f\x52", + "\x4b\x6d\x98\x39\xf8\x44\x06\xdf\x1f\x09\xcc\x16\x6d\xb4\xb8\x3c" + "\x57\x18\x48\xb7\x84\xa3\xd6\xbd\xc3\x46\x58\x9a\x3e\x39\x3f\x9e" + }, + { + "foo", "", -1, + 0, + ETYPE_ARCFOUR_HMAC_MD5, 16, + NULL, + "\xac\x8e\x65\x7f\x83\xdf\x82\xbe\xea\x5d\x43\xbd\xaf\x78\x00\xcc" + }, + { + "test", "", -1, + 0, + ETYPE_ARCFOUR_HMAC_MD5, 16, + NULL, + "\x0c\xb6\x94\x88\x05\xf7\x97\xbf\x2a\x82\x80\x79\x73\xb8\x95\x37" + } +}; + +static int +string_to_key_test(krb5_context context) +{ + krb5_data password, opaque; + krb5_error_code ret; + krb5_salt salt; + int i, val = 0; + char iter[4]; + + for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { + + password.data = keys[i].password; + password.length = strlen(password.data); + + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.data = keys[i].salt; + if (keys[i].saltlen == -1) + salt.saltvalue.length = strlen(salt.saltvalue.data); + else + salt.saltvalue.length = keys[i].saltlen; + + opaque.data = iter; + opaque.length = sizeof(iter); + _krb5_put_int(iter, keys[i].iterations, 4); + + if (keys[i].pbkdf2) { + unsigned char keyout[32]; + + if (keys[i].keylen > sizeof(keyout)) + abort(); + + PKCS5_PBKDF2_HMAC(password.data, password.length, + salt.saltvalue.data, salt.saltvalue.length, + keys[i].iterations, EVP_sha1(), + keys[i].keylen, keyout); + + if (memcmp(keyout, keys[i].pbkdf2, keys[i].keylen) != 0) { + krb5_warnx(context, "%d: pbkdf2", i); + val = 1; + hex_dump_data(keyout, keys[i].keylen); + continue; + } + + if (verbose) { + printf("PBKDF2:\n"); + hex_dump_data(keyout, keys[i].keylen); + } + } + + { + krb5_keyblock key; + + ret = krb5_string_to_key_data_salt_opaque (context, + keys[i].enctype, + password, + salt, + opaque, + &key); + if (ret) { + krb5_warn(context, ret, "%d: string_to_key_data_salt_opaque", + i); + val = 1; + continue; + } + + if (key.keyvalue.length != keys[i].keylen) { + krb5_warnx(context, "%d: key wrong length (%lu/%lu)", + i, (unsigned long)key.keyvalue.length, + (unsigned long)keys[i].keylen); + val = 1; + continue; + } + + if (memcmp(key.keyvalue.data, keys[i].key, keys[i].keylen) != 0) { + krb5_warnx(context, "%d: key wrong", i); + val = 1; + hex_dump_data(key.keyvalue.data, key.keyvalue.length); + hex_dump_data(keys[i].key, keys[i].keylen); + continue; + } + + if (verbose) { + printf("key:\n"); + hex_dump_data(key.keyvalue.data, key.keyvalue.length); + } + krb5_free_keyblock_contents(context, &key); + } + } + return val; +} + +static int +krb_enc(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_data *cipher, + krb5_data *clear) +{ + krb5_data decrypt; + krb5_error_code ret; + + krb5_data_zero(&decrypt); + + ret = krb5_decrypt(context, + crypto, + usage, + cipher->data, + cipher->length, + &decrypt); + + if (ret) { + krb5_warn(context, ret, "krb5_decrypt"); + return ret; + } + + if (decrypt.length != clear->length || + (decrypt.length && + memcmp(decrypt.data, clear->data, decrypt.length) != 0)) { + krb5_warnx(context, "clear text not same"); + return EINVAL; + } + + krb5_data_free(&decrypt); + + return 0; +} + +static int +krb_enc_iov2(krb5_context context, + krb5_crypto crypto, + unsigned usage, + size_t cipher_len, + krb5_data *clear) +{ + krb5_crypto_iov iov[4]; + krb5_data decrypt; + int ret; + char *p, *q; + size_t len, i; + + p = clear->data; + len = clear->length; + + iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); + iov[0].data.data = emalloc(iov[0].data.length); + + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data.length = len; + iov[1].data.data = emalloc(iov[1].data.length); + memcpy(iov[1].data.data, p, iov[1].data.length); + + /* padding buffer */ + iov[2].flags = KRB5_CRYPTO_TYPE_PADDING; + krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_PADDING, &iov[2].data.length); + iov[2].data.data = emalloc(iov[2].data.length); + + iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER; + krb5_crypto_length(context, crypto, iov[3].flags, &iov[3].data.length); + iov[3].data.data = emalloc(iov[3].data.length); + + ret = krb5_encrypt_iov_ivec(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + errx(1, "encrypt iov failed: %d", ret); + + /* check len */ + for (i = 0, len = 0; i < sizeof(iov)/sizeof(iov[0]); i++) + len += iov[i].data.length; + if (len != cipher_len) + errx(1, "cipher len wrong"); + + /* + * Plain decrypt + */ + + p = q = emalloc(len); + for (i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + memcpy(q, iov[i].data.data, iov[i].data.length); + q += iov[i].data.length; + } + + ret = krb5_decrypt(context, crypto, usage, p, len, &decrypt); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt"); + else + krb5_data_free(&decrypt); + + free(p); + + /* + * Now decrypt use iov + */ + + /* padding turn into data */ + p = q = emalloc(iov[1].data.length + iov[2].data.length); + + memcpy(q, iov[1].data.data, iov[1].data.length); + q += iov[1].data.length; + memcpy(q, iov[2].data.data, iov[2].data.length); + + free(iov[1].data.data); + free(iov[2].data.data); + + iov[1].data.data = p; + iov[1].data.length += iov[2].data.length; + + iov[2].flags = KRB5_CRYPTO_TYPE_EMPTY; + iov[2].data.length = 0; + + ret = krb5_decrypt_iov_ivec(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + free(iov[0].data.data); + free(iov[3].data.data); + + if (ret) + krb5_err(context, 1, ret, "decrypt iov failed: %d", ret); + + if (clear->length != iov[1].data.length) + errx(1, "length incorrect"); + + p = clear->data; + if (memcmp(iov[1].data.data, p, iov[1].data.length) != 0) + errx(1, "iov[1] incorrect"); + + free(iov[1].data.data); + + return 0; +} + + +static int +krb_enc_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_data *cipher, + krb5_data *clear) +{ + krb5_crypto_iov iov[3]; + int ret; + char *p; + size_t len; + + p = cipher->data; + len = cipher->length; + + iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); + iov[0].data.data = emalloc(iov[0].data.length); + memcpy(iov[0].data.data, p, iov[0].data.length); + p += iov[0].data.length; + len -= iov[0].data.length; + + iov[1].flags = KRB5_CRYPTO_TYPE_TRAILER; + krb5_crypto_length(context, crypto, iov[1].flags, &iov[1].data.length); + iov[1].data.data = emalloc(iov[1].data.length); + memcpy(iov[1].data.data, p + len - iov[1].data.length, iov[1].data.length); + len -= iov[1].data.length; + + iov[2].flags = KRB5_CRYPTO_TYPE_DATA; + iov[2].data.length = len; + iov[2].data.data = emalloc(len); + memcpy(iov[2].data.data, p, len); + + ret = krb5_decrypt_iov_ivec(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb_enc_iov decrypt iov failed: %d", ret); + + if (clear->length != iov[2].data.length) + errx(1, "length incorrect"); + + p = clear->data; + if (memcmp(iov[2].data.data, p, iov[2].data.length) != 0) + errx(1, "iov[2] incorrect"); + + free(iov[0].data.data); + free(iov[1].data.data); + free(iov[2].data.data); + + + return 0; +} + +static int +krb_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_data *plain, + krb5_data *verify) +{ + krb5_crypto_iov iov[3]; + int ret; + char *p; + size_t len; + + p = plain->data; + len = plain->length; + + iov[0].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (verify) { + iov[0].data = *verify; + } else { + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); + iov[0].data.data = emalloc(iov[0].data.length); + } + + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data.length = len; + iov[1].data.data = p; + + iov[2].flags = KRB5_CRYPTO_TYPE_TRAILER; + krb5_crypto_length(context, crypto, iov[0].flags, &iov[2].data.length); + iov[2].data.data = malloc(iov[2].data.length); + + if (verify == NULL) { + ret = krb5_create_checksum_iov(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_create_checksum_iov failed"); + } + + ret = krb5_verify_checksum_iov(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_verify_checksum_iov"); + + if (verify == NULL) + free(iov[0].data.data); + free(iov[2].data.data); + + return 0; +} + + +static int +krb_enc_mit(krb5_context context, + krb5_enctype enctype, + krb5_keyblock *key, + unsigned usage, + krb5_data *cipher, + krb5_data *clear) +{ +#ifndef HEIMDAL_SMALLER + krb5_error_code ret; + krb5_enc_data e; + krb5_data decrypt; + size_t len; + + e.kvno = 0; + e.enctype = enctype; + e.ciphertext = *cipher; + + ret = krb5_c_decrypt(context, *key, usage, NULL, &e, &decrypt); + if (ret) + return ret; + + if (decrypt.length != clear->length || + (decrypt.length && + memcmp(decrypt.data, clear->data, decrypt.length) != 0)) { + krb5_warnx(context, "clear text not same"); + return EINVAL; + } + + krb5_data_free(&decrypt); + + ret = krb5_c_encrypt_length(context, enctype, clear->length, &len); + if (ret) + return ret; + + if (len != cipher->length) { + krb5_warnx(context, "c_encrypt_length wrong %lu != %lu", + (unsigned long)len, (unsigned long)cipher->length); + return EINVAL; + } +#endif /* HEIMDAL_SMALLER */ + return 0; +} + +struct { + krb5_enctype enctype; + unsigned usage; + size_t keylen; + void *key; + size_t elen; + void* edata; + size_t plen; + void *pdata; + size_t clen; /* checksum length */ + void *cdata; /* checksum data */ +} krbencs[] = { + { + ETYPE_AES256_CTS_HMAC_SHA1_96, + 7, + 32, + "\x47\x75\x69\x64\x65\x6c\x69\x6e\x65\x73\x20\x74\x6f\x20\x41\x75" + "\x74\x68\x6f\x72\x73\x20\x6f\x66\x20\x49\x6e\x74\x65\x72\x6e\x65", + 44, + "\xcf\x79\x8f\x0d\x76\xf3\xe0\xbe\x8e\x66\x94\x70\xfa\xcc\x9e\x91" + "\xa9\xec\x1c\x5c\x21\xfb\x6e\xef\x1a\x7a\xc8\xc1\xcc\x5a\x95\x24" + "\x6f\x9f\xf4\xd5\xbe\x5d\x59\x97\x44\xd8\x47\xcd", + 16, + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x2e\x0a", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 32, + "\xEF\x85\xFB\x89\x0B\xB8\x47\x2F\x4D\xAB\x20\x39\x4D\xCA\x78\x1D" + "\xAD\x87\x7E\xDA\x39\xD5\x0C\x87\x0C\x0D\x5A\x0A\x8E\x48\xC7\x18", + 0, + "", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 38, + "\x84\xD7\xF3\x07\x54\xED\x98\x7B\xAB\x0B\xF3\x50\x6B\xEB\x09\xCF" + "\xB5\x54\x02\xCE\xF7\xE6\x87\x7C\xE9\x9E\x24\x7E\x52\xD1\x6E\xD4" + "\x42\x1D\xFD\xF8\x97\x6C", + 6, + "\x00\x01\x02\x03\x04\x05", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 48, + "\x35\x17\xD6\x40\xF5\x0D\xDC\x8A\xD3\x62\x87\x22\xB3\x56\x9D\x2A" + "\xE0\x74\x93\xFA\x82\x63\x25\x40\x80\xEA\x65\xC1\x00\x8E\x8F\xC2" + "\x95\xFB\x48\x52\xE7\xD8\x3E\x1E\x7C\x48\xC3\x7E\xEB\xE6\xB0\xD3", + 16, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 53, + "\x72\x0F\x73\xB1\x8D\x98\x59\xCD\x6C\xCB\x43\x46\x11\x5C\xD3\x36" + "\xC7\x0F\x58\xED\xC0\xC4\x43\x7C\x55\x73\x54\x4C\x31\xC8\x13\xBC" + "\xE1\xE6\xD0\x72\xC1\x86\xB3\x9A\x41\x3C\x2F\x92\xCA\x9B\x83\x34" + "\xA2\x87\xFF\xCB\xFC", + 21, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14", + 16, + "\xD7\x83\x67\x18\x66\x43\xD6\x7B\x41\x1C\xBA\x91\x39\xFC\x1D\xEE" + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 40, + "\x41\xF5\x3F\xA5\xBF\xE7\x02\x6D\x91\xFA\xF9\xBE\x95\x91\x95\xA0" + "\x58\x70\x72\x73\xA9\x6A\x40\xF0\xA0\x19\x60\x62\x1A\xC6\x12\x74" + "\x8B\x9B\xBF\xBE\x7E\xB4\xCE\x3C", + 0, + "", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 46, + "\x4E\xD7\xB3\x7C\x2B\xCA\xC8\xF7\x4F\x23\xC1\xCF\x07\xE6\x2B\xC7" + "\xB7\x5F\xB3\xF6\x37\xB9\xF5\x59\xC7\xF6\x64\xF6\x9E\xAB\x7B\x60" + "\x92\x23\x75\x26\xEA\x0D\x1F\x61\xCB\x20\xD6\x9D\x10\xF2", + 6, + "\x00\x01\x02\x03\x04\x05", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 56, + "\xBC\x47\xFF\xEC\x79\x98\xEB\x91\xE8\x11\x5C\xF8\xD1\x9D\xAC\x4B" + "\xBB\xE2\xE1\x63\xE8\x7D\xD3\x7F\x49\xBE\xCA\x92\x02\x77\x64\xF6" + "\x8C\xF5\x1F\x14\xD7\x98\xC2\x27\x3F\x35\xDF\x57\x4D\x1F\x93\x2E" + "\x40\xC4\xFF\x25\x5B\x36\xA2\x66", + 16, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 61, + "\x40\x01\x3E\x2D\xF5\x8E\x87\x51\x95\x7D\x28\x78\xBC\xD2\xD6\xFE" + "\x10\x1C\xCF\xD5\x56\xCB\x1E\xAE\x79\xDB\x3C\x3E\xE8\x64\x29\xF2" + "\xB2\xA6\x02\xAC\x86\xFE\xF6\xEC\xB6\x47\xD6\x29\x5F\xAE\x07\x7A" + "\x1F\xEB\x51\x75\x08\xD2\xC1\x6B\x41\x92\xE0\x1F\x62", + 21, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14", + 24, + "\x45\xEE\x79\x15\x67\xEE\xFC\xA3\x7F\x4A\xC1\xE0\x22\x2D\xE8\x0D" + "\x43\xC3\xBF\xA0\x66\x99\x67\x2A" + } +}; + +static int +krb_enc_test(krb5_context context) +{ + krb5_error_code ret; + krb5_crypto crypto; + krb5_keyblock kb; + krb5_data cipher, plain; + int i; + + for (i = 0; i < sizeof(krbencs)/sizeof(krbencs[0]); i++) { + + kb.keytype = krbencs[i].enctype; + kb.keyvalue.length = krbencs[i].keylen; + kb.keyvalue.data = krbencs[i].key; + + ret = krb5_crypto_init(context, &kb, krbencs[i].enctype, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init failed with %d for test %d", + ret, i); + + cipher.length = krbencs[i].elen; + cipher.data = krbencs[i].edata; + plain.length = krbencs[i].plen; + plain.data = krbencs[i].pdata; + + ret = krb_enc(context, crypto, krbencs[i].usage, &cipher, &plain); + + if (ret) + krb5_err(context, 1, ret, "krb_enc failed with %d for test %d", + ret, i); + + ret = krb_enc_iov(context, crypto, krbencs[i].usage, &cipher, &plain); + if (ret) + krb5_err(context, 1, ret, "krb_enc_iov failed with %d for test %d", + ret, i); + + ret = krb_enc_iov2(context, crypto, krbencs[i].usage, + cipher.length, &plain); + if (ret) + krb5_err(context, 1, ret, "krb_enc_iov2 failed with %d for test %d", + ret, i); + + ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain, NULL); + if (ret) + krb5_err(context, 1, ret, + "krb_checksum_iov failed with %d for test %d", ret, i); + + if (krbencs[i].cdata) { + krb5_data checksum; + + checksum.length = krbencs[i].clen; + checksum.data = krbencs[i].cdata; + + ret = krb_checksum_iov(context, crypto, krbencs[i].usage, + &plain, &checksum); + if (ret) + krb5_err(context, 1, ret, + "krb_checksum_iov(2) failed with %d for test %d", + ret, i); + } + + krb5_crypto_destroy(context, crypto); + + ret = krb_enc_mit(context, krbencs[i].enctype, &kb, + krbencs[i].usage, &cipher, &plain); + if (ret) + krb5_err(context, 1, ret, "krb_enc_mit failed with %d for test %d", + ret, i); + } + + return 0; +} + +static int +iov_test(krb5_context context, krb5_enctype enctype) +{ + krb5_error_code ret; + krb5_crypto crypto; + krb5_keyblock key; + krb5_data signonly, in, in2; + krb5_crypto_iov iov[6]; + size_t len, i; + unsigned char *base, *p; + + ret = krb5_generate_random_keyblock(context, enctype, &key); + if (ret) + krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); + + ret = krb5_crypto_init(context, &key, 0, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init"); + + + ret = krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &len); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length"); + + signonly.data = "This should be signed"; + signonly.length = strlen(signonly.data); + in.data = "inputdata"; + in.length = strlen(in.data); + + in2.data = "INPUTDATA"; + in2.length = strlen(in2.data); + + + memset(iov, 0, sizeof(iov)); + + iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data = in; + iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + iov[2].data = signonly; + iov[3].flags = KRB5_CRYPTO_TYPE_EMPTY; + iov[4].flags = KRB5_CRYPTO_TYPE_PADDING; + iov[5].flags = KRB5_CRYPTO_TYPE_TRAILER; + + ret = krb5_crypto_length_iov(context, crypto, iov, + sizeof(iov)/sizeof(iov[0])); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length_iov"); + + for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += iov[i].data.length; + } + + base = emalloc(len); + + /* + * Allocate data for the fields + */ + + for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue;; + iov[i].data.data = p; + p += iov[i].data.length; + } + assert(iov[1].data.length == in.length); + memcpy(iov[1].data.data, in.data, iov[1].data.length); + + /* + * Encrypt + */ + + ret = krb5_encrypt_iov_ivec(context, crypto, 7, iov, + sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec"); + + /* + * Decrypt + */ + + ret = krb5_decrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec"); + + /* + * Verify data + */ + + if (krb5_data_cmp(&iov[1].data, &in) != 0) + krb5_errx(context, 1, "decrypted data not same"); + + /* + * Free memory + */ + + free(base); + + /* Set up for second try */ + + iov[3].flags = KRB5_CRYPTO_TYPE_DATA; + iov[3].data = in; + + ret = krb5_crypto_length_iov(context, crypto, + iov, sizeof(iov)/sizeof(iov[0])); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length_iov"); + + for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += iov[i].data.length; + } + + base = emalloc(len); + + /* + * Allocate data for the fields + */ + + for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue;; + iov[i].data.data = p; + p += iov[i].data.length; + } + assert(iov[1].data.length == in.length); + memcpy(iov[1].data.data, in.data, iov[1].data.length); + + assert(iov[3].data.length == in2.length); + memcpy(iov[3].data.data, in2.data, iov[3].data.length); + + + + /* + * Encrypt + */ + + ret = krb5_encrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec"); + + /* + * Decrypt + */ + + ret = krb5_decrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec"); + + /* + * Verify data + */ + + if (krb5_data_cmp(&iov[1].data, &in) != 0) + krb5_errx(context, 1, "decrypted data 2.1 not same"); + + if (krb5_data_cmp(&iov[3].data, &in2) != 0) + krb5_errx(context, 1, "decrypted data 2.2 not same"); + + /* + * Free memory + */ + + free(base); + + krb5_crypto_destroy(context, crypto); + + krb5_free_keyblock_contents(context, &key); + + return 0; +} + + + +static int +random_to_key(krb5_context context) +{ + krb5_error_code ret; + krb5_keyblock key; + + ret = krb5_random_to_key(context, + ETYPE_DES3_CBC_SHA1, + "\x21\x39\x04\x58\x6A\xBD\x7F" + "\x21\x39\x04\x58\x6A\xBD\x7F" + "\x21\x39\x04\x58\x6A\xBD\x7F", + 21, + &key); + if (ret){ + krb5_warn(context, ret, "random_to_key"); + return 1; + } + if (key.keyvalue.length != 24) + return 1; + + if (memcmp(key.keyvalue.data, + "\x20\x38\x04\x58\x6b\xbc\x7f\xc7" + "\x20\x38\x04\x58\x6b\xbc\x7f\xc7" + "\x20\x38\x04\x58\x6b\xbc\x7f\xc7", + 24) != 0) + return 1; + + krb5_free_keyblock_contents(context, &key); + + return 0; +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + int val = 0; + + if (argc > 1 && strcmp(argv[1], "-v") == 0) + verbose = 1; + + ret = krb5_init_context (&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + val |= string_to_key_test(context); + + val |= krb_enc_test(context); + val |= random_to_key(context); + val |= iov_test(context, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96); + val |= iov_test(context, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128); + val |= iov_test(context, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192); + + if (verbose && val == 0) + printf("all ok\n"); + if (val) + printf("tests failed\n"); + + krb5_free_context(context); + + return val; +} diff --git a/third_party/heimdal/lib/krb5/an2ln_plugin.h b/third_party/heimdal/lib/krb5/an2ln_plugin.h new file mode 100644 index 0000000..b592f23 --- /dev/null +++ b/third_party/heimdal/lib/krb5/an2ln_plugin.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIMDAL_KRB5_AN2LN_PLUGIN_H +#define HEIMDAL_KRB5_AN2LN_PLUGIN_H 1 + +#include + +#define KRB5_PLUGIN_AN2LN "an2ln" +#define KRB5_PLUGIN_AN2LN_VERSION_0 0 + +typedef krb5_error_code (KRB5_LIB_CALL *set_result_f)(void *, const char *); + +/** @struct krb5plugin_an2ln_ftable_desc + * + * @brief Description of the krb5_aname_to_lname(3) plugin facility. + * + * The krb5_aname_to_lname(3) function is pluggable. The plugin is + * named KRB5_PLUGIN_AN2LN ("an2ln"), with a single minor version, + * KRB5_PLUGIN_AN2LN_VERSION_0 (0). + * + * The plugin for krb5_aname_to_lname(3) consists of a data symbol + * referencing a structure of type krb5plugin_an2ln_ftable, with four + * fields: + * + * @param init Plugin initialization function (see krb5-plugin(7)) + * + * @param minor_version The plugin minor version number (0) + * + * @param fini Plugin finalization function + * + * @param an2ln Plugin aname_to_lname function + * + * The an2ln field is the plugin entry point that performs the + * traditional aname_to_lname operation however the plugin desires. It + * is invoked in no particular order relative to other an2ln plugins, + * but it has a 'rule' argument that indicates which plugin is intended + * to act on the rule. The plugin an2ln function must return + * KRB5_PLUGIN_NO_HANDLE if the rule is not applicable to it. + * + * The plugin an2ln function has the following arguments, in this order: + * + * -# plug_ctx, the context value output by the plugin's init function + * -# context, a krb5_context + * -# rule, the aname_to_lname rule being evaluated (from krb5.conf(5)) + * -# aname, the krb5_principal to be mapped to an lname + * -# set_res_f, a function the plugin must call to set its result + * -# set_res_ctx, the first argument to set_res_f (the second is the result lname string) + * + * @ingroup krb5_support + */ +typedef struct krb5plugin_an2ln_ftable_desc { + HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context); + krb5_error_code (KRB5_LIB_CALL *an2ln)(void *, krb5_context, const char *, + krb5_const_principal, set_result_f, void *); +} krb5plugin_an2ln_ftable; + +#endif /* HEIMDAL_KRB5_AN2LN_PLUGIN_H */ + diff --git a/third_party/heimdal/lib/krb5/aname_to_localname.c b/third_party/heimdal/lib/krb5/aname_to_localname.c new file mode 100644 index 0000000..7c546fb --- /dev/null +++ b/third_party/heimdal/lib/krb5/aname_to_localname.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 1997 - 1999, 2002 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include "an2ln_plugin.h" +#include "db_plugin.h" + +#include + +/* Default plugin (DB using binary search of sorted text file) follows */ +static krb5_error_code KRB5_LIB_CALL an2ln_def_plug_init(krb5_context, void **); +static void KRB5_LIB_CALL an2ln_def_plug_fini(void *); +static krb5_error_code KRB5_LIB_CALL an2ln_def_plug_an2ln(void *, krb5_context, const char *, + krb5_const_principal, set_result_f, + void *); + +static const krb5plugin_an2ln_ftable an2ln_def_plug = { + 0, + an2ln_def_plug_init, + an2ln_def_plug_fini, + an2ln_def_plug_an2ln, +}; + +/* Plugin engine code follows */ +struct plctx { + krb5_const_principal aname; + heim_string_t luser; + const char *rule; +}; + +static krb5_error_code KRB5_LIB_CALL +set_res(void *userctx, const char *res) +{ + struct plctx *plctx = userctx; + plctx->luser = heim_string_create(res); + if (plctx->luser == NULL) + return ENOMEM; + return 0; +} + +static krb5_error_code KRB5_LIB_CALL +plcallback(krb5_context context, + const void *plug, void *plugctx, void *userctx) +{ + const krb5plugin_an2ln_ftable *locate = plug; + struct plctx *plctx = userctx; + + if (plctx->luser) + return 0; + + return locate->an2ln(plugctx, context, plctx->rule, plctx->aname, set_res, plctx); +} + +static const char *const an2ln_plugin_deps[] = { "krb5", NULL }; + +static const struct heim_plugin_data +an2ln_plugin_data = { + "krb5", + KRB5_PLUGIN_AN2LN, + KRB5_PLUGIN_AN2LN_VERSION_0, + an2ln_plugin_deps, + krb5_get_instance +}; + +static krb5_error_code +an2ln_plugin(krb5_context context, const char *rule, krb5_const_principal aname, + size_t lnsize, char *lname) +{ + krb5_error_code ret; + struct plctx ctx; + + ctx.rule = rule; + ctx.aname = aname; + ctx.luser = NULL; + + /* + * Order of plugin invocation is non-deterministic, but there should + * really be no more than one plugin that can handle any given kind + * rule, so the effect should be deterministic anyways. + */ + ret = _krb5_plugin_run_f(context, &an2ln_plugin_data, + 0, &ctx, plcallback); + if (ret != 0) { + heim_release(ctx.luser); + return ret; + } + + if (ctx.luser == NULL) + return KRB5_PLUGIN_NO_HANDLE; + + if (strlcpy(lname, heim_string_get_utf8(ctx.luser), lnsize) >= lnsize) + ret = KRB5_CONFIG_NOTENUFSPACE; + + heim_release(ctx.luser); + return ret; +} + +static void +reg_def_plugins_once(void *ctx) +{ + krb5_context context = ctx; + + krb5_plugin_register(context, PLUGIN_TYPE_DATA, KRB5_PLUGIN_AN2LN, + &an2ln_def_plug); +} + +static int +princ_realm_is_default(krb5_context context, + krb5_const_principal aname) +{ + krb5_error_code ret; + krb5_realm *lrealms = NULL; + krb5_realm *r; + int valid; + + ret = krb5_get_default_realms(context, &lrealms); + if (ret) + return 0; + + valid = 0; + for (r = lrealms; *r != NULL; ++r) { + if (strcmp (*r, aname->realm) == 0) { + valid = 1; + break; + } + } + krb5_free_host_realm (context, lrealms); + return valid; +} + +/* + * This function implements MIT's auth_to_local_names configuration for + * configuration compatibility. Specifically: + * + * [realms] + * = { + * auth_to_local_names = { + * = + * } + * } + * + * If multiple usernames are configured then the last one is taken. + * + * The configuration can only be expected to hold a relatively small + * number of mappings. For lots of mappings use a DB. + */ +static krb5_error_code +an2ln_local_names(krb5_context context, + krb5_const_principal aname, + size_t lnsize, + char *lname) +{ + krb5_error_code ret; + char *unparsed; + char **values; + char *res; + size_t i; + + if (!princ_realm_is_default(context, aname)) + return KRB5_PLUGIN_NO_HANDLE; + + ret = krb5_unparse_name_flags(context, aname, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, + &unparsed); + if (ret) + return ret; + + ret = KRB5_PLUGIN_NO_HANDLE; + values = krb5_config_get_strings(context, NULL, "realms", aname->realm, + "auth_to_local_names", unparsed, NULL); + free(unparsed); + if (!values) + return ret; + /* Take the last value, just like MIT */ + for (res = NULL, i = 0; values[i]; i++) + res = values[i]; + if (res) { + ret = 0; + if (strlcpy(lname, res, lnsize) >= lnsize) + ret = KRB5_CONFIG_NOTENUFSPACE; + + if (!*res || strcmp(res, ":") == 0) + ret = KRB5_NO_LOCALNAME; + } + + krb5_config_free_strings(values); + return ret; +} + +/* + * Heimdal's default aname2lname mapping. + */ +static krb5_error_code +an2ln_default(krb5_context context, + char *rule, + krb5_const_principal aname, + size_t lnsize, char *lname) +{ + krb5_error_code ret; + const char *res; + int root_princs_ok; + + if (strcmp(rule, "NONE") == 0) + return KRB5_NO_LOCALNAME; + + if (strcmp(rule, "DEFAULT") == 0) + root_princs_ok = 0; + else if (strcmp(rule, "HEIMDAL_DEFAULT") == 0) + root_princs_ok = 1; + else + return KRB5_PLUGIN_NO_HANDLE; + + if (!princ_realm_is_default(context, aname)) + return KRB5_PLUGIN_NO_HANDLE; + + if (aname->name.name_string.len == 1) { + /* + * One component principal names in default realm -> the one + * component is the username. + */ + res = aname->name.name_string.val[0]; + } else if (root_princs_ok && aname->name.name_string.len == 2 && + strcmp (aname->name.name_string.val[1], "root") == 0) { + /* + * Two-component principal names in default realm where the + * first component is "root" -> root IFF the principal is in + * root's .k5login (or whatever krb5_kuserok() does). + */ + krb5_principal rootprinc; + krb5_boolean userok; + + res = "root"; + + ret = krb5_copy_principal(context, aname, &rootprinc); + if (ret) + return ret; + + userok = _krb5_kuserok(context, rootprinc, res, FALSE); + krb5_free_principal(context, rootprinc); + if (!userok) + return KRB5_NO_LOCALNAME; + } else { + return KRB5_PLUGIN_NO_HANDLE; + } + + if (strlcpy(lname, res, lnsize) >= lnsize) + return KRB5_CONFIG_NOTENUFSPACE; + + return 0; +} + +/** + * Map a principal name to a local username. + * + * Returns 0 on success, KRB5_NO_LOCALNAME if no mapping was found, or + * some Kerberos or system error. + * + * Inputs: + * + * @param context A krb5_context + * @param aname A principal name + * @param lnsize The size of the buffer into which the username will be written + * @param lname The buffer into which the username will be written + * + * @ingroup krb5_support + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_aname_to_localname(krb5_context context, + krb5_const_principal aname, + size_t lnsize, + char *lname) +{ + static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT; + krb5_error_code ret; + krb5_realm realm; + size_t i; + char **rules = NULL; + char *rule; + + if (lnsize) + lname[0] = '\0'; + + heim_base_once_f(®_def_plugins, context, reg_def_plugins_once); + + /* Try MIT's auth_to_local_names config first */ + ret = an2ln_local_names(context, aname, lnsize, lname); + if (ret != KRB5_PLUGIN_NO_HANDLE) + return ret; + + ret = krb5_get_default_realm(context, &realm); + if (ret) + return ret; + + rules = krb5_config_get_strings(context, NULL, "realms", realm, + "auth_to_local", NULL); + krb5_xfree(realm); + if (!rules) { + /* Heimdal's default rule */ + ret = an2ln_default(context, "HEIMDAL_DEFAULT", aname, lnsize, lname); + if (ret == KRB5_PLUGIN_NO_HANDLE) + return KRB5_NO_LOCALNAME; + return ret; + } + + /* + * MIT rules. + * + * Note that RULEs and DBs only have white-list functionality, + * thus RULEs and DBs that we don't understand we simply ignore. + * + * This means that plugins that implement black-lists are + * dangerous: if a black-list plugin isn't found, the black-list + * won't be enforced. But black-lists are dangerous anyways. + */ + for (ret = KRB5_PLUGIN_NO_HANDLE, i = 0; rules[i]; i++) { + rule = rules[i]; + + /* Try NONE, DEFAULT, and HEIMDAL_DEFAULT rules */ + ret = an2ln_default(context, rule, aname, lnsize, lname); + if (ret == KRB5_PLUGIN_NO_HANDLE) + /* Try DB, RULE, ... plugins */ + ret = an2ln_plugin(context, rule, aname, lnsize, lname); + + if (ret == 0 && lnsize && !lname[0]) + continue; /* Success but no lname?! lies! */ + else if (ret != KRB5_PLUGIN_NO_HANDLE) + break; + } + + if (ret == KRB5_PLUGIN_NO_HANDLE) { + if (lnsize) + lname[0] = '\0'; + ret = KRB5_NO_LOCALNAME; + } + + krb5_config_free_strings(rules); + return ret; +} + +static krb5_error_code KRB5_LIB_CALL +an2ln_def_plug_init(krb5_context context, void **ctx) +{ + *ctx = NULL; + return 0; +} + +static void KRB5_LIB_CALL +an2ln_def_plug_fini(void *ctx) +{ +} + +static heim_base_once_t sorted_text_db_init_once = HEIM_BASE_ONCE_INIT; + +static void +sorted_text_db_init_f(void *arg) +{ + (void) heim_db_register("sorted-text", NULL, &heim_sorted_text_file_dbtype); +} + +static krb5_error_code KRB5_LIB_CALL +an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context, + const char *rule, + krb5_const_principal aname, + set_result_f set_res_f, void *set_res_ctx) +{ + krb5_error_code ret; + const char *an2ln_db_fname; + heim_db_t dbh = NULL; + heim_dict_t db_options; + heim_data_t k, v; + heim_error_t error; + char *unparsed = NULL; + char *value = NULL; + + _krb5_load_db_plugins(context); + heim_base_once_f(&sorted_text_db_init_once, NULL, sorted_text_db_init_f); + + if (strncmp(rule, "DB:", strlen("DB:")) != 0) + return KRB5_PLUGIN_NO_HANDLE; + + an2ln_db_fname = &rule[strlen("DB:")]; + if (!*an2ln_db_fname) + return KRB5_PLUGIN_NO_HANDLE; + + ret = krb5_unparse_name(context, aname, &unparsed); + if (ret) + return ret; + + db_options = heim_dict_create(11); + if (db_options != NULL) + heim_dict_set_value(db_options, HSTR("read-only"), + heim_number_create(1)); + dbh = heim_db_create(NULL, an2ln_db_fname, db_options, &error); + heim_release(db_options); + if (dbh == NULL) { + krb5_set_error_message(context, heim_error_get_code(error), + N_("Couldn't open aname2lname-text-db", "")); + ret = KRB5_PLUGIN_NO_HANDLE; + goto cleanup; + } + + /* Binary search; file should be sorted (in C locale) */ + k = heim_data_ref_create(unparsed, strlen(unparsed), NULL); + if (k == NULL) { + ret = krb5_enomem(context); + goto cleanup; + } + v = heim_db_copy_value(dbh, NULL, k, &error); + heim_release(k); + if (v == NULL && error != NULL) { + krb5_set_error_message(context, heim_error_get_code(error), + N_("Lookup in aname2lname-text-db failed", "")); + ret = heim_error_get_code(error); + goto cleanup; + } else if (v == NULL) { + ret = KRB5_PLUGIN_NO_HANDLE; + goto cleanup; + } else { + /* found */ + if (heim_data_get_length(v) == 0) { + krb5_set_error_message(context, ret, + N_("Principal mapped to empty username", "")); + ret = KRB5_NO_LOCALNAME; + goto cleanup; + } + value = strndup(heim_data_get_ptr(v), heim_data_get_length(v)); + heim_release(v); + if (value == NULL) { + ret = krb5_enomem(context); + goto cleanup; + } + ret = set_res_f(set_res_ctx, value); + } + +cleanup: + heim_release(dbh); + free(unparsed); + free(value); + return ret; +} + diff --git a/third_party/heimdal/lib/krb5/appdefault.c b/third_party/heimdal/lib/krb5/appdefault.c new file mode 100644 index 0000000..d4e963d --- /dev/null +++ b/third_party/heimdal/lib/krb5/appdefault.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_appdefault_boolean(krb5_context context, const char *appname, + krb5_const_realm realm, const char *option, + krb5_boolean def_val, krb5_boolean *ret_val) +{ + + if(appname == NULL) + appname = getprogname(); + + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "libdefaults", option, NULL); + if(realm != NULL) + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "realms", realm, option, NULL); + + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "appdefaults", + option, + NULL); + if(realm != NULL) + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "appdefaults", + realm, + option, + NULL); + if(appname != NULL) { + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "appdefaults", + appname, + option, + NULL); + if(realm != NULL) + def_val = krb5_config_get_bool_default(context, NULL, def_val, + "appdefaults", + appname, + realm, + option, + NULL); + } + *ret_val = def_val; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_appdefault_string(krb5_context context, const char *appname, + krb5_const_realm realm, const char *option, + const char *def_val, char **ret_val) +{ + if(appname == NULL) + appname = getprogname(); + + def_val = krb5_config_get_string_default(context, NULL, def_val, + "libdefaults", option, NULL); + if(realm != NULL) + def_val = krb5_config_get_string_default(context, NULL, def_val, + "realms", realm, option, NULL); + + def_val = krb5_config_get_string_default(context, NULL, def_val, + "appdefaults", + option, + NULL); + if(realm != NULL) + def_val = krb5_config_get_string_default(context, NULL, def_val, + "appdefaults", + realm, + option, + NULL); + if(appname != NULL) { + def_val = krb5_config_get_string_default(context, NULL, def_val, + "appdefaults", + appname, + option, + NULL); + if(realm != NULL) + def_val = krb5_config_get_string_default(context, NULL, def_val, + "appdefaults", + appname, + realm, + option, + NULL); + } + if(def_val != NULL) + *ret_val = strdup(def_val); + else + *ret_val = NULL; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_appdefault_time(krb5_context context, const char *appname, + krb5_const_realm realm, const char *option, + time_t def_val, time_t *ret_val) +{ + krb5_deltat t; + char *val; + + krb5_appdefault_string(context, appname, realm, option, NULL, &val); + if (val == NULL) { + *ret_val = def_val; + return; + } + if (krb5_string_to_deltat(val, &t)) + *ret_val = def_val; + else + *ret_val = t; + free(val); +} diff --git a/third_party/heimdal/lib/krb5/asn1_glue.c b/third_party/heimdal/lib/krb5/asn1_glue.c new file mode 100644 index 0000000..16eda2f --- /dev/null +++ b/third_party/heimdal/lib/krb5/asn1_glue.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_principal2principalname(PrincipalName *p, + krb5_const_principal from) +{ + return copy_PrincipalName(&from->name, p); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_principalname2krb5_principal (krb5_context context, + krb5_principal *principal, + const PrincipalName from, + const Realm realm) +{ + krb5_error_code ret; + krb5_principal p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return krb5_enomem(context); + ret = copy_PrincipalName(&from, &p->name); + if (ret) { + free(p); + return ret; + } + p->realm = strdup(realm); + if (p->realm == NULL) { + free_PrincipalName(&p->name); + free(p); + return krb5_enomem(context); + } + *principal = p; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_ticket2krb5_principal(krb5_context context, + krb5_principal *principal, + const EncTicketPart *ticket, + const AuthorizationData *authenticator_ad) +{ + krb5_error_code ret; + krb5_principal p = NULL; + + *principal = NULL; + + ret = _krb5_principalname2krb5_principal(context, + &p, + ticket->cname, + ticket->crealm); + if (ret == 0 && + (p->nameattrs = calloc(1, sizeof(p->nameattrs[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + p->nameattrs->authenticated = 1; + if (ret == 0 && + (p->nameattrs->source = + calloc(1, sizeof(p->nameattrs->source[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) { + p->nameattrs->source->element = + choice_PrincipalNameAttrSrc_enc_ticket_part; + ret = copy_EncTicketPart(ticket, + &p->nameattrs->source->u.enc_ticket_part); + /* NOTE: we don't want to keep a copy of the session key here! */ + if (ret == 0) + der_free_octet_string(&p->nameattrs->source->u.enc_ticket_part.key.keyvalue); + } + if (ret == 0 && authenticator_ad) { + p->nameattrs->authenticator_ad = + calloc(1, sizeof(p->nameattrs->authenticator_ad[0])); + if (p->nameattrs->authenticator_ad == NULL) + ret = krb5_enomem(context); + if (ret == 0) + ret = copy_AuthorizationData(authenticator_ad, + p->nameattrs->authenticator_ad); + } + + if (ret == 0) + *principal = p; + else + krb5_free_principal(context, p); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kdcrep2krb5_principal(krb5_context context, + krb5_principal *principal, + const EncKDCRepPart *kdcrep) +{ + krb5_error_code ret; + krb5_principal p = NULL; + + *principal = NULL; + + ret = _krb5_principalname2krb5_principal(context, + &p, + kdcrep->sname, + kdcrep->srealm); + if (ret == 0 && + (p->nameattrs = calloc(1, sizeof(p->nameattrs[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) + p->nameattrs->authenticated = 1; + if (ret == 0 && + (p->nameattrs->source = + calloc(1, sizeof(p->nameattrs->source[0]))) == NULL) + ret = krb5_enomem(context); + if (ret == 0) { + p->nameattrs->source->element = + choice_PrincipalNameAttrSrc_enc_kdc_rep_part; + ret = copy_EncKDCRepPart(kdcrep, + &p->nameattrs->source->u.enc_kdc_rep_part); + /* NOTE: we don't want to keep a copy of the session key here! */ + if (ret == 0) + der_free_octet_string(&p->nameattrs->source->u.enc_kdc_rep_part.key.keyvalue); + } + + if (ret == 0) + *principal = p; + else + krb5_free_principal(context, p); + return ret; +} diff --git a/third_party/heimdal/lib/krb5/auth_context.c b/third_party/heimdal/lib/krb5/auth_context.c new file mode 100644 index 0000000..8b43b63 --- /dev/null +++ b/third_party/heimdal/lib/krb5/auth_context.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Allocate and initialize an autentication context. + * + * @param context A kerberos context. + * @param auth_context The authentication context to be initialized. + * + * Use krb5_auth_con_free() to release the memory when done using the context. + * + * @return An krb5 error code, see krb5_get_error_message(). + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_init(krb5_context context, + krb5_auth_context *auth_context) +{ + krb5_auth_context p; + + ALLOC(p, 1); + if (!p) + return krb5_enomem(context); + memset(p, 0, sizeof(*p)); + ALLOC(p->authenticator, 1); + if (!p->authenticator) { + free(p); + return krb5_enomem(context); + } + memset (p->authenticator, 0, sizeof(*p->authenticator)); + p->flags = KRB5_AUTH_CONTEXT_DO_TIME; + + p->local_address = NULL; + p->remote_address = NULL; + p->local_port = 0; + p->remote_port = 0; + p->keytype = KRB5_ENCTYPE_NULL; + p->cksumtype = CKSUMTYPE_NONE; + p->auth_data = NULL; + *auth_context = p; + return 0; +} + +/** + * Deallocate an authentication context previously initialized with + * krb5_auth_con_init(). + * + * @param context A kerberos context. + * @param auth_context The authentication context to be deallocated. + * + * @return An krb5 error code, see krb5_get_error_message(). + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_free(krb5_context context, + krb5_auth_context auth_context) +{ + if (auth_context != NULL) { + if (auth_context->authenticator) + krb5_free_authenticator(context, &auth_context->authenticator); + if(auth_context->local_address){ + free_HostAddress(auth_context->local_address); + free(auth_context->local_address); + } + if(auth_context->remote_address){ + free_HostAddress(auth_context->remote_address); + free(auth_context->remote_address); + } + krb5_free_keyblock(context, auth_context->keyblock); + krb5_free_keyblock(context, auth_context->remote_subkey); + krb5_free_keyblock(context, auth_context->local_subkey); + if (auth_context->auth_data) { + free_AuthorizationData(auth_context->auth_data); + free(auth_context->auth_data); + } + free (auth_context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setflags(krb5_context context, + krb5_auth_context auth_context, + int32_t flags) +{ + auth_context->flags = flags; + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getflags(krb5_context context, + krb5_auth_context auth_context, + int32_t *flags) +{ + *flags = auth_context->flags; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_addflags(krb5_context context, + krb5_auth_context auth_context, + int32_t addflags, + int32_t *flags) +{ + if (flags) + *flags = auth_context->flags; + auth_context->flags |= addflags; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_removeflags(krb5_context context, + krb5_auth_context auth_context, + int32_t removeflags, + int32_t *flags) +{ + if (flags) + *flags = auth_context->flags; + auth_context->flags &= ~removeflags; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setaddrs(krb5_context context, + krb5_auth_context auth_context, + krb5_address *local_addr, + krb5_address *remote_addr) +{ + if (local_addr) { + if (auth_context->local_address) + krb5_free_address (context, auth_context->local_address); + else + if ((auth_context->local_address = malloc(sizeof(krb5_address))) == NULL) + return krb5_enomem(context); + krb5_copy_address(context, local_addr, auth_context->local_address); + } + if (remote_addr) { + if (auth_context->remote_address) + krb5_free_address (context, auth_context->remote_address); + else + if ((auth_context->remote_address = malloc(sizeof(krb5_address))) == NULL) + return krb5_enomem(context); + krb5_copy_address(context, remote_addr, auth_context->remote_address); + } + return 0; +} + +/** + * Update the authentication context \a auth_context with the local + * and remote addresses from socket \a fd, according to \a flags. + * + * @return An krb5 error code, see krb5_get_error_message(). + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_genaddrs(krb5_context context, + krb5_auth_context auth_context, + krb5_socket_t fd, int flags) +{ + krb5_error_code ret; + krb5_address local_k_address, remote_k_address; + krb5_address *lptr = NULL, *rptr = NULL; + struct sockaddr_storage ss_local, ss_remote; + struct sockaddr *local = (struct sockaddr *)&ss_local; + struct sockaddr *remote = (struct sockaddr *)&ss_remote; + socklen_t len; + + if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR) { + if (auth_context->local_address == NULL) { + len = sizeof(ss_local); + if(rk_IS_SOCKET_ERROR(getsockname(fd, local, &len))) { + char buf[128]; + ret = rk_SOCK_ERRNO; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, "getsockname: %s", buf); + goto out; + } + ret = krb5_sockaddr2address (context, local, &local_k_address); + if(ret) goto out; + if(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) { + krb5_sockaddr2port (context, local, &auth_context->local_port); + } else + auth_context->local_port = 0; + lptr = &local_k_address; + } + } + if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR) { + len = sizeof(ss_remote); + if(rk_IS_SOCKET_ERROR(getpeername(fd, remote, &len))) { + char buf[128]; + ret = rk_SOCK_ERRNO; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, "getpeername: %s", buf); + goto out; + } + ret = krb5_sockaddr2address (context, remote, &remote_k_address); + if(ret) goto out; + if(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) { + krb5_sockaddr2port (context, remote, &auth_context->remote_port); + } else + auth_context->remote_port = 0; + rptr = &remote_k_address; + } + ret = krb5_auth_con_setaddrs (context, + auth_context, + lptr, + rptr); + out: + if (lptr) + krb5_free_address (context, lptr); + if (rptr) + krb5_free_address (context, rptr); + return ret; + +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setaddrs_from_fd (krb5_context context, + krb5_auth_context auth_context, + void *p_fd) +{ + krb5_socket_t fd = *(krb5_socket_t *)p_fd; + int flags = 0; + if(auth_context->local_address == NULL) + flags |= KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR; + if(auth_context->remote_address == NULL) + flags |= KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR; + return krb5_auth_con_genaddrs(context, auth_context, fd, flags); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getaddrs(krb5_context context, + krb5_auth_context auth_context, + krb5_address **local_addr, + krb5_address **remote_addr) +{ + if(*local_addr) + krb5_free_address (context, *local_addr); + *local_addr = malloc (sizeof(**local_addr)); + if (*local_addr == NULL) + return krb5_enomem(context); + krb5_copy_address(context, + auth_context->local_address, + *local_addr); + + if(*remote_addr) + krb5_free_address (context, *remote_addr); + *remote_addr = malloc (sizeof(**remote_addr)); + if (*remote_addr == NULL) { + krb5_free_address (context, *local_addr); + *local_addr = NULL; + return krb5_enomem(context); + } + krb5_copy_address(context, + auth_context->remote_address, + *remote_addr); + return 0; +} + +/* coverity[+alloc : arg-*2] */ +static krb5_error_code +copy_key(krb5_context context, + krb5_keyblock *in, + krb5_keyblock **out) +{ + *out = NULL; + if (in) + return krb5_copy_keyblock(context, in, out); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock **keyblock) +{ + return copy_key(context, auth_context->keyblock, keyblock); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getlocalsubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock **keyblock) +{ + return copy_key(context, auth_context->local_subkey, keyblock); +} + +/* coverity[+alloc : arg-*2] */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getremotesubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock **keyblock) +{ + return copy_key(context, auth_context->remote_subkey, keyblock); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock *keyblock) +{ + if(auth_context->keyblock) + krb5_free_keyblock(context, auth_context->keyblock); + return copy_key(context, keyblock, &auth_context->keyblock); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setlocalsubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock *keyblock) +{ + if(auth_context->local_subkey) + krb5_free_keyblock(context, auth_context->local_subkey); + return copy_key(context, keyblock, &auth_context->local_subkey); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_generatelocalsubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_keyblock *subkey; + + ret = krb5_generate_subkey_extended (context, key, + auth_context->keytype, + &subkey); + if(ret) + return ret; + if(auth_context->local_subkey) + krb5_free_keyblock(context, auth_context->local_subkey); + auth_context->local_subkey = subkey; + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setremotesubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock *keyblock) +{ + if(auth_context->remote_subkey) + krb5_free_keyblock(context, auth_context->remote_subkey); + return copy_key(context, keyblock, &auth_context->remote_subkey); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setcksumtype(krb5_context context, + krb5_auth_context auth_context, + krb5_cksumtype cksumtype) +{ + auth_context->cksumtype = cksumtype; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getcksumtype(krb5_context context, + krb5_auth_context auth_context, + krb5_cksumtype *cksumtype) +{ + *cksumtype = auth_context->cksumtype; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setkeytype (krb5_context context, + krb5_auth_context auth_context, + krb5_keytype keytype) +{ + auth_context->keytype = keytype; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getkeytype (krb5_context context, + krb5_auth_context auth_context, + krb5_keytype *keytype) +{ + *keytype = auth_context->keytype; + return 0; +} + +krb5_error_code +_krb5_add_1auth_data(krb5_context context, + krb5int32 ad_type, krb5_data *ad_data, int critical, + krb5_authdata **dst) +{ + AuthorizationDataElement e; + + e.ad_type = ad_type; + e.ad_data = *ad_data; + + if (!critical) { + AuthorizationData ad; + krb5_error_code ret; + krb5_data ir; + size_t len; + + /* Build an AD-IF-RELEVANT with the new element inside it */ + ad.len = 0; + ad.val = NULL; + ret = add_AuthorizationData(&ad, &e); + + /* Encode the AD-IF-RELEVANT */ + if (ret == 0) + ASN1_MALLOC_ENCODE(AuthorizationData, ir.data, ir.length, &ad, + &len, ret); + if (ret == 0 && ir.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + /* Re-enter to add the encoded AD-IF-RELEVANT */ + ret = _krb5_add_1auth_data(context, KRB5_AUTHDATA_IF_RELEVANT, &ir, 1, + dst); + + free_AuthorizationData(&ad); + krb5_data_free(&ir); + return ret; + } + + if (*dst == NULL) { + ALLOC(*dst, 1); + if (*dst == NULL) + return krb5_enomem(context); + } + return add_AuthorizationData(*dst, &e); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_add_AuthorizationData(krb5_context context, + krb5_auth_context auth_context, + int type, + krb5_data *data) +{ + if (auth_context->auth_data == NULL) { + auth_context->auth_data = calloc(1, sizeof(*auth_context->auth_data)); + if (auth_context->auth_data == NULL) + return krb5_enomem(context); + } + return _krb5_add_1auth_data(context, type, data, 1, + &auth_context->auth_data); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_add_AuthorizationDataIfRelevant(krb5_context context, + krb5_auth_context auth_context, + krb5int32 type, + krb5_data *data) +{ + if (auth_context->auth_data == NULL) { + auth_context->auth_data = calloc(1, sizeof(*auth_context->auth_data)); + if (auth_context->auth_data == NULL) + return krb5_enomem(context); + } + return _krb5_add_1auth_data(context, type, data, 0, + &auth_context->auth_data); +} + + + +#if 0 +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setenctype(krb5_context context, + krb5_auth_context auth_context, + krb5_enctype etype) +{ + if(auth_context->keyblock) + krb5_free_keyblock(context, auth_context->keyblock); + ALLOC(auth_context->keyblock, 1); + if(auth_context->keyblock == NULL) + return krb5_enomem(context); + auth_context->keyblock->keytype = etype; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getenctype(krb5_context context, + krb5_auth_context auth_context, + krb5_enctype *etype) +{ + krb5_abortx(context, "unimplemented krb5_auth_getenctype called"); +} +#endif + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getlocalseqnumber(krb5_context context, + krb5_auth_context auth_context, + int32_t *seqnumber) +{ + *seqnumber = auth_context->local_seqnumber; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setlocalseqnumber (krb5_context context, + krb5_auth_context auth_context, + int32_t seqnumber) +{ + auth_context->local_seqnumber = seqnumber; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getremoteseqnumber(krb5_context context, + krb5_auth_context auth_context, + int32_t *seqnumber) +{ + *seqnumber = auth_context->remote_seqnumber; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setremoteseqnumber (krb5_context context, + krb5_auth_context auth_context, + int32_t seqnumber) +{ + auth_context->remote_seqnumber = seqnumber; + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getauthenticator(krb5_context context, + krb5_auth_context auth_context, + krb5_authenticator *authenticator) +{ + *authenticator = malloc(sizeof(**authenticator)); + if (*authenticator == NULL) + return krb5_enomem(context); + + return copy_Authenticator(auth_context->authenticator, + *authenticator); +} + + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_authenticator(krb5_context context, + krb5_authenticator *authenticator) +{ + free_Authenticator (*authenticator); + free (*authenticator); + *authenticator = NULL; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setuserkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock *keyblock) +{ + if(auth_context->keyblock) + krb5_free_keyblock(context, auth_context->keyblock); + return krb5_copy_keyblock(context, keyblock, &auth_context->keyblock); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_getrcache(krb5_context context, + krb5_auth_context auth_context, + krb5_rcache *rcache) +{ + *rcache = auth_context->rcache; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setrcache(krb5_context context, + krb5_auth_context auth_context, + krb5_rcache rcache) +{ + auth_context->rcache = rcache; + return 0; +} + +#if 0 /* not implemented */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_initivector(krb5_context context, + krb5_auth_context auth_context) +{ + krb5_abortx(context, "unimplemented krb5_auth_con_initivector called"); +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_con_setivector(krb5_context context, + krb5_auth_context auth_context, + krb5_pointer ivector) +{ + krb5_abortx(context, "unimplemented krb5_auth_con_setivector called"); +} + +#endif /* not implemented */ diff --git a/third_party/heimdal/lib/krb5/authdata.c b/third_party/heimdal/lib/krb5/authdata.c new file mode 100644 index 0000000..ac42661 --- /dev/null +++ b/third_party/heimdal/lib/krb5/authdata.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1997-2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (c) 2021 Isaac Boukris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * Add the AuthorizationData `data´ of `type´ to the last element in + * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_kdc_tkt_add_if_relevant_ad(krb5_context context, + EncTicketPart *tkt, + int type, + const krb5_data *data) +{ + krb5_error_code ret; + size_t size = 0; + + if (tkt->authorization_data == NULL) { + tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data)); + if (tkt->authorization_data == NULL) { + return krb5_enomem(context); + } + } + + /* add the entry to the last element */ + { + AuthorizationData ad = { 0, NULL }; + AuthorizationDataElement ade; + + ade.ad_type = type; + ade.ad_data = *data; + + ret = add_AuthorizationData(&ad, &ade); + if (ret) { + krb5_set_error_message(context, ret, "add AuthorizationData failed"); + return ret; + } + + ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + + ASN1_MALLOC_ENCODE(AuthorizationData, + ade.ad_data.data, ade.ad_data.length, + &ad, &size, ret); + free_AuthorizationData(&ad); + if (ret) { + krb5_set_error_message(context, ret, "ASN.1 encode of " + "AuthorizationData failed"); + return ret; + } + if (ade.ad_data.length != size) + krb5_abortx(context, "internal asn.1 encoder error"); + + ret = add_AuthorizationData(tkt->authorization_data, &ade); + der_free_octet_string(&ade.ad_data); + if (ret) { + krb5_set_error_message(context, ret, "add AuthorizationData failed"); + return ret; + } + } + + return 0; +} + +/* + * Insert a PAC wrapped in AD-IF-RELEVANT container as the first AD element, + * as some clients such as Windows may fail to parse it otherwise. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_kdc_tkt_insert_pac(krb5_context context, + EncTicketPart *tkt, + const krb5_data *data) +{ + AuthorizationDataElement ade; + unsigned int i; + krb5_error_code ret; + + ret = _kdc_tkt_add_if_relevant_ad(context, tkt, KRB5_AUTHDATA_WIN2K_PAC, + data); + if (ret) + return ret; + + heim_assert(tkt->authorization_data->len != 0, "No authorization_data!"); + ade = tkt->authorization_data->val[tkt->authorization_data->len - 1]; + for (i = 0; i < tkt->authorization_data->len - 1; i++) { + tkt->authorization_data->val[i + 1] = tkt->authorization_data->val[i]; + } + tkt->authorization_data->val[0] = ade; + + return 0; +} diff --git a/third_party/heimdal/lib/krb5/build_ap_req.c b/third_party/heimdal/lib/krb5/build_ap_req.c new file mode 100644 index 0000000..cb6f60d --- /dev/null +++ b/third_party/heimdal/lib/krb5/build_ap_req.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_build_ap_req (krb5_context context, + krb5_enctype enctype, + krb5_creds *cred, + krb5_flags ap_options, + krb5_data authenticator, + krb5_data *retdata) +{ + krb5_error_code ret = 0; + AP_REQ ap; + size_t len; + + ap.pvno = 5; + ap.msg_type = krb_ap_req; + memset(&ap.ap_options, 0, sizeof(ap.ap_options)); + ap.ap_options.use_session_key = (ap_options & AP_OPTS_USE_SESSION_KEY) > 0; + ap.ap_options.mutual_required = (ap_options & AP_OPTS_MUTUAL_REQUIRED) > 0; + + ret = decode_Ticket(cred->ticket.data, cred->ticket.length, &ap.ticket, &len); + if (ret) + return ret; + if (cred->ticket.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + ap.authenticator.etype = enctype; + ap.authenticator.kvno = NULL; + ap.authenticator.cipher = authenticator; + + ASN1_MALLOC_ENCODE(AP_REQ, retdata->data, retdata->length, &ap, &len, ret); + if (ret == 0 && retdata->length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + free_AP_REQ(&ap); + return ret; +} diff --git a/third_party/heimdal/lib/krb5/build_auth.c b/third_party/heimdal/lib/krb5/build_auth.c new file mode 100644 index 0000000..3e00125 --- /dev/null +++ b/third_party/heimdal/lib/krb5/build_auth.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +static krb5_error_code +add_auth_data(krb5_context context, + AuthorizationData *src, + AuthorizationData **dst) +{ + krb5_error_code ret = 0; + size_t i; + + if (*dst == NULL && + (*dst = calloc(1, sizeof(**dst))) == NULL) + return krb5_enomem(context); + for (i = 0; ret == 0 && i < src->len; i++) + ret = add_AuthorizationData(*dst, &src->val[i]); + return ret; +} + +static krb5_error_code +add_etypelist(krb5_context context, + krb5_authdata *auth_data) +{ + AuthorizationDataElement ade; + EtypeList etypes; + krb5_error_code ret; + krb5_data e; + size_t len = 0; + + ret = _krb5_init_etype(context, KRB5_PDU_NONE, + &etypes.len, &etypes.val, + NULL); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EtypeList, e.data, e.length, &etypes, &len, ret); + if (ret) { + free_EtypeList(&etypes); + return ret; + } + if(e.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + free_EtypeList(&etypes); + + ade.ad_type = KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION; + ade.ad_data = e; + + ret = add_AuthorizationData(auth_data, &ade); + + krb5_data_free(&e); + + return ret; +} + +static krb5_error_code +add_ap_options(krb5_context context, + krb5_authdata *auth_data) +{ + krb5_error_code ret; + AuthorizationDataElement ade; + krb5_boolean require_cb; + uint8_t ap_options[4]; + + require_cb = krb5_config_get_bool_default(context, NULL, FALSE, + "libdefaults", + "client_aware_channel_bindings", + NULL); + + if (!require_cb) + return 0; + + ap_options[0] = (KERB_AP_OPTIONS_CBT >> 0 ) & 0xFF; + ap_options[1] = (KERB_AP_OPTIONS_CBT >> 8 ) & 0xFF; + ap_options[2] = (KERB_AP_OPTIONS_CBT >> 16) & 0xFF; + ap_options[3] = (KERB_AP_OPTIONS_CBT >> 24) & 0xFF; + + ade.ad_type = KRB5_AUTHDATA_AP_OPTIONS; + ade.ad_data.length = sizeof(ap_options); + ade.ad_data.data = ap_options; + + ret = add_AuthorizationData(auth_data, &ade); + + return ret; +} + +static krb5_error_code +make_ap_authdata(krb5_context context, + krb5_authdata **auth_data) +{ + krb5_error_code ret; + AuthorizationData ad; + krb5_data ir; + size_t len; + + ad.len = 0; + ad.val = NULL; + + ret = add_etypelist(context, &ad); + if (ret) + return ret; + + /* + * Windows has a bug and only looks for first occurrence of AD-IF-RELEVANT + * in the AP authenticator when looking for AD-AP-OPTIONS. Make sure to + * bundle it together with etypes. + */ + ret = add_ap_options(context, &ad); + if (ret) { + free_AuthorizationData(&ad); + return ret; + } + + ASN1_MALLOC_ENCODE(AuthorizationData, ir.data, ir.length, &ad, &len, ret); + if (ret) { + free_AuthorizationData(&ad); + return ret; + } + if(ir.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = _krb5_add_1auth_data(context, KRB5_AUTHDATA_IF_RELEVANT, &ir, 1, + auth_data); + + free_AuthorizationData(&ad); + krb5_data_free(&ir); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_build_authenticator (krb5_context context, + krb5_auth_context auth_context, + krb5_enctype enctype, + krb5_creds *cred, + Checksum *cksum, + krb5_data *result, + krb5_key_usage usage) +{ + Authenticator auth; + u_char *buf = NULL; + size_t buf_size; + size_t len = 0; + krb5_error_code ret; + krb5_crypto crypto; + + memset(&auth, 0, sizeof(auth)); + + auth.authenticator_vno = 5; + ret = copy_Realm(&cred->client->realm, &auth.crealm); + if (ret) + goto fail; + ret = copy_PrincipalName(&cred->client->name, &auth.cname); + if (ret) + goto fail; + + krb5_us_timeofday (context, &auth.ctime, &auth.cusec); + + ret = krb5_auth_con_getlocalsubkey(context, auth_context, &auth.subkey); + if(ret) + goto fail; + + if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + if(auth_context->local_seqnumber == 0) + krb5_generate_seq_number (context, + &cred->session, + &auth_context->local_seqnumber); + ALLOC(auth.seq_number, 1); + if(auth.seq_number == NULL) { + ret = krb5_enomem(context); + goto fail; + } + *auth.seq_number = auth_context->local_seqnumber; + } else + auth.seq_number = NULL; + auth.authorization_data = NULL; + + if (cksum) { + ALLOC(auth.cksum, 1); + if (auth.cksum == NULL) { + ret = krb5_enomem(context); + goto fail; + } + ret = copy_Checksum(cksum, auth.cksum); + if (ret) + goto fail; + + if (auth.cksum->cksumtype == CKSUMTYPE_GSSAPI) { + /* + * This is not GSS-API specific, we only enable it for + * GSS for now + */ + ret = make_ap_authdata(context, &auth.authorization_data); + if (ret) + goto fail; + } + } + + /* Copy other authz data from auth_context */ + if (auth_context->auth_data) { + ret = add_auth_data(context, auth_context->auth_data, &auth.authorization_data); + if (ret) + goto fail; + } + + /* XXX - Copy more to auth_context? */ + + auth_context->authenticator->ctime = auth.ctime; + auth_context->authenticator->cusec = auth.cusec; + + ASN1_MALLOC_ENCODE(Authenticator, buf, buf_size, &auth, &len, ret); + if (ret) + goto fail; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_crypto_init(context, &cred->session, enctype, &crypto); + if (ret) + goto fail; + ret = krb5_encrypt (context, + crypto, + usage /* KRB5_KU_AP_REQ_AUTH */, + buf, + len, + result); + krb5_crypto_destroy(context, crypto); + + if (ret) + goto fail; + + fail: + free_Authenticator (&auth); + free (buf); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/cache.c b/third_party/heimdal/lib/krb5/cache.c new file mode 100644 index 0000000..3f16d69 --- /dev/null +++ b/third_party/heimdal/lib/krb5/cache.c @@ -0,0 +1,2300 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * @page krb5_ccache_intro The credential cache functions + * @section section_krb5_ccache Kerberos credential caches + * + * krb5_ccache structure holds a Kerberos credential cache. + * + * Heimdal support the follow types of credential caches: + * + * - SCC + * Store the credential in a database + * - FILE + * Store the credential in memory + * - MEMORY + * Store the credential in memory + * - API + * A credential cache server based solution for Mac OS X + * - KCM + * A credential cache server based solution for all platforms + * + * @subsection Example + * + * This is a minimalistic version of klist: +@code +#include + +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_ccache id; + krb5_creds creds; + + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_cc_default (context, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_default"); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); + + while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){ + char *principal; + + krb5_unparse_name(context, creds.server, &principal); + printf("principal: %s\\n", principal); + free(principal); + krb5_free_cred_contents (context, &creds); + } + ret = krb5_cc_end_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); + + krb5_cc_close(context, id); + + krb5_free_context(context); + return 0; +} +* @endcode +*/ + +static const krb5_cc_ops * +cc_get_prefix_ops(krb5_context context, + const char *prefix, + const char **residual); + +/** + * Add a new ccache type with operations `ops', overwriting any + * existing one if `override'. + * + * @param context a Kerberos context + * @param ops type of plugin symbol + * @param override flag to select if the registration is to overide + * an existing ops with the same name. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_register(krb5_context context, + const krb5_cc_ops *ops, + krb5_boolean override) +{ + int i; + + for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { + if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) { + if(!override) { + krb5_set_error_message(context, + KRB5_CC_TYPE_EXISTS, + N_("cache type %s already exists", "type"), + ops->prefix); + return KRB5_CC_TYPE_EXISTS; + } + break; + } + } + if(i == context->num_cc_ops) { + const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops), + (context->num_cc_ops + 1) * + sizeof(context->cc_ops[0])); + if(o == NULL) { + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); + return KRB5_CC_NOMEM; + } + context->cc_ops = o; + context->cc_ops[context->num_cc_ops] = NULL; + context->num_cc_ops++; + } + context->cc_ops[i] = ops; + return 0; +} + +/* + * Allocate the memory for a `id' and the that function table to + * `ops'. Returns 0 or and error code. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_cc_allocate(krb5_context context, + const krb5_cc_ops *ops, + krb5_ccache *id) +{ + krb5_ccache p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); + return KRB5_CC_NOMEM; + } + p->ops = ops; + *id = p; + + return 0; +} + +/* + * Allocate memory for a new ccache in `id' with operations `ops' + * and name `residual'. Return 0 or an error code. + */ + +static krb5_error_code +allocate_ccache(krb5_context context, + const krb5_cc_ops *ops, + const char *residual, + const char *subsidiary, + krb5_ccache *id) +{ + krb5_error_code ret = 0; + char *exp_residual = NULL; + int filepath; + + filepath = (strcmp("FILE", ops->prefix) == 0 + || strcmp("DIR", ops->prefix) == 0 + || strcmp("SCC", ops->prefix) == 0); + + if (residual) + ret = _krb5_expand_path_tokens(context, residual, filepath, &exp_residual); + if (ret == 0) + ret = _krb5_cc_allocate(context, ops, id); + + if (ret == 0) { + if ((*id)->ops->version < KRB5_CC_OPS_VERSION_5 + || (*id)->ops->resolve_2 == NULL) { + ret = (*id)->ops->resolve(context, id, exp_residual); + } else { + ret = (*id)->ops->resolve_2(context, id, exp_residual, subsidiary); + } + } + if (ret) { + free(*id); + *id = NULL; + } + free(exp_residual); + return ret; +} + + +/** + * Find and allocate a ccache in `id' from the specification in `residual'. + * If the ccache name doesn't contain any colon, interpret it as a file name. + * + * @param context a Kerberos context. + * @param name string name of a credential cache. + * @param id return pointer to a found credential cache. + * + * @return Return 0 or an error code. In case of an error, id is set + * to NULL, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_resolve(krb5_context context, + const char *name, + krb5_ccache *id) +{ + const krb5_cc_ops *ops; + const char *residual = NULL; + + *id = NULL; + + ops = cc_get_prefix_ops(context, name, &residual); + if (ops == NULL) + ops = &krb5_fcc_ops; /* residual will point to name */ + + return allocate_ccache(context, ops, residual, NULL, id); +} + +#ifdef _WIN32 +static const char * +get_default_cc_type_win32(krb5_context context) +{ + krb5_error_code ret; + krb5_ccache id; + + /* + * If the MSLSA ccache type has a principal name, + * use it as the default. + */ + ret = krb5_cc_resolve(context, "MSLSA:", &id); + if (ret == 0) { + krb5_principal princ; + ret = krb5_cc_get_principal(context, id, &princ); + krb5_cc_close(context, id); + if (ret == 0) { + krb5_free_principal(context, princ); + return "MSLSA"; + } + } + + /* + * If the API: ccache can be resolved, + * use it as the default. + */ + ret = krb5_cc_resolve(context, "API:", &id); + if (ret == 0) { + krb5_cc_close(context, id); + return "API"; + } + + return NULL; +} +#endif /* _WIN32 */ + +static const char * +get_default_cc_type(krb5_context context, int simple) +{ + const char *def_ccname; + const char *def_cctype = + krb5_config_get_string_default(context, NULL, + secure_getenv("KRB5CCTYPE"), + "libdefaults", "default_cc_type", NULL); + const char *def_cccol = + krb5_config_get_string(context, NULL, "libdefaults", + "default_cc_collection", NULL); + const krb5_cc_ops *ops; + + if (!simple && (def_ccname = krb5_cc_default_name(context))) { + ops = cc_get_prefix_ops(context, def_ccname, NULL); + if (ops) + return ops->prefix; + } + if (!def_cctype && def_cccol) { + ops = cc_get_prefix_ops(context, def_cccol, NULL); + if (ops) + return ops->prefix; + } +#ifdef _WIN32 + if (def_cctype == NULL) + def_cctype = get_default_cc_type_win32(context); +#endif + if (def_cctype == NULL) + def_cctype = KRB5_DEFAULT_CCTYPE->prefix; + return def_cctype; +} + +/** + * Find and allocate a ccache in `id' for the subsidiary cache named by + * `subsidiary' in the collection named by `collection'. + * + * @param context a Kerberos context. + * @param cctype string name of a credential cache collection type. + * @param collection string name of a credential cache collection. + * @param subsidiary string name of a credential cache in a collection. + * @param id return pointer to a found credential cache. + * + * @return Return 0 or an error code. In case of an error, id is set + * to NULL, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_resolve_sub(krb5_context context, + const char *cctype, + const char *collection, + const char *subsidiary, + krb5_ccache *id) +{ + const krb5_cc_ops *ops = NULL; + + *id = NULL; + + /* Get the cctype from the collection, maybe */ + if (cctype == NULL && collection) + ops = cc_get_prefix_ops(context, collection, &collection); + + if (ops == NULL) + ops = cc_get_prefix_ops(context, get_default_cc_type(context, 0), NULL); + + if (ops == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + N_("unknown ccache type %s", ""), cctype); + return KRB5_CC_UNKNOWN_TYPE; + } + + return allocate_ccache(context, ops, collection, subsidiary, id); +} + + +/** + * Find and allocate a ccache in `id' from the specification in `residual', but + * specific to the given principal `principal' by using the principal name as + * the name of a "subsidiary" credentials cache in the collection named by + * `name'. If the ccache name doesn't contain any colon, interpret it as a + * file name. + * + * @param context a Kerberos context. + * @param name string name of a credential cache. + * @param principal principal name of desired credentials. + * @param id return pointer to a found credential cache. + * + * @return Return 0 or an error code. In case of an error, id is set + * to NULL, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_resolve_for(krb5_context context, + const char *cctype, + const char *name, + krb5_const_principal principal, + krb5_ccache *id) +{ + krb5_error_code ret; + char *p, *s; + + *id = NULL; + + ret = krb5_unparse_name(context, principal, &p); + if (ret) + return ret; + /* + * Subsidiary components cannot have various chars in them that are used as + * separators. ':' is used for subsidiary separators in all ccache types + * except FILE, where '+' is used instead because we can't use ':' in file + * paths on Windows and because ':' is not in the POSIX safe set. + */ + for (s = p; *s; s++) { + switch (s[0]) { + case ':': + case '+': + case '/': + case '\\': + s[0] = '-'; + default: break; + } + } + ret = krb5_cc_resolve_sub(context, cctype, name, p, id); + free(p); + return ret; +} + +/** + * Generates a new unique ccache of `type` in `id'. If `type' is NULL, + * the library chooses the default credential cache type. The supplied + * `hint' (that can be NULL) is a string that the credential cache + * type can use to base the name of the credential on, this is to make + * it easier for the user to differentiate the credentials. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_new_unique(krb5_context context, const char *type, + const char *hint, krb5_ccache *id) +{ + const krb5_cc_ops *ops; + krb5_error_code ret; + + if (type == NULL) + type = get_default_cc_type(context, 1); + + ops = krb5_cc_get_prefix_ops(context, type); + if (ops == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + "Credential cache type %s is unknown", type); + return KRB5_CC_UNKNOWN_TYPE; + } + + ret = _krb5_cc_allocate(context, ops, id); + if (ret) + return ret; + ret = (*id)->ops->gen_new(context, id); + if (ret) { + free(*id); + *id = NULL; + } + return ret; +} + +/** + * Return the name of the ccache `id' + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_cc_get_name(krb5_context context, + krb5_ccache id) +{ + const char *name = NULL; + + if (id->ops->version < KRB5_CC_OPS_VERSION_5 + || id->ops->get_name_2 == NULL) + return id->ops->get_name(context, id); + + (void) id->ops->get_name_2(context, id, &name, NULL, NULL); + return name; +} + +/** + * Return the name of the ccache collection associated with `id' + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_cc_get_collection(krb5_context context, krb5_ccache id) +{ + const char *name = NULL; + + if (id->ops->version < KRB5_CC_OPS_VERSION_5 + || id->ops->get_name_2 == NULL) + return NULL; + + (void) id->ops->get_name_2(context, id, NULL, &name, NULL); + return name; +} + +/** + * Return the name of the subsidiary ccache of `id' + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_cc_get_subsidiary(krb5_context context, krb5_ccache id) +{ + const char *name = NULL; + + if (id->ops->version >= KRB5_CC_OPS_VERSION_5 + && id->ops->get_name_2 != NULL) + (void) id->ops->get_name_2(context, id, NULL, NULL, &name); + return name; +} + +/** + * Return the type of the ccache `id'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_cc_get_type(krb5_context context, + krb5_ccache id) +{ + return id->ops->prefix; +} + +/** + * Return the complete resolvable name the cache + + * @param context a Kerberos context + * @param id return pointer to a found credential cache + * @param str the returned name of a credential cache, free with krb5_xfree() + * + * @return Returns 0 or an error (and then *str is set to NULL). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_full_name(krb5_context context, + krb5_ccache id, + char **str) +{ + const char *type, *name; + + *str = NULL; + + type = krb5_cc_get_type(context, id); + if (type == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + "cache has no name of type"); + return KRB5_CC_UNKNOWN_TYPE; + } + + name = krb5_cc_get_name(context, id); + if (name == NULL) { + krb5_set_error_message(context, KRB5_CC_BADNAME, + "cache of type %s has no name", type); + return KRB5_CC_BADNAME; + } + + if (asprintf(str, "%s:%s", type, name) == -1) { + *str = NULL; + return krb5_enomem(context); + } + return 0; +} + +/** + * Return krb5_cc_ops of a the ccache `id'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL +krb5_cc_get_ops(krb5_context context, krb5_ccache id) +{ + return id->ops; +} + +/* + * Expand variables in `str' into `res' + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) +{ + int filepath; + + filepath = (strncmp("FILE:", str, 5) == 0 + || strncmp("DIR:", str, 4) == 0 + || strncmp("SCC:", str, 4) == 0); + + return _krb5_expand_path_tokens(context, str, filepath, res); +} + +/* + * Return non-zero if envirnoment that will determine default krb5cc + * name has changed. + */ + +static int +environment_changed(krb5_context context) +{ + const char *e; + + /* if the cc name was set, don't change it */ + if (context->default_cc_name_set) + return 0; + + /* XXX performance: always ask KCM/API if default name has changed */ + if (context->default_cc_name && + (strncmp(context->default_cc_name, "KCM:", 4) == 0 || + strncmp(context->default_cc_name, "API:", 4) == 0)) + return 1; + + e = secure_getenv("KRB5CCNAME"); + if (e == NULL) { + if (context->default_cc_name_env) { + free(context->default_cc_name_env); + context->default_cc_name_env = NULL; + return 1; + } + } else { + if (context->default_cc_name_env == NULL) + return 1; + if (strcmp(e, context->default_cc_name_env) != 0) + return 1; + } + return 0; +} + +/** + * Switch the default default credential cache for a specific + * credcache type (and name for some implementations). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_switch(krb5_context context, krb5_ccache id) +{ +#ifdef _WIN32 + _krb5_set_default_cc_name_to_registry(context, id); +#endif + + if (id->ops->version == KRB5_CC_OPS_VERSION_0 + || id->ops->set_default == NULL) + return 0; + + return (*id->ops->set_default)(context, id); +} + +/** + * Return true if the default credential cache support switch + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_cc_support_switch(krb5_context context, const char *type) +{ + const krb5_cc_ops *ops; + + ops = krb5_cc_get_prefix_ops(context, type); + if (ops && ops->version > KRB5_CC_OPS_VERSION_0 && ops->set_default) + return 1; + return FALSE; +} + +/** + * Set the default cc name for `context' to `name'. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_set_default_name(krb5_context context, const char *name) +{ + krb5_error_code ret = 0; + char *p = NULL; + + if (name == NULL) { + const char *e; + + if ((e = secure_getenv("KRB5CCNAME"))) { + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); + + free(context->default_cc_name_env); + context->default_cc_name_env = p; + + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); + + /* + * We're resetting the default ccache name. Recall that we got + * this from the environment, which might change. + */ + context->default_cc_name_set = 0; + } else if ((e = krb5_cc_configured_default_name(context))) { + if ((p = strdup(e)) == NULL) + return krb5_enomem(context); + + /* + * Since $KRB5CCNAME was not set, and since we got the default + * ccache name from configuration, we'll not want + * environment_changed() to return true to avoid re-doing the + * krb5_cc_configured_default_name() call unnecessarily. + * + * XXX Perhaps if we got the ccache name from the registry then + * we'd want to recheck it? If so we might need an indication + * from krb5_cc_configured_default_name() about that! + */ + context->default_cc_name_set = 1; + } + } else { + int filepath = (strncmp("FILE:", name, 5) == 0 || + strncmp("DIR:", name, 4) == 0 || + strncmp("SCC:", name, 4) == 0); + + ret = _krb5_expand_path_tokens(context, name, filepath, &p); + if (ret) + return ret; + + /* + * Since the default ccache name was set explicitly, we won't want + * environment_changed() to return true until the default ccache name + * is reset. + */ + context->default_cc_name_set = 1; + } + + free(context->default_cc_name); + context->default_cc_name = p; + return 0; +} + +/** + * Return a pointer to a context static string containing the default + * ccache name. + * + * @return String to the default credential cache name. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_cc_default_name(krb5_context context) +{ + if (context->default_cc_name == NULL || environment_changed(context)) + krb5_cc_set_default_name(context, NULL); + + return context->default_cc_name; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_cc_configured_default_name(krb5_context context) +{ + krb5_error_code ret = 0; +#ifdef _WIN32 + krb5_ccache id; +#endif + const char *cfg; + char *expanded; + const krb5_cc_ops *ops; + + if (context->configured_default_cc_name) + return context->configured_default_cc_name; + +#ifdef _WIN32 + if ((expanded = _krb5_get_default_cc_name_from_registry(context))) + return context->configured_default_cc_name = expanded; +#endif + + /* If there's a configured default, expand the tokens and use it */ + cfg = krb5_config_get_string(context, NULL, "libdefaults", + "default_cc_name", NULL); + if (cfg == NULL) + cfg = krb5_config_get_string(context, NULL, "libdefaults", + "default_ccache_name", NULL); + if (cfg) { + ret = _krb5_expand_default_cc_name(context, cfg, &expanded); + if (ret) { + krb5_set_error_message(context, ret, + "token expansion failed for %s", cfg); + return NULL; + } + return context->configured_default_cc_name = expanded; + } + + /* Else try a configured default ccache type's default */ + cfg = get_default_cc_type(context, 1); + if ((ops = krb5_cc_get_prefix_ops(context, cfg)) == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + "unknown configured credential cache " + "type %s", cfg); + return NULL; + } + + /* The get_default_name() method expands any tokens */ + ret = (*ops->get_default_name)(context, &expanded); + if (ret) { + krb5_set_error_message(context, ret, "failed to find a default " + "ccache for default ccache type %s", cfg); + return NULL; + } + return context->configured_default_cc_name = expanded; +} + +KRB5_LIB_FUNCTION char * KRB5_LIB_CALL +krb5_cccol_get_default_ccname(krb5_context context) +{ + const char *cfg = get_default_cc_type(context, 1); + char *cccol_default_ccname; + const krb5_cc_ops *ops = krb5_cc_get_prefix_ops(context, cfg); + + (void) (*ops->get_default_name)(context, &cccol_default_ccname); + return cccol_default_ccname; +} + +/** + * Open the default ccache in `id'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_default(krb5_context context, + krb5_ccache *id) +{ + const char *p = krb5_cc_default_name(context); + + *id = NULL; + if (p == NULL) + return krb5_enomem(context); + return krb5_cc_resolve(context, p, id); +} + +/** + * Open the named subsidiary cache from the default ccache collection in `id'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_default_sub(krb5_context context, + const char *subsidiary, + krb5_ccache *id) +{ + return krb5_cc_resolve_sub(context, get_default_cc_type(context, 0), NULL, + subsidiary, id); +} + +/** + * Open the default ccache in `id' that corresponds to the given principal. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_default_for(krb5_context context, + krb5_const_principal principal, + krb5_ccache *id) +{ + return krb5_cc_resolve_for(context, get_default_cc_type(context, 0), NULL, + principal, id); +} + +/** + * Create a new ccache in `id' for `primary_principal'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_error_code ret; + + ret = (*id->ops->init)(context, id, primary_principal); + if (ret == 0) { + id->cc_kx509_done = 0; + id->cc_initialized = 1; + id->cc_need_start_realm = 1; + id->cc_start_tgt_stored = 0; + } + return ret; +} + + +/** + * Remove the ccache `id'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_destroy(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret2 = 0; + krb5_error_code ret; + krb5_data d; + + /* + * Destroy associated hx509 PKIX credential store created by krb5_kx509*(). + */ + if (krb5_cc_get_config(context, id, NULL, "kx509store", &d) == 0) { + char *name; + + if ((name = strndup(d.data, d.length)) == NULL) { + ret2 = krb5_enomem(context); + } else { + hx509_certs certs; + ret = hx509_certs_init(context->hx509ctx, name, 0, NULL, &certs); + if (ret == 0) + ret2 = hx509_certs_destroy(context->hx509ctx, &certs); + else + hx509_certs_free(&certs); + free(name); + } + } + + ret = (*id->ops->destroy)(context, id); + (void) krb5_cc_close(context, id); + return ret ? ret : ret2; +} + +/** + * Stop using the ccache `id' and free the related resources. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_close(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret; + + if (!id) + return 0; + + /* + * We want to automatically acquire a PKIX credential using kx509. + * + * This can be slow if we're generating an RSA key. Plus it means talking + * to the KDC. + * + * We only want to do this when: + * + * - krb5_cc_initialize() was called on this ccache handle, + * - a start TGT was stored (actually, a cross-realm TGT would do), + * + * and + * + * - we aren't creating a gss_cred_id_t for a delegated credential. + * + * We only have a heuristic for the last condition: that `id' is not a + * MEMORY ccache, which is what's used for delegated credentials. + * + * We really only want to do this when storing a credential in a user's + * default ccache, but we leave it to krb5_kx509() to do that check. + * + * XXX Perhaps we should do what krb5_kx509() does here, and just call + * krb5_kx509_ext() (renamed to krb5_kx509()). Then we wouldn't need + * the delegated cred handle heuristic. + */ + if (id->cc_initialized && id->cc_start_tgt_stored && !id->cc_kx509_done && + strcmp("MEMORY", krb5_cc_get_type(context, id)) != 0) { + krb5_boolean enabled; + + krb5_appdefault_boolean(context, NULL, NULL, "enable_kx509", FALSE, + &enabled); + if (enabled) { + _krb5_debug(context, 2, "attempting to fetch a certificate using " + "kx509"); + ret = krb5_kx509(context, id, NULL); + if (ret) + _krb5_debug(context, 2, "failed to fetch a certificate"); + else + _krb5_debug(context, 2, "fetched a certificate"); + } + } + + ret = (*id->ops->close)(context, id); + free(id); + return ret; +} + +/** + * Store `creds' in the ccache `id'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_data realm; + const char *cfg = ""; + + /* Automatic cc_config-setting and other actions */ + if (krb5_principal_get_num_comp(context, creds->server) > 1 && + krb5_is_config_principal(context, creds->server)) + cfg = krb5_principal_get_comp_string(context, creds->server, 1); + + if (id->cc_initialized && !id->cc_need_start_realm && + strcmp(cfg, "start_realm") == 0) + return 0; + + ret = (*id->ops->store)(context, id, creds); + if (ret) + return ret; + + if (id->cc_initialized && !id->cc_start_tgt_stored && + id->cc_need_start_realm && + krb5_principal_is_root_krbtgt(context, creds->server)) { + /* Mark the first root TGT's realm as the start realm */ + id->cc_start_tgt_stored = 1; + realm.length = strlen(creds->server->realm); + realm.data = creds->server->realm; + (void) krb5_cc_set_config(context, id, NULL, "start_realm", &realm); + id->cc_need_start_realm = 0; + } else if (id->cc_initialized && id->cc_start_tgt_stored && + !id->cc_kx509_done && strcmp(cfg, "kx509cert") == 0) { + /* + * Do not attempt kx509 at cc close time -- we're copying a ccache and + * we've already got a cert (and private key). + */ + id->cc_kx509_done = 1; + } else if (id->cc_initialized && id->cc_start_tgt_stored && + !id->cc_kx509_done && strcmp(cfg, "kx509_service_status") == 0) { + /* + * Do not attempt kx509 at cc close time -- we're copying a ccache and + * we know the kx509 service is not available. + */ + id->cc_kx509_done = 1; + } else if (id->cc_initialized && strcmp(cfg, "start_realm") == 0) { + /* + * If the caller is storing a start_realm ccconfig, then stop looking + * for root TGTs to mark as the start_realm. + * + * By honoring any start_realm cc config stored, we interop both, with + * ccache implementations that don't preserve insertion order, and + * Kerberos implementations that store this cc config before the TGT. + */ + id->cc_need_start_realm = 0; + } + return ret; +} + +/** + * Retrieve the credential identified by `mcreds' (and `whichfields') + * from `id' in `creds'. 'creds' must be free by the caller using + * krb5_free_cred_contents. + * + * @param context A Kerberos 5 context + * @param id a Kerberos 5 credential cache + * @param whichfields what fields to use for matching credentials, same + * flags as whichfields in krb5_compare_creds() + * @param mcreds template credential to use for comparing + * @param creds returned credential, free with krb5_free_cred_contents() + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_retrieve_cred(krb5_context context, + krb5_ccache id, + krb5_flags whichfields, + const krb5_creds *mcreds, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_cc_cursor cursor; + + if (id->ops->retrieve != NULL) { + return (*id->ops->retrieve)(context, id, whichfields, + mcreds, creds); + } + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + return ret; + while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ + if(krb5_compare_creds(context, whichfields, mcreds, creds)){ + ret = 0; + break; + } + krb5_free_cred_contents (context, creds); + } + krb5_cc_end_seq_get(context, id, &cursor); + return ret; +} + +/** + * Return the principal of `id' in `principal'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + return (*id->ops->get_princ)(context, id, principal); +} + +/** + * Start iterating over `id', `cursor' is initialized to the + * beginning. Caller must free the cursor with krb5_cc_end_seq_get(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_start_seq_get (krb5_context context, + const krb5_ccache id, + krb5_cc_cursor *cursor) +{ + return (*id->ops->get_first)(context, id, cursor); +} + +/** + * Retrieve the next cred pointed to by (`id', `cursor') in `creds' + * and advance `cursor'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_next_cred (krb5_context context, + const krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + return (*id->ops->get_next)(context, id, cursor, creds); +} + +/** + * Destroy the cursor `cursor'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_end_seq_get (krb5_context context, + const krb5_ccache id, + krb5_cc_cursor *cursor) +{ + return (*id->ops->end_get)(context, id, cursor); +} + +/** + * Remove the credential identified by `cred', `which' from `id'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *cred) +{ + if(id->ops->remove_cred == NULL) { + krb5_set_error_message(context, + EACCES, + "ccache %s does not support remove_cred", + id->ops->prefix); + return EACCES; /* XXX */ + } + return (*id->ops->remove_cred)(context, id, which, cred); +} + +/** + * Set the flags of `id' to `flags'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + return (*id->ops->set_flags)(context, id, flags); +} + +/** + * Get the flags of `id', store them in `flags'. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_flags(krb5_context context, + krb5_ccache id, + krb5_flags *flags) +{ + *flags = 0; + return 0; +} + +/** + * Copy the contents of `from' to `to' if the given match function + * return true. + * + * @param context A Kerberos 5 context. + * @param from the cache to copy data from. + * @param to the cache to copy data to. + * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied. + * @param matchctx context passed to match function. + * @param matched set to true if there was a credential that matched, may be NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_copy_match_f(krb5_context context, + const krb5_ccache from, + krb5_ccache to, + krb5_boolean (*match)(krb5_context, void *, const krb5_creds *), + void *matchctx, + unsigned int *matched) +{ + krb5_error_code ret; + krb5_cc_cursor cursor; + krb5_creds cred; + krb5_principal princ; + + if (matched) + *matched = 0; + + ret = krb5_cc_get_principal(context, from, &princ); + if (ret) + return ret; + ret = krb5_cc_initialize(context, to, princ); + if (ret) { + krb5_free_principal(context, princ); + return ret; + } + ret = krb5_cc_start_seq_get(context, from, &cursor); + if (ret) { + krb5_free_principal(context, princ); + return ret; + } + + while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) { + if (match == NULL || (*match)(context, matchctx, &cred)) { + if (matched) + (*matched)++; + ret = krb5_cc_store_cred(context, to, &cred); + if (ret) + break; + } + krb5_free_cred_contents(context, &cred); + } + krb5_cc_end_seq_get(context, from, &cursor); + krb5_free_principal(context, princ); + if (ret == KRB5_CC_END) + ret = 0; + return ret; +} + +/** + * Just like krb5_cc_copy_match_f(), but copy everything. + * + * @ingroup @krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_copy_cache(krb5_context context, + const krb5_ccache from, + krb5_ccache to) +{ + return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL); +} + +/** + * Return the version of `id'. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_version(krb5_context context, + const krb5_ccache id) +{ + if(id->ops->get_version) + return (*id->ops->get_version)(context, id); + else + return 0; +} + +/** + * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_cc_clear_mcred(krb5_creds *mcred) +{ + memset(mcred, 0, sizeof(*mcred)); +} + +/** + * Get the cc ops that is registered in `context' to handle the + * prefix. prefix can be a complete credential cache name or a + * prefix, the function will only use part up to the first colon (:) + * if there is one. If prefix the argument is NULL, the default ccache + * implemtation is returned. + * + * @return Returns NULL if ops not found. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL +krb5_cc_get_prefix_ops(krb5_context context, const char *prefix) +{ + return cc_get_prefix_ops(context, prefix, NULL); +} + +/** + * Get the cc ops that is registered in `context' to handle the + * prefix. prefix can be a complete credential cache name or a + * prefix, the function will only use part up to the first colon (:) + * if there is one. If prefix the argument is NULL, the default ccache + * implementation is returned. + * + * If residual is non-NULL, it is set to the residual component of + * prefix (if present) or the prefix itself. + * + * @return Returns NULL if ops not found. + * + * @ingroup krb5_ccache + */ + + +static const krb5_cc_ops * +cc_get_prefix_ops(krb5_context context, + const char *prefix, + const char **residual) +{ + int i; + + if (residual) + *residual = prefix; + + if (prefix == NULL) + return KRB5_DEFAULT_CCTYPE; + + /* Is absolute path? Or UNC path? */ + if (ISPATHSEP(prefix[0])) + return &krb5_fcc_ops; + +#ifdef _WIN32 + /* Is drive letter? */ + if (isalpha((unsigned char)prefix[0]) && prefix[1] == ':') + return &krb5_fcc_ops; +#endif + + for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { + size_t prefix_len = strlen(context->cc_ops[i]->prefix); + + if (strncmp(context->cc_ops[i]->prefix, prefix, prefix_len) == 0 && + (prefix[prefix_len] == ':' || prefix[prefix_len] == '\0')) { + if (residual) { + if (prefix[prefix_len] == ':' && prefix[prefix_len + 1] != '\0') + *residual = &prefix[prefix_len + 1]; + else + *residual = NULL; + } + + return context->cc_ops[i]; + } + } + + return NULL; +} + +struct krb5_cc_cache_cursor_data { + const krb5_cc_ops *ops; + krb5_cc_cursor cursor; +}; + +/** + * Start iterating over all caches of specified type. See also + * krb5_cccol_cursor_new(). + + * @param context A Kerberos 5 context + * @param type optional type to iterate over, if NULL, the default cache is used. + * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_cache_get_first (krb5_context context, + const char *type, + krb5_cc_cache_cursor *cursor) +{ + const krb5_cc_ops *ops; + krb5_error_code ret; + + if (type == NULL) + type = krb5_cc_default_name(context); + + ops = krb5_cc_get_prefix_ops(context, type); + if (ops == NULL) { + krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, + "Unknown type \"%s\" when iterating " + "trying to iterate the credential caches", type); + return KRB5_CC_UNKNOWN_TYPE; + } + + if (ops->get_cache_first == NULL) { + krb5_set_error_message(context, KRB5_CC_NOSUPP, + N_("Credential cache type %s doesn't support " + "iterations over caches", "type"), + ops->prefix); + return KRB5_CC_NOSUPP; + } + + *cursor = calloc(1, sizeof(**cursor)); + if (*cursor == NULL) + return krb5_enomem(context); + + (*cursor)->ops = ops; + + ret = ops->get_cache_first(context, &(*cursor)->cursor); + if (ret) { + free(*cursor); + *cursor = NULL; + } + return ret; +} + +/** + * Retrieve the next cache pointed to by (`cursor') in `id' + * and advance `cursor'. + * + * @param context A Kerberos 5 context + * @param cursor the iterator cursor, returned by krb5_cc_cache_get_first() + * @param id next ccache + * + * @return Return 0 or an error code. Returns KRB5_CC_END when the end + * of caches is reached, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_cache_next (krb5_context context, + krb5_cc_cache_cursor cursor, + krb5_ccache *id) +{ + return cursor->ops->get_cache_next(context, cursor->cursor, id); +} + +/** + * Destroy the cursor `cursor'. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_cache_end_seq_get (krb5_context context, + krb5_cc_cache_cursor cursor) +{ + krb5_error_code ret; + ret = cursor->ops->end_cache_get(context, cursor->cursor); + cursor->ops = NULL; + free(cursor); + return ret; +} + +/** + * Search for a matching credential cache that have the + * `principal' as the default principal. On success, `id' needs to be + * freed with krb5_cc_close() or krb5_cc_destroy(). + * + * @param context A Kerberos 5 context + * @param client The principal to search for + * @param id the returned credential cache + * + * @return On failure, error code is returned and `id' is set to NULL. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_cache_match (krb5_context context, + krb5_principal client, + krb5_ccache *id) +{ + krb5_cccol_cursor cursor; + krb5_error_code ret; + krb5_ccache cache = NULL; + krb5_ccache expired_match = NULL; + + *id = NULL; + + ret = krb5_cccol_cursor_new (context, &cursor); + if (ret) + return ret; + + while (krb5_cccol_cursor_next(context, cursor, &cache) == 0 && cache != NULL) { + krb5_principal principal; + krb5_boolean match; + time_t lifetime; + + ret = krb5_cc_get_principal(context, cache, &principal); + if (ret) + goto next; + + if (client->name.name_string.len == 0) + match = (strcmp(client->realm, principal->realm) == 0); + else + match = krb5_principal_compare(context, principal, client); + krb5_free_principal(context, principal); + + if (!match) + goto next; + + if (expired_match == NULL && + (krb5_cc_get_lifetime(context, cache, &lifetime) != 0 || lifetime == 0)) { + expired_match = cache; + cache = NULL; + goto next; + } + break; + + next: + if (cache) + krb5_cc_close(context, cache); + cache = NULL; + } + + krb5_cccol_cursor_free(context, &cursor); + + if (cache == NULL && expired_match) { + cache = expired_match; + expired_match = NULL; + } else if (expired_match) { + krb5_cc_close(context, expired_match); + } else if (cache == NULL) { + char *str; + + (void) krb5_unparse_name(context, client, &str); + krb5_set_error_message(context, KRB5_CC_NOTFOUND, + N_("Principal %s not found in any " + "credential cache", ""), + str ? str : ""); + if (str) + free(str); + return KRB5_CC_NOTFOUND; + } + + *id = cache; + + return 0; +} + +/** + * Move the content from one credential cache to another. The + * operation is an atomic switch. + * + * @param context a Kerberos context + * @param from the credential cache to move the content from + * @param to the credential cache to move the content to + + * @return On sucess, from is destroyed and closed. On failure, error code is + * returned and from and to are both still allocated; see + * krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code ret = ENOTSUP; + krb5_principal princ = NULL; + + if (to->ops->move && + strcmp(from->ops->prefix, to->ops->prefix) == 0) { + /* + * NOTE: to->ops->move() is expected to call + * krb5_cc_destroy(context, from) on success. + */ + ret = (*to->ops->move)(context, from, to); + if (ret == 0) + return 0; + if (ret != EXDEV && ret != ENOTSUP && ret != KRB5_CC_NOSUPP && + ret != KRB5_FCC_INTERNAL) + return ret; + /* Fallback to high-level copy */ + } /* Else high-level copy */ + + /* + * Initialize destination, copy the source's contents to the destination, + * then destroy the source on success. + * + * It'd be nice if we could destroy any half-built destination if the copy + * fails, but the interface is not documented as doing so. + */ + ret = krb5_cc_get_principal(context, from, &princ); + if (ret == 0) + ret = krb5_cc_initialize(context, to, princ); + krb5_free_principal(context, princ); + if (ret == 0) + ret = krb5_cc_copy_cache(context, from, to); + if (ret == 0) + krb5_cc_destroy(context, from); + return ret; +} + +#define KRB5_CONF_NAME "krb5_ccache_conf_data" +#define KRB5_REALM_NAME "X-CACHECONF:" + +static krb5_error_code +build_conf_principals(krb5_context context, krb5_ccache id, + krb5_const_principal principal, + const char *name, krb5_creds *cred) +{ + krb5_principal client; + krb5_error_code ret; + char *pname = NULL; + + memset(cred, 0, sizeof(*cred)); + + ret = krb5_cc_get_principal(context, id, &client); + if (ret) + return ret; + + if (principal) { + ret = krb5_unparse_name(context, principal, &pname); + if (ret) + return ret; + } + + ret = krb5_make_principal(context, &cred->server, + KRB5_REALM_NAME, + KRB5_CONF_NAME, name, pname, NULL); + free(pname); + if (ret) { + krb5_free_principal(context, client); + return ret; + } + ret = krb5_copy_principal(context, client, &cred->client); + krb5_free_principal(context, client); + return ret; +} + +/** + * Return TRUE (non zero) if the principal is a configuration + * principal (generated part of krb5_cc_set_config()). Returns FALSE + * (zero) if not a configuration principal. + * + * @param context a Kerberos context + * @param principal principal to check if it a configuration principal + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_is_config_principal(krb5_context context, + krb5_const_principal principal) +{ + if (strcmp(principal->realm, KRB5_REALM_NAME) != 0) + return FALSE; + + if (principal->name.name_string.len == 0 || + strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0) + return FALSE; + + return TRUE; +} + +/** + * Store some configuration for the credential cache in the cache. + * Existing configuration under the same name is over-written. + * + * @param context a Kerberos context + * @param id the credential cache to store the data for + * @param principal configuration for a specific principal, if + * NULL, global for the whole cache. + * @param name name under which the configuraion is stored. + * @param data data to store, if NULL, configure is removed. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_set_config(krb5_context context, krb5_ccache id, + krb5_const_principal principal, + const char *name, krb5_data *data) +{ + krb5_error_code ret; + krb5_creds cred; + + ret = build_conf_principals(context, id, principal, name, &cred); + if (ret) + goto out; + + /* Remove old configuration */ + ret = krb5_cc_remove_cred(context, id, 0, &cred); + if (ret && ret != KRB5_CC_NOTFOUND && ret != KRB5_CC_NOSUPP && + ret != KRB5_FCC_INTERNAL) + goto out; + + if (data) { + /* not that anyone care when this expire */ + cred.times.authtime = time(NULL); + cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; + + ret = krb5_data_copy(&cred.ticket, data->data, data->length); + if (ret) + goto out; + + ret = krb5_cc_store_cred(context, id, &cred); + } + +out: + krb5_free_cred_contents (context, &cred); + return ret; +} + +/** + * Get some configuration for the credential cache in the cache. + * + * @param context a Kerberos context + * @param id the credential cache to store the data for + * @param principal configuration for a specific principal, if + * NULL, global for the whole cache. + * @param name name under which the configuraion is stored. + * @param data data to fetched, free with krb5_data_free() + * @return 0 on success, KRB5_CC_NOTFOUND or KRB5_CC_END if not found, + * or other system error. + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_config(krb5_context context, krb5_ccache id, + krb5_const_principal principal, + const char *name, krb5_data *data) +{ + krb5_creds mcred, cred; + krb5_error_code ret; + + memset(&cred, 0, sizeof(cred)); + krb5_data_zero(data); + + ret = build_conf_principals(context, id, principal, name, &mcred); + if (ret) + goto out; + + ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred); + if (ret) + goto out; + + ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length); + +out: + krb5_free_cred_contents (context, &cred); + krb5_free_cred_contents (context, &mcred); + return ret; +} + +/* + * + */ + +struct krb5_cccol_cursor_data { + int idx; + krb5_cc_cache_cursor cursor; +}; + +/** + * Get a new cache interation cursor that will interate over all + * credentials caches independent of type. + * + * @param context a Kerberos context + * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free(). + * + * @return Returns 0 or and error code, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor) +{ + *cursor = calloc(1, sizeof(**cursor)); + if (*cursor == NULL) + return krb5_enomem(context); + (*cursor)->idx = 0; + (*cursor)->cursor = NULL; + + return 0; +} + +/** + * Get next credential cache from the iteration. + * + * @param context A Kerberos 5 context + * @param cursor the iteration cursor + * @param cache the returned cursor, pointer is set to NULL on failure + * and a cache on success. The returned cache needs to be freed + * with krb5_cc_close() or destroyed with krb5_cc_destroy(). + * MIT Kerberos behavies slightly diffrent and sets cache to NULL + * when all caches are iterated over and return 0. + * + * @return Return 0 or and error, KRB5_CC_END is returned at the end + * of iteration. See krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor, + krb5_ccache *cache) +{ + krb5_error_code ret = 0; + + *cache = NULL; + + while (cursor->idx < context->num_cc_ops) { + + if (cursor->cursor == NULL) { + ret = krb5_cc_cache_get_first (context, + context->cc_ops[cursor->idx]->prefix, + &cursor->cursor); + if (ret) { + cursor->idx++; + continue; + } + } + ret = krb5_cc_cache_next(context, cursor->cursor, cache); + if (ret == 0) + break; + + krb5_cc_cache_end_seq_get(context, cursor->cursor); + cursor->cursor = NULL; + if (ret != KRB5_CC_END) + break; + + cursor->idx++; + } + if (cursor->idx >= context->num_cc_ops) { + krb5_set_error_message(context, KRB5_CC_END, + N_("Reached end of credential caches", "")); + return KRB5_CC_END; + } + + return ret; +} + +/** + * End an iteration and free all resources, can be done before end is reached. + * + * @param context A Kerberos 5 context + * @param cursor the iteration cursor to be freed. + * + * @return Return 0 or and error, KRB5_CC_END is returned at the end + * of iteration. See krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor) +{ + krb5_cccol_cursor c = *cursor; + + *cursor = NULL; + if (c) { + if (c->cursor) + krb5_cc_cache_end_seq_get(context, c->cursor); + free(c); + } + return 0; +} + +/** + * Return the last time the credential cache was modified. + * + * @param context A Kerberos 5 context + * @param id The credential cache to probe + * @param mtime the last modification time, set to 0 on error. + + * @return Return 0 or and error. See krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_last_change_time(krb5_context context, + krb5_ccache id, + krb5_timestamp *mtime) +{ + *mtime = 0; + + if (id->ops->version < KRB5_CC_OPS_VERSION_2 + || id->ops->lastchange == NULL) + return KRB5_CC_NOSUPP; + + return (*id->ops->lastchange)(context, id, mtime); +} + +/** + * Return the last modfication time for a cache collection. The query + * can be limited to a specific cache type. If the function return 0 + * and mtime is 0, there was no credentials in the caches. + * + * @param context A Kerberos 5 context + * @param type The credential cache to probe, if NULL, all type are traversed. + * @param mtime the last modification time, set to 0 on error. + + * @return Return 0 or and error. See krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cccol_last_change_time(krb5_context context, + const char *type, + krb5_timestamp *mtime) +{ + krb5_cccol_cursor cursor; + krb5_error_code ret; + krb5_ccache id; + krb5_timestamp t = 0; + + *mtime = 0; + + ret = krb5_cccol_cursor_new (context, &cursor); + if (ret) + return ret; + + while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { + + if (type && strcmp(krb5_cc_get_type(context, id), type) != 0) + continue; + + ret = krb5_cc_last_change_time(context, id, &t); + krb5_cc_close(context, id); + if (ret) + continue; + if (t > *mtime) + *mtime = t; + } + + krb5_cccol_cursor_free(context, &cursor); + + return 0; +} +/** + * Return a friendly name on credential cache. Free the result with krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_friendly_name(krb5_context context, + krb5_ccache id, + char **name) +{ + krb5_error_code ret; + krb5_data data; + + ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data); + if (ret) { + krb5_principal principal; + ret = krb5_cc_get_principal(context, id, &principal); + if (ret) + return ret; + ret = krb5_unparse_name(context, principal, name); + krb5_free_principal(context, principal); + } else { + ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data); + krb5_data_free(&data); + if (ret <= 0) + ret = krb5_enomem(context); + else + ret = 0; + } + + return ret; +} + +/** + * Set the friendly name on credential cache. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_set_friendly_name(krb5_context context, + krb5_ccache id, + const char *name) +{ + krb5_data data; + + data.data = rk_UNCONST(name); + data.length = strlen(name); + + return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data); +} + +/** + * Get the lifetime of the initial ticket in the cache + * + * Get the lifetime of the initial ticket in the cache, if the initial + * ticket was not found, the error code KRB5_CC_END is returned. + * + * @param context A Kerberos 5 context. + * @param id a credential cache + * @param t the relative lifetime of the initial ticket + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) +{ + krb5_data config_start_realm; + char *start_realm; + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_creds cred; + time_t now, endtime = 0; + + *t = 0; + krb5_timeofday(context, &now); + + ret = krb5_cc_get_config(context, id, NULL, "start_realm", &config_start_realm); + if (ret == 0) { + start_realm = strndup(config_start_realm.data, config_start_realm.length); + krb5_data_free(&config_start_realm); + } else { + krb5_principal client; + + ret = krb5_cc_get_principal(context, id, &client); + if (ret) + return ret; + start_realm = strdup(krb5_principal_get_realm(context, client)); + krb5_free_principal(context, client); + } + if (start_realm == NULL) + return krb5_enomem(context); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) { + free(start_realm); + return ret; + } + + while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) { + /** + * If we find the start krbtgt in the cache, use that as the lifespan. + */ + if (krb5_principal_is_root_krbtgt(context, cred.server) && + strcmp(cred.server->realm, start_realm) == 0) { + if (now < cred.times.endtime) + endtime = cred.times.endtime; + krb5_free_cred_contents(context, &cred); + break; + } + /* + * Skip config entries + */ + if (krb5_is_config_principal(context, cred.server)) { + krb5_free_cred_contents(context, &cred); + continue; + } + /** + * If there was no krbtgt, use the shortest lifetime of + * service tickets that have yet to expire. If all + * credentials are expired, krb5_cc_get_lifetime() will fail. + */ + if ((endtime == 0 || cred.times.endtime < endtime) && now < cred.times.endtime) + endtime = cred.times.endtime; + krb5_free_cred_contents(context, &cred); + } + free(start_realm); + + /* if we found an endtime use that */ + if (endtime) { + *t = endtime - now; + ret = 0; + } + + krb5_cc_end_seq_get(context, id, &cursor); + + return ret; +} + +/** + * Set the time offset betwen the client and the KDC + * + * If the backend doesn't support KDC offset, use the context global setting. + * + * @param context A Kerberos 5 context. + * @param id a credential cache + * @param offset the offset in seconds + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset) +{ + if (id->ops->version < KRB5_CC_OPS_VERSION_3 + || id->ops->set_kdc_offset == NULL) { + context->kdc_sec_offset = offset; + context->kdc_usec_offset = 0; + return 0; + } + return (*id->ops->set_kdc_offset)(context, id, offset); +} + +/** + * Get the time offset betwen the client and the KDC + * + * If the backend doesn't support KDC offset, use the context global setting. + * + * @param context A Kerberos 5 context. + * @param id a credential cache + * @param offset the offset in seconds + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset) +{ + if (id->ops->version < KRB5_CC_OPS_VERSION_3 + || id->ops->get_kdc_offset == NULL) { + *offset = context->kdc_sec_offset; + return 0; + } + return (*id->ops->get_kdc_offset)(context, id, offset); +} + +#ifdef _WIN32 +#define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5" + +static char * +_get_default_cc_name_from_registry(krb5_context context, HKEY hkBase) +{ + HKEY hk_k5 = 0; + LONG code; + char *ccname = NULL; + + code = RegOpenKeyEx(hkBase, + REGPATH_MIT_KRB5, + 0, KEY_READ, &hk_k5); + + if (code != ERROR_SUCCESS) + return NULL; + + ccname = heim_parse_reg_value_as_string(context->hcontext, hk_k5, "ccname", + REG_NONE, 0); + + RegCloseKey(hk_k5); + + return ccname; +} + +KRB5_LIB_FUNCTION char * KRB5_LIB_CALL +_krb5_get_default_cc_name_from_registry(krb5_context context) +{ + char *ccname; + + ccname = _get_default_cc_name_from_registry(context, HKEY_CURRENT_USER); + if (ccname == NULL) + ccname = _get_default_cc_name_from_registry(context, + HKEY_LOCAL_MACHINE); + + return ccname; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +_krb5_set_default_cc_name_to_registry(krb5_context context, krb5_ccache id) +{ + HKEY hk_k5 = 0; + LONG code; + int ret = -1; + char * ccname = NULL; + + code = RegOpenKeyEx(HKEY_CURRENT_USER, + REGPATH_MIT_KRB5, + 0, KEY_READ|KEY_WRITE, &hk_k5); + + if (code != ERROR_SUCCESS) + return -1; + + ret = asprintf(&ccname, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id)); + if (ret < 0) + goto cleanup; + + ret = heim_store_string_to_reg_value(context->hcontext, hk_k5, "ccname", + REG_SZ, ccname, -1, 0); + + cleanup: + + if (ccname) + free(ccname); + + RegCloseKey(hk_k5); + + return ret; +} +#endif diff --git a/third_party/heimdal/lib/krb5/ccache_plugin.h b/third_party/heimdal/lib/krb5/ccache_plugin.h new file mode 100644 index 0000000..e0fda4c --- /dev/null +++ b/third_party/heimdal/lib/krb5/ccache_plugin.h @@ -0,0 +1,46 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#ifndef HEIMDAL_KRB5_CCACHE_PLUGIN_H +#define HEIMDAL_KRB5_CCACHE_PLUGIN_H 1 + +#include +#include + +#define KRB5_PLUGIN_CCACHE "ccache_ops" + +krb5_error_code KRB5_CALLCONV +ccache_ops_plugin_load(krb5_context context, + krb5_get_instance_func_t *func, + size_t *n_ftables, + heim_plugin_common_ftable_p **ftables); + +#endif /* HEIMDAL_KRB5_CCACHE_PLUGIN_H */ diff --git a/third_party/heimdal/lib/krb5/changepw.c b/third_party/heimdal/lib/krb5/changepw.c new file mode 100644 index 0000000..22a1f40 --- /dev/null +++ b/third_party/heimdal/lib/krb5/changepw.c @@ -0,0 +1,860 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#undef __attribute__ +#define __attribute__(X) + + +static void +str2data (krb5_data *d, + const char *fmt, + ...) __attribute__ ((__format__ (__printf__, 2, 3))); + +static void +str2data (krb5_data *d, + const char *fmt, + ...) +{ + va_list args; + char *str; + + va_start(args, fmt); + d->length = vasprintf (&str, fmt, args); + va_end(args); + d->data = str; +} + +/* + * Change password protocol defined by + * draft-ietf-cat-kerb-chg-password-02.txt + * + * Share the response part of the protocol with MS set password + * (RFC3244) + */ + +static krb5_error_code +chgpw_send_request (krb5_context context, + krb5_auth_context *auth_context, + krb5_creds *creds, + krb5_principal targprinc, + int is_stream, + rk_socket_t sock, + const char *passwd, + const char *host) +{ + krb5_error_code ret; + krb5_data ap_req_data; + krb5_data krb_priv_data; + krb5_data passwd_data; + size_t len; + u_char header[6]; + struct iovec iov[3]; + struct msghdr msghdr; + + if (is_stream) + return KRB5_KPASSWD_MALFORMED; + + if (targprinc && + krb5_principal_compare(context, creds->client, targprinc) != TRUE) + return KRB5_KPASSWD_MALFORMED; + + krb5_data_zero (&ap_req_data); + + ret = krb5_mk_req_extended (context, + auth_context, + AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, + NULL, /* in_data */ + creds, + &ap_req_data); + if (ret) + return ret; + + passwd_data.data = rk_UNCONST(passwd); + passwd_data.length = strlen(passwd); + + krb5_data_zero (&krb_priv_data); + + ret = krb5_mk_priv (context, + *auth_context, + &passwd_data, + &krb_priv_data, + NULL); + if (ret) + goto out2; + + len = 6 + ap_req_data.length + krb_priv_data.length; + header[0] = (len >> 8) & 0xFF; + header[1] = (len >> 0) & 0xFF; + header[2] = 0; + header[3] = 1; + header[4] = (ap_req_data.length >> 8) & 0xFF; + header[5] = (ap_req_data.length >> 0) & 0xFF; + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); +#if 0 + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; +#endif + + iov[0].iov_base = (void*)header; + iov[0].iov_len = 6; + iov[1].iov_base = ap_req_data.data; + iov[1].iov_len = ap_req_data.length; + iov[2].iov_base = krb_priv_data.data; + iov[2].iov_len = krb_priv_data.length; + + if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) { + ret = rk_SOCK_ERRNO; + krb5_set_error_message(context, ret, "sendmsg %s: %s", + host, strerror(ret)); + } + + krb5_data_free (&krb_priv_data); +out2: + krb5_data_free (&ap_req_data); + return ret; +} + +/* + * Set password protocol as defined by RFC3244 -- + * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols + */ + +static krb5_error_code +setpw_send_request (krb5_context context, + krb5_auth_context *auth_context, + krb5_creds *creds, + krb5_principal targprinc, + int is_stream, + rk_socket_t sock, + const char *passwd, + const char *host) +{ + krb5_error_code ret; + krb5_data ap_req_data; + krb5_data krb_priv_data; + krb5_data pwd_data; + ChangePasswdDataMS chpw; + size_t len = 0; + u_char header[4 + 6]; + u_char *p; + struct iovec iov[3]; + struct msghdr msghdr; + + krb5_data_zero (&ap_req_data); + + ret = krb5_mk_req_extended (context, + auth_context, + AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, + NULL, /* in_data */ + creds, + &ap_req_data); + if (ret) + return ret; + + chpw.newpasswd.length = strlen(passwd); + chpw.newpasswd.data = rk_UNCONST(passwd); + if (targprinc) { + chpw.targname = &targprinc->name; + chpw.targrealm = &targprinc->realm; + } else { + chpw.targname = NULL; + chpw.targrealm = NULL; + } + + ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length, + &chpw, &len, ret); + if (ret) { + krb5_data_free (&ap_req_data); + return ret; + } + + if(pwd_data.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_mk_priv (context, + *auth_context, + &pwd_data, + &krb_priv_data, + NULL); + if (ret) + goto out2; + + len = 6 + ap_req_data.length + krb_priv_data.length; + p = header; + if (is_stream) { + _krb5_put_int(p, len, 4); + p += 4; + } + *p++ = (len >> 8) & 0xFF; + *p++ = (len >> 0) & 0xFF; + *p++ = 0xff; + *p++ = 0x80; + *p++ = (ap_req_data.length >> 8) & 0xFF; + *p = (ap_req_data.length >> 0) & 0xFF; + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); +#if 0 + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; +#endif + + iov[0].iov_base = (void*)header; + if (is_stream) + iov[0].iov_len = 10; + else + iov[0].iov_len = 6; + iov[1].iov_base = ap_req_data.data; + iov[1].iov_len = ap_req_data.length; + iov[2].iov_base = krb_priv_data.data; + iov[2].iov_len = krb_priv_data.length; + + if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) { + ret = rk_SOCK_ERRNO; + krb5_set_error_message(context, ret, "sendmsg %s: %s", + host, strerror(ret)); + } + + krb5_data_free (&krb_priv_data); +out2: + krb5_data_free (&ap_req_data); + krb5_data_free (&pwd_data); + return ret; +} + +static krb5_error_code +process_reply (krb5_context context, + krb5_auth_context auth_context, + int is_stream, + rk_socket_t sock, + int *result_code, + krb5_data *result_code_string, + krb5_data *result_string, + const char *host) +{ + krb5_error_code ret; + u_char reply[1024 * 3]; + size_t len; + uint16_t pkt_len, pkt_ver; + krb5_data ap_rep_data; + int save_errno; + + len = 0; + if (is_stream) { + while (len < sizeof(reply)) { + unsigned long size; + + ret = recvfrom (sock, reply + len, sizeof(reply) - len, + 0, NULL, NULL); + if (rk_IS_SOCKET_ERROR(ret)) { + save_errno = rk_SOCK_ERRNO; + krb5_set_error_message(context, save_errno, + "recvfrom %s: %s", + host, strerror(save_errno)); + return save_errno; + } else if (ret == 0) { + krb5_set_error_message(context, 1,"recvfrom timeout %s", host); + return 1; + } + len += ret; + if (len < 4) + continue; + _krb5_get_int(reply, &size, 4); + if (size + 4 < len) + continue; + if (sizeof(reply) - 4 < size) { + krb5_set_error_message(context, ERANGE, "size from server too large %s", host); + return ERANGE; + } + memmove(reply, reply + 4, size); + len = size; + break; + } + if (len == sizeof(reply)) { + krb5_set_error_message(context, ENOMEM, + N_("Message too large from %s", "host"), + host); + return ENOMEM; + } + } else { + ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL); + if (rk_IS_SOCKET_ERROR(ret)) { + save_errno = rk_SOCK_ERRNO; + krb5_set_error_message(context, save_errno, + "recvfrom %s: %s", + host, strerror(save_errno)); + return save_errno; + } + len = ret; + } + + if (len < 6) { + str2data (result_string, "server %s sent to too short message " + "(%llu bytes)", host, (unsigned long long)len); + *result_code = KRB5_KPASSWD_MALFORMED; + return 0; + } + + pkt_len = (reply[0] << 8) | (reply[1]); + pkt_ver = (reply[2] << 8) | (reply[3]); + + if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) { + KRB_ERROR error; + size_t size; + u_char *p; + + memset(&error, 0, sizeof(error)); + + ret = decode_KRB_ERROR(reply, len, &error, &size); + if (ret) + return ret; + + if (error.e_data->length < 2) { + str2data(result_string, "server %s sent too short " + "e_data to print anything usable", host); + free_KRB_ERROR(&error); + *result_code = KRB5_KPASSWD_MALFORMED; + return 0; + } + + p = error.e_data->data; + *result_code = (p[0] << 8) | p[1]; + if (error.e_data->length == 2) + str2data(result_string, "server only sent error code"); + else + krb5_data_copy (result_string, + p + 2, + error.e_data->length - 2); + free_KRB_ERROR(&error); + return 0; + } + + if (pkt_len != len) { + str2data (result_string, "client: wrong len in reply"); + *result_code = KRB5_KPASSWD_MALFORMED; + return 0; + } + if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) { + str2data (result_string, + "client: wrong version number (%d)", pkt_ver); + *result_code = KRB5_KPASSWD_MALFORMED; + return 0; + } + + ap_rep_data.data = reply + 6; + ap_rep_data.length = (reply[4] << 8) | (reply[5]); + + if (len - 6 < ap_rep_data.length) { + str2data (result_string, "client: wrong AP len in reply"); + *result_code = KRB5_KPASSWD_MALFORMED; + return 0; + } + + if (ap_rep_data.length) { + krb5_ap_rep_enc_part *ap_rep; + krb5_data priv_data; + u_char *p; + + priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length; + priv_data.length = len - ap_rep_data.length - 6; + + ret = krb5_rd_rep (context, + auth_context, + &ap_rep_data, + &ap_rep); + if (ret) + return ret; + + krb5_free_ap_rep_enc_part (context, ap_rep); + + ret = krb5_rd_priv (context, + auth_context, + &priv_data, + result_code_string, + NULL); + if (ret) { + krb5_data_free (result_code_string); + return ret; + } + + if (result_code_string->length < 2) { + *result_code = KRB5_KPASSWD_MALFORMED; + str2data (result_string, + "client: bad length in result"); + return 0; + } + + p = result_code_string->data; + + *result_code = (p[0] << 8) | p[1]; + krb5_data_copy (result_string, + (unsigned char*)result_code_string->data + 2, + result_code_string->length - 2); + return 0; + } else { + KRB_ERROR error; + size_t size; + u_char *p; + + ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size); + if (ret) { + return ret; + } + if (error.e_data->length < 2) { + krb5_warnx (context, "too short e_data to print anything usable"); + return 1; /* XXX */ + } + + p = error.e_data->data; + *result_code = (p[0] << 8) | p[1]; + krb5_data_copy (result_string, + p + 2, + error.e_data->length - 2); + return 0; + } +} + + +/* + * change the password using the credentials in `creds' (for the + * principal indicated in them) to `newpw', storing the result of + * the operation in `result_*' and an error code or 0. + */ + +typedef krb5_error_code (*kpwd_send_request) (krb5_context, + krb5_auth_context *, + krb5_creds *, + krb5_principal, + int, + rk_socket_t, + const char *, + const char *); +typedef krb5_error_code (*kpwd_process_reply) (krb5_context, + krb5_auth_context, + int, + rk_socket_t, + int *, + krb5_data *, + krb5_data *, + const char *); + +static const struct kpwd_proc { + const char *name; + int flags; +#define SUPPORT_TCP 1 +#define SUPPORT_UDP 2 + kpwd_send_request send_req; + kpwd_process_reply process_rep; +} procs[] = { + { + "MS set password", + SUPPORT_TCP|SUPPORT_UDP, + setpw_send_request, + process_reply + }, + { + "change password", + SUPPORT_UDP, + chgpw_send_request, + process_reply + }, + { NULL, 0, NULL, NULL } +}; + +/* + * + */ + +static krb5_error_code +change_password_loop (krb5_context context, + krb5_creds *creds, + krb5_principal targprinc, + const char *newpw, + int *result_code, + krb5_data *result_code_string, + krb5_data *result_string, + const struct kpwd_proc *proc) +{ + krb5_error_code ret; + krb5_auth_context auth_context = NULL; + krb5_krbhst_handle handle = NULL; + krb5_krbhst_info *hi; + rk_socket_t sock; + unsigned int i; + int done = 0; + krb5_realm realm; + + if (targprinc) + realm = targprinc->realm; + else + realm = creds->client->realm; + + ret = krb5_auth_con_init (context, &auth_context); + if (ret) + return ret; + + krb5_auth_con_setflags (context, auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE); + + ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle); + if (ret) + goto out; + + while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) { + struct addrinfo *ai, *a; + int is_stream; + + switch (hi->proto) { + case KRB5_KRBHST_UDP: + if ((proc->flags & SUPPORT_UDP) == 0) + continue; + is_stream = 0; + break; + case KRB5_KRBHST_TCP: + if ((proc->flags & SUPPORT_TCP) == 0) + continue; + is_stream = 1; + break; + default: + continue; + } + + ret = krb5_krbhst_get_addrinfo(context, hi, &ai); + if (ret) + continue; + + for (a = ai; !done && a != NULL; a = a->ai_next) { + int replied = 0; + + sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol); + if (rk_IS_BAD_SOCKET(sock)) + continue; + rk_cloexec(sock); + + ret = connect(sock, a->ai_addr, a->ai_addrlen); + if (rk_IS_SOCKET_ERROR(ret)) { + rk_closesocket (sock); + goto out; + } + + ret = krb5_auth_con_genaddrs (context, auth_context, sock, + KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR); + if (ret) { + rk_closesocket (sock); + goto out; + } + + for (i = 0; !done && i < 5; ++i) { + fd_set fdset; + struct timeval tv; + + if (!replied) { + replied = 0; + + ret = (*proc->send_req) (context, + &auth_context, + creds, + targprinc, + is_stream, + sock, + newpw, + hi->hostname); + if (ret) { + rk_closesocket(sock); + goto out; + } + } + +#ifndef NO_LIMIT_FD_SETSIZE + if (sock >= FD_SETSIZE) { + ret = ERANGE; + krb5_set_error_message(context, ret, + "fd %d too large", sock); + rk_closesocket (sock); + goto out; + } +#endif + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + tv.tv_usec = 0; + tv.tv_sec = 1 + (1 << i); + + ret = select (sock + 1, &fdset, NULL, NULL, &tv); + if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) { + rk_closesocket(sock); + goto out; + } + if (ret == 1) { + ret = (*proc->process_rep) (context, + auth_context, + is_stream, + sock, + result_code, + result_code_string, + result_string, + hi->hostname); + if (ret == 0) + done = 1; + else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL) + replied = 1; + } else { + ret = KRB5_KDC_UNREACH; + } + } + rk_closesocket (sock); + } + } + + out: + krb5_krbhst_free (context, handle); + krb5_auth_con_free (context, auth_context); + + if (ret == KRB5_KDC_UNREACH) { + krb5_set_error_message(context, + ret, + N_("Unable to reach any changepw server " + " in realm %s", "realm"), realm); + *result_code = KRB5_KPASSWD_HARDERROR; + } + return ret; +} + +#ifndef HEIMDAL_SMALLER + +static const struct kpwd_proc * +find_chpw_proto(const char *name) +{ + const struct kpwd_proc *p; + for (p = procs; p->name != NULL; p++) { + if (strcmp(p->name, name) == 0) + return p; + } + return NULL; +} + +/** + * Deprecated: krb5_change_password() is deprecated, use krb5_set_password(). + * + * @param context a Keberos context + * @param creds + * @param newpw + * @param result_code + * @param result_code_string + * @param result_string + * + * @return On sucess password is changed. + + * @ingroup @krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_change_password (krb5_context context, + krb5_creds *creds, + const char *newpw, + int *result_code, + krb5_data *result_code_string, + krb5_data *result_string) + KRB5_DEPRECATED_FUNCTION("Use krb5_set_password instead") +{ + const struct kpwd_proc *p = find_chpw_proto("change password"); + + *result_code = KRB5_KPASSWD_MALFORMED; + result_code_string->data = result_string->data = NULL; + result_code_string->length = result_string->length = 0; + + if (p == NULL) + return KRB5_KPASSWD_MALFORMED; + + return change_password_loop(context, creds, NULL, newpw, + result_code, result_code_string, + result_string, p); +} +#endif /* HEIMDAL_SMALLER */ + +/** + * Change password using creds. + * + * @param context a Keberos context + * @param creds The initial kadmin/passwd for the principal or an admin principal + * @param newpw The new password to set + * @param targprinc if unset, the client principal from creds is used + * @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed. + * @param result_code_string binary message from the server, contains + * at least the result_code. + * @param result_string A message from the kpasswd service or the + * library in human printable form. The string is NUL terminated. + * + * @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed. + + * @ingroup @krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_password(krb5_context context, + krb5_creds *creds, + const char *newpw, + krb5_principal targprinc, + int *result_code, + krb5_data *result_code_string, + krb5_data *result_string) +{ + krb5_principal principal = NULL; + krb5_error_code ret = 0; + int i; + + *result_code = KRB5_KPASSWD_MALFORMED; + krb5_data_zero(result_code_string); + krb5_data_zero(result_string); + + if (targprinc == NULL) { + ret = krb5_copy_principal(context, creds->client, &principal); + if (ret) + return ret; + } else + principal = targprinc; + + for (i = 0; procs[i].name != NULL; i++) { + *result_code = 0; + ret = change_password_loop(context, creds, principal, newpw, + result_code, result_code_string, + result_string, + &procs[i]); + if (ret == 0 && *result_code == 0) + break; + } + + if (targprinc == NULL) + krb5_free_principal(context, principal); + return ret; +} + +/* + * + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_password_using_ccache(krb5_context context, + krb5_ccache ccache, + const char *newpw, + krb5_principal targprinc, + int *result_code, + krb5_data *result_code_string, + krb5_data *result_string) +{ + krb5_creds creds, *credsp; + krb5_error_code ret; + krb5_principal principal = NULL; + + *result_code = KRB5_KPASSWD_MALFORMED; + result_code_string->data = result_string->data = NULL; + result_code_string->length = result_string->length = 0; + + memset(&creds, 0, sizeof(creds)); + + if (targprinc == NULL) { + ret = krb5_cc_get_principal(context, ccache, &principal); + if (ret) + return ret; + } else + principal = targprinc; + + ret = krb5_make_principal(context, &creds.server, + krb5_principal_get_realm(context, principal), + "kadmin", "changepw", NULL); + if (ret) + goto out; + + ret = krb5_cc_get_principal(context, ccache, &creds.client); + if (ret) { + krb5_free_principal(context, creds.server); + goto out; + } + + ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); + krb5_free_principal(context, creds.server); + krb5_free_principal(context, creds.client); + if (ret) + goto out; + + ret = krb5_set_password(context, + credsp, + newpw, + principal, + result_code, + result_code_string, + result_string); + + krb5_free_creds(context, credsp); + + return ret; + out: + if (targprinc == NULL) + krb5_free_principal(context, principal); + return ret; +} + +/* + * + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_passwd_result_to_string (krb5_context context, + int result) +{ + static const char *strings[] = { + "Success", + "Malformed", + "Hard error", + "Auth error", + "Soft error" , + "Access denied", + "Bad version", + "Initial flag needed" + }; + + if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED) + return "unknown result code"; + else + return strings[result]; +} diff --git a/third_party/heimdal/lib/krb5/codec.c b/third_party/heimdal/lib/krb5/codec.c new file mode 100644 index 0000000..5e754c6 --- /dev/null +++ b/third_party/heimdal/lib/krb5/codec.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1998 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_EncTicketPart (krb5_context context, + const void *data, + size_t length, + EncTicketPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_EncTicketPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_EncTicketPart (krb5_context context, + void *data, + size_t length, + EncTicketPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_EncTicketPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_EncASRepPart (krb5_context context, + const void *data, + size_t length, + EncASRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_EncASRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_EncASRepPart (krb5_context context, + void *data, + size_t length, + EncASRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_EncASRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_EncTGSRepPart (krb5_context context, + const void *data, + size_t length, + EncTGSRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_EncTGSRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_EncTGSRepPart (krb5_context context, + void *data, + size_t length, + EncTGSRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_EncTGSRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_EncAPRepPart (krb5_context context, + const void *data, + size_t length, + EncAPRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_EncAPRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_EncAPRepPart (krb5_context context, + void *data, + size_t length, + EncAPRepPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_EncAPRepPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_Authenticator (krb5_context context, + const void *data, + size_t length, + Authenticator *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_Authenticator(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_Authenticator (krb5_context context, + void *data, + size_t length, + Authenticator *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_Authenticator(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_EncKrbCredPart (krb5_context context, + const void *data, + size_t length, + EncKrbCredPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_EncKrbCredPart(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_EncKrbCredPart (krb5_context context, + void *data, + size_t length, + EncKrbCredPart *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_EncKrbCredPart (data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_ETYPE_INFO (krb5_context context, + const void *data, + size_t length, + ETYPE_INFO *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_ETYPE_INFO(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_ETYPE_INFO (krb5_context context, + void *data, + size_t length, + ETYPE_INFO *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_ETYPE_INFO (data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decode_ETYPE_INFO2 (krb5_context context, + const void *data, + size_t length, + ETYPE_INFO2 *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return decode_ETYPE_INFO2(data, length, t, len); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encode_ETYPE_INFO2 (krb5_context context, + void *data, + size_t length, + ETYPE_INFO2 *t, + size_t *len) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return encode_ETYPE_INFO2 (data, length, t, len); +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/config_file.c b/third_party/heimdal/lib/krb5/config_file.c new file mode 100644 index 0000000..22eff10 --- /dev/null +++ b/third_party/heimdal/lib/krb5/config_file.c @@ -0,0 +1,758 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#if defined(HAVE_FRAMEWORK_COREFOUNDATION) +#include +#endif + +/** + * Parse configuration files in the given directory and add the result + * into res. Only files whose names consist only of alphanumeric + * characters, hyphen, and underscore, will be parsed, though files + * ending in ".conf" will also be parsed. + * + * This interface can be used to parse several configuration directories + * into one resulting krb5_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param dname a directory name to a Kerberos configuration file + * @param res the returned result, must be free with krb5_free_config_files(). + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_config_parse_dir_multi(krb5_context context, + const char *dname, + krb5_config_section **res) +{ + krb5_error_code ret; + heim_config_section *section = NULL; + + if (res == NULL) + return EINVAL; + + *res = NULL; + + ret = heim_config_parse_dir_multi(context->hcontext, dname, §ion); + if (ret == HEIM_ERR_CONFIG_BADFORMAT) + return KRB5_CONFIG_BADFORMAT; + if (ret) + return ret; + *res = (krb5_config_section *)section; + return 0; +} + +/** + * Parse a configuration file and add the result into res. This + * interface can be used to parse several configuration files into one + * resulting krb5_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param fname a file name to a Kerberos configuration file + * @param res the returned result, must be free with krb5_free_config_files(). + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_config_parse_file_multi(krb5_context context, + const char *fname, + krb5_config_section **res) +{ + krb5_error_code ret; + heim_config_section *section = NULL; + + if (res == NULL) + return EINVAL; + + *res = NULL; + + ret = heim_config_parse_file_multi(context->hcontext, fname, §ion); + if (ret == HEIM_ERR_CONFIG_BADFORMAT) + return KRB5_CONFIG_BADFORMAT; + if (ret) + return ret; + *res = (krb5_config_section *)section; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_config_parse_file(krb5_context context, + const char *fname, + krb5_config_section **res) +{ + return krb5_config_parse_file_multi(context, fname, res); +} + +/** + * Free configuration file section, the result of + * krb5_config_parse_file() and krb5_config_parse_file_multi(). + * + * @param context A Kerberos 5 context + * @param s the configuration section to free + * + * @return returns 0 on successes, otherwise an error code, see + * krb5_get_error_message() + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_config_file_free(krb5_context context, krb5_config_section *s) +{ + return heim_config_file_free(context->hcontext, (heim_config_section *)s); +} + +#ifndef HEIMDAL_SMALLER + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_config_copy(krb5_context context, + krb5_config_section *c, + krb5_config_section **res) +{ + krb5_error_code ret; + heim_config_section *section = NULL; + + if (res == NULL) + return EINVAL; + + *res = NULL; + ret = heim_config_copy(context->hcontext, (heim_config_section *)c, §ion); + if (ret) + return ret; + *res = (krb5_config_section *)section; + return 0; +} + +#endif /* HEIMDAL_SMALLER */ + +KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL +_krb5_config_get_next(krb5_context context, + const krb5_config_section *c, + const krb5_config_binding **pointer, + int type, + ...) +{ + const char *ret; + va_list args; + + va_start(args, type); + ret = heim_config_vget_next(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + (const heim_config_binding **)pointer, type, args); + va_end(args); + return ret; +} + +KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL +_krb5_config_vget_next(krb5_context context, + const krb5_config_section *c, + const krb5_config_binding **pointer, + int type, + va_list args) +{ + return heim_config_vget_next(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + (const heim_config_binding **)pointer, type, args); +} + +KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL +_krb5_config_get(krb5_context context, + const krb5_config_section *c, + int type, + ...) +{ + const void *ret; + va_list args; + + va_start(args, type); + ret = heim_config_vget(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + type, args); + va_end(args); + return ret; +} + + +KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL +_krb5_config_vget(krb5_context context, + const krb5_config_section *c, + int type, + va_list args) +{ + return heim_config_vget(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + type, args); +} + +/** + * Get a list of configuration binding list for more processing + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return NULL if configuration list is not found, a list otherwise + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL +krb5_config_get_list(krb5_context context, + const krb5_config_section *c, + ...) +{ + const heim_config_binding *ret; + va_list args; + + va_start(args, c); + ret = heim_config_vget_list(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + args); + va_end(args); + return (const krb5_config_binding *)ret; +} + +/** + * Get a list of configuration binding list for more processing + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return NULL if configuration list is not found, a list otherwise + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL +krb5_config_vget_list(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + const heim_config_binding *ret; + + ret = heim_config_vget_list(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + args); + return (const krb5_config_binding *)ret; +} + +/** + * Returns a "const char *" to a string in the configuration database. + * The string may not be valid after a reload of the configuration + * database so a caller should make a local copy if it needs to keep + * the string. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return NULL if configuration string not found, a string otherwise + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_config_get_string(krb5_context context, + const krb5_config_section *c, + ...) +{ + const char *ret; + va_list args; + + va_start(args, c); + ret = heim_config_vget_string(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + args); + va_end(args); + return ret; +} + +/** + * Like krb5_config_get_string(), but uses a va_list instead of ... + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return NULL if configuration string not found, a string otherwise + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_config_vget_string(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + return heim_config_vget_string(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + args); +} + +/** + * Like krb5_config_vget_string(), but instead of returning NULL, + * instead return a default value. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return a configuration string + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_config_vget_string_default(krb5_context context, + const krb5_config_section *c, + const char *def_value, + va_list args) +{ + return heim_config_vget_string_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, args); +} + +/** + * Like krb5_config_get_string(), but instead of returning NULL, + * instead return a default value. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return a configuration string + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_config_get_string_default(krb5_context context, + const krb5_config_section *c, + const char *def_value, + ...) +{ + const char *ret; + va_list args; + + va_start(args, def_value); + ret = heim_config_vget_string_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, args); + va_end(args); + return ret; +} + +/** + * Get a list of configuration strings, free the result with + * krb5_config_free_strings(). + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION char ** KRB5_LIB_CALL +krb5_config_vget_strings(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + return heim_config_vget_strings(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + args); +} + +/** + * Get a list of configuration strings, free the result with + * krb5_config_free_strings(). + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION char** KRB5_LIB_CALL +krb5_config_get_strings(krb5_context context, + const krb5_config_section *c, + ...) +{ + va_list ap; + char **ret; + va_start(ap, c); + ret = heim_config_vget_strings(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + ap); + va_end(ap); + return ret; +} + +/** + * Free the resulting strings from krb5_config-get_strings() and + * krb5_config_vget_strings(). + * + * @param strings strings to free + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_config_free_strings(char **strings) +{ + heim_config_free_strings(strings); +} + +/** + * Like krb5_config_get_bool_default() but with a va_list list of + * configuration selection. + * + * Configuration value to a boolean value, where yes/true and any + * non-zero number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_config_vget_bool_default(krb5_context context, + const krb5_config_section *c, + krb5_boolean def_value, + va_list args) +{ + return heim_config_vget_bool_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, args); +} + +/** + * krb5_config_get_bool() will convert the configuration + * option value to a boolean value, where yes/true and any non-zero + * number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_config_vget_bool(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + return heim_config_vget_bool_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + FALSE, args); +} + +/** + * krb5_config_get_bool_default() will convert the configuration + * option value to a boolean value, where yes/true and any non-zero + * number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_config_get_bool_default(krb5_context context, + const krb5_config_section *c, + krb5_boolean def_value, + ...) +{ + va_list ap; + krb5_boolean ret; + va_start(ap, def_value); + ret = heim_config_vget_bool_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, ap); + va_end(ap); + return ret; +} + +/** + * Like krb5_config_get_bool() but with a va_list list of + * configuration selection. + * + * Configuration value to a boolean value, where yes/true and any + * non-zero number means TRUE and other value is FALSE. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return TRUE or FALSE + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_config_get_bool (krb5_context context, + const krb5_config_section *c, + ...) +{ + va_list ap; + krb5_boolean ret; + va_start(ap, c); + ret = krb5_config_vget_bool (context, c, ap); + va_end(ap); + return ret; +} + +/** + * Get the time from the configuration file using a relative time. + * + * Like krb5_config_get_time_default() but with a va_list list of + * configuration selection. + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param args a va_list of arguments + * + * @return parsed the time (or def_value on parse error) + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_vget_time_default(krb5_context context, + const krb5_config_section *c, + int def_value, + va_list args) +{ + return heim_config_vget_time_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, args); +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param args a va_list of arguments + * + * @return parsed the time or -1 on error + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_vget_time(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + return heim_config_vget_time_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + -1, args); +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param def_value the default value to return if no configuration + * found in the database. + * @param ... a list of names, terminated with NULL. + * + * @return parsed the time (or def_value on parse error) + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_get_time_default(krb5_context context, + const krb5_config_section *c, + int def_value, + ...) +{ + va_list ap; + int ret; + va_start(ap, def_value); + ret = heim_config_vget_time_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, ap); + va_end(ap); + return ret; +} + +/** + * Get the time from the configuration file using a relative time, for example: 1h30s + * + * @param context A Kerberos 5 context. + * @param c a configuration section, or NULL to use the section from context + * @param ... a list of names, terminated with NULL. + * + * @return parsed the time or -1 on error + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_get_time(krb5_context context, + const krb5_config_section *c, + ...) +{ + va_list ap; + int ret; + va_start(ap, c); + ret = heim_config_vget_time(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + ap); + va_end(ap); + return ret; +} + + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_vget_int_default(krb5_context context, + const krb5_config_section *c, + int def_value, + va_list args) +{ + return heim_config_vget_int_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, args); +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_vget_int(krb5_context context, + const krb5_config_section *c, + va_list args) +{ + return heim_config_vget_int_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + -1, args); +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_get_int_default(krb5_context context, + const krb5_config_section *c, + int def_value, + ...) +{ + va_list ap; + int ret; + va_start(ap, def_value); + ret = heim_config_vget_int_default(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + def_value, ap); + va_end(ap); + return ret; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_config_get_int(krb5_context context, + const krb5_config_section *c, + ...) +{ + va_list ap; + int ret; + va_start(ap, c); + ret = heim_config_vget_int(context->hcontext, + (const heim_config_section *)(c ? c : context->cf), + ap); + va_end(ap); + return ret; +} + + +#ifndef HEIMDAL_SMALLER +/** + * Deprecated: configuration files are not strings + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_config_parse_string_multi(krb5_context context, + const char *string, + krb5_config_section **res) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_error_code ret; + heim_config_section *section = NULL; + + if (res == NULL) + return EINVAL; + + *res = NULL; + ret = heim_config_parse_string_multi(context->hcontext, string, §ion); + if (ret == HEIM_ERR_CONFIG_BADFORMAT) + return KRB5_CONFIG_BADFORMAT; + if (ret) + return ret; + *res = (krb5_config_section *)section; + return 0; +} +#endif diff --git a/third_party/heimdal/lib/krb5/constants.c b/third_party/heimdal/lib/krb5/constants.c new file mode 100644 index 0000000..43b8f54 --- /dev/null +++ b/third_party/heimdal/lib/krb5/constants.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_VARIABLE const char *const krb5_config_file = +#ifdef KRB5_DEFAULT_CONFIG_FILE +KRB5_DEFAULT_CONFIG_FILE +#else +#ifdef __APPLE__ +"~/Library/Preferences/com.apple.Kerberos.plist" PATH_SEP +"/Library/Preferences/com.apple.Kerberos.plist" PATH_SEP +"~/Library/Preferences/edu.mit.Kerberos" PATH_SEP +"/Library/Preferences/edu.mit.Kerberos" PATH_SEP +#endif /* __APPLE__ */ +"~/.krb5/config" PATH_SEP +SYSCONFDIR "/krb5.conf" PATH_SEP +#ifdef _WIN32 +"%{COMMON_APPDATA}/Kerberos/krb5.conf" PATH_SEP +"%{WINDOWS}/krb5.ini" +#else /* _WIN32 */ +"/etc/krb5.conf" +#endif /* _WIN32 */ +#endif /* KRB5_DEFAULT_CONFIG_FILE */ +; + +KRB5_LIB_VARIABLE const char *const krb5_defkeyname = KEYTAB_DEFAULT; + +KRB5_LIB_VARIABLE const char *const krb5_cc_type_api = "API"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_file = "FILE"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_memory = "MEMORY"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_kcm = "KCM"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_scc = "SCC"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_dcc = "DIR"; +KRB5_LIB_VARIABLE const char *const krb5_cc_type_keyring = "KEYRING"; diff --git a/third_party/heimdal/lib/krb5/context.c b/third_party/heimdal/lib/krb5/context.c new file mode 100644 index 0000000..9d03a80 --- /dev/null +++ b/third_party/heimdal/lib/krb5/context.c @@ -0,0 +1,1506 @@ +/* + * Copyright (c) 1997 - 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#undef KRB5_DEPRECATED_FUNCTION +#define KRB5_DEPRECATED_FUNCTION(x) + +#include "krb5_locl.h" +#include +#include + +static void _krb5_init_ets(krb5_context); + +#define INIT_FIELD(C, T, E, D, F) \ + (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ + "libdefaults", F, NULL) + +#define INIT_FLAG(C, O, V, D, F) \ + do { \ + if (krb5_config_get_bool_default((C), NULL, (D),"libdefaults", F, NULL)) { \ + (C)->O |= V; \ + } \ + } while(0) + +static krb5_error_code +copy_enctypes(krb5_context context, + const krb5_enctype *in, + krb5_enctype **out); + +/* + * Set the list of etypes `ret_etypes' from the configuration variable + * `name' + */ + +static krb5_error_code +set_etypes (krb5_context context, + const char *name, + krb5_enctype **ret_enctypes) +{ + char **etypes_str; + krb5_enctype *etypes = NULL; + + etypes_str = krb5_config_get_strings(context, NULL, "libdefaults", + name, NULL); + if(etypes_str){ + int i, j, k; + for(i = 0; etypes_str[i]; i++); + etypes = malloc((i+1) * sizeof(*etypes)); + if (etypes == NULL) { + krb5_config_free_strings (etypes_str); + return krb5_enomem(context); + } + for(j = 0, k = 0; j < i; j++) { + krb5_enctype e; + if(krb5_string_to_enctype(context, etypes_str[j], &e) != 0) + continue; + if (krb5_enctype_valid(context, e) != 0) + continue; + etypes[k++] = e; + } + etypes[k] = ETYPE_NULL; + krb5_config_free_strings(etypes_str); + } + *ret_enctypes = etypes; + return 0; +} + +/* + * read variables from the configuration file and set in `context' + */ + +static krb5_error_code +init_context_from_config_file(krb5_context context) +{ + krb5_error_code ret; + const char * tmp; + char **s; + krb5_enctype *tmptypes = NULL; + + INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); + INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout"); + INIT_FIELD(context, time, host_timeout, 3, "host_timeout"); + INIT_FIELD(context, int, max_retries, 3, "max_retries"); + + INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); + + ret = krb5_config_get_bool_default(context, NULL, FALSE, + "libdefaults", + "allow_weak_crypto", NULL); + if (ret) { + krb5_enctype_enable(context, ETYPE_DES_CBC_CRC); + krb5_enctype_enable(context, ETYPE_DES_CBC_MD4); + krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); + krb5_enctype_enable(context, ETYPE_DES_CBC_NONE); + krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE); + krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE); + } + + ret = set_etypes (context, "default_etypes", &tmptypes); + if(ret) + return ret; + free(context->etypes); + context->etypes = tmptypes; + + /* The etypes member may change during the lifetime + * of the context. To be able to reset it to + * config value, we keep another copy. + */ + free(context->cfg_etypes); + context->cfg_etypes = NULL; + if (tmptypes) { + ret = copy_enctypes(context, tmptypes, &context->cfg_etypes); + if (ret) + return ret; + } + + ret = set_etypes (context, "default_etypes_des", &tmptypes); + if(ret) + return ret; + free(context->etypes_des); + context->etypes_des = tmptypes; + + ret = set_etypes (context, "default_as_etypes", &tmptypes); + if(ret) + return ret; + free(context->as_etypes); + context->as_etypes = tmptypes; + + ret = set_etypes (context, "default_tgs_etypes", &tmptypes); + if(ret) + return ret; + free(context->tgs_etypes); + context->tgs_etypes = tmptypes; + + ret = set_etypes (context, "permitted_enctypes", &tmptypes); + if(ret) + return ret; + free(context->permitted_enctypes); + context->permitted_enctypes = tmptypes; + + INIT_FIELD(context, string, default_keytab, + KEYTAB_DEFAULT, "default_keytab_name"); + + INIT_FIELD(context, string, default_keytab_modify, + NULL, "default_keytab_modify_name"); + + INIT_FIELD(context, string, time_fmt, + "%Y-%m-%dT%H:%M:%S", "time_format"); + + INIT_FIELD(context, string, date_fmt, + "%Y-%m-%d", "date_format"); + + INIT_FIELD(context, bool, log_utc, + FALSE, "log_utc"); + + context->no_ticket_store = + getenv("KRB5_NO_TICKET_STORE") != NULL; + + /* init dns-proxy slime */ + tmp = krb5_config_get_string(context, NULL, "libdefaults", + "dns_proxy", NULL); + if(tmp) + roken_gethostby_setup(context->http_proxy, tmp); + krb5_free_host_realm (context, context->default_realms); + context->default_realms = NULL; + + { + krb5_addresses addresses; + char **adr, **a; + + krb5_set_extra_addresses(context, NULL); + adr = krb5_config_get_strings(context, NULL, + "libdefaults", + "extra_addresses", + NULL); + memset(&addresses, 0, sizeof(addresses)); + for(a = adr; a && *a; a++) { + ret = krb5_parse_address(context, *a, &addresses); + if (ret == 0) { + krb5_add_extra_addresses(context, &addresses); + krb5_free_addresses(context, &addresses); + } + } + krb5_config_free_strings(adr); + + krb5_set_ignore_addresses(context, NULL); + adr = krb5_config_get_strings(context, NULL, + "libdefaults", + "ignore_addresses", + NULL); + memset(&addresses, 0, sizeof(addresses)); + for(a = adr; a && *a; a++) { + ret = krb5_parse_address(context, *a, &addresses); + if (ret == 0) { + krb5_add_ignore_addresses(context, &addresses); + krb5_free_addresses(context, &addresses); + } + } + krb5_config_free_strings(adr); + } + + INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces"); + INIT_FIELD(context, int, fcache_vno, 0, "fcache_version"); + /* prefer dns_lookup_kdc over srv_lookup. */ + INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); + INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); + INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); + INIT_FIELD(context, int, max_msg_size, 1000 * 1024, "maximum_message_size"); + INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname"); + INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac"); + INIT_FLAG(context, flags, KRB5_CTX_F_ENFORCE_OK_AS_DELEGATE, FALSE, "enforce_ok_as_delegate"); + INIT_FLAG(context, flags, KRB5_CTX_F_REPORT_CANONICAL_CLIENT_NAME, FALSE, "report_canonical_client_name"); + + /* report_canonical_client_name implies check_pac */ + if (context->flags & KRB5_CTX_F_REPORT_CANONICAL_CLIENT_NAME) + context->flags |= KRB5_CTX_F_CHECK_PAC; + + free(context->default_cc_name); + context->default_cc_name = NULL; + context->default_cc_name_set = 0; + free(context->configured_default_cc_name); + context->configured_default_cc_name = NULL; + + tmp = secure_getenv("KRB5_TRACE"); + if (tmp) + heim_add_debug_dest(context->hcontext, "libkrb5", tmp); + s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); + if (s) { + char **p; + + for (p = s; *p; p++) + heim_add_debug_dest(context->hcontext, "libkrb5", *p); + krb5_config_free_strings(s); + } + + tmp = krb5_config_get_string(context, NULL, "libdefaults", + "check-rd-req-server", NULL); + if (tmp == NULL) + tmp = secure_getenv("KRB5_CHECK_RD_REQ_SERVER"); + if(tmp) { + if (strcasecmp(tmp, "ignore") == 0) + context->flags |= KRB5_CTX_F_RD_REQ_IGNORE; + } + ret = krb5_config_get_bool_default(context, NULL, TRUE, + "libdefaults", + "fcache_strict_checking", NULL); + if (ret) + context->flags |= KRB5_CTX_F_FCACHE_STRICT_CHECKING; + + return 0; +} + +static krb5_error_code +cc_ops_register(krb5_context context) +{ + krb5_error_code ret; + + context->cc_ops = NULL; + context->num_cc_ops = 0; + +#ifndef KCM_IS_API_CACHE + ret = krb5_cc_register(context, &krb5_acc_ops, TRUE); + if (ret) + return ret; +#endif + ret = krb5_cc_register(context, &krb5_fcc_ops, TRUE); + if (ret) + return ret; + ret = krb5_cc_register(context, &krb5_dcc_ops, TRUE); + if (ret) + return ret; + ret = krb5_cc_register(context, &krb5_mcc_ops, TRUE); + if (ret) + return ret; +#ifdef HAVE_SCC + ret = krb5_cc_register(context, &krb5_scc_ops, TRUE); + if (ret) + return ret; +#endif +#ifdef HAVE_KCM +#ifdef KCM_IS_API_CACHE + ret = krb5_cc_register(context, &krb5_akcm_ops, TRUE); + if (ret) + return ret; +#endif + ret = krb5_cc_register(context, &krb5_kcm_ops, TRUE); + if (ret) + return ret; +#endif +#if defined(HAVE_KEYUTILS_H) + ret = krb5_cc_register(context, &krb5_krcc_ops, TRUE); + if (ret) + return ret; +#endif + ret = _krb5_load_ccache_plugins(context); + return ret; +} + +static krb5_error_code +cc_ops_copy(krb5_context context, const krb5_context src_context) +{ + const krb5_cc_ops **cc_ops; + + context->cc_ops = NULL; + context->num_cc_ops = 0; + + if (src_context->num_cc_ops == 0) + return 0; + + cc_ops = malloc(sizeof(cc_ops[0]) * src_context->num_cc_ops); + if (cc_ops == NULL) { + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); + return KRB5_CC_NOMEM; + } + + memcpy(rk_UNCONST(cc_ops), src_context->cc_ops, + sizeof(cc_ops[0]) * src_context->num_cc_ops); + context->cc_ops = cc_ops; + context->num_cc_ops = src_context->num_cc_ops; + + return 0; +} + +static krb5_error_code +kt_ops_register(krb5_context context) +{ + krb5_error_code ret; + + context->num_kt_types = 0; + context->kt_types = NULL; + + ret = krb5_kt_register (context, &krb5_fkt_ops); + if (ret) + return ret; + ret = krb5_kt_register (context, &krb5_wrfkt_ops); + if (ret) + return ret; + ret = krb5_kt_register (context, &krb5_javakt_ops); + if (ret) + return ret; + ret = krb5_kt_register (context, &krb5_mkt_ops); + if (ret) + return ret; +#ifndef HEIMDAL_SMALLER + ret = krb5_kt_register (context, &krb5_akf_ops); + if (ret) + return ret; +#endif + ret = krb5_kt_register (context, &krb5_any_ops); + return ret; +} + +static krb5_error_code +kt_ops_copy(krb5_context context, const krb5_context src_context) +{ + context->num_kt_types = 0; + context->kt_types = NULL; + + if (src_context->num_kt_types == 0) + return 0; + + context->kt_types = malloc(sizeof(context->kt_types[0]) * src_context->num_kt_types); + if (context->kt_types == NULL) + return krb5_enomem(context); + + context->num_kt_types = src_context->num_kt_types; + memcpy(context->kt_types, src_context->kt_types, + sizeof(context->kt_types[0]) * src_context->num_kt_types); + + return 0; +} + +static const char *const sysplugin_dirs[] = { +#ifdef _WIN32 + "$ORIGIN", +#else + "$ORIGIN/../lib/plugin/krb5", +#endif +#ifdef __APPLE__ + LIBDIR "/plugin/krb5", +#ifdef HEIM_PLUGINS_SEARCH_SYSTEM + "/Library/KerberosPlugins/KerberosFrameworkPlugins", + "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", +#endif +#endif + NULL +}; + +static void +init_context_once(void *ctx) +{ + krb5_context context = ctx; + char **dirs; + +#ifdef _WIN32 + dirs = rk_UNCONST(sysplugin_dirs); +#else + dirs = krb5_config_get_strings(context, NULL, "libdefaults", + "plugin_dir", NULL); + if (dirs == NULL) + dirs = rk_UNCONST(sysplugin_dirs); +#endif + + _krb5_load_plugins(context, "krb5", (const char **)dirs); + + if (dirs != rk_UNCONST(sysplugin_dirs)) + krb5_config_free_strings(dirs); + + bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); +} + +/** + * Initializes the context structure and reads the configuration file + * /etc/krb5.conf. The structure should be freed by calling + * krb5_free_context() when it is no longer being used. + * + * @param context pointer to returned context + * + * @return Returns 0 to indicate success. Otherwise an errno code is + * returned. Failure means either that something bad happened during + * initialization (typically ENOMEM) or that Kerberos should not be + * used ENXIO. If the function returns HEIM_ERR_RANDOM_OFFLINE, the + * random source is not available and later Kerberos calls might fail. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_context(krb5_context *context) +{ + static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; + krb5_context p; + krb5_error_code ret; + char **files; + uint8_t rnd; + + *context = NULL; + + /** + * krb5_init_context() will get one random byte to make sure our + * random is alive. Assumption is that once the non blocking + * source allows us to pull bytes, its all seeded and allows us to + * pull more bytes. + * + * Most Kerberos users calls krb5_init_context(), so this is + * useful point where we can do the checking. + */ + ret = krb5_generate_random(&rnd, sizeof(rnd)); + if (ret) + return ret; + + p = calloc(1, sizeof(*p)); + if(!p) + return ENOMEM; + + if ((p->hcontext = heim_context_init()) == NULL) { + ret = ENOMEM; + goto out; + } + + if (!issuid()) + p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + + ret = krb5_get_default_config_files(&files); + if(ret) + goto out; + ret = krb5_set_config_files(p, files); + krb5_free_config_files(files); + if(ret) + goto out; + + /* done enough to load plugins */ + heim_base_once_f(&init_context, p, init_context_once); + + /* init error tables */ + _krb5_init_ets(p); + ret = cc_ops_register(p); + if (ret) + goto out; + ret = kt_ops_register(p); + if (ret) + goto out; + +#ifdef PKINIT + ret = hx509_context_init(&p->hx509ctx); + if (ret) + goto out; +#endif + if (rk_SOCK_INIT()) + p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED; + +out: + if (ret) { + krb5_free_context(p); + p = NULL; + } else { + heim_context_set_log_utc(p->hcontext, p->log_utc); + } + *context = p; + return ret; +} + +#ifndef HEIMDAL_SMALLER + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_permitted_enctypes(krb5_context context, + krb5_enctype **etypes) +{ + return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, etypes); +} + +/* + * + */ + +static krb5_error_code +copy_etypes (krb5_context context, + krb5_enctype *enctypes, + krb5_enctype **ret_enctypes) +{ + unsigned int i; + + for (i = 0; enctypes[i]; i++) + ; + i++; + + *ret_enctypes = malloc(sizeof(enctypes[0]) * i); + if (*ret_enctypes == NULL) + return krb5_enomem(context); + memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * i); + return 0; +} + +/** + * Make a copy for the Kerberos 5 context, the new krb5_context shoud + * be freed with krb5_free_context(). + * + * @param context the Kerberos context to copy + * @param out the copy of the Kerberos, set to NULL error. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_context(krb5_context context, krb5_context *out) +{ + krb5_error_code ret = 0; + krb5_context p; + + *out = NULL; + + p = calloc(1, sizeof(*p)); + if (p == NULL) + return krb5_enomem(context); + + p->cc_ops = NULL; + p->etypes = NULL; + p->kt_types = NULL; + p->cfg_etypes = NULL; + p->etypes_des = NULL; + p->default_realms = NULL; + p->extra_addresses = NULL; + p->ignore_addresses = NULL; + + if ((p->hcontext = heim_context_init()) == NULL) + ret = ENOMEM; + + if (ret == 0) { + heim_context_set_log_utc(p->hcontext, context->log_utc); + ret = _krb5_config_copy(context, context->cf, &p->cf); + } + if (ret == 0) + ret = init_context_from_config_file(p); + if (ret == 0 && context->default_cc_name) { + free(p->default_cc_name); + if ((p->default_cc_name = strdup(context->default_cc_name)) == NULL) + ret = ENOMEM; + } + if (ret == 0 && context->default_cc_name_env) { + free(p->default_cc_name_env); + if ((p->default_cc_name_env = + strdup(context->default_cc_name_env)) == NULL) + ret = ENOMEM; + } + if (ret == 0 && context->configured_default_cc_name) { + free(p->configured_default_cc_name); + if ((p->configured_default_cc_name = + strdup(context->configured_default_cc_name)) == NULL) + ret = ENOMEM; + } + + if (ret == 0 && context->etypes) { + free(p->etypes); + ret = copy_etypes(context, context->etypes, &p->etypes); + } + if (ret == 0 && context->cfg_etypes) { + free(p->cfg_etypes); + ret = copy_etypes(context, context->cfg_etypes, &p->cfg_etypes); + } + if (ret == 0 && context->etypes_des) { + free(p->etypes_des); + ret = copy_etypes(context, context->etypes_des, &p->etypes_des); + } + + if (ret == 0 && context->default_realms) { + krb5_free_host_realm(context, p->default_realms); + ret = krb5_copy_host_realm(context, + context->default_realms, &p->default_realms); + } + + /* XXX should copy */ + if (ret == 0) + _krb5_init_ets(p); + + if (ret == 0) + ret = cc_ops_copy(p, context); + if (ret == 0) + ret = kt_ops_copy(p, context); + if (ret == 0) + ret = krb5_set_extra_addresses(p, context->extra_addresses); + if (ret == 0) + ret = krb5_set_extra_addresses(p, context->ignore_addresses); + if (ret == 0) + ret = _krb5_copy_send_to_kdc_func(p, context); + + if (ret == 0) + *out = p; + else + krb5_free_context(p); + return ret; +} + +#endif + +/** + * Frees the krb5_context allocated by krb5_init_context(). + * + * @param context context to be freed. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_context(krb5_context context) +{ + _krb5_free_name_canon_rules(context, context->name_canon_rules); + free(context->default_cc_name); + free(context->default_cc_name_env); + free(context->configured_default_cc_name); + free(context->etypes); + free(context->cfg_etypes); + free(context->etypes_des); + free(context->permitted_enctypes); + free(context->tgs_etypes); + free(context->as_etypes); + krb5_free_host_realm (context, context->default_realms); + krb5_config_file_free (context, context->cf); + free(rk_UNCONST(context->cc_ops)); + free(context->kt_types); + krb5_clear_error_message(context); + krb5_set_extra_addresses(context, NULL); + krb5_set_ignore_addresses(context, NULL); + krb5_set_send_to_kdc_func(context, NULL, NULL); + +#ifdef PKINIT + hx509_context_free(&context->hx509ctx); +#endif + + if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) { + rk_SOCK_EXIT(); + } + + heim_context_free(&context->hcontext); + memset(context, 0, sizeof(*context)); + free(context); +} + +/** + * Reinit the context from a new set of filenames. + * + * @param context context to add configuration too. + * @param filenames array of filenames, end of list is indicated with a NULL filename. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_config_files(krb5_context context, char **filenames) +{ + krb5_error_code ret; + heim_config_binding *tmp = NULL; + + if ((ret = heim_set_config_files(context->hcontext, filenames, + &tmp))) + return ret; + krb5_config_file_free(context, context->cf); + context->cf = (krb5_config_binding *)tmp; + return init_context_from_config_file(context); +} + +#ifndef HEIMDAL_SMALLER +/** + * Reinit the context from configuration file contents in a C string. + * This should only be used in tests. + * + * @param context context to add configuration too. + * @param config configuration. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_config(krb5_context context, const char *config) +{ + krb5_error_code ret; + krb5_config_binding *tmp = NULL; + + if ((ret = krb5_config_parse_string_multi(context, config, &tmp))) + return ret; +#if 0 + /* with this enabled and if there are no config files, Kerberos is + considererd disabled */ + if (tmp == NULL) + return ENXIO; +#endif + + krb5_config_file_free(context, context->cf); + context->cf = tmp; + ret = init_context_from_config_file(context); + return ret; +} +#endif + +/* + * `pq' isn't free, it's up the the caller + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp) +{ + return heim_prepend_config_files(filelist, pq, ret_pp); +} + +/** + * Prepend the filename to the global configuration list. + * + * @param filelist a filename to add to the default list of filename + * @param pfilenames return array of filenames, should be freed with krb5_free_config_files(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_prepend_config_files_default(const char *filelist, char ***pfilenames) +{ + return heim_prepend_config_files_default(filelist, krb5_config_file, + "KRB5_CONFIG", pfilenames); +} + +/** + * Get the global configuration list. + * + * @param pfilenames return array of filenames, should be freed with krb5_free_config_files(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_default_config_files(char ***pfilenames) +{ + if (pfilenames == NULL) + return EINVAL; + return heim_get_default_config_files(krb5_config_file, "KRB5_CONFIG", + pfilenames); +} + +/** + * Free a list of configuration files. + * + * @param filenames list, terminated with a NULL pointer, to be + * freed. NULL is an valid argument. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_config_files(char **filenames) +{ + heim_free_config_files(filenames); +} + +/** + * Returns the list of Kerberos encryption types sorted in order of + * most preferred to least preferred encryption type. Note that some + * encryption types might be disabled, so you need to check with + * krb5_enctype_valid() before using the encryption type. + * + * @return list of enctypes, terminated with ETYPE_NULL. Its a static + * array completed into the Kerberos library so the content doesn't + * need to be freed. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL +krb5_kerberos_enctypes(krb5_context context) +{ + static const krb5_enctype p[] = { + ETYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA1_96, + ETYPE_AES256_CTS_HMAC_SHA384_192, + ETYPE_AES128_CTS_HMAC_SHA256_128, + ETYPE_DES3_CBC_SHA1, + ETYPE_ARCFOUR_HMAC_MD5, + ETYPE_NULL + }; + + static const krb5_enctype weak[] = { + ETYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA1_96, + ETYPE_AES256_CTS_HMAC_SHA384_192, + ETYPE_AES128_CTS_HMAC_SHA256_128, + ETYPE_DES3_CBC_SHA1, + ETYPE_DES3_CBC_MD5, + ETYPE_ARCFOUR_HMAC_MD5, + ETYPE_DES_CBC_MD5, + ETYPE_DES_CBC_MD4, + ETYPE_DES_CBC_CRC, + ETYPE_NULL + }; + + /* + * if the list of enctypes enabled by "allow_weak_crypto" + * are valid, then return the former default enctype list + * that contained the weak entries. + */ + if (krb5_enctype_valid(context, ETYPE_DES_CBC_CRC) == 0 && + krb5_enctype_valid(context, ETYPE_DES_CBC_MD4) == 0 && + krb5_enctype_valid(context, ETYPE_DES_CBC_MD5) == 0 && + krb5_enctype_valid(context, ETYPE_DES_CBC_NONE) == 0 && + krb5_enctype_valid(context, ETYPE_DES_CFB64_NONE) == 0 && + krb5_enctype_valid(context, ETYPE_DES_PCBC_NONE) == 0) + return weak; + + return p; +} + +/* + * + */ + +static krb5_error_code +copy_enctypes(krb5_context context, + const krb5_enctype *in, + krb5_enctype **out) +{ + krb5_enctype *p = NULL; + size_t m, n; + + for (n = 0; in[n]; n++) + ; + n++; + ALLOC(p, n); + if(p == NULL) + return krb5_enomem(context); + for (n = 0, m = 0; in[n]; n++) { + if (krb5_enctype_valid(context, in[n]) != 0) + continue; + p[m++] = in[n]; + } + p[m] = KRB5_ENCTYPE_NULL; + if (m == 0) { + free(p); + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("no valid enctype set", "")); + return KRB5_PROG_ETYPE_NOSUPP; + } + *out = p; + return 0; +} + + +/* + * set `etype' to a malloced list of the default enctypes + */ + +static krb5_error_code +default_etypes(krb5_context context, krb5_enctype **etype) +{ + const krb5_enctype *p = krb5_kerberos_enctypes(context); + return copy_enctypes(context, p, etype); +} + +/** + * Set the default encryption types that will be use in communcation + * with the KDC, clients and servers. + * + * @param context Kerberos 5 context. + * @param etypes Encryption types, array terminated with ETYPE_NULL (0). + * A value of NULL resets the encryption types to the defaults set in the + * configuration file. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_default_in_tkt_etypes(krb5_context context, + const krb5_enctype *etypes) +{ + krb5_error_code ret; + krb5_enctype *p = NULL; + + if(!etypes) { + etypes = context->cfg_etypes; + } + + if(etypes) { + ret = copy_enctypes(context, etypes, &p); + if (ret) + return ret; + } + if(context->etypes) + free(context->etypes); + context->etypes = p; + return 0; +} + +/** + * Get the default encryption types that will be use in communcation + * with the KDC, clients and servers. + * + * @param context Kerberos 5 context. + * @param pdu_type request type (AS, TGS or none) + * @param etypes Encryption types, array terminated with + * ETYPE_NULL(0), caller should free array with krb5_xfree(): + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_default_in_tkt_etypes(krb5_context context, + krb5_pdu pdu_type, + krb5_enctype **etypes) +{ + krb5_enctype *enctypes = NULL; + krb5_error_code ret; + krb5_enctype *p; + + heim_assert(pdu_type == KRB5_PDU_AS_REQUEST || + pdu_type == KRB5_PDU_TGS_REQUEST || + pdu_type == KRB5_PDU_NONE, "unexpected pdu type"); + + if (pdu_type == KRB5_PDU_AS_REQUEST && context->as_etypes != NULL) + enctypes = context->as_etypes; + else if (pdu_type == KRB5_PDU_TGS_REQUEST && context->tgs_etypes != NULL) + enctypes = context->tgs_etypes; + else if (context->etypes != NULL) + enctypes = context->etypes; + + if (enctypes != NULL) { + ret = copy_enctypes(context, enctypes, &p); + if (ret) + return ret; + } else { + ret = default_etypes(context, &p); + if (ret) + return ret; + } + *etypes = p; + return 0; +} + +/** + * Init the built-in ets in the Kerberos library. + * + * @param context kerberos context to add the ets too + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_init_ets(krb5_context context) +{ +} + +static void +_krb5_init_ets(krb5_context context) +{ + heim_add_et_list(context->hcontext, initialize_krb5_error_table_r); + heim_add_et_list(context->hcontext, initialize_asn1_error_table_r); + heim_add_et_list(context->hcontext, initialize_heim_error_table_r); + + heim_add_et_list(context->hcontext, initialize_k524_error_table_r); + heim_add_et_list(context->hcontext, initialize_k5e1_error_table_r); + +#ifdef COM_ERR_BINDDOMAIN_krb5 + bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR); + bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR); + bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR); + bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR); +#endif + +#ifdef PKINIT + heim_add_et_list(context->hcontext, initialize_hx_error_table_r); +#ifdef COM_ERR_BINDDOMAIN_hx + bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR); +#endif +#endif +} + +/** + * Make the kerberos library default to the admin KDC. + * + * @param context Kerberos 5 context. + * @param flag boolean flag to select if the use the admin KDC or not. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag) +{ + context->use_admin_kdc = flag; +} + +/** + * Make the kerberos library default to the admin KDC. + * + * @param context Kerberos 5 context. + * + * @return boolean flag to telling the context will use admin KDC as the default KDC. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_get_use_admin_kdc (krb5_context context) +{ + return context->use_admin_kdc; +} + +/** + * Add extra address to the address list that the library will add to + * the client's address list when communicating with the KDC. + * + * @param context Kerberos 5 context. + * @param addresses addreses to add + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses) +{ + + if(context->extra_addresses) + return krb5_append_addresses(context, + context->extra_addresses, addresses); + else + return krb5_set_extra_addresses(context, addresses); +} + +/** + * Set extra address to the address list that the library will add to + * the client's address list when communicating with the KDC. + * + * @param context Kerberos 5 context. + * @param addresses addreses to set + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses) +{ + if(context->extra_addresses) + krb5_free_addresses(context, context->extra_addresses); + + if(addresses == NULL) { + if(context->extra_addresses != NULL) { + free(context->extra_addresses); + context->extra_addresses = NULL; + } + return 0; + } + if(context->extra_addresses == NULL) { + context->extra_addresses = malloc(sizeof(*context->extra_addresses)); + if (context->extra_addresses == NULL) + return krb5_enomem(context); + } + return krb5_copy_addresses(context, addresses, context->extra_addresses); +} + +/** + * Get extra address to the address list that the library will add to + * the client's address list when communicating with the KDC. + * + * @param context Kerberos 5 context. + * @param addresses addreses to set + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses) +{ + if(context->extra_addresses == NULL) { + memset(addresses, 0, sizeof(*addresses)); + return 0; + } + return krb5_copy_addresses(context,context->extra_addresses, addresses); +} + +/** + * Add extra addresses to ignore when fetching addresses from the + * underlaying operating system. + * + * @param context Kerberos 5 context. + * @param addresses addreses to ignore + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses) +{ + + if(context->ignore_addresses) + return krb5_append_addresses(context, + context->ignore_addresses, addresses); + else + return krb5_set_ignore_addresses(context, addresses); +} + +/** + * Set extra addresses to ignore when fetching addresses from the + * underlaying operating system. + * + * @param context Kerberos 5 context. + * @param addresses addreses to ignore + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses) +{ + if(context->ignore_addresses) + krb5_free_addresses(context, context->ignore_addresses); + if(addresses == NULL) { + if(context->ignore_addresses != NULL) { + free(context->ignore_addresses); + context->ignore_addresses = NULL; + } + return 0; + } + if(context->ignore_addresses == NULL) { + context->ignore_addresses = malloc(sizeof(*context->ignore_addresses)); + if (context->ignore_addresses == NULL) + return krb5_enomem(context); + } + return krb5_copy_addresses(context, addresses, context->ignore_addresses); +} + +/** + * Get extra addresses to ignore when fetching addresses from the + * underlaying operating system. + * + * @param context Kerberos 5 context. + * @param addresses list addreses ignored + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses) +{ + if(context->ignore_addresses == NULL) { + memset(addresses, 0, sizeof(*addresses)); + return 0; + } + return krb5_copy_addresses(context, context->ignore_addresses, addresses); +} + +/** + * Set version of fcache that the library should use. + * + * @param context Kerberos 5 context. + * @param version version number. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_fcache_version(krb5_context context, int version) +{ + context->fcache_vno = version; + return 0; +} + +/** + * Get version of fcache that the library should use. + * + * @param context Kerberos 5 context. + * @param version version number. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_fcache_version(krb5_context context, int *version) +{ + *version = context->fcache_vno; + return 0; +} + +/** + * Runtime check if the Kerberos library was complied with thread support. + * + * @return TRUE if the library was compiled with thread support, FALSE if not. + * + * @ingroup krb5 + */ + + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_is_thread_safe(void) +{ +#ifdef ENABLE_PTHREAD_SUPPORT + return TRUE; +#else + return FALSE; +#endif +} + +/** + * Set if the library should use DNS to canonicalize hostnames. + * + * @param context Kerberos 5 context. + * @param flag if its dns canonicalizion is used or not. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag) +{ + if (flag) + context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME; + else + context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME; +} + +/** + * Get if the library uses DNS to canonicalize hostnames. + * + * @param context Kerberos 5 context. + * + * @return return non zero if the library uses DNS to canonicalize hostnames. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_get_dns_canonicalize_hostname (krb5_context context) +{ + return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0; +} + +/** + * Get current offset in time to the KDC. + * + * @param context Kerberos 5 context. + * @param sec seconds part of offset. + * @param usec micro seconds part of offset. + * + * @return returns zero + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec) +{ + if (sec) + *sec = context->kdc_sec_offset; + if (usec) + *usec = context->kdc_usec_offset; + return 0; +} + +/** + * Set current offset in time to the KDC. + * + * @param context Kerberos 5 context. + * @param sec seconds part of offset. + * @param usec micro seconds part of offset. + * + * @return returns zero + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec) +{ + context->kdc_sec_offset = sec; + if (usec >= 0) + context->kdc_usec_offset = usec; + return 0; +} + +/** + * Get max time skew allowed. + * + * @param context Kerberos 5 context. + * + * @return timeskew in seconds. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL +krb5_get_max_time_skew (krb5_context context) +{ + return context->max_skew; +} + +/** + * Set max time skew allowed. + * + * @param context Kerberos 5 context. + * @param t timeskew in seconds. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_set_max_time_skew (krb5_context context, time_t t) +{ + context->max_skew = t; +} + +/* + * Init encryption types in len, val with etypes. + * + * @param context Kerberos 5 context. + * @param pdu_type type of pdu + * @param len output length of val. + * @param val output array of enctypes. + * @param etypes etypes to set val and len to, if NULL, use default enctypes. + + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_init_etype(krb5_context context, + krb5_pdu pdu_type, + unsigned *len, + krb5_enctype **val, + const krb5_enctype *etypes) +{ + krb5_error_code ret; + + if (etypes == NULL) + ret = krb5_get_default_in_tkt_etypes(context, pdu_type, val); + else + ret = copy_enctypes(context, etypes, val); + if (ret) + return ret; + + if (len) { + *len = 0; + while ((*val)[*len] != KRB5_ENCTYPE_NULL) + (*len)++; + } + return 0; +} + +/* + * Allow homedir access + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_homedir_access(krb5_context context) +{ + if (context) + return !!(context->flags & KRB5_CTX_F_HOMEDIR_ACCESS); + return !issuid(); +} + +/** + * Enable and disable home directory access on either the global state + * or the krb5_context state. By calling krb5_set_home_dir_access() + * with context set to NULL, the global state is configured otherwise + * the state for the krb5_context is modified. + * + * For home directory access to be allowed, both the global state and + * the krb5_context state have to be allowed. + * + * @param context a Kerberos 5 context or NULL + * @param allow allow if TRUE home directory + * @return the old value + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_set_home_dir_access(krb5_context context, krb5_boolean allow) +{ + krb5_boolean old = _krb5_homedir_access(context); + + if (context) { + if (allow) + context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + else + context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS; + heim_context_set_homedir_access(context->hcontext, allow ? 1 : 0); + } + + return old; +} + diff --git a/third_party/heimdal/lib/krb5/convert_creds.c b/third_party/heimdal/lib/krb5/convert_creds.c new file mode 100644 index 0000000..56261b2 --- /dev/null +++ b/third_party/heimdal/lib/krb5/convert_creds.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER + +/** + * Convert the v5 credentials in in_cred to v4-dito in v4creds. This + * is done by sending them to the 524 function in the KDC. If + * `in_cred' doesn't contain a DES session key, then a new one is + * gotten from the KDC and stored in the cred cache `ccache'. + * + * @param context Kerberos 5 context. + * @param in_cred the credential to convert + * @param v4creds the converted credential + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5_v4compat + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb524_convert_creds_kdc(krb5_context context, + krb5_creds *in_cred, + struct credentials *v4creds) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_set_error_message(context, EINVAL, + N_("krb524_convert_creds_kdc not supported", "")); + return EINVAL; +} + +/** + * Convert the v5 credentials in in_cred to v4-dito in v4creds, + * check the credential cache ccache before checking with the KDC. + * + * @param context Kerberos 5 context. + * @param ccache credential cache used to check for des-ticket. + * @param in_cred the credential to convert + * @param v4creds the converted credential + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5_v4compat + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb524_convert_creds_kdc_ccache(krb5_context context, + krb5_ccache ccache, + krb5_creds *in_cred, + struct credentials *v4creds) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_set_error_message(context, EINVAL, + N_("krb524_convert_creds_kdc_ccache not supported", "")); + return EINVAL; +} + +#endif diff --git a/third_party/heimdal/lib/krb5/copy_host_realm.c b/third_party/heimdal/lib/krb5/copy_host_realm.c new file mode 100644 index 0000000..f68d0d7 --- /dev/null +++ b/third_party/heimdal/lib/krb5/copy_host_realm.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Copy the list of realms from `from' to `to'. + * + * @param context Kerberos 5 context. + * @param from list of realms to copy from. + * @param to list of realms to copy to, free list of krb5_free_host_realm(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_host_realm(krb5_context context, + const krb5_realm *from, + krb5_realm **to) +{ + unsigned int n, i; + const krb5_realm *p; + + for (n = 1, p = from; *p != NULL; ++p) + ++n; + + *to = calloc (n, sizeof(**to)); + if (*to == NULL) + return krb5_enomem(context); + + for (i = 0, p = from; *p != NULL; ++p, ++i) { + (*to)[i] = strdup(*p); + if ((*to)[i] == NULL) { + krb5_free_host_realm (context, *to); + return krb5_enomem(context); + } + } + return 0; +} diff --git a/third_party/heimdal/lib/krb5/crc.c b/third_party/heimdal/lib/krb5/crc.c new file mode 100644 index 0000000..3090760 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crc.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +static u_long table[256]; + +#define CRC_GEN 0xEDB88320L + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_crc_init_table(void) +{ + static int flag = 0; + unsigned long crc, poly; + unsigned int i, j; + + if(flag) return; + poly = CRC_GEN; + for (i = 0; i < 256; i++) { + crc = i; + for (j = 8; j > 0; j--) { + if (crc & 1) { + crc = (crc >> 1) ^ poly; + } else { + crc >>= 1; + } + } + table[i] = crc; + } + flag = 1; +} + +KRB5_LIB_FUNCTION uint32_t KRB5_LIB_CALL +_krb5_crc_update (const char *p, size_t len, uint32_t res) +{ + while (len--) + res = table[(res ^ *p++) & 0xFF] ^ (res >> 8); + return res & 0xFFFFFFFF; +} diff --git a/third_party/heimdal/lib/krb5/creds.c b/third_party/heimdal/lib/krb5/creds.c new file mode 100644 index 0000000..d62a70a --- /dev/null +++ b/third_party/heimdal/lib/krb5/creds.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Free content of krb5_creds. + * + * @param context Kerberos 5 context. + * @param c krb5_creds to free. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_cred_contents (krb5_context context, krb5_creds *c) +{ + krb5_free_principal (context, c->client); + c->client = NULL; + krb5_free_principal (context, c->server); + c->server = NULL; + krb5_free_keyblock_contents (context, &c->session); + krb5_data_free (&c->ticket); + krb5_data_free (&c->second_ticket); + free_AuthorizationData (&c->authdata); + krb5_free_addresses (context, &c->addresses); + memset(c, 0, sizeof(*c)); + return 0; +} + +/** + * Copy content of krb5_creds. + * + * @param context Kerberos 5 context. + * @param incred source credential + * @param c destination credential, free with krb5_free_cred_contents(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_creds_contents (krb5_context context, + const krb5_creds *incred, + krb5_creds *c) +{ + krb5_error_code ret; + + memset(c, 0, sizeof(*c)); + ret = krb5_copy_principal (context, incred->client, &c->client); + if (ret) + goto fail; + ret = krb5_copy_principal (context, incred->server, &c->server); + if (ret) + goto fail; + ret = krb5_copy_keyblock_contents (context, &incred->session, &c->session); + if (ret) + goto fail; + c->times = incred->times; + ret = krb5_data_copy (&c->ticket, + incred->ticket.data, + incred->ticket.length); + if (ret) + goto fail; + ret = krb5_data_copy (&c->second_ticket, + incred->second_ticket.data, + incred->second_ticket.length); + if (ret) + goto fail; + ret = copy_AuthorizationData(&incred->authdata, &c->authdata); + if (ret) + goto fail; + ret = krb5_copy_addresses (context, + &incred->addresses, + &c->addresses); + if (ret) + goto fail; + c->flags = incred->flags; + return 0; + +fail: + krb5_free_cred_contents (context, c); + return ret; +} + +/** + * Copy krb5_creds. + * + * @param context Kerberos 5 context. + * @param incred source credential + * @param outcred destination credential, free with krb5_free_creds(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_creds (krb5_context context, + const krb5_creds *incred, + krb5_creds **outcred) +{ + krb5_creds *c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return krb5_enomem(context); + *outcred = c; + return krb5_copy_creds_contents (context, incred, c); +} + +/** + * Free krb5_creds. + * + * @param context Kerberos 5 context. + * @param c krb5_creds to free. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_creds (krb5_context context, krb5_creds *c) +{ + if (c != NULL) + krb5_free_cred_contents(context, c); + free(c); + return 0; +} + +/* XXX this do not belong here */ +static krb5_boolean +krb5_times_equal(const krb5_times *a, const krb5_times *b) +{ + return a->starttime == b->starttime && + a->authtime == b->authtime && + a->endtime == b->endtime && + a->renew_till == b->renew_till; +} + +/** + * Return TRUE if `mcreds' and `creds' are equal (`whichfields' + * determines what equal means). + * + * + * The following flags, set in whichfields affects the comparison: + * - KRB5_TC_MATCH_SRV_NAMEONLY Consider all realms equal when comparing the service principal. + * - KRB5_TC_MATCH_KEYTYPE Compare enctypes. + * - KRB5_TC_MATCH_FLAGS_EXACT Make sure that the ticket flags are identical. + * - KRB5_TC_MATCH_FLAGS Make sure that all ticket flags set in mcreds are also present in creds . + * - KRB5_TC_MATCH_TIMES_EXACT Compares the ticket times exactly. + * - KRB5_TC_MATCH_TIMES Compares only the expiration times of the creds. + * - KRB5_TC_MATCH_AUTHDATA Compares the authdata fields. + * - KRB5_TC_MATCH_2ND_TKT Compares the second tickets (used by user-to-user authentication). + * - KRB5_TC_MATCH_IS_SKEY Compares the existence of the second ticket. + * + * @param context Kerberos 5 context. + * @param whichfields which fields to compare. + * @param mcreds cred to compare with. + * @param creds cred to compare with. + * + * @return return TRUE if mcred and creds are equal, FALSE if not. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_compare_creds(krb5_context context, krb5_flags whichfields, + const krb5_creds * mcreds, const krb5_creds * creds) +{ + krb5_boolean match = TRUE; + + if (match && mcreds->server) { + if (whichfields & (KRB5_TC_DONT_MATCH_REALM | KRB5_TC_MATCH_SRV_NAMEONLY)) + match = krb5_principal_compare_any_realm (context, mcreds->server, + creds->server); + else + match = krb5_principal_compare (context, mcreds->server, + creds->server); + } + + if (match && mcreds->client) { + if(whichfields & KRB5_TC_DONT_MATCH_REALM) + match = krb5_principal_compare_any_realm (context, mcreds->client, + creds->client); + else + match = krb5_principal_compare (context, mcreds->client, + creds->client); + } + + if (match && (whichfields & KRB5_TC_MATCH_KEYTYPE)) + match = mcreds->session.keytype == creds->session.keytype; + + if (match && (whichfields & KRB5_TC_MATCH_FLAGS_EXACT)) + match = mcreds->flags.i == creds->flags.i; + + if (match && (whichfields & KRB5_TC_MATCH_FLAGS)) + match = (creds->flags.i & mcreds->flags.i) == mcreds->flags.i; + + if (match && (whichfields & KRB5_TC_MATCH_TIMES_EXACT)) + match = krb5_times_equal(&mcreds->times, &creds->times); + + if (match && (whichfields & KRB5_TC_MATCH_TIMES)) + /* compare only expiration times */ + match = (mcreds->times.renew_till <= creds->times.renew_till) && + (mcreds->times.endtime <= creds->times.endtime); + + if (match && (whichfields & KRB5_TC_MATCH_AUTHDATA)) { + unsigned int i; + if(mcreds->authdata.len != creds->authdata.len) + match = FALSE; + else + for(i = 0; match && i < mcreds->authdata.len; i++) + match = (mcreds->authdata.val[i].ad_type == + creds->authdata.val[i].ad_type) && + (krb5_data_cmp(&mcreds->authdata.val[i].ad_data, + &creds->authdata.val[i].ad_data) == 0); + } + if (match && (whichfields & KRB5_TC_MATCH_2ND_TKT)) + match = (krb5_data_cmp(&mcreds->second_ticket, &creds->second_ticket) == 0); + + if (match && (whichfields & KRB5_TC_MATCH_IS_SKEY)) + match = ((mcreds->second_ticket.length == 0) == + (creds->second_ticket.length == 0)); + + return match; +} + +/** + * Returns the ticket flags for the credentials in creds. + * See also krb5_ticket_get_flags(). + * + * @param creds credential to get ticket flags from + * + * @return ticket flags + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL +krb5_creds_get_ticket_flags(krb5_creds *creds) +{ + return TicketFlags2int(creds->flags.b); +} diff --git a/third_party/heimdal/lib/krb5/crypto-aes-sha1.c b/third_party/heimdal/lib/krb5/crypto-aes-sha1.c new file mode 100644 index 0000000..1f3760d --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-aes-sha1.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * AES + */ + +static struct _krb5_key_type keytype_aes128_sha1 = { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, + "aes-128", + 128, + 16, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA1_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_128_cbc +}; + +static struct _krb5_key_type keytype_aes256_sha1 = { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + "aes-256", + 256, + 32, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA1_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_256_cbc +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = { + CKSUMTYPE_HMAC_SHA1_96_AES_128, + "hmac-sha1-96-aes128", + 64, + 12, + F_KEYED | F_CPROOF | F_DERIVED, + _krb5_SP_HMAC_SHA1_checksum, + _krb5_SP_HMAC_SHA1_verify +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = { + CKSUMTYPE_HMAC_SHA1_96_AES_256, + "hmac-sha1-96-aes256", + 64, + 12, + F_KEYED | F_CPROOF | F_DERIVED, + _krb5_SP_HMAC_SHA1_checksum, + _krb5_SP_HMAC_SHA1_verify +}; + +static krb5_error_code +AES_SHA1_PRF(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + struct _krb5_checksum_type *ct = crypto->et->checksum; + struct krb5_crypto_iov iov[1]; + krb5_error_code ret; + Checksum result; + krb5_keyblock *derived; + + result.cksumtype = ct->type; + ret = krb5_data_alloc(&result.checksum, ct->checksumsize); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out memory", "")); + return ret; + } + + iov[0].data = *in; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = (*ct->checksum)(context, crypto, NULL, 0, iov, 1, &result); + if (ret) { + krb5_data_free(&result.checksum); + return ret; + } + + if (result.checksum.length < crypto->et->blocksize) + krb5_abortx(context, "internal prf error"); + + derived = NULL; + ret = krb5_derive_key(context, crypto->key.key, + crypto->et->type, "prf", 3, &derived); + if (ret) + krb5_abortx(context, "krb5_derive_key"); + + ret = krb5_data_alloc(out, crypto->et->blocksize); + if (ret) + krb5_abortx(context, "malloc failed"); + + { + const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); + EVP_CIPHER_CTX ctx; + + EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ + EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); + EVP_Cipher(&ctx, out->data, result.checksum.data, + crypto->et->blocksize); + EVP_CIPHER_CTX_cleanup(&ctx); + } + + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + + return ret; +} + +struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { + ETYPE_AES128_CTS_HMAC_SHA1_96, + "aes128-cts-hmac-sha1-96", + "aes128-cts", + 16, + 1, + 16, + &keytype_aes128_sha1, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_aes128, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF, + _krb5_evp_encrypt_cts, + _krb5_evp_encrypt_iov_cts, + 16, + AES_SHA1_PRF +}; + +struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { + ETYPE_AES256_CTS_HMAC_SHA1_96, + "aes256-cts-hmac-sha1-96", + "aes256-cts", + 16, + 1, + 16, + &keytype_aes256_sha1, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_aes256, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF, + _krb5_evp_encrypt_cts, + _krb5_evp_encrypt_iov_cts, + 16, + AES_SHA1_PRF +}; diff --git a/third_party/heimdal/lib/krb5/crypto-aes-sha2.c b/third_party/heimdal/lib/krb5/crypto-aes-sha2.c new file mode 100644 index 0000000..94ec9a1 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-aes-sha2.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * AES HMAC-SHA2 + */ + +krb5_error_code +_krb5_aes_sha2_md_for_enctype(krb5_context context, + krb5_enctype enctype, + const EVP_MD **md) +{ + switch (enctype) { + case ETYPE_AES128_CTS_HMAC_SHA256_128: + *md = EVP_sha256(); + break; + case ETYPE_AES256_CTS_HMAC_SHA384_192: + *md = EVP_sha384(); + break; + default: + return KRB5_PROG_ETYPE_NOSUPP; + break; + } + return 0; +} + +static krb5_error_code +SP_HMAC_SHA2_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *result) +{ + krb5_error_code ret; + const EVP_MD *md; + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned int hmaclen = sizeof(hmac); + + ret = _krb5_aes_sha2_md_for_enctype(context, key->key->keytype, &md); + if (ret) + return ret; + + ret = _krb5_evp_hmac_iov(context, crypto, key, iov, niov, hmac, + &hmaclen, md, NULL); + if (ret) + return ret; + + heim_assert(result->checksum.length <= hmaclen, "SHA2 internal error"); + + memcpy(result->checksum.data, hmac, result->checksum.length); + + return 0; +} + +static struct _krb5_key_type keytype_aes128_sha2 = { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + "aes-128-sha2", + 128, + 16, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA2_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_128_cbc +}; + +static struct _krb5_key_type keytype_aes256_sha2 = { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + "aes-256-sha2", + 256, + 32, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA2_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_256_cbc +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha256_128_aes128 = { + CKSUMTYPE_HMAC_SHA256_128_AES128, + "hmac-sha256-128-aes128", + 64, + 16, + F_KEYED | F_CPROOF | F_DERIVED, + SP_HMAC_SHA2_checksum, + NULL +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha384_192_aes256 = { + CKSUMTYPE_HMAC_SHA384_192_AES256, + "hmac-sha384-192-aes256", + 128, + 24, + F_KEYED | F_CPROOF | F_DERIVED, + SP_HMAC_SHA2_checksum, + NULL +}; + +static krb5_error_code +AES_SHA2_PRF(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + krb5_error_code ret; + krb5_data label; + const EVP_MD *md = NULL; + + ret = _krb5_aes_sha2_md_for_enctype(context, crypto->et->type, &md); + if (ret) + return ret; + + label.data = "prf"; + label.length = 3; + + ret = krb5_data_alloc(out, EVP_MD_size(md)); + if (ret) + return ret; + + ret = _krb5_SP800_108_HMAC_KDF(context, &crypto->key.key->keyvalue, + &label, in, md, out); + + if (ret) + krb5_data_free(out); + + return ret; +} + +struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha256_128 = { + ETYPE_AES128_CTS_HMAC_SHA256_128, + "aes128-cts-hmac-sha256-128", + "aes128-cts-sha256", + 16, + 1, + 16, + &keytype_aes128_sha2, + NULL, /* should never be called */ + &_krb5_checksum_hmac_sha256_128_aes128, + F_DERIVED | F_ENC_THEN_CKSUM | F_SP800_108_HMAC_KDF, + _krb5_evp_encrypt_cts, + NULL, + 16, + AES_SHA2_PRF +}; + +struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha384_192 = { + ETYPE_AES256_CTS_HMAC_SHA384_192, + "aes256-cts-hmac-sha384-192", + "aes256-cts-sha384", + 16, + 1, + 16, + &keytype_aes256_sha2, + NULL, /* should never be called */ + &_krb5_checksum_hmac_sha384_192_aes256, + F_DERIVED | F_ENC_THEN_CKSUM | F_SP800_108_HMAC_KDF, + _krb5_evp_encrypt_cts, + NULL, + 16, + AES_SHA2_PRF +}; diff --git a/third_party/heimdal/lib/krb5/crypto-algs.c b/third_party/heimdal/lib/krb5/crypto-algs.c new file mode 100644 index 0000000..eb21fce --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-algs.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER +#define DES3_OLD_ENCTYPE 1 +#endif + +struct _krb5_checksum_type *_krb5_checksum_types[] = { + &_krb5_checksum_none, +#ifdef HEIM_WEAK_CRYPTO + &_krb5_checksum_crc32, + &_krb5_checksum_rsa_md4, + &_krb5_checksum_rsa_md4_des, + &_krb5_checksum_rsa_md5_des, +#endif +#ifdef DES3_OLD_ENCTYPE + &_krb5_checksum_rsa_md5_des3, +#endif + &_krb5_checksum_rsa_md5, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_des3, + &_krb5_checksum_hmac_sha1_aes128, + &_krb5_checksum_hmac_sha1_aes256, + &_krb5_checksum_hmac_sha256_128_aes128, + &_krb5_checksum_hmac_sha384_192_aes256, + &_krb5_checksum_hmac_md5, + &_krb5_checksum_sha256, + &_krb5_checksum_sha384, + &_krb5_checksum_sha512 +}; + +int _krb5_num_checksums + = sizeof(_krb5_checksum_types) / sizeof(_krb5_checksum_types[0]); + +/* + * these should currently be in reverse preference order. + * (only relevant for !F_PSEUDO) */ + +struct _krb5_encryption_type *_krb5_etypes[] = { + &_krb5_enctype_aes256_cts_hmac_sha384_192, + &_krb5_enctype_aes128_cts_hmac_sha256_128, + &_krb5_enctype_aes256_cts_hmac_sha1, + &_krb5_enctype_aes128_cts_hmac_sha1, + &_krb5_enctype_des3_cbc_sha1, + &_krb5_enctype_des3_cbc_none, /* used by the gss-api mech */ + &_krb5_enctype_arcfour_hmac_md5, +#ifdef DES3_OLD_ENCTYPE + &_krb5_enctype_des3_cbc_md5, + &_krb5_enctype_old_des3_cbc_sha1, +#endif +#ifdef HEIM_WEAK_CRYPTO + &_krb5_enctype_des_cbc_md5, + &_krb5_enctype_des_cbc_md4, + &_krb5_enctype_des_cbc_crc, + &_krb5_enctype_des_cbc_none, + &_krb5_enctype_des_cfb64_none, + &_krb5_enctype_des_pcbc_none, +#endif + &_krb5_enctype_null +}; + +int _krb5_num_etypes = sizeof(_krb5_etypes) / sizeof(_krb5_etypes[0]); diff --git a/third_party/heimdal/lib/krb5/crypto-arcfour.c b/third_party/heimdal/lib/krb5/crypto-arcfour.c new file mode 100644 index 0000000..28fc52e --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-arcfour.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * ARCFOUR + */ + +#include "krb5_locl.h" + +static struct _krb5_key_type keytype_arcfour = { + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, + "arcfour", + 128, + 16, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_arcfour_salt, + NULL, + _krb5_evp_cleanup, + EVP_rc4 +}; + +/* + * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt + */ + +krb5_error_code +_krb5_HMAC_MD5_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *result) +{ + EVP_MD_CTX *m; + struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); + const char signature[] = "signaturekey"; + Checksum ksign_c; + struct _krb5_key_data ksign; + krb5_keyblock kb; + unsigned char t[4]; + unsigned char tmp[16]; + unsigned char ksign_c_data[16]; + krb5_error_code ret; + int i; + + if (crypto != NULL) { + if (crypto->mdctx == NULL) + crypto->mdctx = EVP_MD_CTX_create(); + if (crypto->mdctx == NULL) + return krb5_enomem(context); + m = crypto->mdctx; + } else + m = EVP_MD_CTX_create(); + + ksign_c.checksum.length = sizeof(ksign_c_data); + ksign_c.checksum.data = ksign_c_data; + ret = _krb5_internal_hmac(context, crypto, c, signature, sizeof(signature), + 0, key, &ksign_c); + if (ret) + goto out; + + ksign.key = &kb; + kb.keyvalue = ksign_c.checksum; + EVP_DigestInit_ex(m, EVP_md5(), NULL); + t[0] = (usage >> 0) & 0xFF; + t[1] = (usage >> 8) & 0xFF; + t[2] = (usage >> 16) & 0xFF; + t[3] = (usage >> 24) & 0xFF; + EVP_DigestUpdate(m, t, 4); + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length); + } + EVP_DigestFinal_ex (m, tmp, NULL); + + ret = _krb5_internal_hmac(context, crypto, c, tmp, sizeof(tmp), 0, &ksign, result); +out: + if (crypto == NULL) + EVP_MD_CTX_destroy(m); + + return ret; +} + +struct _krb5_checksum_type _krb5_checksum_hmac_md5 = { + CKSUMTYPE_HMAC_MD5, + "hmac-md5", + 64, + 16, + F_KEYED | F_CPROOF, + _krb5_HMAC_MD5_checksum, + NULL +}; + +/* + * section 6 of draft-brezak-win2k-krb-rc4-hmac-03 + * + * warning: not for small children + */ + +static krb5_error_code +ARCFOUR_subencrypt(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + unsigned usage, + void *ivec) +{ + EVP_CIPHER_CTX ctx; + struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); + Checksum k1_c, k2_c, k3_c, cksum; + struct _krb5_key_data ke; + krb5_keyblock kb; + unsigned char t[4]; + unsigned char *cdata = data; + unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; + krb5_error_code ret; + + if (len < 16) { + return KRB5KRB_AP_ERR_INAPP_CKSUM; + } + + t[0] = (usage >> 0) & 0xFF; + t[1] = (usage >> 8) & 0xFF; + t[2] = (usage >> 16) & 0xFF; + t[3] = (usage >> 24) & 0xFF; + + k1_c.checksum.length = sizeof(k1_c_data); + k1_c.checksum.data = k1_c_data; + + ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c); + if (ret) + krb5_abortx(context, "hmac failed"); + + memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); + + k2_c.checksum.length = sizeof(k2_c_data); + k2_c.checksum.data = k2_c_data; + + ke.key = &kb; + kb.keyvalue = k2_c.checksum; + + cksum.checksum.length = 16; + cksum.checksum.data = data; + + ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum); + if (ret) + krb5_abortx(context, "hmac failed"); + + ke.key = &kb; + kb.keyvalue = k1_c.checksum; + + k3_c.checksum.length = sizeof(k3_c_data); + k3_c.checksum.data = k3_c_data; + + ret = _krb5_internal_hmac(context, NULL, c, data, 16, 0, &ke, &k3_c); + if (ret) + krb5_abortx(context, "hmac failed"); + + EVP_CIPHER_CTX_init(&ctx); + + EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1); + EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16); + EVP_CIPHER_CTX_cleanup(&ctx); + + memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); + memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); + memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); + return 0; +} + +static krb5_error_code +ARCFOUR_subdecrypt(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + unsigned usage, + void *ivec) +{ + EVP_CIPHER_CTX ctx; + struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); + Checksum k1_c, k2_c, k3_c, cksum; + struct _krb5_key_data ke; + krb5_keyblock kb; + unsigned char t[4]; + unsigned char *cdata = data; + unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; + unsigned char cksum_data[16]; + krb5_error_code ret; + + if (len < 16) { + return KRB5KRB_AP_ERR_INAPP_CKSUM; + } + + t[0] = (usage >> 0) & 0xFF; + t[1] = (usage >> 8) & 0xFF; + t[2] = (usage >> 16) & 0xFF; + t[3] = (usage >> 24) & 0xFF; + + k1_c.checksum.length = sizeof(k1_c_data); + k1_c.checksum.data = k1_c_data; + + ret = _krb5_internal_hmac(context, NULL, c, t, sizeof(t), 0, key, &k1_c); + if (ret) + krb5_abortx(context, "hmac failed"); + + memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); + + k2_c.checksum.length = sizeof(k2_c_data); + k2_c.checksum.data = k2_c_data; + + ke.key = &kb; + kb.keyvalue = k1_c.checksum; + + k3_c.checksum.length = sizeof(k3_c_data); + k3_c.checksum.data = k3_c_data; + + ret = _krb5_internal_hmac(context, NULL, c, cdata, 16, 0, &ke, &k3_c); + if (ret) + krb5_abortx(context, "hmac failed"); + + EVP_CIPHER_CTX_init(&ctx); + EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0); + EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16); + EVP_CIPHER_CTX_cleanup(&ctx); + + ke.key = &kb; + kb.keyvalue = k2_c.checksum; + + cksum.checksum.length = 16; + cksum.checksum.data = cksum_data; + + ret = _krb5_internal_hmac(context, NULL, c, cdata + 16, len - 16, 0, &ke, &cksum); + if (ret) + krb5_abortx(context, "hmac failed"); + + memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); + memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); + memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); + + if (ct_memcmp (cksum.checksum.data, data, 16) != 0) { + krb5_clear_error_message (context); + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + } else { + return 0; + } +} + +/* + * convert the usage numbers used in + * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in + * draft-brezak-win2k-krb-rc4-hmac-04.txt + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_usage2arcfour(krb5_context context, unsigned *usage) +{ + switch (*usage) { + case KRB5_KU_AS_REP_ENC_PART : /* 3 */ + *usage = 8; + return 0; + case KRB5_KU_USAGE_SEAL : /* 22 */ + *usage = 13; + return 0; + case KRB5_KU_USAGE_SIGN : /* 23 */ + *usage = 15; + return 0; + case KRB5_KU_USAGE_SEQ: /* 24 */ + *usage = 0; + return 0; + default : + return 0; + } +} + +static krb5_error_code +ARCFOUR_encrypt(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + krb5_error_code ret; + unsigned keyusage = usage; + + if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0) + return ret; + + if (encryptp) + return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec); + else + return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec); +} + +static krb5_error_code +ARCFOUR_prf(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); + krb5_error_code ret; + Checksum res; + + ret = krb5_data_alloc(out, c->checksumsize); + if (ret) + return ret; + + res.checksum.data = out->data; + res.checksum.length = out->length; + + ret = _krb5_internal_hmac(context, crypto, c, in->data, in->length, 0, &crypto->key, &res); + if (ret) + krb5_data_free(out); + return 0; +} + + +struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { + ETYPE_ARCFOUR_HMAC_MD5, + "arcfour-hmac-md5", + "rc4-hmac", + 1, + 1, + 8, + &keytype_arcfour, + &_krb5_checksum_hmac_md5, + &_krb5_checksum_hmac_md5, + F_SPECIAL | F_WEAK | F_OLD, + ARCFOUR_encrypt, + NULL, + 0, + ARCFOUR_prf +}; diff --git a/third_party/heimdal/lib/krb5/crypto-des-common.c b/third_party/heimdal/lib/krb5/crypto-des-common.c new file mode 100644 index 0000000..a8344ae --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-des-common.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Functions which are used by both single and triple DES enctypes */ + +#include "krb5_locl.h" + +/* + * A = A xor B. A & B are 8 bytes. + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_xor8(unsigned char *a, const unsigned char *b) +{ + a[0] ^= b[0]; + a[1] ^= b[1]; + a[2] ^= b[2]; + a[3] ^= b[3]; + a[4] ^= b[4]; + a[5] ^= b[5]; + a[6] ^= b[6]; + a[7] ^= b[7]; +} + +#if defined(DES3_OLD_ENCTYPE) || defined(HEIM_WEAK_CRYPTO) +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_checksum(krb5_context context, + const EVP_MD *evp_md, + struct _krb5_key_data *key, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *cksum) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_MD_CTX *m; + DES_cblock ivec; + int i; + unsigned char *p = cksum->checksum.data; + + krb5_generate_random_block(p, 8); + + m = EVP_MD_CTX_create(); + if (m == NULL) + return krb5_enomem(context); + + EVP_DigestInit_ex(m, evp_md, NULL); + EVP_DigestUpdate(m, p, 8); + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length); + } + EVP_DigestFinal_ex (m, p + 8, NULL); + EVP_MD_CTX_destroy(m); + memset_s(&ivec, sizeof(ivec), 0, sizeof(ivec)); + EVP_CipherInit_ex(&ctx->ectx, NULL, NULL, NULL, (void *)&ivec, -1); + EVP_Cipher(&ctx->ectx, p, p, 24); + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_verify(krb5_context context, + const EVP_MD *evp_md, + struct _krb5_key_data *key, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_MD_CTX *m; + unsigned char tmp[24]; + unsigned char res[16]; + DES_cblock ivec; + krb5_error_code ret = 0; + int i; + + m = EVP_MD_CTX_create(); + if (m == NULL) + return krb5_enomem(context); + + memset_s(&ivec, sizeof(ivec), 0, sizeof(ivec)); + EVP_CipherInit_ex(&ctx->dctx, NULL, NULL, NULL, (void *)&ivec, -1); + EVP_Cipher(&ctx->dctx, tmp, C->checksum.data, 24); + + EVP_DigestInit_ex(m, evp_md, NULL); + EVP_DigestUpdate(m, tmp, 8); /* confounder */ + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length); + } + EVP_DigestFinal_ex (m, res, NULL); + EVP_MD_CTX_destroy(m); + if(ct_memcmp(res, tmp + 8, sizeof(res)) != 0) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + memset_s(tmp, sizeof(tmp), 0, sizeof(tmp)); + memset_s(res, sizeof(res), 0, sizeof(res)); + return ret; +} + +#endif + +static krb5_error_code +RSA_MD5_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + if (_krb5_evp_digest_iov(crypto, iov, niov, C->checksum.data, + NULL, EVP_md5(), NULL) != 1) + krb5_abortx(context, "md5 checksum failed"); + + return 0; +} + +struct _krb5_checksum_type _krb5_checksum_rsa_md5 = { + CKSUMTYPE_RSA_MD5, + "rsa-md5", + 64, + 16, + F_CPROOF, + RSA_MD5_checksum, + NULL +}; diff --git a/third_party/heimdal/lib/krb5/crypto-des.c b/third_party/heimdal/lib/krb5/crypto-des.c new file mode 100644 index 0000000..c569295 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-des.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifdef HEIM_WEAK_CRYPTO + + +static void +krb5_DES_random_key(krb5_context context, + krb5_keyblock *key) +{ + DES_cblock *k = key->keyvalue.data; + do { + krb5_generate_random_block(k, sizeof(DES_cblock)); + DES_set_odd_parity(k); + } while(DES_is_weak_key(k)); +} + +static void +krb5_DES_schedule_old(krb5_context context, + struct _krb5_key_type *kt, + struct _krb5_key_data *key) +{ + DES_set_key_unchecked(key->key->keyvalue.data, key->schedule->data); +} + +static void +krb5_DES_random_to_key(krb5_context context, + krb5_keyblock *key, + const void *data, + size_t size) +{ + DES_cblock *k = key->keyvalue.data; + memcpy(k, data, key->keyvalue.length); + DES_set_odd_parity(k); + if(DES_is_weak_key(k)) + _krb5_xor8(*k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); +} + +static struct _krb5_key_type keytype_des_old = { + ETYPE_DES_CBC_CRC, + "des-old", + 56, + 8, + sizeof(DES_key_schedule), + krb5_DES_random_key, + krb5_DES_schedule_old, + _krb5_des_salt, + krb5_DES_random_to_key, + NULL, + NULL +}; + +static struct _krb5_key_type keytype_des = { + ETYPE_DES_CBC_CRC, + "des", + 56, + 8, + sizeof(struct _krb5_evp_schedule), + krb5_DES_random_key, + _krb5_evp_schedule, + _krb5_des_salt, + krb5_DES_random_to_key, + _krb5_evp_cleanup, + EVP_des_cbc +}; + +static krb5_error_code +CRC32_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + uint32_t crc = 0; + unsigned char *r = C->checksum.data; + int i; + + _krb5_crc_init_table (); + + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + crc = _krb5_crc_update(iov[i].data.data, iov[i].data.length, crc); + } + + r[0] = crc & 0xff; + r[1] = (crc >> 8) & 0xff; + r[2] = (crc >> 16) & 0xff; + r[3] = (crc >> 24) & 0xff; + return 0; +} + +static krb5_error_code +RSA_MD4_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + if (_krb5_evp_digest_iov(crypto, iov, niov, C->checksum.data, + NULL, EVP_md4(), NULL) != 1) + krb5_abortx(context, "md4 checksum failed"); + return 0; +} + +static krb5_error_code +RSA_MD4_DES_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *cksum) +{ + return _krb5_des_checksum(context, EVP_md4(), key, iov, niov, cksum); +} + +static krb5_error_code +RSA_MD4_DES_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, EVP_md4(), key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_checksum(context, EVP_md5(), key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, EVP_md5(), key, iov, niov, C); +} + +struct _krb5_checksum_type _krb5_checksum_crc32 = { + CKSUMTYPE_CRC32, + "crc32", + 1, + 4, + 0, + CRC32_checksum, + NULL +}; + +struct _krb5_checksum_type _krb5_checksum_rsa_md4 = { + CKSUMTYPE_RSA_MD4, + "rsa-md4", + 64, + 16, + F_CPROOF, + RSA_MD4_checksum, + NULL +}; + +struct _krb5_checksum_type _krb5_checksum_rsa_md4_des = { + CKSUMTYPE_RSA_MD4_DES, + "rsa-md4-des", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD4_DES_checksum, + RSA_MD4_DES_verify +}; + +struct _krb5_checksum_type _krb5_checksum_rsa_md5_des = { + CKSUMTYPE_RSA_MD5_DES, + "rsa-md5-des", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD5_DES_checksum, + RSA_MD5_DES_verify +}; + +static krb5_error_code +evp_des_encrypt_null_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_CIPHER_CTX *c; + DES_cblock ivec; + memset(&ivec, 0, sizeof(ivec)); + c = encryptp ? &ctx->ectx : &ctx->dctx; + EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1); + EVP_Cipher(c, data, data, len); + return 0; +} + +static krb5_error_code +evp_des_encrypt_key_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_CIPHER_CTX *c; + DES_cblock ivec; + memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec)); + c = encryptp ? &ctx->ectx : &ctx->dctx; + EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1); + EVP_Cipher(c, data, data, len); + return 0; +} + +static krb5_error_code +DES_CFB64_encrypt_null_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + DES_cblock ivec; + int num = 0; + DES_key_schedule *s = key->schedule->data; + memset(&ivec, 0, sizeof(ivec)); + + DES_cfb64_encrypt(data, data, len, s, &ivec, &num, encryptp); + return 0; +} + +static krb5_error_code +DES_PCBC_encrypt_key_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + DES_cblock ivec; + DES_key_schedule *s = key->schedule->data; + memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec)); + + DES_pcbc_encrypt(data, data, len, s, &ivec, encryptp); + return 0; +} + +struct _krb5_encryption_type _krb5_enctype_des_cbc_crc = { + ETYPE_DES_CBC_CRC, + "des-cbc-crc", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_crc32, + NULL, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_key_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_md4 = { + ETYPE_DES_CBC_MD4, + "des-cbc-md4", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_rsa_md4, + &_krb5_checksum_rsa_md4_des, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_md5 = { + ETYPE_DES_CBC_MD5, + "des-cbc-md5", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_rsa_md5, + &_krb5_checksum_rsa_md5_des, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_none = { + ETYPE_DES_CBC_NONE, + "des-cbc-none", + NULL, + 8, + 8, + 0, + &keytype_des, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cfb64_none = { + ETYPE_DES_CFB64_NONE, + "des-cfb64-none", + NULL, + 1, + 1, + 0, + &keytype_des_old, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + DES_CFB64_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_pcbc_none = { + ETYPE_DES_PCBC_NONE, + "des-pcbc-none", + NULL, + 8, + 8, + 0, + &keytype_des_old, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + DES_PCBC_encrypt_key_ivec, + NULL, + 0, + NULL +}; +#endif /* HEIM_WEAK_CRYPTO */ diff --git a/third_party/heimdal/lib/krb5/crypto-des3.c b/third_party/heimdal/lib/krb5/crypto-des3.c new file mode 100644 index 0000000..d231921 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-des3.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * + */ + +static void +DES3_random_key(krb5_context context, + krb5_keyblock *key) +{ + DES_cblock *k = key->keyvalue.data; + do { + krb5_generate_random_block(k, 3 * sizeof(DES_cblock)); + DES_set_odd_parity(&k[0]); + DES_set_odd_parity(&k[1]); + DES_set_odd_parity(&k[2]); + } while(DES_is_weak_key(&k[0]) || + DES_is_weak_key(&k[1]) || + DES_is_weak_key(&k[2])); +} + +static krb5_error_code +DES3_prf(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + struct _krb5_checksum_type *ct = crypto->et->checksum; + struct krb5_crypto_iov iov[1]; + krb5_error_code ret; + Checksum result; + krb5_keyblock *derived; + + result.cksumtype = ct->type; + ret = krb5_data_alloc(&result.checksum, ct->checksumsize); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out memory", "")); + return ret; + } + + iov[0].data = *in; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = (*ct->checksum)(context, crypto, NULL, 0, iov, 1, &result); + if (ret) { + krb5_data_free(&result.checksum); + return ret; + } + + if (result.checksum.length < crypto->et->blocksize) + krb5_abortx(context, "internal prf error"); + + derived = NULL; + ret = krb5_derive_key(context, crypto->key.key, + crypto->et->type, "prf", 3, &derived); + if (ret) + krb5_abortx(context, "krb5_derive_key"); + + ret = krb5_data_alloc(out, crypto->et->prf_length); + if (ret) + krb5_abortx(context, "malloc failed"); + + { + const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); + EVP_CIPHER_CTX ctx; + + EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ + EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); + EVP_Cipher(&ctx, out->data, result.checksum.data, + crypto->et->prf_length); + EVP_CIPHER_CTX_cleanup(&ctx); + } + + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + + return ret; +} + +#ifdef DES3_OLD_ENCTYPE +static struct _krb5_key_type keytype_des3 = { + ETYPE_OLD_DES3_CBC_SHA1, + "des3", + 168, + 24, + sizeof(struct _krb5_evp_schedule), + DES3_random_key, + _krb5_evp_schedule, + _krb5_des3_salt, + _krb5_DES3_random_to_key, + _krb5_evp_cleanup, + EVP_des_ede3_cbc +}; +#endif + +static struct _krb5_key_type keytype_des3_derived = { + ETYPE_OLD_DES3_CBC_SHA1, + "des3", + 168, + 24, + sizeof(struct _krb5_evp_schedule), + DES3_random_key, + _krb5_evp_schedule, + _krb5_des3_salt_derived, + _krb5_DES3_random_to_key, + _krb5_evp_cleanup, + EVP_des_ede3_cbc +}; + +#ifdef DES3_OLD_ENCTYPE +static krb5_error_code +RSA_MD5_DES3_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_checksum(context, EVP_md5(), key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES3_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, EVP_md5(), key, iov, niov, C); +} + +struct _krb5_checksum_type _krb5_checksum_rsa_md5_des3 = { + CKSUMTYPE_RSA_MD5_DES3, + "rsa-md5-des3", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD5_DES3_checksum, + RSA_MD5_DES3_verify +}; +#endif + +struct _krb5_checksum_type _krb5_checksum_hmac_sha1_des3 = { + CKSUMTYPE_HMAC_SHA1_DES3, + "hmac-sha1-des3", + 64, + 20, + F_KEYED | F_CPROOF | F_DERIVED, + _krb5_SP_HMAC_SHA1_checksum, + NULL +}; + +#ifdef DES3_OLD_ENCTYPE +struct _krb5_encryption_type _krb5_enctype_des3_cbc_md5 = { + ETYPE_DES3_CBC_MD5, + "des3-cbc-md5", + NULL, + 8, + 8, + 8, + &keytype_des3, + &_krb5_checksum_rsa_md5, + &_krb5_checksum_rsa_md5_des3, + F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; +#endif + +struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1 = { + ETYPE_DES3_CBC_SHA1, + "des3-cbc-sha1", + NULL, + 8, + 8, + 8, + &keytype_des3_derived, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_des3, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF | F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 16, + DES3_prf +}; + +#ifdef DES3_OLD_ENCTYPE +struct _krb5_encryption_type _krb5_enctype_old_des3_cbc_sha1 = { + ETYPE_OLD_DES3_CBC_SHA1, + "old-des3-cbc-sha1", + NULL, + 8, + 8, + 8, + &keytype_des3, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_des3, + F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; +#endif + +struct _krb5_encryption_type _krb5_enctype_des3_cbc_none = { + ETYPE_DES3_CBC_NONE, + "des3-cbc-none", + NULL, + 8, + 8, + 0, + &keytype_des3_derived, + &_krb5_checksum_none, + NULL, + F_PSEUDO | F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; + +void +_krb5_DES3_random_to_key(krb5_context context, + krb5_keyblock *key, + const void *data, + size_t size) +{ + unsigned char *x = key->keyvalue.data; + const u_char *q = data; + DES_cblock *k; + int i, j; + + memset(key->keyvalue.data, 0, key->keyvalue.length); + for (i = 0; i < 3; ++i) { + unsigned char foo; + for (j = 0; j < 7; ++j) { + unsigned char b = q[7 * i + j]; + + x[8 * i + j] = b; + } + foo = 0; + for (j = 6; j >= 0; --j) { + foo |= q[7 * i + j] & 1; + foo <<= 1; + } + x[8 * i + 7] = foo; + } + k = key->keyvalue.data; + for (i = 0; i < 3; i++) { + DES_set_odd_parity(&k[i]); + if(DES_is_weak_key(&k[i])) + _krb5_xor8(k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); + } +} diff --git a/third_party/heimdal/lib/krb5/crypto-evp.c b/third_party/heimdal/lib/krb5/crypto-evp.c new file mode 100644 index 0000000..82237f1 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-evp.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +void +_krb5_evp_schedule(krb5_context context, + struct _krb5_key_type *kt, + struct _krb5_key_data *kd) +{ + struct _krb5_evp_schedule *key = kd->schedule->data; + const EVP_CIPHER *c = (*kt->evp)(); + + EVP_CIPHER_CTX_init(&key->ectx); + EVP_CIPHER_CTX_init(&key->dctx); + + EVP_CipherInit_ex(&key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1); + EVP_CipherInit_ex(&key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0); +} + +void +_krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd) +{ + struct _krb5_evp_schedule *key = kd->schedule->data; + EVP_CIPHER_CTX_cleanup(&key->ectx); + EVP_CIPHER_CTX_cleanup(&key->dctx); +} + +int +_krb5_evp_digest_iov(krb5_crypto crypto, + const struct krb5_crypto_iov *iov, + int niov, + void *hash, + unsigned int *hsize, + const EVP_MD *md, + ENGINE *engine) +{ + EVP_MD_CTX *ctx; + int ret, i; + krb5_data current = {0,0}; + + if (crypto != NULL) { + if (crypto->mdctx == NULL) + crypto->mdctx = EVP_MD_CTX_create(); + if (crypto->mdctx == NULL) + return 0; + ctx = crypto->mdctx; + } else + ctx = EVP_MD_CTX_create(); + + ret = EVP_DigestInit_ex(ctx, md, engine); + if (ret != 1) + goto out; + + /* Minimize EVP calls by coalescing contiguous iovec elements */ + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) { + if (current.data && + (char *)current.data + current.length == iov[i].data.data) { + current.length += iov[i].data.length; + } else { + if (current.data) { + ret = EVP_DigestUpdate(ctx, current.data, current.length); + if (ret != 1) + goto out; + } + current = iov[i].data; + } + } + } + + if (current.data) { + ret = EVP_DigestUpdate(ctx, current.data, current.length); + if (ret != 1) + goto out; + } + + ret = EVP_DigestFinal_ex(ctx, hash, hsize); + +out: + if (crypto == NULL) + EVP_MD_CTX_destroy(ctx); + + return ret; +} + +krb5_error_code +_krb5_evp_hmac_iov(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + const struct krb5_crypto_iov *iov, + int niov, + void *hmac, + unsigned int *hmaclen, + const EVP_MD *md, + ENGINE *engine) +{ + HMAC_CTX *ctx; + krb5_data current = {0, NULL}; + int i; + + if (crypto != NULL) { + if (crypto->hmacctx == NULL) + crypto->hmacctx = HMAC_CTX_new(); + ctx = crypto->hmacctx; + } else { + ctx = HMAC_CTX_new(); + } + if (ctx == NULL) + return krb5_enomem(context); + + if (HMAC_Init_ex(ctx, key->key->keyvalue.data, key->key->keyvalue.length, + md, engine) == 0) { + HMAC_CTX_free(ctx); + return krb5_enomem(context); + } + + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) { + if (current.data && + (char *)current.data + current.length == iov[i].data.data) { + current.length += iov[i].data.length; + } else { + if (current.data) + HMAC_Update(ctx, current.data, current.length); + current = iov[i].data; + } + } + } + + if (current.data) + HMAC_Update(ctx, current.data, current.length); + + HMAC_Final(ctx, hmac, hmaclen); + + if (crypto == NULL) + HMAC_CTX_free(ctx); + + return 0; +} + +krb5_error_code +_krb5_evp_encrypt(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_CIPHER_CTX *c; + c = encryptp ? &ctx->ectx : &ctx->dctx; + if (ivec == NULL) { + /* alloca ? */ + size_t len2 = EVP_CIPHER_CTX_iv_length(c); + void *loiv = malloc(len2); + if (loiv == NULL) + return krb5_enomem(context); + memset(loiv, 0, len2); + EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1); + free(loiv); + } else + EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); + EVP_Cipher(c, data, data, len); + return 0; +} + +struct _krb5_evp_iov_cursor +{ + struct krb5_crypto_iov *iov; + int niov; + krb5_data current; + int nextidx; +}; + +static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 }; + +static inline int +_krb5_evp_iov_should_encrypt(struct krb5_crypto_iov *iov) +{ + return (iov->flags == KRB5_CRYPTO_TYPE_DATA + || iov->flags == KRB5_CRYPTO_TYPE_HEADER + || iov->flags == KRB5_CRYPTO_TYPE_PADDING); +} +/* + * If we have a group of iovecs which have been split up from + * a single common buffer, expand the 'current' iovec out to + * be as large as possible. + */ + +static inline void +_krb5_evp_iov_cursor_expand(struct _krb5_evp_iov_cursor *cursor) +{ + if (cursor->nextidx == cursor->niov) + return; + + while (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx])) { + if (cursor->iov[cursor->nextidx].data.length != 0 && + ((char *)cursor->current.data + cursor->current.length + != cursor->iov[cursor->nextidx].data.data)) { + return; + } + cursor->current.length += cursor->iov[cursor->nextidx].data.length; + cursor->nextidx++; + } + + return; +} + +/* Move the cursor along to the start of the next block to be + * encrypted */ +static inline void +_krb5_evp_iov_cursor_nextcrypt(struct _krb5_evp_iov_cursor *cursor) +{ + for (; cursor->nextidx < cursor->niov; cursor->nextidx++) { + if (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx]) + && cursor->iov[cursor->nextidx].data.length != 0) { + cursor->current = cursor->iov[cursor->nextidx].data; + cursor->nextidx++; + _krb5_evp_iov_cursor_expand(cursor); + return; + } + } + + cursor->current.length = 0; /* No matches, so we're done here */ +} + +static inline void +_krb5_evp_iov_cursor_init(struct _krb5_evp_iov_cursor *cursor, + struct krb5_crypto_iov *iov, int niov) +{ + memset(cursor, 0, sizeof(struct _krb5_evp_iov_cursor)); + + cursor->iov = iov; + cursor->niov = niov; + cursor->nextidx = 0; + + /* Move along to the first block we're going to be encrypting */ + _krb5_evp_iov_cursor_nextcrypt(cursor); +} + +static inline void +_krb5_evp_iov_cursor_advance(struct _krb5_evp_iov_cursor *cursor, + size_t amount) +{ + while (amount > 0) { + if (cursor->current.length > amount) { + cursor->current.data = (char *)cursor->current.data + amount; + cursor->current.length -= amount; + return; + } + amount -= cursor->current.length; + _krb5_evp_iov_cursor_nextcrypt(cursor); + } +} + +static inline int +_krb5_evp_iov_cursor_done(struct _krb5_evp_iov_cursor *cursor) +{ + return (cursor->nextidx == cursor->niov && cursor->current.length == 0); +} + +/* Fill a memory buffer with data from one or more iovecs. Doesn't + * advance the passed in cursor - use outcursor for the position + * at the end + */ +static inline void +_krb5_evp_iov_cursor_fillbuf(struct _krb5_evp_iov_cursor *cursor, + unsigned char *buf, size_t length, + struct _krb5_evp_iov_cursor *outcursor) +{ + struct _krb5_evp_iov_cursor cursorint; + + cursorint = *cursor; + + while (length > 0 && !_krb5_evp_iov_cursor_done(&cursorint)) { + if (cursorint.current.length > length) { + memcpy(buf, cursorint.current.data, length); + _krb5_evp_iov_cursor_advance(&cursorint, length); + length = 0; + } else { + memcpy(buf, cursorint.current.data, cursorint.current.length); + length -= cursorint.current.length; + buf += cursorint.current.length; + _krb5_evp_iov_cursor_nextcrypt(&cursorint); + } + } + + if (outcursor != NULL) + *outcursor = cursorint; +} + +/* Fill an iovec from a memory buffer. Always advances the cursor to + * the end of the filled region + */ +static inline void +_krb5_evp_iov_cursor_fillvec(struct _krb5_evp_iov_cursor *cursor, + unsigned char *buf, size_t length) +{ + while (length > 0 && !_krb5_evp_iov_cursor_done(cursor)) { + if (cursor->current.length > length) { + memcpy(cursor->current.data, buf, length); + _krb5_evp_iov_cursor_advance(cursor, length); + length = 0; + } else { + memcpy(cursor->current.data, buf, cursor->current.length); + length -= cursor->current.length; + buf += cursor->current.length; + _krb5_evp_iov_cursor_nextcrypt(cursor); + } + } +} + +static size_t +_krb5_evp_iov_cryptlength(struct krb5_crypto_iov *iov, int niov) +{ + int i; + size_t length = 0; + + for (i = 0; i < niov; i++) { + if (_krb5_evp_iov_should_encrypt(&iov[i])) + length += iov[i].data.length; + } + + return length; +} + +int +_krb5_evp_encrypt_iov(krb5_context context, + struct _krb5_key_data *key, + struct krb5_crypto_iov *iov, + int niov, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + size_t blocksize, blockmask, wholeblocks; + struct _krb5_evp_schedule *ctx = key->schedule->data; + unsigned char tmp[EVP_MAX_BLOCK_LENGTH]; + EVP_CIPHER_CTX *c; + struct _krb5_evp_iov_cursor cursor; + + c = encryptp ? &ctx->ectx : &ctx->dctx; + + blocksize = EVP_CIPHER_CTX_block_size(c); + + blockmask = ~(blocksize - 1); + + if (ivec) + EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); + else + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + + _krb5_evp_iov_cursor_init(&cursor, iov, niov); + + while (!_krb5_evp_iov_cursor_done(&cursor)) { + + /* Number of bytes of data in this iovec that are in whole blocks */ + wholeblocks = cursor.current.length & ~blockmask; + + if (wholeblocks != 0) { + EVP_Cipher(c, cursor.current.data, + cursor.current.data, wholeblocks); + _krb5_evp_iov_cursor_advance(&cursor, wholeblocks); + } + + /* If there's a partial block of data remaining in the current + * iovec, steal enough from subsequent iovecs to form a whole block */ + if (cursor.current.length > 0 && cursor.current.length < blocksize) { + /* Build up a block's worth of data in tmp, leaving the cursor + * pointing at where we started */ + _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, NULL); + + EVP_Cipher(c, tmp, tmp, blocksize); + + /* Copy the data in tmp back into the iovecs that it came from, + * advancing the cursor */ + _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize); + } + } + + return 0; +} + +int +_krb5_evp_encrypt_iov_cts(krb5_context context, + struct _krb5_key_data *key, + struct krb5_crypto_iov *iov, + int niov, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + size_t blocksize, blockmask, wholeblocks, length; + size_t remaining, partiallen; + struct _krb5_evp_iov_cursor cursor, lastpos; + struct _krb5_evp_schedule *ctx = key->schedule->data; + unsigned char tmp[EVP_MAX_BLOCK_LENGTH], tmp2[EVP_MAX_BLOCK_LENGTH]; + unsigned char tmp3[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH]; + EVP_CIPHER_CTX *c; + int i; + + c = encryptp ? &ctx->ectx : &ctx->dctx; + + blocksize = EVP_CIPHER_CTX_block_size(c); + blockmask = ~(blocksize - 1); + + length = _krb5_evp_iov_cryptlength(iov, niov); + + if (length < blocksize) { + krb5_set_error_message(context, EINVAL, + "message block too short"); + return EINVAL; + } + + if (length == blocksize) + return _krb5_evp_encrypt_iov(context, key, iov, niov, + encryptp, usage, ivec); + + if (ivec) + EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); + else + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + + if (encryptp) { + /* On our first pass, we want to process everything but the + * final partial block */ + remaining = ((length - 1) & blockmask); + partiallen = length - remaining; + + memset(&lastpos, 0, sizeof(lastpos)); /* Keep the compiler happy */ + } else { + /* Decryption needs to leave 2 whole blocks and a partial for + * further processing */ + if (length > 2 * blocksize) { + remaining = (((length - 1) / blocksize) * blocksize) - (blocksize*2); + partiallen = length - remaining - (blocksize * 2); + } else { + remaining = 0; + partiallen = length - blocksize; + } + } + + _krb5_evp_iov_cursor_init(&cursor, iov, niov); + while (remaining > 0) { + /* If the iovec has more data than we need, just use it */ + if (cursor.current.length >= remaining) { + EVP_Cipher(c, cursor.current.data, cursor.current.data, remaining); + + if (encryptp) { + /* We've just encrypted the last block of data. Make a copy + * of it (and its location) for the CTS dance, below */ + lastpos = cursor; + _krb5_evp_iov_cursor_advance(&lastpos, remaining - blocksize); + memcpy(ivec2, lastpos.current.data, blocksize); + } + + _krb5_evp_iov_cursor_advance(&cursor, remaining); + remaining = 0; + } else { + /* Use as much as we can, firstly all of the whole blocks */ + wholeblocks = cursor.current.length & blockmask; + + if (wholeblocks > 0) { + EVP_Cipher(c, cursor.current.data, cursor.current.data, + wholeblocks); + _krb5_evp_iov_cursor_advance(&cursor, wholeblocks); + remaining -= wholeblocks; + } + + /* Then, if we have partial data left, steal enough from subsequent + * iovecs to make a whole block */ + if (cursor.current.length > 0 && cursor.current.length < blocksize) { + if (encryptp && remaining == blocksize) + lastpos = cursor; + + _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL); + EVP_Cipher(c, ivec2, ivec2, blocksize); + _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, blocksize); + + remaining -= blocksize; + } + } + } + + /* Encryption */ + if (encryptp) { + /* Copy the partial block into tmp */ + _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, partiallen, NULL); + + /* XOR the final partial block with ivec2 */ + for (i = 0; i < partiallen; i++) + tmp[i] = tmp[i] ^ ivec2[i]; + for (; i < blocksize; i++) + tmp[i] = 0 ^ ivec2[i]; /* XOR 0s if partial block exhausted */ + + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, tmp, tmp, blocksize); + + _krb5_evp_iov_cursor_fillvec(&lastpos, tmp, blocksize); + _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, partiallen); + + if (ivec) + memcpy(ivec, tmp, blocksize); + + return 0; + } + + /* Decryption */ + + /* Make a copy of the 2nd last full ciphertext block in ivec2 before + * decrypting it. If no such block exists, use ivec or zero_ivec */ + if (length <= blocksize * 2) { + if (ivec) + memcpy(ivec2, ivec, blocksize); + else + memcpy(ivec2, zero_ivec, blocksize); + } else { + _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL); + EVP_Cipher(c, tmp, ivec2, blocksize); + _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize); + } + + lastpos = cursor; /* Remember where the last block is */ + _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, &cursor); + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, tmp2, tmp, blocksize); /* tmp eventually becomes output ivec */ + + _krb5_evp_iov_cursor_fillbuf(&cursor, tmp3, partiallen, NULL); + + memcpy(tmp3 + partiallen, tmp2 + partiallen, blocksize - partiallen); /* xor 0 */ + for (i = 0; i < partiallen; i++) + tmp2[i] = tmp2[i] ^ tmp3[i]; + + _krb5_evp_iov_cursor_fillvec(&cursor, tmp2, partiallen); + + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, tmp3, tmp3, blocksize); + + for (i = 0; i < blocksize; i++) + tmp3[i] ^= ivec2[i]; + + _krb5_evp_iov_cursor_fillvec(&lastpos, tmp3, blocksize); + + if (ivec) + memcpy(ivec, tmp, blocksize); + + return 0; +} + +krb5_error_code +_krb5_evp_encrypt_cts(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + size_t i, blocksize; + struct _krb5_evp_schedule *ctx = key->schedule->data; + unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH]; + EVP_CIPHER_CTX *c; + unsigned char *p; + + c = encryptp ? &ctx->ectx : &ctx->dctx; + + blocksize = EVP_CIPHER_CTX_block_size(c); + + if (len < blocksize) { + krb5_set_error_message(context, EINVAL, + "message block too short"); + return EINVAL; + } else if (len == blocksize) { + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, data, data, len); + return 0; + } + + if (ivec) + EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); + else + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + + if (encryptp) { + + p = data; + i = ((len - 1) / blocksize) * blocksize; + EVP_Cipher(c, p, p, i); + p += i - blocksize; + len -= i; + memcpy(ivec2, p, blocksize); + + for (i = 0; i < len; i++) + tmp[i] = p[i + blocksize] ^ ivec2[i]; + for (; i < blocksize; i++) + tmp[i] = 0 ^ ivec2[i]; + + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, p, tmp, blocksize); + + memcpy(p + blocksize, ivec2, len); + if (ivec) + memcpy(ivec, p, blocksize); + } else { + unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH]; + + p = data; + if (len > blocksize * 2) { + /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */ + i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize); + memcpy(ivec2, p + i - blocksize, blocksize); + EVP_Cipher(c, p, p, i); + p += i; + len -= i + blocksize; + } else { + if (ivec) + memcpy(ivec2, ivec, blocksize); + else + memcpy(ivec2, zero_ivec, blocksize); + len -= blocksize; + } + + memcpy(tmp, p, blocksize); + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, tmp2, p, blocksize); + + memcpy(tmp3, p + blocksize, len); + memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */ + + for (i = 0; i < len; i++) + p[i + blocksize] = tmp2[i] ^ tmp3[i]; + + EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); + EVP_Cipher(c, p, tmp3, blocksize); + + for (i = 0; i < blocksize; i++) + p[i] ^= ivec2[i]; + if (ivec) + memcpy(ivec, tmp, blocksize); + } + return 0; +} diff --git a/third_party/heimdal/lib/krb5/crypto-null.c b/third_party/heimdal/lib/krb5/crypto-null.c new file mode 100644 index 0000000..a62a57f --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-null.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER +#define DES3_OLD_ENCTYPE 1 +#endif + +static struct _krb5_key_type keytype_null = { + KRB5_ENCTYPE_NULL, + "null", + 0, + 0, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static krb5_error_code +NONE_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return 0; +} + +struct _krb5_checksum_type _krb5_checksum_none = { + CKSUMTYPE_NONE, + "none", + 1, + 0, + 0, + NONE_checksum, + NULL +}; + +static krb5_error_code +NULL_encrypt(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ivec) +{ + return 0; +} + +struct _krb5_encryption_type _krb5_enctype_null = { + ETYPE_NULL, + "null", + NULL, + 1, + 1, + 0, + &keytype_null, + &_krb5_checksum_none, + NULL, + F_DISABLED | F_OLD, + NULL_encrypt, + NULL, + 0, + NULL +}; diff --git a/third_party/heimdal/lib/krb5/crypto-pk.c b/third_party/heimdal/lib/krb5/crypto-pk.c new file mode 100644 index 0000000..24a07cd --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-pk.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#include + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_pk_octetstring2key(krb5_context context, + krb5_enctype type, + const void *dhdata, + size_t dhsize, + const heim_octet_string *c_n, + const heim_octet_string *k_n, + krb5_keyblock *key) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + krb5_error_code ret; + size_t keylen, offset; + void *keydata; + unsigned char counter; + unsigned char shaoutput[SHA_DIGEST_LENGTH]; + EVP_MD_CTX *m; + + if(et == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + type); + return KRB5_PROG_ETYPE_NOSUPP; + } + keylen = (et->keytype->bits + 7) / 8; + + keydata = malloc(keylen); + if (keydata == NULL) + return krb5_enomem(context); + + m = EVP_MD_CTX_create(); + if (m == NULL) { + free(keydata); + return krb5_enomem(context); + } + + counter = 0; + offset = 0; + do { + + EVP_DigestInit_ex(m, EVP_sha1(), NULL); + EVP_DigestUpdate(m, &counter, 1); + EVP_DigestUpdate(m, dhdata, dhsize); + + if (c_n) + EVP_DigestUpdate(m, c_n->data, c_n->length); + if (k_n) + EVP_DigestUpdate(m, k_n->data, k_n->length); + + EVP_DigestFinal_ex(m, shaoutput, NULL); + + memcpy((unsigned char *)keydata + offset, + shaoutput, + min(keylen - offset, sizeof(shaoutput))); + + offset += sizeof(shaoutput); + counter++; + } while(offset < keylen); + memset_s(shaoutput, sizeof(shaoutput), 0, sizeof(shaoutput)); + + EVP_MD_CTX_destroy(m); + + ret = krb5_random_to_key(context, type, keydata, keylen, key); + memset_s(keydata, sizeof(keylen), 0, sizeof(keylen)); + free(keydata); + return ret; +} + +static krb5_error_code +encode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data) +{ + KRB5PrincipalName pn; + krb5_error_code ret; + size_t size = 0; + + pn.principalName = p->name; + pn.realm = p->realm; + + ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length, + &pn, &size, ret); + if (ret) { + krb5_data_zero(data); + krb5_set_error_message(context, ret, + N_("Failed to encode KRB5PrincipalName", "")); + return ret; + } + if (data->length != size) + krb5_abortx(context, "asn1 compiler internal error"); + return 0; +} + +static krb5_error_code +encode_otherinfo(krb5_context context, + const AlgorithmIdentifier *ai, + krb5_const_principal client, + krb5_const_principal server, + krb5_enctype enctype, + const krb5_data *as_req, + const krb5_data *pk_as_rep, + const Ticket *ticket, + krb5_data *other) +{ + PkinitSP80056AOtherInfo otherinfo; + PkinitSuppPubInfo pubinfo; + krb5_error_code ret; + krb5_data pub; + size_t size = 0; + + krb5_data_zero(other); + memset(&otherinfo, 0, sizeof(otherinfo)); + memset(&pubinfo, 0, sizeof(pubinfo)); + + pubinfo.enctype = enctype; + pubinfo.as_REQ = *as_req; + pubinfo.pk_as_rep = *pk_as_rep; + pubinfo.ticket = *ticket; + ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length, + &pubinfo, &size, ret); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + return ret; + } + if (pub.length != size) + krb5_abortx(context, "asn1 compiler internal error"); + + ret = encode_uvinfo(context, client, &otherinfo.partyUInfo); + if (ret) { + free(pub.data); + return ret; + } + ret = encode_uvinfo(context, server, &otherinfo.partyVInfo); + if (ret) { + free(otherinfo.partyUInfo.data); + free(pub.data); + return ret; + } + + otherinfo.algorithmID = *ai; + otherinfo.suppPubInfo = &pub; + + ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length, + &otherinfo, &size, ret); + free(otherinfo.partyUInfo.data); + free(otherinfo.partyVInfo.data); + free(pub.data); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + return ret; + } + if (other->length != size) + krb5_abortx(context, "asn1 compiler internal error"); + + return 0; +} + + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_pk_kdf(krb5_context context, + const struct AlgorithmIdentifier *ai, + const void *dhdata, + size_t dhsize, + krb5_const_principal client, + krb5_const_principal server, + krb5_enctype enctype, + const krb5_data *as_req, + const krb5_data *pk_as_rep, + const Ticket *ticket, + krb5_keyblock *key) +{ + struct _krb5_encryption_type *et; + krb5_error_code ret; + krb5_data other; + size_t keylen, offset; + uint32_t counter; + unsigned char *keydata; + unsigned char shaoutput[SHA512_DIGEST_LENGTH]; + const EVP_MD *md; + EVP_MD_CTX *m; + + if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { + md = EVP_sha1(); + } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { + md = EVP_sha256(); + } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { + md = EVP_sha512(); + } else { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("KDF not supported", "")); + return KRB5_PROG_ETYPE_NOSUPP; + } + if (ai->parameters != NULL && + (ai->parameters->length != 2 || + memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) + { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("kdf params not NULL or the NULL-type", + "")); + return KRB5_PROG_ETYPE_NOSUPP; + } + + et = _krb5_find_enctype(enctype); + if(et == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + enctype); + return KRB5_PROG_ETYPE_NOSUPP; + } + keylen = (et->keytype->bits + 7) / 8; + + keydata = malloc(keylen); + if (keydata == NULL) + return krb5_enomem(context); + + ret = encode_otherinfo(context, ai, client, server, + enctype, as_req, pk_as_rep, ticket, &other); + if (ret) { + free(keydata); + return ret; + } + + m = EVP_MD_CTX_create(); + if (m == NULL) { + free(keydata); + free(other.data); + return krb5_enomem(context); + } + + offset = 0; + counter = 1; + do { + unsigned char cdata[4]; + + EVP_DigestInit_ex(m, md, NULL); + _krb5_put_int(cdata, counter, 4); + EVP_DigestUpdate(m, cdata, 4); + EVP_DigestUpdate(m, dhdata, dhsize); + EVP_DigestUpdate(m, other.data, other.length); + + EVP_DigestFinal_ex(m, shaoutput, NULL); + + memcpy((unsigned char *)keydata + offset, + shaoutput, + min(keylen - offset, EVP_MD_CTX_size(m))); + + offset += EVP_MD_CTX_size(m); + counter++; + } while(offset < keylen); + memset_s(shaoutput, sizeof(shaoutput), 0, sizeof(shaoutput)); + + EVP_MD_CTX_destroy(m); + free(other.data); + + ret = krb5_random_to_key(context, enctype, keydata, keylen, key); + memset_s(keydata, sizeof(keylen), 0, sizeof(keylen)); + free(keydata); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/crypto-rand.c b/third_party/heimdal/lib/krb5/crypto-rand.c new file mode 100644 index 0000000..7b126c6 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-rand.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#undef HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE +#define HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE + +#define ENTROPY_NEEDED 128 + +static HEIMDAL_MUTEX crypto_mutex = HEIMDAL_MUTEX_INITIALIZER; + +static int +seed_something(void) +{ +#ifndef NO_RANDFILE + char buf[1024], seedfile[256]; + + /* If there is a seed file, load it. But such a file cannot be trusted, + so use 0 for the entropy estimate */ + if (RAND_file_name(seedfile, sizeof(seedfile))) { + int fd; + fd = open(seedfile, O_RDONLY | O_BINARY | O_CLOEXEC); + if (fd >= 0) { + ssize_t ret; + rk_cloexec(fd); + ret = read(fd, buf, sizeof(buf)); + if (ret > 0) + RAND_add(buf, ret, 0.0); + close(fd); + } else + seedfile[0] = '\0'; + } else + seedfile[0] = '\0'; +#endif + + /* Calling RAND_status() will try to use /dev/urandom if it exists so + we do not have to deal with it. */ + if (RAND_status() != 1) { + /* TODO: Once a Windows CryptoAPI RAND method is defined, we + can use that and failover to another method. */ + } + + if (RAND_status() == 1) { +#ifndef NO_RANDFILE + /* Update the seed file */ + if (seedfile[0]) + RAND_write_file(seedfile); +#endif + + return 0; + } else + return -1; +} + +/** + * Fill buffer buf with len bytes of PRNG randomness that is ok to use + * for key generation, padding and public diclosing the randomness w/o + * disclosing the randomness source. + * + * This function can fail, and callers must check the return value. + * + * @param buf a buffer to fill with randomness + * @param len length of memory that buf points to. + * + * @return return 0 on success or HEIM_ERR_RANDOM_OFFLINE if the + * funcation failed to initialize the randomness source. + * + * @ingroup krb5_crypto + */ + +HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_generate_random(void *buf, size_t len) +{ + static int rng_initialized = 0; + int ret; + + HEIMDAL_MUTEX_lock(&crypto_mutex); + if (!rng_initialized) { + if (seed_something()) { + HEIMDAL_MUTEX_unlock(&crypto_mutex); + return HEIM_ERR_RANDOM_OFFLINE; + } + rng_initialized = 1; + } + if (RAND_bytes(buf, len) <= 0) + ret = HEIM_ERR_RANDOM_OFFLINE; + else + ret = 0; + HEIMDAL_MUTEX_unlock(&crypto_mutex); + + return ret; +} + +/** + * Fill buffer buf with len bytes of PRNG randomness that is ok to use + * for key generation, padding and public diclosing the randomness w/o + * disclosing the randomness source. + * + * This function can NOT fail, instead it will abort() and program will crash. + * + * If this function is called after a successful krb5_init_context(), + * the chance of it failing is low due to that krb5_init_context() + * pulls out some random, and quite commonly the randomness sources + * will not fail once it have started to produce good output, + * /dev/urandom behavies that way. + * + * @param buf a buffer to fill with randomness + * @param len length of memory that buf points to. + * + * @ingroup krb5_crypto + */ + + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_generate_random_block(void *buf, size_t len) +{ + int ret = krb5_generate_random(buf, len); + if (ret) + krb5_abortx(NULL, "Failed to generate random block"); +} diff --git a/third_party/heimdal/lib/krb5/crypto-stubs.c b/third_party/heimdal/lib/krb5/crypto-stubs.c new file mode 100644 index 0000000..5251f88 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto-stubs.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* These are stub functions for the standalone RFC3961 crypto library */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_context(krb5_context *context) +{ + krb5_context p; + + *context = NULL; + + /* should have a run_once */ + bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); + + p = calloc(1, sizeof(*p)); + if(!p) + return ENOMEM; + + *context = p; + return 0; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_context(krb5_context context) +{ + krb5_clear_error_message(context); + + if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) { + rk_SOCK_EXIT(); + } + + memset(context, 0, sizeof(*context)); + free(context); +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_homedir_access(krb5_context context) { + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_log(krb5_context context, + krb5_log_facility *fac, + int level, + const char *fmt, + ...) +{ + return 0; +} + +void KRB5_LIB_FUNCTION +_krb5_debug(krb5_context context, + int level, + const char *fmt, + ...) +{ +} + + +/* This function is currently just used to get the location of the EGD + * socket. If we're not using an EGD, then we can just return NULL */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_config_get_string (krb5_context context, + const krb5_config_section *c, + ...) +{ + return NULL; +} diff --git a/third_party/heimdal/lib/krb5/crypto.c b/third_party/heimdal/lib/krb5/crypto.c new file mode 100644 index 0000000..b52f084 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto.c @@ -0,0 +1,3248 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +struct _krb5_key_usage { + unsigned usage; + struct _krb5_key_data key; +}; + + +#ifndef HEIMDAL_SMALLER +#define DES3_OLD_ENCTYPE 1 +#endif + +static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, + unsigned, struct _krb5_key_data**); +static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage); + +static void free_key_schedule(krb5_context, + struct _krb5_key_data *, + struct _krb5_encryption_type *); + +/* + * Converts etype to a user readable string and sets as a side effect + * the krb5_error_message containing this string. Returns + * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in + * which case the error code of the etype convesion is returned. + */ + +static krb5_error_code +unsupported_enctype(krb5_context context, krb5_enctype etype) +{ + krb5_error_code ret; + char *name; + + ret = krb5_enctype_to_string(context, etype, &name); + if (ret) + return ret; + + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("Encryption type %s not supported", ""), + name); + free(name); + return KRB5_PROG_ETYPE_NOSUPP; +} + +/* + * + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_keysize(krb5_context context, + krb5_enctype type, + size_t *keysize) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + if(et == NULL) { + return unsupported_enctype (context, type); + } + *keysize = et->keytype->size; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_keybits(krb5_context context, + krb5_enctype type, + size_t *keybits) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + if(et == NULL) { + return unsupported_enctype (context, type); + } + *keybits = et->keytype->bits; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_generate_random_keyblock(krb5_context context, + krb5_enctype type, + krb5_keyblock *key) +{ + krb5_error_code ret; + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + if(et == NULL) { + return unsupported_enctype (context, type); + } + ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); + if(ret) + return ret; + key->keytype = type; + if(et->keytype->random_key) + (*et->keytype->random_key)(context, key); + else + krb5_generate_random_block(key->keyvalue.data, + key->keyvalue.length); + return 0; +} + +static krb5_error_code +_key_schedule(krb5_context context, + struct _krb5_key_data *key) +{ + krb5_error_code ret; + struct _krb5_encryption_type *et; + struct _krb5_key_type *kt; + + if (key->schedule != NULL) + return 0; + + et = _krb5_find_enctype(key->key->keytype); + + if (et == NULL) { + return unsupported_enctype (context, + key->key->keytype); + } + + kt = et->keytype; + + if(kt->schedule == NULL) + return 0; + ALLOC(key->schedule, 1); + if (key->schedule == NULL) + return krb5_enomem(context); + ret = krb5_data_alloc(key->schedule, kt->schedule_size); + if(ret) { + free(key->schedule); + key->schedule = NULL; + return ret; + } + (*kt->schedule)(context, kt, key); + return 0; +} + +/************************************************************ + * * + ************************************************************/ + +static krb5_error_code +EVP_unkeyed_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C, + const EVP_MD *md) +{ + if (_krb5_evp_digest_iov(crypto, + iov, niov, + C->checksum.data, NULL, + md, NULL) != 1) + krb5_abortx(context, "unkeyed checksum failed"); + + return 0; +} + +#define EVP_SHA_CHECKSUM(name) \ + \ + static krb5_error_code \ + SHA ## name ##_checksum(krb5_context context, \ + krb5_crypto crypto, \ + struct _krb5_key_data *key, \ + unsigned usage, \ + const struct krb5_crypto_iov *iov, \ + int niov, \ + Checksum *C) \ + { \ + return EVP_unkeyed_checksum(context, crypto, key, \ + usage, iov, niov, \ + C, EVP_sha##name()); \ + } + +EVP_SHA_CHECKSUM(1) +EVP_SHA_CHECKSUM(256) +EVP_SHA_CHECKSUM(384) +EVP_SHA_CHECKSUM(512) + +/* HMAC according to RFC2104 */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_internal_hmac_iov(krb5_context context, + krb5_crypto crypto, + struct _krb5_checksum_type *cm, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + struct _krb5_key_data *keyblock, + Checksum *result) +{ + unsigned char *ipad, *opad; + unsigned char *key; + struct krb5_crypto_iov *working; + size_t key_len; + size_t i; + + ipad = malloc(cm->blocksize); + if (ipad == NULL) + return ENOMEM; + + opad = malloc(cm->blocksize + cm->checksumsize); + if (opad == NULL) { + free(ipad); + return ENOMEM; + } + + working = calloc(niov + 1, sizeof(struct krb5_crypto_iov)); + if (working == NULL) { + free(ipad); + free(opad); + return ENOMEM; + } + + memset(ipad, 0x36, cm->blocksize); + memset(opad, 0x5c, cm->blocksize); + + if(keyblock->key->keyvalue.length > cm->blocksize){ + working[0].data = keyblock->key->keyvalue; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; + (*cm->checksum)(context, + crypto, + keyblock, + usage, + working, + 1, + result); + key = result->checksum.data; + key_len = result->checksum.length; + } else { + key = keyblock->key->keyvalue.data; + key_len = keyblock->key->keyvalue.length; + } + for(i = 0; i < key_len; i++){ + ipad[i] ^= key[i]; + opad[i] ^= key[i]; + } + + working[0].data.data = ipad; + working[0].data.length = cm->blocksize; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; + for (i = 0; i < niov; i++) + working[i + 1] = iov[i]; + + (*cm->checksum)(context, crypto, keyblock, usage, working, niov + 1, result); + memcpy(opad + cm->blocksize, result->checksum.data, + result->checksum.length); + + working[0].data.data = opad; + working[0].data.length = cm->blocksize + cm->checksumsize; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; + (*cm->checksum)(context, crypto, keyblock, usage, working, 1, result); + memset(ipad, 0, cm->blocksize); + free(ipad); + memset(opad, 0, cm->blocksize + cm->checksumsize); + free(opad); + free(working); + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_internal_hmac(krb5_context context, + krb5_crypto crypto, + struct _krb5_checksum_type *cm, + const void *data, + size_t len, + unsigned usage, + struct _krb5_key_data *keyblock, + Checksum *result) +{ + struct krb5_crypto_iov iov[1]; + + iov[0].data.data = (void *) data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + return _krb5_internal_hmac_iov(context, crypto, cm, usage, iov, 1, + keyblock, result); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_hmac(krb5_context context, + krb5_cksumtype cktype, + const void *data, + size_t len, + unsigned usage, + krb5_keyblock *key, + Checksum *result) +{ + struct _krb5_checksum_type *c = _krb5_find_checksum(cktype); + struct _krb5_key_data kd; + + krb5_error_code ret; + + if (c == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + cktype); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + kd.key = key; + kd.schedule = NULL; + + ret = _krb5_internal_hmac(context, NULL, c, data, len, usage, &kd, result); + + if (kd.schedule) + krb5_free_data(context, kd.schedule); + + return ret; +} + +krb5_error_code +_krb5_SP_HMAC_SHA1_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *result) +{ + krb5_error_code ret; + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned int hmaclen = sizeof(hmac); + + ret = _krb5_evp_hmac_iov(context, crypto, key, iov, niov, hmac, &hmaclen, + EVP_sha1(), NULL); + if (ret) + return ret; + + heim_assert(result->checksum.length <= hmaclen, + "SHA1 checksum too short"); + memcpy(result->checksum.data, hmac, result->checksum.length); + + return 0; +} + +krb5_error_code +_krb5_SP_HMAC_SHA1_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *verify) +{ + krb5_error_code ret; + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned int hmaclen = sizeof(hmac); + krb5_data data; + + ret = _krb5_evp_hmac_iov(context, crypto, key, iov, niov, hmac, &hmaclen, + EVP_sha1(), NULL); + if (ret) + return ret; + + data.data = hmac; + data.length = min(hmaclen, verify->checksum.length); + + if(krb5_data_ct_cmp(&data, &verify->checksum) != 0) + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + + return 0; +} + +#define SHA_CHECKSUM(name, blocksize, outputsize) \ + struct _krb5_checksum_type _krb5_checksum_sha##name = { \ + CKSUMTYPE_SHA##name, \ + "sha" #name, \ + blocksize, \ + outputsize, \ + F_CPROOF, \ + SHA##name##_checksum, \ + NULL \ + }; + +SHA_CHECKSUM(1, 64, 20); +SHA_CHECKSUM(256, 64, 32); +SHA_CHECKSUM(384, 128, 48); +SHA_CHECKSUM(512, 128, 64); + +KRB5_LIB_FUNCTION struct _krb5_checksum_type * KRB5_LIB_CALL +_krb5_find_checksum(krb5_cksumtype type) +{ + int i; + for(i = 0; i < _krb5_num_checksums; i++) + if(_krb5_checksum_types[i]->type == type) + return _krb5_checksum_types[i]; + return NULL; +} + +static krb5_error_code +get_checksum_key(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + struct _krb5_checksum_type *ct, + struct _krb5_key_data **key) +{ + krb5_error_code ret = 0; + struct _krb5_checksum_type *kct = NULL; + + if (crypto == NULL) { + krb5_set_error_message(context, KRB5_BAD_ENCTYPE, + N_("Checksum type %s is keyed but no " + "crypto context (key) was passed in", ""), + ct->name); + return KRB5_BAD_ENCTYPE; + } + kct = crypto->et->keyed_checksum; + if (kct == NULL || kct->type != ct->type) { + krb5_set_error_message(context, KRB5_BAD_ENCTYPE, + N_("Checksum type %s is keyed, but " + "the key type %s passed didnt have that checksum " + "type as the keyed type", ""), + ct->name, crypto->et->name); + return KRB5_BAD_ENCTYPE; + } + + if(ct->flags & F_DERIVED) + ret = _get_derived_key(context, crypto, usage, key); + else if(ct->flags & F_VARIANT) { + size_t i; + + *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */); + if (*key == NULL) + return krb5_enomem(context); + ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key); + if(ret) + return ret; + for(i = 0; i < (*key)->key->keyvalue.length; i++) + ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0; + } else { + *key = &crypto->key; + } + if(ret == 0) + ret = _key_schedule(context, *key); + return ret; +} + +static krb5_error_code +create_checksum_iov(krb5_context context, + struct _krb5_checksum_type *ct, + krb5_crypto crypto, + unsigned usage, + struct krb5_crypto_iov *iov, + int niov, + krb5_flags flags, + Checksum *result) +{ + krb5_error_code ret; + struct _krb5_key_data *dkey; + + if (ct->flags & F_DISABLED) { + krb5_clear_error_message (context); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + if (ct->flags & F_KEYED) { + ret = get_checksum_key(context, crypto, usage, ct, &dkey); + if (ret) + return ret; + } else if ((flags & KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM) == 0) { + return EINVAL; + } else + dkey = NULL; + + result->cksumtype = ct->type; + + return (*ct->checksum)(context, crypto, dkey, usage, iov, niov, result); +} + +static krb5_error_code +create_checksum (krb5_context context, + struct _krb5_checksum_type *ct, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_flags flags, + Checksum *result) +{ + int ret; + struct krb5_crypto_iov iov[1]; + + ret = krb5_data_alloc(&result->checksum, ct->checksumsize); + if (ret) + return ret; + + iov[0].data.data = data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + + return create_checksum_iov(context, ct, crypto, usage, iov, 1, flags, result); +} + +static int +arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto) +{ + return (ct->type == CKSUMTYPE_HMAC_MD5) && + (crypto->key.key->keytype == KEYTYPE_ARCFOUR); +} + +static inline krb5_flags +crypto_flags(krb5_crypto crypto) +{ + /* If caller didn't specify a key, unkeyed checksums are the only option */ + if (crypto == NULL) + return KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM; + else + return crypto->flags; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_create_checksum(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + int type, + void *data, + size_t len, + Checksum *result) +{ + struct _krb5_checksum_type *ct = NULL; + unsigned keyusage; + + /* type 0 -> pick from crypto */ + if (type) { + ct = _krb5_find_checksum(type); + } else if (crypto) { + ct = crypto->et->keyed_checksum; + if (ct == NULL) + ct = crypto->et->checksum; + } + + if(ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + type); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + if (arcfour_checksum_p(ct, crypto)) { + keyusage = usage; + _krb5_usage2arcfour(context, &keyusage); + } else + keyusage = CHECKSUM_USAGE(usage); + + return create_checksum(context, ct, crypto, keyusage, data, len, + crypto_flags(crypto), result); +} + +static krb5_error_code +verify_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + struct krb5_crypto_iov *iov, + int niov, + krb5_flags flags, + Checksum *cksum) +{ + krb5_error_code ret; + struct _krb5_key_data *dkey; + Checksum c; + struct _krb5_checksum_type *ct; + + ct = _krb5_find_checksum(cksum->cksumtype); + if (ct == NULL || (ct->flags & F_DISABLED)) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + cksum->cksumtype); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + if(ct->checksumsize != cksum->checksum.length) { + krb5_clear_error_message (context); + krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY, + N_("Decrypt integrity check failed for checksum type %s, " + "length was %u, expected %u", ""), + ct->name, (unsigned)cksum->checksum.length, + (unsigned)ct->checksumsize); + + return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ + } + if (ct->flags & F_KEYED) { + ret = get_checksum_key(context, crypto, usage, ct, &dkey); + if (ret) + return ret; + } else if ((flags & KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM) == 0) { + krb5_clear_error_message (context); + krb5_set_error_message(context, KRB5KRB_AP_ERR_INAPP_CKSUM, + N_("Unkeyed checksum type %s provided where keyed " + "checksum was expected", ""), ct->name); + + return KRB5KRB_AP_ERR_INAPP_CKSUM; + } else + dkey = NULL; + + /* + * If checksum have a verify function, lets use that instead of + * calling ->checksum and then compare result. + */ + + if(ct->verify) { + ret = (*ct->verify)(context, crypto, dkey, usage, iov, niov, cksum); + if (ret) + krb5_set_error_message(context, ret, + N_("Decrypt integrity check failed for checksum " + "type %s, key type %s", ""), + ct->name, (crypto != NULL)? crypto->et->name : "(none)"); + return ret; + } + + ret = krb5_data_alloc (&c.checksum, ct->checksumsize); + if (ret) + return ret; + + ret = (*ct->checksum)(context, crypto, dkey, usage, iov, niov, &c); + if (ret) { + krb5_data_free(&c.checksum); + return ret; + } + + if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + krb5_set_error_message(context, ret, + N_("Decrypt integrity check failed for checksum " + "type %s, key type %s", ""), + ct->name, crypto ? crypto->et->name : "(unkeyed)"); + } else { + ret = 0; + } + krb5_data_free (&c.checksum); + return ret; +} + +static krb5_error_code +verify_checksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + void *data, + size_t len, + krb5_flags flags, + Checksum *cksum) +{ + struct krb5_crypto_iov iov[1]; + + iov[0].data.data = data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + + return verify_checksum_iov(context, crypto, usage, iov, 1, flags, cksum); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_verify_checksum(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + void *data, + size_t len, + Checksum *cksum) +{ + struct _krb5_checksum_type *ct; + unsigned keyusage; + + ct = _krb5_find_checksum(cksum->cksumtype); + if(ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + cksum->cksumtype); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + if (arcfour_checksum_p(ct, crypto)) { + keyusage = usage; + _krb5_usage2arcfour(context, &keyusage); + } else + keyusage = CHECKSUM_USAGE(usage); + + return verify_checksum(context, crypto, keyusage, + data, len, crypto_flags(crypto), cksum); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_get_checksum_type(krb5_context context, + krb5_crypto crypto, + krb5_cksumtype *type) +{ + struct _krb5_checksum_type *ct = NULL; + + if (crypto != NULL) { + ct = crypto->et->keyed_checksum; + if (ct == NULL) + ct = crypto->et->checksum; + } + + if (ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type not found", "")); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + *type = ct->type; + + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_checksumsize(krb5_context context, + krb5_cksumtype type, + size_t *size) +{ + struct _krb5_checksum_type *ct = _krb5_find_checksum(type); + if(ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + type); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + *size = ct->checksumsize; + return 0; +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_checksum_is_keyed(krb5_context context, + krb5_cksumtype type) +{ + struct _krb5_checksum_type *ct = _krb5_find_checksum(type); + if(ct == NULL) { + if (context) + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + type); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + return ct->flags & F_KEYED; +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_checksum_is_collision_proof(krb5_context context, + krb5_cksumtype type) +{ + struct _krb5_checksum_type *ct = _krb5_find_checksum(type); + if(ct == NULL) { + if (context) + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + type); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + return ct->flags & F_CPROOF; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_checksum_disable(krb5_context context, + krb5_cksumtype type) +{ + struct _krb5_checksum_type *ct = _krb5_find_checksum(type); + if(ct == NULL) { + if (context) + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + type); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + ct->flags |= F_DISABLED; + return 0; +} + +/************************************************************ + * * + ************************************************************/ + +KRB5_LIB_FUNCTION struct _krb5_encryption_type * KRB5_LIB_CALL +_krb5_find_enctype(krb5_enctype type) +{ + int i; + for(i = 0; i < _krb5_num_etypes; i++) + if(_krb5_etypes[i]->type == type) + return _krb5_etypes[i]; + return NULL; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_to_string(krb5_context context, + krb5_enctype etype, + char **string) +{ + struct _krb5_encryption_type *e; + e = _krb5_find_enctype(etype); + if(e == NULL) { + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + etype); + *string = NULL; + return KRB5_PROG_ETYPE_NOSUPP; + } + *string = strdup(e->name); + if (*string == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_string_to_enctype(krb5_context context, + const char *string, + krb5_enctype *etype) +{ + int i; + for(i = 0; i < _krb5_num_etypes; i++) { + if(strcasecmp(_krb5_etypes[i]->name, string) == 0){ + *etype = _krb5_etypes[i]->type; + return 0; + } + if(_krb5_etypes[i]->alias != NULL && + strcasecmp(_krb5_etypes[i]->alias, string) == 0){ + *etype = _krb5_etypes[i]->type; + return 0; + } + } + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %s not supported", ""), + string); + return KRB5_PROG_ETYPE_NOSUPP; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_to_keytype(krb5_context context, + krb5_enctype etype, + krb5_keytype *keytype) +{ + struct _krb5_encryption_type *e = _krb5_find_enctype(etype); + if(e == NULL) { + return unsupported_enctype (context, etype); + } + *keytype = (krb5_keytype)e->keytype->type; + return 0; +} + +/** + * Check if a enctype is valid, return 0 if it is. + * + * @param context Kerberos context + * @param etype enctype to check if its valid or not + * + * @return Return an error code for an failure or 0 on success (enctype valid). + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_valid(krb5_context context, + krb5_enctype etype) +{ + struct _krb5_encryption_type *e = _krb5_find_enctype(etype); + if(e && (e->flags & F_DISABLED) == 0) + return 0; + if (context == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + if(e == NULL) { + return unsupported_enctype (context, etype); + } + /* Must be (e->flags & F_DISABLED) */ + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %s is disabled", ""), + e->name); + return KRB5_PROG_ETYPE_NOSUPP; +} + +/** + * Return the coresponding encryption type for a checksum type. + * + * @param context Kerberos context + * @param ctype The checksum type to get the result enctype for + * @param etype The returned encryption, when the matching etype is + * not found, etype is set to ETYPE_NULL. + * + * @return Return an error code for an failure or 0 on success. + * @ingroup krb5_crypto + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cksumtype_to_enctype(krb5_context context, + krb5_cksumtype ctype, + krb5_enctype *etype) +{ + int i; + + *etype = ETYPE_NULL; + + for(i = 0; i < _krb5_num_etypes; i++) { + if(_krb5_etypes[i]->keyed_checksum && + _krb5_etypes[i]->keyed_checksum->type == ctype) + { + *etype = _krb5_etypes[i]->type; + return 0; + } + } + + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + (int)ctype); + return KRB5_PROG_SUMTYPE_NOSUPP; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cksumtype_valid(krb5_context context, + krb5_cksumtype ctype) +{ + struct _krb5_checksum_type *c = _krb5_find_checksum(ctype); + if (c == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + ctype); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + if (c->flags & F_DISABLED) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %s is disabled", ""), + c->name); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + return 0; +} + +static krb5_boolean +derived_crypto(krb5_context context, + krb5_crypto crypto) +{ + return (crypto->et->flags & F_DERIVED) != 0; +} + +#define CHECKSUMSIZE(C) ((C)->checksumsize) +#define CHECKSUMTYPE(C) ((C)->type) + +static krb5_error_code +encrypt_internal_derived(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t sz, block_sz, checksum_sz, total_sz; + Checksum cksum; + unsigned char *p, *q; + krb5_error_code ret; + struct _krb5_key_data *dkey; + const struct _krb5_encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + + sz = et->confoundersize + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + total_sz = block_sz + checksum_sz; + p = calloc(1, total_sz); + if (p == NULL) + return krb5_enomem(context); + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + memcpy(q, data, len); + + ret = create_checksum(context, + et->keyed_checksum, + crypto, + INTEGRITY_USAGE(usage), + p, + block_sz, + 0, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) { + free_Checksum (&cksum); + krb5_clear_error_message (context); + ret = KRB5_CRYPTO_INTERNAL; + } + if(ret) + goto fail; + memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto fail; + ret = _key_schedule(context, dkey); + if(ret) + goto fail; + ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); + if (ret) + goto fail; + result->data = p; + result->length = total_sz; + return 0; + fail: + memset(p, 0, total_sz); + free(p); + return ret; +} + +static krb5_error_code +encrypt_internal_enc_then_cksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t sz, block_sz, checksum_sz, total_sz; + Checksum cksum; + unsigned char *p, *q, *ivc = NULL; + krb5_error_code ret; + struct _krb5_key_data *dkey; + const struct _krb5_encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + + sz = et->confoundersize + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + total_sz = block_sz + checksum_sz; + p = calloc(1, total_sz); + if (p == NULL) + return krb5_enomem(context); + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + memcpy(q, data, len); + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto fail; + ret = _key_schedule(context, dkey); + if(ret) + goto fail; + + /* XXX EVP style update API would avoid needing to allocate here */ + ivc = malloc(et->blocksize + block_sz); + if (ivc == NULL) { + ret = krb5_enomem(context); + goto fail; + } + if (ivec) + memcpy(ivc, ivec, et->blocksize); + else + memset(ivc, 0, et->blocksize); + + ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); + if (ret) + goto fail; + memcpy(&ivc[et->blocksize], p, block_sz); + + ret = create_checksum(context, + et->keyed_checksum, + crypto, + INTEGRITY_USAGE(usage), + ivc, + et->blocksize + block_sz, + 0, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) { + free_Checksum (&cksum); + krb5_clear_error_message (context); + ret = KRB5_CRYPTO_INTERNAL; + } + if(ret) + goto fail; + memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + result->data = p; + result->length = total_sz; + free(ivc); + return 0; + fail: + memset_s(p, total_sz, 0, total_sz); + free(p); + free(ivc); + return ret; +} + +static krb5_error_code +encrypt_internal(krb5_context context, + krb5_crypto crypto, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t sz, block_sz, checksum_sz; + Checksum cksum; + unsigned char *p, *q; + krb5_error_code ret; + const struct _krb5_encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->checksum); + + sz = et->confoundersize + checksum_sz + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + p = calloc(1, block_sz); + if (p == NULL) + return krb5_enomem(context); + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + memset(q, 0, checksum_sz); + q += checksum_sz; + memcpy(q, data, len); + + ret = create_checksum(context, + et->checksum, + crypto, + 0, + p, + block_sz, + KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) { + krb5_clear_error_message (context); + free_Checksum(&cksum); + ret = KRB5_CRYPTO_INTERNAL; + } + if(ret) + goto fail; + memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length); + free_Checksum(&cksum); + ret = _key_schedule(context, &crypto->key); + if(ret) + goto fail; + ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec); + if (ret) { + memset(p, 0, block_sz); + free(p); + return ret; + } + result->data = p; + result->length = block_sz; + return 0; + fail: + memset(p, 0, block_sz); + free(p); + return ret; +} + +static krb5_error_code +encrypt_internal_special(krb5_context context, + krb5_crypto crypto, + int usage, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t cksum_sz = CHECKSUMSIZE(et->checksum); + size_t sz = len + cksum_sz + et->confoundersize; + char *tmp, *p; + krb5_error_code ret; + + tmp = malloc (sz); + if (tmp == NULL) + return krb5_enomem(context); + p = tmp; + memset (p, 0, cksum_sz); + p += cksum_sz; + krb5_generate_random_block(p, et->confoundersize); + p += et->confoundersize; + memcpy (p, data, len); + ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec); + if (ret) { + memset(tmp, 0, sz); + free(tmp); + return ret; + } + result->data = tmp; + result->length = sz; + return 0; +} + +static krb5_error_code +decrypt_internal_derived(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t checksum_sz; + Checksum cksum; + unsigned char *p; + krb5_error_code ret; + struct _krb5_key_data *dkey; + struct _krb5_encryption_type *et = crypto->et; + unsigned long l; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + if (len < checksum_sz + et->confoundersize) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Encrypted data shorter then " + "checksum + confunder", "")); + return KRB5_BAD_MSIZE; + } + + if (((len - checksum_sz) % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + + p = malloc(len); + if (len != 0 && p == NULL) + return krb5_enomem(context); + memcpy(p, data, len); + + len -= checksum_sz; + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) { + free(p); + return ret; + } + ret = _key_schedule(context, dkey); + if(ret) { + free(p); + return ret; + } + ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); + if (ret) { + free(p); + return ret; + } + + cksum.checksum.data = p + len; + cksum.checksum.length = checksum_sz; + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + + ret = verify_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + p, + len, + 0, + &cksum); + if(ret) { + free(p); + return ret; + } + l = len - et->confoundersize; + memmove(p, p + et->confoundersize, l); + result->data = p; + result->length = l; + return 0; +} + +static krb5_error_code +decrypt_internal_enc_then_cksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t checksum_sz; + Checksum cksum; + unsigned char *p; + krb5_error_code ret; + struct _krb5_key_data *dkey; + struct _krb5_encryption_type *et = crypto->et; + unsigned long l; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + if (len < checksum_sz + et->confoundersize) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Encrypted data shorter then " + "checksum + confunder", "")); + return KRB5_BAD_MSIZE; + } + + if (((len - checksum_sz) % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + + len -= checksum_sz; + + p = malloc(et->blocksize + len); + if (p == NULL) + return krb5_enomem(context); + + if (ivec) + memcpy(p, ivec, et->blocksize); + else + memset(p, 0, et->blocksize); + memcpy(&p[et->blocksize], data, len); + + cksum.checksum.data = (unsigned char *)data + len; + cksum.checksum.length = checksum_sz; + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + + ret = verify_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + p, + et->blocksize + len, + 0, + &cksum); + if(ret) { + free(p); + return ret; + } + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) { + free(p); + return ret; + } + ret = _key_schedule(context, dkey); + if(ret) { + free(p); + return ret; + } + ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec); + if (ret) { + free(p); + return ret; + } + + l = len - et->confoundersize; + memmove(p, p + et->blocksize + et->confoundersize, l); + result->data = p; + result->length = l; + return 0; +} + +static krb5_error_code +decrypt_internal(krb5_context context, + krb5_crypto crypto, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + krb5_error_code ret; + unsigned char *p; + Checksum cksum; + size_t checksum_sz, l; + struct _krb5_encryption_type *et = crypto->et; + + if ((len % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + checksum_sz = CHECKSUMSIZE(et->checksum); + if (len < checksum_sz + et->confoundersize) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Encrypted data shorter then " + "checksum + confunder", "")); + return KRB5_BAD_MSIZE; + } + + p = malloc(len); + if (len != 0 && p == NULL) + return krb5_enomem(context); + memcpy(p, data, len); + + ret = _key_schedule(context, &crypto->key); + if(ret) { + free(p); + return ret; + } + ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec); + if (ret) { + free(p); + return ret; + } + ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz); + if(ret) { + free(p); + return ret; + } + memset(p + et->confoundersize, 0, checksum_sz); + cksum.cksumtype = CHECKSUMTYPE(et->checksum); + ret = verify_checksum(context, NULL, 0, p, len, + KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM, &cksum); + free_Checksum(&cksum); + if(ret) { + free(p); + return ret; + } + l = len - et->confoundersize - checksum_sz; + memmove(p, p + et->confoundersize + checksum_sz, l); + result->data = p; + result->length = l; + return 0; +} + +static krb5_error_code +decrypt_internal_special(krb5_context context, + krb5_crypto crypto, + int usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t cksum_sz = CHECKSUMSIZE(et->checksum); + size_t sz = len - cksum_sz - et->confoundersize; + unsigned char *p; + krb5_error_code ret; + + if ((len % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + if (len < cksum_sz + et->confoundersize) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Encrypted data shorter then " + "checksum + confunder", "")); + return KRB5_BAD_MSIZE; + } + + p = malloc (len); + if (p == NULL) + return krb5_enomem(context); + memcpy(p, data, len); + + ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec); + if (ret) { + free(p); + return ret; + } + + memmove (p, p + cksum_sz + et->confoundersize, sz); + result->data = p; + result->length = sz; + return 0; +} + +static krb5_crypto_iov * +iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type) +{ + size_t i; + for (i = 0; i < num_data; i++) + if (data[i].flags == type) + return &data[i]; + return NULL; +} + +static size_t +iov_enc_data_len(krb5_crypto_iov *data, int num_data) +{ + size_t i, len; + + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + len += data[i].data.length; + } + + return len; +} + +static size_t +iov_sign_data_len(krb5_crypto_iov *data, int num_data) +{ + size_t i, len; + + for (len = 0, i = 0; i < num_data; i++) { + /* Can't use should_sign, because we must only count data, not + * header/trailer */ + if (data[i].flags == KRB5_CRYPTO_TYPE_DATA || + data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + len += data[i].data.length; + } + + return len; +} + +static krb5_error_code +iov_coalesce(krb5_context context, + krb5_data *prefix, + krb5_crypto_iov *data, + int num_data, + krb5_boolean inc_sign_data, + krb5_data *out) +{ + unsigned char *p, *q; + krb5_crypto_iov *hiv, *piv; + size_t len; + unsigned int i; + + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + + len = 0; + if (prefix) + len += prefix->length; + len += hiv->data.length; + if (inc_sign_data) + len += iov_sign_data_len(data, num_data); + else + len += iov_enc_data_len(data, num_data); + if (piv) + len += piv->data.length; + + p = q = malloc(len); + if (p == NULL) + return krb5_enomem(context); + + if (prefix) { + memcpy(q, prefix->data, prefix->length); + q += prefix->length; + } + memcpy(q, hiv->data.data, hiv->data.length); + q += hiv->data.length; + for (i = 0; i < num_data; i++) { + if (data[i].flags == KRB5_CRYPTO_TYPE_DATA || + (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) { + memcpy(q, data[i].data.data, data[i].data.length); + q += data[i].data.length; + } + } + if (piv) + memset(q, 0, piv->data.length); + + out->length = len; + out->data = p; + + return 0; +} + +static krb5_error_code +iov_uncoalesce(krb5_context context, + krb5_data *enc_data, + krb5_crypto_iov *data, + int num_data) +{ + unsigned char *q = enc_data->data; + krb5_crypto_iov *hiv, *piv; + unsigned int i; + + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + + memcpy(hiv->data.data, q, hiv->data.length); + q += hiv->data.length; + + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(data[i].data.data, q, data[i].data.length); + q += data[i].data.length; + } + if (piv) + memcpy(piv->data.data, q, piv->data.length); + + return 0; +} + +static krb5_error_code +iov_pad_validate(const struct _krb5_encryption_type *et, + krb5_crypto_iov *data, + int num_data, + krb5_crypto_iov **ppiv) +{ + krb5_crypto_iov *piv; + size_t sz, headersz, block_sz, pad_sz, len; + + len = iov_enc_data_len(data, num_data); + + headersz = et->confoundersize; + + sz = headersz + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + + pad_sz = block_sz - sz; + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + /* its ok to have no TYPE_PADDING if there is no padding */ + if (piv == NULL && pad_sz != 0) + return KRB5_BAD_MSIZE; + if (piv) { + if (piv->data.length < pad_sz) + return KRB5_BAD_MSIZE; + piv->data.length = pad_sz; + if (pad_sz) + memset(piv->data.data, 0, pad_sz); + else + piv = NULL; + } + + *ppiv = piv; + return 0; +} + +/** + * Inline encrypt a kerberos message + * + * @param context Kerberos context + * @param crypto Kerberos crypto context + * @param usage Key usage for this buffer + * @param data array of buffers to process + * @param num_data length of array + * @param ivec initial cbc/cts vector + * + * @return Return an error code or 0. + * @ingroup krb5_crypto + * + * Kerberos encrypted data look like this: + * + * 1. KRB5_CRYPTO_TYPE_HEADER + * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...] + * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver + * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is + * commonly used headers and trailers. + * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1 + * 4. KRB5_CRYPTO_TYPE_TRAILER + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encrypt_iov_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_crypto_iov *data, + int num_data, + void *ivec) +{ + size_t headersz, trailersz; + Checksum cksum; + krb5_data enc_data, sign_data; + krb5_error_code ret; + struct _krb5_key_data *dkey; + const struct _krb5_encryption_type *et = crypto->et; + krb5_crypto_iov *tiv, *piv, *hiv; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + + if(!derived_crypto(context, crypto)) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + + krb5_data_zero(&enc_data); + krb5_data_zero(&sign_data); + + headersz = et->confoundersize; + trailersz = CHECKSUMSIZE(et->keyed_checksum); + + /* header */ + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (hiv == NULL || hiv->data.length != headersz) + return KRB5_BAD_MSIZE; + krb5_generate_random_block(hiv->data.data, hiv->data.length); + + /* padding */ + ret = iov_pad_validate(et, data, num_data, &piv); + if(ret) + goto cleanup; + + /* trailer */ + tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (tiv == NULL || tiv->data.length != trailersz) { + ret = KRB5_BAD_MSIZE; + goto cleanup; + } + + if (et->flags & F_ENC_THEN_CKSUM) { + unsigned char old_ivec[EVP_MAX_IV_LENGTH]; + krb5_data ivec_data; + + heim_assert(et->blocksize <= sizeof(old_ivec), + "blocksize too big for ivec buffer"); + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + if (ivec) + memcpy(old_ivec, ivec, et->blocksize); + else + memset(old_ivec, 0, et->blocksize); + + if (et->encrypt_iov != NULL) { + ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage, + ivec); + if (ret) + goto cleanup; + } else { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if (ret) + goto cleanup; + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 1, usage, ivec); + if (ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if (ret) + goto cleanup; + } + + ivec_data.length = et->blocksize; + ivec_data.data = old_ivec; + + ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; + + ret = create_checksum(context, + et->keyed_checksum, + crypto, + INTEGRITY_USAGE(usage), + sign_data.data, + sign_data.length, + 0, + &cksum); + + if(ret == 0 && cksum.checksum.length != trailersz) { + free_Checksum (&cksum); + krb5_clear_error_message (context); + ret = KRB5_CRYPTO_INTERNAL; + } + if (ret) + goto cleanup; + + /* save cksum at end */ + memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + + } else { + cksum.checksum = tiv->data; + ret = create_checksum_iov(context, + et->keyed_checksum, + crypto, + INTEGRITY_USAGE(usage), + data, + num_data, + 0, + &cksum); + if (ret) + goto cleanup; + + /* create_checksum may realloc the derived key space, so any keys + * obtained before it was called may no longer be valid */ + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + if (et->encrypt_iov != NULL) { + ret = (*et->encrypt_iov)(context, dkey, data, num_data, 1, usage, + ivec); + if (ret) + goto cleanup; + } else { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if (ret) + goto cleanup; + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 1, usage, ivec); + if (ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if (ret) + goto cleanup; + } + } + +cleanup: + if (enc_data.data) { + memset_s(enc_data.data, enc_data.length, 0, enc_data.length); + krb5_data_free(&enc_data); + } + if (sign_data.data) { + memset_s(sign_data.data, sign_data.length, 0, sign_data.length); + krb5_data_free(&sign_data); + } + return ret; +} + +/** + * Inline decrypt a Kerberos message. + * + * @param context Kerberos context + * @param crypto Kerberos crypto context + * @param usage Key usage for this buffer + * @param data array of buffers to process + * @param num_data length of array + * @param ivec initial cbc/cts vector + * + * @return Return an error code or 0. + * @ingroup krb5_crypto + * + * 1. KRB5_CRYPTO_TYPE_HEADER + * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in + * any order, however the receiver have to aware of the + * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted + * protocol headers and trailers. The output data will be of same + * size as the input data or shorter. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decrypt_iov_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_crypto_iov *data, + unsigned int num_data, + void *ivec) +{ + Checksum cksum; + krb5_data enc_data, sign_data; + krb5_error_code ret; + struct _krb5_key_data *dkey; + struct _krb5_encryption_type *et = crypto->et; + krb5_crypto_iov *tiv, *hiv; + + if(!derived_crypto(context, crypto)) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + + /* header */ + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (hiv == NULL || hiv->data.length != et->confoundersize) + return KRB5_BAD_MSIZE; + + /* trailer */ + tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum)) + return KRB5_BAD_MSIZE; + + /* padding */ + if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + + krb5_data_zero(&enc_data); + krb5_data_zero(&sign_data); + + if (!(et->flags & F_ENC_THEN_CKSUM)) { + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + if (et->encrypt_iov != NULL) { + ret = (*et->encrypt_iov)(context, dkey, data, num_data, + 0, usage, ivec); + if(ret) + goto cleanup; + } else { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 0, usage, ivec); + if(ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; + } + + cksum.checksum.data = tiv->data.data; + cksum.checksum.length = tiv->data.length; + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + + ret = verify_checksum_iov(context, crypto, INTEGRITY_USAGE(usage), + data, num_data, 0, &cksum); + if(ret) + goto cleanup; + } else { + krb5_data ivec_data; + static const unsigned char zero_ivec[EVP_MAX_IV_LENGTH]; + + heim_assert(et->blocksize <= sizeof(zero_ivec), + "blocksize too big for ivec buffer"); + + ivec_data.length = et->blocksize; + ivec_data.data = ivec ? ivec : rk_UNCONST(zero_ivec); + + ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; + + cksum.checksum.data = tiv->data.data; + cksum.checksum.length = tiv->data.length; + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + + ret = verify_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + sign_data.data, + sign_data.length, + 0, + &cksum); + if(ret) + goto cleanup; + + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 0, usage, ivec); + if(ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; + } + +cleanup: + if (enc_data.data) { + memset_s(enc_data.data, enc_data.length, 0, enc_data.length); + krb5_data_free(&enc_data); + } + if (sign_data.data) { + memset_s(sign_data.data, sign_data.length, 0, sign_data.length); + krb5_data_free(&sign_data); + } + return ret; +} + +/** + * Create a Kerberos message checksum. + * + * @param context Kerberos context + * @param crypto Kerberos crypto context + * @param usage Key usage for this buffer + * @param data array of buffers to process + * @param num_data length of array + * @param type output data + * + * @return Return an error code or 0. + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_create_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_crypto_iov *data, + unsigned int num_data, + krb5_cksumtype *type) +{ + Checksum cksum; + krb5_crypto_iov *civ; + struct _krb5_checksum_type *ct; + unsigned keyusage; + krb5_error_code ret; + + civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + if (civ == NULL) + return KRB5_BAD_MSIZE; + + ct = crypto->et->keyed_checksum; + if (ct == NULL) + ct = crypto->et->checksum; + + if(ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type not found", "")); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + if (arcfour_checksum_p(ct, crypto)) { + keyusage = usage; + _krb5_usage2arcfour(context, &keyusage); + } else + keyusage = CHECKSUM_USAGE(usage); + + if (ct->checksumsize > civ->data.length) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Checksum larger then input buffer", "")); + return KRB5_BAD_MSIZE; + } + + cksum.checksum = civ->data; + ret = create_checksum_iov(context, ct, crypto, keyusage, + data, num_data, crypto_flags(crypto), &cksum); + + if (ret == 0 && type) + *type = cksum.cksumtype; + + return ret; +} + +/** + * Verify a Kerberos message checksum. + * + * @param context Kerberos context + * @param crypto Kerberos crypto context + * @param usage Key usage for this buffer + * @param data array of buffers to process + * @param num_data length of array + * @param type return checksum type if not NULL + * + * @return Return an error code or 0. + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_verify_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_crypto_iov *data, + unsigned int num_data, + krb5_cksumtype *type) +{ + struct _krb5_encryption_type *et = crypto->et; + struct _krb5_checksum_type *ct; + Checksum cksum; + krb5_crypto_iov *civ; + krb5_error_code ret; + unsigned keyusage; + + civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + if (civ == NULL) + return KRB5_BAD_MSIZE; + + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + cksum.checksum.length = civ->data.length; + cksum.checksum.data = civ->data.data; + + ct = _krb5_find_checksum(cksum.cksumtype); + if(ct == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("checksum type %d not supported", ""), + cksum.cksumtype); + return KRB5_PROG_SUMTYPE_NOSUPP; + } + + if (arcfour_checksum_p(ct, crypto)) { + keyusage = usage; + _krb5_usage2arcfour(context, &keyusage); + } else + keyusage = CHECKSUM_USAGE(usage); + + ret = verify_checksum_iov(context, crypto, keyusage, data, num_data, + crypto_flags(crypto), &cksum); + + if (ret == 0 && type) + *type = cksum.cksumtype; + + return ret; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_length(krb5_context context, + krb5_crypto crypto, + int type, + size_t *len) +{ + if (!derived_crypto(context, crypto)) { + krb5_set_error_message(context, EINVAL, "not a derived crypto"); + return EINVAL; + } + + switch(type) { + case KRB5_CRYPTO_TYPE_EMPTY: + *len = 0; + return 0; + case KRB5_CRYPTO_TYPE_HEADER: + *len = crypto->et->blocksize; + return 0; + case KRB5_CRYPTO_TYPE_DATA: + case KRB5_CRYPTO_TYPE_SIGN_ONLY: + /* len must already been filled in */ + return 0; + case KRB5_CRYPTO_TYPE_PADDING: + if (crypto->et->padsize > 1) + *len = crypto->et->padsize; + else + *len = 0; + return 0; + case KRB5_CRYPTO_TYPE_TRAILER: + if (crypto->et->keyed_checksum) + *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + else + *len = 0; + return 0; + case KRB5_CRYPTO_TYPE_CHECKSUM: + if (crypto->et->keyed_checksum) + *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + else + *len = CHECKSUMSIZE(crypto->et->checksum); + return 0; + } + krb5_set_error_message(context, EINVAL, + "%d not a supported type", type); + return EINVAL; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_length_iov(krb5_context context, + krb5_crypto crypto, + krb5_crypto_iov *data, + unsigned int num_data) +{ + krb5_error_code ret; + size_t i; + + for (i = 0; i < num_data; i++) { + ret = krb5_crypto_length(context, crypto, + data[i].flags, + &data[i].data.length); + if (ret) + return ret; + } + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encrypt_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + krb5_error_code ret; + + switch (crypto->et->flags & F_CRYPTO_MASK) { + case F_RFC3961_ENC: + ret = encrypt_internal_derived(context, crypto, usage, + data, len, result, ivec); + break; + case F_SPECIAL: + ret = encrypt_internal_special (context, crypto, usage, + data, len, result, ivec); + break; + case F_ENC_THEN_CKSUM: + ret = encrypt_internal_enc_then_cksum(context, crypto, usage, + data, len, result, ivec); + break; + default: + ret = encrypt_internal(context, crypto, data, len, result, ivec); + break; + } + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const void *data, + size_t len, + krb5_data *result) +{ + return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_encrypt_EncryptedData(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + int kvno, + EncryptedData *result) +{ + result->etype = CRYPTO_ETYPE(crypto); + if(kvno){ + ALLOC(result->kvno, 1); + *result->kvno = kvno; + }else + result->kvno = NULL; + return krb5_encrypt(context, crypto, usage, data, len, &result->cipher); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decrypt_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + krb5_error_code ret; + + switch (crypto->et->flags & F_CRYPTO_MASK) { + case F_RFC3961_ENC: + ret = decrypt_internal_derived(context, crypto, usage, + data, len, result, ivec); + break; + case F_SPECIAL: + ret = decrypt_internal_special(context, crypto, usage, + data, len, result, ivec); + break; + case F_ENC_THEN_CKSUM: + ret = decrypt_internal_enc_then_cksum(context, crypto, usage, + data, len, result, ivec); + break; + default: + ret = decrypt_internal(context, crypto, data, len, result, ivec); + break; + } + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + return krb5_decrypt_ivec (context, crypto, usage, data, len, result, + NULL); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_decrypt_EncryptedData(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const EncryptedData *e, + krb5_data *result) +{ + return krb5_decrypt(context, crypto, usage, + e->cipher.data, e->cipher.length, result); +} + +/************************************************************ + * * + ************************************************************/ + +static krb5_error_code +derive_key_rfc3961(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) +{ + + unsigned char *k = NULL; + unsigned int nblocks = 0, i; + krb5_error_code ret = 0; + struct _krb5_key_type *kt = et->keytype; + + if(et->blocksize * 8 < kt->bits || len != et->blocksize) { + nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); + k = malloc(nblocks * et->blocksize); + if(k == NULL) { + ret = krb5_enomem(context); + goto out; + } + ret = _krb5_n_fold(constant, len, k, et->blocksize); + if (ret) { + krb5_enomem(context); + goto out; + } + + for(i = 0; i < nblocks; i++) { + if(i > 0) + memcpy(k + i * et->blocksize, + k + (i - 1) * et->blocksize, + et->blocksize); + ret = (*et->encrypt)(context, key, k + i * et->blocksize, + et->blocksize, 1, 0, NULL); + if (ret) { + krb5_set_error_message(context, ret, N_("encrypt failed", "")); + goto out; + } + } + } else { + /* this case is probably broken, but won't be run anyway */ + void *c = malloc(len); + size_t res_len = (kt->bits + 7) / 8; + + if(len != 0 && c == NULL) { + ret = krb5_enomem(context); + goto out; + } + memcpy(c, constant, len); + ret = (*et->encrypt)(context, key, c, len, 1, 0, NULL); + if (ret) { + free(c); + krb5_set_error_message(context, ret, N_("encrypt failed", "")); + goto out; + } + k = malloc(res_len); + if(res_len != 0 && k == NULL) { + free(c); + ret = krb5_enomem(context); + goto out; + } + ret = _krb5_n_fold(c, len, k, res_len); + free(c); + if (ret) { + krb5_enomem(context); + goto out; + } + } + + if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1) + _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); + else + memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); + + out: + if (k) { + memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize); + free(k); + } + return ret; +} + +static krb5_error_code +derive_key_sp800_hmac(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) +{ + krb5_error_code ret; + struct _krb5_key_type *kt = et->keytype; + krb5_data label; + const EVP_MD *md = NULL; + const unsigned char *c = constant; + size_t key_len; + krb5_data K1; + + ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md); + if (ret) + return ret; + + /* + * PRF usage: not handled here (output cannot be longer) + * Integrity usage: truncated hash (half length) + * Encryption usage: base key length + */ + if (len == 5 && (c[4] == 0x99 || c[4] == 0x55)) + key_len = EVP_MD_size(md) / 2; + else + key_len = kt->size; + + ret = krb5_data_alloc(&K1, key_len); + if (ret) + return ret; + + label.data = (void *)constant; + label.length = len; + + ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue, + &label, NULL, md, &K1); + if (ret == 0) { + if (key->key->keyvalue.length > key_len) + key->key->keyvalue.length = key_len; + memcpy(key->key->keyvalue.data, K1.data, key_len); + } + + memset_s(K1.data, K1.length, 0, K1.length); + krb5_data_free(&K1); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_derive_key(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) +{ + krb5_error_code ret; + + ret = _key_schedule(context, key); + if(ret) + return ret; + + switch (et->flags & F_KDF_MASK) { + case F_RFC3961_KDF: + ret = derive_key_rfc3961(context, et, key, constant, len); + break; + case F_SP800_108_HMAC_KDF: + ret = derive_key_sp800_hmac(context, et, key, constant, len); + break; + default: + ret = KRB5_CRYPTO_INTERNAL; + krb5_set_error_message(context, ret, + N_("derive_key() called with unknown keytype (%u)", ""), + et->keytype->type); + break; + } + + if (key->schedule) { + free_key_schedule(context, key, et); + key->schedule = NULL; + } + + return ret; +} + +static struct _krb5_key_data * +_new_derived_key(krb5_crypto crypto, unsigned usage) +{ + struct _krb5_key_usage *d = crypto->key_usage; + d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d)); + if(d == NULL) + return NULL; + crypto->key_usage = d; + d += crypto->num_key_usage++; + memset(d, 0, sizeof(*d)); + d->usage = usage; + return &d->key; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_derive_key(krb5_context context, + const krb5_keyblock *key, + krb5_enctype etype, + const void *constant, + size_t constant_len, + krb5_keyblock **derived_key) +{ + krb5_error_code ret; + struct _krb5_encryption_type *et; + struct _krb5_key_data d; + + *derived_key = NULL; + + et = _krb5_find_enctype (etype); + if (et == NULL) { + return unsupported_enctype (context, etype); + } + + ret = krb5_copy_keyblock(context, key, &d.key); + if (ret) + return ret; + + d.schedule = NULL; + ret = _krb5_derive_key(context, et, &d, constant, constant_len); + if (ret == 0) + ret = krb5_copy_keyblock(context, d.key, derived_key); + _krb5_free_key_data(context, &d, et); + return ret; +} + +static krb5_error_code +_get_derived_key(krb5_context context, + krb5_crypto crypto, + unsigned usage, + struct _krb5_key_data **key) +{ + int i; + struct _krb5_key_data *d; + unsigned char constant[5]; + + *key = NULL; + for(i = 0; i < crypto->num_key_usage; i++) + if(crypto->key_usage[i].usage == usage) { + *key = &crypto->key_usage[i].key; + return 0; + } + d = _new_derived_key(crypto, usage); + if (d == NULL) + return krb5_enomem(context); + *key = d; + krb5_copy_keyblock(context, crypto->key.key, &d->key); + _krb5_put_int(constant, usage, sizeof(constant)); + return _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant)); +} + +/** + * Create a crypto context used for all encryption and signature + * operation. The encryption type to use is taken from the key, but + * can be overridden with the enctype parameter. This can be useful + * for encryptions types which is compatiable (DES for example). + * + * To free the crypto context, use krb5_crypto_destroy(). + * + * @param context Kerberos context + * @param key the key block information with all key data + * @param etype the encryption type + * @param crypto the resulting crypto context + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_init(krb5_context context, + const krb5_keyblock *key, + krb5_enctype etype, + krb5_crypto *crypto) +{ + krb5_error_code ret; + ALLOC(*crypto, 1); + if (*crypto == NULL) + return krb5_enomem(context); + if(etype == ETYPE_NULL) + etype = key->keytype; + (*crypto)->et = _krb5_find_enctype(etype); + if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) { + free(*crypto); + *crypto = NULL; + return unsupported_enctype(context, etype); + } + if((*crypto)->et->keytype->size != key->keyvalue.length) { + free(*crypto); + *crypto = NULL; + krb5_set_error_message (context, KRB5_BAD_KEYSIZE, + "encryption key has bad length"); + return KRB5_BAD_KEYSIZE; + } + ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key); + if(ret) { + free(*crypto); + *crypto = NULL; + return ret; + } + (*crypto)->key.schedule = NULL; + (*crypto)->num_key_usage = 0; + (*crypto)->key_usage = NULL; + (*crypto)->flags = 0; + return 0; +} + +static void +free_key_schedule(krb5_context context, + struct _krb5_key_data *key, + struct _krb5_encryption_type *et) +{ + if (et->keytype->cleanup) + (*et->keytype->cleanup)(context, key); + memset(key->schedule->data, 0, key->schedule->length); + krb5_free_data(context, key->schedule); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_free_key_data(krb5_context context, struct _krb5_key_data *key, + struct _krb5_encryption_type *et) +{ + krb5_free_keyblock(context, key->key); + if(key->schedule) { + free_key_schedule(context, key, et); + key->schedule = NULL; + } +} + +static void +free_key_usage(krb5_context context, struct _krb5_key_usage *ku, + struct _krb5_encryption_type *et) +{ + _krb5_free_key_data(context, &ku->key, et); +} + +/** + * Free a crypto context created by krb5_crypto_init(). + * + * @param context Kerberos context + * @param crypto crypto context to free + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_destroy(krb5_context context, + krb5_crypto crypto) +{ + int i; + + for(i = 0; i < crypto->num_key_usage; i++) + free_key_usage(context, &crypto->key_usage[i], crypto->et); + free(crypto->key_usage); + _krb5_free_key_data(context, &crypto->key, crypto->et); + + if (crypto->mdctx) + EVP_MD_CTX_destroy(crypto->mdctx); + + if (crypto->hmacctx) + HMAC_CTX_free(crypto->hmacctx); + + free (crypto); + return 0; +} + +/** + * Return the blocksize used algorithm referenced by the crypto context + * + * @param context Kerberos context + * @param crypto crypto context to query + * @param blocksize the resulting blocksize + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_getblocksize(krb5_context context, + krb5_crypto crypto, + size_t *blocksize) +{ + *blocksize = crypto->et->blocksize; + return 0; +} + +/** + * Return the encryption type used by the crypto context + * + * @param context Kerberos context + * @param crypto crypto context to query + * @param enctype the resulting encryption type + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_getenctype(krb5_context context, + krb5_crypto crypto, + krb5_enctype *enctype) +{ + *enctype = crypto->et->type; + return 0; +} + +/** + * Return the padding size used by the crypto context + * + * @param context Kerberos context + * @param crypto crypto context to query + * @param padsize the return padding size + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_getpadsize(krb5_context context, + krb5_crypto crypto, + size_t *padsize) +{ + *padsize = crypto->et->padsize; + return 0; +} + +/** + * Return the confounder size used by the crypto context + * + * @param context Kerberos context + * @param crypto crypto context to query + * @param confoundersize the returned confounder size + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_getconfoundersize(krb5_context context, + krb5_crypto crypto, + size_t *confoundersize) +{ + *confoundersize = crypto->et->confoundersize; + return 0; +} + + +/** + * Disable encryption type + * + * @param context Kerberos 5 context + * @param enctype encryption type to disable + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_disable(krb5_context context, + krb5_enctype enctype) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); + if(et == NULL) { + if (context) + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + enctype); + return KRB5_PROG_ETYPE_NOSUPP; + } + et->flags |= F_DISABLED; + return 0; +} + +/** + * Enable encryption type + * + * @param context Kerberos 5 context + * @param enctype encryption type to enable + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enctype_enable(krb5_context context, + krb5_enctype enctype) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); + if(et == NULL) { + if (context) + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + enctype); + return KRB5_PROG_ETYPE_NOSUPP; + } + et->flags &= ~F_DISABLED; + return 0; +} + +/** + * Enable or disable all weak encryption types + * + * @param context Kerberos 5 context + * @param enable true to enable, false to disable + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_allow_weak_crypto(krb5_context context, + krb5_boolean enable) +{ + int i; + + for(i = 0; i < _krb5_num_etypes; i++) + if(_krb5_etypes[i]->flags & F_WEAK) { + if(enable) + _krb5_etypes[i]->flags &= ~F_DISABLED; + else + _krb5_etypes[i]->flags |= F_DISABLED; + } + return 0; +} + +/** + * Returns is the encryption is strong or weak + * + * @param context Kerberos 5 context + * @param enctype encryption type to probe + * + * @return Returns true if encryption type is weak or is not supported. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); + if(et == NULL || (et->flags & F_WEAK)) + return TRUE; + return FALSE; +} + +/** + * Returns whether the encryption type is new or old + * + * @param context Kerberos 5 context + * @param enctype encryption type to probe + * + * @return Returns true if encryption type is old or is not supported. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_is_enctype_old(krb5_context context, krb5_enctype enctype) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); + if (!et || (et->flags & F_OLD)) + return TRUE; + return FALSE; +} + +/** + * Returns whether the encryption type should use randomly generated salts + * + * @param context Kerberos 5 context + * @param enctype encryption type to probe + * + * @return Returns true if generated salts should have random component + * + * @ingroup krb5_crypto + */ +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_enctype_requires_random_salt(krb5_context context, + krb5_enctype enctype) +{ + struct _krb5_encryption_type *et; + + et = _krb5_find_enctype (enctype); + + return et && (et->flags & F_SP800_108_HMAC_KDF); +} + +static size_t +wrapped_length (krb5_context context, + krb5_crypto crypto, + size_t data_len) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t padsize = et->padsize; + size_t checksumsize = CHECKSUMSIZE(et->checksum); + size_t res; + + res = et->confoundersize + checksumsize + data_len; + res = (res + padsize - 1) / padsize * padsize; + return res; +} + +static size_t +wrapped_length_dervied (krb5_context context, + krb5_crypto crypto, + size_t data_len) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t padsize = et->padsize; + size_t res; + + res = et->confoundersize + data_len; + res = (res + padsize - 1) / padsize * padsize; + if (et->keyed_checksum) + res += et->keyed_checksum->checksumsize; + else + res += et->checksum->checksumsize; + return res; +} + +/* + * Return the size of an encrypted packet of length `data_len' + */ + +KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL +krb5_get_wrapped_length (krb5_context context, + krb5_crypto crypto, + size_t data_len) +{ + if (derived_crypto (context, crypto)) + return wrapped_length_dervied (context, crypto, data_len); + else + return wrapped_length (context, crypto, data_len); +} + +/* + * Return the size of an encrypted packet of length `data_len' + */ + +static size_t +crypto_overhead (krb5_context context, + krb5_crypto crypto) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t res; + + res = CHECKSUMSIZE(et->checksum); + res += et->confoundersize; + if (et->padsize > 1) + res += et->padsize; + return res; +} + +static size_t +crypto_overhead_dervied (krb5_context context, + krb5_crypto crypto) +{ + struct _krb5_encryption_type *et = crypto->et; + size_t res; + + if (et->keyed_checksum) + res = CHECKSUMSIZE(et->keyed_checksum); + else + res = CHECKSUMSIZE(et->checksum); + res += et->confoundersize; + if (et->padsize > 1) + res += et->padsize; + return res; +} + +KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL +krb5_crypto_overhead (krb5_context context, krb5_crypto crypto) +{ + if (derived_crypto (context, crypto)) + return crypto_overhead_dervied (context, crypto); + else + return crypto_overhead (context, crypto); +} + +/** + * Converts the random bytestring to a protocol key according to + * Kerberos crypto frame work. It may be assumed that all the bits of + * the input string are equally random, even though the entropy + * present in the random source may be limited. + * + * @param context Kerberos 5 context + * @param type the enctype resulting key will be of + * @param data input random data to convert to a key + * @param size size of input random data, at least krb5_enctype_keysize() long + * @param key key, output key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_random_to_key(krb5_context context, + krb5_enctype type, + const void *data, + size_t size, + krb5_keyblock *key) +{ + krb5_error_code ret; + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + if(et == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + type); + return KRB5_PROG_ETYPE_NOSUPP; + } + if ((et->keytype->bits + 7) / 8 > size) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption key %s needs %d bytes " + "of random to make an encryption key " + "out of it", ""), + et->name, (int)et->keytype->size); + return KRB5_PROG_ETYPE_NOSUPP; + } + ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); + if(ret) + return ret; + key->keytype = type; + if (et->keytype->random_to_key) + (*et->keytype->random_to_key)(context, key, data, size); + else + memcpy(key->keyvalue.data, data, et->keytype->size); + + return 0; +} + + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_prf_length(krb5_context context, + krb5_enctype type, + size_t *length) +{ + struct _krb5_encryption_type *et = _krb5_find_enctype(type); + + if(et == NULL || et->prf_length == 0) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + type); + return KRB5_PROG_ETYPE_NOSUPP; + } + + *length = et->prf_length; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_prf(krb5_context context, + const krb5_crypto crypto, + const krb5_data *input, + krb5_data *output) +{ + struct _krb5_encryption_type *et = crypto->et; + + krb5_data_zero(output); + + if(et->prf == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "kerberos prf for %s not supported", + et->name); + return KRB5_PROG_ETYPE_NOSUPP; + } + + return (*et->prf)(context, crypto, input, output); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_prfplus(krb5_context context, + const krb5_crypto crypto, + const krb5_data *input, + size_t length, + krb5_data *output) +{ + krb5_error_code ret; + krb5_data input2; + unsigned char i = 1; + unsigned char *p; + + krb5_data_zero(&input2); + krb5_data_zero(output); + + krb5_clear_error_message(context); + + ret = krb5_data_alloc(output, length); + if (ret) goto out; + ret = krb5_data_alloc(&input2, input->length + 1); + if (ret) goto out; + + krb5_clear_error_message(context); + + memcpy(((unsigned char *)input2.data) + 1, input->data, input->length); + + p = output->data; + + while (length) { + krb5_data block; + + ((unsigned char *)input2.data)[0] = i++; + + ret = krb5_crypto_prf(context, crypto, &input2, &block); + if (ret) + goto out; + + if (block.length < length) { + memcpy(p, block.data, block.length); + length -= block.length; + } else { + memcpy(p, block.data, length); + length = 0; + } + p += block.length; + krb5_data_free(&block); + } + + out: + krb5_data_free(&input2); + if (ret) + krb5_data_free(output); + return ret; +} + +/** + * The FX-CF2 key derivation function, used in FAST and preauth framework. + * + * @param context Kerberos 5 context + * @param crypto1 first key to combine + * @param crypto2 second key to combine + * @param pepper1 factor to combine with first key to guarantee uniqueness + * @param pepper2 factor to combine with second key to guarantee uniqueness + * @param enctype the encryption type of the resulting key + * @param res allocated key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_crypto_fx_cf2(krb5_context context, + const krb5_crypto crypto1, + const krb5_crypto crypto2, + krb5_data *pepper1, + krb5_data *pepper2, + krb5_enctype enctype, + krb5_keyblock *res) +{ + krb5_error_code ret; + krb5_data os1, os2; + size_t i, keysize; + + memset(res, 0, sizeof(*res)); + krb5_data_zero(&os1); + krb5_data_zero(&os2); + + ret = krb5_enctype_keybits(context, enctype, &keysize); + if (ret) + return ret; + keysize = (keysize + 7) / 8; + + ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1); + if (ret) + goto out; + ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2); + if (ret) + goto out; + + res->keytype = enctype; + { + unsigned char *p1 = os1.data, *p2 = os2.data; + for (i = 0; i < keysize; i++) + p1[i] ^= p2[i]; + } + ret = krb5_random_to_key(context, enctype, os1.data, keysize, res); + out: + krb5_data_free(&os1); + krb5_data_free(&os2); + + return ret; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_crypto_set_flags(krb5_context context, + krb5_crypto crypto, + krb5_flags flags) +{ + crypto->flags |= flags; +} + +#ifndef HEIMDAL_SMALLER + +/** + * Deprecated: keytypes don't exist, they are really enctypes. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_keytype_to_enctypes (krb5_context context, + krb5_keytype keytype, + unsigned *len, + krb5_enctype **val) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + int i; + unsigned n = 0; + krb5_enctype *ret; + + for (i = _krb5_num_etypes - 1; i >= 0; --i) { + if (_krb5_etypes[i]->keytype->type == keytype + && !(_krb5_etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) + ++n; + } + if (n == 0) { + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "Keytype has no mapping"); + return KRB5_PROG_KEYTYPE_NOSUPP; + } + + ret = malloc(n * sizeof(*ret)); + if (ret == NULL && n != 0) + return krb5_enomem(context); + n = 0; + for (i = _krb5_num_etypes - 1; i >= 0; --i) { + if (_krb5_etypes[i]->keytype->type == keytype + && !(_krb5_etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) + ret[n++] = _krb5_etypes[i]->type; + } + *len = n; + *val = ret; + return 0; +} + +/** + * Deprecated: keytypes don't exist, they are really enctypes. + * + * @ingroup krb5_deprecated + */ + +/* if two enctypes have compatible keys */ +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_enctypes_compatible_keys(krb5_context context, + krb5_enctype etype1, + krb5_enctype etype2) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1); + struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2); + return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/crypto.h b/third_party/heimdal/lib/krb5/crypto.h new file mode 100644 index 0000000..d02f841 --- /dev/null +++ b/third_party/heimdal/lib/krb5/crypto.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1997 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HEIMDAL_SMALLER +#define DES3_OLD_ENCTYPE 1 +#endif + +struct _krb5_key_data { + krb5_keyblock *key; + krb5_data *schedule; +}; + +struct _krb5_key_usage; + +#define CRYPTO_ETYPE(C) ((C)->et->type) + +/* bits for `flags' below */ +#define F_KEYED 0x0001 /* checksum is keyed */ +#define F_CPROOF 0x0002 /* checksum is collision proof */ +#define F_DERIVED 0x0004 /* uses derived keys */ +#define F_VARIANT 0x0008 /* uses `variant' keys (6.4.3) */ +#define F_PSEUDO 0x0010 /* not a real protocol type */ +#define F_DISABLED 0x0020 /* enctype/checksum disabled */ +#define F_WEAK 0x0040 /* enctype is considered weak */ +#define F_OLD 0x0080 /* enctype is old */ + +#define F_RFC3961_ENC 0x0100 /* RFC3961 simplified profile */ +#define F_SPECIAL 0x0200 /* backwards */ +#define F_ENC_THEN_CKSUM 0x0400 /* checksum is over encrypted data */ +#define F_CRYPTO_MASK 0x0F00 + +#define F_RFC3961_KDF 0x1000 /* RFC3961 KDF */ +#define F_SP800_108_HMAC_KDF 0x2000 /* SP800-108 HMAC KDF */ +#define F_KDF_MASK 0xF000 + +struct salt_type { + krb5_salttype type; + const char *name; + krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data, + krb5_salt, krb5_data, krb5_keyblock*); +}; + +struct _krb5_key_type { + krb5_enctype type; + const char *name; + size_t bits; + size_t size; + size_t schedule_size; + void (*random_key)(krb5_context, krb5_keyblock*); + void (*schedule)(krb5_context, struct _krb5_key_type *, struct _krb5_key_data *); + struct salt_type *string_to_key; + void (*random_to_key)(krb5_context, krb5_keyblock*, const void*, size_t); + void (*cleanup)(krb5_context, struct _krb5_key_data *); + const EVP_CIPHER *(*evp)(void); +}; + +struct _krb5_checksum_type { + krb5_cksumtype type; + const char *name; + size_t blocksize; + size_t checksumsize; + unsigned flags; + krb5_error_code (*checksum)(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, int niov, + Checksum *csum); + krb5_error_code (*verify)(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, int niov, + Checksum *csum); +}; + +struct _krb5_encryption_type { + krb5_enctype type; + const char *name; + const char *alias; + size_t blocksize; + size_t padsize; + size_t confoundersize; + struct _krb5_key_type *keytype; + struct _krb5_checksum_type *checksum; + struct _krb5_checksum_type *keyed_checksum; + unsigned flags; + krb5_error_code (*encrypt)(krb5_context context, + struct _krb5_key_data *key, + void *data, size_t len, + krb5_boolean encryptp, + int usage, + void *ivec); + krb5_error_code (*encrypt_iov)(krb5_context context, + struct _krb5_key_data *key, + krb5_crypto_iov *iov, int niov, + krb5_boolean encryptp, + int usage, + void *ivec); + size_t prf_length; + krb5_error_code (*prf)(krb5_context, + krb5_crypto, const krb5_data *, krb5_data *); +}; + +#define ENCRYPTION_USAGE(U) (((uint32_t)(U) << 8) | 0xAA) +#define INTEGRITY_USAGE(U) (((uint32_t)(U) << 8) | 0x55) +#define CHECKSUM_USAGE(U) (((uint32_t)(U) << 8) | 0x99) + +/* Checksums */ + +extern struct _krb5_checksum_type _krb5_checksum_none; +extern struct _krb5_checksum_type _krb5_checksum_crc32; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md4; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md4_des; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md5_des; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md5_des3; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md5; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_des3; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha256_128_aes128; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha384_192_aes256; +extern struct _krb5_checksum_type _krb5_checksum_hmac_md5; +extern struct _krb5_checksum_type _krb5_checksum_sha1; +extern struct _krb5_checksum_type _krb5_checksum_sha256; +extern struct _krb5_checksum_type _krb5_checksum_sha384; +extern struct _krb5_checksum_type _krb5_checksum_sha512; + +extern struct _krb5_checksum_type *_krb5_checksum_types[]; +extern int _krb5_num_checksums; + +/* Salts */ + +extern struct salt_type _krb5_AES_SHA1_salt[]; +extern struct salt_type _krb5_AES_SHA2_salt[]; +extern struct salt_type _krb5_arcfour_salt[]; +extern struct salt_type _krb5_des_salt[]; +extern struct salt_type _krb5_des3_salt[]; +extern struct salt_type _krb5_des3_salt_derived[]; + +/* Encryption types */ + +extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1; +extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1; +extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha256_128; +extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha384_192; +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1; +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_md5; +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_none; +extern struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_md5; +extern struct _krb5_encryption_type _krb5_enctype_old_des3_cbc_sha1; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_crc; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_md4; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_md5; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_none; +extern struct _krb5_encryption_type _krb5_enctype_des_cfb64_none; +extern struct _krb5_encryption_type _krb5_enctype_des_pcbc_none; +extern struct _krb5_encryption_type _krb5_enctype_null; + +extern struct _krb5_encryption_type *_krb5_etypes[]; +extern int _krb5_num_etypes; + +static inline int +_krb5_crypto_iov_should_sign(const struct krb5_crypto_iov *iov) +{ + return (iov->flags == KRB5_CRYPTO_TYPE_DATA + || iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY + || iov->flags == KRB5_CRYPTO_TYPE_HEADER + || iov->flags == KRB5_CRYPTO_TYPE_PADDING); +} + +/* NO_HCRYPTO_POLLUTION is defined in pkinit-ec.c. See commentary there. */ +#ifndef NO_HCRYPTO_POLLUTION +/* Interface to the EVP crypto layer provided by hcrypto */ +struct _krb5_evp_schedule { + /* + * Normally we'd say EVP_CIPHER_CTX here, but! this header gets + * included in lib/krb5/pkinit-ec.c + */ + EVP_CIPHER_CTX ectx; + EVP_CIPHER_CTX dctx; +}; + +struct krb5_crypto_data { + struct _krb5_encryption_type *et; + struct _krb5_key_data key; + EVP_MD_CTX *mdctx; + HMAC_CTX *hmacctx; + int num_key_usage; + struct _krb5_key_usage *key_usage; + krb5_flags flags; +}; + +/* + * Allow generation and verification of unkeyed checksums even when + * key material is available. + */ +#define KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM 0x01 + +#endif diff --git a/third_party/heimdal/lib/krb5/data.c b/third_party/heimdal/lib/krb5/data.c new file mode 100644 index 0000000..abfa053 --- /dev/null +++ b/third_party/heimdal/lib/krb5/data.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Reset the (potentially uninitialized) krb5_data structure. + * + * @param p krb5_data to reset. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_data_zero(krb5_data *p) +{ + p->length = 0; + p->data = NULL; +} + +/** + * Free the content of krb5_data structure, its ok to free a zeroed + * structure (with memset() or krb5_data_zero()). When done, the + * structure will be zeroed. The same function is called + * krb5_free_data_contents() in MIT Kerberos. + * + * @param p krb5_data to free. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_data_free(krb5_data *p) +{ + free(p->data); + krb5_data_zero(p); +} + +/** + * Free krb5_data (and its content). + * + * @param context Kerberos 5 context. + * @param p krb5_data to free. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_data(krb5_context context, + krb5_data *p) +{ + krb5_data_free(p); + free(p); +} + +/** + * Allocate data of and krb5_data. + * + * @param p krb5_data to allocate. + * @param len size to allocate. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_data_alloc(krb5_data *p, int len) +{ + p->data = malloc(len); + if(len && p->data == NULL) + return ENOMEM; + p->length = len; + return 0; +} + +/** + * Grow (or shrink) the content of krb5_data to a new size. + * + * @param p krb5_data to free. + * @param len new size. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_data_realloc(krb5_data *p, int len) +{ + void *tmp; + tmp = realloc(p->data, len); + if(len && !tmp) + return ENOMEM; + p->data = tmp; + p->length = len; + return 0; +} + +/** + * Copy the data of len into the krb5_data. + * + * @param p krb5_data to copy into. + * @param data data to copy.. + * @param len new size. + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_data_copy(krb5_data *p, const void *data, size_t len) +{ + if (len) { + if(krb5_data_alloc(p, len)) + return ENOMEM; + memcpy(p->data, data, len); + } else + p->data = NULL; + p->length = len; + return 0; +} + +/** + * Copy the data into a newly allocated krb5_data. + * + * @param context Kerberos 5 context. + * @param indata the krb5_data data to copy + * @param outdata new krb5_date to copy too. Free with krb5_free_data(). + * + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_data(krb5_context context, + const krb5_data *indata, + krb5_data **outdata) +{ + krb5_error_code ret; + ALLOC(*outdata, 1); + if(*outdata == NULL) + return krb5_enomem(context); + ret = der_copy_octet_string(indata, *outdata); + if(ret) { + krb5_clear_error_message (context); + free(*outdata); + *outdata = NULL; + } + return ret; +} + +/** + * Compare to data. + * + * @param data1 krb5_data to compare + * @param data2 krb5_data to compare + * + * @return return the same way as memcmp(), useful when sorting. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_data_cmp(const krb5_data *data1, const krb5_data *data2) +{ + size_t len = data1->length < data2->length ? data1->length : data2->length; + int cmp = memcmp(data1->data, data2->data, len); + + if (cmp == 0) + return data1->length - data2->length; + return cmp; +} + +/** + * Compare to data not exposing timing information from the checksum data + * + * @param data1 krb5_data to compare + * @param data2 krb5_data to compare + * + * @return returns zero for same data, otherwise non zero. + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_data_ct_cmp(const krb5_data *data1, const krb5_data *data2) +{ + if (data1->length != data2->length) + return data1->length - data2->length; + return ct_memcmp(data1->data, data2->data, data1->length); +} diff --git a/third_party/heimdal/lib/krb5/db_plugin.c b/third_party/heimdal/lib/krb5/db_plugin.c new file mode 100644 index 0000000..e997d3d --- /dev/null +++ b/third_party/heimdal/lib/krb5/db_plugin.c @@ -0,0 +1,41 @@ +/* + */ + +#include "krb5_locl.h" +#include "db_plugin.h" + +/* Default plugin (DB using binary search of sorted text file) follows */ +static heim_base_once_t db_plugins_once = HEIM_BASE_ONCE_INIT; + +static krb5_error_code KRB5_LIB_CALL +db_plugins_plcallback(krb5_context context, const void *plug, void *plugctx, + void *userctx) +{ + return 0; +} + +static const char *const db_plugin_deps[] = { "krb5", NULL }; + +static const struct heim_plugin_data +db_plugin_data = { + "krb5", + KRB5_PLUGIN_DB, + KRB5_PLUGIN_DB_VERSION_0, + db_plugin_deps, + krb5_get_instance +}; + +static void +db_plugins_init(void *arg) +{ + krb5_context context = arg; + (void)_krb5_plugin_run_f(context, &db_plugin_data, 0, NULL, + db_plugins_plcallback); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_load_db_plugins(krb5_context context) +{ + heim_base_once_f(&db_plugins_once, context, db_plugins_init); +} + diff --git a/third_party/heimdal/lib/krb5/db_plugin.h b/third_party/heimdal/lib/krb5/db_plugin.h new file mode 100644 index 0000000..ab676d5 --- /dev/null +++ b/third_party/heimdal/lib/krb5/db_plugin.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIMDAL_KRB5_DB_PLUGIN_H +#define HEIMDAL_KRB5_DB_PLUGIN_H 1 + +#include + +#define KRB5_PLUGIN_DB "krb5_db_plug" +#define KRB5_PLUGIN_DB_VERSION_0 0 + +/** @struct krb5plugin_db_ftable_desc + * + * @brief Description of the krb5 DB plugin facility. + * + * The krb5_aname_to_lname(3) function's DB rule is pluggable. The + * plugin is named KRB5_PLUGIN_DB ("krb5_db_plug"), with a single minor + * version, KRB5_PLUGIN_DB_VERSION_0 (0). + * + * The plugin consists of a data symbol referencing a structure of type + * krb5plugin_db_ftable_desc, with three fields: + * + * @param init Plugin initialization function (see krb5-plugin(7)) + * + * @param minor_version The plugin minor version number (0) + * + * @param fini Plugin finalization function + * + * The init entry point is expected to call heim_db_register(). The + * fini entry point is expected to do nothing. + * + * @ingroup krb5_support + */ +typedef struct krb5plugin_db_ftable_desc { + HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context); +} krb5plugin_db_ftable; + +#endif /* HEIMDAL_KRB5_DB_PLUGIN_H */ + diff --git a/third_party/heimdal/lib/krb5/dcache.c b/third_party/heimdal/lib/krb5/dcache.c new file mode 100644 index 0000000..77ccda1 --- /dev/null +++ b/third_party/heimdal/lib/krb5/dcache.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +typedef struct krb5_dcache{ + krb5_ccache fcache; + char *name; + char *dir; + char *sub; + unsigned int default_candidate:1; +} krb5_dcache; + +#define DCACHE(X) ((krb5_dcache*)(X)->data.data) +#define D2FCACHE(X) ((X)->fcache) + +static krb5_error_code KRB5_CALLCONV dcc_close(krb5_context, krb5_ccache); +static krb5_error_code KRB5_CALLCONV dcc_get_default_name(krb5_context, char **); +static krb5_error_code KRB5_CALLCONV dcc_set_default(krb5_context, krb5_ccache); + +/* + * Make subsidiary filesystem safe by mapping / and : to -. If the subsidiary + * is longer than 128 bytes, then truncate. + * In all cases, "tkt." is prefixed to be compatible with the DIR requirement + * that subsidiary ccache files be named tkt*. + * + * Thus host/foo.bar.baz@BAR.BAZ -> tkt.host-foo.bar.baz@BAR.BAZ. + * + * In particular, no filesystem component separators will be emitted, and . and + * .. will never be traversed. + */ +static krb5_error_code +fs_encode_subsidiary(krb5_context context, + krb5_dcache *dc, + const char *subsidiary, + char **res) +{ + size_t len = strlen(subsidiary); + size_t i; + + *res = NULL; + if (asprintf(res, "tkt.%s", subsidiary) == -1 || *res == NULL) + return krb5_enomem(context); + for (i = sizeof("tkt.") - 1; i < len; i++) { + switch ((*res)[i]) { +#ifdef WIN32 + case '\\': (*res)[0] = '-'; break; +#endif + case '/': (*res)[0] = '-'; break; + case ':': (*res)[0] = '-'; break; + default: break; + } + } + + /* Hopefully this will work on all filesystems */ + if (len > 128 - sizeof("tkt.") - 1) + (*res)[127] = '\0'; + return 0; +} + +static char * +primary_create(krb5_dcache *dc) +{ + char *primary = NULL; + int asprintf_ret = asprintf(&primary, "%s/primary", dc->dir); + if (asprintf_ret == -1 || primary == NULL) { + return NULL; + } + + return primary; +} + +static int +is_filename_cacheish(const char *name) +{ + size_t i; + + if (strncmp(name, "tkt", sizeof("tkt") - 1) != 0) + return 0; + for (i = sizeof("tkt") - 1; name[i]; i++) + if (ISPATHSEP(name[i])) + return 0; + return 1; +} + +static krb5_error_code +set_default_cache(krb5_context context, krb5_dcache *dc, const char *residual) +{ + char *path = NULL, *primary = NULL; + krb5_error_code ret; + struct iovec iov[2]; + size_t len; + int fd = -1; + int asprintf_ret; + + asprintf_ret = asprintf(&path, "%s/primary-XXXXXX", dc->dir); + if (asprintf_ret == -1 || path == NULL) { + return krb5_enomem(context); + } + + fd = mkstemp(path); + if (fd < 0) { + ret = errno; + goto out; + } + rk_cloexec(fd); +#ifndef _WIN32 + if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) { + ret = errno; + goto out; + } +#endif + len = strlen(residual); + + iov[0].iov_base = rk_UNCONST(residual); + iov[0].iov_len = len; + iov[1].iov_base = "\n"; + iov[1].iov_len = 1; + + if (writev(fd, iov, sizeof(iov)/sizeof(iov[0])) != len + 1) { + ret = errno; + goto out; + } + + primary = primary_create(dc); + if (primary == NULL) { + ret = krb5_enomem(context); + goto out; + } + + if (rename(path, primary) < 0) { + ret = errno; + goto out; + } + + close(fd); + fd = -1; + + ret = 0; + out: + if (fd >= 0) { + (void)unlink(path); + close(fd); + } + if (path) + free(path); + if (primary) + free(primary); + + return ret; +} + +static krb5_error_code +get_default_cache(krb5_context context, krb5_dcache *dc, + const char *subsidiary, char **residual) +{ + krb5_error_code ret; + char buf[MAXPATHLEN]; + char *primary = NULL; + FILE *f; + + *residual = NULL; + if (subsidiary) + return fs_encode_subsidiary(context, dc, subsidiary, residual); + + primary = primary_create(dc); + if (primary == NULL) + return krb5_enomem(context); + + f = fopen(primary, "r"); + if (f == NULL) { + if (errno == ENOENT) { + free(primary); + *residual = strdup("tkt"); + if (*residual == NULL) + return krb5_enomem(context); + return 0; + } + ret = errno; + krb5_set_error_message(context, ret, "failed to open %s", primary); + free(primary); + return ret; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + ret = ferror(f); + fclose(f); + krb5_set_error_message(context, ret, "read file %s", primary); + free(primary); + return ret; + } + fclose(f); + + buf[strcspn(buf, "\r\n")] = '\0'; + + if (!is_filename_cacheish(buf)) { + krb5_set_error_message(context, KRB5_CC_FORMAT, + "name in %s is not a cache (doesn't start with tkt)", primary); + free(primary); + return KRB5_CC_FORMAT; + } + + free(primary); + + *residual = strdup(buf); + if (*residual == NULL) + return krb5_enomem(context); + + return 0; +} + + + +static krb5_error_code KRB5_CALLCONV +dcc_get_name_2(krb5_context context, + krb5_ccache id, + const char **name, + const char **dir, + const char **sub) +{ + krb5_dcache *dc = DCACHE(id); + + if (name) + *name = dc->name; + if (dir) + *dir = dc->dir; + if (sub) + *sub = dc->sub; + return 0; +} + + +static krb5_error_code +verify_directory(krb5_context context, const char *path) +{ + struct stat sb; + + if (!path[0]) { + krb5_set_error_message(context, EINVAL, + N_("DIR empty directory component", "")); + return EINVAL; + } + + /* XXX should use mkdirx_np() */ + if (rk_mkdir(path, S_IRWXU) == 0) + return 0; + + if (stat(path, &sb) != 0) { + if (errno == ENOENT) { + krb5_set_error_message(context, ENOENT, + N_("DIR directory %s doesn't exists", ""), path); + return ENOENT; + } else { + krb5_set_error_message(context, errno, + N_("DIR directory %s is bad: %s", ""), path, strerror(errno)); + return errno; + } + } + if (!S_ISDIR(sb.st_mode)) { + krb5_set_error_message(context, KRB5_CC_BADNAME, + N_("DIR directory %s is not a directory", ""), path); + return KRB5_CC_BADNAME; + } + + return 0; +} + +static void +dcc_release(krb5_context context, krb5_dcache *dc) +{ + if (dc->fcache) + krb5_cc_close(context, dc->fcache); + free(dc->sub); + free(dc->dir); + free(dc->name); + memset(dc, 0, sizeof(*dc)); + free(dc); +} + +static krb5_error_code +get_default_dir(krb5_context context, char **res) +{ + krb5_error_code ret; + char *s; + + if ((ret = dcc_get_default_name(context, &s))) + return ret; + if (strncmp(s, "DIR:", sizeof("DIR:") - 1) != 0) { + *res = s; + s = NULL; + } else if ((*res = strdup(s + sizeof("DIR:") - 1)) == NULL) { + ret = krb5_enomem(context); + } + free(s); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +dcc_resolve_2(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) +{ + krb5_error_code ret; + krb5_dcache *dc = NULL; + char *filename = NULL; + size_t len; + int has_pathsep = 0; + + if (sub) { + /* + * Here `res' has the directory name (or, if NULL, refers to the + * default DIR cccol), and `sub' has the "subsidiary" name, to which + * we'll prefix "tkt." (though we will insist only on "tkt" later). + */ + if ((dc = calloc(1, sizeof(*dc))) == NULL || + asprintf(&dc->sub, "tkt.%s", sub) == -1 || dc->sub == NULL) { + free(dc); + return krb5_enomem(context); + } + if (res && res[0] && (dc->dir = strdup(res)) == NULL) { + free(dc->sub); + free(dc); + return krb5_enomem(context); + } else if ((!res || !res[0]) && (ret = get_default_dir(context, &dc->dir))) { + free(dc->sub); + free(dc); + return ret; + } + } else { + const char *p; + int is_drive_letter_colon = 0; + + /* + * Here `res' has whatever string followed "DIR:", and we need to parse + * it into `dc->dir' and `dc->sub'. + * + * Conventions we support for DIR cache naming: + * + * - DIR:path:NAME ---> FILE:path/tktNAME + * - DIR::path/tktNAME ---> FILE:path/tktNAME + * - DIR::NAME ---> FILE:${default_DIR_cccol_path}/tktNAME + * \-> FILE:/tmp/krb5cc_${uid}_dir/tktNAME + * - DIR:path ---> FILE:path/$(cat primary) or FILE:path/tkt + * + */ + + if (res == NULL || *res == '\0' || (res[0] == ':' && res[1] == '\0')) { + /* XXX Why not? */ + krb5_set_error_message(context, KRB5_CC_FORMAT, + N_("\"DIR:\" is not a valid ccache name", "")); + return KRB5_CC_FORMAT; + } + +#ifdef WIN32 + has_pathsep = strchr(res, '\\') != NULL; +#endif + has_pathsep |= strchr(res, '/') != NULL; + + if ((dc = calloc(1, sizeof(*dc))) == NULL) + return krb5_enomem(context); + + p = strrchr(res, ':'); +#ifdef WIN32 + is_drive_letter_colon = + p && ((res[0] == ':' && res[1] != ':' && p - res == 2) || + (res[0] != ':' && p - res == 1)); +#endif + + if (res[0] != ':' && p && !is_drive_letter_colon) { + /* DIR:path:NAME */ + if ((dc->dir = strndup(res, (p - res))) == NULL || + asprintf(&dc->sub, "tkt.%s", p + 1) < 0 || dc->sub == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } + } else if (res[0] == ':' && has_pathsep) { + char *q; + + /* DIR::path/tktNAME (the "tkt" must be there; we'll check) */ + if ((dc->dir = strdup(&res[1])) == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } +#ifdef _WIN32 + q = strrchr(dc->dir, '\\'); + if (q == NULL || ((p = strrchr(dc->dir, '/')) && q < p)) +#endif + q = strrchr(dc->dir, '/'); + *q++ = '\0'; + if ((dc->sub = strdup(q)) == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } + } else if (res[0] == ':') { + /* DIR::NAME -- no path component separators in NAME */ + if ((ret = get_default_dir(context, &dc->dir))) { + dcc_release(context, dc); + return ret; + } + if (asprintf(&dc->sub, "tkt.%s", res + 1) < 0 || dc->sub == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } + } else { + /* DIR:path */ + if ((dc->dir = strdup(res)) == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } + + if ((ret = get_default_cache(context, dc, NULL, &dc->sub))) { + dcc_release(context, dc); + return ret; + } + } + } + + /* Strip off extra slashes on the end */ + for (len = strlen(dc->dir); + len && ISPATHSEP(dc->dir[len - 1]); + len--) + dc->dir[len - 1] = '\0'; + + /* If we got here then `dc->dir' and `dc->sub' must both be set */ + + if ((ret = verify_directory(context, dc->dir))) { + dcc_release(context, dc); + return ret; + } + if (!is_filename_cacheish(dc->sub)) { + krb5_set_error_message(context, KRB5_CC_FORMAT, + N_("Name %s is not a cache " + "(doesn't start with tkt)", ""), dc->sub); + dcc_release(context, dc); + return KRB5_CC_FORMAT; + } + if (asprintf(&dc->name, ":%s/%s", dc->dir, dc->sub) == -1 || + dc->name == NULL || + asprintf(&filename, "FILE%s", dc->name) == -1 || filename == NULL) { + dcc_release(context, dc); + return krb5_enomem(context); + } + + ret = krb5_cc_resolve(context, filename, &dc->fcache); + free(filename); + if (ret) { + dcc_release(context, dc); + return ret; + } + + dc->default_candidate = 1; + (*id)->data.data = dc; + (*id)->data.length = sizeof(*dc); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +dcc_gen_new(krb5_context context, krb5_ccache *id) +{ + krb5_error_code ret; + char *def_dir = NULL; + char *name = NULL; + int fd = -1; + + ret = get_default_dir(context, &def_dir); + if (ret == 0) + ret = verify_directory(context, def_dir); + if (ret == 0 && + (asprintf(&name, "DIR::%s/tktXXXXXX", def_dir) == -1 || name == NULL)) + ret = krb5_enomem(context); + if (ret == 0 && (fd = mkstemp(name + sizeof("DIR::") - 1)) == -1) + ret = errno; + if (ret == 0) + ret = dcc_resolve_2(context, id, name + sizeof("DIR:") - 1, NULL); + + free(def_dir); + free(name); + if (fd != -1) + close(fd); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +dcc_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_initialize(context, D2FCACHE(dc), primary_principal); +} + +static krb5_error_code KRB5_CALLCONV +dcc_close(krb5_context context, + krb5_ccache id) +{ + krb5_dcache *dc = DCACHE(id); + krb5_principal p = NULL; + struct stat st; + char *primary = NULL; + + /* + * If there's no default cache, but we're closing one, and the one we're + * closing has been initialized, then make it the default. This makes the + * first cache created the default. + * + * FIXME We should check if `D2FCACHE(dc)' has live credentials. + */ + if (dc->default_candidate && D2FCACHE(dc) && + krb5_cc_get_principal(context, D2FCACHE(dc), &p) == 0 && + (primary = primary_create(dc)) && + (stat(primary, &st) == -1 || !S_ISREG(st.st_mode) || st.st_size == 0)) + dcc_set_default(context, id); + krb5_free_principal(context, p); + free(primary); + dcc_release(context, DCACHE(id)); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +dcc_destroy(krb5_context context, + krb5_ccache id) +{ + krb5_dcache *dc = DCACHE(id); + krb5_ccache fcache = D2FCACHE(dc); + dc->fcache = NULL; + return krb5_cc_destroy(context, fcache); +} + +static krb5_error_code KRB5_CALLCONV +dcc_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_store_cred(context, D2FCACHE(dc), creds); +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_get_principal(context, D2FCACHE(dc), principal); +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_first (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_start_seq_get(context, D2FCACHE(dc), cursor); +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_next (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_next_cred(context, D2FCACHE(dc), cursor, creds); +} + +static krb5_error_code KRB5_CALLCONV +dcc_end_get (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_end_seq_get(context, D2FCACHE(dc), cursor); +} + +static krb5_error_code KRB5_CALLCONV +dcc_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *cred) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_remove_cred(context, D2FCACHE(dc), which, cred); +} + +static krb5_error_code KRB5_CALLCONV +dcc_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_set_flags(context, D2FCACHE(dc), flags); +} + +static int KRB5_CALLCONV +dcc_get_version(krb5_context context, + krb5_ccache id) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_get_version(context, D2FCACHE(dc)); +} + +struct dcache_iter { + char *primary; + krb5_dcache *dc; + DIR *d; + unsigned int first:1; +}; + +static krb5_error_code KRB5_CALLCONV +dcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct dcache_iter *iter = NULL; + const char *name = krb5_cc_default_name(context); + size_t len; + char *p; + + *cursor = NULL; + + if (strncmp(name, "DIR:", sizeof("DIR:") - 1) != 0) { + krb5_set_error_message(context, KRB5_CC_FORMAT, + N_("Can't list DIR caches unless its the default type", "")); + return KRB5_CC_FORMAT; + } + + if ((iter = calloc(1, sizeof(*iter))) == NULL || + (iter->dc = calloc(1, sizeof(iter->dc[0]))) == NULL || + (iter->dc->dir = strdup(name + sizeof("DIR:") - 1)) == NULL) { + if (iter) + free(iter->dc); + free(iter); + return krb5_enomem(context); + } + iter->first = 1; + p = strrchr(iter->dc->dir, ':'); +#ifdef WIN32 + if (p == iter->dc->dir + 1) + p = NULL; +#endif + if (p) + *p = '\0'; + + /* Strip off extra slashes on the end */ + for (len = strlen(iter->dc->dir); + len && ISPATHSEP(iter->dc->dir[len - 1]); + len--) { + iter->dc->dir[len - 1] = '\0'; + } + + if ((iter->d = opendir(iter->dc->dir)) == NULL) { + krb5_set_error_message(context, KRB5_CC_FORMAT, + N_("Can't open DIR %s: %s", ""), + iter->dc->dir, strerror(errno)); + free(iter->dc->dir); + free(iter->dc); + free(iter); + return KRB5_CC_FORMAT; + } + + *cursor = iter; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct dcache_iter *iter = cursor; + krb5_error_code ret; + struct stat st; + struct dirent *dentry; + char *p = NULL; + + *id = NULL; + if (iter == NULL) + return krb5_einval(context, 2); + + /* Emit primary subsidiary first */ + if (iter->first && + get_default_cache(context, iter->dc, NULL, &iter->primary) == 0 && + iter->primary && is_filename_cacheish(iter->primary)) { + iter->first = 0; + ret = KRB5_CC_END; + if (asprintf(&p, "FILE:%s/%s", iter->dc->dir, iter->primary) > -1 && p != NULL && + stat(p + sizeof("FILE:") - 1, &st) == 0 && S_ISREG(st.st_mode)) + ret = krb5_cc_resolve(context, p, id); + if (p == NULL) + return krb5_enomem(context); + free(p); + if (ret == 0) + return ret; + p = NULL; + } + + iter->first = 0; + for (dentry = readdir(iter->d); dentry; dentry = readdir(iter->d)) { + if (!is_filename_cacheish(dentry->d_name) || + (iter->primary && strcmp(dentry->d_name, iter->primary) == 0)) + continue; + p = NULL; + ret = KRB5_CC_END; + if (asprintf(&p, "FILE:%s/%s", iter->dc->dir, dentry->d_name) > -1 && + p != NULL && + stat(p + sizeof("FILE:") - 1, &st) == 0 && S_ISREG(st.st_mode)) + ret = krb5_cc_resolve(context, p, id); + free(p); + if (p == NULL) + return krb5_enomem(context); + if (ret == 0) + return ret; + } + return KRB5_CC_END; +} + +static krb5_error_code KRB5_CALLCONV +dcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct dcache_iter *iter = cursor; + + if (iter == NULL) + return krb5_einval(context, 2); + + (void) closedir(iter->d); + free(iter->dc->dir); + free(iter->dc); + free(iter->primary); + free(iter); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +dcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_dcache *dcfrom = DCACHE(from); + krb5_dcache *dcto = DCACHE(to); + + dcfrom->default_candidate = 0; + dcto->default_candidate = 1; + return krb5_cc_move(context, D2FCACHE(dcfrom), D2FCACHE(dcto)); +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_default_name(krb5_context context, char **str) +{ + const char *def_cc_colname = + krb5_config_get_string_default(context, NULL, KRB5_DEFAULT_CCNAME_DIR, + "libdefaults", "default_cc_collection", + NULL); + + /* [libdefaults] default_cc_collection is for testing */ + if (strncmp(def_cc_colname, "DIR:", sizeof("DIR:") - 1) != 0) + def_cc_colname = KRB5_DEFAULT_CCNAME_DIR; + return _krb5_expand_default_cc_name(context, def_cc_colname, str); +} + +static krb5_error_code KRB5_CALLCONV +dcc_set_default(krb5_context context, krb5_ccache id) +{ + krb5_dcache *dc = DCACHE(id); + + if (dc->sub == NULL) + return ENOENT; + return set_default_cache(context, dc, dc->sub); +} + +static krb5_error_code KRB5_CALLCONV +dcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_last_change_time(context, D2FCACHE(dc), mtime); +} + +static krb5_error_code KRB5_CALLCONV +dcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_set_kdc_offset(context, D2FCACHE(dc), kdc_offset); +} + +static krb5_error_code KRB5_CALLCONV +dcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset) +{ + krb5_dcache *dc = DCACHE(id); + return krb5_cc_get_kdc_offset(context, D2FCACHE(dc), kdc_offset); +} + + +/** + * Variable containing the DIR based credential cache implemention. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_VARIABLE const krb5_cc_ops krb5_dcc_ops = { + KRB5_CC_OPS_VERSION_5, + "DIR", + NULL, + NULL, + dcc_gen_new, + dcc_initialize, + dcc_destroy, + dcc_close, + dcc_store_cred, + NULL, /* dcc_retrieve */ + dcc_get_principal, + dcc_get_first, + dcc_get_next, + dcc_end_get, + dcc_remove_cred, + dcc_set_flags, + dcc_get_version, + dcc_get_cache_first, + dcc_get_cache_next, + dcc_end_cache_get, + dcc_move, + dcc_get_default_name, + dcc_set_default, + dcc_lastchange, + dcc_set_kdc_offset, + dcc_get_kdc_offset, + dcc_get_name_2, + dcc_resolve_2 +}; diff --git a/third_party/heimdal/lib/krb5/deprecated.c b/third_party/heimdal/lib/krb5/deprecated.c new file mode 100644 index 0000000..172f089 --- /dev/null +++ b/third_party/heimdal/lib/krb5/deprecated.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 1997 - 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __GNUC__ +/* For some GCCs there's no way to shut them up about deprecated functions */ +#define KRB5_DEPRECATED_FUNCTION(x) +#endif + +#include "krb5_locl.h" + + +#undef __attribute__ +#define __attribute__(x) + +#ifndef HEIMDAL_SMALLER + +/** + * Same as krb5_data_free(). MIT compat. + * + * Deprecated: use krb5_data_free(). + * + * @param context Kerberos 5 context. + * @param data krb5_data to free. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_data_contents(krb5_context context, krb5_data *data) + KRB5_DEPRECATED_FUNCTION("Use krb5_data_free instead") +{ + krb5_data_free(data); +} + +/** + * Deprecated: keytypes doesn't exists, they are really enctypes. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_keytype_to_enctypes_default (krb5_context context, + krb5_keytype keytype, + unsigned *len, + krb5_enctype **val) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + unsigned int i, n; + krb5_enctype *ret; + + if (keytype != (krb5_keytype)KEYTYPE_DES || context->etypes_des == NULL) + return krb5_keytype_to_enctypes (context, keytype, len, val); + + for (n = 0; context->etypes_des[n]; ++n) + ; + ret = malloc (n * sizeof(*ret)); + if (ret == NULL && n != 0) + return krb5_enomem(context); + for (i = 0; i < n; ++i) + ret[i] = context->etypes_des[i]; + *len = n; + *val = ret; + return 0; +} + + +static struct { + const char *name; + krb5_keytype type; +} keys[] = { + { "null", KRB5_ENCTYPE_NULL }, + { "des", KRB5_ENCTYPE_DES_CBC_CRC }, + { "des3", KRB5_ENCTYPE_OLD_DES3_CBC_SHA1 }, + { "aes-128", KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96 }, + { "aes-256", KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 }, + { "arcfour", KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 }, + { "arcfour-56", KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56 } +}; + +static int num_keys = sizeof(keys) / sizeof(keys[0]); + +/** + * Deprecated: keytypes doesn't exists, they are really enctypes in + * most cases, use krb5_enctype_to_string(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_keytype_to_string(krb5_context context, + krb5_keytype keytype, + char **string) + KRB5_DEPRECATED_FUNCTION("Use krb5_enctype_to_string instead") +{ + const char *name = NULL; + int i; + + for(i = 0; i < num_keys; i++) { + if(keys[i].type == keytype) { + name = keys[i].name; + break; + } + } + + if(i >= num_keys) { + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "key type %d not supported", keytype); + return KRB5_PROG_KEYTYPE_NOSUPP; + } + *string = strdup(name); + if (*string == NULL) + return krb5_enomem(context); + return 0; +} + +/** + * Deprecated: keytypes doesn't exists, they are really enctypes in + * most cases, use krb5_string_to_enctype(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_string_to_keytype(krb5_context context, + const char *string, + krb5_keytype *keytype) + KRB5_DEPRECATED_FUNCTION("Use krb5_string_to_enctype instead") +{ + char *end; + int i; + + for(i = 0; i < num_keys; i++) + if(strcasecmp(keys[i].name, string) == 0){ + *keytype = keys[i].type; + return 0; + } + + /* check if the enctype is a number */ + *keytype = strtol(string, &end, 0); + if(*end == '\0' && *keytype != 0) { + if (krb5_enctype_valid(context, *keytype) == 0) + return 0; + } + + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "key type %s not supported", string); + return KRB5_PROG_KEYTYPE_NOSUPP; +} + +/** + * Deprecated: use krb5_get_init_creds() and friends. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV +krb5_password_key_proc (krb5_context context, + krb5_enctype type, + krb5_salt salt, + krb5_const_pointer keyseed, + krb5_keyblock **key) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_error_code ret; + const char *password = (const char *)keyseed; + char buf[BUFSIZ]; + + *key = malloc (sizeof (**key)); + if (*key == NULL) + return krb5_enomem(context); + if (password == NULL) { + if(UI_UTIL_read_pw_string (buf, sizeof(buf), "Password: ", 0)) { + free (*key); + krb5_clear_error_message(context); + return KRB5_LIBOS_PWDINTR; + } + password = buf; + } + ret = krb5_string_to_key_salt (context, type, password, salt, *key); + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + return ret; +} + +/** + * Deprecated: use krb5_get_init_creds() and friends. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_in_tkt_with_password (krb5_context context, + krb5_flags options, + krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *pre_auth_types, + const char *password, + krb5_ccache ccache, + krb5_creds *creds, + krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + return krb5_get_in_tkt (context, + options, + addrs, + etypes, + pre_auth_types, + krb5_password_key_proc, + password, + NULL, + NULL, + creds, + ccache, + ret_as_reply); +} + +static krb5_error_code KRB5_CALLCONV +krb5_skey_key_proc (krb5_context context, + krb5_enctype type, + krb5_salt salt, + krb5_const_pointer keyseed, + krb5_keyblock **key) +{ + return krb5_copy_keyblock (context, keyseed, key); +} + +/** + * Deprecated: use krb5_get_init_creds() and friends. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_in_tkt_with_skey (krb5_context context, + krb5_flags options, + krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *pre_auth_types, + const krb5_keyblock *key, + krb5_ccache ccache, + krb5_creds *creds, + krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + if(key == NULL) + return krb5_get_in_tkt_with_keytab (context, + options, + addrs, + etypes, + pre_auth_types, + NULL, + ccache, + creds, + ret_as_reply); + else + return krb5_get_in_tkt (context, + options, + addrs, + etypes, + pre_auth_types, + krb5_skey_key_proc, + key, + NULL, + NULL, + creds, + ccache, + ret_as_reply); +} + +/** + * Deprecated: use krb5_get_init_creds() and friends. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV +krb5_keytab_key_proc (krb5_context context, + krb5_enctype enctype, + krb5_salt salt, + krb5_const_pointer keyseed, + krb5_keyblock **key) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); + krb5_keytab keytab = args->keytab; + krb5_principal principal = args->principal; + krb5_error_code ret; + krb5_keytab real_keytab; + krb5_keytab_entry entry; + + if(keytab == NULL) + krb5_kt_default(context, &real_keytab); + else + real_keytab = keytab; + + ret = krb5_kt_get_entry (context, real_keytab, principal, + 0, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + } + + if (keytab == NULL) + krb5_kt_close (context, real_keytab); + return ret; +} + +/** + * Deprecated: use krb5_get_init_creds() and friends. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_in_tkt_with_keytab (krb5_context context, + krb5_flags options, + krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *pre_auth_types, + krb5_keytab keytab, + krb5_ccache ccache, + krb5_creds *creds, + krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_keytab_key_proc_args a; + + a.principal = creds->client; + a.keytab = keytab; + + return krb5_get_in_tkt (context, + options, + addrs, + etypes, + pre_auth_types, + krb5_keytab_key_proc, + &a, + NULL, + NULL, + creds, + ccache, + ret_as_reply); +} + +/** + * Generate a new ccache of type `ops' in `id'. + * + * Deprecated: use krb5_cc_new_unique() instead. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_cc_gen_new(krb5_context context, + const krb5_cc_ops *ops, + krb5_ccache *id) + KRB5_DEPRECATED_FUNCTION("Use krb5_cc_new_unique instead") +{ + return krb5_cc_new_unique(context, ops->prefix, NULL, id); +} + +/** + * Deprecated: use krb5_principal_get_realm() + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_realm * KRB5_LIB_CALL +krb5_princ_realm(krb5_context context, + krb5_principal principal) + KRB5_DEPRECATED_FUNCTION("Use krb5_principal_get_realm instead") +{ + return &principal->realm; +} + + +/** + * Deprecated: use krb5_principal_set_realm() + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_princ_set_realm(krb5_context context, + krb5_principal principal, + krb5_realm *realm) + KRB5_DEPRECATED_FUNCTION("Use krb5_principal_set_realm instead") +{ + principal->realm = *realm; +} + +/** + * Deprecated: use krb5_free_cred_contents() + * + * @ingroup krb5_deprecated + */ + +/* keep this for compatibility with older code */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_creds_contents (krb5_context context, krb5_creds *c) + KRB5_DEPRECATED_FUNCTION("Use krb5_free_cred_contents instead") +{ + return krb5_free_cred_contents (context, c); +} + +/** + * Free the error message returned by krb5_get_error_string(). + * + * Deprecated: use krb5_free_error_message() + * + * @param context Kerberos context + * @param str error message to free + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_error_string(krb5_context context, char *str) + KRB5_DEPRECATED_FUNCTION("Use krb5_free_error_message instead") +{ + krb5_free_error_message(context, str); +} + +/** + * Set the error message returned by krb5_get_error_string(). + * + * Deprecated: use krb5_set_error_message() + * + * @param context Kerberos context + * @param fmt error message to free + * + * @return Return an error code or 0. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_error_string(krb5_context context, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))) + KRB5_DEPRECATED_FUNCTION("Use krb5_set_error_message instead") +{ + va_list ap; + + va_start(ap, fmt); + krb5_vset_error_message (context, 0, fmt, ap); + va_end(ap); + return 0; +} + +/** + * Set the error message returned by krb5_get_error_string(). + * + * Deprecated: use krb5_vset_error_message() + * + * @param context Kerberos context + * @param fmt error message to free + * @param args variable argument list vector + * + * @return Return an error code or 0. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_vset_error_string(krb5_context context, const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 2, 0))) + KRB5_DEPRECATED_FUNCTION("Use krb5_vset_error_message instead") +{ + krb5_vset_error_message(context, 0, fmt, args); + return 0; +} + +/** + * Clear the error message returned by krb5_get_error_string(). + * + * Deprecated: use krb5_clear_error_message() + * + * @param context Kerberos context + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_clear_error_string(krb5_context context) + KRB5_DEPRECATED_FUNCTION("Use krb5_clear_error_message instead") +{ + krb5_clear_error_message(context); +} + +/** + * Deprecated: use krb5_get_credentials_with_flags(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_cred_from_kdc_opt(krb5_context context, + krb5_ccache ccache, + krb5_creds *in_creds, + krb5_creds **out_creds, + krb5_creds ***ret_tgts, + krb5_flags flags) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_credentials_with_flags instead") +{ + krb5_kdc_flags f; + f.i = flags; + return _krb5_get_cred_kdc_any(context, f, ccache, NULL, + in_creds, NULL, NULL, + out_creds, ret_tgts); +} + +/** + * Deprecated: use krb5_get_credentials_with_flags(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_cred_from_kdc(krb5_context context, + krb5_ccache ccache, + krb5_creds *in_creds, + krb5_creds **out_creds, + krb5_creds ***ret_tgts) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_credentials_with_flags instead") +{ + return krb5_get_cred_from_kdc_opt(context, ccache, + in_creds, out_creds, ret_tgts, 0); +} + +/** + * Deprecated: use krb5_xfree(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_unparsed_name(krb5_context context, char *str) + KRB5_DEPRECATED_FUNCTION("Use krb5_xfree instead") +{ + krb5_xfree(str); +} + +/** + * Deprecated: use krb5_generate_subkey_extended() + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_generate_subkey(krb5_context context, + const krb5_keyblock *key, + krb5_keyblock **subkey) + KRB5_DEPRECATED_FUNCTION("Use krb5_generate_subkey_extended instead") +{ + return krb5_generate_subkey_extended(context, key, ETYPE_NULL, subkey); +} + +/** + * Deprecated: use krb5_auth_con_getremoteseqnumber() + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_auth_getremoteseqnumber(krb5_context context, + krb5_auth_context auth_context, + int32_t *seqnumber) + KRB5_DEPRECATED_FUNCTION("Use krb5_auth_con_getremoteseqnumber instead") +{ + *seqnumber = auth_context->remote_seqnumber; + return 0; +} + +/** + * Return the error message in context. On error or no error string, + * the function returns NULL. + * + * @param context Kerberos 5 context + * + * @return an error string, needs to be freed with + * krb5_free_error_message(). The functions return NULL on error. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_get_error_string(krb5_context context) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead") +{ + return heim_get_error_string(context->hcontext); +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_have_error_string(krb5_context context) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead") +{ + return heim_have_error_string(context->hcontext); +} + +struct send_to_kdc { + krb5_send_to_kdc_func func; + void *data; +}; + +/* + * Send the data `send' to one host from `handle` and get back the reply + * in `receive'. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sendto (krb5_context context, + const krb5_data *send_data, + krb5_krbhst_handle handle, + krb5_data *receive) +{ + krb5_error_code ret; + krb5_sendto_ctx ctx; + + ret = krb5_sendto_ctx_alloc(context, &ctx); + if (ret) + return ret; + _krb5_sendto_ctx_set_krb5hst(context, ctx, handle); + + ret = krb5_sendto_context(context, ctx, send_data, (char *)_krb5_krbhst_get_realm(handle), receive); + krb5_sendto_ctx_free(context, ctx); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sendto_kdc(krb5_context context, + const krb5_data *send_data, + const krb5_realm *realm, + krb5_data *receive) +{ + return krb5_sendto_kdc_flags(context, send_data, realm, receive, 0); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_sendto_kdc_flags(krb5_context context, + const krb5_data *send_data, + const krb5_realm *realm, + krb5_data *receive, + int flags) +{ + krb5_error_code ret; + krb5_sendto_ctx ctx; + + ret = krb5_sendto_ctx_alloc(context, &ctx); + if (ret) + return ret; + krb5_sendto_ctx_add_flags(ctx, flags); + krb5_sendto_ctx_set_func(ctx, _krb5_kdc_retry, NULL); + + ret = krb5_sendto_context(context, ctx, send_data, *realm, receive); + krb5_sendto_ctx_free(context, ctx); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_set_send_to_kdc_func(krb5_context context, + krb5_send_to_kdc_func func, + void *data) +{ + free(context->send_to_kdc); + if (func == NULL) { + context->send_to_kdc = NULL; + return 0; + } + + context->send_to_kdc = malloc(sizeof(*context->send_to_kdc)); + if (context->send_to_kdc == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + + context->send_to_kdc->func = func; + context->send_to_kdc->data = data; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_copy_send_to_kdc_func(krb5_context context, krb5_context to) +{ + if (context->send_to_kdc) + return krb5_set_send_to_kdc_func(to, + context->send_to_kdc->func, + context->send_to_kdc->data); + else + return krb5_set_send_to_kdc_func(to, NULL, NULL); +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/derived-key-test.c b/third_party/heimdal/lib/krb5/derived-key-test.c new file mode 100644 index 0000000..0e92764 --- /dev/null +++ b/third_party/heimdal/lib/krb5/derived-key-test.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "krb5_locl.h" +#include + +enum { MAXSIZE = 32 }; + +static struct testcase { + krb5_enctype enctype; + unsigned char constant[MAXSIZE]; + size_t constant_len; + unsigned char key[MAXSIZE]; + unsigned char res[MAXSIZE]; +} tests[] = { + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0x55}, 5, + {0xdc, 0xe0, 0x6b, 0x1f, 0x64, 0xc8, 0x57, 0xa1, 0x1c, 0x3d, 0xb5, 0x7c, 0x51, 0x89, 0x9b, 0x2c, 0xc1, 0x79, 0x10, 0x08, 0xce, 0x97, 0x3b, 0x92}, + {0x92, 0x51, 0x79, 0xd0, 0x45, 0x91, 0xa7, 0x9b, 0x5d, 0x31, 0x92, 0xc4, 0xa7, 0xe9, 0xc2, 0x89, 0xb0, 0x49, 0xc7, 0x1f, 0x6e, 0xe6, 0x04, 0xcd}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0xaa}, 5, + {0x5e, 0x13, 0xd3, 0x1c, 0x70, 0xef, 0x76, 0x57, 0x46, 0x57, 0x85, 0x31, 0xcb, 0x51, 0xc1, 0x5b, 0xf1, 0x1c, 0xa8, 0x2c, 0x97, 0xce, 0xe9, 0xf2}, + {0x9e, 0x58, 0xe5, 0xa1, 0x46, 0xd9, 0x94, 0x2a, 0x10, 0x1c, 0x46, 0x98, 0x45, 0xd6, 0x7a, 0x20, 0xe3, 0xc4, 0x25, 0x9e, 0xd9, 0x13, 0xf2, 0x07}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0x55}, 5, + {0x98, 0xe6, 0xfd, 0x8a, 0x04, 0xa4, 0xb6, 0x85, 0x9b, 0x75, 0xa1, 0x76, 0x54, 0x0b, 0x97, 0x52, 0xba, 0xd3, 0xec, 0xd6, 0x10, 0xa2, 0x52, 0xbc}, + {0x13, 0xfe, 0xf8, 0x0d, 0x76, 0x3e, 0x94, 0xec, 0x6d, 0x13, 0xfd, 0x2c, 0xa1, 0xd0, 0x85, 0x07, 0x02, 0x49, 0xda, 0xd3, 0x98, 0x08, 0xea, 0xbf}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0xaa}, 5, + {0x62, 0x2a, 0xec, 0x25, 0xa2, 0xfe, 0x2c, 0xad, 0x70, 0x94, 0x68, 0x0b, 0x7c, 0x64, 0x94, 0x02, 0x80, 0x08, 0x4c, 0x1a, 0x7c, 0xec, 0x92, 0xb5}, + {0xf8, 0xdf, 0xbf, 0x04, 0xb0, 0x97, 0xe6, 0xd9, 0xdc, 0x07, 0x02, 0x68, 0x6b, 0xcb, 0x34, 0x89, 0xd9, 0x1f, 0xd9, 0xa4, 0x51, 0x6b, 0x70, 0x3e}}, + {ETYPE_DES3_CBC_SHA1, {0x6b, 0x65, 0x72, 0x62, 0x65, 0x72, 0x6f, 0x73}, 8, + {0xd3, 0xf8, 0x29, 0x8c, 0xcb, 0x16, 0x64, 0x38, 0xdc, 0xb9, 0xb9, 0x3e, 0xe5, 0xa7, 0x62, 0x92, 0x86, 0xa4, 0x91, 0xf8, 0x38, 0xf8, 0x02, 0xfb}, + {0x23, 0x70, 0xda, 0x57, 0x5d, 0x2a, 0x3d, 0xa8, 0x64, 0xce, 0xbf, 0xdc, 0x52, 0x04, 0xd5, 0x6d, 0xf7, 0x79, 0xa7, 0xdf, 0x43, 0xd9, 0xda, 0x43}}, + {ETYPE_DES3_CBC_SHA1, {0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65}, 7, + {0xb5, 0x5e, 0x98, 0x34, 0x67, 0xe5, 0x51, 0xb3, 0xe5, 0xd0, 0xe5, 0xb6, 0xc8, 0x0d, 0x45, 0x76, 0x94, 0x23, 0xa8, 0x73, 0xdc, 0x62, 0xb3, 0x0e}, + {0x01, 0x26, 0x38, 0x8a, 0xad, 0xc8, 0x1a, 0x1f, 0x2a, 0x62, 0xbc, 0x45, 0xf8, 0xd5, 0xc1, 0x91, 0x51, 0xba, 0xcd, 0xd5, 0xcb, 0x79, 0x8a, 0x3e}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0x55}, 5, + {0xc1, 0x08, 0x16, 0x49, 0xad, 0xa7, 0x43, 0x62, 0xe6, 0xa1, 0x45, 0x9d, 0x01, 0xdf, 0xd3, 0x0d, 0x67, 0xc2, 0x23, 0x4c, 0x94, 0x07, 0x04, 0xda}, + {0x34, 0x80, 0x57, 0xec, 0x98, 0xfd, 0xc4, 0x80, 0x16, 0x16, 0x1c, 0x2a, 0x4c, 0x7a, 0x94, 0x3e, 0x92, 0xae, 0x49, 0x2c, 0x98, 0x91, 0x75, 0xf7}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0xaa}, 5, + {0x5d, 0x15, 0x4a, 0xf2, 0x38, 0xf4, 0x67, 0x13, 0x15, 0x57, 0x19, 0xd5, 0x5e, 0x2f, 0x1f, 0x79, 0x0d, 0xd6, 0x61, 0xf2, 0x79, 0xa7, 0x91, 0x7c}, + {0xa8, 0x80, 0x8a, 0xc2, 0x67, 0xda, 0xda, 0x3d, 0xcb, 0xe9, 0xa7, 0xc8, 0x46, 0x26, 0xfb, 0xc7, 0x61, 0xc2, 0x94, 0xb0, 0x13, 0x15, 0xe5, 0xc1}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0x55}, 5, + {0x79, 0x85, 0x62, 0xe0, 0x49, 0x85, 0x2f, 0x57, 0xdc, 0x8c, 0x34, 0x3b, 0xa1, 0x7f, 0x2c, 0xa1, 0xd9, 0x73, 0x94, 0xef, 0xc8, 0xad, 0xc4, 0x43}, + {0xc8, 0x13, 0xf8, 0x8a, 0x3b, 0xe3, 0xb3, 0x34, 0xf7, 0x54, 0x25, 0xce, 0x91, 0x75, 0xfb, 0xe3, 0xc8, 0x49, 0x3b, 0x89, 0xc8, 0x70, 0x3b, 0x49}}, + {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0xaa}, 5, + {0x26, 0xdc, 0xe3, 0x34, 0xb5, 0x45, 0x29, 0x2f, 0x2f, 0xea, 0xb9, 0xa8, 0x70, 0x1a, 0x89, 0xa4, 0xb9, 0x9e, 0xb9, 0x94, 0x2c, 0xec, 0xd0, 0x16}, + {0xf4, 0x8f, 0xfd, 0x6e, 0x83, 0xf8, 0x3e, 0x73, 0x54, 0xe6, 0x94, 0xfd, 0x25, 0x2c, 0xf8, 0x3b, 0xfe, 0x58, 0xf7, 0xd5, 0xba, 0x37, 0xec, 0x5d}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0x99}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0xB3, 0x1A, 0x01, 0x8A, 0x48, 0xF5, 0x47, 0x76, 0xF4, 0x03, 0xE9, 0xA3, 0x96, 0x32, 0x5D, 0xC3}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0xAA}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0x9B, 0x19, 0x7D, 0xD1, 0xE8, 0xC5, 0x60, 0x9D, 0x6E, 0x67, 0xC3, 0xE3, 0x7C, 0x62, 0xC7, 0x2E}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0x55}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0x9F, 0xDA, 0x0E, 0x56, 0xAB, 0x2D, 0x85, 0xE1, 0x56, 0x9A, 0x68, 0x86, 0x96, 0xC2, 0x6A, 0x6C}}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0x99}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0xEF, 0x57, 0x18, 0xBE, 0x86, 0xCC, 0x84, 0x96, 0x3D, 0x8B, 0xBB, 0x50, 0x31, 0xE9, 0xF5, 0xC4, + 0xBA, 0x41, 0xF2, 0x8F, 0xAF, 0x69, 0xE7, 0x3D }}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0xAA}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0x56, 0xAB, 0x22, 0xBE, 0xE6, 0x3D, 0x82, 0xD7, 0xBC, 0x52, 0x27, 0xF6, 0x77, 0x3F, 0x8E, 0xA7, + 0xA5, 0xEB, 0x1C, 0x82, 0x51, 0x60, 0xC3, 0x83, 0x12, 0x98, 0x0C, 0x44, 0x2E, 0x5C, 0x7E, 0x49}}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0x55}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0x69, 0xB1, 0x65, 0x14, 0xE3, 0xCD, 0x8E, 0x56, 0xB8, 0x20, 0x10, 0xD5, 0xC7, 0x30, 0x12, 0xB6, + 0x22, 0xC4, 0xD0, 0x0F, 0xFC, 0x23, 0xED, 0x1F}}, + {0, {0}, 0, {0}, {0}} +}; + +int +main(int argc, char **argv) +{ + struct testcase *t; + krb5_context context; + krb5_error_code ret; + int val = 0; + + ret = krb5_init_context (&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + for (t = tests; t->enctype != 0; ++t) { + krb5_keyblock key; + krb5_keyblock *dkey; + + key.keytype = t->enctype; + krb5_enctype_keysize(context, t->enctype, &key.keyvalue.length); + key.keyvalue.data = t->key; + + ret = krb5_derive_key(context, &key, t->enctype, t->constant, + t->constant_len, &dkey); + if (ret) + krb5_err (context, 1, ret, "krb5_derive_key"); + if (memcmp (dkey->keyvalue.data, t->res, dkey->keyvalue.length) != 0) { + const unsigned char *p = dkey->keyvalue.data; + int i; + + printf ("derive_key failed (enctype %d)\n", t->enctype); + printf ("should be: "); + for (i = 0; i < dkey->keyvalue.length; ++i) + printf ("%02x", t->res[i]); + printf ("\nresult was: "); + for (i = 0; i < dkey->keyvalue.length; ++i) + printf ("%02x", p[i]); + printf ("\n"); + val = 1; + } + krb5_free_keyblock(context, dkey); + } + krb5_free_context(context); + + return val; +} diff --git a/third_party/heimdal/lib/krb5/digest.c b/third_party/heimdal/lib/krb5/digest.c new file mode 100644 index 0000000..cc37c6d --- /dev/null +++ b/third_party/heimdal/lib/krb5/digest.c @@ -0,0 +1,1165 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include "digest_asn1.h" + +#ifndef HEIMDAL_SMALLER + +struct krb5_digest_data { + char *cbtype; + char *cbbinding; + + DigestInit init; + DigestInitReply initReply; + DigestRequest request; + DigestResponse response; +}; + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_alloc(krb5_context context, krb5_digest *digest) +{ + krb5_digest d; + + d = calloc(1, sizeof(*d)); + if (d == NULL) { + *digest = NULL; + return krb5_enomem(context); + } + *digest = d; + + return 0; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_digest_free(krb5_digest digest) +{ + if (digest == NULL) + return; + free_DigestInit(&digest->init); + free_DigestInitReply(&digest->initReply); + free_DigestRequest(&digest->request); + free_DigestResponse(&digest->response); + memset(digest, 0, sizeof(*digest)); + free(digest); + return; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_server_cb(krb5_context context, + krb5_digest digest, + const char *type, + const char *binding) +{ + if (digest->init.channel) { + krb5_set_error_message(context, EINVAL, + N_("server channel binding already set", "")); + return EINVAL; + } + digest->init.channel = calloc(1, sizeof(*digest->init.channel)); + if (digest->init.channel == NULL) + goto error; + + digest->init.channel->cb_type = strdup(type); + if (digest->init.channel->cb_type == NULL) + goto error; + + digest->init.channel->cb_binding = strdup(binding); + if (digest->init.channel->cb_binding == NULL) + goto error; + return 0; + error: + if (digest->init.channel) { + free(digest->init.channel->cb_type); + free(digest->init.channel->cb_binding); + free(digest->init.channel); + digest->init.channel = NULL; + } + return krb5_enomem(context); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_type(krb5_context context, + krb5_digest digest, + const char *type) +{ + if (digest->init.type) { + krb5_set_error_message(context, EINVAL, "client type already set"); + return EINVAL; + } + digest->init.type = strdup(type); + if (digest->init.type == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_hostname(krb5_context context, + krb5_digest digest, + const char *hostname) +{ + if (digest->init.hostname) { + krb5_set_error_message(context, EINVAL, "server hostname already set"); + return EINVAL; + } + digest->init.hostname = malloc(sizeof(*digest->init.hostname)); + if (digest->init.hostname == NULL) + return krb5_enomem(context); + *digest->init.hostname = strdup(hostname); + if (*digest->init.hostname == NULL) { + free(digest->init.hostname); + digest->init.hostname = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_digest_get_server_nonce(krb5_context context, + krb5_digest digest) +{ + return digest->initReply.nonce; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_server_nonce(krb5_context context, + krb5_digest digest, + const char *nonce) +{ + if (digest->request.serverNonce) { + krb5_set_error_message(context, EINVAL, N_("nonce already set", "")); + return EINVAL; + } + digest->request.serverNonce = strdup(nonce); + if (digest->request.serverNonce == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_digest_get_opaque(krb5_context context, + krb5_digest digest) +{ + return digest->initReply.opaque; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_opaque(krb5_context context, + krb5_digest digest, + const char *opaque) +{ + if (digest->request.opaque) { + krb5_set_error_message(context, EINVAL, "opaque already set"); + return EINVAL; + } + digest->request.opaque = strdup(opaque); + if (digest->request.opaque == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_digest_get_identifier(krb5_context context, + krb5_digest digest) +{ + if (digest->initReply.identifier == NULL) + return NULL; + return *digest->initReply.identifier; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_identifier(krb5_context context, + krb5_digest digest, + const char *id) +{ + if (digest->request.identifier) { + krb5_set_error_message(context, EINVAL, N_("identifier already set", "")); + return EINVAL; + } + digest->request.identifier = calloc(1, sizeof(*digest->request.identifier)); + if (digest->request.identifier == NULL) + return krb5_enomem(context); + *digest->request.identifier = strdup(id); + if (*digest->request.identifier == NULL) { + free(digest->request.identifier); + digest->request.identifier = NULL; + return krb5_enomem(context); + } + return 0; +} + +static krb5_error_code +digest_request(krb5_context context, + krb5_realm realm, + krb5_ccache ccache, + krb5_key_usage usage, + const DigestReqInner *ireq, + DigestRepInner *irep) +{ + DigestREQ req; + DigestREP rep; + krb5_error_code ret; + krb5_data data, data2; + size_t size = 0; + krb5_crypto crypto = NULL; + krb5_auth_context ac = NULL; + krb5_principal principal = NULL; + krb5_ccache id = NULL; + krb5_realm r = NULL; + + krb5_data_zero(&data); + krb5_data_zero(&data2); + memset(&req, 0, sizeof(req)); + memset(&rep, 0, sizeof(rep)); + + if (ccache == NULL) { + ret = krb5_cc_default(context, &id); + if (ret) + goto out; + } else + id = ccache; + + if (realm == NULL) { + ret = krb5_get_default_realm(context, &r); + if (ret) + goto out; + } else + r = realm; + + /* + * + */ + + ret = krb5_make_principal(context, &principal, + r, KRB5_DIGEST_NAME, r, NULL); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length, + ireq, &size, ret); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to encode digest inner request", "")); + goto out; + } + if (size != data.length) + krb5_abortx(context, "ASN.1 internal encoder error"); + + ret = krb5_mk_req_exact(context, &ac, + AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED, + principal, NULL, id, &req.apReq); + if (ret) + goto out; + + { + krb5_keyblock *key; + + ret = krb5_auth_con_getlocalsubkey(context, ac, &key); + if (ret) + goto out; + if (key == NULL) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("Digest failed to get local subkey", "")); + goto out; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + krb5_free_keyblock (context, key); + if (ret) + goto out; + } + + ret = krb5_encrypt_EncryptedData(context, crypto, usage, + data.data, data.length, 0, + &req.innerReq); + if (ret) + goto out; + + krb5_data_free(&data); + + ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length, + &req, &size, ret); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to encode DigestREQest", "")); + goto out; + } + if (size != data.length) + krb5_abortx(context, "ASN.1 internal encoder error"); + + ret = krb5_sendto_kdc(context, &data, &r, &data2); + if (ret) + goto out; + + ret = decode_DigestREP(data2.data, data2.length, &rep, NULL); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to parse digest response", "")); + goto out; + } + + { + krb5_ap_rep_enc_part *repl; + + ret = krb5_rd_rep(context, ac, &rep.apRep, &repl); + if (ret) + goto out; + + krb5_free_ap_rep_enc_part(context, repl); + } + { + krb5_keyblock *key; + + ret = krb5_auth_con_getremotesubkey(context, ac, &key); + if (ret) + goto out; + if (key == NULL) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("Digest reply has no remote subkey", "")); + goto out; + } + + krb5_crypto_destroy(context, crypto); + ret = krb5_crypto_init(context, key, 0, &crypto); + krb5_free_keyblock (context, key); + if (ret) + goto out; + } + + krb5_data_free(&data); + ret = krb5_decrypt_EncryptedData(context, crypto, usage, + &rep.innerRep, &data); + if (ret) + goto out; + + ret = decode_DigestRepInner(data.data, data.length, irep, NULL); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode digest inner reply", "")); + goto out; + } + + out: + if (ccache == NULL && id) + krb5_cc_close(context, id); + if (realm == NULL && r) + free(r); + if (crypto) + krb5_crypto_destroy(context, crypto); + if (ac) + krb5_auth_con_free(context, ac); + if (principal) + krb5_free_principal(context, principal); + + krb5_data_free(&data); + krb5_data_free(&data2); + + free_DigestREQ(&req); + free_DigestREP(&rep); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_init_request(krb5_context context, + krb5_digest digest, + krb5_realm realm, + krb5_ccache ccache) +{ + DigestReqInner ireq; + DigestRepInner irep; + krb5_error_code ret; + + memset(&ireq, 0, sizeof(ireq)); + memset(&irep, 0, sizeof(irep)); + + if (digest->init.type == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Type missing from init req", "")); + return EINVAL; + } + + ireq.element = choice_DigestReqInner_init; + ireq.u.init = digest->init; + + ret = digest_request(context, realm, ccache, + KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); + if (ret) + goto out; + + if (irep.element == choice_DigestRepInner_error) { + ret = irep.u.error.code; + krb5_set_error_message(context, ret, N_("Digest init error: %s", ""), + irep.u.error.reason); + goto out; + } + + if (irep.element != choice_DigestRepInner_initReply) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("digest reply not an initReply", "")); + goto out; + } + + ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to copy initReply", "")); + goto out; + } + + out: + free_DigestRepInner(&irep); + + return ret; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_client_nonce(krb5_context context, + krb5_digest digest, + const char *nonce) +{ + if (digest->request.clientNonce) { + krb5_set_error_message(context, EINVAL, + N_("clientNonce already set", "")); + return EINVAL; + } + digest->request.clientNonce = + calloc(1, sizeof(*digest->request.clientNonce)); + if (digest->request.clientNonce == NULL) + return krb5_enomem(context); + *digest->request.clientNonce = strdup(nonce); + if (*digest->request.clientNonce == NULL) { + free(digest->request.clientNonce); + digest->request.clientNonce = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_digest(krb5_context context, + krb5_digest digest, + const char *dgst) +{ + if (digest->request.digest) { + krb5_set_error_message(context, EINVAL, + N_("digest already set", "")); + return EINVAL; + } + digest->request.digest = strdup(dgst); + if (digest->request.digest == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_username(krb5_context context, + krb5_digest digest, + const char *username) +{ + if (digest->request.username) { + krb5_set_error_message(context, EINVAL, "username already set"); + return EINVAL; + } + digest->request.username = strdup(username); + if (digest->request.username == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_authid(krb5_context context, + krb5_digest digest, + const char *authid) +{ + if (digest->request.authid) { + krb5_set_error_message(context, EINVAL, "authid already set"); + return EINVAL; + } + digest->request.authid = malloc(sizeof(*digest->request.authid)); + if (digest->request.authid == NULL) + return krb5_enomem(context); + *digest->request.authid = strdup(authid); + if (*digest->request.authid == NULL) { + free(digest->request.authid); + digest->request.authid = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_authentication_user(krb5_context context, + krb5_digest digest, + krb5_principal authentication_user) +{ + krb5_error_code ret; + + if (digest->request.authentication_user) { + krb5_set_error_message(context, EINVAL, + N_("authentication_user already set", "")); + return EINVAL; + } + ret = krb5_copy_principal(context, + authentication_user, + &digest->request.authentication_user); + if (ret) + return ret; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_realm(krb5_context context, + krb5_digest digest, + const char *realm) +{ + if (digest->request.realm) { + krb5_set_error_message(context, EINVAL, "realm already set"); + return EINVAL; + } + digest->request.realm = malloc(sizeof(*digest->request.realm)); + if (digest->request.realm == NULL) + return krb5_enomem(context); + *digest->request.realm = strdup(realm); + if (*digest->request.realm == NULL) { + free(digest->request.realm); + digest->request.realm = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_method(krb5_context context, + krb5_digest digest, + const char *method) +{ + if (digest->request.method) { + krb5_set_error_message(context, EINVAL, + N_("method already set", "")); + return EINVAL; + } + digest->request.method = malloc(sizeof(*digest->request.method)); + if (digest->request.method == NULL) + return krb5_enomem(context); + *digest->request.method = strdup(method); + if (*digest->request.method == NULL) { + free(digest->request.method); + digest->request.method = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_uri(krb5_context context, + krb5_digest digest, + const char *uri) +{ + if (digest->request.uri) { + krb5_set_error_message(context, EINVAL, N_("uri already set", "")); + return EINVAL; + } + digest->request.uri = malloc(sizeof(*digest->request.uri)); + if (digest->request.uri == NULL) + return krb5_enomem(context); + *digest->request.uri = strdup(uri); + if (*digest->request.uri == NULL) { + free(digest->request.uri); + digest->request.uri = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_nonceCount(krb5_context context, + krb5_digest digest, + const char *nonce_count) +{ + if (digest->request.nonceCount) { + krb5_set_error_message(context, EINVAL, + N_("nonceCount already set", "")); + return EINVAL; + } + digest->request.nonceCount = + malloc(sizeof(*digest->request.nonceCount)); + if (digest->request.nonceCount == NULL) + return krb5_enomem(context); + *digest->request.nonceCount = strdup(nonce_count); + if (*digest->request.nonceCount == NULL) { + free(digest->request.nonceCount); + digest->request.nonceCount = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_set_qop(krb5_context context, + krb5_digest digest, + const char *qop) +{ + if (digest->request.qop) { + krb5_set_error_message(context, EINVAL, "qop already set"); + return EINVAL; + } + digest->request.qop = malloc(sizeof(*digest->request.qop)); + if (digest->request.qop == NULL) + return krb5_enomem(context); + *digest->request.qop = strdup(qop); + if (*digest->request.qop == NULL) { + free(digest->request.qop); + digest->request.qop = NULL; + return krb5_enomem(context); + } + return 0; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_digest_set_responseData(krb5_context context, + krb5_digest digest, + const char *response) +{ + digest->request.responseData = strdup(response); + if (digest->request.responseData == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_request(krb5_context context, + krb5_digest digest, + krb5_realm realm, + krb5_ccache ccache) +{ + DigestReqInner ireq; + DigestRepInner irep; + krb5_error_code ret; + + memset(&ireq, 0, sizeof(ireq)); + memset(&irep, 0, sizeof(irep)); + + ireq.element = choice_DigestReqInner_digestRequest; + ireq.u.digestRequest = digest->request; + + if (digest->request.type == NULL) { + if (digest->init.type == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Type missing from req", "")); + return EINVAL; + } + ireq.u.digestRequest.type = digest->init.type; + } + + if (ireq.u.digestRequest.digest == NULL) { + static char md5[] = "md5"; + ireq.u.digestRequest.digest = md5; + } + + ret = digest_request(context, realm, ccache, + KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); + if (ret) + return ret; + + if (irep.element == choice_DigestRepInner_error) { + ret = irep.u.error.code; + krb5_set_error_message(context, ret, + N_("Digest response error: %s", ""), + irep.u.error.reason); + goto out; + } + + if (irep.element != choice_DigestRepInner_response) { + krb5_set_error_message(context, EINVAL, + N_("digest reply not an DigestResponse", "")); + ret = EINVAL; + goto out; + } + + ret = copy_DigestResponse(&irep.u.response, &digest->response); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to copy initReply,", "")); + goto out; + } + + out: + free_DigestRepInner(&irep); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_digest_rep_get_status(krb5_context context, + krb5_digest digest) +{ + return digest->response.success ? TRUE : FALSE; +} + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_digest_get_rsp(krb5_context context, + krb5_digest digest) +{ + if (digest->response.rsp == NULL) + return NULL; + return *digest->response.rsp; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_get_tickets(krb5_context context, + krb5_digest digest, + Ticket **tickets) +{ + *tickets = NULL; + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_get_client_binding(krb5_context context, + krb5_digest digest, + char **type, + char **binding) +{ + if (digest->response.channel) { + *type = strdup(digest->response.channel->cb_type); + *binding = strdup(digest->response.channel->cb_binding); + if (*type == NULL || *binding == NULL) { + free(*type); + free(*binding); + return krb5_enomem(context); + } + } else { + *type = NULL; + *binding = NULL; + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_get_session_key(krb5_context context, + krb5_digest digest, + krb5_data *data) +{ + krb5_error_code ret; + + krb5_data_zero(data); + if (digest->response.session_key == NULL) + return 0; + ret = der_copy_octet_string(digest->response.session_key, data); + if (ret) + krb5_clear_error_message(context); + + return ret; +} + +struct krb5_ntlm_data { + NTLMInit init; + NTLMInitReply initReply; + NTLMRequest request; + NTLMResponse response; +}; + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_alloc(krb5_context context, + krb5_ntlm *ntlm) +{ + *ntlm = calloc(1, sizeof(**ntlm)); + if (*ntlm == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm) +{ + free_NTLMInit(&ntlm->init); + free_NTLMInitReply(&ntlm->initReply); + free_NTLMRequest(&ntlm->request); + free_NTLMResponse(&ntlm->response); + memset(ntlm, 0, sizeof(*ntlm)); + free(ntlm); + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_request(krb5_context context, + krb5_ntlm ntlm, + krb5_realm realm, + krb5_ccache ccache, + uint32_t flags, + const char *hostname, + const char *domainname) +{ + DigestReqInner ireq; + DigestRepInner irep; + krb5_error_code ret; + + memset(&ireq, 0, sizeof(ireq)); + memset(&irep, 0, sizeof(irep)); + + ntlm->init.flags = flags; + if (hostname) { + ALLOC(ntlm->init.hostname, 1); + *ntlm->init.hostname = strdup(hostname); + } + if (domainname) { + ALLOC(ntlm->init.domain, 1); + *ntlm->init.domain = strdup(domainname); + } + + ireq.element = choice_DigestReqInner_ntlmInit; + ireq.u.ntlmInit = ntlm->init; + + ret = digest_request(context, realm, ccache, + KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); + if (ret) + goto out; + + if (irep.element == choice_DigestRepInner_error) { + ret = irep.u.error.code; + krb5_set_error_message(context, ret, N_("Digest init error: %s", ""), + irep.u.error.reason); + goto out; + } + + if (irep.element != choice_DigestRepInner_ntlmInitReply) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("ntlm reply not an initReply", "")); + goto out; + } + + ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to copy initReply", "")); + goto out; + } + + out: + free_DigestRepInner(&irep); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_get_flags(krb5_context context, + krb5_ntlm ntlm, + uint32_t *flags) +{ + *flags = ntlm->initReply.flags; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_get_challenge(krb5_context context, + krb5_ntlm ntlm, + krb5_data *challenge) +{ + krb5_error_code ret; + + ret = der_copy_octet_string(&ntlm->initReply.challenge, challenge); + if (ret) + krb5_clear_error_message(context); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_get_opaque(krb5_context context, + krb5_ntlm ntlm, + krb5_data *opaque) +{ + krb5_error_code ret; + + ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque); + if (ret) + krb5_clear_error_message(context); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_get_targetname(krb5_context context, + krb5_ntlm ntlm, + char **name) +{ + *name = strdup(ntlm->initReply.targetname); + if (*name == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_init_get_targetinfo(krb5_context context, + krb5_ntlm ntlm, + krb5_data *data) +{ + krb5_error_code ret; + + if (ntlm->initReply.targetinfo == NULL) { + krb5_data_zero(data); + return 0; + } + + ret = krb5_data_copy(data, + ntlm->initReply.targetinfo->data, + ntlm->initReply.targetinfo->length); + if (ret) { + krb5_clear_error_message(context); + return ret; + } + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_request(krb5_context context, + krb5_ntlm ntlm, + krb5_realm realm, + krb5_ccache ccache) +{ + DigestReqInner ireq; + DigestRepInner irep; + krb5_error_code ret; + + memset(&ireq, 0, sizeof(ireq)); + memset(&irep, 0, sizeof(irep)); + + ireq.element = choice_DigestReqInner_ntlmRequest; + ireq.u.ntlmRequest = ntlm->request; + + ret = digest_request(context, realm, ccache, + KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); + if (ret) + return ret; + + if (irep.element == choice_DigestRepInner_error) { + ret = irep.u.error.code; + krb5_set_error_message(context, ret, + N_("NTLM response error: %s", ""), + irep.u.error.reason); + goto out; + } + + if (irep.element != choice_DigestRepInner_ntlmResponse) { + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("NTLM reply not an NTLMResponse", "")); + goto out; + } + + ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to copy NTLMResponse", "")); + goto out; + } + + out: + free_DigestRepInner(&irep); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_flags(krb5_context context, + krb5_ntlm ntlm, + uint32_t flags) +{ + ntlm->request.flags = flags; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_username(krb5_context context, + krb5_ntlm ntlm, + const char *username) +{ + ntlm->request.username = strdup(username); + if (ntlm->request.username == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_targetname(krb5_context context, + krb5_ntlm ntlm, + const char *targetname) +{ + ntlm->request.targetname = strdup(targetname); + if (ntlm->request.targetname == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_lm(krb5_context context, + krb5_ntlm ntlm, + void *hash, size_t len) +{ + ntlm->request.lm.data = malloc(len); + if (ntlm->request.lm.data == NULL && len != 0) + return krb5_enomem(context); + ntlm->request.lm.length = len; + memcpy(ntlm->request.lm.data, hash, len); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_ntlm(krb5_context context, + krb5_ntlm ntlm, + void *hash, size_t len) +{ + ntlm->request.ntlm.data = malloc(len); + if (ntlm->request.ntlm.data == NULL && len != 0) + return krb5_enomem(context); + ntlm->request.ntlm.length = len; + memcpy(ntlm->request.ntlm.data, hash, len); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_opaque(krb5_context context, + krb5_ntlm ntlm, + krb5_data *opaque) +{ + ntlm->request.opaque.data = malloc(opaque->length); + if (ntlm->request.opaque.data == NULL && opaque->length != 0) + return krb5_enomem(context); + ntlm->request.opaque.length = opaque->length; + memcpy(ntlm->request.opaque.data, opaque->data, opaque->length); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_req_set_session(krb5_context context, + krb5_ntlm ntlm, + void *sessionkey, size_t length) +{ + ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey)); + if (ntlm->request.sessionkey == NULL) + return krb5_enomem(context); + ntlm->request.sessionkey->data = malloc(length); + if (ntlm->request.sessionkey->data == NULL && length != 0) + return krb5_enomem(context); + memcpy(ntlm->request.sessionkey->data, sessionkey, length); + ntlm->request.sessionkey->length = length; + return 0; +} + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_ntlm_rep_get_status(krb5_context context, + krb5_ntlm ntlm) +{ + return ntlm->response.success ? TRUE : FALSE; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_ntlm_rep_get_sessionkey(krb5_context context, + krb5_ntlm ntlm, + krb5_data *data) +{ + if (ntlm->response.sessionkey == NULL) { + krb5_set_error_message(context, EINVAL, + N_("no ntlm session key", "")); + return EINVAL; + } + krb5_clear_error_message(context); + return krb5_data_copy(data, + ntlm->response.sessionkey->data, + ntlm->response.sessionkey->length); +} + +/** + * Get the supported/allowed mechanism for this principal. + * + * @param context A Keberos context. + * @param realm The realm of the KDC. + * @param ccache The credential cache to use when talking to the KDC. + * @param flags The supported mechanism. + * + * @return Return an error code or 0. + * + * @ingroup krb5_digest + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_digest_probe(krb5_context context, + krb5_realm realm, + krb5_ccache ccache, + unsigned *flags) +{ + DigestReqInner ireq; + DigestRepInner irep; + krb5_error_code ret; + + memset(&ireq, 0, sizeof(ireq)); + memset(&irep, 0, sizeof(irep)); + + ireq.element = choice_DigestReqInner_supportedMechs; + + ret = digest_request(context, realm, ccache, + KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); + if (ret) + goto out; + + if (irep.element == choice_DigestRepInner_error) { + ret = irep.u.error.code; + krb5_set_error_message(context, ret, "Digest probe error: %s", + irep.u.error.reason); + goto out; + } + + if (irep.element != choice_DigestRepInner_supportedMechs) { + ret = EINVAL; + krb5_set_error_message(context, ret, "Digest reply not an probe"); + goto out; + } + + *flags = DigestTypes2int(irep.u.supportedMechs); + + out: + free_DigestRepInner(&irep); + + return ret; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/dll.c b/third_party/heimdal/lib/krb5/dll.c new file mode 100644 index 0000000..80d9fa4 --- /dev/null +++ b/third_party/heimdal/lib/krb5/dll.c @@ -0,0 +1,76 @@ +/*********************************************************************** + * Copyright (c) 2009, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include + +extern void heim_w32_service_thread_detach(void *); + +HINSTANCE _krb5_hInstance = NULL; + +#if NTDDI_VERSION >= NTDDI_VISTA +extern BOOL WINAPI +_hc_w32crypto_DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); +#endif + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ +#if NTDDI_VERSION >= NTDDI_VISTA + BOOL ret; + + ret = _hc_w32crypto_DllMain(hinstDLL, fdwReason, lpvReserved); + if (!ret) + return ret; +#endif + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + + _krb5_hInstance = hinstDLL; + return TRUE; + + case DLL_PROCESS_DETACH: + return FALSE; + + case DLL_THREAD_ATTACH: + return FALSE; + + case DLL_THREAD_DETACH: + heim_w32_service_thread_detach(NULL); + return FALSE; + } + + return FALSE; +} + diff --git a/third_party/heimdal/lib/krb5/doxygen.c b/third_party/heimdal/lib/krb5/doxygen.c new file mode 100644 index 0000000..e9266c9 --- /dev/null +++ b/third_party/heimdal/lib/krb5/doxygen.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2007-2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * + */ + +/*! @mainpage Heimdal Kerberos 5 library + * + * @section intro Introduction + * + * Heimdal libkrb5 library is a implementation of the Kerberos + * protocol. + * + * Kerberos is a system for authenticating users and services on a + * network. It is built upon the assumption that the network is + * ``unsafe''. For example, data sent over the network can be + * eavesdropped and altered, and addresses can also be faked. + * Therefore they cannot be used for authentication purposes. + * + * + * - @ref krb5_introduction + * - @ref krb5_principal_intro + * - @ref krb5_ccache_intro + * - @ref krb5_keytab_intro + * + * If you want to know more about the file formats that is used by + * Heimdal, please see: @ref krb5_fileformats + * + * The project web page: http://www.h5l.org/ + * + */ + +/** @defgroup krb5 Heimdal Kerberos 5 library */ +/** @defgroup krb5_address Heimdal Kerberos 5 address functions */ +/** @defgroup krb5_principal Heimdal Kerberos 5 principal functions */ +/** @defgroup krb5_ccache Heimdal Kerberos 5 credential cache functions */ +/** @defgroup krb5_crypto Heimdal Kerberos 5 cryptography functions */ +/** @defgroup krb5_credential Heimdal Kerberos 5 credential handing functions */ +/** @defgroup krb5_deprecated Heimdal Kerberos 5 deprecated functions */ +/** @defgroup krb5_digest Heimdal Kerberos 5 digest service */ +/** @defgroup krb5_error Heimdal Kerberos 5 error reporting functions */ +/** @defgroup krb5_keytab Heimdal Kerberos 5 keytab handling functions */ +/** @defgroup krb5_ticket Heimdal Kerberos 5 ticket functions */ +/** @defgroup krb5_pac Heimdal Kerberos 5 PAC handling functions */ +/** @defgroup krb5_v4compat Heimdal Kerberos 4 compatiblity functions */ +/** @defgroup krb5_storage Heimdal Kerberos 5 storage functions */ +/** @defgroup krb5_support Heimdal Kerberos 5 support functions */ +/** @defgroup krb5_auth Heimdal Kerberos 5 authentication functions */ + + +/** + * @page krb5_introduction Introduction to the Kerberos 5 API + * @section api_overview Kerberos 5 API Overview + * + * All functions are documented in manual pages. This section tries + * to give an overview of the major components used in Kerberos + * library, and point to where to look for a specific function. + * + * @subsection intro_krb5_context Kerberos context + * + * A kerberos context (krb5_context) holds all per thread state. All + * global variables that are context specific are stored in this + * structure, including default encryption types, credential cache + * (for example, a ticket file), and default realms. + * + * The internals of the structure should never be accessed directly, + * functions exist for extracting information. + * + * See the manual page for krb5_init_context() how to create a context + * and module @ref krb5 for more information about the functions. + * + * @subsection intro_krb5_auth_context Kerberos authentication context + * + * Kerberos authentication context (krb5_auth_context) holds all + * context related to an authenticated connection, in a similar way to + * the kerberos context that holds the context for the thread or + * process. + * + * The krb5_auth_context is used by various functions that are + * directly related to authentication between the + * server/client. Example of data that this structure contains are + * various flags, addresses of client and server, port numbers, + * keyblocks (and subkeys), sequence numbers, replay cache, and + * checksum types. + * + * @subsection intro_krb5_principal Kerberos principal + * + * The Kerberos principal is the structure that identifies a user or + * service in Kerberos. The structure that holds the principal is the + * krb5_principal. There are function to extract the realm and + * elements of the principal, but most applications have no reason to + * inspect the content of the structure. + * + * The are several ways to create a principal (with different degree of + * portability), and one way to free it. + * + * See also the page @ref krb5_principal_intro for more information and also + * module @ref krb5_principal. + * + * @subsection intro_krb5_ccache Credential cache + * + * A credential cache holds the tickets for a user. A given user can + * have several credential caches, one for each realm where the user + * have the initial tickets (the first krbtgt). + * + * The credential cache data can be stored internally in different + * way, each of them for different proposes. File credential (FILE) + * caches and processes based (KCM) caches are for permanent + * storage. While memory caches (MEMORY) are local caches to the local + * process. + * + * Caches are opened with krb5_cc_resolve() or created with + * krb5_cc_new_unique(). + * + * If the cache needs to be opened again (using krb5_cc_resolve()) + * krb5_cc_close() will close the handle, but not the remove the + * cache. krb5_cc_destroy() will zero out the cache, remove the cache + * so it can no longer be referenced. + * + * See also @ref krb5_ccache_intro and @ref krb5_ccache . + * + * @subsection intro_krb5_error_code Kerberos errors + * + * Kerberos errors are based on the com_err library. All error codes are + * 32-bit signed numbers, the first 24 bits define what subsystem the + * error originates from, and last 8 bits are 255 error codes within the + * library. Each error code have fixed string associated with it. For + * example, the error-code -1765328383 have the symbolic name + * KRB5KDC_ERR_NAME_EXP, and associated error string ``Client's entry in + * database has expired''. + * + * This is a great improvement compared to just getting one of the unix + * error-codes back. However, Heimdal have an extention to pass back + * customised errors messages. Instead of getting ``Key table entry not + * found'', the user might back ``failed to find + * host/host.example.com\@EXAMLE.COM(kvno 3) in keytab /etc/krb5.keytab + * (des-cbc-crc)''. This improves the chance that the user find the + * cause of the error so you should use the customised error message + * whenever it's available. + * + * See also module @ref krb5_error . + * + * + * @subsection intro_krb5_keytab Keytab management + * + * A keytab is a storage for locally stored keys. Heimdal includes keytab + * support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's, + * and for storing keys in memory. + * + * Keytabs are used for servers and long-running services. + * + * See also @ref krb5_keytab_intro and @ref krb5_keytab . + * + * @subsection intro_krb5_crypto Kerberos crypto + * + * Heimdal includes a implementation of the Kerberos crypto framework, + * all crypto operations. To create a crypto context call krb5_crypto_init(). + * + * See also module @ref krb5_crypto . + * + * @section kerberos5_client Walkthrough of a sample Kerberos 5 client + * + * This example contains parts of a sample TCP Kerberos 5 clients, if you + * want a real working client, please look in appl/test directory in + * the Heimdal distribution. + * + * All Kerberos error-codes that are returned from kerberos functions in + * this program are passed to krb5_err, that will print a + * descriptive text of the error code and exit. Graphical programs can + * convert error-code to a human readable error-string with the + * krb5_get_error_message() function. + * + * Note that you should not use any Kerberos function before + * krb5_init_context() have completed successfully. That is the + * reason err() is used when krb5_init_context() fails. + * + * First the client needs to call krb5_init_context to initialise + * the Kerberos 5 library. This is only needed once per thread + * in the program. If the function returns a non-zero value it indicates + * that either the Kerberos implementation is failing or it's disabled on + * this host. + * + * @code + * #include + * + * int + * main(int argc, char **argv) + * { + * krb5_context context; + * + * if (krb5_init_context(&context)) + * errx (1, "krb5_context"); + * @endcode + * + * Now the client wants to connect to the host at the other end. The + * preferred way of doing this is using getaddrinfo (for + * operating system that have this function implemented), since getaddrinfo + * is neutral to the address type and can use any protocol that is available. + * + * @code + * struct addrinfo *ai, *a; + * struct addrinfo hints; + * int error; + * + * memset (&hints, 0, sizeof(hints)); + * hints.ai_socktype = SOCK_STREAM; + * hints.ai_protocol = IPPROTO_TCP; + * + * error = getaddrinfo (hostname, "pop3", &hints, &ai); + * if (error) + * errx (1, "%s: %s", hostname, gai_strerror(error)); + * + * for (a = ai; a != NULL; a = a->ai_next) { + * int s; + * + * s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + * if (s < 0) + * continue; + * if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { + * warn ("connect(%s)", hostname); + * close (s); + * continue; + * } + * freeaddrinfo (ai); + * ai = NULL; + * } + * if (ai) { + * freeaddrinfo (ai); + * errx ("failed to contact %s", hostname); + * } + * @endcode + * + * Before authenticating, an authentication context needs to be + * created. This context keeps all information for one (to be) authenticated + * connection (see krb5_auth_context). + * + * @code + * status = krb5_auth_con_init (context, &auth_context); + * if (status) + * krb5_err (context, 1, status, "krb5_auth_con_init"); + * @endcode + * + * For setting the address in the authentication there is a help function + * krb5_auth_con_setaddrs_from_fd() that does everything that is needed + * when given a connected file descriptor to the socket. + * + * @code + * status = krb5_auth_con_setaddrs_from_fd (context, + * auth_context, + * &sock); + * if (status) + * krb5_err (context, 1, status, + * "krb5_auth_con_setaddrs_from_fd"); + * @endcode + * + * The next step is to build a server principal for the service we want + * to connect to. (See also krb5_sname_to_principal().) + * + * @code + * status = krb5_sname_to_principal (context, + * hostname, + * service, + * KRB5_NT_SRV_HST, + * &server); + * if (status) + * krb5_err (context, 1, status, "krb5_sname_to_principal"); + * @endcode + * + * The client principal is not passed to krb5_sendauth() + * function, this causes the krb5_sendauth() function to try to figure it + * out itself. + * + * The server program is using the function krb5_recvauth() to + * receive the Kerberos 5 authenticator. + * + * In this case, mutual authentication will be tried. That means that the server + * will authenticate to the client. Using mutual authentication + * is required to avoid man-in-the-middle attacks, since it enables the user to + * verify that they are talking to the right server (a server that knows the key). + * + * If you are using a non-blocking socket you will need to do all work of + * krb5_sendauth() yourself. Basically you need to send over the + * authenticator from krb5_mk_req() and, in case of mutual + * authentication, verifying the result from the server with + * krb5_rd_rep(). + * + * @code + * status = krb5_sendauth (context, + * &auth_context, + * &sock, + * VERSION, + * NULL, + * server, + * AP_OPTS_MUTUAL_REQUIRED, + * NULL, + * NULL, + * NULL, + * NULL, + * NULL, + * NULL); + * if (status) + * krb5_err (context, 1, status, "krb5_sendauth"); + * @endcode + * + * Once authentication has been performed, it is time to send some + * data. First we create a krb5_data structure, then we sign it with + * krb5_mk_safe() using the auth_context that contains the + * session-key that was exchanged in the + * krb5_sendauth()/krb5_recvauth() authentication + * sequence. + * + * @code + * data.data = "hej"; + * data.length = 3; + * + * krb5_data_zero (&packet); + * + * status = krb5_mk_safe (context, + * auth_context, + * &data, + * &packet, + * NULL); + * if (status) + * krb5_err (context, 1, status, "krb5_mk_safe"); + * @endcode + * + * And send it over the network. + * + * @code + * len = packet.length; + * net_len = htonl(len); + * + * if (krb5_net_write (context, &sock, &net_len, 4) != 4) + * err (1, "krb5_net_write"); + * if (krb5_net_write (context, &sock, packet.data, len) != len) + * err (1, "krb5_net_write"); + * @endcode + * + * To send encrypted (and signed) data krb5_mk_priv() should be + * used instead. krb5_mk_priv() works the same way as + * krb5_mk_safe(), with the exception that it encrypts the data + * in addition to signing it. + * + * @code + * data.data = "hemligt"; + * data.length = 7; + * + * krb5_data_free (&packet); + * + * status = krb5_mk_priv (context, + * auth_context, + * &data, + * &packet, + * NULL); + * if (status) + * krb5_err (context, 1, status, "krb5_mk_priv"); + * @endcode + * + * And send it over the network. + * + * @code + * len = packet.length; + * net_len = htonl(len); + * + * if (krb5_net_write (context, &sock, &net_len, 4) != 4) + * err (1, "krb5_net_write"); + * if (krb5_net_write (context, &sock, packet.data, len) != len) + * err (1, "krb5_net_write"); + * + * @endcode + * + * The server is using krb5_rd_safe() and + * krb5_rd_priv() to verify the signature and decrypt the packet. + * + * @section intro_krb5_verify_user Validating a password in an application + * + * See the manual page for krb5_verify_user(). + * + * @section mit_differences API differences to MIT Kerberos + * + * This section is somewhat disorganised, but so far there is no overall + * structure to the differences, though some of the have their root in + * that Heimdal uses an ASN.1 compiler and MIT doesn't. + * + * @subsection mit_krb5_principal Principal and realms + * + * Heimdal stores the realm as a krb5_realm, that is a char *. + * MIT Kerberos uses a krb5_data to store a realm. + * + * In Heimdal krb5_principal doesn't contain the component + * name_type; it's instead stored in component + * name.name_type. To get and set the nametype in Heimdal, use + * krb5_principal_get_type() and + * krb5_principal_set_type(). + * + * For more information about principal and realms, see + * krb5_principal. + * + * @subsection mit_krb5_error_code Error messages + * + * To get the error string, Heimdal uses + * krb5_get_error_message(). This is to return custom error messages + * (like ``Can't find host/datan.example.com\@CODE.COM in + * /etc/krb5.conf.'' instead of a ``Key table entry not found'' that + * error_message returns. + * + * Heimdal uses a threadsafe(r) version of the com_err interface; the + * global com_err table isn't initialised. Then + * error_message returns quite a boring error string (just + * the error code itself). + * + * + */ + +/** + * + * + * @page krb5_fileformats File formats + * + * @section fileformats File formats + * + * This section documents the diffrent file formats that are used in + * Heimdal and other Kerberos implementations. + * + * @subsection file_keytab keytab + * + * The keytab binary format is not a standard format. The format has + * evolved and may continue to. It is however understood by several + * Kerberos implementations including Heimdal, MIT, Sun's Java ktab and + * are created by the ktpass.exe utility from Windows. So it has + * established itself as the defacto format for storing Kerberos keys. + * + * The following C-like structure definitions illustrate the MIT keytab + * file format. All values are in network byte order. All text is ASCII. + * + * @code + * keytab { + * uint16_t file_format_version; # 0x502 + * keytab_entry entries[*]; + * }; + * + * keytab_entry { + * int32_t size; + * uint16_t num_components; # subtract 1 if version 0x501 + * counted_octet_string realm; + * counted_octet_string components[num_components]; + * uint32_t name_type; # not present if version 0x501 + * uint32_t timestamp; + * uint8_t vno8; + * keyblock key; + * uint32_t vno; #only present if >= 4 bytes left in entry + * uint32_t flags; #only present if >= 4 bytes left in entry + * }; + * + * counted_octet_string { + * uint16_t length; + * uint8_t data[length]; + * }; + * + * keyblock { + * uint16_t type; + * counted_octet_string; + * }; + * @endcode + * + * All numbers are stored in network byteorder (big endian) format. + * + * The keytab file format begins with the 16 bit file_format_version which + * at the time this document was authored is 0x502. The format of older + * keytabs is described at the end of this document. + * + * The file_format_version is immediately followed by an array of + * keytab_entry structures which are prefixed with a 32 bit size indicating + * the number of bytes that follow in the entry. Note that the size should be + * evaluated as signed. This is because a negative value indicates that the + * entry is in fact empty (e.g. it has been deleted) and that the negative + * value of that negative value (which is of course a positive value) is + * the offset to the next keytab_entry. Based on these size values alone + * the entire keytab file can be traversed. + * + * The size is followed by a 16 bit num_components field indicating the + * number of counted_octet_string components in the components array. + * + * The num_components field is followed by a counted_octet_string + * representing the realm of the principal. + * + * A counted_octet_string is simply an array of bytes prefixed with a 16 + * bit length. For the realm and name components, the counted_octet_string + * bytes are ASCII encoded text with no zero terminator. + * + * Following the realm is the components array that represents the name of + * the principal. The text of these components may be joined with slashs + * to construct the typical SPN representation. For example, the service + * principal HTTP/www.foo.net\@FOO.NET would consist of name components + * "HTTP" followed by "www.foo.net". + * + * Following the components array is the 32 bit name_type (e.g. 1 is + * KRB5_NT_PRINCIPAL, 2 is KRB5_NT_SRV_INST, 5 is KRB5_NT_UID, etc). In + * practice the name_type is almost certainly 1 meaning KRB5_NT_PRINCIPAL. + * + * The 32 bit timestamp indicates the time the key was established for that + * principal. The value represents the number of seconds since Jan 1, 1970. + * + * The 8 bit vno8 field is the version number of the key. This value is + * overridden by the 32 bit vno field if it is present. The vno8 field is + * filled with the lower 8 bits of the 32 bit protocol kvno field. + * + * The keyblock structure consists of a 16 bit value indicating the + * encryption type and is a counted_octet_string containing the key. The + * encryption type is the same as the Kerberos standard (e.g. 3 is + * des-cbc-md5, 23 is arcfour-hmac-md5, etc). + * + * The last field of the keytab_entry structure is optional. If the size of + * the keytab_entry indicates that there are at least 4 bytes remaining, + * a 32 bit value representing the key version number is present. This + * value supersedes the 8 bit vno8 value preceeding the keyblock. + * + * Older keytabs with a file_format_version of 0x501 are different in + * three ways: + * + * - All integers are in host byte order [1]. + * - The num_components field is 1 too large (i.e. after decoding, decrement by 1). + * - The 32 bit name_type field is not present. + * + * [1] The file_format_version field should really be treated as two + * separate 8 bit quantities representing the major and minor version + * number respectively. + * + * @subsection file_hdb_dump Heimdal database dump file + * + * Format of the Heimdal text dump file as of Heimdal 0.6.3: + * + * Each line in the dump file is one entry in the database. + * + * Each field of a line is separated by one or more spaces, with the + * exception of fields consisting of principals containing spaces, where + * space can be quoted with \ and \ is quoted by \. + * + * Fields and their types are: + * + * @code + * Quoted principal (quote character is \) [string] + * Keys [keys] + * Created by [event] + * Modified by [event optional] + * Valid start time [time optional] + * Valid end time [time optional] + * Password end valid time [time optional] + * Max lifetime of ticket [time optional] + * Max renew time of ticket [integer optional] + * Flags [hdb flags] + * Generation number [generation optional] + * Extensions [extentions optional] + * @endcode + * + * Fields following these silently are ignored. + * + * All optional fields will be skipped if they fail to parse (or comprise + * the optional field marker of "-", w/o quotes). + * + * Example: + * + * @code + * fred\@CODE.COM 27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:- 20020415130120:admin\@CODE.COM 20041221112428:fred\@CODE.COM - - - 86400 604800 126 20020415130120:793707:28 - + * @endcode + * + * Encoding of types are as follows: + * + * - keys + * + * @code + * kvno:[masterkvno:keytype:keydata:salt]{zero or more separated by :} + * @endcode + * + * kvno is the key version number. + * + * keydata is hex-encoded + * + * masterkvno is the kvno of the database master key. If this field is + * empty, the kadmin load and merge operations will encrypt the key data + * with the master key if there is one. Otherwise the key data will be + * imported asis. + * + * salt is encoded as "-" (no/default salt) or + * + * @code + * salt-type / + * salt-type / "string" + * salt-type / hex-encoded-data + * @endcode + * + * keytype is the protocol enctype number; see enum ENCTYPE in + * include/krb5_asn1.h for values. + * + * Example: + * @code + * 27:1:16:e8b4c8fc7e60b9e641dcf4cff3f08a701d982a2f89ba373733d26ca59ba6c789666f6b8bfcf169412bb1e5dceb9b33cda29f3412:-:1:3:4498a933881178c744f4232172dcd774c64e81fa6d05ecdf643a7e390624a0ebf3c7407a:-:1:2:b01934b13eb795d76f3a80717d469639b4da0cfb644161340ef44fdeb375e54d684dbb85:-:1:1:ea8e16d8078bf60c781da90f508d4deccba70595258b9d31888d33987cd31af0c9cced2e:- + * @endcode + * + * + * @code + * kvno=27,{key: masterkvno=1,keytype=des3-cbc-sha1,keydata=..., default salt}... + * @endcode + * + * - time + * + * Format of the time is: YYYYmmddHHMMSS, corresponding to strftime + * format "%Y%m%d%k%M%S". + * + * Time is expressed in UTC. + * + * Time can be optional (using -), when the time 0 is used. + * + * Example: + * + * @code + * 20041221112428 + * @endcode + * + * - event + * + * @code + * time:principal + * @endcode + * + * time is as given in format time + * + * principal is a string. Not quoting it may not work in earlier + * versions of Heimdal. + * + * Example: + * @code + * 20041221112428:bloggs\@CODE.COM + * @endcode + * + * - hdb flags + * + * Integer encoding of HDB flags, see HDBFlags in lib/hdb/hdb.asn1. Each + * bit in the integer is the same as the bit in the specification. + * + * - generation: + * + * @code + * time:usec:gen + * @endcode + * + * + * usec is a the microsecond, integer. + * gen is generation number, integer. + * + * The generation can be defaulted (using '-') or the empty string + * + * - extensions: + * + * @code + * first-hex-encoded-HDB-Extension[:second-...] + * @endcode + * + * HDB-extension is encoded the DER encoded HDB-Extension from + * lib/hdb/hdb.asn1. Consumers HDB extensions should be aware that + * unknown entires needs to be preserved even thought the ASN.1 data + * content might be unknown. There is a critical flag in the data to show + * to the KDC that the entry MUST be understod if the entry is to be + * used. + * + * + */ diff --git a/third_party/heimdal/lib/krb5/eai_to_heim_errno.c b/third_party/heimdal/lib/krb5/eai_to_heim_errno.c new file mode 100644 index 0000000..a6e14ab --- /dev/null +++ b/third_party/heimdal/lib/krb5/eai_to_heim_errno.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Convert the getaddrinfo() error code to a Kerberos et error code. + * + * @param eai_errno contains the error code from getaddrinfo(). + * @param system_error should have the value of errno after the failed getaddrinfo(). + * + * @return Kerberos error code representing the EAI errors. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_eai_to_heim_errno(int eai_errno, int system_error) +{ + switch(eai_errno) { + case EAI_NOERROR: + return 0; +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: + return HEIM_EAI_ADDRFAMILY; +#endif + case EAI_AGAIN: + return HEIM_EAI_AGAIN; + case EAI_BADFLAGS: + return HEIM_EAI_BADFLAGS; + case EAI_FAIL: + return HEIM_EAI_FAIL; + case EAI_FAMILY: + return HEIM_EAI_FAMILY; + case EAI_MEMORY: + return HEIM_EAI_MEMORY; +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: + return HEIM_EAI_NODATA; +#endif +#ifdef WSANO_DATA + case WSANO_DATA: + return HEIM_EAI_NODATA; +#endif + case EAI_NONAME: + return HEIM_EAI_NONAME; + case EAI_SERVICE: + return HEIM_EAI_SERVICE; + case EAI_SOCKTYPE: + return HEIM_EAI_SOCKTYPE; +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + return system_error; +#endif + default: + return HEIM_EAI_UNKNOWN; /* XXX */ + } +} + +/** + * Convert the gethostname() error code (h_error) to a Kerberos et + * error code. + * + * @param eai_errno contains the error code from gethostname(). + * + * @return Kerberos error code representing the gethostname errors. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_h_errno_to_heim_errno(int eai_errno) +{ + switch(eai_errno) { + case 0: + return 0; + case HOST_NOT_FOUND: + return HEIM_EAI_NONAME; + case TRY_AGAIN: + return HEIM_EAI_AGAIN; + case NO_RECOVERY: + return HEIM_EAI_FAIL; + case NO_DATA: + return HEIM_EAI_NONAME; + default: + return HEIM_EAI_UNKNOWN; /* XXX */ + } +} diff --git a/third_party/heimdal/lib/krb5/enomem.c b/third_party/heimdal/lib/krb5/enomem.c new file mode 100644 index 0000000..b4444e5 --- /dev/null +++ b/third_party/heimdal/lib/krb5/enomem.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#undef krb5_enomem +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_enomem(krb5_context context) +{ + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; +} diff --git a/third_party/heimdal/lib/krb5/error_string.c b/third_party/heimdal/lib/krb5/error_string.c new file mode 100644 index 0000000..da86b37 --- /dev/null +++ b/third_party/heimdal/lib/krb5/error_string.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2001, 2003, 2005 - 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#undef __attribute__ +#define __attribute__(x) + +/** + * Clears the error message from the Kerberos 5 context. + * + * @param context The Kerberos 5 context to clear + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_clear_error_message(krb5_context context) +{ + heim_clear_error_message(context->hcontext); +} + +/** + * Set the context full error string for a specific error code. + * The error that is stored should be internationalized. + * + * The if context is NULL, no error string is stored. + * + * @param context Kerberos 5 context + * @param ret The error code + * @param fmt Error string for the error code + * @param ... printf(3) style parameters. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_set_error_message(krb5_context context, krb5_error_code ret, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) +{ + va_list ap; + + va_start(ap, fmt); + krb5_vset_error_message (context, ret, fmt, ap); + va_end(ap); +} + +/** + * Set the context full error string for a specific error code. + * + * The if context is NULL, no error string is stored. + * + * @param context Kerberos 5 context + * @param ret The error code + * @param fmt Error string for the error code + * @param args printf(3) style parameters. + * + * @ingroup krb5_error + */ + + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_vset_error_message(krb5_context context, krb5_error_code ret, + const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + const char *msg; + + if (context == NULL) + return; + + heim_vset_error_message(context->hcontext, ret, fmt, args); + msg = heim_get_error_message(context->hcontext, ret); + if (msg) { + _krb5_debug(context, 100, "error message: %s: %d", msg, ret); + heim_free_error_message(context->hcontext, msg); + } +} + +/** + * Prepend the context full error string for a specific error code. + * The error that is stored should be internationalized. + * + * The if context is NULL, no error string is stored. + * + * @param context Kerberos 5 context + * @param ret The error code + * @param fmt Error string for the error code + * @param ... printf(3) style parameters. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_prepend_error_message(krb5_context context, krb5_error_code ret, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) +{ + va_list ap; + + va_start(ap, fmt); + krb5_vprepend_error_message(context, ret, fmt, ap); + va_end(ap); +} + +/** + * Prepend the contexts's full error string for a specific error code. + * + * The if context is NULL, no error string is stored. + * + * @param context Kerberos 5 context + * @param ret The error code + * @param fmt Error string for the error code + * @param args printf(3) style parameters. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_vprepend_error_message(krb5_context context, krb5_error_code ret, + const char *fmt, va_list args) + __attribute__ ((__format__ (__printf__, 3, 0))) +{ + if (context) + heim_vprepend_error_message(context->hcontext, ret, fmt, args); +} + +/** + * Return the error message for `code' in context. On memory + * allocation error the function returns NULL. + * + * @param context Kerberos 5 context + * @param code Error code related to the error + * + * @return an error string, needs to be freed with + * krb5_free_error_message(). The functions return NULL on error. + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL +krb5_get_error_message(krb5_context context, krb5_error_code code) +{ + const char *cstr = NULL; + + if (code == 0) + return strdup("Success"); + + /* + * The MIT version of this function ignores the krb5_context + * and several widely deployed applications call krb5_get_error_message() + * with a NULL context in order to translate an error code as a + * replacement for error_message(). Another reason a NULL context + * might be provided is if the krb5_init_context() call itself + * failed. + */ + if (context == NULL && krb5_init_context(&context) == 0) { + cstr = heim_get_error_message(context->hcontext, code); + krb5_free_context(context); + } else if (context) { + cstr = heim_get_error_message(context->hcontext, code); + } else { + cstr = heim_get_error_message(NULL, code); + } + return cstr; +} + + +/** + * Free the error message returned by krb5_get_error_message(). + * + * @param context Kerberos context + * @param msg error message to free, returned byg + * krb5_get_error_message(). + * + * @ingroup krb5_error + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_error_message(krb5_context context, const char *msg) +{ + heim_free_error_message(context ? context->hcontext : NULL, msg); +} + + +/** + * Return the error string for the error code. The caller must not + * free the string. + * + * This function is deprecated since its not threadsafe. + * + * @param context Kerberos 5 context. + * @param code Kerberos error code. + * + * @return the error message matching code + * + * @ingroup krb5 + */ + +KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL +krb5_get_err_text(krb5_context context, krb5_error_code code) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead") +{ + return krb5_get_error_message(context, code); +} diff --git a/third_party/heimdal/lib/krb5/expand_hostname.c b/third_party/heimdal/lib/krb5/expand_hostname.c new file mode 100644 index 0000000..5023d16 --- /dev/null +++ b/third_party/heimdal/lib/krb5/expand_hostname.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +static krb5_error_code +copy_hostname(krb5_context context, + const char *orig_hostname, + char **new_hostname) +{ + *new_hostname = strdup (orig_hostname); + if (*new_hostname == NULL) + return krb5_enomem(context); + strlwr (*new_hostname); + return 0; +} + +/** + * krb5_expand_hostname() tries to make orig_hostname into a more + * canonical one in the newly allocated space returned in + * new_hostname. + + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_expand_hostname (krb5_context context, + const char *orig_hostname, + char **new_hostname) +{ + struct addrinfo *ai, *a, hints; + int error; + + if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0) + return copy_hostname (context, orig_hostname, new_hostname); + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + error = getaddrinfo (orig_hostname, NULL, &hints, &ai); + if (error) + return copy_hostname (context, orig_hostname, new_hostname); + for (a = ai; a != NULL; a = a->ai_next) { + if (a->ai_canonname != NULL) { + *new_hostname = strdup (a->ai_canonname); + freeaddrinfo (ai); + if (*new_hostname == NULL) + return krb5_enomem(context); + else + return 0; + } + } + freeaddrinfo (ai); + return copy_hostname (context, orig_hostname, new_hostname); +} + +/* + * handle the case of the hostname being unresolvable and thus identical + */ + +static krb5_error_code +vanilla_hostname (krb5_context context, + const char *orig_hostname, + char **new_hostname, + char ***realms) +{ + krb5_error_code ret; + + ret = copy_hostname (context, orig_hostname, new_hostname); + if (ret) + return ret; + strlwr (*new_hostname); + + ret = krb5_get_host_realm (context, *new_hostname, realms); + if (ret) { + free (*new_hostname); + return ret; + } + return 0; +} + +/** + * krb5_expand_hostname_realms() expands orig_hostname to a name we + * believe to be a hostname in newly allocated space in new_hostname + * and return the realms new_hostname is believed to belong to in + * realms. + * + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * @param realms output possible realms, is an array that is terminated + * with NULL. Caller must free with krb5_free_host_realm(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_expand_hostname_realms (krb5_context context, + const char *orig_hostname, + char **new_hostname, + char ***realms) +{ + struct addrinfo *ai, *a, hints; + int error; + krb5_error_code ret = 0; + + if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0) + return vanilla_hostname (context, orig_hostname, new_hostname, + realms); + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + error = getaddrinfo (orig_hostname, NULL, &hints, &ai); + if (error) + return vanilla_hostname (context, orig_hostname, new_hostname, + realms); + + for (a = ai; a != NULL; a = a->ai_next) { + if (a->ai_canonname != NULL) { + ret = copy_hostname (context, a->ai_canonname, new_hostname); + if (ret) { + freeaddrinfo (ai); + return ret; + } + strlwr (*new_hostname); + ret = krb5_get_host_realm (context, *new_hostname, realms); + if (ret == 0) { + freeaddrinfo (ai); + return 0; + } + free (*new_hostname); + } + } + freeaddrinfo(ai); + return vanilla_hostname (context, orig_hostname, new_hostname, realms); +} diff --git a/third_party/heimdal/lib/krb5/expand_path.c b/third_party/heimdal/lib/krb5/expand_path.c new file mode 100644 index 0000000..a040235 --- /dev/null +++ b/third_party/heimdal/lib/krb5/expand_path.c @@ -0,0 +1,94 @@ + +/*********************************************************************** + * Copyright (c) 2009, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include "krb5_locl.h" + +#include + +/** + * Internal function to expand tokens in paths. + * + * Inputs: + * + * @context A krb5_context + * @path_in The path to expand tokens from + * @filepath True if the value is a filesystem path (converts slashes to + * backslashes on Windows) + * @ppath_out The expanded path + * + * Outputs: + * + * @ppath_out Path with expanded tokens (caller must free() this) + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_expand_path_tokens(krb5_context context, + const char *path_in, + int filepath, + char **ppath_out) +{ + return heim_expand_path_tokens(context ? context->hcontext : NULL, path_in, + filepath, ppath_out, NULL); +} + +/** + * Internal function to expand tokens in paths. + * + * Inputs: + * + * @context A krb5_context + * @path_in The path to expand tokens from + * @filepath True if the value is a filesystem path (converts slashes to + * backslashes on Windows) + * @ppath_out The expanded path + * @... Variable number of pairs of strings, the first of each + * being a token (e.g., "luser") and the second a string to + * replace it with. The list is terminated by a NULL. + * + * Outputs: + * + * @ppath_out Path with expanded tokens (caller must free() this) + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_expand_path_tokensv(krb5_context context, + const char *path_in, + int filepath, + char **ppath_out, ...) +{ + krb5_error_code ret; + va_list ap; + + va_start(ap, ppath_out); + ret = heim_expand_path_tokensv(context->hcontext, path_in, filepath, ppath_out, ap); + va_end(ap); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/fast.c b/third_party/heimdal/lib/krb5/fast.c new file mode 100644 index 0000000..90133a7 --- /dev/null +++ b/third_party/heimdal/lib/krb5/fast.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#ifndef WIN32 +#include +#endif + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_fast_cf2(krb5_context context, + krb5_keyblock *key1, + const char *pepper1, + krb5_keyblock *key2, + const char *pepper2, + krb5_keyblock *armorkey, + krb5_crypto *armor_crypto) +{ + krb5_crypto crypto1, crypto2; + krb5_data pa1, pa2; + krb5_error_code ret; + + ret = krb5_crypto_init(context, key1, 0, &crypto1); + if (ret) + return ret; + + ret = krb5_crypto_init(context, key2, 0, &crypto2); + if (ret) { + krb5_crypto_destroy(context, crypto1); + return ret; + } + + pa1.data = rk_UNCONST(pepper1); + pa1.length = strlen(pepper1); + pa2.data = rk_UNCONST(pepper2); + pa2.length = strlen(pepper2); + + ret = krb5_crypto_fx_cf2(context, crypto1, crypto2, &pa1, &pa2, + key1->keytype, armorkey); + krb5_crypto_destroy(context, crypto1); + krb5_crypto_destroy(context, crypto2); + if (ret) + return ret; + + if (armor_crypto) { + ret = krb5_crypto_init(context, armorkey, 0, armor_crypto); + if (ret) + krb5_free_keyblock_contents(context, armorkey); + } + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_fast_armor_key(krb5_context context, + krb5_keyblock *subkey, + krb5_keyblock *sessionkey, + krb5_keyblock *armorkey, + krb5_crypto *armor_crypto) +{ + return _krb5_fast_cf2(context, + subkey, + "subkeyarmor", + sessionkey, + "ticketarmor", + armorkey, + armor_crypto); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_fast_explicit_armor_key(krb5_context context, + krb5_keyblock *armorkey, + krb5_keyblock *subkey, + krb5_keyblock *explicit_armorkey, + krb5_crypto *explicit_armor_crypto) +{ + return _krb5_fast_cf2(context, + armorkey, + "explicitarmor", + subkey, + "tgsarmor", + explicit_armorkey, + explicit_armor_crypto); +} + +static krb5_error_code +check_fast(krb5_context context, struct krb5_fast_state *state) +{ + if (state && (state->flags & KRB5_FAST_EXPECTED)) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + "Expected FAST, but no FAST " + "was in the response from the KDC"); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + +static krb5_error_code +make_local_fast_ap_fxarmor(krb5_context context, + krb5_ccache armor_ccache, + krb5_const_realm realm, + krb5_data *armor_value, + krb5_keyblock *armor_key, + krb5_crypto *armor_crypto) +{ + krb5_auth_context auth_context = NULL; + krb5_creds cred, *credp = NULL; + krb5_error_code ret; + krb5_data empty; + krb5_const_realm tgs_realm; + + if (armor_ccache == NULL) { + krb5_set_error_message(context, EINVAL, + "Armor credential cache required"); + return EINVAL; + } + + krb5_data_zero(&empty); + memset(&cred, 0, sizeof(cred)); + + ret = krb5_auth_con_init (context, &auth_context); + if (ret) + goto out; + + ret = krb5_cc_get_principal(context, armor_ccache, &cred.client); + if (ret) + goto out; + + /* + * Make sure we don't ask for a krbtgt/WELLKNOWN:ANONYMOUS + */ + if (krb5_principal_is_anonymous(context, cred.client, + KRB5_ANON_MATCH_UNAUTHENTICATED)) + tgs_realm = realm; + else + tgs_realm = cred.client->realm; + + ret = krb5_make_principal(context, &cred.server, + tgs_realm, + KRB5_TGS_NAME, + tgs_realm, + NULL); + if (ret) + goto out; + + ret = krb5_get_credentials(context, 0, armor_ccache, &cred, &credp); + if (ret) + goto out; + + ret = krb5_auth_con_add_AuthorizationData(context, auth_context, + KRB5_AUTHDATA_FX_FAST_ARMOR, + &empty); + if (ret) + goto out; + + ret = krb5_mk_req_extended(context, + &auth_context, + AP_OPTS_USE_SUBKEY, + NULL, + credp, + armor_value); + if (ret) + goto out; + + ret = _krb5_fast_armor_key(context, + auth_context->local_subkey, + auth_context->keyblock, + armor_key, + armor_crypto); + if (ret) + goto out; + + out: + if (auth_context) + krb5_auth_con_free(context, auth_context); + if (credp) + krb5_free_creds(context, credp); + krb5_free_principal(context, cred.server); + krb5_free_principal(context, cred.client); + + return ret; +} + +#ifndef WIN32 +static heim_base_once_t armor_service_once = HEIM_BASE_ONCE_INIT; +static heim_ipc armor_service = NULL; + +static void +fast_armor_init_ipc(void *ctx) +{ + heim_ipc *ipc = ctx; + heim_ipc_init_context("ANY:org.h5l.armor-service", ipc); +} +#endif + +static krb5_error_code +make_fast_ap_fxarmor(krb5_context context, + struct krb5_fast_state *state, + krb5_const_realm realm, + KrbFastArmor **armor) +{ + KrbFastArmor *fxarmor = NULL; + krb5_error_code ret; + + *armor = NULL; + + ALLOC(fxarmor, 1); + if (fxarmor == NULL) { + ret = ENOMEM; + goto out; + } + + if (state->flags & KRB5_FAST_AP_ARMOR_SERVICE) { +#ifdef WIN32 + krb5_set_error_message(context, ENOTSUP, "Fast armor IPC service not supportted yet on Windows"); + ret = ENOTSUP; + goto out; +#else + KERB_ARMOR_SERVICE_REPLY msg; + krb5_data request, reply; + + heim_base_once_f(&armor_service_once, &armor_service, fast_armor_init_ipc); + if (armor_service == NULL) { + krb5_set_error_message(context, ENOENT, "Failed to open fast armor service"); + ret = ENOENT; + goto out; + } + + krb5_data_zero(&reply); + + request.data = rk_UNCONST(realm); + request.length = strlen(realm); + + ret = heim_ipc_call(armor_service, &request, &reply, NULL); + if (ret) { + krb5_set_error_message(context, ret, "Failed to get armor service credential"); + goto out; + } + + ret = decode_KERB_ARMOR_SERVICE_REPLY(reply.data, reply.length, &msg, NULL); + krb5_data_free(&reply); + if (ret) + goto out; + + ret = copy_KrbFastArmor(fxarmor, &msg.armor); + if (ret) { + free_KERB_ARMOR_SERVICE_REPLY(&msg); + goto out; + } + + ret = krb5_copy_keyblock_contents(context, &msg.armor_key, &state->armor_key); + free_KERB_ARMOR_SERVICE_REPLY(&msg); + if (ret) + goto out; + + ret = krb5_crypto_init(context, &state->armor_key, 0, &state->armor_crypto); + if (ret) + goto out; +#endif /* WIN32 */ + } else { + fxarmor->armor_type = 1; + + ret = make_local_fast_ap_fxarmor(context, + state->armor_ccache, + realm, + &fxarmor->armor_value, + &state->armor_key, + &state->armor_crypto); + if (ret) + goto out; + } + + + *armor = fxarmor; + fxarmor = NULL; + + out: + if (fxarmor) { + free_KrbFastArmor(fxarmor); + free(fxarmor); + } + return ret; +} + +static krb5_error_code +unwrap_fast_rep(krb5_context context, + struct krb5_fast_state *state, + PA_DATA *pa, + KrbFastResponse *fastrep) +{ + PA_FX_FAST_REPLY fxfastrep; + krb5_error_code ret; + + memset(&fxfastrep, 0, sizeof(fxfastrep)); + + ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data, + pa->padata_value.length, + &fxfastrep, NULL); + if (ret) + return ret; + + if (fxfastrep.element == choice_PA_FX_FAST_REPLY_armored_data) { + krb5_data data; + + ret = krb5_decrypt_EncryptedData(context, + state->armor_crypto, + KRB5_KU_FAST_REP, + &fxfastrep.u.armored_data.enc_fast_rep, + &data); + if (ret) + goto out; + + ret = decode_KrbFastResponse(data.data, data.length, fastrep, NULL); + krb5_data_free(&data); + if (ret) + goto out; + + } else { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + out: + free_PA_FX_FAST_REPLY(&fxfastrep); + + return ret; +} + +static krb5_error_code +set_anon_principal(krb5_context context, PrincipalName **p) +{ + + ALLOC((*p), 1); + if (*p == NULL) + goto fail; + + (*p)->name_type = KRB5_NT_PRINCIPAL; + + ALLOC_SEQ(&(*p)->name_string, 2); + if ((*p)->name_string.val == NULL) + goto fail; + + (*p)->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME); + if ((*p)->name_string.val[0] == NULL) + goto fail; + + (*p)->name_string.val[1] = strdup(KRB5_ANON_NAME); + if ((*p)->name_string.val[1] == NULL) + goto fail; + + return 0; + fail: + if (*p) { + if ((*p)->name_string.val) { + free((*p)->name_string.val[0]); + free((*p)->name_string.val[1]); + free((*p)->name_string.val); + } + free(*p); + } + + return krb5_enomem(context); +} + +krb5_error_code +_krb5_fast_create_armor(krb5_context context, + struct krb5_fast_state *state, + const char *realm) +{ + krb5_error_code ret; + + if (state->armor_crypto == NULL) { + if (state->armor_ccache || state->armor_ac || (state->flags & KRB5_FAST_AP_ARMOR_SERVICE)) { + /* + * Instead of keeping state in FX_COOKIE in the KDC, we + * rebuild a new armor key for every request, because this + * is what the MIT KDC expect and RFC6113 is vage about + * what the behavior should be. + */ + state->type = choice_PA_FX_FAST_REQUEST_armored_data; + } else { + return check_fast(context, state); + } + } + + if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) { + if (state->armor_crypto) { + krb5_crypto_destroy(context, state->armor_crypto); + state->armor_crypto = NULL; + } + if (state->strengthen_key) { + krb5_free_keyblock(context, state->strengthen_key); + state->strengthen_key = NULL; + } + krb5_free_keyblock_contents(context, &state->armor_key); + + /* + * If we have a armor auth context, its because the caller + * wants us to do an implicit FAST armor (TGS-REQ). + */ + if (state->armor_ac) { + heim_assert((state->flags & KRB5_FAST_AS_REQ) == 0, "FAST AS with AC"); + + ret = _krb5_fast_armor_key(context, + state->armor_ac->local_subkey, + state->armor_ac->keyblock, + &state->armor_key, + &state->armor_crypto); + if (ret) + goto out; + } else { + heim_assert((state->flags & KRB5_FAST_AS_REQ) != 0, "FAST TGS without AC"); + + if (state->armor_data) { + free_KrbFastArmor(state->armor_data); + free(state->armor_data); + state->armor_data = NULL; + } + ret = make_fast_ap_fxarmor(context, state, realm, + &state->armor_data); + if (ret) + goto out; + } + } else { + heim_abort("unknown state type: %d", (int)state->type); + } + out: + return ret; +} + + +krb5_error_code +_krb5_fast_wrap_req(krb5_context context, + struct krb5_fast_state *state, + KDC_REQ *req) +{ + PA_FX_FAST_REQUEST fxreq; + krb5_error_code ret; + KrbFastReq fastreq; + krb5_data data, aschecksum_data, tgschecksum_data; + const krb5_data *checksum_data = NULL; + size_t size = 0; + krb5_boolean readd_padata_to_outer = FALSE; + + if (state->flags & KRB5_FAST_DISABLED) { + _krb5_debug(context, 10, "fast disabled, not doing any fast wrapping"); + return 0; + } + + memset(&fxreq, 0, sizeof(fxreq)); + memset(&fastreq, 0, sizeof(fastreq)); + krb5_data_zero(&data); + krb5_data_zero(&aschecksum_data); + krb5_data_zero(&tgschecksum_data); + + if (state->armor_crypto == NULL) + return check_fast(context, state); + + state->flags |= KRB5_FAST_EXPECTED; + + fastreq.fast_options.hide_client_names = 1; + + ret = copy_KDC_REQ_BODY(&req->req_body, &fastreq.req_body); + if (ret) + goto out; + + /* + * In the case of a AS-REQ, remove all account names. Want to this + * for TGS-REQ too, but due to layering this is tricky. + * + * 1. TGS-REQ need checksum of REQ-BODY + * 2. FAST needs checksum of TGS-REQ, so, FAST needs to happen after TGS-REQ + * 3. FAST privacy mangaling needs to happen before TGS-REQ does the checksum in 1. + * + * So lets not modify the bits for now for TGS-REQ + */ + if (state->flags & KRB5_FAST_AS_REQ) { + free_KDC_REQ_BODY(&req->req_body); + + req->req_body.realm = strdup(KRB5_ANON_REALM); + if (req->req_body.realm == NULL) { + ret = krb5_enomem(context); + goto out; + } + + ret = set_anon_principal(context, &req->req_body.cname); + if (ret) + goto out; + + ALLOC(req->req_body.till, 1); + *req->req_body.till = 0; + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, + aschecksum_data.data, + aschecksum_data.length, + &req->req_body, + &size, ret); + if (ret) + goto out; + heim_assert(aschecksum_data.length == size, "ASN.1 internal error"); + + checksum_data = &aschecksum_data; + + if (req->padata) { + ret = copy_METHOD_DATA(req->padata, &fastreq.padata); + free_METHOD_DATA(req->padata); + if (ret) + goto out; + } + } else { + const PA_DATA *tgs_req_ptr = NULL; + int tgs_req_idx = 0; + size_t i; + + heim_assert(req->padata != NULL, "req->padata is NULL"); + + tgs_req_ptr = krb5_find_padata(req->padata->val, + req->padata->len, + KRB5_PADATA_TGS_REQ, + &tgs_req_idx); + heim_assert(tgs_req_ptr != NULL, "KRB5_PADATA_TGS_REQ not found"); + heim_assert(tgs_req_idx == 0, "KRB5_PADATA_TGS_REQ not first"); + + tgschecksum_data.data = tgs_req_ptr->padata_value.data; + tgschecksum_data.length = tgs_req_ptr->padata_value.length; + checksum_data = &tgschecksum_data; + + /* + * Now copy all remaining once to + * the fastreq.padata and clear + * them in the outer req first, + * and remember to readd them later. + */ + readd_padata_to_outer = TRUE; + + for (i = 1; i < req->padata->len; i++) { + PA_DATA *val = &req->padata->val[i]; + + ret = krb5_padata_add(context, + &fastreq.padata, + val->padata_type, + val->padata_value.data, + val->padata_value.length); + if (ret) { + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + val->padata_value.data = NULL; + val->padata_value.length = 0; + } + + /* + * Only TGS-REQ remaining + */ + req->padata->len = 1; + } + + if (req->padata == NULL) { + ALLOC(req->padata, 1); + if (req->padata == NULL) { + ret = krb5_enomem(context); + goto out; + } + } + + ASN1_MALLOC_ENCODE(KrbFastReq, data.data, data.length, &fastreq, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + fxreq.element = state->type; + + if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) { + fxreq.u.armored_data.armor = state->armor_data; + state->armor_data = NULL; + + heim_assert(state->armor_crypto != NULL, + "FAST armor key missing when FAST started"); + + ret = krb5_create_checksum(context, state->armor_crypto, + KRB5_KU_FAST_REQ_CHKSUM, 0, + checksum_data->data, + checksum_data->length, + &fxreq.u.armored_data.req_checksum); + if (ret) + goto out; + + ret = krb5_encrypt_EncryptedData(context, state->armor_crypto, + KRB5_KU_FAST_ENC, + data.data, + data.length, + 0, + &fxreq.u.armored_data.enc_fast_req); + krb5_data_free(&data); + if (ret) + goto out; + + } else { + krb5_data_free(&data); + heim_assert(false, "unknown FAST type, internal error"); + } + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, data.data, data.length, &fxreq, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + + ret = krb5_padata_add(context, req->padata, KRB5_PADATA_FX_FAST, data.data, data.length); + if (ret) + goto out; + krb5_data_zero(&data); + + if (readd_padata_to_outer) { + size_t i; + + for (i = 0; i < fastreq.padata.len; i++) { + PA_DATA *val = &fastreq.padata.val[i]; + + ret = krb5_padata_add(context, + req->padata, + val->padata_type, + val->padata_value.data, + val->padata_value.length); + if (ret) { + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + val->padata_value.data = NULL; + val->padata_value.length = 0; + } + } + + out: + free_KrbFastReq(&fastreq); + free_PA_FX_FAST_REQUEST(&fxreq); + krb5_data_free(&data); + krb5_data_free(&aschecksum_data); + + return ret; +} + +krb5_error_code +_krb5_fast_unwrap_error(krb5_context context, + int32_t nonce, + struct krb5_fast_state *state, + METHOD_DATA *md, + KRB_ERROR *error) +{ + KrbFastResponse fastrep; + krb5_error_code ret; + PA_DATA *pa; + int idx; + + if (state->armor_crypto == NULL) + return check_fast(context, state); + + memset(&fastrep, 0, sizeof(fastrep)); + + idx = 0; + pa = krb5_find_padata(md->val, md->len, KRB5_PADATA_FX_FAST, &idx); + if (pa == NULL) { + ret = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, ret, + N_("FAST fast response is missing FX-FAST", "")); + goto out; + } + + ret = unwrap_fast_rep(context, state, pa, &fastrep); + if (ret) + goto out; + + if (fastrep.strengthen_key || nonce != (int32_t)fastrep.nonce) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + idx = 0; + pa = krb5_find_padata(fastrep.padata.val, fastrep.padata.len, KRB5_PADATA_FX_ERROR, &idx); + if (pa == NULL) { + ret = KRB5_KDCREP_MODIFIED; + krb5_set_error_message(context, ret, N_("No wrapped error", "")); + goto out; + } + + free_KRB_ERROR(error); + + ret = krb5_rd_error(context, &pa->padata_value, error); + if (ret) + goto out; + + if (error->e_data) + _krb5_debug(context, 10, "FAST wrapped KBB_ERROR contained e_data: %d", + (int)error->e_data->length); + + free_METHOD_DATA(md); + md->val = fastrep.padata.val; + md->len = fastrep.padata.len; + + fastrep.padata.val = NULL; + fastrep.padata.len = 0; + + out: + free_KrbFastResponse(&fastrep); + return ret; +} + +krb5_error_code +_krb5_fast_unwrap_kdc_rep(krb5_context context, int32_t nonce, + krb5_data *chksumdata, + struct krb5_fast_state *state, AS_REP *rep) +{ + KrbFastResponse fastrep; + krb5_error_code ret; + PA_DATA *pa = NULL; + int idx = 0; + + if (state == NULL || state->armor_crypto == NULL || rep->padata == NULL) + return check_fast(context, state); + + /* find PA_FX_FAST_REPLY */ + + pa = krb5_find_padata(rep->padata->val, rep->padata->len, + KRB5_PADATA_FX_FAST, &idx); + if (pa == NULL) + return check_fast(context, state); + + memset(&fastrep, 0, sizeof(fastrep)); + + ret = unwrap_fast_rep(context, state, pa, &fastrep); + if (ret) + goto out; + + free_METHOD_DATA(rep->padata); + ret = copy_METHOD_DATA(&fastrep.padata, rep->padata); + if (ret) + goto out; + + if (fastrep.strengthen_key) { + if (state->strengthen_key) + krb5_free_keyblock(context, state->strengthen_key); + + ret = krb5_copy_keyblock(context, fastrep.strengthen_key, &state->strengthen_key); + if (ret) + goto out; + } + + if (nonce != (int32_t)fastrep.nonce) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + if (fastrep.finished) { + PrincipalName cname; + krb5_realm crealm = NULL; + + if (chksumdata == NULL) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_verify_checksum(context, state->armor_crypto, + KRB5_KU_FAST_FINISHED, + chksumdata->data, chksumdata->length, + &fastrep.finished->ticket_checksum); + if (ret) + goto out; + + /* update */ + ret = copy_Realm(&fastrep.finished->crealm, &crealm); + if (ret) + goto out; + free_Realm(&rep->crealm); + rep->crealm = crealm; + + ret = copy_PrincipalName(&fastrep.finished->cname, &cname); + if (ret) + goto out; + free_PrincipalName(&rep->cname); + rep->cname = cname; + } else if (chksumdata) { + /* expected fastrep.finish but didn't get it */ + ret = KRB5KDC_ERR_PREAUTH_FAILED; + } + + out: + free_KrbFastResponse(&fastrep); + return ret; +} + +void +_krb5_fast_free(krb5_context context, struct krb5_fast_state *state) +{ + if (state->armor_ccache) { + if (state->flags & KRB5_FAST_ANON_PKINIT_ARMOR) + krb5_cc_destroy(context, state->armor_ccache); + else + krb5_cc_close(context, state->armor_ccache); + } + if (state->armor_service) + krb5_free_principal(context, state->armor_service); + if (state->armor_crypto) + krb5_crypto_destroy(context, state->armor_crypto); + if (state->strengthen_key) + krb5_free_keyblock(context, state->strengthen_key); + krb5_free_keyblock_contents(context, &state->armor_key); + if (state->armor_data) { + free_KrbFastArmor(state->armor_data); + free(state->armor_data); + } + + if (state->anon_pkinit_ctx) + krb5_init_creds_free(context, state->anon_pkinit_ctx); + if (state->anon_pkinit_opt) + krb5_get_init_creds_opt_free(context, state->anon_pkinit_opt); + + memset(state, 0, sizeof(*state)); +} + +krb5_error_code +_krb5_fast_anon_pkinit_step(krb5_context context, + krb5_init_creds_context ctx, + struct krb5_fast_state *state, + const krb5_data *in, + krb5_data *out, + krb5_realm *out_realm, + unsigned int *flags) +{ + krb5_error_code ret; + krb5_const_realm realm = _krb5_init_creds_get_cred_client(context, ctx)->realm; + krb5_init_creds_context anon_pk_ctx; + krb5_principal principal = NULL, anon_pk_client; + krb5_ccache ccache = NULL; + krb5_creds cred; + krb5_data data = { 3, rk_UNCONST("yes") }; + + krb5_data_zero(out); + *out_realm = NULL; + + memset(&cred, 0, sizeof(cred)); + + if (state->anon_pkinit_opt == NULL) { + ret = krb5_get_init_creds_opt_alloc(context, &state->anon_pkinit_opt); + if (ret) + goto out; + + krb5_get_init_creds_opt_set_tkt_life(state->anon_pkinit_opt, 60); + krb5_get_init_creds_opt_set_anonymous(state->anon_pkinit_opt, TRUE); + + ret = krb5_make_principal(context, &principal, realm, + KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); + if (ret) + goto out; + + ret = krb5_get_init_creds_opt_set_pkinit(context, + state->anon_pkinit_opt, + principal, + NULL, NULL, NULL, NULL, + KRB5_GIC_OPT_PKINIT_ANONYMOUS | + KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR, + NULL, NULL, NULL); + if (ret) + goto out; + + ret = krb5_init_creds_init(context, principal, NULL, NULL, + _krb5_init_creds_get_cred_starttime(context, ctx), + state->anon_pkinit_opt, + &state->anon_pkinit_ctx); + if (ret) + goto out; + } + + anon_pk_ctx = state->anon_pkinit_ctx; + + ret = krb5_init_creds_step(context, anon_pk_ctx, in, out, out_realm, flags); + if (ret || + (*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) + goto out; + + ret = krb5_process_last_request(context, state->anon_pkinit_opt, anon_pk_ctx); + if (ret) + goto out; + + ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache); + if (ret) + goto out; + + ret = krb5_init_creds_get_creds(context, anon_pk_ctx, &cred); + if (ret) + goto out; + + if (!cred.flags.b.enc_pa_rep) { + ret = KRB5KDC_ERR_BADOPTION; /* KDC does not support FAST */ + goto out; + } + + anon_pk_client = _krb5_init_creds_get_cred_client(context, anon_pk_ctx); + + ret = krb5_cc_initialize(context, ccache, anon_pk_client); + if (ret) + goto out; + + ret = krb5_cc_store_cred(context, ccache, &cred); + if (ret) + goto out; + + ret = krb5_cc_set_config(context, ccache, cred.server, + "fast_avail", &data); + if (ret && ret != KRB5_CC_NOSUPP) + return ret; + + if (_krb5_pk_is_kdc_verified(context, state->anon_pkinit_opt)) + state->flags |= KRB5_FAST_KDC_VERIFIED; + else + state->flags &= ~(KRB5_FAST_KDC_VERIFIED); + + state->armor_ccache = ccache; + ccache = NULL; + + krb5_init_creds_free(context, state->anon_pkinit_ctx); + state->anon_pkinit_ctx = NULL; + + krb5_get_init_creds_opt_free(context, state->anon_pkinit_opt); + state->anon_pkinit_opt = NULL; + +out: + krb5_free_principal(context, principal); + krb5_free_cred_contents(context, &cred); + if (ccache) + krb5_cc_destroy(context, ccache); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/fcache.c b/third_party/heimdal/lib/krb5/fcache.c new file mode 100644 index 0000000..20c335d --- /dev/null +++ b/third_party/heimdal/lib/krb5/fcache.c @@ -0,0 +1,1693 @@ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +typedef struct krb5_fcache{ + char *filename; + char *res; + char *sub; + char *tmpfn; + int version; +}krb5_fcache; + +struct fcc_cursor { + int fd; + off_t cred_start; + off_t cred_end; + krb5_storage *sp; +}; + +#define KRB5_FCC_FVNO_1 1 +#define KRB5_FCC_FVNO_2 2 +#define KRB5_FCC_FVNO_3 3 +#define KRB5_FCC_FVNO_4 4 + +#define FCC_TAG_DELTATIME 1 + +#define FCACHE(X) ((krb5_fcache*)(X)->data.data) + +#define FILENAME(X) (FCACHE(X)->filename) +#define TMPFILENAME(X) (FCACHE(X)->tmpfn) +#define RESFILENAME(X) (FCACHE(X)->res) +#define SUBFILENAME(X) (FCACHE(X)->sub) + +#define FCC_CURSOR(C) ((struct fcc_cursor*)(C)) + +static krb5_error_code KRB5_CALLCONV +fcc_get_name_2(krb5_context context, + krb5_ccache id, + const char **name, + const char **colname, + const char **sub) +{ + if (FCACHE(id) == NULL) + return KRB5_CC_NOTFOUND; + + if (name) + *name = FILENAME(id); + if (colname) + *colname = FILENAME(id); + if (sub) + *sub = NULL; + return 0; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +_krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive, + const char *filename) +{ + int ret; +#ifdef HAVE_FCNTL + struct flock l; + + l.l_start = 0; + l.l_len = 0; + l.l_type = exclusive ? F_WRLCK : F_RDLCK; + l.l_whence = SEEK_SET; + ret = fcntl(fd, F_SETLKW, &l); +#else + ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH); +#endif + if(ret < 0) + ret = errno; + if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */ + ret = EAGAIN; + + switch (ret) { + case 0: + break; + case EINVAL: /* filesystem doesn't support locking, let the user have it */ + ret = 0; + break; + case EAGAIN: + krb5_set_error_message(context, ret, + N_("timed out locking cache file %s", "file"), + filename); + break; + default: { + char buf[128]; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, + N_("error locking cache file %s: %s", + "file, error"), filename, buf); + break; + } + } + return ret; +} + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +_krb5_xunlock(krb5_context context, int fd) +{ + int ret; +#ifdef HAVE_FCNTL + struct flock l; + l.l_start = 0; + l.l_len = 0; + l.l_type = F_UNLCK; + l.l_whence = SEEK_SET; + ret = fcntl(fd, F_SETLKW, &l); +#else + ret = flock(fd, LOCK_UN); +#endif + if (ret < 0) + ret = errno; + switch (ret) { + case 0: + break; + case EINVAL: /* filesystem doesn't support locking, let the user have it */ + ret = 0; + break; + default: { + char buf[128]; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, + N_("Failed to unlock file: %s", ""), buf); + break; + } + } + return ret; +} + +static krb5_error_code +write_storage(krb5_context context, krb5_storage *sp, int fd) +{ + krb5_error_code ret; + krb5_data data; + ssize_t sret; + + ret = krb5_storage_to_data(sp, &data); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + return ret; + } + sret = write(fd, data.data, data.length); + ret = (sret != (ssize_t)data.length); + krb5_data_free(&data); + if (ret) { + ret = errno; + krb5_set_error_message(context, ret, + N_("Failed to write FILE credential data", "")); + return ret; + } + return 0; +} + + +static krb5_error_code KRB5_CALLCONV +fcc_lock(krb5_context context, krb5_ccache id, + int fd, krb5_boolean exclusive) +{ + krb5_error_code ret; + const char *name; + + if (exclusive == FALSE) + return 0; + ret = fcc_get_name_2(context, id, &name, NULL, NULL); + if (ret == 0) + ret = _krb5_xlock(context, fd, exclusive, name); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_get_default_name(krb5_context, char **); + +/* + * This is the character used to separate the residual from the subsidiary name + * when both are given. It's tempting to use ':' just as we do in the ccache + * names, but we can't on Windows. + */ +#define FILESUBSEP "+" +#define FILESUBSEPCHR ((FILESUBSEP)[0]) + +static krb5_error_code KRB5_CALLCONV +fcc_resolve_2(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) +{ + krb5_fcache *f; + char *freeme = NULL; + + if (res == NULL && sub == NULL) + return krb5_einval(context, 3); + if (res == NULL) { + krb5_error_code ret; + + if ((ret = fcc_get_default_name(context, &freeme))) + return ret; + res = freeme + sizeof("FILE:") - 1; + } else if (!sub && (sub = strchr(res, FILESUBSEPCHR))) { + if (sub[1] == '\0') { + sub = NULL; + } else { + /* `res' has a subsidiary component, so split on it */ + if ((freeme = strndup(res, sub - res)) == NULL) + return krb5_enomem(context); + res = freeme; + sub++; + } + } + + if ((f = calloc(1, sizeof(*f))) == NULL || + (f->res = strdup(res)) == NULL || + (f->sub = sub ? strdup(sub) : NULL) == (sub ? NULL : "") || + asprintf(&f->filename, "%s%s%s", + res, sub ? FILESUBSEP : "", sub ? sub : "") == -1 || + f->filename == NULL) { + if (f) { + free(f->filename); + free(f->res); + free(f->sub); + } + free(f); + free(freeme); + return krb5_enomem(context); + } + f->tmpfn = NULL; + f->version = 0; + (*id)->data.data = f; + (*id)->data.length = sizeof(*f); + + free(freeme); + return 0; +} + +/* + * Try to scrub the contents of `filename' safely. + */ + +static int +scrub_file (int fd) +{ + off_t pos; + char buf[128]; + + pos = lseek(fd, 0, SEEK_END); + if (pos < 0) + return errno; + if (lseek(fd, 0, SEEK_SET) < 0) + return errno; + memset(buf, 0, sizeof(buf)); + while(pos > 0) { + ssize_t tmp; + size_t wr = sizeof(buf); + if (wr > pos) + wr = (size_t)pos; + tmp = write(fd, buf, wr); + + if (tmp < 0) + return errno; + pos -= tmp; + } +#ifdef _MSC_VER + _commit (fd); +#else + fsync (fd); +#endif + return 0; +} + +/* + * Erase `filename' if it exists, trying to remove the contents if + * it's `safe'. We always try to remove the file, it it exists. It's + * only overwritten if it's a regular file (not a symlink and not a + * hardlink) + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_erase_file(krb5_context context, const char *filename) +{ + int fd; + struct stat sb1, sb2; + int ret; + + ret = lstat (filename, &sb1); + if (ret < 0) { + if(errno == ENOENT) + return 0; + else + return errno; + } + + fd = open(filename, O_RDWR | O_BINARY | O_CLOEXEC | O_NOFOLLOW); + if(fd < 0) { + if(errno == ENOENT) + return 0; + else + return errno; + } + rk_cloexec(fd); + ret = _krb5_xlock(context, fd, 1, filename); + if (ret) { + close(fd); + return ret; + } + if (unlink(filename) < 0) { + ret = errno; + close (fd); + krb5_set_error_message(context, errno, + N_("krb5_cc_destroy: unlinking \"%s\": %s", ""), + filename, strerror(ret)); + return ret; + } + ret = fstat(fd, &sb2); + if (ret < 0) { + ret = errno; + close (fd); + return ret; + } + + /* check if someone was playing with symlinks */ + + if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) { + close(fd); + return EPERM; + } + + /* there are still hard links to this file */ + + if (sb2.st_nlink != 0) { + close(fd); + return 0; + } + + ret = scrub_file(fd); + close(fd); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_gen_new(krb5_context context, krb5_ccache *id) +{ + char *file = NULL, *exp_file = NULL; + krb5_error_code ret; + krb5_fcache *f; + int fd; + + f = calloc(1, sizeof(*f)); + if(f == NULL) { + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); + return KRB5_CC_NOMEM; + } + f->tmpfn = NULL; + /* + * XXX We should asprintf(&file, "%s:XXXXXX", KRB5_DEFAULT_CCNAME_FILE) + * instead so that new unique FILE ccaches can be found in the user's + * default collection. + * */ + ret = asprintf(&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT); + if(ret < 0 || file == NULL) { + free(f); + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); + return KRB5_CC_NOMEM; + } + ret = _krb5_expand_path_tokens(context, file, 1, &exp_file); + free(file); + if (ret) { + free(f); + return ret; + } + + file = exp_file; + + fd = mkostemp(exp_file, O_CLOEXEC); + if(fd < 0) { + ret = (krb5_error_code)errno; + krb5_set_error_message(context, ret, N_("mkstemp %s failed", ""), exp_file); + free(f); + free(exp_file); + return ret; + } + close(fd); + f->filename = exp_file; + f->res = strdup(exp_file); /* XXX See above commentary about collection */ + f->sub = NULL; + f->version = 0; + (*id)->data.data = f; + (*id)->data.length = sizeof(*f); + return 0; +} + +static void +storage_set_flags(krb5_context context, krb5_storage *sp, int vno) +{ + int flags = 0; + switch(vno) { + case KRB5_FCC_FVNO_1: + flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; + flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; + flags |= KRB5_STORAGE_HOST_BYTEORDER; + break; + case KRB5_FCC_FVNO_2: + flags |= KRB5_STORAGE_HOST_BYTEORDER; + break; + case KRB5_FCC_FVNO_3: + flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE; + break; + case KRB5_FCC_FVNO_4: + break; + default: + krb5_abortx(context, + "storage_set_flags called with bad vno (%x)", vno); + } + krb5_storage_set_flags(sp, flags); +} + +static krb5_error_code KRB5_CALLCONV +fcc_open(krb5_context context, + krb5_ccache id, + const char *operation, + int *fd_ret, + int flags, + mode_t mode) +{ + krb5_boolean exclusive = ((flags | O_WRONLY) == flags || + (flags | O_RDWR) == flags); + krb5_error_code ret; + const char *filename; + struct stat sb1, sb2; +#ifndef _WIN32 + struct stat sb3; + size_t tries = 3; +#endif + int strict_checking; + int fd; + + flags |= O_BINARY | O_CLOEXEC | O_NOFOLLOW; + + *fd_ret = -1; + + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + if ((flags & O_EXCL)) { + /* + * FIXME Instead of mkostemp()... we could instead try to use a .new + * file... with care. Or the O_TMPFILE / linkat() extensions. We need + * a roken / heimbase abstraction for that. + */ + if (TMPFILENAME(id)) + (void) unlink(TMPFILENAME(id)); + free(TMPFILENAME(id)); + TMPFILENAME(id) = NULL; + if (asprintf(&TMPFILENAME(id), "%s-XXXXXX", FILENAME(id)) < 0 || + TMPFILENAME(id) == NULL) + return krb5_enomem(context); + if ((fd = mkostemp(TMPFILENAME(id), O_CLOEXEC)) == -1) { + krb5_set_error_message(context, ret = errno, + N_("Could not make temp ccache FILE:%s", ""), + TMPFILENAME(id)); + free(TMPFILENAME(id)); + TMPFILENAME(id) = NULL; + return ret; + } + goto out; + } + + filename = TMPFILENAME(id) ? TMPFILENAME(id) : FILENAME(id); + strict_checking = (flags & O_CREAT) == 0 && + (context->flags & KRB5_CTX_F_FCACHE_STRICT_CHECKING) != 0; + +#ifndef WIN32 +again: +#endif + memset(&sb1, 0, sizeof(sb1)); + ret = lstat(filename, &sb1); + if (ret == 0) { + if (!S_ISREG(sb1.st_mode)) { + krb5_set_error_message(context, EPERM, + N_("Refuses to open symlinks for caches FILE:%s", ""), filename); + return EPERM; + } + } else if (errno != ENOENT || !(flags & O_CREAT)) { + krb5_set_error_message(context, errno, N_("%s lstat(%s)", "file, error"), + operation, filename); + return errno; + } + + fd = open(filename, flags, mode); + if(fd < 0) { + char buf[128]; + ret = errno; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, N_("%s open(%s): %s", "file, error"), + operation, filename, buf); + return ret; + } + rk_cloexec(fd); + + ret = fstat(fd, &sb2); + if (ret < 0) { + krb5_clear_error_message(context); + close(fd); + return errno; + } + + if (!S_ISREG(sb2.st_mode)) { + krb5_set_error_message(context, EPERM, N_("Refuses to open non files caches: FILE:%s", ""), filename); + close(fd); + return EPERM; + } + +#ifndef _WIN32 + if (sb1.st_dev && sb1.st_ino && + (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino)) { + /* + * Perhaps we raced with a rename(). To complain about + * symlinks in that case would cause unnecessary concern, so + * we check for that possibility and loop. This has no + * TOCTOU problems because we redo the open(). We could also + * not do any of this checking if O_NOFOLLOW != 0... + */ + close(fd); + ret = lstat(filename, &sb3); + if (ret || sb1.st_dev != sb2.st_dev || + sb3.st_dev != sb2.st_dev || sb3.st_ino != sb2.st_ino) { + krb5_set_error_message(context, EPERM, N_("Refuses to open possible symlink for caches: FILE:%s", ""), filename); + return EPERM; + } + if (--tries == 0) { + krb5_set_error_message(context, EPERM, N_("Raced too many times with renames of FILE:%s", ""), filename); + return EPERM; + } + goto again; + } +#endif + + /* + * /tmp (or wherever default ccaches go) might not be on its own + * filesystem, or on a filesystem different /etc, say, and even if + * it were, suppose a user hard-links another's ccache to her + * default ccache, then runs a set-uid program that will user her + * default ccache (even if it ignores KRB5CCNAME)... + * + * Default ccache locations should really be on per-user non-tmp + * locations on tmpfs "run" directories. But we don't know here + * that this is the case. Thus: no hard-links, no symlinks. + */ + if (sb2.st_nlink > 1) { + krb5_set_error_message(context, EPERM, N_("Refuses to open hardlinks for caches FILE:%s", ""), filename); + close(fd); + return EPERM; + } + + if (strict_checking) { +#ifndef _WIN32 + /* + * XXX WIN32: Needs to have ACL checking code! + * st_mode comes out as 100666, and st_uid is no use. + */ + /* + * XXX Should probably add options to improve control over this + * check. We might want strict checking of everything except + * this. + */ + if (sb2.st_uid != geteuid()) { + krb5_set_error_message(context, EPERM, N_("Refuses to open cache files not own by myself FILE:%s (owned by %d)", ""), filename, (int)sb2.st_uid); + close(fd); + return EPERM; + } + if ((sb2.st_mode & 077) != 0) { + krb5_set_error_message(context, EPERM, + N_("Refuses to open group/other readable files FILE:%s", ""), filename); + close(fd); + return EPERM; + } +#endif + } + +out: + if((ret = fcc_lock(context, id, fd, exclusive)) != 0) { + close(fd); + return ret; + } + *fd_ret = fd; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_fcache *f = FCACHE(id); + int ret = 0; + int fd; + + if (f == NULL) + return krb5_einval(context, 2); + + /* + * fcc_open() will notice the O_EXCL and will make a temporary file that + * will later be renamed into place. + */ + ret = fcc_open(context, id, "initialize", &fd, O_RDWR | O_CREAT | O_EXCL, 0600); + if(ret) + return ret; + { + krb5_storage *sp; + sp = krb5_storage_emem(); + if (sp == NULL) + return krb5_enomem(context); + krb5_storage_set_eof_code(sp, KRB5_CC_END); + if(context->fcache_vno != 0) + f->version = context->fcache_vno; + else + f->version = KRB5_FCC_FVNO_4; + if (ret == 0) + ret = krb5_store_int8(sp, 5); + if (ret == 0) + ret = krb5_store_int8(sp, f->version); + storage_set_flags(context, sp, f->version); + if(f->version == KRB5_FCC_FVNO_4 && ret == 0) { + /* V4 stuff */ + if (context->kdc_sec_offset) { + if (ret == 0) + ret = krb5_store_int16 (sp, 12); /* length */ + if (ret == 0) + ret = krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */ + if (ret == 0) + ret = krb5_store_int16 (sp, 8); /* length of data */ + if (ret == 0) + ret = krb5_store_int32 (sp, context->kdc_sec_offset); + if (ret == 0) + ret = krb5_store_int32 (sp, context->kdc_usec_offset); + } else { + if (ret == 0) + ret = krb5_store_int16 (sp, 0); + } + } + if (ret == 0) + ret = krb5_store_principal(sp, primary_principal); + + if (ret == 0) + ret = write_storage(context, sp, fd); + + krb5_storage_free(sp); + } + if (close(fd) < 0) + if (ret == 0) { + char buf[128]; + ret = errno; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, N_("close %s: %s", ""), + FILENAME(id), buf); + } + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_close(krb5_context context, + krb5_ccache id) +{ + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + if (TMPFILENAME(id)) + (void) unlink(TMPFILENAME(id)); + free(TMPFILENAME(id)); + free(RESFILENAME(id)); + free(SUBFILENAME(id)); + free(FILENAME(id)); + krb5_data_free(&id->data); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_destroy(krb5_context context, + krb5_ccache id) +{ + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + if (TMPFILENAME(id)) + (void) _krb5_erase_file(context, TMPFILENAME(id)); + return _krb5_erase_file(context, FILENAME(id)); +} + +static krb5_error_code KRB5_CALLCONV +fcc_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + int ret; + int fd; + + ret = fcc_open(context, id, "store", &fd, O_WRONLY | O_APPEND, 0); + if(ret) + return ret; + { + krb5_storage *sp; + + sp = krb5_storage_emem(); + if (sp == NULL) + return krb5_enomem(context); + krb5_storage_set_eof_code(sp, KRB5_CC_END); + storage_set_flags(context, sp, FCACHE(id)->version); + ret = krb5_store_creds(sp, creds); + if (ret == 0) + ret = write_storage(context, sp, fd); + krb5_storage_free(sp); + } + if (close(fd) < 0) { + if (ret == 0) { + char buf[128]; + ret = errno; + rk_strerror_r(ret, buf, sizeof(buf)); + krb5_set_error_message(context, ret, N_("close %s: %s", ""), + FILENAME(id), buf); + } + } + if (ret == 0 && TMPFILENAME(id) && + !krb5_is_config_principal(context, creds->server)) { + + /* + * Portability note: there's no need to have WIN32 or other code here + * for odd rename cases because rk_rename() is meant to handle that. + */ + ret = rk_rename(TMPFILENAME(id), FILENAME(id)); + if (ret == 0) { + free(TMPFILENAME(id)); + TMPFILENAME(id) = NULL; + } else { + ret = errno; + } + } + return ret; +} + +static krb5_error_code +init_fcc(krb5_context context, + krb5_ccache id, + const char *operation, + krb5_storage **ret_sp, + int *ret_fd, + krb5_deltat *kdc_offset) +{ + int fd; + int8_t pvno, tag; + krb5_storage *sp; + krb5_error_code ret; + + *ret_fd = -1; + *ret_sp = NULL; + if (kdc_offset) + *kdc_offset = 0; + + ret = fcc_open(context, id, operation, &fd, O_RDONLY, 0); + if(ret) + return ret; + + sp = krb5_storage_stdio_from_fd(fd, "r"); + if(sp == NULL) { + krb5_clear_error_message(context); + ret = ENOMEM; + goto out; + } + krb5_storage_set_eof_code(sp, KRB5_CC_END); + ret = krb5_ret_int8(sp, &pvno); + if (ret != 0) { + if(ret == KRB5_CC_END) { + ret = ENOENT; + krb5_set_error_message(context, ret, + N_("Empty credential cache file: %s", ""), + FILENAME(id)); + } else + krb5_set_error_message(context, ret, N_("Error reading pvno " + "in cache file: %s", ""), + FILENAME(id)); + goto out; + } + if (pvno != 5) { + ret = KRB5_CCACHE_BADVNO; + krb5_set_error_message(context, ret, N_("Bad version number in credential " + "cache file: %s", ""), + FILENAME(id)); + goto out; + } + ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */ + if (ret != 0) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, "Error reading tag in " + "cache file: %s", FILENAME(id)); + goto out; + } + FCACHE(id)->version = tag; + storage_set_flags(context, sp, FCACHE(id)->version); + switch (tag) { + case KRB5_FCC_FVNO_4: { + int16_t length; + + ret = krb5_ret_int16 (sp, &length); + if(ret) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, + N_("Error reading tag length in " + "cache file: %s", ""), FILENAME(id)); + goto out; + } + while(length > 0) { + int16_t dtag, data_len; + int i; + int8_t dummy; + + ret = krb5_ret_int16 (sp, &dtag); + if(ret) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, N_("Error reading dtag in " + "cache file: %s", ""), + FILENAME(id)); + goto out; + } + ret = krb5_ret_int16 (sp, &data_len); + if(ret) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, + N_("Error reading dlength " + "in cache file: %s",""), + FILENAME(id)); + goto out; + } + switch (dtag) { + case FCC_TAG_DELTATIME : { + int32_t offset; + + ret = krb5_ret_int32 (sp, &offset); + ret |= krb5_ret_int32 (sp, &context->kdc_usec_offset); + if(ret) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, + N_("Error reading kdc_sec in " + "cache file: %s", ""), + FILENAME(id)); + goto out; + } + context->kdc_sec_offset = offset; + if (kdc_offset) + *kdc_offset = offset; + break; + } + default : + for (i = 0; i < data_len; ++i) { + ret = krb5_ret_int8 (sp, &dummy); + if(ret) { + ret = KRB5_CC_FORMAT; + krb5_set_error_message(context, ret, + N_("Error reading unknown " + "tag in cache file: %s", ""), + FILENAME(id)); + goto out; + } + } + break; + } + length -= 4 + data_len; + } + break; + } + case KRB5_FCC_FVNO_3: + case KRB5_FCC_FVNO_2: + case KRB5_FCC_FVNO_1: + break; + default : + ret = KRB5_CCACHE_BADVNO; + krb5_set_error_message(context, ret, + N_("Unknown version number (%d) in " + "credential cache file: %s", ""), + (int)tag, FILENAME(id)); + goto out; + } + *ret_sp = sp; + *ret_fd = fd; + + return 0; + out: + if(sp != NULL) + krb5_storage_free(sp); + close(fd); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + krb5_error_code ret; + int fd; + krb5_storage *sp; + + ret = init_fcc (context, id, "get-principal", &sp, &fd, NULL); + if (ret) + return ret; + ret = krb5_ret_principal(sp, principal); + if (ret) + krb5_clear_error_message(context); + krb5_storage_free(sp); + close(fd); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_end_get(krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor); + +static krb5_error_code KRB5_CALLCONV +fcc_get_first(krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_error_code ret; + krb5_principal principal; + + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + *cursor = calloc(1, sizeof(struct fcc_cursor)); + if (*cursor == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + + ret = init_fcc(context, id, "get-first", &FCC_CURSOR(*cursor)->sp, + &FCC_CURSOR(*cursor)->fd, NULL); + if (ret) { + free(*cursor); + *cursor = NULL; + return ret; + } + ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal); + if(ret) { + krb5_clear_error_message(context); + fcc_end_get(context, id, cursor); + return ret; + } + krb5_free_principal (context, principal); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_get_next (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + krb5_error_code ret; + + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + if (FCC_CURSOR(*cursor) == NULL) + return krb5_einval(context, 3); + + FCC_CURSOR(*cursor)->cred_start = + krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); + + ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds); + if (ret) + krb5_clear_error_message(context); + + FCC_CURSOR(*cursor)->cred_end = + krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); + + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_end_get (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + if (FCC_CURSOR(*cursor) == NULL) + return krb5_einval(context, 3); + + krb5_storage_free(FCC_CURSOR(*cursor)->sp); + close (FCC_CURSOR(*cursor)->fd); + free(*cursor); + *cursor = NULL; + return 0; +} + +static void KRB5_CALLCONV +cred_delete(krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *cred) +{ + krb5_error_code ret; + krb5_storage *sp; + krb5_data orig_cred_data; + unsigned char *cred_data_in_file = NULL; + off_t new_cred_sz; + struct stat sb1, sb2; + int fd = -1; + ssize_t bytes; + krb5_const_realm srealm = krb5_principal_get_realm(context, cred->server); + + /* This is best-effort code; if we lose track of errors here it's OK */ + + heim_assert(FCC_CURSOR(*cursor)->cred_start < FCC_CURSOR(*cursor)->cred_end, + "fcache internal error"); + + krb5_data_zero(&orig_cred_data); + + sp = krb5_storage_emem(); + if (sp == NULL) + return; + krb5_storage_set_eof_code(sp, KRB5_CC_END); + storage_set_flags(context, sp, FCACHE(id)->version); + + /* Get a copy of what the cred should look like in the file; see below */ + ret = krb5_store_creds(sp, cred); + if (ret) + goto out; + + ret = krb5_storage_to_data(sp, &orig_cred_data); + if (ret) + goto out; + krb5_storage_free(sp); + + cred_data_in_file = malloc(orig_cred_data.length); + if (cred_data_in_file == NULL) + goto out; + + /* + * Mark the cred expired; krb5_cc_retrieve_cred() callers should use + * KRB5_TC_MATCH_TIMES, so this should be good enough... + */ + cred->times.endtime = 0; + + /* ...except for config creds because we don't check their endtimes */ + if (srealm && strcmp(srealm, "X-CACHECONF:") == 0) { + ret = krb5_principal_set_realm(context, cred->server, "X-RMED-CONF:"); + if (ret) + goto out; + } + + sp = krb5_storage_emem(); + if (sp == NULL) + goto out; + krb5_storage_set_eof_code(sp, KRB5_CC_END); + storage_set_flags(context, sp, FCACHE(id)->version); + + ret = krb5_store_creds(sp, cred); + + /* The new cred must be the same size as the old cred */ + new_cred_sz = krb5_storage_seek(sp, 0, SEEK_END); + if (new_cred_sz != orig_cred_data.length || new_cred_sz != + (FCC_CURSOR(*cursor)->cred_end - FCC_CURSOR(*cursor)->cred_start)) { + /* XXX This really can't happen. Assert like above? */ + krb5_set_error_message(context, EINVAL, + N_("Credential deletion failed on ccache " + "FILE:%s: new credential size did not " + "match old credential size", ""), + FILENAME(id)); + goto out; + } + + ret = fcc_open(context, id, "remove_cred", &fd, O_RDWR, 0); + if (ret) + goto out; + + /* + * Check that we're updating the same file where we got the + * cred's offset, else we'd be corrupting a new ccache. + */ + if (fstat(FCC_CURSOR(*cursor)->fd, &sb1) == -1 || + fstat(fd, &sb2) == -1) + goto out; + if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) + goto out; + + /* + * Make sure what we overwrite is what we expected. + * + * FIXME: We *really* need the ccache v4 tag for ccache ID. This + * check that we're only overwriting something that looks exactly + * like what we want to is probably good enough in practice, but + * it's not guaranteed to work. + */ + if (lseek(fd, FCC_CURSOR(*cursor)->cred_start, SEEK_SET) == (off_t)-1) + goto out; + bytes = read(fd, cred_data_in_file, orig_cred_data.length); + if (bytes != orig_cred_data.length) + goto out; + if (memcmp(orig_cred_data.data, cred_data_in_file, bytes) != 0) + goto out; + if (lseek(fd, FCC_CURSOR(*cursor)->cred_start, SEEK_SET) == (off_t)-1) + goto out; + ret = write_storage(context, sp, fd); +out: + if (fd > -1) { + if (close(fd) < 0 && ret == 0) { + krb5_set_error_message(context, errno, N_("close %s", ""), + FILENAME(id)); + } + } + krb5_data_free(&orig_cred_data); + free(cred_data_in_file); + krb5_storage_free(sp); + return; +} + +static krb5_error_code KRB5_CALLCONV +fcc_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *mcred) +{ + krb5_error_code ret, ret2; + krb5_cc_cursor cursor; + krb5_creds found_cred; + + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + return ret; + while ((ret = krb5_cc_next_cred(context, id, &cursor, &found_cred)) == 0) { + if (!krb5_compare_creds(context, which, mcred, &found_cred)) { + krb5_free_cred_contents(context, &found_cred); + continue; + } + cred_delete(context, id, &cursor, &found_cred); + krb5_free_cred_contents(context, &found_cred); + } + ret2 = krb5_cc_end_seq_get(context, id, &cursor); + if (ret2) /* not expected to fail */ + return ret2; + if (ret == KRB5_CC_END) + return 0; + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + if (FCACHE(id) == NULL) + return krb5_einval(context, 2); + + return 0; /* XXX */ +} + +static int KRB5_CALLCONV +fcc_get_version(krb5_context context, + krb5_ccache id) +{ + if (FCACHE(id) == NULL) + return -1; + + return FCACHE(id)->version; +} + +static const char * +my_basename(const char *fn) +{ + const char *base, *p; + + if (strncmp(fn, "FILE:", sizeof("FILE:") - 1) == 0) + fn += sizeof("FILE:") - 1; + for (p = base = fn; *p; p++) { +#ifdef WIN32 + if (*p == '/' || *p == '\\') + base = p + 1; +#else + if (*p == '/') + base = p + 1; +#endif + } + return base; +} + +/* We could use an rk_dirname()... */ +static char * +my_dirname(const char *fn) +{ + size_t len, i; + char *dname; + + if (strncmp(fn, "FILE:", sizeof("FILE:") - 1) == 0) + fn += sizeof("FILE:") - 1; + + if ((dname = strdup(fn)) == NULL) + return NULL; + len = strlen(dname); + for (i = 0; i < len; i++) { +#ifdef WIN32 + if (dname[len - i] == '\\' || + dname[len - i] == '/') { + dname[len - i] = '\0'; + break; + } +#else + if (dname[len - i] == '/') { + dname[len - i] = '\0'; + break; + } +#endif + } + if (i < len) + return dname; + free(dname); + return strdup("."); +} + +/* + * This checks that a directory entry matches a required basename and has a + * non-empty subsidiary component. + */ +static int +matchbase(const char *fn, const char *base, size_t baselen) +{ + return strncmp(fn, base, baselen) == 0 && + (fn[baselen] == FILESUBSEPCHR && fn[baselen + 1] != '\0'); +} + +/* + * Check if `def_locs' contains `name' (which must be the default ccache name), + * in which case the caller may look for subsidiaries of all of `def_locs'. + * + * This is needed because the collection iterators don't take a base location + * as an argument, so we can only search default locations, but only if the + * current default ccache name is indeed a default (as opposed to from + * KRB5CCNAME being set in the environment pointing to a non-default name). + */ +static krb5_error_code +is_default_collection(krb5_context context, const char *name, + const char * const *def_locs, int *res) +{ + krb5_error_code ret; + const char *def_loc[2] = { KRB5_DEFAULT_CCNAME_FILE, NULL }; + const char *sep; + size_t namelen; + size_t i; + + *res = 0; + if (name == NULL) { + *res = 1; + return 0; + } + if ((sep = strchr(name, FILESUBSEPCHR))) + namelen = (size_t)(sep - name); + else + namelen = strlen(name); + if (def_locs == NULL) + def_locs = def_loc; + for (i = 0; !(*res) && def_locs[i]; i++) { + char *e = NULL; + + if ((ret = _krb5_expand_default_cc_name(context, def_locs[i], &e))) + return ret; + *res = strncmp(e, name, namelen) == 0 && + (sep == NULL || e[namelen] == FILESUBSEPCHR || e[namelen] == '\0'); + free(e); + } + return 0; +} + +/* + * Collection iterator cursor. + * + * There may be an array of locations, and for each location we'll try + * resolving it, as well as doing a readdir() of the dirname of it and output + * all ccache names in that directory that begin with the current location and + * end in "+${subsidiary}". + */ +struct fcache_iter { + const char *curr_location; + char *def_ccname; /* The default ccname */ + char **locations; /* All the other places we'll look for a ccache */ + char *dname; /* dirname() of curr_location */ + DIR *d; + struct dirent *dentry; + int location; /* Index of `locations' */ + unsigned int first:1; + unsigned int dead:1; +}; + +/* Initiate FILE collection iteration */ +static krb5_error_code KRB5_CALLCONV +fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct fcache_iter *iter = NULL; + krb5_error_code ret; + const char *def_ccname = NULL; + char **def_locs = NULL; + int is_def_coll = 0; + + if (krb5_config_get_bool_default(context, NULL, FALSE, "libdefaults", + "enable_file_cache_iteration", NULL)) { + def_ccname = krb5_cc_default_name(context); + def_locs = krb5_config_get_strings(context, NULL, "libdefaults", + "default_file_cache_collections", + NULL); + } + + /* + * Note: do not allow krb5_cc_default_name() to recurse via + * krb5_cc_cache_match(). + * Note that context->default_cc_name will be NULL even though + * KRB5CCNAME is set in the environment if neither krb5_cc_default_name() + * nor krb5_cc_set_default_name() have been called. + */ + + /* + * Figure out if the current default ccache name is a really a default one + * so we know whether to search any other default FILE collection + * locations. + */ + if ((ret = is_default_collection(context, def_ccname, + (const char **)def_locs, + &is_def_coll))) + goto out; + + /* Setup the cursor */ + if ((iter = calloc(1, sizeof(*iter))) == NULL || + (def_ccname && (iter->def_ccname = strdup(def_ccname)) == NULL)) { + ret = krb5_enomem(context); + goto out; + } + + if (is_def_coll) { + /* Since def_ccname is in the `def_locs', we'll include those */ + iter->locations = def_locs; + free(iter->def_ccname); + iter->def_ccname = NULL; + def_locs = NULL; + } else { + /* Since def_ccname is NOT in the `def_locs', we'll exclude those */ + iter->locations = NULL; + } + iter->curr_location = NULL; + iter->location = -1; /* Pre-incremented */ + iter->first = 1; + iter->dname = NULL; + iter->d = NULL; + *cursor = iter; + iter = NULL; + ret = 0; + +out: + krb5_config_free_strings(def_locs); + free(iter); + return ret; +} + +/* Pick the next location as the `iter->curr_location' */ +static krb5_error_code +next_location(krb5_context context, struct fcache_iter *iter) +{ + if (iter->first && iter->def_ccname) { + iter->curr_location = iter->def_ccname; + iter->first = 0; + return 0; + } + iter->first = 0; + + if (iter->d) + closedir(iter->d); + iter->d = NULL; + iter->curr_location = NULL; + if (iter->locations && + (iter->curr_location = iter->locations[++(iter->location)])) + return 0; + + iter->dead = 1; /* Do not run off the end of iter->locations */ + return KRB5_CC_END; +} + +/* Output the next match for `iter->curr_location' from readdir() */ +static krb5_error_code +next_dir_match(krb5_context context, struct fcache_iter *iter, char **fn) +{ + struct stat st; + const char *base = my_basename(iter->curr_location); + size_t baselen = strlen(base); + char *s; + + *fn = NULL; + if (iter->d == NULL) + return 0; + for (iter->dentry = readdir(iter->d); + iter->dentry; + iter->dentry = readdir(iter->d)) { + if (!matchbase(iter->dentry->d_name, base, baselen)) + continue; + if (asprintf(&s, "FILE:%s/%s", iter->dname, iter->dentry->d_name) == -1 || + s == NULL) + return krb5_enomem(context); + if (stat(s + sizeof("FILE:") - 1, &st) == 0 && S_ISREG(st.st_mode)) { + *fn = s; + return 0; + } + free(s); + } + iter->curr_location = NULL; + closedir(iter->d); + iter->d = NULL; + return 0; +} + +/* See if the given `ccname' is a FILE ccache we can resolve */ +static krb5_error_code +try1(krb5_context context, const char *ccname, krb5_ccache *id) +{ + krb5_error_code ret; + krb5_ccache cc; + + ret = krb5_cc_resolve(context, ccname, &cc); + if (ret == ENOMEM) + return ret; + if (ret == 0) { + if (strcmp(krb5_cc_get_type(context, cc), "FILE") == 0) { + *id = cc; + cc = NULL; + } + krb5_cc_close(context, cc); + } + return 0; +} + +/* Output the next FILE ccache in the FILE ccache collection */ +static krb5_error_code KRB5_CALLCONV +fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct fcache_iter *iter = cursor; + krb5_error_code ret; + char *name = NULL; + + *id = NULL; + if (iter == NULL) + return krb5_einval(context, 2); + + /* Do not run off the end of iter->locations */ + if (iter->dead) + return KRB5_CC_END; + + if (!iter->curr_location) { + /* Next base location */ + if ((ret = next_location(context, iter))) + return ret; + /* Output the current base location */ + if ((ret = try1(context, iter->curr_location, id)) || *id) + return ret; + } + + /* Look for subsidiaries of iter->curr_location */ + if (!iter->d) { + free(iter->dname); + if ((iter->dname = my_dirname(iter->curr_location)) == NULL) + return krb5_enomem(context); + if ((iter->d = opendir(iter->dname)) == NULL) { + /* Dirname ENOENT -> next location */ + if ((ret = next_location(context, iter))) + return ret; + /* Tail-recurse */ + return fcc_get_cache_next(context, cursor, id); + } + } + for (ret = next_dir_match(context, iter, &name); + ret == 0 && name != NULL; + ret = next_dir_match(context, iter, &name)) { + if ((ret = try1(context, name, id)) || *id) { + free(name); + return ret; + } + free(name); + } + + /* Directory listing exhausted -> go to next location, tail-recurse */ + if ((ret = next_location(context, iter))) + return ret; + return fcc_get_cache_next(context, cursor, id); +} + +static krb5_error_code KRB5_CALLCONV +fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct fcache_iter *iter = cursor; + + if (iter == NULL) + return krb5_einval(context, 2); + + krb5_config_free_strings(iter->locations); + if (iter->d) + closedir(iter->d); + free(iter->def_ccname); + free(iter->dname); + free(iter); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code ret = 0; + krb5_fcache *f = FCACHE(from); + krb5_fcache *t = FCACHE(to); + + if (f->tmpfn) { + /* + * If `from' has a temp file and we haven't renamed it into place yet, + * then we should rename TMPFILENAME(from) to FILENAME(to). + * + * This can only happen if we're moving a ccache where only cc config + * entries, or no entries, have been written. That's not likely. + */ + if (rk_rename(f->tmpfn, t->filename)) { + ret = errno; + } else { + free(f->tmpfn); + f->tmpfn = NULL; + } + } else if (rk_rename(f->filename, t->filename)) { + ret = errno; + } + /* + * We need only close from -- we can't destroy it since the rename + * succeeded, which "destroyed" it at its old name. + */ + if (ret == 0) + krb5_cc_close(context, from); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_get_default_name(krb5_context context, char **str) +{ + return _krb5_expand_default_cc_name(context, + KRB5_DEFAULT_CCNAME_FILE, + str); +} + +static krb5_error_code KRB5_CALLCONV +fcc_set_default_cache(krb5_context context, krb5_ccache id) +{ + krb5_error_code ret; + krb5_ccache dest; + char *s = NULL; + + if (SUBFILENAME(id) == NULL) + return 0; /* Already a primary */ + if (asprintf(&s, "FILE:%s", RESFILENAME(id)) == -1 || s == NULL) + return krb5_enomem(context); + + /* + * We can't hard-link, since we refuse to open ccaches with st_nlink > 1, + * and we can't rename() the ccache because the old name should remain + * available. Ergo, we copy the ccache. + */ + ret = krb5_cc_resolve(context, s, &dest); + if (ret == 0) + ret = krb5_cc_copy_cache(context, id, dest); + free(s); + if (ret) + krb5_set_error_message(context, ret, + N_("Failed to copy subsidiary cache file %s to " + "default %s", ""), FILENAME(id), + RESFILENAME(id)); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + krb5_error_code ret; + struct stat sb; + int fd; + + ret = fcc_open(context, id, "lastchange", &fd, O_RDONLY, 0); + if(ret) + return ret; + ret = fstat(fd, &sb); + close(fd); + if (ret) { + ret = errno; + krb5_set_error_message(context, ret, N_("Failed to stat cache file", "")); + return ret; + } + *mtime = sb.st_mtime; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset) +{ + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset) +{ + krb5_error_code ret; + krb5_storage *sp = NULL; + int fd; + ret = init_fcc(context, id, "get-kdc-offset", &sp, &fd, kdc_offset); + if (sp) + krb5_storage_free(sp); + close(fd); + + return ret; +} + + +/** + * Variable containing the FILE based credential cache implemention. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = { + KRB5_CC_OPS_VERSION_5, + "FILE", + NULL, + NULL, + fcc_gen_new, + fcc_initialize, + fcc_destroy, + fcc_close, + fcc_store_cred, + NULL, /* fcc_retrieve */ + fcc_get_principal, + fcc_get_first, + fcc_get_next, + fcc_end_get, + fcc_remove_cred, + fcc_set_flags, + fcc_get_version, + fcc_get_cache_first, + fcc_get_cache_next, + fcc_end_cache_get, + fcc_move, + fcc_get_default_name, + fcc_set_default_cache, + fcc_lastchange, + fcc_set_kdc_offset, + fcc_get_kdc_offset, + fcc_get_name_2, + fcc_resolve_2 +}; diff --git a/third_party/heimdal/lib/krb5/free.c b/third_party/heimdal/lib/krb5/free.c new file mode 100644 index 0000000..5bb33b4 --- /dev/null +++ b/third_party/heimdal/lib/krb5/free.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1997 - 1999, 2004 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep) +{ + free_KDC_REP(&rep->kdc_rep); + free_EncTGSRepPart(&rep->enc_part); + free_KRB_ERROR(&rep->error); + memset(rep, 0, sizeof(*rep)); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_xfree (void *ptr) +{ + free (ptr); + return 0; +} diff --git a/third_party/heimdal/lib/krb5/free_host_realm.c b/third_party/heimdal/lib/krb5/free_host_realm.c new file mode 100644 index 0000000..0932674 --- /dev/null +++ b/third_party/heimdal/lib/krb5/free_host_realm.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1997, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Free all memory allocated by `realmlist' + * + * @param context A Kerberos 5 context. + * @param realmlist realmlist to free, NULL is ok + * + * @return a Kerberos error code, always 0. + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_free_host_realm(krb5_context context, + krb5_realm *realmlist) +{ + krb5_realm *p; + + if(realmlist == NULL) + return 0; + for (p = realmlist; *p; ++p) + free (*p); + free (realmlist); + return 0; +} diff --git a/third_party/heimdal/lib/krb5/generate_seq_number.c b/third_party/heimdal/lib/krb5/generate_seq_number.c new file mode 100644 index 0000000..6001d69 --- /dev/null +++ b/third_party/heimdal/lib/krb5/generate_seq_number.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_generate_seq_number(krb5_context context, + const krb5_keyblock *key, + uint32_t *seqno) +{ + if (RAND_bytes((void *)seqno, sizeof(*seqno)) <= 0) + krb5_abortx(context, "Failed to generate random block"); + /* MIT used signed numbers, lets not stomp into that space directly */ + *seqno &= 0x3fffffff; + if (*seqno == 0) + *seqno = 1; + return 0; +} diff --git a/third_party/heimdal/lib/krb5/generate_subkey.c b/third_party/heimdal/lib/krb5/generate_subkey.c new file mode 100644 index 0000000..767d94c --- /dev/null +++ b/third_party/heimdal/lib/krb5/generate_subkey.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Generate subkey, from keyblock + * + * @param context kerberos context + * @param key session key + * @param etype encryption type of subkey, if ETYPE_NULL, use key's enctype + * @param subkey returned new, free with krb5_free_keyblock(). + * + * @return 0 on success or a Kerberos 5 error code + * +* @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_generate_subkey_extended(krb5_context context, + const krb5_keyblock *key, + krb5_enctype etype, + krb5_keyblock **subkey) +{ + krb5_error_code ret; + + ALLOC(*subkey, 1); + if (*subkey == NULL) + return krb5_enomem(context); + + if (etype == ETYPE_NULL) + etype = key->keytype; /* use session key etype */ + + /* XXX should we use the session key as input to the RF? */ + ret = krb5_generate_random_keyblock(context, etype, *subkey); + if (ret != 0) { + free(*subkey); + *subkey = NULL; + } + + return ret; +} + diff --git a/third_party/heimdal/lib/krb5/get_addrs.c b/third_party/heimdal/lib/krb5/get_addrs.c new file mode 100644 index 0000000..8246504 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_addrs.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifdef __osf__ +/* hate */ +struct rtentry; +struct mbuf; +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include + +static krb5_error_code +gethostname_fallback (krb5_context context, krb5_addresses *res) +{ + krb5_error_code ret; + char hostname[MAXHOSTNAMELEN]; + struct hostent *hostent; + + if (gethostname (hostname, sizeof(hostname))) { + ret = errno; + krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret)); + return ret; + } + hostent = roken_gethostbyname (hostname); + if (hostent == NULL) { + ret = errno; + krb5_set_error_message (context, ret, "gethostbyname %s: %s", + hostname, strerror(ret)); + return ret; + } + res->len = 1; + res->val = malloc (sizeof(*res->val)); + if (res->val == NULL) + return krb5_enomem(context); + res->val[0].addr_type = hostent->h_addrtype; + res->val[0].address.data = NULL; + res->val[0].address.length = 0; + ret = krb5_data_copy (&res->val[0].address, + hostent->h_addr, + hostent->h_length); + if (ret) { + free (res->val); + return ret; + } + return 0; +} + +enum { + LOOP = 1, /* do include loopback addrs */ + LOOP_IF_NONE = 2, /* include loopback addrs if no others */ + EXTRA_ADDRESSES = 4, /* include extra addresses */ + SCAN_INTERFACES = 8 /* scan interfaces for addresses */ +}; + +/* + * Try to figure out the addresses of all configured interfaces with a + * lot of magic ioctls. + */ + +static krb5_error_code +find_all_addresses (krb5_context context, krb5_addresses *res, int flags) +{ + struct sockaddr sa_zero; + struct ifaddrs *ifa0, *ifa; + krb5_error_code ret = ENXIO; + unsigned int num, idx; + krb5_addresses ignore_addresses; + + if (getifaddrs(&ifa0) == -1) { + ret = errno; + krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret)); + return (ret); + } + + memset(&sa_zero, 0, sizeof(sa_zero)); + + /* First, count all the ifaddrs. */ + for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++) + /* nothing */; + + if (num == 0) { + freeifaddrs(ifa0); + krb5_set_error_message(context, ENXIO, N_("no addresses found", "")); + return (ENXIO); + } + + if (flags & EXTRA_ADDRESSES) { + /* we'll remove the addresses we don't care about */ + ret = krb5_get_ignore_addresses(context, &ignore_addresses); + if(ret) + return ret; + } + + /* Allocate storage for them. */ + res->val = calloc(num, sizeof(*res->val)); + if (res->val == NULL) { + if (flags & EXTRA_ADDRESSES) + krb5_free_addresses(context, &ignore_addresses); + freeifaddrs(ifa0); + return krb5_enomem(context); + } + + /* Now traverse the list. */ + for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + if (ifa->ifa_addr == NULL) + continue; + if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) + continue; + if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) + continue; + if (krb5_sockaddr_is_loopback(ifa->ifa_addr) && (flags & LOOP) == 0) + /* We'll deal with the LOOP_IF_NONE case later. */ + continue; + + ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]); + if (ret) { + /* + * The most likely error here is going to be "Program + * lacks support for address type". This is no big + * deal -- just continue, and we'll listen on the + * addresses who's type we *do* support. + */ + continue; + } + /* possibly skip this address? */ + if((flags & EXTRA_ADDRESSES) && + krb5_address_search(context, &res->val[idx], &ignore_addresses)) { + krb5_free_address(context, &res->val[idx]); + flags &= ~LOOP_IF_NONE; /* we actually found an address, + so don't add any loop-back + addresses */ + continue; + } + + idx++; + } + + /* + * If no addresses were found, and LOOP_IF_NONE is set, then find + * the loopback addresses and add them to our list. + */ + if ((flags & LOOP_IF_NONE) != 0 && idx == 0) { + for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + if (ifa->ifa_addr == NULL) + continue; + if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) + continue; + if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) + continue; + if (!krb5_sockaddr_is_loopback(ifa->ifa_addr)) + continue; + if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) + /* Presumably loopback addrs are only used on loopback ifs! */ + continue; + ret = krb5_sockaddr2address(context, + ifa->ifa_addr, &res->val[idx]); + if (ret) + continue; /* We don't consider this failure fatal */ + if((flags & EXTRA_ADDRESSES) && + krb5_address_search(context, &res->val[idx], + &ignore_addresses)) { + krb5_free_address(context, &res->val[idx]); + continue; + } + idx++; + } + } + + if (flags & EXTRA_ADDRESSES) + krb5_free_addresses(context, &ignore_addresses); + freeifaddrs(ifa0); + if (ret) { + free(res->val); + res->val = NULL; + } else + res->len = idx; /* Now a count. */ + return (ret); +} + +static krb5_error_code +get_addrs_int (krb5_context context, krb5_addresses *res, int flags) +{ + krb5_error_code ret = -1; + + res->len = 0; + res->val = NULL; + + if (flags & SCAN_INTERFACES) { + ret = find_all_addresses (context, res, flags); + if(ret || res->len == 0) + ret = gethostname_fallback (context, res); + } else { + ret = 0; + } + + if(ret == 0 && (flags & EXTRA_ADDRESSES)) { + krb5_addresses a; + /* append user specified addresses */ + ret = krb5_get_extra_addresses(context, &a); + if(ret) { + krb5_free_addresses(context, res); + return ret; + } + ret = krb5_append_addresses(context, res, &a); + if(ret) { + krb5_free_addresses(context, res); + return ret; + } + krb5_free_addresses(context, &a); + } + if(res->len == 0) { + free(res->val); + res->val = NULL; + } + return ret; +} + +/* + * Try to get all addresses, but return the one corresponding to + * `hostname' if we fail. + * + * Only include loopback address if there are no other. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res) +{ + int flags = LOOP_IF_NONE | EXTRA_ADDRESSES; + + if (context->scan_interfaces) + flags |= SCAN_INTERFACES; + + return get_addrs_int (context, res, flags); +} + +/* + * Try to get all local addresses that a server should listen to. + * If that fails, we return the address corresponding to `hostname'. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res) +{ + return get_addrs_int (context, res, LOOP | SCAN_INTERFACES); +} diff --git a/third_party/heimdal/lib/krb5/get_cred.c b/third_party/heimdal/lib/krb5/get_cred.c new file mode 100644 index 0000000..ff06325 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_cred.c @@ -0,0 +1,2044 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include + +static krb5_error_code +get_cred_kdc_capath(krb5_context, krb5_kdc_flags, + krb5_ccache, struct krb5_fast_state *, + krb5_creds *, krb5_principal, + Ticket *, const char *, const char *, + krb5_creds **, krb5_creds ***); + +/* + * Take the `body' and encode it into `padata' using the credentials + * in `creds'. + */ + +static krb5_error_code +make_pa_tgs_req(krb5_context context, + krb5_auth_context *ac, + KDC_REQ_BODY *body, + krb5_ccache ccache, + krb5_creds *creds, + krb5_data *tgs_req) +{ + krb5_error_code ret; + krb5_data in_data; + size_t buf_size; + size_t len = 0; + uint8_t *buf; + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); + if (ret) + return ret; + + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + in_data.length = len; + in_data.data = buf; + ret = _krb5_mk_req_internal(context, ac, 0, &in_data, + creds, tgs_req, + KRB5_KU_TGS_REQ_AUTH_CKSUM, + KRB5_KU_TGS_REQ_AUTH); + free (buf); + return ret; +} + +/* + * Set the `enc-authorization-data' in `req_body' based on `authdata' + */ + +static krb5_error_code +set_auth_data (krb5_context context, + KDC_REQ_BODY *req_body, + krb5_authdata *authdata, + krb5_keyblock *subkey) +{ + if(authdata->len) { + size_t len = 0, buf_size; + unsigned char *buf; + krb5_crypto crypto; + krb5_error_code ret; + + ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, + &len, ret); + if (ret) + return ret; + if (buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ALLOC(req_body->enc_authorization_data, 1); + if (req_body->enc_authorization_data == NULL) { + free (buf); + return krb5_enomem(context); + } + ret = krb5_crypto_init(context, subkey, 0, &crypto); + if (ret) { + free (buf); + free (req_body->enc_authorization_data); + req_body->enc_authorization_data = NULL; + return ret; + } + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, + buf, + len, + 0, + req_body->enc_authorization_data); + free (buf); + krb5_crypto_destroy(context, crypto); + return ret; + } else { + req_body->enc_authorization_data = NULL; + return 0; + } +} + +/* + * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' + * (if not-NULL), `in_creds', `krbtgt', and returning the generated + * subkey in `subkey'. + */ + +static krb5_error_code +init_tgs_req (krb5_context context, + krb5_ccache ccache, + struct krb5_fast_state *state, + krb5_addresses *addresses, + krb5_kdc_flags flags, + Ticket *second_ticket, + krb5_creds *in_creds, + krb5_creds *krbtgt, + unsigned nonce, + const METHOD_DATA *padata, + krb5_keyblock **subkey, + TGS_REQ *t) +{ + krb5_auth_context ac = NULL; + krb5_error_code ret = 0; + krb5_data tgs_req; + + krb5_data_zero(&tgs_req); + memset(t, 0, sizeof(*t)); + + t->pvno = 5; + t->msg_type = krb_tgs_req; + if (in_creds->session.keytype) { + ALLOC_SEQ(&t->req_body.etype, 1); + if(t->req_body.etype.val == NULL) { + ret = krb5_enomem(context); + goto fail; + } + t->req_body.etype.val[0] = in_creds->session.keytype; + } else { + ret = _krb5_init_etype(context, + KRB5_PDU_TGS_REQUEST, + &t->req_body.etype.len, + &t->req_body.etype.val, + NULL); + } + if (ret) + goto fail; + t->req_body.addresses = addresses; + t->req_body.kdc_options = flags.b; + t->req_body.kdc_options.forwardable = krbtgt->flags.b.forwardable; + t->req_body.kdc_options.renewable = krbtgt->flags.b.renewable; + t->req_body.kdc_options.proxiable = krbtgt->flags.b.proxiable; + ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); + if (ret) + goto fail; + ALLOC(t->req_body.sname, 1); + if (t->req_body.sname == NULL) { + ret = krb5_enomem(context); + goto fail; + } + + /* some versions of some code might require that the client be + present in TGS-REQs, but this is clearly against the spec */ + + ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); + if (ret) + goto fail; + + if (krbtgt->times.starttime) { + ALLOC(t->req_body.from, 1); + if(t->req_body.from == NULL){ + ret = krb5_enomem(context); + goto fail; + } + *t->req_body.from = in_creds->times.starttime; + } + + /* req_body.till should be NULL if there is no endtime specified, + but old MIT code (like DCE secd) doesn't like that */ + ALLOC(t->req_body.till, 1); + if(t->req_body.till == NULL){ + ret = krb5_enomem(context); + goto fail; + } + *t->req_body.till = in_creds->times.endtime; + + if (t->req_body.kdc_options.renewable && krbtgt->times.renew_till) { + ALLOC(t->req_body.rtime, 1); + if(t->req_body.rtime == NULL){ + ret = krb5_enomem(context); + goto fail; + } + *t->req_body.rtime = in_creds->times.renew_till; + } + + t->req_body.nonce = nonce; + if(second_ticket){ + ALLOC(t->req_body.additional_tickets, 1); + if (t->req_body.additional_tickets == NULL) { + ret = krb5_enomem(context); + goto fail; + } + ALLOC_SEQ(t->req_body.additional_tickets, 1); + if (t->req_body.additional_tickets->val == NULL) { + ret = krb5_enomem(context); + goto fail; + } + ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); + if (ret) + goto fail; + } + + ret = krb5_auth_con_init(context, &ac); + if(ret) + goto fail; + + ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); + if (ret) + goto fail; + + if (state) { + krb5_data empty; + + krb5_data_zero(&empty); + ret = krb5_auth_con_add_AuthorizationData(context, ac, + KRB5_AUTHDATA_FX_FAST_USED, + &empty); + if (ret) + goto fail; + } + + ret = set_auth_data(context, &t->req_body, + &in_creds->authdata, ac->local_subkey); + if (ret) + goto fail; + + ret = make_pa_tgs_req(context, + &ac, + &t->req_body, + ccache, + krbtgt, + &tgs_req); + if(ret) + goto fail; + + /* + * Add KRB5_PADATA_TGS_REQ first + * followed by all others. + */ + + if (t->padata == NULL) { + ALLOC(t->padata, 1); + if (t->padata == NULL) { + ret = krb5_enomem(context); + goto fail; + } + } + + ret = krb5_padata_add(context, t->padata, KRB5_PADATA_TGS_REQ, + tgs_req.data, tgs_req.length); + if (ret) + goto fail; + + krb5_data_zero(&tgs_req); + + { + size_t i; + for (i = 0; i < padata->len; i++) { + const PA_DATA *val1 = &padata->val[i]; + PA_DATA val2; + + ret = copy_PA_DATA(val1, &val2); + if (ret) { + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto fail; + } + + ret = krb5_padata_add(context, t->padata, + val2.padata_type, + val2.padata_value.data, + val2.padata_value.length); + if (ret) { + free_PA_DATA(&val2); + + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto fail; + } + } + } + + if (state) { + state->armor_ac = ac; + ret = _krb5_fast_create_armor(context, state, NULL); + state->armor_ac = NULL; + if (ret) + goto fail; + + ret = _krb5_fast_wrap_req(context, state, t); + if (ret) + goto fail; + + /* Its ok if there is no fast in the TGS-REP, older heimdal only support it in the AS code path */ + state->flags &= ~KRB5_FAST_EXPECTED; + } + + ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); + if (ret) + goto fail; + +fail: + if (ac) + krb5_auth_con_free(context, ac); + if (ret) { + t->req_body.addresses = NULL; + free_TGS_REQ (t); + } + krb5_data_free(&tgs_req); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_get_krbtgt(krb5_context context, + krb5_ccache id, + krb5_realm realm, + krb5_creds **cred) +{ + krb5_error_code ret; + krb5_creds tmp_cred; + + memset(&tmp_cred, 0, sizeof(tmp_cred)); + + ret = krb5_cc_get_principal(context, id, &tmp_cred.client); + if (ret) + return ret; + + if (realm == NULL) + realm = tmp_cred.client->realm; + + ret = krb5_make_principal(context, + &tmp_cred.server, + realm, + KRB5_TGS_NAME, + realm, + NULL); + if(ret) { + krb5_free_principal(context, tmp_cred.client); + return ret; + } + /* + * The forwardable TGT might not be the start TGT, in which case, it is + * generally, but not always already cached. Just in case, get it again if + * lost. + */ + ret = krb5_get_credentials(context, + 0, + id, + &tmp_cred, + cred); + krb5_free_principal(context, tmp_cred.client); + krb5_free_principal(context, tmp_cred.server); + if(ret) + return ret; + return 0; +} + +static krb5_error_code +fast_tgs_strengthen_key(krb5_context context, + struct krb5_fast_state *state, + krb5_keyblock *reply_key, + krb5_keyblock *extract_key) +{ + krb5_error_code ret; + + if (state && state->strengthen_key) { + _krb5_debug(context, 5, "_krb5_fast_tgs_strengthen_key"); + + if (state->strengthen_key->keytype != reply_key->keytype) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("strengthen_key %d not same enctype as reply key %d", ""), + state->strengthen_key->keytype, reply_key->keytype); + return KRB5KRB_AP_ERR_MODIFIED; + } + + ret = _krb5_fast_cf2(context, + state->strengthen_key, + "strengthenkey", + reply_key, + "replykey", + extract_key, + NULL); + if (ret) + return ret; + } else { + ret = krb5_copy_keyblock_contents(context, reply_key, extract_key); + if (ret) + return ret; + } + + return 0; +} + +/* DCE compatible decrypt proc */ +static krb5_error_code KRB5_CALLCONV +decrypt_tkt_with_subkey (krb5_context context, + krb5_keyblock *key, + krb5_key_usage usage, + krb5_const_pointer skey, + krb5_kdc_rep *dec_rep) +{ + struct krb5_decrypt_tkt_with_subkey_state *state; + krb5_error_code ret = 0; + krb5_data data; + size_t size; + krb5_crypto crypto; + krb5_keyblock extract_key; + + state = (struct krb5_decrypt_tkt_with_subkey_state *)skey; + + assert(usage == 0); + + krb5_data_zero(&data); + + /* + * start out with trying with subkey if we have one + */ + if (state->subkey) { + ret = fast_tgs_strengthen_key(context, state->fast_state, + state->subkey, &extract_key); + if (ret) + return ret; + + ret = krb5_crypto_init(context, &extract_key, 0, &crypto); + krb5_free_keyblock_contents(context, &extract_key); + if (ret) + return ret; + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, + &dec_rep->kdc_rep.enc_part, + &data); + /* + * If the is Windows 2000 DC, we need to retry with key usage + * 8 when doing ARCFOUR. + */ + if (ret && state->subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) { + ret = krb5_decrypt_EncryptedData(context, + crypto, + 8, + &dec_rep->kdc_rep.enc_part, + &data); + } + krb5_crypto_destroy(context, crypto); + } + if (state->subkey == NULL || ret) { + ret = fast_tgs_strengthen_key(context, state->fast_state, key, &extract_key); + if (ret) + return ret; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TGS_REP_ENC_PART_SESSION, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); + } + if (ret) + return ret; + + ret = decode_EncASRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + ret = decode_EncTGSRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + krb5_set_error_message(context, ret, + N_("Failed to decode encpart in ticket", "")); + krb5_data_free (&data); + return ret; +} + +static krb5_error_code +get_cred_kdc(krb5_context context, + krb5_ccache id, + struct krb5_fast_state *fast_state, + krb5_kdc_flags flags, + krb5_addresses *addresses, + krb5_creds *in_creds, + krb5_creds *krbtgt, + krb5_principal impersonate_principal, + Ticket *second_ticket, + const char *kdc_hostname, + const char *sitename, + krb5_creds *out_creds) +{ + TGS_REQ req; + krb5_data enc; + krb5_data resp; + krb5_kdc_rep rep; + krb5_error_code ret; + unsigned nonce; + krb5_keyblock *subkey = NULL; + size_t len = 0; + Ticket second_ticket_data; + METHOD_DATA padata; + + memset(&rep, 0, sizeof(rep)); + krb5_data_zero(&resp); + krb5_data_zero(&enc); + padata.val = NULL; + padata.len = 0; + + krb5_generate_random_block(&nonce, sizeof(nonce)); + nonce &= 0xffffffff; + + if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ + ret = decode_Ticket(in_creds->second_ticket.data, + in_creds->second_ticket.length, + &second_ticket_data, &len); + if(ret) + return ret; + second_ticket = &second_ticket_data; + } + + + if (impersonate_principal) { + krb5_crypto crypto; + PA_S4U2Self self; + krb5_data data; + void *buf; + size_t size = 0; + + self.name = impersonate_principal->name; + self.realm = impersonate_principal->realm; + self.auth = estrdup("Kerberos"); + + ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); + if (ret) { + free(self.auth); + goto out; + } + + ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); + if (ret) { + free(self.auth); + krb5_data_free(&data); + goto out; + } + + ret = krb5_create_checksum(context, + crypto, + KRB5_KU_OTHER_CKSUM, + 0, + data.data, + data.length, + &self.cksum); + krb5_crypto_destroy(context, crypto); + krb5_data_free(&data); + if (ret) { + free(self.auth); + goto out; + } + + ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); + free(self.auth); + free_Checksum(&self.cksum); + if (ret) + goto out; + if (len != size) + krb5_abortx(context, "internal asn1 error"); + + ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); + if (ret) + goto out; + } + + ret = init_tgs_req (context, + id, + fast_state, + addresses, + flags, + second_ticket, + in_creds, + krbtgt, + nonce, + &padata, + &subkey, + &req); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); + if (ret) + goto out; + if(enc.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + /* don't free addresses */ + req.req_body.addresses = NULL; + free_TGS_REQ(&req); + + /* + * Send and receive + */ + { + krb5_sendto_ctx stctx; + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + return ret; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + + if (kdc_hostname) + krb5_sendto_set_hostname(context, stctx, kdc_hostname); + if (sitename) + krb5_sendto_set_sitename(context, stctx, sitename); + + ret = krb5_sendto_context (context, stctx, &enc, + krbtgt->server->name.name_string.val[1], + &resp); + krb5_sendto_ctx_free(context, stctx); + } + if(ret) + goto out; + + if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { + struct krb5_decrypt_tkt_with_subkey_state state; + unsigned eflags = 0; + krb5_data data; + size_t size; + + ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, + &rep.kdc_rep.ticket, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + ret = _krb5_fast_unwrap_kdc_rep(context, nonce, &data, + fast_state, &rep.kdc_rep); + krb5_data_free(&data); + if (ret) + goto out; + + ret = krb5_copy_principal(context, + in_creds->client, + &out_creds->client); + if(ret) + goto out; + ret = krb5_copy_principal(context, + in_creds->server, + &out_creds->server); + if(ret) + goto out; + /* this should go someplace else */ + out_creds->times.endtime = in_creds->times.endtime; + + /* XXX should do better testing */ + if (flags.b.cname_in_addl_tkt || impersonate_principal) + eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + if (flags.b.request_anonymous) + eflags |= EXTRACT_TICKET_MATCH_ANON; + + state.subkey = subkey; + state.fast_state = fast_state; + + ret = _krb5_extract_ticket(context, + &rep, + out_creds, + &krbtgt->session, + NULL, + 0, + &krbtgt->addresses, + nonce, + eflags, + NULL, + decrypt_tkt_with_subkey, + &state); + } else if(krb5_rd_error(context, &resp, &rep.error) == 0) { + METHOD_DATA md; + + memset(&md, 0, sizeof(md)); + + if (rep.error.e_data) { + KERB_ERROR_DATA kerb_error_data; + + memset(&kerb_error_data, 0, sizeof(kerb_error_data)); + + /* First try to decode the e-data as KERB-ERROR-DATA. */ + ret = decode_KERB_ERROR_DATA(rep.error.e_data->data, + rep.error.e_data->length, + &kerb_error_data, + &len); + if (ret) { + /* That failed, so try to decode it as METHOD-DATA. */ + ret = decode_METHOD_DATA(rep.error.e_data->data, + rep.error.e_data->length, + &md, NULL); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode METHOD-DATA", "")); + goto out; + } + } else if (len != rep.error.e_data->length) { + /* Trailing data — just ignore the error. */ + free_KERB_ERROR_DATA(&kerb_error_data); + } else { + /* OK. */ + free_KERB_ERROR_DATA(&kerb_error_data); + } + } + + ret = _krb5_fast_unwrap_error(context, nonce, fast_state, &md, &rep.error); + free_METHOD_DATA(&md); + if (ret) + goto out; + + ret = krb5_error_from_rd_error(context, &rep.error, in_creds); + + /* log the failure */ + if (_krb5_have_debug(context, 5)) { + const char *str = krb5_get_error_message(context, ret); + _krb5_debug(context, 5, "parse_tgs_rep: KRB-ERROR %d/%s", ret, str); + krb5_free_error_message(context, str); + } + } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { + ret = KRB5KRB_AP_ERR_V4_REPLY; + krb5_clear_error_message(context); + } else { + ret = KRB5KRB_AP_ERR_MSG_TYPE; + krb5_clear_error_message(context); + } + +out: + krb5_free_kdc_rep(context, &rep); + if (second_ticket == &second_ticket_data) + free_Ticket(&second_ticket_data); + free_METHOD_DATA(&padata); + krb5_data_free(&resp); + krb5_data_free(&enc); + if(subkey) + krb5_free_keyblock(context, subkey); + return ret; + +} + +/* + * same as above, just get local addresses first if the krbtgt have + * them and the realm is not addressless + */ + +static krb5_error_code +get_cred_kdc_address(krb5_context context, + krb5_ccache id, + struct krb5_fast_state *fast_state, + krb5_kdc_flags flags, + krb5_addresses *addrs, + krb5_creds *in_creds, + krb5_creds *krbtgt, + krb5_principal impersonate_principal, + Ticket *second_ticket, + const char *kdc_hostname, + const char *sitename, + krb5_creds *out_creds) +{ + krb5_error_code ret; + krb5_addresses addresses = { 0, NULL }; + + /* + * Inherit the address-ness of the krbtgt if the address is not + * specified. + */ + + if (addrs == NULL && krbtgt->addresses.len != 0) { + krb5_boolean noaddr; + + krb5_appdefault_boolean(context, NULL, krbtgt->server->realm, + "no-addresses", FALSE, &noaddr); + + if (!noaddr) { + ret = krb5_get_all_client_addrs(context, &addresses); + if (ret) + return ret; + /* XXX this sucks. */ + addrs = &addresses; + if(addresses.len == 0) + addrs = NULL; + } + } + ret = get_cred_kdc(context, id, fast_state, flags, addrs, + in_creds, krbtgt, impersonate_principal, + second_ticket, kdc_hostname, sitename, out_creds); + krb5_free_addresses(context, &addresses); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_kdc_cred(krb5_context context, + krb5_ccache id, + krb5_kdc_flags flags, + krb5_addresses *addresses, + Ticket *second_ticket, + krb5_creds *in_creds, + krb5_creds **out_creds + ) +{ + krb5_error_code ret; + krb5_creds *krbtgt; + struct krb5_fast_state fast_state; + + memset(&fast_state, 0, sizeof(fast_state)); + + *out_creds = calloc(1, sizeof(**out_creds)); + if(*out_creds == NULL) + return krb5_enomem(context); + ret = _krb5_get_krbtgt (context, + id, + in_creds->server->realm, + &krbtgt); + if(ret) { + free(*out_creds); + *out_creds = NULL; + return ret; + } + ret = get_cred_kdc(context, id, &fast_state, flags, + addresses, in_creds, krbtgt, + NULL, NULL, NULL, NULL, *out_creds); + krb5_free_creds (context, krbtgt); + _krb5_fast_free(context, &fast_state); + if(ret) { + free(*out_creds); + *out_creds = NULL; + } + return ret; +} + +static int +not_found(krb5_context context, krb5_const_principal p, krb5_error_code code) +{ + krb5_error_code ret; + char *str; + const char *err; + + ret = krb5_unparse_name(context, p, &str); + if(ret) { + krb5_clear_error_message(context); + return code; + } + err = krb5_get_error_message(context, code); + krb5_set_error_message(context, code, N_("%s (%s)", ""), err, str); + krb5_free_error_message(context, err); + free(str); + return code; +} + +static krb5_error_code +find_cred(krb5_context context, + krb5_ccache id, + krb5_principal server, + krb5_creds **tgts, + krb5_creds *out_creds) +{ + krb5_error_code ret; + krb5_creds mcreds; + + krb5_cc_clear_mcred(&mcreds); + mcreds.server = server; + krb5_timeofday(context, &mcreds.times.endtime); + ret = krb5_cc_retrieve_cred(context, id, + KRB5_TC_DONT_MATCH_REALM | + KRB5_TC_MATCH_TIMES, + &mcreds, out_creds); + if(ret == 0) + return 0; + while(tgts && *tgts){ + if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, + &mcreds, *tgts)){ + ret = krb5_copy_creds_contents(context, *tgts, out_creds); + return ret; + } + tgts++; + } + return not_found(context, server, KRB5_CC_NOTFOUND); +} + +static krb5_error_code +add_cred(krb5_context context, krb5_creds const *tkt, krb5_creds ***tgts) +{ + int i; + krb5_error_code ret; + krb5_creds **tmp = *tgts; + + for(i = 0; tmp && tmp[i]; i++); /* XXX */ + tmp = realloc(tmp, (i+2)*sizeof(*tmp)); + if(tmp == NULL) + return krb5_enomem(context); + *tgts = tmp; + ret = krb5_copy_creds(context, tkt, &tmp[i]); + tmp[i+1] = NULL; + return ret; +} + +static krb5_error_code +get_cred_kdc_capath_worker(krb5_context context, + krb5_kdc_flags flags, + krb5_ccache ccache, + struct krb5_fast_state *fast_state, + krb5_creds *in_creds, + krb5_const_realm try_realm, + krb5_principal impersonate_principal, + Ticket *second_ticket, + const char *kdc_hostname, + const char *sitename, + krb5_creds **out_creds, + krb5_creds ***ret_tgts) +{ + krb5_error_code ret; + krb5_creds *tgt = NULL; + krb5_creds tmp_creds; + krb5_const_realm client_realm, server_realm; + int ok_as_delegate = 1; + + *out_creds = calloc(1, sizeof(**out_creds)); + if (*out_creds == NULL) + return krb5_enomem(context); + + memset(&tmp_creds, 0, sizeof(tmp_creds)); + + client_realm = krb5_principal_get_realm(context, in_creds->client); + server_realm = krb5_principal_get_realm(context, in_creds->server); + ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); + if (ret) + goto out; + + ret = krb5_make_principal(context, + &tmp_creds.server, + try_realm, + KRB5_TGS_NAME, + server_realm, + NULL); + if (ret) + goto out; + + { + krb5_creds tgts; + + /* + * If we have krbtgt/server_realm@try_realm cached, use it and we're + * done. + */ + ret = find_cred(context, ccache, tmp_creds.server, + *ret_tgts, &tgts); + if (ret == 0) { + /* only allow implicit ok_as_delegate if the realm is the clients realm */ + if (strcmp(try_realm, client_realm) != 0 + || strcmp(try_realm, server_realm) != 0) { + ok_as_delegate = tgts.flags.b.ok_as_delegate; + } + + ret = get_cred_kdc_address(context, ccache, fast_state, + flags, NULL, + in_creds, &tgts, + impersonate_principal, + second_ticket, + kdc_hostname, + sitename, + *out_creds); + krb5_free_cred_contents(context, &tgts); + if (ret == 0 && + !krb5_principal_compare(context, in_creds->server, + (*out_creds)->server)) { + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + } + if (ret == 0 && ok_as_delegate == 0) + (*out_creds)->flags.b.ok_as_delegate = 0; + + goto out; + } + } + + if (krb5_realm_compare(context, in_creds->client, in_creds->server)) { + ret = not_found(context, in_creds->server, KRB5_CC_NOTFOUND); + goto out; + } + + /* + * XXX This can loop forever, plus we recurse, so we can't just keep a + * count here. The count would have to get passed around by reference. + * + * The KDCs check for transit loops for us, and capath data is finite, so + * in fact we'll fall out of this loop at some point. We should do our own + * transit loop checking (like get_cred_kdc_referral()), and we should + * impose a max number of iterations altogether. But barring malicious or + * broken KDCs, this is good enough. + */ + while (1) { + heim_general_string tgt_inst; + + ret = get_cred_kdc_capath(context, flags, ccache, fast_state, + &tmp_creds, NULL, NULL, + kdc_hostname, sitename, + &tgt, ret_tgts); + if (ret) + goto out; + + /* + * if either of the chain or the ok_as_delegate was stripped + * by the kdc, make sure we strip it too. + */ + if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) { + ok_as_delegate = 0; + tgt->flags.b.ok_as_delegate = 0; + } + + ret = add_cred(context, tgt, ret_tgts); + if (ret) + goto out; + tgt_inst = tgt->server->name.name_string.val[1]; + if (strcmp(tgt_inst, server_realm) == 0) + break; + krb5_free_principal(context, tmp_creds.server); + tmp_creds.server = NULL; + ret = krb5_make_principal(context, &tmp_creds.server, + tgt_inst, KRB5_TGS_NAME, server_realm, NULL); + if (ret) + goto out; + ret = krb5_free_creds(context, tgt); + tgt = NULL; + if (ret) + goto out; + } + + ret = get_cred_kdc_address(context, ccache, fast_state, flags, NULL, + in_creds, tgt, impersonate_principal, + second_ticket, kdc_hostname, sitename, *out_creds); + if (ret == 0 && + !krb5_principal_compare(context, in_creds->server, + (*out_creds)->server)) { + krb5_free_cred_contents(context, *out_creds); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + } + if (ret == 0 && ok_as_delegate == 0) + (*out_creds)->flags.b.ok_as_delegate = 0; + +out: + if (ret) { + krb5_free_creds(context, *out_creds); + *out_creds = NULL; + } + if (tmp_creds.server) + krb5_free_principal(context, tmp_creds.server); + if (tmp_creds.client) + krb5_free_principal(context, tmp_creds.client); + if (tgt) + krb5_free_creds(context, tgt); + return ret; +} + +/* +get_cred(server) + creds = cc_get_cred(server) + if(creds) return creds + tgt = cc_get_cred(krbtgt/server_realm@any_realm) + if(tgt) + return get_cred_tgt(server, tgt) + if(client_realm == server_realm) + return NULL + tgt = get_cred(krbtgt/server_realm@client_realm) + while(tgt_inst != server_realm) + tgt = get_cred(krbtgt/server_realm@tgt_inst) + return get_cred_tgt(server, tgt) + */ + +static krb5_error_code +get_cred_kdc_capath(krb5_context context, + krb5_kdc_flags flags, + krb5_ccache ccache, + struct krb5_fast_state *fast_state, + krb5_creds *in_creds, + krb5_principal impersonate_principal, + Ticket *second_ticket, + const char *kdc_hostname, + const char *sitename, + krb5_creds **out_creds, + krb5_creds ***ret_tgts) +{ + krb5_error_code ret; + krb5_const_realm client_realm, server_realm, try_realm; + + client_realm = krb5_principal_get_realm(context, in_creds->client); + server_realm = krb5_principal_get_realm(context, in_creds->server); + + try_realm = client_realm; + ret = get_cred_kdc_capath_worker(context, flags, ccache, fast_state, + in_creds, try_realm, impersonate_principal, + second_ticket, kdc_hostname, sitename, + out_creds, ret_tgts); + + if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { + try_realm = krb5_config_get_string(context, NULL, "capaths", + client_realm, server_realm, NULL); + + if (try_realm != NULL && strcmp(try_realm, client_realm) != 0) { + ret = get_cred_kdc_capath_worker(context, flags, ccache, fast_state, + in_creds, try_realm, impersonate_principal, + second_ticket, kdc_hostname, sitename, + out_creds, ret_tgts); + } + } + + return ret; +} + +static krb5_boolean skip_referrals(krb5_principal server, + krb5_kdc_flags *flags) +{ + return server->name.name_string.len < 2 && !flags->b.canonicalize; +} + +/* + * Get a service ticket from a KDC by chasing referrals from a start realm. + * + * All referral TGTs produced in the process are thrown away when we're done. + * We don't store them, and we don't allow other search mechanisms (capaths) to + * use referral TGTs produced here. + */ +static krb5_error_code +get_cred_kdc_referral(krb5_context context, + krb5_kdc_flags flags, + krb5_ccache ccache, + struct krb5_fast_state *fast_state, + krb5_creds *in_creds, + krb5_principal impersonate_principal, + Ticket *second_ticket, + const char *kdc_hostname, + const char *sitename, + krb5_creds **out_creds) +{ + krb5_realm start_realm = NULL; + krb5_data config_start_realm; + krb5_error_code ret; + krb5_creds tgt, referral, ticket; + krb5_creds **referral_tgts = NULL; /* used for loop detection */ + int loop = 0; + int ok_as_delegate = 1; + int want_tgt; + size_t i; + + if (skip_referrals(in_creds->server, &flags)) { + krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED, + N_("Name too short to do referals, skipping", "")); + return KRB5KDC_ERR_PATH_NOT_ACCEPTED; + } + + memset(&tgt, 0, sizeof(tgt)); + memset(&ticket, 0, sizeof(ticket)); + + flags.b.canonicalize = 1; + + *out_creds = NULL; + + + ret = krb5_cc_get_config(context, ccache, NULL, "start_realm", &config_start_realm); + if (ret == 0) { + start_realm = strndup(config_start_realm.data, config_start_realm.length); + krb5_data_free(&config_start_realm); + } else { + start_realm = strdup(krb5_principal_get_realm(context, in_creds->client)); + } + if (start_realm == NULL) + return krb5_enomem(context); + + /* find tgt for the clients base realm */ + { + krb5_principal tgtname; + + ret = krb5_make_principal(context, &tgtname, + start_realm, + KRB5_TGS_NAME, + start_realm, + NULL); + if (ret) { + free(start_realm); + return ret; + } + + ret = find_cred(context, ccache, tgtname, NULL, &tgt); + krb5_free_principal(context, tgtname); + if (ret) { + free(start_realm); + return ret; + } + } + + /* + * If the desired service principal service/host@REALM is not a TGT, start + * by asking for a ticket for service/host@START_REALM and process referrals + * from there. + * + * However, when we ask for a TGT, krbtgt/A@B, we're actually looking for a + * path to realm B, so that we can explicitly obtain a ticket for krbtgt/A + * from B, and not some other realm. Therefore, in this case our starting + * point will be krbtgt/B@START_REALM. Only once we obtain a ticket for + * krbtgt/B@some-transit, do we switch to requesting krbtgt/A@B on our + * final request. + */ + referral = *in_creds; + want_tgt = in_creds->server->realm[0] != '\0' && + krb5_principal_is_krbtgt(context, in_creds->server); + if (!want_tgt) + ret = krb5_copy_principal(context, in_creds->server, &referral.server); + else + ret = krb5_make_principal(context, &referral.server, start_realm, + KRB5_TGS_NAME, in_creds->server->realm, NULL); + + if (ret) { + krb5_free_cred_contents(context, &tgt); + free(start_realm); + return ret; + } + if (!want_tgt) + ret = krb5_principal_set_realm(context, referral.server, start_realm); + free(start_realm); + start_realm = NULL; + if (ret) { + krb5_free_cred_contents(context, &tgt); + krb5_free_principal(context, referral.server); + return ret; + } + + while (loop++ < 17) { + krb5_creds **tickets; + krb5_creds mcreds; + char *referral_realm; + + /* Use cache if we are not doing impersonation or contrained deleg */ + if (impersonate_principal == NULL && !flags.b.cname_in_addl_tkt) { + krb5_cc_clear_mcred(&mcreds); + mcreds.server = referral.server; + krb5_timeofday(context, &mcreds.times.endtime); + ret = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_TIMES, + &mcreds, &ticket); + } else + ret = EINVAL; + + if (ret) { + ret = get_cred_kdc_address(context, ccache, fast_state, flags, NULL, + &referral, &tgt, impersonate_principal, + second_ticket, kdc_hostname, sitename, &ticket); + if (ret) + goto out; + } + + /* + * Did we get the right ticket? + * + * If we weren't asking for a TGT, then we don't mind if we took a realm + * change (referral.server has a referral realm, not necessarily the + * original). + * + * However, if we were looking for a TGT (which wouldn't be the start + * TGT, since that one must be in the ccache) then we actually want the + * one from the realm we wanted, since otherwise a _referral_ will + * confuse us and we will store that referral. In Heimdal we mostly + * never ask krb5_get_cred*() for TGTs, but some sites have code to ask + * for a ktbgt/REMOTE.REALM@REMOTE.REALM, and one could always use + * kgetcred(1) to get here asking for a krbtgt/C@D and we need to handle + * the case where last hop we get is krbtgt/C@B (in which case we must + * stop so we don't beat up on B for the remaining tries). + */ + if (!want_tgt && + krb5_principal_compare(context, referral.server, ticket.server)) + break; + + if (!krb5_principal_is_krbtgt(context, ticket.server)) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, + N_("Got back an non krbtgt " + "ticket referrals", "")); + ret = KRB5KRB_AP_ERR_NOT_US; + goto out; + } + + referral_realm = ticket.server->name.name_string.val[1]; + + /* check that there are no referrals loops */ + tickets = referral_tgts; + + krb5_cc_clear_mcred(&mcreds); + mcreds.server = ticket.server; + + while (tickets && *tickets){ + if (krb5_compare_creds(context, + KRB5_TC_DONT_MATCH_REALM, + &mcreds, + *tickets)) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + N_("Referral from %s " + "loops back to realm %s", ""), + tgt.server->realm, + referral_realm); + ret = KRB5_GET_IN_TKT_LOOP; + goto out; + } + tickets++; + } + + /* + * if either of the chain or the ok_as_delegate was stripped + * by the kdc, make sure we strip it too. + */ + + if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) { + ok_as_delegate = 0; + ticket.flags.b.ok_as_delegate = 0; + } + + _krb5_debug(context, 6, "get_cred_kdc_referral: got referral " + "to %s from %s", referral_realm, referral.server->realm); + ret = add_cred(context, &ticket, &referral_tgts); + if (ret) + goto out; + + /* try realm in the referral */ + if (!want_tgt || strcmp(referral_realm, in_creds->server->realm) != 0) + ret = krb5_principal_set_realm(context, + referral.server, + referral_realm); + else { + /* + * Now that we have a ticket for the desired realm, we reset + * want_tgt and reinstate the desired principal so that the we can + * match it and break out of the loop. + */ + want_tgt = 0; + krb5_free_principal(context, referral.server); + referral.server = NULL; + ret = krb5_copy_principal(context, in_creds->server, &referral.server); + } + krb5_free_cred_contents(context, &tgt); + tgt = ticket; + memset(&ticket, 0, sizeof(ticket)); + if (ret) + goto out; + } + + ret = krb5_copy_creds(context, &ticket, out_creds); + +out: + for (i = 0; referral_tgts && referral_tgts[i]; i++) + krb5_free_creds(context, referral_tgts[i]); + free(referral_tgts); + krb5_free_principal(context, referral.server); + krb5_free_cred_contents(context, &tgt); + krb5_free_cred_contents(context, &ticket); + return ret; +} + + +/* + * Glue function between referrals version and old client chasing + * codebase. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_get_cred_kdc_any(krb5_context context, + krb5_kdc_flags flags, + krb5_ccache ccache, + struct krb5_fast_state *fast_state, + krb5_creds *in_creds, + krb5_principal impersonate_principal, + Ticket *second_ticket, + krb5_creds **out_creds, + krb5_creds ***ret_tgts) +{ + char *kdc_hostname = NULL; + char *sitename = NULL; + krb5_error_code ret; + krb5_deltat offset; + krb5_data data; + + krb5_data_zero(&data); + + /* + * If we are using LKDC, lets pull out the addreses from the + * ticket and use that. + */ + + ret = krb5_cc_get_config(context, ccache, NULL, "lkdc-hostname", &data); + if (ret == 0) { + if ((kdc_hostname = strndup(data.data, data.length)) == NULL) { + ret = krb5_enomem(context); + goto out; + } + krb5_data_free(&data); + } + + ret = krb5_cc_get_config(context, ccache, NULL, "sitename", &data); + if (ret == 0) { + if ((sitename = strndup(data.data, data.length)) == NULL) { + ret = krb5_enomem(context); + goto out; + } + krb5_data_free(&data); + } + + ret = krb5_cc_get_kdc_offset(context, ccache, &offset); + if (ret == 0) { + context->kdc_sec_offset = offset; + context->kdc_usec_offset = 0; + } + + if (strcmp(in_creds->server->realm, "") != 0) { + /* + * Non-empty realm? Try capaths first. We might have local + * policy (capaths) to honor. + */ + ret = get_cred_kdc_capath(context, + flags, + ccache, + fast_state, + in_creds, + impersonate_principal, + second_ticket, + kdc_hostname, + sitename, + out_creds, + ret_tgts); + if (ret == 0 || skip_referrals(in_creds->server, &flags)) + goto out; + } + + /* Otherwise try referrals */ + ret = get_cred_kdc_referral(context, + flags, + ccache, + fast_state, + in_creds, + impersonate_principal, + second_ticket, + kdc_hostname, + sitename, + out_creds); + +out: + krb5_data_free(&data); + free(kdc_hostname); + free(sitename); + return ret; +} + +static krb5_error_code +check_cc(krb5_context context, krb5_flags options, krb5_ccache ccache, + krb5_creds *in_creds, krb5_creds *out_creds) +{ + krb5_error_code ret; + krb5_timestamp now; + krb5_creds mcreds = *in_creds; + + krb5_timeofday(context, &now); + + if (!(options & KRB5_GC_EXPIRED_OK) && + mcreds.times.endtime < now) { + mcreds.times.renew_till = 0; + krb5_timeofday(context, &mcreds.times.endtime); + options |= KRB5_TC_MATCH_TIMES; + } + + if (mcreds.server->name.name_type == KRB5_NT_SRV_HST_NEEDS_CANON) { + /* Avoid name canonicalization in krb5_cc_retrieve_cred() */ + krb5_principal_set_type(context, mcreds.server, KRB5_NT_SRV_HST); + } + + if (options & KRB5_GC_ANONYMOUS) { + ret = krb5_make_principal(context, + &mcreds.client, + krb5_principal_get_realm(context, mcreds.client), + KRB5_WELLKNOWN_NAME, + KRB5_ANON_NAME, + NULL); + if (ret) + return ret; + } + + ret = krb5_cc_retrieve_cred(context, ccache, + (options & + (KRB5_TC_DONT_MATCH_REALM | + KRB5_TC_MATCH_KEYTYPE | + KRB5_TC_MATCH_TIMES)), + &mcreds, out_creds); + + if (options & KRB5_GC_ANONYMOUS) + krb5_free_principal(context, mcreds.client); + + if (ret == 0 && out_creds->server->realm && + out_creds->server->realm[0] == '\0') { + Ticket ticket; + + /* + * We only write tickets to the ccache that have been validated, as in, + * the sname/srealm from the KDC-REP enc-part have been checked to + * match the sname/realm from the Ticket from the KDC-REP. + * + * Our caller needs the canonical realm of the service in order to be + * able to get forwarded credentials for it when destination-TGT + * forwarding is enabled. + * + * As well, gss_init_sec_context() ought to arrange for + * gss_inquire_context() to output the canonical acceptor name on the + * initiator side. + */ + ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, + &ticket, NULL); + if (ret == 0) { + ret = krb5_principal_set_realm(context, out_creds->server, + ticket.realm); + free_Ticket(&ticket); + } else { + krb5_free_cred_contents(context, out_creds); + } + } + return ret; +} + +static void +store_cred(krb5_context context, krb5_ccache ccache, + krb5_const_principal server_princ, krb5_creds *creds) +{ + if (context->no_ticket_store) + return; + if (!krb5_principal_compare(context, creds->server, server_princ) && + !krb5_principal_is_krbtgt(context, server_princ)) { + krb5_principal tmp_princ = creds->server; + /* + * Store the cred with the pre-canon server princ first so it + * can be found quickly in the future. + */ + creds->server = (krb5_principal)server_princ; + krb5_cc_store_cred(context, ccache, creds); + creds->server = tmp_princ; + /* Then store again with the canonicalized server princ */ + } + krb5_cc_store_cred(context, ccache, creds); +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_credentials_with_flags(krb5_context context, + krb5_flags options, + krb5_kdc_flags flags, + krb5_ccache ccache, + krb5_creds *in_creds, + krb5_creds **out_creds) +{ + struct krb5_fast_state fast_state; + krb5_error_code ret; + krb5_name_canon_iterator name_canon_iter = NULL; + krb5_name_canon_rule_options rule_opts; + krb5_const_principal try_princ = NULL; + krb5_principal save_princ = in_creds->server; + krb5_creds **tgts; + krb5_creds *res_creds; + int i; + + memset(&fast_state, 0, sizeof(fast_state)); + + if (_krb5_have_debug(context, 5)) { + char *unparsed; + + ret = krb5_unparse_name(context, in_creds->server, &unparsed); + if (ret) { + _krb5_debug(context, 5, "krb5_get_creds: unable to display " + "requested service principal"); + } else { + _krb5_debug(context, 5, "krb5_get_creds: requesting a ticket " + "for %s", unparsed); + free(unparsed); + } + } + + if (in_creds->session.keytype) { + ret = krb5_enctype_valid(context, in_creds->session.keytype); + if (ret) + return ret; + options |= KRB5_TC_MATCH_KEYTYPE; + } + + *out_creds = NULL; + res_creds = calloc(1, sizeof(*res_creds)); + if (res_creds == NULL) + return krb5_enomem(context); + + ret = krb5_name_canon_iterator_start(context, in_creds->server, + &name_canon_iter); + if (ret) + goto out; + +next_rule: + krb5_free_cred_contents(context, res_creds); + memset(res_creds, 0, sizeof (*res_creds)); + ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, + &rule_opts); + in_creds->server = rk_UNCONST(try_princ); + if (ret) + goto out; + + if (name_canon_iter == NULL) { + if (options & KRB5_GC_CACHED) + ret = KRB5_CC_NOTFOUND; + else + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + ret = check_cc(context, options, ccache, in_creds, res_creds); + if (ret == 0) { + *out_creds = res_creds; + res_creds = NULL; + goto out; + } else if(ret != KRB5_CC_END) { + goto out; + } + if (options & KRB5_GC_CACHED) + goto next_rule; + + if(options & KRB5_GC_USER_USER) + flags.b.enc_tkt_in_skey = 1; + if (flags.b.enc_tkt_in_skey) + options |= KRB5_GC_NO_STORE; + + tgts = NULL; + ret = _krb5_get_cred_kdc_any(context, flags, ccache, &fast_state, + in_creds, NULL, NULL, out_creds, &tgts); + for (i = 0; tgts && tgts[i]; i++) { + if ((options & KRB5_GC_NO_STORE) == 0) + krb5_cc_store_cred(context, ccache, tgts[i]); + krb5_free_creds(context, tgts[i]); + } + free(tgts); + + /* We don't yet have TGS w/ FAST, so we can't protect KBR-ERRORs */ + if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && + !(rule_opts & KRB5_NCRO_USE_FAST)) + goto next_rule; + + if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) + store_cred(context, ccache, in_creds->server, *out_creds); + + if (ret == 0 && _krb5_have_debug(context, 5)) { + char *unparsed; + + ret = krb5_unparse_name(context, (*out_creds)->server, &unparsed); + if (ret) { + _krb5_debug(context, 5, "krb5_get_creds: unable to display " + "service principal"); + } else { + _krb5_debug(context, 5, "krb5_get_creds: got a ticket for %s", + unparsed); + free(unparsed); + } + } + +out: + in_creds->server = save_princ; + krb5_free_creds(context, res_creds); + krb5_free_name_canon_iterator(context, name_canon_iter); + _krb5_fast_free(context, &fast_state); + if (ret) + return not_found(context, in_creds->server, ret); + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_credentials(krb5_context context, + krb5_flags options, + krb5_ccache ccache, + krb5_creds *in_creds, + krb5_creds **out_creds) +{ + krb5_kdc_flags flags; + flags.i = 0; + return krb5_get_credentials_with_flags(context, options, flags, + ccache, in_creds, out_creds); +} + +struct krb5_get_creds_opt_data { + krb5_principal self; + krb5_flags options; + krb5_enctype enctype; + Ticket *ticket; +}; + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt) +{ + *opt = calloc(1, sizeof(**opt)); + if (*opt == NULL) + return krb5_enomem(context); + return 0; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) +{ + if (opt->self) + krb5_free_principal(context, opt->self); + if (opt->ticket) { + free_Ticket(opt->ticket); + free(opt->ticket); + } + memset(opt, 0, sizeof(*opt)); + free(opt); +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_creds_opt_set_options(krb5_context context, + krb5_get_creds_opt opt, + krb5_flags options) +{ + opt->options = options; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_creds_opt_add_options(krb5_context context, + krb5_get_creds_opt opt, + krb5_flags options) +{ + opt->options |= options; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_creds_opt_set_enctype(krb5_context context, + krb5_get_creds_opt opt, + krb5_enctype enctype) +{ + opt->enctype = enctype; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_creds_opt_set_impersonate(krb5_context context, + krb5_get_creds_opt opt, + krb5_const_principal self) +{ + if (opt->self) + krb5_free_principal(context, opt->self); + return krb5_copy_principal(context, self, &opt->self); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_creds_opt_set_ticket(krb5_context context, + krb5_get_creds_opt opt, + const Ticket *ticket) +{ + if (opt->ticket) { + free_Ticket(opt->ticket); + free(opt->ticket); + opt->ticket = NULL; + } + if (ticket) { + krb5_error_code ret; + + opt->ticket = malloc(sizeof(*ticket)); + if (opt->ticket == NULL) + return krb5_enomem(context); + ret = copy_Ticket(ticket, opt->ticket); + if (ret) { + free(opt->ticket); + opt->ticket = NULL; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + return ret; + } + } + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_creds(krb5_context context, + krb5_get_creds_opt opt, + krb5_ccache ccache, + krb5_const_principal inprinc, + krb5_creds **out_creds) +{ + struct krb5_fast_state fast_state; + krb5_kdc_flags flags; + krb5_flags options; + krb5_creds in_creds; + krb5_error_code ret; + krb5_creds **tgts; + krb5_creds *res_creds; + krb5_const_principal try_princ = NULL; + krb5_name_canon_iterator name_canon_iter = NULL; + krb5_name_canon_rule_options rule_opts; + int i; + int type; + const char *comp; + + memset(&fast_state, 0, sizeof(fast_state)); + memset(&in_creds, 0, sizeof(in_creds)); + in_creds.server = rk_UNCONST(inprinc); + + if (_krb5_have_debug(context, 5)) { + char *unparsed; + + ret = krb5_unparse_name(context, in_creds.server, &unparsed); + if (ret) { + _krb5_debug(context, 5, "krb5_get_creds: unable to display " + "requested service principal"); + } else { + _krb5_debug(context, 5, "krb5_get_creds: requesting a ticket " + "for %s", unparsed); + free(unparsed); + } + } + + if (opt && opt->enctype) { + ret = krb5_enctype_valid(context, opt->enctype); + if (ret) + return ret; + } + + ret = krb5_cc_get_principal(context, ccache, &in_creds.client); + if (ret) + return ret; + + if (opt) + options = opt->options; + else + options = 0; + flags.i = 0; + + *out_creds = NULL; + res_creds = calloc(1, sizeof(*res_creds)); + if (res_creds == NULL) { + krb5_free_principal(context, in_creds.client); + return krb5_enomem(context); + } + + if (opt && opt->enctype) { + in_creds.session.keytype = opt->enctype; + options |= KRB5_TC_MATCH_KEYTYPE; + } + + ret = krb5_name_canon_iterator_start(context, in_creds.server, + &name_canon_iter); + if (ret) + goto out; + +next_rule: + ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, + &rule_opts); + in_creds.server = rk_UNCONST(try_princ); + if (ret) + goto out; + + if (name_canon_iter == NULL) { + if (options & KRB5_GC_CACHED) + ret = KRB5_CC_NOTFOUND; + else + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + if ((options & KRB5_GC_CONSTRAINED_DELEGATION) == 0) { + ret = check_cc(context, options, ccache, &in_creds, res_creds); + if (ret == 0) { + *out_creds = res_creds; + res_creds = NULL; + goto out; + } else if (ret != KRB5_CC_END) { + goto out; + } + } + if (options & KRB5_GC_CACHED) + goto next_rule; + + type = krb5_principal_get_type(context, try_princ); + comp = krb5_principal_get_comp_string(context, try_princ, 0); + if ((type == KRB5_NT_SRV_HST || type == KRB5_NT_UNKNOWN) && + comp != NULL && strcmp(comp, "host") == 0) + flags.b.canonicalize = 1; + if (rule_opts & KRB5_NCRO_NO_REFERRALS) + flags.b.canonicalize = 0; + else + flags.b.canonicalize = (options & KRB5_GC_CANONICALIZE) ? 1 : 0; + if (options & KRB5_GC_USER_USER) { + flags.b.enc_tkt_in_skey = 1; + options |= KRB5_GC_NO_STORE; + } + if (options & KRB5_GC_FORWARDABLE) + flags.b.forwardable = 1; + if (options & KRB5_GC_NO_TRANSIT_CHECK) + flags.b.disable_transited_check = 1; + if (options & KRB5_GC_CONSTRAINED_DELEGATION) + flags.b.cname_in_addl_tkt = 1; + if (options & KRB5_GC_ANONYMOUS) + flags.b.request_anonymous = 1; + + tgts = NULL; + ret = _krb5_get_cred_kdc_any(context, flags, ccache, &fast_state, + &in_creds, opt ? opt->self : 0, + opt ? opt->ticket : 0, out_creds, + &tgts); + for (i = 0; tgts && tgts[i]; i++) { + if ((options & KRB5_GC_NO_STORE) == 0) + krb5_cc_store_cred(context, ccache, tgts[i]); + krb5_free_creds(context, tgts[i]); + } + free(tgts); + + /* We don't yet have TGS w/ FAST, so we can't protect KBR-ERRORs */ + if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && + !(rule_opts & KRB5_NCRO_USE_FAST)) + goto next_rule; + + if (ret == 0 && (options & KRB5_GC_NO_STORE) == 0) + store_cred(context, ccache, inprinc, *out_creds); + + if (ret == 0 && _krb5_have_debug(context, 5)) { + char *unparsed; + + ret = krb5_unparse_name(context, (*out_creds)->server, &unparsed); + if (ret) { + _krb5_debug(context, 5, "krb5_get_creds: unable to display " + "service principal"); + } else { + _krb5_debug(context, 5, "krb5_get_creds: got a ticket for %s", + unparsed); + free(unparsed); + } + } + +out: + _krb5_fast_free(context, &fast_state); + krb5_free_creds(context, res_creds); + krb5_free_principal(context, in_creds.client); + krb5_free_name_canon_iterator(context, name_canon_iter); + if (ret) + return not_found(context, inprinc, ret); + return ret; +} + +/* + * + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_renewed_creds(krb5_context context, + krb5_creds *creds, + krb5_const_principal client, + krb5_ccache ccache, + const char *in_tkt_service) +{ + krb5_error_code ret; + krb5_kdc_flags flags; + krb5_creds in, *template, *out = NULL; + + memset(&in, 0, sizeof(in)); + memset(creds, 0, sizeof(*creds)); + + ret = krb5_copy_principal(context, client, &in.client); + if (ret) + return ret; + + if (in_tkt_service) { + ret = krb5_parse_name(context, in_tkt_service, &in.server); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } else { + const char *realm = krb5_principal_get_realm(context, client); + + ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, + realm, NULL); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } + + flags.i = 0; + flags.b.renewable = flags.b.renew = 1; + + /* + * Get template from old credential cache for the same entry, if + * this failes, no worries. + */ + ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); + if (ret == 0) { + flags.b.forwardable = template->flags.b.forwardable; + flags.b.proxiable = template->flags.b.proxiable; + krb5_free_creds (context, template); + } + + ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out); + krb5_free_principal(context, in.client); + krb5_free_principal(context, in.server); + if (ret) + return ret; + + ret = krb5_copy_creds_contents(context, out, creds); + krb5_free_creds(context, out); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/get_default_principal.c b/third_party/heimdal/lib/krb5/get_default_principal.c new file mode 100644 index 0000000..3548074 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_default_principal.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * Try to find out what's a reasonable default principal. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_get_default_principal_local (krb5_context context, + krb5_principal *princ) +{ + const char *user = NULL; + const char *second_component = NULL; + char userbuf[128]; + + *princ = NULL; + + /* + * NOTE: We prefer getlogin_r() (via roken_get_loginname()) to using $USER, + * $LOGNAME, or getpwuid_r() (via roken_get_username()), in that + * order, otherwise we won't figure out to output + * /root@DEFAULT_REALM. + */ +#ifndef WIN32 + if (geteuid() == 0) + user = roken_get_loginname(userbuf, sizeof(userbuf)); +#endif + if (user == NULL) + user = roken_get_username(userbuf, sizeof(userbuf)); + if (user == NULL) { + krb5_set_error_message(context, ENOTTY, + N_("unable to figure out current principal", + "")); + return ENOTTY; /* XXX */ + } + +#ifndef WIN32 + if (!issuid() && getuid() == 0 && strcmp(user, "root") != 0) + second_component = "root"; /* We'll use /root */ +#endif + return krb5_make_principal(context, princ, NULL, user, + second_component, NULL); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_default_principal (krb5_context context, + krb5_principal *princ) +{ + krb5_error_code ret; + krb5_ccache id; + + *princ = NULL; + + ret = krb5_cc_default (context, &id); + if (ret == 0) { + ret = krb5_cc_get_principal (context, id, princ); + krb5_cc_close (context, id); + if (ret == 0) + return 0; + } + + return _krb5_get_default_principal_local(context, princ); +} diff --git a/third_party/heimdal/lib/krb5/get_default_realm.c b/third_party/heimdal/lib/krb5/get_default_realm.c new file mode 100644 index 0000000..81a55bb --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_default_realm.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1997 - 2001, 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * Return a NULL-terminated list of default realms in `realms'. + * Free this memory with krb5_free_host_realm. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_default_realms (krb5_context context, + krb5_realm **realms) +{ + if (context->default_realms == NULL) { + krb5_error_code ret = krb5_set_default_realm (context, NULL); + if (ret) + return KRB5_CONFIG_NODEFREALM; + } + + return krb5_copy_host_realm (context, + context->default_realms, + realms); +} + +/* + * Return the first default realm. For compatibility. + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_default_realm(krb5_context context, + krb5_realm *realm) +{ + krb5_error_code ret; + char *res; + + if (context->default_realms == NULL + || context->default_realms[0] == NULL) { + krb5_clear_error_message(context); + ret = krb5_set_default_realm (context, NULL); + if (ret) + return ret; + } + + res = strdup (context->default_realms[0]); + if (res == NULL) + return krb5_enomem(context); + *realm = res; + return 0; +} diff --git a/third_party/heimdal/lib/krb5/get_for_creds.c b/third_party/heimdal/lib/krb5/get_for_creds.c new file mode 100644 index 0000000..3a6be10 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_for_creds.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +static krb5_error_code set_tgs_creds(krb5_context, krb5_ccache, + krb5_const_principal, + krb5_const_principal, krb5_creds *); +static krb5_error_code get_cred(krb5_context, krb5_ccache, krb5_creds *, + krb5_flags, const char *, krb5_creds **); +static krb5_error_code get_addresses(krb5_context, krb5_ccache, krb5_creds *, + const char *, krb5_addresses *); + +static krb5_error_code +add_addrs(krb5_context context, + krb5_addresses *addr, + struct addrinfo *ai) +{ + krb5_error_code ret; + unsigned n, i; + void *tmp; + struct addrinfo *a; + + n = 0; + for (a = ai; a != NULL; a = a->ai_next) + ++n; + + tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val)); + if (tmp == NULL && (addr->len + n) != 0) { + ret = krb5_enomem(context); + goto fail; + } + addr->val = tmp; + for (i = addr->len; i < (addr->len + n); ++i) { + addr->val[i].addr_type = 0; + krb5_data_zero(&addr->val[i].address); + } + i = addr->len; + for (a = ai; a != NULL; a = a->ai_next) { + krb5_address ad; + + ret = krb5_sockaddr2address (context, a->ai_addr, &ad); + if (ret == 0) { + if (krb5_address_search(context, &ad, addr)) + krb5_free_address(context, &ad); + else + addr->val[i++] = ad; + } + else if (ret == KRB5_PROG_ATYPE_NOSUPP) + krb5_clear_error_message (context); + else + goto fail; + addr->len = i; + } + return 0; +fail: + krb5_free_addresses (context, addr); + return ret; +} + +/** + * Forward credentials for client to host hostname, making them + * forwardable if forwardable, and returning the blob of data to sent + * in out_data. If hostname == NULL, pick it from server. + * + * If the server's realm is configured for delegation of destination + * TGTs, forward a TGT for the server realm, rather than the client + * realm. This works better with destinations on the far side of a + * firewall. We also forward the destination TGT when the client + * TGT is not available (we may have just the destination TGT). + * + * @param context A kerberos 5 context. + * @param auth_context the auth context with the key to encrypt the out_data. + * @param hostname the host to forward the tickets too. + * @param client the client to delegate from. + * @param server the server to delegate the credential too. + * @param ccache credential cache to use. + * @param forwardable make the forwarded ticket forwabledable. + * @param out_data the resulting credential. + * + * @return Return an error code or 0. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_fwd_tgt_creds(krb5_context context, + krb5_auth_context auth_context, + const char *hostname, + krb5_const_principal client, + krb5_const_principal server, + krb5_ccache ccache, + int forwardable, + krb5_data *out_data) +{ + krb5_flags flags = 0; + krb5_creds creds; + krb5_error_code ret; + + flags |= KDC_OPT_FORWARDED; + + if (forwardable) + flags |= KDC_OPT_FORWARDABLE; + + if (hostname == NULL && + krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) { + const char *inst = krb5_principal_get_comp_string(context, server, 0); + const char *host = krb5_principal_get_comp_string(context, server, 1); + + if (inst != NULL && + strcmp(inst, "host") == 0 && + host != NULL && + krb5_principal_get_comp_string(context, server, 2) == NULL) + hostname = host; + } + + /* + * Fill-in the request creds, the server principal will be the TGS + * of either the client's or the server's realm. + */ + ret = set_tgs_creds(context, ccache, client, server, &creds); + if (ret) + return ret; + + ret = krb5_get_forwarded_creds (context, + auth_context, + ccache, + flags, + hostname, + &creds, + out_data); + + krb5_free_cred_contents(context, &creds); + return ret; +} + +/** + * Gets tickets forwarded to hostname. If the tickets that are + * forwarded are address-less, the forwarded tickets will also be + * address-less. + * + * If the ticket have any address, hostname will be used for figure + * out the address to forward the ticket too. This since this might + * use DNS, its insecure and also doesn't represent configured all + * addresses of the host. For example, the host might have two + * adresses, one IPv4 and one IPv6 address where the later is not + * published in DNS. This IPv6 address might be used communications + * and thus the resulting ticket useless. + * + * @param context A kerberos 5 context. + * @param auth_context the auth context with the key to encrypt the out_data. + * @param ccache credential cache to use + * @param flags the flags to control the resulting ticket flags + * @param hostname the host to forward the tickets too. + * @param in_creds the in client and server ticket names. The client + * and server components forwarded to the remote host. + * @param out_data the resulting credential. + * + * @return Return an error code or 0. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_forwarded_creds (krb5_context context, + krb5_auth_context auth_context, + krb5_ccache ccache, + krb5_flags flags, + const char *hostname, + krb5_creds *in_creds, + krb5_data *out_data) +{ + krb5_error_code ret; + krb5_creds *creds; + + /* Obtain the requested TGT */ + ret = get_cred(context, ccache, in_creds, flags, hostname, &creds); + if (ret) + return ret; + + /* Forward obtained creds */ + ret = _krb5_mk_1cred(context, auth_context, creds, out_data, NULL); + krb5_free_creds(context, creds); + return ret; +} + +/* + * Get a TGT for forwarding to hostname. If the client TGT is + * addressless, the forwarded ticket will also be addressless. + * + * If the TGT has any addresses, hostname will be used to determine + * the address to forward the ticket to. Thus, since this might use DNS, + * it's insecure and also may not capture all the addresses of the host. + * In general addressless tickets are more robust, be it at a small + * security penalty. + * + * @param context A kerberos 5 context. + * @param ccache The credential cache to use + * @param creds Creds with client and server principals + * @param flags The flags to control the resulting ticket flags + * @param hostname The hostname of server + * @param out_creds The resulting credential + * + * @return Return an error code or 0. + */ + +static krb5_error_code +get_cred(krb5_context context, + krb5_ccache ccache, + krb5_creds *creds, + krb5_flags flags, + const char *hostname, + krb5_creds **out_creds) +{ + krb5_error_code ret; + krb5_kdc_flags kdc_flags; + krb5_addresses addrs; + + addrs.len = 0; + addrs.val = NULL; + ret = get_addresses(context, ccache, creds, hostname, &addrs); + if (ret) + return ret; + + kdc_flags.b = int2KDCOptions(flags); + ret = krb5_get_kdc_cred(context, ccache, kdc_flags, &addrs, NULL, + creds, out_creds); + + krb5_free_addresses(context, &addrs); + return ret; +} + +static krb5_error_code +set_tgs_creds(krb5_context context, + krb5_ccache ccache, + krb5_const_principal client, + krb5_const_principal server, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_const_realm client_realm; + krb5_const_realm server_realm; + krb5_boolean fwd_dest_tgt; + krb5_creds *client_tgt; + + client_realm = krb5_principal_get_realm(context, client); + server_realm = krb5_principal_get_realm(context, server); + + memset (creds, 0, sizeof(*creds)); + ret = krb5_copy_principal(context, client, &creds->client); + if (ret) + return ret; + ret = krb5_make_principal(context, &creds->server, client_realm, + KRB5_TGS_NAME, client_realm, NULL); + if (ret) { + krb5_free_principal(context, creds->client); + return ret; + } + + /* + * Optionally delegate a TGT for the server's realm, rather than + * the client's. Do this also when we don't have a client realm TGT. + * + * XXX: Note, when we have a start-realm, and delegate-destination-tgt + * is not set, we must use the start-realm. + */ + krb5_appdefault_boolean(context, NULL, server_realm, + "delegate-destination-tgt", FALSE, &fwd_dest_tgt); + + if (!fwd_dest_tgt) { + ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, creds, + &client_tgt); + if (ret == 0) { + krb5_free_creds(context, client_tgt); + return ret; + } + } + + /* + * Client TGT inapplicable or unavailable + */ + krb5_free_principal(context, creds->server); + creds->server = 0; + return krb5_make_principal(context, &creds->server, server_realm, + KRB5_TGS_NAME, server_realm, NULL); +} + +/* + * Obtain address list for hostname if server realm policy is not addressless. + */ +static krb5_error_code +get_addresses(krb5_context context, + krb5_ccache ccache, + krb5_creds *creds, + const char *hostname, + krb5_addresses *addrs) +{ + krb5_error_code ret; + krb5_creds *ticket; + krb5_const_realm realm; + krb5_boolean noaddr; + struct addrinfo *ai; + int eai; + + if (hostname == 0) + return 0; + + ret = krb5_get_credentials(context, 0, ccache, creds, &ticket); + if (ret == 0) { + noaddr = (ticket->addresses.len == 0) ? TRUE : FALSE; + krb5_free_creds(context, ticket); + } else { + realm = krb5_principal_get_realm(context, creds->server); + krb5_appdefault_boolean(context, NULL, realm, "no-addresses", + KRB5_ADDRESSLESS_DEFAULT, &noaddr); + } + + if (noaddr) + return 0; + + /* Need addresses, get the address of the remote host. */ + + eai = getaddrinfo (hostname, NULL, NULL, &ai); + if (eai) { + ret = krb5_eai_to_heim_errno(eai, errno); + krb5_set_error_message(context, ret, + N_("resolving host %s failed: %s", + "hostname, error"), + hostname, gai_strerror(eai)); + return ret; + } + + ret = add_addrs(context, addrs, ai); + freeaddrinfo(ai); + + return ret; +} diff --git a/third_party/heimdal/lib/krb5/get_host_realm.c b/third_party/heimdal/lib/krb5/get_host_realm.c new file mode 100644 index 0000000..7b58fe9 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_host_realm.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +#include + +/* To automagically find the correct realm of a host (without + * [domain_realm] in krb5.conf) add a text record for your domain with + * the name of your realm, like this: + * + * _kerberos IN TXT "FOO.SE" + * + * The search is recursive, so you can add entries for specific + * hosts. To find the realm of host a.b.c, it first tries + * _kerberos.a.b.c, then _kerberos.b.c and so on. + * + * This method is described in draft-ietf-cat-krb-dns-locate-03.txt. + * + */ + +static int +copy_txt_to_realms(krb5_context context, + const char *domain, + struct rk_resource_record *head, + krb5_realm **realms) +{ + struct rk_resource_record *rr; + unsigned int n, i; + + for(n = 0, rr = head; rr; rr = rr->next) + if (rr->type == rk_ns_t_txt) + ++n; + + if (n == 0) + return -1; + + *realms = malloc ((n + 1) * sizeof(krb5_realm)); + if (*realms == NULL) + return krb5_enomem(context);; + + for (i = 0; i < n + 1; ++i) + (*realms)[i] = NULL; + + for (i = 0, rr = head; rr; rr = rr->next) { + if (rr->type == rk_ns_t_txt) { + char *tmp = NULL; + int invalid_tld = 1; + + /* Check for a gTLD controlled interruption */ + if (strcmp("Your DNS configuration needs immediate " + "attention see https://icann.org/namecollision", + rr->u.txt) != 0) { + invalid_tld = 0; + tmp = strdup(rr->u.txt); + } + if (tmp == NULL) { + for (i = 0; i < n; ++i) + free ((*realms)[i]); + free (*realms); + if (invalid_tld) { + krb5_warnx(context, + "Realm lookup failed: " + "Domain '%s' needs immediate attention " + "see https://icann.org/namecollision", + domain); + return KRB5_KDC_UNREACH; + } + return krb5_enomem(context);; + } + (*realms)[i] = tmp; + ++i; + } + } + return 0; +} + +static int +dns_find_realm(krb5_context context, + const char *domain, + krb5_realm **realms) +{ + static const char *const default_labels[] = { "_kerberos", NULL }; + char dom[MAXHOSTNAMELEN]; + struct rk_dns_reply *r; + const char *const *labels; + char **config_labels; + int i, ret = 0; + + config_labels = krb5_config_get_strings(context, NULL, "libdefaults", + "dns_lookup_realm_labels", NULL); + if(config_labels != NULL) + labels = (const char *const *)config_labels; + else + labels = default_labels; + if(*domain == '.') + domain++; + for (i = 0; labels[i] != NULL; i++) { + ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); + if(ret < 0 || (size_t)ret >= sizeof(dom)) { + ret = krb5_enomem(context); + goto out; + } + r = rk_dns_lookup(dom, "TXT"); + if(r != NULL) { + ret = copy_txt_to_realms(context, domain, r->head, realms); + rk_dns_free_data(r); + if(ret == 0) + goto out; + } + } + krb5_set_error_message(context, KRB5_KDC_UNREACH, + "Realm lookup failed: " + "No DNS TXT record for %s", + domain); + ret = KRB5_KDC_UNREACH; +out: + if (config_labels) + krb5_config_free_strings(config_labels); + return ret; +} + +/* + * Try to figure out what realms host in `domain' belong to from the + * configuration file. + */ + +static int +config_find_realm(krb5_context context, + const char *domain, + krb5_realm **realms) +{ + char **tmp = krb5_config_get_strings (context, NULL, + "domain_realm", + domain, + NULL); + + if (tmp == NULL) + return -1; + *realms = tmp; + return 0; +} + +/* + * This function assumes that `host' is a FQDN (and doesn't handle the + * special case of host == NULL either). + * Try to find mapping in the config file or DNS and it that fails, + * fall back to guessing + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_get_host_realm_int(krb5_context context, + const char *host, + krb5_boolean use_dns, + krb5_realm **realms) +{ + const char *p, *q; + const char *port; + char *freeme = NULL; + krb5_boolean dns_locate_enable; + krb5_error_code ret = 0; + + /* Strip off any trailing ":port" suffix. */ + port = strchr(host, ':'); + if (port != NULL && port != host && port[1] != '\0') { + host = freeme = strndup(host, port - host); + if (host == NULL) + return krb5_enomem(context); + } + + dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, + "libdefaults", "dns_lookup_realm", NULL); + for (p = host; p != NULL && p[0] != '\0'; p = strchr (p + 1, '.')) { + if (config_find_realm(context, p, realms) == 0) { + if (strcasecmp(*realms[0], "dns_locate") != 0) + break; + krb5_free_host_realm(context, *realms); + *realms = NULL; + if (!use_dns) + continue; + for (q = host; q != NULL; q = strchr(q + 1, '.')) + if (dns_find_realm(context, q, realms) == 0) + break; + if (q) + break; + } else if (use_dns && dns_locate_enable) { + if (dns_find_realm(context, p, realms) == 0) + break; + } + } + + /* + * If 'p' is NULL, we did not find an explicit realm mapping in either the + * configuration file or DNS. Try the hostname suffix -upcased- as a realm + * as a last resort. + * + * NOTE: If we implement a KDC-specific variant of this function just for + * referrals, we could check whether we have a cross-realm TGT for the + * realm in question, and if not try the parent (loop again). Such a + * variant would have to have access to the HDB, naturally. + * + * We should start by adding an argument to this function that + * indicates whether this fallback here is desired (the KDC wouldn't + * desire it). Then when the KDC gets KRB5_ERR_HOST_REALM_UNKNOWN + * from this function, the KDC would search the HDB for cross-realm + * krbtgt principals that denote a hierarchical path to a realm that + * matches the host's domain suffix (or a suffix of it...). + */ + if (p == NULL) { + p = strchr(host, '.'); + if (p != NULL) { + p++; + *realms = malloc(2 * sizeof(krb5_realm)); + if (*realms != NULL && + ((*realms)[0] = strdup(p)) != NULL) { + strupr((*realms)[0]); + (*realms)[1] = NULL; + } else { + free(*realms); + ret = krb5_enomem(context); + } + } else { + krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, + N_("unable to find realm of host %s", ""), + host); + ret = KRB5_ERR_HOST_REALM_UNKNOWN; + } + } + + free(freeme); + return ret; +} + +/* + * Return the realm(s) of `host' as a NULL-terminated list in + * `realms'. Free `realms' with krb5_free_host_realm(). + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_host_realm(krb5_context context, + const char *targethost, + krb5_realm **realms) +{ + const char *host = targethost; + char hostname[MAXHOSTNAMELEN]; + krb5_error_code ret; + int use_dns; + + if (host == NULL) { + if (gethostname (hostname, sizeof(hostname))) { + *realms = NULL; + return errno; + } + host = hostname; + } + + /* + * If our local hostname is without components, don't even try to dns. + */ + + use_dns = (strchr(host, '.') != NULL); + + ret = _krb5_get_host_realm_int (context, host, use_dns, realms); + if (ret && targethost != NULL) { + /* + * If there was no realm mapping for the host (and we wasn't + * looking for ourself), guess at the local realm, maybe our + * KDC knows better then we do and we get a referral back. + */ + ret = krb5_get_default_realms(context, realms); + if (ret) { + krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, + N_("Unable to find realm of host %s", ""), + host); + return KRB5_ERR_HOST_REALM_UNKNOWN; + } + } + return ret; +} diff --git a/third_party/heimdal/lib/krb5/get_in_tkt.c b/third_party/heimdal/lib/krb5/get_in_tkt.c new file mode 100644 index 0000000..476844c --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_in_tkt.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define KRB5_DEPRECATED_FUNCTION(x) + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER + +static krb5_error_code +make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, + krb5_enctype etype, krb5_keyblock *key) +{ + PA_ENC_TS_ENC p; + unsigned char *buf; + size_t buf_size; + size_t len = 0; + EncryptedData encdata; + krb5_error_code ret; + int32_t usec; + int usec2; + krb5_crypto crypto; + + krb5_us_timeofday (context, &p.patimestamp, &usec); + usec2 = usec; + p.pausec = &usec2; + + ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free(buf); + return ret; + } + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, + buf, + len, + 0, + &encdata); + free(buf); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); + free_EncryptedData(&encdata); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; + pa->padata_value.length = len; + pa->padata_value.data = buf; + return 0; +} + +static krb5_error_code +add_padata(krb5_context context, + METHOD_DATA *md, + krb5_principal client, + krb5_key_proc key_proc, + krb5_const_pointer keyseed, + krb5_enctype *enctypes, + unsigned netypes, + krb5_salt *salt) +{ + krb5_error_code ret; + PA_DATA *pa2; + krb5_salt salt2; + krb5_enctype *ep; + size_t i; + + if(salt == NULL) { + /* default to standard salt */ + ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; + salt = &salt2; + } + if (!enctypes) { + enctypes = context->etypes; + netypes = 0; + for (ep = enctypes; *ep != ETYPE_NULL; ep++) + netypes++; + } + pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val)); + if (pa2 == NULL) + return krb5_enomem(context); + md->val = pa2; + + for (i = 0; i < netypes; ++i) { + krb5_keyblock *key; + + ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key); + if (ret) + continue; + ret = make_pa_enc_timestamp (context, &md->val[md->len], + enctypes[i], key); + krb5_free_keyblock (context, key); + if (ret) + return ret; + ++md->len; + } + if(salt == &salt2) + krb5_free_salt(context, salt2); + return 0; +} + +static krb5_error_code +init_as_req (krb5_context context, + KDCOptions opts, + krb5_creds *creds, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *ptypes, + const krb5_preauthdata *preauth, + krb5_key_proc key_proc, + krb5_const_pointer keyseed, + unsigned nonce, + AS_REQ *a) +{ + krb5_error_code ret; + krb5_salt salt; + + memset(a, 0, sizeof(*a)); + + a->pvno = 5; + a->msg_type = krb_as_req; + a->req_body.kdc_options = opts; + a->req_body.cname = malloc(sizeof(*a->req_body.cname)); + if (a->req_body.cname == NULL) { + ret = krb5_enomem(context); + goto fail; + } + a->req_body.sname = malloc(sizeof(*a->req_body.sname)); + if (a->req_body.sname == NULL) { + ret = krb5_enomem(context); + goto fail; + } + ret = _krb5_principal2principalname (a->req_body.cname, creds->client); + if (ret) + goto fail; + ret = _krb5_principal2principalname (a->req_body.sname, creds->server); + if (ret) + goto fail; + ret = copy_Realm(&creds->client->realm, &a->req_body.realm); + if (ret) + goto fail; + + if(creds->times.starttime) { + a->req_body.from = malloc(sizeof(*a->req_body.from)); + if (a->req_body.from == NULL) { + ret = krb5_enomem(context); + goto fail; + } + *a->req_body.from = creds->times.starttime; + } + if(creds->times.endtime){ + ALLOC(a->req_body.till, 1); + *a->req_body.till = creds->times.endtime; + } + if(creds->times.renew_till){ + a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); + if (a->req_body.rtime == NULL) { + ret = krb5_enomem(context); + goto fail; + } + *a->req_body.rtime = creds->times.renew_till; + } + a->req_body.nonce = nonce; + ret = _krb5_init_etype(context, + KRB5_PDU_AS_REQUEST, + &a->req_body.etype.len, + &a->req_body.etype.val, + etypes); + if (ret) + goto fail; + + /* + * This means no addresses + */ + + if (addrs && addrs->len == 0) { + a->req_body.addresses = NULL; + } else { + a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); + if (a->req_body.addresses == NULL) { + ret = krb5_enomem(context); + goto fail; + } + + if (addrs) + ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); + else { + ret = krb5_get_all_client_addrs (context, a->req_body.addresses); + if(ret == 0 && a->req_body.addresses->len == 0) { + free(a->req_body.addresses); + a->req_body.addresses = NULL; + } + } + if (ret) + return ret; + } + + a->req_body.enc_authorization_data = NULL; + a->req_body.additional_tickets = NULL; + + if(preauth != NULL) { + size_t i; + ALLOC(a->padata, 1); + if(a->padata == NULL) { + ret = krb5_enomem(context); + goto fail; + } + a->padata->val = NULL; + a->padata->len = 0; + for(i = 0; i < preauth->len; i++) { + if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){ + size_t j; + + for(j = 0; j < preauth->val[i].info.len; j++) { + krb5_salt *sp = &salt; + if(preauth->val[i].info.val[j].salttype) + salt.salttype = *preauth->val[i].info.val[j].salttype; + else + salt.salttype = KRB5_PW_SALT; + if(preauth->val[i].info.val[j].salt) + salt.saltvalue = *preauth->val[i].info.val[j].salt; + else + if(salt.salttype == KRB5_PW_SALT) + sp = NULL; + else + krb5_data_zero(&salt.saltvalue); + ret = add_padata(context, a->padata, creds->client, + key_proc, keyseed, + &preauth->val[i].info.val[j].etype, 1, + sp); + if (ret == 0) + break; + } + } + } + } else + /* not sure this is the way to use `ptypes' */ + if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE) + a->padata = NULL; + else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) { + ALLOC(a->padata, 1); + if (a->padata == NULL) { + ret = krb5_enomem(context); + goto fail; + } + a->padata->len = 0; + a->padata->val = NULL; + + /* make a v5 salted pa-data */ + add_padata(context, a->padata, creds->client, + key_proc, keyseed, a->req_body.etype.val, + a->req_body.etype.len, NULL); + + /* make a v4 salted pa-data */ + salt.salttype = KRB5_PW_SALT; + krb5_data_zero(&salt.saltvalue); + add_padata(context, a->padata, creds->client, + key_proc, keyseed, a->req_body.etype.val, + a->req_body.etype.len, &salt); + } else { + ret = KRB5_PREAUTH_BAD_TYPE; + krb5_set_error_message (context, ret, + N_("pre-auth type %d not supported", ""), + *ptypes); + goto fail; + } + return 0; +fail: + free_AS_REQ(a); + return ret; +} + +static int +set_ptypes(krb5_context context, + KRB_ERROR *error, + const krb5_preauthtype **ptypes, + krb5_preauthdata **preauth) +{ + static krb5_preauthdata preauth2; + static const krb5_preauthtype ptypes2[] = { + KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE + }; + + if(error->e_data) { + METHOD_DATA md; + size_t i; + decode_METHOD_DATA(error->e_data->data, + error->e_data->length, + &md, + NULL); + for(i = 0; i < md.len; i++){ + switch(md.val[i].padata_type){ + case KRB5_PADATA_ENC_TIMESTAMP: + *ptypes = ptypes2; + break; + case KRB5_PADATA_ETYPE_INFO: + *preauth = &preauth2; + ALLOC_SEQ(*preauth, 1); + (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP; + decode_ETYPE_INFO(md.val[i].padata_value.data, + md.val[i].padata_value.length, + &(*preauth)->val[0].info, + NULL); + break; + default: + break; + } + } + free_METHOD_DATA(&md); + } else { + *ptypes = ptypes2; + } + return(1); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_in_cred(krb5_context context, + krb5_flags options, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *ptypes, + const krb5_preauthdata *preauth, + krb5_key_proc key_proc, + krb5_const_pointer keyseed, + krb5_decrypt_proc decrypt_proc, + krb5_const_pointer decryptarg, + krb5_creds *creds, + krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_error_code ret; + AS_REQ a; + krb5_kdc_rep rep; + krb5_data req, resp; + size_t len = 0; + krb5_salt salt; + krb5_keyblock *key; + size_t size; + KDCOptions opts; + PA_DATA *pa; + krb5_enctype etype; + krb5_preauthdata *my_preauth = NULL; + unsigned nonce; + int done; + + opts = int2KDCOptions(options); + + krb5_generate_random_block (&nonce, sizeof(nonce)); + nonce &= 0xffffffff; + + do { + done = 1; + ret = init_as_req (context, + opts, + creds, + addrs, + etypes, + ptypes, + preauth, + key_proc, + keyseed, + nonce, + &a); + if (my_preauth) { + free_ETYPE_INFO(&my_preauth->val[0].info); + free (my_preauth->val); + my_preauth = NULL; + } + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret); + free_AS_REQ(&a); + if (ret) + return ret; + if(len != req.length) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp); + krb5_data_free(&req); + if (ret) + return ret; + + memset (&rep, 0, sizeof(rep)); + ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); + if(ret) { + /* let's try to parse it as a KRB-ERROR */ + KRB_ERROR error; + int ret2; + + ret2 = krb5_rd_error(context, &resp, &error); + if(ret2 && resp.data && ((char*)resp.data)[0] == 4) + ret = KRB5KRB_AP_ERR_V4_REPLY; + krb5_data_free(&resp); + if (ret2 == 0) { + ret = krb5_error_from_rd_error(context, &error, creds); + /* if no preauth was set and KDC requires it, give it + one more try */ + if (!ptypes && !preauth + && ret == KRB5KDC_ERR_PREAUTH_REQUIRED + && set_ptypes(context, &error, &ptypes, &my_preauth)) { + done = 0; + preauth = my_preauth; + krb5_free_error_contents(context, &error); + krb5_clear_error_message(context); + continue; + } + if(ret_as_reply) + ret_as_reply->error = error; + else + free_KRB_ERROR (&error); + return ret; + } + return ret; + } + krb5_data_free(&resp); + } while(!done); + + pa = NULL; + etype = rep.kdc_rep.enc_part.etype; + if(rep.kdc_rep.padata){ + int i = 0; + pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, + KRB5_PADATA_PW_SALT, &i); + if(pa == NULL) { + i = 0; + pa = krb5_find_padata(rep.kdc_rep.padata->val, + rep.kdc_rep.padata->len, + KRB5_PADATA_AFS3_SALT, &i); + } + } + if(pa) { + salt.salttype = (krb5_salttype)pa->padata_type; + salt.saltvalue = pa->padata_value; + + ret = (*key_proc)(context, etype, salt, keyseed, &key); + } else { + /* make a v5 salted pa-data */ + ret = krb5_get_pw_salt (context, creds->client, &salt); + + if (ret) + goto out; + ret = (*key_proc)(context, etype, salt, keyseed, &key); + krb5_free_salt(context, salt); + } + if (ret) + goto out; + + { + unsigned flags = EXTRACT_TICKET_TIMESYNC; + if (opts.request_anonymous) + flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH | EXTRACT_TICKET_MATCH_ANON; + + ret = _krb5_extract_ticket(context, + &rep, + creds, + key, + keyseed, + KRB5_KU_AS_REP_ENC_PART, + NULL, + nonce, + flags, + NULL, + decrypt_proc, + decryptarg); + } + memset (key->keyvalue.data, 0, key->keyvalue.length); + krb5_free_keyblock_contents (context, key); + free (key); + +out: + if (ret == 0 && ret_as_reply) + *ret_as_reply = rep; + else + krb5_free_kdc_rep (context, &rep); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_in_tkt(krb5_context context, + krb5_flags options, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + const krb5_preauthtype *ptypes, + krb5_key_proc key_proc, + krb5_const_pointer keyseed, + krb5_decrypt_proc decrypt_proc, + krb5_const_pointer decryptarg, + krb5_creds *creds, + krb5_ccache ccache, + krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + krb5_error_code ret; + + ret = krb5_get_in_cred (context, + options, + addrs, + etypes, + ptypes, + NULL, + key_proc, + keyseed, + decrypt_proc, + decryptarg, + creds, + ret_as_reply); + if(ret) + return ret; + if (ccache) + ret = krb5_cc_store_cred (context, ccache, creds); + return ret; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/get_port.c b/third_party/heimdal/lib/krb5/get_port.c new file mode 100644 index 0000000..93d9433 --- /dev/null +++ b/third_party/heimdal/lib/krb5/get_port.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997-2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +KRB5_LIB_FUNCTION int KRB5_LIB_CALL +krb5_getportbyname (krb5_context context, + const char *service, + const char *proto, + int default_port) +{ + struct servent *sp; + + if ((sp = roken_getservbyname (service, proto)) == NULL) { +#if 0 + krb5_warnx(context, "%s/%s unknown service, using default port %d", + service, proto, default_port); +#endif + return htons(default_port); + } else + return sp->s_port; +} diff --git a/third_party/heimdal/lib/krb5/init_creds.c b/third_party/heimdal/lib/krb5/init_creds.c new file mode 100644 index 0000000..6e77578 --- /dev/null +++ b/third_party/heimdal/lib/krb5/init_creds.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#undef __attribute__ +#define __attribute__(x) + +/** + * @page krb5_init_creds_intro The initial credential handing functions + * @section section_krb5_init_creds Initial credential + * + * Functions to get initial credentials: @ref krb5_credential . + */ + +/** + * Allocate a new krb5_get_init_creds_opt structure, free with + * krb5_get_init_creds_opt_free(). + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_alloc(krb5_context context, + krb5_get_init_creds_opt **opt) +{ + krb5_get_init_creds_opt *o; + + *opt = NULL; + o = calloc(1, sizeof(*o)); + if (o == NULL) + return krb5_enomem(context); + + o->opt_private = calloc(1, sizeof(*o->opt_private)); + if (o->opt_private == NULL) { + free(o); + return krb5_enomem(context); + } + o->opt_private->refcount = 1; + *opt = o; + return 0; +} + +/** + * Free krb5_get_init_creds_opt structure. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_free(krb5_context context, + krb5_get_init_creds_opt *opt) +{ + if (opt == NULL || opt->opt_private == NULL) + return; + if (opt->opt_private->refcount < 1) /* abort ? */ + return; + if (--opt->opt_private->refcount == 0) { + _krb5_get_init_creds_opt_free_pkinit(opt); + free(opt->opt_private->fast_armor_ccache_name); + free(opt->opt_private); + } + memset(opt, 0, sizeof(*opt)); + free(opt); +} + +static int +get_config_time (krb5_context context, + const char *realm, + const char *name, + int def) +{ + int ret; + + ret = krb5_config_get_time (context, NULL, + "realms", + realm, + name, + NULL); + if (ret >= 0) + return ret; + ret = krb5_config_get_time (context, NULL, + "libdefaults", + name, + NULL); + if (ret >= 0) + return ret; + return def; +} + +static krb5_boolean +get_config_bool (krb5_context context, + krb5_boolean def_value, + const char *realm, + const char *name) +{ + krb5_boolean b; + + b = krb5_config_get_bool_default(context, NULL, def_value, + "realms", realm, name, NULL); + if (b != def_value) + return b; + b = krb5_config_get_bool_default (context, NULL, def_value, + "libdefaults", name, NULL); + if (b != def_value) + return b; + return def_value; +} + +/* + * set all the values in `opt' to the appropriate values for + * application `appname' (default to getprogname() if NULL), and realm + * `realm'. First looks in [appdefaults] but falls back to + * [realms] or [libdefaults] for some of the values. + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_default_flags(krb5_context context, + const char *appname, + krb5_const_realm realm, + krb5_get_init_creds_opt *opt) +{ + krb5_boolean b; + time_t t; + + b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT, + realm, "forwardable"); + krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b); + krb5_get_init_creds_opt_set_forwardable(opt, b); + + b = get_config_bool (context, FALSE, realm, "proxiable"); + krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b); + krb5_get_init_creds_opt_set_proxiable (opt, b); + + krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t); + if (t == 0) + t = get_config_time (context, realm, "ticket_lifetime", 0); + if(t != 0) + krb5_get_init_creds_opt_set_tkt_life(opt, t); + + krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t); + if (t == 0) + t = get_config_time (context, realm, "renew_lifetime", 0); + if(t != 0) + krb5_get_init_creds_opt_set_renew_life(opt, t); + + krb5_appdefault_boolean(context, appname, realm, "no-addresses", + KRB5_ADDRESSLESS_DEFAULT, &b); + krb5_get_init_creds_opt_set_addressless (context, opt, b); + +#if 0 + krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b); + krb5_get_init_creds_opt_set_anonymous (opt, b); + + krb5_get_init_creds_opt_set_etype_list(opt, enctype, + etype_str.num_strings); + + krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, + krb5_data *salt); + + krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, + krb5_preauthtype *preauth_list, + int preauth_list_length); +#endif +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_change_password_prompt(krb5_get_init_creds_opt *opt, + int change_password_prompt) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT; + opt->change_password_prompt = change_password_prompt; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt, + krb5_deltat tkt_life) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE; + opt->tkt_life = tkt_life; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt, + krb5_deltat renew_life) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE; + opt->renew_life = renew_life; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt, + int forwardable) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE; + opt->forwardable = forwardable; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt, + int proxiable) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE; + opt->proxiable = proxiable; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, + krb5_enctype *etype_list, + int etype_list_length) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST; + opt->etype_list = etype_list; + opt->etype_list_length = etype_list_length; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt, + krb5_addresses *addresses) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST; + opt->address_list = addresses; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, + krb5_preauthtype *preauth_list, + int preauth_list_length) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST; + opt->preauth_list_length = preauth_list_length; + opt->preauth_list = preauth_list; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, + krb5_data *salt) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT; + opt->salt = salt; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt, + int anonymous) +{ + opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; + opt->anonymous = anonymous; +} + +static krb5_error_code +require_ext_opt(krb5_context context, + krb5_get_init_creds_opt *opt, + const char *type) +{ + if (opt->opt_private == NULL) { + krb5_set_error_message(context, EINVAL, + N_("%s on non extendable opt", ""), type); + return EINVAL; + } + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_pa_password(krb5_context context, + krb5_get_init_creds_opt *opt, + const char *password, + krb5_s2k_proc key_proc) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password"); + if (ret) + return ret; + opt->opt_private->password = password; + opt->opt_private->key_proc = key_proc; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_pac_request(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_boolean req_pac) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req"); + if (ret) + return ret; + opt->opt_private->req_pac = req_pac ? + KRB5_INIT_CREDS_TRISTATE_TRUE : + KRB5_INIT_CREDS_TRISTATE_FALSE; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_addressless(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_boolean addressless) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req"); + if (ret) + return ret; + if (addressless) + opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_TRUE; + else + opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_FALSE; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_canonicalize(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_boolean req) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_canonicalize"); + if (ret) + return ret; + if (req) + opt->opt_private->flags |= KRB5_INIT_CREDS_CANONICALIZE; + else + opt->opt_private->flags &= ~KRB5_INIT_CREDS_CANONICALIZE; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_win2k(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_boolean req) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k"); + if (ret) + return ret; + if (req) { + opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK; + opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK; + opt->opt_private->flags |= KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK; + } else { + opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_CANON_CHECK; + opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK; + opt->opt_private->flags &= ~KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK; + } + return 0; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_process_last_req(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_gic_process_last_req func, + void *ctx) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_process_last_req"); + if (ret) + return ret; + + opt->opt_private->lr.func = func; + opt->opt_private->lr.ctx = ctx; + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_ccache(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_ccache fast_ccache) +{ + char *fast_ccache_name; + int ret = krb5_cc_get_full_name(context, + fast_ccache, + &fast_ccache_name); + if (ret) + return ret; + + ret = krb5_get_init_creds_opt_set_fast_ccache_name(context, + opt, + fast_ccache_name); + krb5_xfree(fast_ccache_name); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_ccache_name(krb5_context context, + krb5_get_init_creds_opt *opt, + const char *fast_ccache_name) +{ + if (opt->opt_private->fast_armor_ccache_name) + free(opt->opt_private->fast_armor_ccache_name); + + opt->opt_private->fast_armor_ccache_name = strdup(fast_ccache_name); + if (opt->opt_private->fast_armor_ccache_name == NULL) + return krb5_enomem(context); + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_flags(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_flags flags) +{ + heim_assert((flags & ~KRB5_FAST_PUBLIC_FLAGS) == 0, "invalid flags passed to krb5_get_init_creds_opt_set_fast_flags()"); + opt->opt_private->fast_flags = flags; + return 0; +} + + + +#ifndef HEIMDAL_SMALLER + +/** + * Deprecated: use krb5_get_init_creds_opt_alloc(). + * + * The reason krb5_get_init_creds_opt_init() is deprecated is that + * krb5_get_init_creds_opt is a static structure and for ABI reason it + * can't grow, ie can't add new functionality. + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) + KRB5_DEPRECATED_FUNCTION("Use krb5_get_init_creds_opt_alloc instead") +{ + memset (opt, 0, sizeof(*opt)); +} + +/** + * Deprecated: use the new krb5_init_creds_init() and + * krb5_init_creds_get_error(). + * + * @ingroup krb5_deprecated + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_get_error(krb5_context context, + krb5_get_init_creds_opt *opt, + KRB_ERROR **error) + KRB5_DEPRECATED_FUNCTION("Use X instead") +{ + *error = calloc(1, sizeof(**error)); + if (*error == NULL) + return krb5_enomem(context); + + return 0; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/init_creds_pw.c b/third_party/heimdal/lib/krb5/init_creds_pw.c new file mode 100644 index 0000000..4790c7e --- /dev/null +++ b/third_party/heimdal/lib/krb5/init_creds_pw.c @@ -0,0 +1,4052 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2021, PADL Software Pty Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#include + +struct pa_info_data { + krb5_enctype etype; + krb5_salt salt; + krb5_data *s2kparams; +}; + +struct krb5_gss_init_ctx_data { + krb5_gssic_step step; + krb5_gssic_finish finish; + krb5_gssic_release_cred release_cred; + krb5_gssic_delete_sec_context delete_sec_context; + + const struct gss_OID_desc_struct *mech; + struct gss_cred_id_t_desc_struct *cred; + + struct { + unsigned int release_cred : 1; + } flags; +}; + +struct krb5_get_init_creds_ctx { + KDCOptions flags; + krb5_creds cred; + const krb5_addresses *addrs; + krb5_enctype *etypes; + krb5_preauthtype *pre_auth_types; + char *in_tkt_service; + unsigned nonce; + unsigned pk_nonce; + + krb5_data req_buffer; + AS_REQ as_req; + int pa_counter; + + /* password and keytab_data is freed on completion */ + char *password; + krb5_keytab_key_proc_args *keytab_data; + + krb5_pointer *keyseed; + krb5_s2k_proc keyproc; + + krb5_get_init_creds_tristate req_pac; + + krb5_pk_init_ctx pk_init_ctx; + krb5_gss_init_ctx gss_init_ctx; + int ic_flags; + + char *kdc_hostname; + char *sitename; + + struct { + unsigned int change_password:1; + unsigned int change_password_prompt:1; + unsigned int allow_enc_pa_rep:1; + unsigned int allow_save_as_reply_key:1; + } runflags; + + struct pa_info_data paid; + + METHOD_DATA md; + KRB_ERROR error; + EncKDCRepPart enc_part; + + krb5_prompter_fct prompter; + void *prompter_data; + int warned_user; + + struct pa_info_data *ppaid; + + struct krb5_fast_state fast_state; + krb5_enctype as_enctype; + krb5_keyblock *as_reply_key; + + /* current and available pa mechansm in this exchange */ + struct pa_auth_mech *pa_mech; + heim_array_t available_pa_mechs; + const char *pa_used; + + struct { + struct timeval run_time; + } stats; +}; + +static void +free_paid(krb5_context context, struct pa_info_data *ppaid) +{ + krb5_free_salt(context, ppaid->salt); + if (ppaid->s2kparams) + krb5_free_data(context, ppaid->s2kparams); + memset(ppaid, 0, sizeof(*ppaid)); +} + +static krb5_error_code KRB5_CALLCONV +default_s2k_func(krb5_context context, krb5_enctype type, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + krb5_error_code ret; + krb5_data password; + krb5_data opaque; + + if (_krb5_have_debug(context, 5)) { + char *str = NULL; + ret = krb5_enctype_to_string(context, type, &str); + if (ret) + return ret; + + _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func: %s (%d)", str, (int)type); + free(str); + } + + password.data = rk_UNCONST(keyseed); + password.length = keyseed ? strlen(keyseed) : 0; + if (s2kparms) + opaque = *s2kparms; + else + krb5_data_zero(&opaque); + + *key = malloc(sizeof(**key)); + if (*key == NULL) + return krb5_enomem(context); + ret = krb5_string_to_key_data_salt_opaque(context, type, password, + salt, opaque, *key); + if (ret) { + free(*key); + *key = NULL; + } + return ret; +} + +static void +free_gss_init_ctx(krb5_context context, krb5_gss_init_ctx gssic) +{ + if (gssic == NULL) + return; + + if (gssic->flags.release_cred) + gssic->release_cred(context, gssic, gssic->cred); + free(gssic); +} + +static void +free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) +{ + if (ctx->etypes) + free(ctx->etypes); + if (ctx->pre_auth_types) + free (ctx->pre_auth_types); + if (ctx->in_tkt_service) + free(ctx->in_tkt_service); + if (ctx->keytab_data) + free(ctx->keytab_data); + if (ctx->password) { + size_t len; + len = strlen(ctx->password); + memset_s(ctx->password, len, 0, len); + free(ctx->password); + } + free_gss_init_ctx(context, ctx->gss_init_ctx); + /* + * FAST state + */ + _krb5_fast_free(context, &ctx->fast_state); + if (ctx->as_reply_key) + krb5_free_keyblock(context, ctx->as_reply_key); + + krb5_data_free(&ctx->req_buffer); + krb5_free_cred_contents(context, &ctx->cred); + free_METHOD_DATA(&ctx->md); + free_EncKDCRepPart(&ctx->enc_part); + free_KRB_ERROR(&ctx->error); + free_AS_REQ(&ctx->as_req); + + heim_release(ctx->available_pa_mechs); + heim_release(ctx->pa_mech); + ctx->pa_mech = NULL; + free(ctx->kdc_hostname); + free(ctx->sitename); + free_paid(context, &ctx->paid); + memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); +} + +static krb5_deltat +get_config_time (krb5_context context, + const char *realm, + const char *name, + int def) +{ + krb5_deltat ret; + + ret = krb5_config_get_time (context, NULL, + "realms", + realm, + name, + NULL); + if (ret >= 0) + return ret; + ret = krb5_config_get_time (context, NULL, + "libdefaults", + name, + NULL); + if (ret >= 0) + return ret; + return def; +} + +static krb5_error_code +init_cred (krb5_context context, + krb5_creds *cred, + krb5_principal client, + krb5_deltat start_time, + krb5_get_init_creds_opt *options) +{ + krb5_error_code ret; + krb5_deltat tmp; + krb5_timestamp now; + + krb5_timeofday (context, &now); + + memset (cred, 0, sizeof(*cred)); + + if (client) + ret = krb5_copy_principal(context, client, &cred->client); + else + ret = krb5_get_default_principal(context, &cred->client); + if (ret) + goto out; + + if (start_time) + cred->times.starttime = now + start_time; + + if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE) + tmp = options->tkt_life; + else + tmp = KRB5_TKT_LIFETIME_DEFAULT; + cred->times.endtime = now + tmp; + + if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) { + if (options->renew_life > 0) + tmp = options->renew_life; + else + tmp = KRB5_TKT_RENEW_LIFETIME_DEFAULT; + cred->times.renew_till = now + tmp; + } + + return 0; + +out: + krb5_free_cred_contents (context, cred); + return ret; +} + +/* + * Print a message (str) to the user about the expiration in `lr' + */ + +static void +report_expiration (krb5_context context, + krb5_prompter_fct prompter, + krb5_data *data, + const char *str, + time_t now) +{ + char *p = NULL; + + if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL) + return; + (*prompter)(context, data, NULL, p, 0, NULL); + free(p); +} + +/* + * Check the context, and in the case there is a expiration warning, + * use the prompter to print the warning. + * + * @param context A Kerberos 5 context. + * @param options An GIC options structure + * @param ctx The krb5_init_creds_context check for expiration. + */ + +krb5_error_code +krb5_process_last_request(krb5_context context, + krb5_get_init_creds_opt *options, + krb5_init_creds_context ctx) +{ + LastReq *lr; + size_t i; + + /* + * First check if there is a API consumer. + */ + + lr = &ctx->enc_part.last_req; + + if (options && options->opt_private && options->opt_private->lr.func) { + krb5_last_req_entry **lre; + + lre = calloc(lr->len + 1, sizeof(*lre)); + if (lre == NULL) + return krb5_enomem(context); + + for (i = 0; i < lr->len; i++) { + lre[i] = calloc(1, sizeof(*lre[i])); + if (lre[i] == NULL) + break; + lre[i]->lr_type = lr->val[i].lr_type; + lre[i]->value = lr->val[i].lr_value; + } + + (*options->opt_private->lr.func)(context, lre, + options->opt_private->lr.ctx); + + for (i = 0; i < lr->len; i++) + free(lre[i]); + free(lre); + } + + return krb5_init_creds_warn_user(context, ctx); +} + +/** + * Warn the user using prompter in the krb5_init_creds_context about + * possible password and account expiration. + * + * @param context a Kerberos 5 context. + * @param ctx a krb5_init_creds_context context. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_warn_user(krb5_context context, + krb5_init_creds_context ctx) +{ + krb5_timestamp sec; + krb5_const_realm realm; + krb5_enctype weak_enctype = KRB5_ENCTYPE_NULL; + LastReq *lr; + unsigned i; + time_t t; + + if (ctx->prompter == NULL) + return 0; + + if (ctx->warned_user) + return 0; + + ctx->warned_user = 1; + + krb5_timeofday (context, &sec); + + realm = krb5_principal_get_realm (context, ctx->cred.client); + lr = &ctx->enc_part.last_req; + + t = sec + get_config_time (context, + realm, + "warn_pwexpire", + 7 * 24 * 60 * 60); + + for (i = 0; i < lr->len; ++i) { + if (lr->val[i].lr_value <= t) { + switch (lr->val[i].lr_type) { + case LR_PW_EXPTIME : + report_expiration(context, ctx->prompter, + ctx->prompter_data, + "Your password will expire at ", + lr->val[i].lr_value); + break; + case LR_ACCT_EXPTIME : + report_expiration(context, ctx->prompter, + ctx->prompter_data, + "Your account will expire at ", + lr->val[i].lr_value); + break; + default: + break; + } + } + } + + if (krb5_is_enctype_weak(context, ctx->as_enctype)) + weak_enctype = ctx->as_enctype; + else if (krb5_is_enctype_weak(context, ctx->cred.session.keytype)) + weak_enctype = ctx->cred.session.keytype; + + if (ctx->prompter && weak_enctype != KRB5_ENCTYPE_NULL) { + int suppress = krb5_config_get_bool_default(context, NULL, false, + "libdefaults", + "suppress_weak_enctype", NULL); + if (!suppress) { + char *str = NULL, *p = NULL; + int aret; + + (void) krb5_enctype_to_string(context, weak_enctype, &str); + aret = asprintf(&p, "Encryption type %s(%d) used for authentication is weak and will be deprecated", + str ? str : "unknown", weak_enctype); + if (aret >= 0 && p) { + (*ctx->prompter)(context, ctx->prompter_data, NULL, p, 0, NULL); + free(p); + } + free(str); + } + } + + return 0; +} + +static const krb5_addresses no_addrs = { 0, NULL }; + +static krb5_error_code +get_init_creds_common(krb5_context context, + krb5_principal client, + krb5_prompter_fct prompter, + void *prompter_data, + krb5_deltat start_time, + krb5_get_init_creds_opt *options, + krb5_init_creds_context ctx) +{ + krb5_get_init_creds_opt *default_opt = NULL; + krb5_error_code ret; + krb5_enctype *etypes; + krb5_preauthtype *pre_auth_types; + + memset(ctx, 0, sizeof(*ctx)); + + if (options == NULL) { + const char *realm = krb5_principal_get_realm(context, client); + + ret = krb5_get_init_creds_opt_alloc(context, &default_opt); + if (ret) + return ret; + options = default_opt; + krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); + } + + if (options->opt_private) { + if (options->opt_private->password) { + ret = krb5_init_creds_set_password(context, ctx, + options->opt_private->password); + if (ret) + goto out; + } + + ctx->keyproc = options->opt_private->key_proc; + ctx->req_pac = options->opt_private->req_pac; + ctx->pk_init_ctx = options->opt_private->pk_init_ctx; + ctx->ic_flags = options->opt_private->flags; + } else + ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; + + if (ctx->keyproc == NULL) + ctx->keyproc = default_s2k_func; + + if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) + ctx->flags.canonicalize = 1; + if (krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) + ctx->flags.canonicalize = 1; + + ctx->pre_auth_types = NULL; + ctx->addrs = NULL; + ctx->etypes = NULL; + ctx->pre_auth_types = NULL; + + ret = init_cred(context, &ctx->cred, client, start_time, options); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, NULL); + if (ret) + goto out; + + if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) + ctx->flags.forwardable = options->forwardable; + + if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE) + ctx->flags.proxiable = options->proxiable; + + if (start_time) + ctx->flags.postdated = 1; + if (ctx->cred.times.renew_till) + ctx->flags.renewable = 1; + if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) { + ctx->addrs = options->address_list; + } else if (options->opt_private) { + switch (options->opt_private->addressless) { + case KRB5_INIT_CREDS_TRISTATE_UNSET: +#if KRB5_ADDRESSLESS_DEFAULT == TRUE + ctx->addrs = &no_addrs; +#else + ctx->addrs = NULL; +#endif + break; + case KRB5_INIT_CREDS_TRISTATE_FALSE: + ctx->addrs = NULL; + break; + case KRB5_INIT_CREDS_TRISTATE_TRUE: + ctx->addrs = &no_addrs; + break; + } + } + if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) { + if (ctx->etypes) + free(ctx->etypes); + + etypes = malloc((options->etype_list_length + 1) + * sizeof(krb5_enctype)); + if (etypes == NULL) { + ret = krb5_enomem(context); + goto out; + } + memcpy (etypes, options->etype_list, + options->etype_list_length * sizeof(krb5_enctype)); + etypes[options->etype_list_length] = ETYPE_NULL; + ctx->etypes = etypes; + } + if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { + pre_auth_types = malloc((options->preauth_list_length + 1) + * sizeof(krb5_preauthtype)); + if (pre_auth_types == NULL) { + ret = krb5_enomem(context); + goto out; + } + memcpy (pre_auth_types, options->preauth_list, + options->preauth_list_length * sizeof(krb5_preauthtype)); + pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; + ctx->pre_auth_types = pre_auth_types; + } + if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) + ctx->flags.request_anonymous = options->anonymous; + + ctx->prompter = prompter; + ctx->prompter_data = prompter_data; + + if ((options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT) && + !options->change_password_prompt) + ctx->runflags.change_password_prompt = 0; + else + ctx->runflags.change_password_prompt = ctx->prompter != NULL; + + if (options->opt_private->fast_armor_ccache_name) { + /* Open the caller-supplied FAST ccache and set the caller flags */ + ret = krb5_cc_resolve(context, options->opt_private->fast_armor_ccache_name, + &ctx->fast_state.armor_ccache); + if (ret) + goto out; + } + + ctx->fast_state.flags = options->opt_private->fast_flags; + + /* + * If FAST is required with a real credential cache, then the KDC + * will be verified. This allows the + * krb5_get_init_creds_opt_set_fast API to work like MIT without + * exposing KRB5_FAST_KDC_VERIFIED to callers + */ + if (ctx->fast_state.flags & KRB5_FAST_REQUIRED) + ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED; + + out: + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); + return ret; +} + +static krb5_error_code +change_password (krb5_context context, + krb5_principal client, + const char *password, + char *newpw, + size_t newpw_sz, + krb5_prompter_fct prompter, + void *data, + krb5_get_init_creds_opt *old_options) +{ + krb5_prompt prompts[2]; + krb5_error_code ret; + krb5_creds cpw_cred; + char buf1[BUFSIZ], buf2[BUFSIZ]; + krb5_data password_data[2]; + int result_code; + krb5_data result_code_string; + krb5_data result_string; + char *p; + krb5_get_init_creds_opt *options; + + heim_assert(prompter != NULL, "unexpected NULL prompter"); + + memset (&cpw_cred, 0, sizeof(cpw_cred)); + + ret = krb5_get_init_creds_opt_alloc(context, &options); + if (ret) + return ret; + krb5_get_init_creds_opt_set_tkt_life (options, 60); + krb5_get_init_creds_opt_set_forwardable (options, FALSE); + krb5_get_init_creds_opt_set_proxiable (options, FALSE); + if (old_options && + (old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) + krb5_get_init_creds_opt_set_preauth_list(options, + old_options->preauth_list, + old_options->preauth_list_length); + if (old_options && + (old_options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT)) + krb5_get_init_creds_opt_set_change_password_prompt(options, + old_options->change_password_prompt); + + krb5_data_zero (&result_code_string); + krb5_data_zero (&result_string); + + ret = krb5_get_init_creds_password (context, + &cpw_cred, + client, + password, + prompter, + data, + 0, + "kadmin/changepw", + options); + krb5_get_init_creds_opt_free(context, options); + if (ret) + goto out; + + for(;;) { + password_data[0].data = buf1; + password_data[0].length = sizeof(buf1); + + prompts[0].hidden = 1; + prompts[0].prompt = "New password: "; + prompts[0].reply = &password_data[0]; + prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD; + + password_data[1].data = buf2; + password_data[1].length = sizeof(buf2); + + prompts[1].hidden = 1; + prompts[1].prompt = "Repeat new password: "; + prompts[1].reply = &password_data[1]; + prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN; + + ret = (*prompter) (context, data, NULL, "Changing password", + 2, prompts); + if (ret) { + memset (buf1, 0, sizeof(buf1)); + memset (buf2, 0, sizeof(buf2)); + goto out; + } + + if (strcmp (buf1, buf2) == 0) + break; + memset (buf1, 0, sizeof(buf1)); + memset (buf2, 0, sizeof(buf2)); + } + + ret = krb5_set_password (context, + &cpw_cred, + buf1, + client, + &result_code, + &result_code_string, + &result_string); + if (ret) + goto out; + + if (asprintf(&p, "%s: %.*s\n", + result_code ? "Error" : "Success", + (int)result_string.length, + result_string.length > 0 ? (char*)result_string.data : "") < 0) + { + ret = krb5_enomem(context); + goto out; + } + + /* return the result */ + (*prompter) (context, data, NULL, p, 0, NULL); + + if (result_code == 0) { + strlcpy (newpw, buf1, newpw_sz); + ret = 0; + } else { + krb5_set_error_message(context, ret = KRB5_CHPW_FAIL, + N_("failed changing password: %s", ""), p); + } + free (p); + +out: + memset_s(buf1, sizeof(buf1), 0, sizeof(buf1)); + memset_s(buf2, sizeof(buf2), 0, sizeof(buf2)); + krb5_data_free (&result_string); + krb5_data_free (&result_code_string); + krb5_free_cred_contents (context, &cpw_cred); + return ret; +} + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_keyblock_key_proc (krb5_context context, + krb5_keytype type, + krb5_data *salt, + krb5_const_pointer keyseed, + krb5_keyblock **key) +{ + return krb5_copy_keyblock (context, keyseed, key); +} + +/* + * + */ + +static krb5_error_code +init_as_req (krb5_context context, + KDCOptions opts, + const krb5_creds *creds, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + AS_REQ *a) +{ + krb5_error_code ret; + + memset(a, 0, sizeof(*a)); + + a->pvno = 5; + a->msg_type = krb_as_req; + a->req_body.kdc_options = opts; + a->req_body.cname = calloc(1, sizeof(*a->req_body.cname)); + if (a->req_body.cname == NULL) { + ret = krb5_enomem(context); + goto fail; + } + a->req_body.sname = calloc(1, sizeof(*a->req_body.sname)); + if (a->req_body.sname == NULL) { + ret = krb5_enomem(context); + goto fail; + } + + ret = _krb5_principal2principalname (a->req_body.cname, creds->client); + if (ret) + goto fail; + ret = copy_Realm(&creds->client->realm, &a->req_body.realm); + if (ret) + goto fail; + + ret = _krb5_principal2principalname (a->req_body.sname, creds->server); + if (ret) + goto fail; + + if(creds->times.starttime) { + a->req_body.from = malloc(sizeof(*a->req_body.from)); + if (a->req_body.from == NULL) { + ret = krb5_enomem(context); + goto fail; + } + *a->req_body.from = creds->times.starttime; + } + if(creds->times.endtime){ + if ((ALLOC(a->req_body.till, 1)) != NULL) + *a->req_body.till = creds->times.endtime; + else { + ret = krb5_enomem(context); + goto fail; + } + } + if(creds->times.renew_till){ + a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); + if (a->req_body.rtime == NULL) { + ret = krb5_enomem(context); + goto fail; + } + *a->req_body.rtime = creds->times.renew_till; + } + a->req_body.nonce = 0; + ret = _krb5_init_etype(context, + KRB5_PDU_AS_REQUEST, + &a->req_body.etype.len, + &a->req_body.etype.val, + etypes); + if (ret) + goto fail; + + /* + * This means no addresses + */ + + if (addrs && addrs->len == 0) { + a->req_body.addresses = NULL; + } else { + a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); + if (a->req_body.addresses == NULL) { + ret = krb5_enomem(context); + goto fail; + } + + if (addrs) + ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); + else { + ret = krb5_get_all_client_addrs (context, a->req_body.addresses); + if(ret == 0 && a->req_body.addresses->len == 0) { + free(a->req_body.addresses); + a->req_body.addresses = NULL; + } + } + if (ret) + goto fail; + } + + a->req_body.enc_authorization_data = NULL; + a->req_body.additional_tickets = NULL; + + a->padata = NULL; + + return 0; + fail: + free_AS_REQ(a); + memset_s(a, sizeof(*a), 0, sizeof(*a)); + return ret; +} + + +static krb5_error_code +set_paid(struct pa_info_data *paid, krb5_context context, + krb5_enctype etype, + krb5_salttype salttype, void *salt_string, size_t salt_len, + krb5_data *s2kparams) +{ + paid->etype = etype; + paid->salt.salttype = salttype; + paid->salt.saltvalue.data = malloc(salt_len + 1); + if (paid->salt.saltvalue.data == NULL) { + krb5_clear_error_message(context); + return krb5_enomem(context); + } + memcpy(paid->salt.saltvalue.data, salt_string, salt_len); + ((char *)paid->salt.saltvalue.data)[salt_len] = '\0'; + paid->salt.saltvalue.length = salt_len; + if (s2kparams) { + krb5_error_code ret; + + ret = krb5_copy_data(context, s2kparams, &paid->s2kparams); + if (ret) { + krb5_clear_error_message(context); + krb5_free_salt(context, paid->salt); + return ret; + } + } else + paid->s2kparams = NULL; + + return 0; +} + +static struct pa_info_data * +pa_etype_info2(krb5_context context, + const krb5_principal client, + const AS_REQ *asreq, + struct pa_info_data *paid, + heim_octet_string *data) +{ + krb5_error_code ret; + ETYPE_INFO2 e; + size_t sz; + size_t i, j; + + memset(&e, 0, sizeof(e)); + ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz); + if (ret) + goto out; + if (e.len == 0) + goto out; + for (j = 0; j < asreq->req_body.etype.len; j++) { + for (i = 0; i < e.len; i++) { + + if (krb5_enctype_valid(context, e.val[i].etype) != 0) + continue; + + if (asreq->req_body.etype.val[j] == e.val[i].etype) { + krb5_salt salt; + if (e.val[i].salt == NULL) + ret = krb5_get_pw_salt(context, client, &salt); + else { + salt.saltvalue.data = *e.val[i].salt; + salt.saltvalue.length = strlen(*e.val[i].salt); + ret = 0; + } + if (ret == 0) + ret = set_paid(paid, context, e.val[i].etype, + KRB5_PW_SALT, + salt.saltvalue.data, + salt.saltvalue.length, + e.val[i].s2kparams); + if (e.val[i].salt == NULL) + krb5_free_salt(context, salt); + if (ret == 0) { + free_ETYPE_INFO2(&e); + return paid; + } + } + } + } + out: + free_ETYPE_INFO2(&e); + return NULL; +} + +static struct pa_info_data * +pa_etype_info(krb5_context context, + const krb5_principal client, + const AS_REQ *asreq, + struct pa_info_data *paid, + heim_octet_string *data) +{ + krb5_error_code ret; + ETYPE_INFO e; + size_t sz; + size_t i, j; + + memset(&e, 0, sizeof(e)); + ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz); + if (ret) + goto out; + if (e.len == 0) + goto out; + for (j = 0; j < asreq->req_body.etype.len; j++) { + for (i = 0; i < e.len; i++) { + + if (krb5_enctype_valid(context, e.val[i].etype) != 0) + continue; + + if (asreq->req_body.etype.val[j] == e.val[i].etype) { + krb5_salt salt; + salt.salttype = KRB5_PW_SALT; + if (e.val[i].salt == NULL) + ret = krb5_get_pw_salt(context, client, &salt); + else { + salt.saltvalue = *e.val[i].salt; + ret = 0; + } + if (e.val[i].salttype) + salt.salttype = *e.val[i].salttype; + if (ret == 0) { + ret = set_paid(paid, context, e.val[i].etype, + salt.salttype, + salt.saltvalue.data, + salt.saltvalue.length, + NULL); + if (e.val[i].salt == NULL) + krb5_free_salt(context, salt); + } + if (ret == 0) { + free_ETYPE_INFO(&e); + return paid; + } + } + } + } + out: + free_ETYPE_INFO(&e); + return NULL; +} + +static struct pa_info_data * +pa_pw_or_afs3_salt(krb5_context context, + const krb5_principal client, + const AS_REQ *asreq, + struct pa_info_data *paid, + heim_octet_string *data) +{ + krb5_error_code ret; + if (paid->etype == KRB5_ENCTYPE_NULL) + return NULL; + if (krb5_enctype_valid(context, paid->etype) != 0) + return NULL; + + ret = set_paid(paid, context, + paid->etype, + paid->salt.salttype, + data->data, + data->length, + NULL); + if (ret) + return NULL; + return paid; +} + + +static krb5_error_code +make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md, + krb5_enctype etype, krb5_keyblock *key) +{ + PA_ENC_TS_ENC p; + unsigned char *buf; + size_t buf_size; + size_t len = 0; + EncryptedData encdata; + krb5_error_code ret; + int32_t usec; + int usec2; + krb5_crypto crypto; + + krb5_us_timeofday (context, &p.patimestamp, &usec); + usec2 = usec; + p.pausec = &usec2; + + ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free(buf); + return ret; + } + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, + buf, + len, + 0, + &encdata); + free(buf); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); + free_EncryptedData(&encdata); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len); + if (ret) + free(buf); + return ret; +} + +static krb5_error_code +add_enc_ts_padata(krb5_context context, + METHOD_DATA *md, + krb5_principal client, + krb5_s2k_proc keyproc, + krb5_const_pointer keyseed, + krb5_enctype *enctypes, + unsigned netypes, + krb5_salt *salt, + krb5_data *s2kparams) +{ + krb5_error_code ret; + krb5_salt salt2; + krb5_enctype *ep; + size_t i; + + memset(&salt2, 0, sizeof(salt2)); + + if(salt == NULL) { + /* default to standard salt */ + ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; + salt = &salt2; + } + if (!enctypes) { + enctypes = context->etypes; + netypes = 0; + for (ep = enctypes; *ep != ETYPE_NULL; ep++) + netypes++; + } + + for (i = 0; i < netypes; ++i) { + krb5_keyblock *key; + + _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]); + + ret = (*keyproc)(context, enctypes[i], keyseed, + *salt, s2kparams, &key); + if (ret) + continue; + ret = make_pa_enc_timestamp (context, md, enctypes[i], key); + krb5_free_keyblock (context, key); + if (ret) + return ret; + } + if(salt == &salt2) + krb5_free_salt(context, salt2); + return 0; +} + +static krb5_error_code +pa_data_to_md_ts_enc(krb5_context context, + const AS_REQ *a, + const krb5_principal client, + krb5_init_creds_context ctx, + struct pa_info_data *ppaid, + METHOD_DATA *md) +{ + if (ctx->keyproc == NULL || ctx->keyseed == NULL) + return 0; + + if (ppaid) { + add_enc_ts_padata(context, md, client, + ctx->keyproc, ctx->keyseed, + &ppaid->etype, 1, + &ppaid->salt, ppaid->s2kparams); + } else { + krb5_salt salt; + + _krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt"); + + /* make a v5 salted pa-data */ + add_enc_ts_padata(context, md, client, + ctx->keyproc, ctx->keyseed, + a->req_body.etype.val, a->req_body.etype.len, + NULL, NULL); + + /* make a v4 salted pa-data */ + salt.salttype = KRB5_PW_SALT; + krb5_data_zero(&salt.saltvalue); + add_enc_ts_padata(context, md, client, + ctx->keyproc, ctx->keyseed, + a->req_body.etype.val, a->req_body.etype.len, + &salt, NULL); + } + return 0; +} + +static krb5_error_code +pa_data_to_key_plain(krb5_context context, + const krb5_principal client, + krb5_init_creds_context ctx, + krb5_salt salt, + krb5_data *s2kparams, + krb5_enctype etype, + krb5_keyblock **key) +{ + krb5_error_code ret; + + ret = (*ctx->keyproc)(context, etype, ctx->keyseed, + salt, s2kparams, key); + return ret; +} + +struct pkinit_context { + unsigned int win2k : 1; + unsigned int used_pkinit : 1; +}; + + +static krb5_error_code +pa_data_to_md_pkinit(krb5_context context, + const AS_REQ *a, + const krb5_principal client, + int win2k, + krb5_init_creds_context ctx, + METHOD_DATA *md) +{ + if (ctx->pk_init_ctx == NULL) + return 0; +#ifdef PKINIT + return _krb5_pk_mk_padata(context, + ctx->pk_init_ctx, + ctx->ic_flags, + win2k, + &a->req_body, + ctx->pk_nonce, + md); +#else + krb5_set_error_message(context, EINVAL, + N_("no support for PKINIT compiled in", "")); + return EINVAL; +#endif +} + +static krb5_error_code +pkinit_configure_ietf(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx) +{ + struct pkinit_context *pkinit_ctx = pa_ctx; + + pkinit_ctx->win2k = 0; + + if (ctx->pk_init_ctx == NULL) + return HEIM_ERR_PA_CANT_CONTINUE; + + return 0; +} + +static krb5_error_code +pkinit_configure_win(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx) +{ + struct pkinit_context *pkinit_ctx = pa_ctx; + + pkinit_ctx->win2k = 1; + pkinit_ctx->used_pkinit = 0; + + if (ctx->pk_init_ctx == NULL) + return HEIM_ERR_PA_CANT_CONTINUE; + + return 0; +} + +static krb5_error_code +pkinit_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a, + const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md) +{ + krb5_error_code ret = HEIM_ERR_PA_CANT_CONTINUE; + struct pkinit_context *pkinit_ctx = pa_ctx; + + if (rep == NULL) { + if (pkinit_ctx->used_pkinit) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + "Already tried PKINIT(%s), looping", + pkinit_ctx->win2k ? "win2k" : "ietf"); + } else { + ret = pa_data_to_md_pkinit(context, a, ctx->cred.client, + (pkinit_ctx->win2k != 0), + ctx, out_md); + if (ret == 0) + ret = HEIM_ERR_PA_CONTINUE_NEEDED; + + pkinit_ctx->used_pkinit = 1; + } + } else if (pa) { + ret = _krb5_pk_rd_pa_reply(context, + a->req_body.realm, + ctx->pk_init_ctx, + rep->enc_part.etype, + ctx->pk_nonce, + &ctx->req_buffer, + pa, + &ctx->fast_state.reply_key); + if (ret == 0) + ctx->runflags.allow_save_as_reply_key = 1; + } + + return ret; +} + +static void +pkinit_release(void *pa_ctx) +{ +} + +/* + * GSS-API pre-authentication support + */ + +struct pa_gss_context { + struct gss_ctx_id_t_desc_struct *context_handle; + int open; +}; + +static krb5_error_code +pa_gss_configure(krb5_context context, + krb5_init_creds_context ctx, + void *pa_ctx) +{ + krb5_gss_init_ctx gssic = ctx->gss_init_ctx; + struct pa_gss_context *pa_gss_ctx = pa_ctx; + + if (gssic == NULL) + return HEIM_ERR_PA_CANT_CONTINUE; + + pa_gss_ctx->context_handle = NULL; + pa_gss_ctx->open = 0; + + return 0; +} + +static krb5_error_code +pa_data_to_md_gss(krb5_context context, + const AS_REQ *a, + const krb5_creds *creds, + krb5_init_creds_context ctx, + struct pa_gss_context *pa_gss_ctx, + PA_DATA *pa, + METHOD_DATA *out_md) +{ + krb5_error_code ret; + krb5_gss_init_ctx gssic = ctx->gss_init_ctx; + krb5_data req_body; + krb5_data *input_token, output_token; + size_t len = 0; + + krb5_data_zero(&req_body); + krb5_data_zero(&output_token); + + input_token = pa ? &pa->padata_value : NULL; + + if ((input_token == NULL || input_token->length == 0) && + pa_gss_ctx->context_handle) { + krb5_set_error_message(context, HEIM_ERR_PA_CANT_CONTINUE, + "Missing GSS preauthentication data from KDC"); + return HEIM_ERR_PA_CANT_CONTINUE; + } + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, req_body.data, req_body.length, + &ctx->as_req.req_body, &len, ret); + if (ret) + goto out; + heim_assert(req_body.length == len, "ASN.1 internal error"); + + ret = gssic->step(context, gssic, creds, &pa_gss_ctx->context_handle, + ctx->flags, &req_body, + input_token, &output_token); + + /* + * If FAST authenticated the KDC (which will be the case unless anonymous + * PKINIT was used without KDC certificate validation) then we can relax + * the mutual authentication requirement. + */ + if (ret == KRB5_MUTUAL_FAILED && + (ctx->fast_state.flags & KRB5_FAST_EXPECTED) && + (ctx->fast_state.flags & KRB5_FAST_KDC_VERIFIED)) + ret = 0; + if (ret == 0) { + /* + * Always require a strengthen key if FAST was used, to avoid a MITM + * attack that could result in unintended privilege escalation should + * the KDC add positive authorization data from the armor ticket. + */ + if ((ctx->fast_state.flags & KRB5_FAST_EXPECTED) && + ctx->fast_state.strengthen_key == NULL) { + krb5_set_error_message(context, HEIM_ERR_PA_CANT_CONTINUE, + "FAST GSS pre-authentication without strengthen key"); + ret = KRB5_KDCREP_MODIFIED; + goto out; + } + + pa_gss_ctx->open = 1; + } + + if (output_token.length) { + ret = krb5_padata_add(context, out_md, KRB5_PADATA_GSS, + output_token.data, output_token.length); + if (ret) + goto out; + + krb5_data_zero(&output_token); + } + +out: + krb5_data_free(&output_token); + krb5_data_free(&req_body); + + return ret; +} + +static krb5_error_code +pa_gss_step(krb5_context context, + krb5_init_creds_context ctx, + void *pa_ctx, + PA_DATA *pa, + const AS_REQ *a, + const AS_REP *rep, + METHOD_DATA *in_md, + METHOD_DATA *out_md) +{ + krb5_error_code ret; + krb5_principal cname; + krb5_gss_init_ctx gssic = ctx->gss_init_ctx; + struct pa_gss_context *pa_gss_ctx = pa_ctx; + + heim_assert(gssic != NULL, "invalid context passed to pa_gss_step"); + + if (!pa_gss_ctx->open) { + ret = pa_data_to_md_gss(context, a, &ctx->cred, ctx, + pa_gss_ctx, pa, out_md); + if (ret == HEIM_ERR_PA_CONTINUE_NEEDED && rep) { + krb5_set_error_message(context, KRB5_PREAUTH_FAILED, + "KDC sent AS-REP before GSS " + "pre-authentication completed"); + ret = KRB5_KDCREP_MODIFIED; + } else if (ret == 0 && rep == NULL) { + ret = HEIM_ERR_PA_CONTINUE_NEEDED; /* odd number of legs */ + } + if (ret) + return ret; + } else if (pa && pa->padata_value.length) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + "Already completed GSS pre-authentication"); + return KRB5_GET_IN_TKT_LOOP; + } else if (rep == NULL) { + krb5_set_error_message(context, KRB5_PREAUTH_FAILED, + "Completed GSS pre-authentication before KDC"); + return KRB5_PREAUTH_FAILED; + } + + heim_assert(pa_gss_ctx->open, + "GSS pre-authentication incomplete"); + + ret = gssic->finish(context, gssic, &ctx->cred, + pa_gss_ctx->context_handle, ctx->nonce, + rep->enc_part.etype, &cname, + &ctx->fast_state.reply_key); + if (ret) + return ret; + + { + char *from = NULL; + char *to = NULL; + + if (krb5_unparse_name(context, ctx->cred.client, &from) == 0) { + if (krb5_unparse_name(context, cname, &to) == 0) { + _krb5_debug(context, 1, "pa_gss_step: %s as %s", + from, to); + krb5_xfree(to); + } + krb5_xfree(from); + } + } + + if (krb5_principal_is_federated(context, ctx->cred.client)) { + /* + * The well-known federated name will be replaced with the cname + * in the AS-REP, but save the locally mapped initiator name in the + * cred for logging. + */ + krb5_free_principal(context, ctx->cred.client); + ctx->cred.client = cname; + + ctx->ic_flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK; + } else { + krb5_free_principal(context, cname); + } + + ctx->runflags.allow_save_as_reply_key = 1; + + gssic->delete_sec_context(context, gssic, pa_gss_ctx->context_handle); + pa_gss_ctx->context_handle = NULL; + pa_gss_ctx->open = 0; + + return 0; +} + +static krb5_error_code +pa_gss_restart(krb5_context context, + krb5_init_creds_context ctx, + void *pa_ctx) +{ + krb5_gss_init_ctx gssic = ctx->gss_init_ctx; + struct pa_gss_context *pa_gss_ctx = pa_ctx; + + if (gssic == NULL) + return HEIM_ERR_PA_CANT_CONTINUE; + + gssic->delete_sec_context(context, gssic, pa_gss_ctx->context_handle); + pa_gss_ctx->context_handle = NULL; + pa_gss_ctx->open = 0; + + return 0; +} + +static void +pa_gss_release(void *pa_ctx) +{ +} + +krb5_error_code +_krb5_make_pa_enc_challenge(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + METHOD_DATA *md) +{ + PA_ENC_TS_ENC p; + unsigned char *buf; + size_t buf_size; + size_t len = 0; + EncryptedData encdata; + krb5_error_code ret; + int32_t usec; + int usec2; + + krb5_us_timeofday (context, &p.patimestamp, &usec); + usec2 = usec; + p.pausec = &usec2; + + ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_encrypt_EncryptedData(context, + crypto, + usage, + buf, + len, + 0, + &encdata); + free(buf); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); + free_EncryptedData(&encdata); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len); + if (ret) + free(buf); + return ret; +} + +krb5_error_code +_krb5_validate_pa_enc_challenge(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + EncryptedData *enc_data, + const char *peer_name) +{ + krb5_error_code ret; + krb5_data ts_data; + PA_ENC_TS_ENC p; + time_t timestamp; + int32_t usec; + size_t size; + + ret = krb5_decrypt_EncryptedData(context, crypto, usage, enc_data, &ts_data); + if (ret) + return ret; + + ret = decode_PA_ENC_TS_ENC(ts_data.data, + ts_data.length, + &p, + &size); + krb5_data_free(&ts_data); + if(ret){ + ret = KRB5KDC_ERR_PREAUTH_FAILED; + _krb5_debug(context, 5, "Failed to decode PA-ENC-TS_ENC -- %s", peer_name); + goto out; + } + + krb5_us_timeofday(context, ×tamp, &usec); + + if (krb5_time_abs(timestamp, p.patimestamp) > context->max_skew) { + char client_time[100]; + + krb5_format_time(context, p.patimestamp, + client_time, sizeof(client_time), TRUE); + + ret = KRB5KRB_AP_ERR_SKEW; + _krb5_debug(context, 0, "Too large time skew, " + "client time %s is out by %u > %d seconds -- %s", + client_time, + (unsigned)krb5_time_abs(timestamp, p.patimestamp), + (int)context->max_skew, + peer_name); + } else { + ret = 0; + } + + out: + free_PA_ENC_TS_ENC(&p); + + return ret; +} + + +static struct pa_info_data * +process_pa_info(krb5_context, const krb5_principal, const AS_REQ *, struct pa_info_data *, METHOD_DATA *); + + +static krb5_error_code +enc_chal_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a, + const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md) +{ + struct pa_info_data paid, *ppaid; + krb5_keyblock challengekey; + krb5_data pepper1, pepper2; + krb5_crypto crypto = NULL; + krb5_enctype aenctype; + krb5_error_code ret; + + memset(&paid, 0, sizeof(paid)); + + if (rep == NULL) + paid.etype = KRB5_ENCTYPE_NULL; + else + paid.etype = rep->enc_part.etype; + ppaid = process_pa_info(context, ctx->cred.client, a, &paid, in_md); + + /* + * If we don't have ppaid, it's because the KDC has not sent any + * salt info. Let's do the first roundtrip so the KDC has a chance + * to send some. + */ + if (ppaid == NULL) { + _krb5_debug(context, 5, "no ppaid found"); + return HEIM_ERR_PA_CONTINUE_NEEDED; + } + if (ppaid->etype == KRB5_ENCTYPE_NULL) { + return HEIM_ERR_PA_CANT_CONTINUE; + } + + if (ctx->fast_state.reply_key) + krb5_free_keyblock(context, ctx->fast_state.reply_key); + + ret = pa_data_to_key_plain(context, ctx->cred.client, ctx, + ppaid->salt, ppaid->s2kparams, ppaid->etype, + &ctx->fast_state.reply_key); + free_paid(context, &paid); + if (ret) { + _krb5_debug(context, 5, "enc-chal: failed to build key"); + return ret; + } + + ret = krb5_crypto_init(context, ctx->fast_state.reply_key, 0, &crypto); + if (ret) + return ret; + + krb5_crypto_getenctype(context, ctx->fast_state.armor_crypto, &aenctype); + + pepper1.data = rep ? "kdcchallengearmor" : "clientchallengearmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "challengelongterm"; + pepper2.length = strlen(pepper2.data); + + ret = krb5_crypto_fx_cf2(context, ctx->fast_state.armor_crypto, crypto, + &pepper1, &pepper2, aenctype, + &challengekey); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + ret = krb5_crypto_init(context, &challengekey, 0, &crypto); + krb5_free_keyblock_contents(context, &challengekey); + if (ret) + return ret; + + if (rep) { + EncryptedData enc_data; + size_t size; + + _krb5_debug(context, 5, "ENC_CHAL rep key"); + + if (ctx->fast_state.strengthen_key == NULL) { + krb5_crypto_destroy(context, crypto); + _krb5_debug(context, 5, "ENC_CHAL w/o strengthen_key"); + return KRB5_KDCREP_MODIFIED; + } + + if (pa == NULL) { + krb5_crypto_destroy(context, crypto); + _krb5_debug(context, 0, "KDC response missing"); + return HEIM_ERR_PA_CANT_CONTINUE; + } + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &enc_data, + &size); + if (ret) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + _krb5_debug(context, 5, "Failed to decode ENC_CHAL KDC reply"); + return ret; + } + + ret = _krb5_validate_pa_enc_challenge(context, crypto, + KRB5_KU_ENC_CHALLENGE_KDC, + &enc_data, + "KDC"); + free_EncryptedData(&enc_data); + krb5_crypto_destroy(context, crypto); + + return ret; + + } else { + + ret = _krb5_make_pa_enc_challenge(context, crypto, + KRB5_KU_ENC_CHALLENGE_CLIENT, + out_md); + krb5_crypto_destroy(context, crypto); + if (ret) { + _krb5_debug(context, 5, "enc-chal: failed build enc challenge"); + return ret; + } + + return HEIM_ERR_PA_CONTINUE_NEEDED; + } +} + +struct enc_ts_context { + int used_pa_types; +#define USED_ENC_TS_GUESS 4 +#define USED_ENC_TS_INFO 8 +#define USED_ENC_TS_RENEG 16 + krb5_principal user; +}; + +static krb5_error_code +enc_ts_restart(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx) +{ + struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx; + pactx->used_pa_types = 0; + krb5_free_principal(context, pactx->user); + pactx->user = NULL; + return 0; +} + +static krb5_error_code +enc_ts_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, + const AS_REQ *a, + const AS_REP *rep, + METHOD_DATA *in_md, METHOD_DATA *out_md) +{ + struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx; + struct pa_info_data paid, *ppaid; + krb5_error_code ret; + const char *state; + unsigned flag; + + /* + * Keep track of the user we used so that we can restart + * authentication when we get referrals. + */ + + if (pactx->user && !krb5_principal_compare(context, pactx->user, ctx->cred.client)) { + pactx->used_pa_types = 0; + krb5_free_principal(context, pactx->user); + pactx->user = NULL; + } + + if (pactx->user == NULL) { + ret = krb5_copy_principal(context, ctx->cred.client, &pactx->user); + if (ret) + return ret; + } + + memset(&paid, 0, sizeof(paid)); + + if (rep == NULL) + paid.etype = KRB5_ENCTYPE_NULL; + else + paid.etype = rep->enc_part.etype; + + ppaid = process_pa_info(context, ctx->cred.client, a, &paid, in_md); + + if (rep) { + /* + * Some KDC's don't send salt info in the reply when there is + * success pre-auth happened before, so use cached copy (or + * even better, if there is just one pre-auth, save reply-key). + */ + if (ppaid == NULL && ctx->paid.etype != KRB5_ENCTYPE_NULL) { + ppaid = &ctx->paid; + + } else if (ppaid == NULL) { + _krb5_debug(context, 0, "no paid when building key, build a default salt structure ?"); + return HEIM_ERR_PA_CANT_CONTINUE; + } + + ret = pa_data_to_key_plain(context, ctx->cred.client, ctx, + ppaid->salt, ppaid->s2kparams, rep->enc_part.etype, + &ctx->fast_state.reply_key); + free_paid(context, &paid); + return ret; + } + + /* + * If we don't have ppaid, it's because the KDC has not sent any + * salt info. Let's do the first roundtrip so the KDC has a chance + * to send some. + * + * Don't bother guessing, it sounds like a good idea until you run + * into KDCs that are doing failed auth counting based on the + * ENC_TS tries. + * + * Stashing the salt for the next run is a different issue and + * could be considered in the future. + */ + + if (ppaid == NULL) { + _krb5_debug(context, 5, + "TS-ENC: waiting for KDC to set pw-salt/etype_info{,2}"); + return HEIM_ERR_PA_CONTINUE_NEEDED; + } + if (ppaid->etype == KRB5_ENCTYPE_NULL) { + free_paid(context, &paid); + _krb5_debug(context, 5, + "TS-ENC: kdc proposes enctype NULL ?"); + return HEIM_ERR_PA_CANT_CONTINUE; + } + + /* + * We have to allow the KDC to re-negotiate the PA-TS data + * once, this is since a windows read only + * KDC that doesn't have the keys simply guesses what the + * master is supposed to support. The case where this + * breaks is when the RO-KDC is a newer version than the RW-KDC + * and the RO-KDC announced a enctype that the older doesn't + * support. + */ + if (pactx->used_pa_types & USED_ENC_TS_INFO) { + flag = USED_ENC_TS_RENEG; + state = "reneg"; + } else { + flag = USED_ENC_TS_INFO; + state = "info"; + } + + if (pactx->used_pa_types & flag) { + free_paid(context, &paid); + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + "Already tried ENC-TS-%s, looping", state); + return KRB5_GET_IN_TKT_LOOP; + } + + pactx->used_pa_types |= flag; + + free_paid(context, &ctx->paid); + ctx->paid = *ppaid; + + ret = pa_data_to_md_ts_enc(context, a, ctx->cred.client, ctx, ppaid, out_md); + if (ret) + return ret; + + return HEIM_ERR_PA_CONTINUE_NEEDED; +} + +static void +enc_ts_release(void *pa_ctx) +{ + struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx; + + if (pactx->user) + krb5_free_principal(NULL, pactx->user); +} + +static krb5_error_code +pa_pac_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a, + const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md) +{ + size_t len = 0, length; + krb5_error_code ret; + PA_PAC_REQUEST req; + void *buf; + + switch (ctx->req_pac) { + case KRB5_INIT_CREDS_TRISTATE_UNSET: + return 0; /* don't bother */ + case KRB5_INIT_CREDS_TRISTATE_TRUE: + req.include_pac = 1; + break; + case KRB5_INIT_CREDS_TRISTATE_FALSE: + req.include_pac = 0; + } + + ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length, + &req, &len, ret); + if (ret) + return ret; + heim_assert(len == length, "internal error in ASN.1 encoder"); + + ret = krb5_padata_add(context, out_md, KRB5_PADATA_PA_PAC_REQUEST, buf, len); + if (ret) + free(buf); + + return 0; +} + +static krb5_error_code +pa_enc_pa_rep_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a, + const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md) +{ + if (ctx->runflags.allow_enc_pa_rep) + return krb5_padata_add(context, out_md, KRB5_PADATA_REQ_ENC_PA_REP, NULL, 0); + + return 0; +} + +static krb5_error_code +pa_fx_cookie_step(krb5_context context, + krb5_init_creds_context ctx, + void *pa_ctx, + PA_DATA *pa, + const AS_REQ *a, + const AS_REP *rep, + METHOD_DATA *in_md, + METHOD_DATA *out_md) +{ + krb5_error_code ret; + void *cookie; + PA_DATA *pad; + int idx = 0; + + pad = krb5_find_padata(in_md->val, in_md->len, KRB5_PADATA_FX_COOKIE, &idx); + if (pad == NULL) { + /* + * RFC 6113 5.4.3: PA-FX-COOKIE MUST be included if the KDC + * expects at least one more message from the client. + */ + if (ctx->error.error_code == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) + return KRB5_PREAUTH_FAILED; + else + return 0; + } + + cookie = malloc(pad->padata_value.length); + if (cookie == NULL) + return krb5_enomem(context); + + memcpy(cookie, pad->padata_value.data, pad->padata_value.length); + + ret = krb5_padata_add(context, out_md, KRB5_PADATA_FX_COOKIE, + cookie, pad->padata_value.length); + if (ret) + free(cookie); + else + _krb5_debug(context, 5, "Mirrored FX-COOKIE to KDC"); + + return ret; +} + +typedef struct pa_info_data *(*pa_salt_info_f)(krb5_context, const krb5_principal, const AS_REQ *, struct pa_info_data *, heim_octet_string *); +typedef krb5_error_code (*pa_configure_f)(krb5_context, krb5_init_creds_context, void *); +typedef krb5_error_code (*pa_restart_f)(krb5_context, krb5_init_creds_context, void *); +typedef krb5_error_code (*pa_step_f)(krb5_context, krb5_init_creds_context, void *, PA_DATA *, const AS_REQ *, const AS_REP *, METHOD_DATA *, METHOD_DATA *); +typedef void (*pa_release_f)(void *); + +static const struct patype { + int type; + const char *name; + int flags; +#define PA_F_ANNOUNCE 1 +#define PA_F_CONFIG 2 +#define PA_F_FAST 4 /* available inside FAST */ +#define PA_F_NOT_FAST 8 /* only available without FAST */ + size_t pa_ctx_size; + pa_salt_info_f salt_info; + /** + * Return 0 if the PA-mechanism is available and optionally set pa_ctx pointer to non-NULL. + */ + pa_configure_f configure; + /** + * Return 0 if the PA-mechanism can be restarted (time skew, referrals, etc) + */ + pa_restart_f restart; + /** + * Return 0 when complete, HEIM_ERR_PA_CONTINUE_NEEDED if more steps are required + */ + pa_step_f step; + pa_release_f release; +} patypes[] = { + { + KRB5_PADATA_PK_AS_REP, + "PKINIT(IETF)", + PA_F_FAST | PA_F_NOT_FAST, + sizeof(struct pkinit_context), + NULL, + pkinit_configure_ietf, + NULL, + pkinit_step, + pkinit_release + }, + { + KRB5_PADATA_PK_AS_REP_19, + "PKINIT(win)", + PA_F_FAST | PA_F_NOT_FAST, + sizeof(struct pkinit_context), + NULL, + pkinit_configure_win, + NULL, + pkinit_step, + pkinit_release + }, + { + KRB5_PADATA_GSS, + "GSS", + PA_F_FAST | PA_F_NOT_FAST, + sizeof(struct pa_gss_context), + NULL, + pa_gss_configure, + pa_gss_restart, + pa_gss_step, + pa_gss_release + }, + { + KRB5_PADATA_ENCRYPTED_CHALLENGE, + "ENCRYPTED_CHALLENGE", + PA_F_FAST, + 0, + NULL, + NULL, + NULL, + enc_chal_step, + NULL + }, + { + KRB5_PADATA_ENC_TIMESTAMP, + "ENCRYPTED_TIMESTAMP", + PA_F_NOT_FAST, + sizeof(struct enc_ts_context), + NULL, + NULL, + enc_ts_restart, + enc_ts_step, + enc_ts_release + }, + { + KRB5_PADATA_PA_PAC_REQUEST, + "PA_PAC_REQUEST", + PA_F_CONFIG, + 0, + NULL, + NULL, + NULL, + pa_pac_step, + NULL + }, + { + KRB5_PADATA_REQ_ENC_PA_REP, + "REQ-ENC-PA-REP", + PA_F_CONFIG, + 0, + NULL, + NULL, + NULL, + pa_enc_pa_rep_step, + NULL + }, + { + KRB5_PADATA_FX_COOKIE, + "FX-COOKIE", + PA_F_CONFIG, + 0, + NULL, + NULL, + NULL, + pa_fx_cookie_step, + NULL + }, +#define patype_salt(n, f) { KRB5_PADATA_##n, #n, 0, 0, f, NULL, NULL, NULL, NULL } + patype_salt(ETYPE_INFO2, pa_etype_info2), + patype_salt(ETYPE_INFO, pa_etype_info), + patype_salt(PW_SALT, pa_pw_or_afs3_salt), + patype_salt(AFS3_SALT, pa_pw_or_afs3_salt), +#undef patype_salt + /* below are just for pretty printing */ +#define patype_info(n) { KRB5_PADATA_##n, #n, 0, 0, NULL, NULL, NULL, NULL, NULL } + patype_info(AUTHENTICATION_SET), + patype_info(AUTH_SET_SELECTED), + patype_info(FX_FAST), + patype_info(FX_ERROR), + patype_info(PKINIT_KX), + patype_info(PK_AS_REQ) +#undef patype_info +}; + +static const char * +get_pa_type_name(int type) +{ + size_t n; + for (n = 0; n < sizeof(patypes)/sizeof(patypes[0]); n++) + if (type == patypes[n].type) + return patypes[n].name; + return "unknown"; +} + +/* + * + */ + +struct pa_auth_mech { + const struct patype *patype; + struct pa_auth_mech *next; /* when doing authentication sets */ + char pactx[1]; +}; + +/* + * + */ + +static struct pa_info_data * +process_pa_info(krb5_context context, + const krb5_principal client, + const AS_REQ *asreq, + struct pa_info_data *paid, + METHOD_DATA *md) +{ + struct pa_info_data *p = NULL; + PA_DATA *pa; + size_t i; + + if (md == NULL) + return NULL; + + for (i = 0; p == NULL && i < sizeof(patypes)/sizeof(patypes[0]); i++) { + int idx = 0; + + if (patypes[i].salt_info == NULL) + continue; + + pa = krb5_find_padata(md->val, md->len, patypes[i].type, &idx); + if (pa == NULL) + continue; + + paid->salt.salttype = (krb5_salttype)patypes[i].type; + p = patypes[i].salt_info(context, client, asreq, paid, &pa->padata_value); + } + return p; +} + +static krb5_error_code +pa_announce(krb5_context context, + int types, + krb5_init_creds_context ctx, + METHOD_DATA *in_md, + METHOD_DATA *out_md) +{ + krb5_error_code ret = 0; + size_t n; + + for (n = 0; ret == 0 && n < sizeof(patypes)/sizeof(patypes[0]); n++) { + if ((patypes[n].flags & types) == 0) + continue; + + if (patypes[n].step) + patypes[n].step(context, ctx, NULL, NULL, NULL, NULL, in_md, out_md); + else + ret = krb5_padata_add(context, out_md, patypes[n].type, NULL, 0); + } + return ret; +} + + +static void HEIM_CALLCONV +mech_dealloc(void *ctx) +{ + struct pa_auth_mech *pa_mech = ctx; + if (pa_mech->patype->release) + pa_mech->patype->release((void *)&pa_mech->pactx[0]); +} + +static const struct heim_type_data pa_auth_mech_object = { + HEIM_TID_PA_AUTH_MECH, + "heim-pa-mech-context", + NULL, + mech_dealloc, + NULL, + NULL, + NULL, + NULL +}; + +static struct pa_auth_mech * +pa_mech_create(krb5_context context, krb5_init_creds_context ctx, int pa_type) +{ + struct pa_auth_mech *pa_mech; + const struct patype *patype = NULL; + size_t n; + + for (n = 0; patype == NULL && n < sizeof(patypes)/sizeof(patypes[0]); n++) { + if (patypes[n].type == pa_type) + patype = &patypes[n]; + } + if (patype == NULL) + return NULL; + + pa_mech = _heim_alloc_object(&pa_auth_mech_object, sizeof(*pa_mech) - 1 + patype->pa_ctx_size); + if (pa_mech == NULL) + return NULL; + + pa_mech->patype = patype; + + if (pa_mech->patype->configure) { + krb5_error_code ret; + + ret = pa_mech->patype->configure(context, ctx, &pa_mech->pactx[0]); + if (ret) { + heim_release(pa_mech); + return NULL; + } + } + + _krb5_debug(context, 5, "Adding PA mech: %s", patype->name); + + return pa_mech; +} + +static void +pa_mech_add(krb5_context context, krb5_init_creds_context ctx, int pa_type) +{ + struct pa_auth_mech *mech; + + mech = pa_mech_create(context, ctx, pa_type); + if (mech) { + heim_array_append_value(ctx->available_pa_mechs, mech); + heim_release(mech); + } +} + +static krb5_error_code +pa_configure(krb5_context context, + krb5_init_creds_context ctx, + METHOD_DATA *in_md) +{ + ctx->available_pa_mechs = heim_array_create(); + + if (ctx->gss_init_ctx) { + pa_mech_add(context, ctx, KRB5_PADATA_GSS); + } else if (ctx->pk_init_ctx) { + pa_mech_add(context, ctx, KRB5_PADATA_PK_AS_REP); + pa_mech_add(context, ctx, KRB5_PADATA_PK_AS_REP_19); + } else if (ctx->keyproc || ctx->keyseed || ctx->prompter) { + pa_mech_add(context, ctx, KRB5_PADATA_ENCRYPTED_CHALLENGE); + pa_mech_add(context, ctx, KRB5_PADATA_ENC_TIMESTAMP); + } + /* XXX setup context based on KDC reply */ + + return 0; +} + +static krb5_error_code +pa_restart(krb5_context context, + krb5_init_creds_context ctx) +{ + krb5_error_code ret = HEIM_ERR_PA_CANT_CONTINUE; + + if (ctx->pa_mech && ctx->pa_mech->patype->restart) + ret = ctx->pa_mech->patype->restart(context, ctx, (void *)&ctx->pa_mech->pactx[0]); + + return ret; +} + + +static krb5_error_code +pa_step(krb5_context context, + krb5_init_creds_context ctx, + const AS_REQ *a, + const AS_REP *rep, + METHOD_DATA *in_md, + METHOD_DATA *out_md) +{ + krb5_error_code ret; + PA_DATA *pa = NULL; + int idx; + + next: + do { + if (ctx->pa_mech == NULL) { + size_t len = heim_array_get_length(ctx->available_pa_mechs); + if (len == 0) { + _krb5_debug(context, 0, "no more available_pa_mechs to try"); + return HEIM_ERR_NO_MORE_PA_MECHS; + } + + ctx->pa_mech = heim_array_copy_value(ctx->available_pa_mechs, 0); + heim_array_delete_value(ctx->available_pa_mechs, 0); + } + + if (ctx->fast_state.armor_crypto) { + if ((ctx->pa_mech->patype->flags & PA_F_FAST) == 0) { + _krb5_debug(context, 0, "pa-mech %s dropped under FAST (not supported)", + ctx->pa_mech->patype->name); + heim_release(ctx->pa_mech); + ctx->pa_mech = NULL; + continue; + } + } else { + if ((ctx->pa_mech->patype->flags & PA_F_NOT_FAST) == 0) { + _krb5_debug(context, 0, "dropped pa-mech %s since not running under FAST", + ctx->pa_mech->patype->name); + heim_release(ctx->pa_mech); + ctx->pa_mech = NULL; + continue; + } + } + + _krb5_debug(context, 0, "pa-mech trying: %s, searching for %d", + ctx->pa_mech->patype->name, ctx->pa_mech->patype->type); + + idx = 0; + if (in_md) + pa = krb5_find_padata(in_md->val, in_md->len, ctx->pa_mech->patype->type, &idx); + else + pa = NULL; + + } while (ctx->pa_mech == NULL); + + _krb5_debug(context, 5, "Stepping pa-mech: %s", ctx->pa_mech->patype->name); + + ret = ctx->pa_mech->patype->step(context, ctx, (void *)&ctx->pa_mech->pactx[0], pa, a, rep, in_md, out_md); + _krb5_debug(context, 10, "PA type %s returned %d", ctx->pa_mech->patype->name, ret); + if (ret == 0) { + struct pa_auth_mech *next_pa = ctx->pa_mech->next; + + if (next_pa) { + _krb5_debug(context, 5, "Next PA type in set is: %s", + next_pa->patype->name); + ret = HEIM_ERR_PA_CONTINUE_NEEDED; + } else if (rep == NULL) { + _krb5_debug(context, 5, "PA %s done, but no ticket in sight!!!", + ctx->pa_mech->patype->name); + ret = HEIM_ERR_PA_CANT_CONTINUE; + } else { + ctx->pa_used = ctx->pa_mech->patype->name; + } + + heim_retain(next_pa); + heim_release(ctx->pa_mech); + ctx->pa_mech = next_pa; + } + + if (ret == HEIM_ERR_PA_CANT_CONTINUE) { + if (ctx->pa_mech) { + _krb5_debug(context, 5, "Dropping PA type %s", ctx->pa_mech->patype->name); + heim_release(ctx->pa_mech); + ctx->pa_mech = NULL; + } + goto next; + } else if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) { + _krb5_debug(context, 5, "Continue needed for %s", ctx->pa_mech->patype->name); + } else if (ret != 0) { + _krb5_debug(context, 5, "Other error from mech %s: %d", ctx->pa_mech->patype->name, ret); + heim_release(ctx->pa_mech); + ctx->pa_mech = NULL; + } + + return ret; +} + +static void +log_kdc_pa_types(krb5_context context, METHOD_DATA *in_md) +{ + if (_krb5_have_debug(context, 5)) { + unsigned i; + _krb5_debug(context, 5, "KDC sent %d patypes", in_md->len); + for (i = 0; i < in_md->len; i++) + _krb5_debug(context, 5, "KDC sent PA-DATA type: %d (%s)", + in_md->val[i].padata_type, + get_pa_type_name(in_md->val[i].padata_type)); + } +} + +/* + * Assumes caller always will free `out_md', even on error. + */ + +static krb5_error_code +process_pa_data_to_md(krb5_context context, + const krb5_creds *creds, + const AS_REQ *a, + krb5_init_creds_context ctx, + METHOD_DATA *in_md, + METHOD_DATA **out_md) +{ + krb5_error_code ret; + + ALLOC(*out_md, 1); + if (*out_md == NULL) { + return krb5_enomem(context); + } + (*out_md)->len = 0; + (*out_md)->val = NULL; + + log_kdc_pa_types(context, in_md); + + ret = pa_step(context, ctx, a, NULL, in_md, *out_md); + if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) { + _krb5_debug(context, 0, "pamech need more stepping"); + } else if (ret == 0) { + _krb5_debug(context, 0, "pamech done step"); + } else { + return ret; + } + + /* + * Send announcement (what we support) and configuration (user + * introduced behavior change) + */ + ret = pa_announce(context, PA_F_ANNOUNCE|PA_F_CONFIG, ctx, in_md, *out_md); + + /* + * + */ + + if ((*out_md)->len == 0) { + free(*out_md); + *out_md = NULL; + } + + return ret; +} + +static krb5_error_code +process_pa_data_to_key(krb5_context context, + krb5_init_creds_context ctx, + krb5_creds *creds, + AS_REQ *a, + AS_REP *rep, + krb5_keyblock **key) +{ + struct pa_info_data paid, *ppaid = NULL; + krb5_error_code ret; + krb5_enctype etype = rep->enc_part.etype; + + memset(&paid, 0, sizeof(paid)); + + if (rep->padata) + log_kdc_pa_types(context, rep->padata); + + if (rep->padata) { + paid.etype = etype; + ppaid = process_pa_info(context, creds->client, a, &paid, + rep->padata); + } + if (ppaid == NULL) { + if (ctx->paid.etype == KRB5_ENCTYPE_NULL) { + ctx->paid.etype = etype; + ctx->paid.s2kparams = NULL; + ret = krb5_get_pw_salt (context, creds->client, &ctx->paid.salt); + if (ret) + return ret; + } + } + + ret = pa_step(context, ctx, a, rep, rep->padata, NULL); + if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) { + _krb5_debug(context, 0, "In final stretch and pa require more stepping ?"); + return ret; + } else if (ret == 0) { + _krb5_debug(context, 0, "final pamech done step"); + goto out; + } else { + return ret; + } + out: + free_paid(context, &paid); + return ret; +} + +/* + * + */ + +static krb5_error_code +capture_lkdc_domain(krb5_context context, + krb5_init_creds_context ctx) +{ + size_t len; + + len = strlen(_krb5_wellknown_lkdc); + + if (ctx->kdc_hostname != NULL || + strncmp(ctx->cred.client->realm, _krb5_wellknown_lkdc, len) != 0 || + ctx->cred.client->realm[len] != ':') + return 0; + + ctx->kdc_hostname = strdup(&ctx->cred.client->realm[len + 1]); + + _krb5_debug(context, 5, "krb5_get_init_creds: setting LKDC hostname to: %s", + ctx->kdc_hostname); + return 0; +} + +/** + * Start a new context to get a new initial credential. + * + * @param context A Kerberos 5 context. + * @param client The Kerberos principal to get the credential for, if + * NULL is given, the default principal is used as determined by + * krb5_get_default_principal(). + * @param prompter + * @param prompter_data + * @param start_time the time the ticket should start to be valid or 0 for now. + * @param options a options structure, can be NULL for default options. + * @param rctx A new allocated free with krb5_init_creds_free(). + * + * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_init(krb5_context context, + krb5_principal client, + krb5_prompter_fct prompter, + void *prompter_data, + krb5_deltat start_time, + krb5_get_init_creds_opt *options, + krb5_init_creds_context *rctx) +{ + krb5_init_creds_context ctx; + krb5_error_code ret; + + *rctx = NULL; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return krb5_enomem(context); + + ret = get_init_creds_common(context, client, prompter, prompter_data, + start_time, options, ctx); + if (ret) { + free(ctx); + return ret; + } + + /* Set a new nonce. */ + /* FIXME should generate a new nonce for each AS-REQ */ + krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); + ctx->nonce &= 0x7fffffff; + /* XXX these just need to be the same when using Windows PK-INIT */ + ctx->pk_nonce = ctx->nonce; + + ctx->prompter = prompter; + ctx->prompter_data = prompter_data; + + /* pick up hostname from LKDC realm name */ + ret = capture_lkdc_domain(context, ctx); + if (ret) { + free_init_creds_ctx(context, ctx); + return ret; + } + + ctx->runflags.allow_enc_pa_rep = 1; + + ctx->fast_state.flags |= KRB5_FAST_AS_REQ; + + *rctx = ctx; + + return ret; +} + +/** + * Set the KDC hostname for the initial request, it will not be + * considered in referrals to another KDC. + * + * @param context a Kerberos 5 context. + * @param ctx a krb5_init_creds_context context. + * @param hostname the hostname for the KDC of realm + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_kdc_hostname(krb5_context context, + krb5_init_creds_context ctx, + const char *hostname) +{ + if (ctx->kdc_hostname) + free(ctx->kdc_hostname); + ctx->kdc_hostname = strdup(hostname); + if (ctx->kdc_hostname == NULL) + return krb5_enomem(context); + return 0; +} + +/** + * Set the sitename for the request + * + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_sitename(krb5_context context, + krb5_init_creds_context ctx, + const char *sitename) +{ + if (ctx->sitename) + free(ctx->sitename); + ctx->sitename = strdup(sitename); + if (ctx->sitename == NULL) + return krb5_enomem(context); + return 0; +} + +/** + * Sets the service that the is requested. This call is only neede for + * special initial tickets, by default the a krbtgt is fetched in the default realm. + * + * @param context a Kerberos 5 context. + * @param ctx a krb5_init_creds_context context. + * @param service the service given as a string, for example + * "kadmind/admin". If NULL, the default krbtgt in the clients + * realm is set. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_service(krb5_context context, + krb5_init_creds_context ctx, + const char *service) +{ + krb5_const_realm client_realm; + krb5_principal principal; + krb5_error_code ret; + + client_realm = krb5_principal_get_realm (context, ctx->cred.client); + + if (service) { + ret = krb5_parse_name (context, service, &principal); + if (ret) + return ret; + ret = krb5_principal_set_realm (context, principal, client_realm); + if (ret) { + krb5_free_principal(context, principal); + return ret; + } + } else { + ret = krb5_make_principal(context, &principal, + client_realm, KRB5_TGS_NAME, client_realm, + NULL); + if (ret) + return ret; + } + + /* + * This is for Windows RODC that are picky about what name type + * the server principal have, and the really strange part is that + * they are picky about the AS-REQ name type and not the TGS-REQ + * later. Oh well. + */ + + if (krb5_principal_is_krbtgt(context, principal)) + krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST); + + krb5_free_principal(context, ctx->cred.server); + ctx->cred.server = principal; + + return 0; +} + +/** + * Sets the password that will use for the request. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param password the password to use. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_password(krb5_context context, + krb5_init_creds_context ctx, + const char *password) +{ + if (ctx->password) { + size_t len; + len = strlen(ctx->password); + memset_s(ctx->password, len, 0, len); + free(ctx->password); + } + if (password) { + ctx->password = strdup(password); + if (ctx->password == NULL) + return krb5_enomem(context); + ctx->keyseed = (void *) ctx->password; + } else { + ctx->keyseed = NULL; + ctx->password = NULL; + } + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +keytab_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); + krb5_keytab keytab = args->keytab; + krb5_principal principal = args->principal; + krb5_error_code ret; + krb5_keytab real_keytab = NULL; + krb5_keytab_entry entry; + + if (keytab == NULL) { + ret = krb5_kt_default(context, &real_keytab); + if (ret) + return ret; + keytab = real_keytab; + } + + ret = krb5_kt_get_entry (context, keytab, principal, 0, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock(context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + } + + krb5_kt_close(context, real_keytab); + return ret; +} + + +/** + * Set the keytab to use for authentication. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param keytab the keytab to read the key from. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_keytab(krb5_context context, + krb5_init_creds_context ctx, + krb5_keytab keytab) +{ + krb5_keytab_key_proc_args *a; + krb5_keytab_entry entry; + krb5_kt_cursor cursor; + krb5_enctype *etypes = NULL; + krb5_error_code ret; + size_t netypes = 0; + int kvno = 0, found = 0; + unsigned n; + + a = malloc(sizeof(*a)); + if (a == NULL) + return krb5_enomem(context); + + a->principal = ctx->cred.client; + a->keytab = keytab; + + ctx->keytab_data = a; + ctx->keyseed = (void *)a; + ctx->keyproc = keytab_key_proc; + + /* + * We need to tell the KDC what enctypes we support for this keytab, + * especially if the keytab is really a password based entry, then the + * KDC might have more enctypes in the database then what we have + * in the keytab. + */ + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if(ret) + goto out; + + while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){ + void *ptr; + + if (!krb5_principal_compare(context, entry.principal, ctx->cred.client)) + goto next; + + found = 1; + + /* check if we have this kvno already */ + if (entry.vno > kvno) { + /* remove old list of etype */ + if (etypes) + free(etypes); + etypes = NULL; + netypes = 0; + kvno = entry.vno; + } else if (entry.vno != kvno) + goto next; + + /* check if enctype is supported */ + if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0) + goto next; + + /* + * If user already provided a enctype list, use that as an + * additonal filter. + */ + if (ctx->etypes) { + for (n = 0; ctx->etypes[n] != KRB5_ENCTYPE_NULL; n++) { + if (ctx->etypes[n] == entry.keyblock.keytype) + break; + } + if (ctx->etypes[n] == KRB5_ENCTYPE_NULL) + goto next; + } + + /* add enctype to supported list */ + ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2)); + if (ptr == NULL) { + free(etypes); + ret = krb5_enomem(context); + goto out; + } + + etypes = ptr; + etypes[netypes] = entry.keyblock.keytype; + etypes[netypes + 1] = ETYPE_NULL; + netypes++; + next: + krb5_kt_free_entry(context, &entry); + } + krb5_kt_end_seq_get(context, keytab, &cursor); + + if (etypes) { + if (ctx->etypes) + free(ctx->etypes); + ctx->etypes = etypes; + } + + out: + if (!found) { + if (ret == 0) + ret = KRB5_KT_NOTFOUND; + _krb5_kt_principal_not_found(context, ret, keytab, ctx->cred.client, 0, 0); + } + + return ret; +} + +static krb5_error_code KRB5_CALLCONV +keyblock_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + return krb5_copy_keyblock (context, keyseed, key); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_keyblock(krb5_context context, + krb5_init_creds_context ctx, + krb5_keyblock *keyblock) +{ + ctx->keyseed = (void *)keyblock; + ctx->keyproc = keyblock_key_proc; + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_fast_ccache(krb5_context context, + krb5_init_creds_context ctx, + krb5_ccache fast_ccache) +{ + ctx->fast_state.armor_ccache = fast_ccache; + ctx->fast_state.flags |= KRB5_FAST_REQUIRED; + ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED; + return 0; +} + +static krb5_error_code +validate_pkinit_fx(krb5_context context, + krb5_init_creds_context ctx, + AS_REP *rep, + krb5_keyblock *ticket_sessionkey) +{ + PA_DATA *pa = NULL; + int idx = 0; + + if (rep->padata) + pa = krb5_find_padata(rep->padata->val, rep->padata->len, KRB5_PADATA_PKINIT_KX, &idx); + + if (pa == NULL) { + if (ctx->flags.request_anonymous && ctx->pk_init_ctx) { + /* XXX handle the case where pkinit is not used */ + krb5_set_error_message(context, KRB5_KDCREP_MODIFIED, + N_("Requested anonymous with PKINIT and KDC didn't set PKINIT_KX", "")); + return KRB5_KDCREP_MODIFIED; + } + + return 0; + } + + heim_assert(ctx->fast_state.reply_key != NULL, "must have a reply key at this stage"); + + return _krb5_pk_kx_confirm(context, + ctx->pk_init_ctx, + ctx->fast_state.reply_key, + ticket_sessionkey, + pa); +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_fast_ap_armor_service(krb5_context context, + krb5_init_creds_context ctx, + krb5_const_principal armor_service) +{ + krb5_error_code ret; + + if (ctx->fast_state.armor_service) + krb5_free_principal(context, ctx->fast_state.armor_service); + if (armor_service) { + ret = krb5_copy_principal(context, armor_service, &ctx->fast_state.armor_service); + if (ret) + return ret; + } else { + ctx->fast_state.armor_service = NULL; + } + ctx->fast_state.flags |= KRB5_FAST_AP_ARMOR_SERVICE; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_fast_anon_pkinit(krb5_context context, + krb5_init_creds_context ctx) +{ + if (ctx->fast_state.armor_ccache) + return EINVAL; + + ctx->fast_state.flags |= KRB5_FAST_REQUIRED; + ctx->fast_state.flags |= KRB5_FAST_ANON_PKINIT_ARMOR; + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_init_creds_set_fast_anon_pkinit_optimistic(krb5_context context, + krb5_init_creds_context ctx) +{ + if (ctx->fast_state.armor_ccache) + return EINVAL; + + ctx->fast_state.flags |= KRB5_FAST_REQUIRED; + ctx->fast_state.flags |= KRB5_FAST_ANON_PKINIT_ARMOR; + ctx->fast_state.flags |= KRB5_FAST_OPTIMISTIC; + return 0; +} + +static size_t +available_padata_count(METHOD_DATA *md) +{ + size_t i, count = 0; + + for (i = 0; i < md->len; i++) { + PA_DATA *pa = &md->val[i]; + + if (pa->padata_type == KRB5_PADATA_FX_COOKIE || + pa->padata_type == KRB5_PADATA_FX_ERROR) + continue; + + count++; + } + + return count; +} + +static krb5_error_code +init_creds_step(krb5_context context, + krb5_init_creds_context ctx, + const krb5_data *in, + krb5_data *out, + krb5_realm *out_realm, + unsigned int *flags) +{ + struct timeval start_time, end_time; + krb5_data checksum_data; + krb5_error_code ret; + size_t len = 0; + size_t size; + AS_REQ req2; + + gettimeofday(&start_time, NULL); + + krb5_data_zero(out); + *out_realm = NULL; + krb5_data_zero(&checksum_data); + + if (ctx->as_req.req_body.cname == NULL) { + ret = init_as_req(context, ctx->flags, &ctx->cred, + ctx->addrs, ctx->etypes, &ctx->as_req); + if (ret) + return ret; + if (ctx->fast_state.flags & KRB5_FAST_REQUIRED) + ; + else if (ctx->fast_state.flags & KRB5_FAST_AP_ARMOR_SERVICE) + /* Check with armor service if there is FAST */; + else + ctx->fast_state.flags |= KRB5_FAST_DISABLED; + + + /* XXX should happen after we get back reply from KDC */ + pa_configure(context, ctx, NULL); + } + +#define MAX_PA_COUNTER 15 + if (ctx->pa_counter > MAX_PA_COUNTER) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + N_("Looping %d times while getting " + "initial credentials", ""), + ctx->pa_counter); + return KRB5_GET_IN_TKT_LOOP; + } + ctx->pa_counter++; + + _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter); + + /* Lets process the input packet */ + if (in && in->length) { + krb5_kdc_rep rep; + + memset(&rep, 0, sizeof(rep)); + + _krb5_debug(context, 5, "krb5_get_init_creds: processing input"); + + ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); + if (ret == 0) { + unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; + krb5_data data; + + /* + * Unwrap AS-REP + */ + ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, + &rep.kdc_rep.ticket, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + ret = _krb5_fast_unwrap_kdc_rep(context, ctx->nonce, &data, + &ctx->fast_state, &rep.kdc_rep); + krb5_data_free(&data); + if (ret) + goto out; + + /* + * Now check and extract the ticket + */ + + if (ctx->flags.canonicalize) { + eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; + eflags |= EXTRACT_TICKET_MATCH_REALM; + } + if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) + eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + if (ctx->flags.request_anonymous) + eflags |= EXTRACT_TICKET_MATCH_ANON; + + ret = process_pa_data_to_key(context, ctx, &ctx->cred, + &ctx->as_req, &rep.kdc_rep, + &ctx->fast_state.reply_key); + if (ret) { + free_AS_REP(&rep.kdc_rep); + goto out; + } + + if (ctx->fast_state.strengthen_key) { + krb5_keyblock result; + + _krb5_debug(context, 5, "krb5_get_init_creds: FAST strengthen_key"); + + ret = _krb5_fast_cf2(context, + ctx->fast_state.strengthen_key, + "strengthenkey", + ctx->fast_state.reply_key, + "replykey", + &result, + NULL); + if (ret) { + free_AS_REP(&rep.kdc_rep); + goto out; + } + + ctx->runflags.allow_save_as_reply_key = 1; + + krb5_free_keyblock_contents(context, ctx->fast_state.reply_key); + *ctx->fast_state.reply_key = result; + } + + _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket"); + + ret = _krb5_extract_ticket(context, + &rep, + &ctx->cred, + ctx->fast_state.reply_key, + NULL, + KRB5_KU_AS_REP_ENC_PART, + NULL, + ctx->nonce, + eflags, + &ctx->req_buffer, + NULL, + NULL); + + if (ret == 0) + ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); + if (ret == 0) + ret = validate_pkinit_fx(context, ctx, &rep.kdc_rep, &ctx->cred.session); + + ctx->as_enctype = ctx->fast_state.reply_key->keytype; + + if (ctx->runflags.allow_save_as_reply_key) { + ctx->as_reply_key = ctx->fast_state.reply_key; + ctx->fast_state.reply_key = NULL; + } else { + krb5_free_keyblock(context, ctx->fast_state.reply_key); + ctx->fast_state.reply_key = NULL; + } + ctx->ic_flags |= KRB5_INIT_CREDS_DONE; + *flags = 0; + + free_AS_REP(&rep.kdc_rep); + free_EncASRepPart(&rep.enc_part); + + gettimeofday(&end_time, NULL); + timevalsub(&end_time, &start_time); + timevaladd(&ctx->stats.run_time, &end_time); + + _krb5_debug(context, 1, "krb5_get_init_creds: wc: %lld.%06ld", + (long long)ctx->stats.run_time.tv_sec, + (long)ctx->stats.run_time.tv_usec); + return ret; + + } else { + /* let's try to parse it as a KRB-ERROR */ + + _krb5_debug(context, 5, "krb5_get_init_creds: got an KRB-ERROR from KDC"); + + free_KRB_ERROR(&ctx->error); + + ret = krb5_rd_error(context, in, &ctx->error); + if(ret && in->length && ((char*)in->data)[0] == 4) + ret = KRB5KRB_AP_ERR_V4_REPLY; + if (ret) { + _krb5_debug(context, 5, "krb5_get_init_creds: failed to read error"); + goto out; + } + + /* + * Unwrap method-data, if there is any, + * fast_unwrap_error() below might replace it with a + * wrapped version if we are using FAST. + */ + + free_METHOD_DATA(&ctx->md); + memset(&ctx->md, 0, sizeof(ctx->md)); + + if (ctx->error.e_data) { + KERB_ERROR_DATA kerb_error_data; + krb5_error_code ret2; + + memset(&kerb_error_data, 0, sizeof(kerb_error_data)); + + /* First try to decode the e-data as KERB-ERROR-DATA. */ + ret2 = decode_KERB_ERROR_DATA(ctx->error.e_data->data, + ctx->error.e_data->length, + &kerb_error_data, + &len); + if (ret2) { + /* That failed, so try to decode it as METHOD-DATA. */ + ret2 = decode_METHOD_DATA(ctx->error.e_data->data, + ctx->error.e_data->length, + &ctx->md, + NULL); + if (ret2) { + /* + * Just ignore any error, the error will be pushed + * out from krb5_error_from_rd_error() if there + * was one. + */ + _krb5_debug(context, 5, N_("Failed to decode METHOD-DATA", "")); + } + } else if (len != ctx->error.e_data->length) { + /* Trailing data — just ignore the error. */ + free_KERB_ERROR_DATA(&kerb_error_data); + } else { + /* OK. */ + free_KERB_ERROR_DATA(&kerb_error_data); + } + } + + /* + * Unwrap KRB-ERROR, we are always calling this so that + * FAST can tell us if your peer KDC suddenly dropped FAST + * wrapping and its really an attacker's packet (or a bug + * in the KDC). + */ + ret = _krb5_fast_unwrap_error(context, ctx->nonce, &ctx->fast_state, + &ctx->md, &ctx->error); + if (ret) + goto out; + + /* + * + */ + + ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); + + /* log the failure */ + if (_krb5_have_debug(context, 5)) { + const char *str = krb5_get_error_message(context, ret); + _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d/%s", ret, str); + krb5_free_error_message(context, str); + } + + /* + * Handle special error codes + */ + + if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED + || ret == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED + || ret == KRB5KDC_ERR_ETYPE_NOSUPP) + { + /* + * If no preauth was set and KDC requires it, give it one + * more try. + * + * If the KDC returned KRB5KDC_ERR_ETYPE_NOSUPP, just loop + * one more time since that might mean we are dealing with + * a Windows KDC that is confused about what enctypes are + * available. + */ + + if (available_padata_count(&ctx->md) == 0) { + krb5_set_error_message(context, ret, + N_("Preauth required but no preauth " + "options sent by KDC", "")); + goto out; + } + } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { + /* + * Try adapt to timeskrew when we are using pre-auth, and + * if there was a time skew, try again. + */ + krb5_set_real_time(context, ctx->error.stime, -1); + if (context->kdc_sec_offset) + ret = 0; + + _krb5_debug(context, 10, "init_creds: err skew updating kdc offset to %d", + context->kdc_sec_offset); + if (ret) + goto out; + + pa_restart(context, ctx); + + } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { + /* client referral to a new realm */ + char *ref_realm; + + if (ctx->error.crealm == NULL) { + krb5_set_error_message(context, ret, + N_("Got a client referral, not but no realm", "")); + goto out; + } + ref_realm = *ctx->error.crealm; + + _krb5_debug(context, 5, "krb5_get_init_creds: referral to realm %s", + ref_realm); + + /* + * If its a krbtgt, lets update the requested krbtgt too + */ + if (krb5_principal_is_krbtgt(context, ctx->cred.server)) { + + free(ctx->cred.server->name.name_string.val[1]); + ctx->cred.server->name.name_string.val[1] = strdup(ref_realm); + if (ctx->cred.server->name.name_string.val[1] == NULL) { + ret = krb5_enomem(context); + goto out; + } + + free_PrincipalName(ctx->as_req.req_body.sname); + ret = _krb5_principal2principalname(ctx->as_req.req_body.sname, ctx->cred.server); + if (ret) + goto out; + } + + free(ctx->as_req.req_body.realm); + ret = copy_Realm(&ref_realm, &ctx->as_req.req_body.realm); + if (ret) + goto out; + + ret = krb5_principal_set_realm(context, + ctx->cred.client, + *ctx->error.crealm); + if (ret) + goto out; + + ret = krb5_unparse_name(context, ctx->cred.client, &ref_realm); + if (ret == 0) { + _krb5_debug(context, 5, "krb5_get_init_creds: got referral to %s", ref_realm); + krb5_xfree(ref_realm); + } + + pa_restart(context, ctx); + + } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 && + ctx->runflags.change_password_prompt) { + char buf2[1024]; + + ctx->runflags.change_password = 1; + + ctx->prompter(context, ctx->prompter_data, NULL, N_("Password has expired", ""), 0, NULL); + + /* try to avoid recursion */ + if (ctx->in_tkt_service != NULL && strcmp(ctx->in_tkt_service, "kadmin/changepw") == 0) + goto out; + + /* don't include prompter in runtime */ + gettimeofday(&end_time, NULL); + timevalsub(&end_time, &start_time); + timevaladd(&ctx->stats.run_time, &end_time); + + ret = change_password(context, + ctx->cred.client, + ctx->password, + buf2, + sizeof(buf2), + ctx->prompter, + ctx->prompter_data, + NULL); + if (ret) + goto out; + + gettimeofday(&start_time, NULL); + + krb5_init_creds_set_password(context, ctx, buf2); + + pa_restart(context, ctx); + + } else if (ret == KRB5KDC_ERR_PREAUTH_FAILED) { + + /* + * Old MIT KDC can't handle KRB5_PADATA_REQ_ENC_PA_REP, + * so drop it and try again. But only try that for MIT + * Kerberos servers by keying of no METHOD-DATA. + */ + if (ctx->runflags.allow_enc_pa_rep) { + if (ctx->md.len != 0) { + _krb5_debug(context, 10, "Server sent PA data with KRB-ERROR, " + "so not a pre 1.7 MIT KDC and won't retry w/o ENC-PA-REQ"); + goto out; + } + _krb5_debug(context, 10, "Disabling allow_enc_pa_rep and trying again"); + ctx->runflags.allow_enc_pa_rep = 0; + goto retry; + } + + if (ctx->fast_state.flags & KRB5_FAST_DISABLED) { + _krb5_debug(context, 10, "FAST disabled and got preauth failed"); + goto out; + } + + retry: + pa_restart(context, ctx); + + } else if (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) { + _krb5_debug(context, 10, + "Some other error %d failed with optimistic FAST, trying w/o FAST", ret); + + ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; + ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED; + ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR; + ctx->fast_state.flags |= KRB5_FAST_DISABLED; + pa_restart(context, ctx); + } else { + /* some other error code from the KDC, lets' return it to the user */ + goto out; + } + } + } + + if (ctx->as_req.padata) { + free_METHOD_DATA(ctx->as_req.padata); + free(ctx->as_req.padata); + ctx->as_req.padata = NULL; + } + + ret = _krb5_fast_create_armor(context, &ctx->fast_state, + ctx->cred.client->realm); + if (ret) + goto out; + + /* Set a new nonce. */ + ctx->as_req.req_body.nonce = ctx->nonce; + + + /* + * Step and announce PA-DATA + */ + + ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, + &ctx->md, &ctx->as_req.padata); + if (ret) + goto out; + + + /* + * Wrap with FAST + */ + ret = copy_AS_REQ(&ctx->as_req, &req2); + if (ret) + goto out; + + ret = _krb5_fast_wrap_req(context, + &ctx->fast_state, + &req2); + + krb5_data_free(&checksum_data); + if (ret) { + free_AS_REQ(&req2); + goto out; + } + + krb5_data_free(&ctx->req_buffer); + + ASN1_MALLOC_ENCODE(AS_REQ, + ctx->req_buffer.data, ctx->req_buffer.length, + &req2, &len, ret); + free_AS_REQ(&req2); + if (ret) + goto out; + if(len != ctx->req_buffer.length) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_data_copy(out, + ctx->req_buffer.data, + ctx->req_buffer.length); + if (ret) + goto out; + + *out_realm = strdup(ctx->cred.client->realm); + if (*out_realm == NULL) { + krb5_data_free(out); + ret = ENOMEM; + goto out; + } + + *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE; + + gettimeofday(&end_time, NULL); + timevalsub(&end_time, &start_time); + timevaladd(&ctx->stats.run_time, &end_time); + + return 0; + out: + return ret; +} + +/** + * The core loop if krb5_get_init_creds() function family. Create the + * packets and have the caller send them off to the KDC. + * + * If the caller want all work been done for them, use + * krb5_init_creds_get() instead. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param in input data from KDC, first round it should be reset by krb5_data_zero(). + * @param out reply to KDC. The caller needs to call krb5_data_free() + * @param out_realm the destination realm for 'out', free with krb5_xfree() + * @param flags status of the round, if + * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round. + * + * @return 0 for success, or an Kerberos 5 error code, see + * krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_step(krb5_context context, + krb5_init_creds_context ctx, + const krb5_data *in, + krb5_data *out, + krb5_realm *out_realm, + unsigned int *flags) +{ + krb5_error_code ret; + krb5_data empty; + + krb5_data_zero(&empty); + krb5_data_zero(out); + *out_realm = NULL; + + if ((ctx->fast_state.flags & KRB5_FAST_ANON_PKINIT_ARMOR) && + ctx->fast_state.armor_ccache == NULL) { + ret = _krb5_fast_anon_pkinit_step(context, ctx, &ctx->fast_state, + in, out, out_realm, flags); + if (ret && (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC)) { + _krb5_debug(context, 5, "Preauth failed with optimistic " + "FAST, trying w/o FAST"); + ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC; + ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED; + ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR; + } else if (ret || + (*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) + return ret; + + in = ∅ + } + + return init_creds_step(context, ctx, in, out, out_realm, flags); +} + +/** + * Extract the newly acquired credentials from krb5_init_creds_context + * context. + * + * @param context A Kerberos 5 context. + * @param ctx + * @param cred credentials, free with krb5_free_cred_contents(). + * + * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_get_creds(krb5_context context, + krb5_init_creds_context ctx, + krb5_creds *cred) +{ + return krb5_copy_creds_contents(context, &ctx->cred, cred); +} + +/** + * Extract the as-reply key from the context. + * + * Only allowed when the as-reply-key is not directly derived from the + * password like PK-INIT, GSS, FAST hardened key, etc. + * + * @param context A Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param as_reply_key keyblock, free with krb5_free_keyblock_contents(). + * + * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_get_as_reply_key(krb5_context context, + krb5_init_creds_context ctx, + krb5_keyblock *as_reply_key) +{ + if (ctx->as_reply_key == NULL) + return KRB5KDC_ERR_PREAUTH_REQUIRED; + return krb5_copy_keyblock_contents(context, ctx->as_reply_key, as_reply_key); +} + +KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL +_krb5_init_creds_get_cred_starttime(krb5_context context, krb5_init_creds_context ctx) +{ + return ctx->cred.times.starttime; +} + +KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL +_krb5_init_creds_get_cred_endtime(krb5_context context, krb5_init_creds_context ctx) +{ + return ctx->cred.times.endtime; +} + +KRB5_LIB_FUNCTION krb5_principal KRB5_LIB_CALL +_krb5_init_creds_get_cred_client(krb5_context context, krb5_init_creds_context ctx) +{ + return ctx->cred.client; +} + +/** + * Get the last error from the transaction. + * + * @return Returns 0 or an error code + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_get_error(krb5_context context, + krb5_init_creds_context ctx, + KRB_ERROR *error) +{ + krb5_error_code ret; + + ret = copy_KRB_ERROR(&ctx->error, error); + if (ret) + krb5_enomem(context); + + return ret; +} + +/** + * Store config + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to free. + * @param id store + * + * @return Returns 0 or an error code + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_store_config(krb5_context context, + krb5_init_creds_context ctx, + krb5_ccache id) +{ + krb5_error_code ret; + + if (ctx->kdc_hostname) { + krb5_data data; + data.length = strlen(ctx->kdc_hostname); + data.data = ctx->kdc_hostname; + + ret = krb5_cc_set_config(context, id, NULL, "lkdc-hostname", &data); + if (ret) + return ret; + } + if (ctx->sitename) { + krb5_data data; + data.length = strlen(ctx->sitename); + data.data = ctx->sitename; + + ret = krb5_cc_set_config(context, id, NULL, "sitename", &data); + if (ret) + return ret; + } + + return 0; +} + +/** + * + * @ingroup krb5_credential + */ + +krb5_error_code +krb5_init_creds_store(krb5_context context, + krb5_init_creds_context ctx, + krb5_ccache id) +{ + krb5_error_code ret; + + if (ctx->cred.client == NULL) { + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; + krb5_set_error_message(context, ret, "init creds not completed yet"); + return ret; + } + + ret = krb5_cc_initialize(context, id, ctx->cred.client); + if (ret) + return ret; + + ret = krb5_cc_store_cred(context, id, &ctx->cred); + if (ret) + return ret; + + if (ctx->cred.flags.b.enc_pa_rep) { + krb5_data data = { 3, rk_UNCONST("yes") }; + ret = krb5_cc_set_config(context, id, ctx->cred.server, + "fast_avail", &data); + if (ret && ret != KRB5_CC_NOSUPP) + return ret; + } + + return 0; +} + +/** + * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to free. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_init_creds_free(krb5_context context, + krb5_init_creds_context ctx) +{ + free_init_creds_ctx(context, ctx); + free(ctx); +} + +/** + * Get new credentials as setup by the krb5_init_creds_context. + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to process. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_sendto_ctx stctx = NULL; + krb5_error_code ret; + krb5_data in, out; + unsigned int flags = 0; + + krb5_data_zero(&in); + krb5_data_zero(&out); + + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + goto out; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + + if (ctx->kdc_hostname) + krb5_sendto_set_hostname(context, stctx, ctx->kdc_hostname); + if (ctx->sitename) + krb5_sendto_set_sitename(context, stctx, ctx->sitename); + + while (1) { + struct timeval nstart, nend; + krb5_realm realm = NULL; + + flags = 0; + ret = krb5_init_creds_step(context, ctx, &in, &out, &realm, &flags); + krb5_data_free(&in); + if (ret) + goto out; + + if ((flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0) + break; + + gettimeofday(&nstart, NULL); + + ret = krb5_sendto_context (context, stctx, &out, realm, &in); + krb5_data_free(&out); + free(realm); + if (ret) + goto out; + + gettimeofday(&nend, NULL); + timevalsub(&nend, &nstart); + timevaladd(&ctx->stats.run_time, &nend); + } + + out: + if (stctx) + krb5_sendto_ctx_free(context, stctx); + + return ret; +} + +/** + * Get new credentials using password. + * + * @ingroup krb5_credential + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_password(krb5_context context, + krb5_creds *creds, + krb5_principal client, + const char *password, + krb5_prompter_fct prompter, + void *data, + krb5_deltat start_time, + const char *in_tkt_service, + krb5_get_init_creds_opt *options) +{ + krb5_init_creds_context ctx; + char buf[BUFSIZ], buf2[BUFSIZ]; + krb5_error_code ret; + int chpw = 0; + + again: + ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + if (prompter != NULL && ctx->password == NULL && password == NULL) { + krb5_prompt prompt; + krb5_data password_data; + char *p, *q = NULL; + int aret; + + ret = krb5_unparse_name(context, client, &p); + if (ret) + goto out; + + aret = asprintf(&q, "%s's Password: ", p); + free (p); + if (aret == -1 || q == NULL) { + ret = krb5_enomem(context); + goto out; + } + prompt.prompt = q; + password_data.data = buf; + password_data.length = sizeof(buf); + prompt.hidden = 1; + prompt.reply = &password_data; + prompt.type = KRB5_PROMPT_TYPE_PASSWORD; + + ret = (*prompter) (context, data, NULL, NULL, 1, &prompt); + free (q); + if (ret) { + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + ret = KRB5_LIBOS_PWDINTR; + krb5_clear_error_message (context); + goto out; + } + password = password_data.data; + } + + if (password) { + ret = krb5_init_creds_set_password(context, ctx, password); + if (ret) + goto out; + } + + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + krb5_process_last_request(context, options, ctx); + + + if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { + /* try to avoid recursion */ + if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) + goto out; + + /* don't try to change password if no prompter or prompting disabled */ + if (!ctx->runflags.change_password_prompt) + goto out; + + ret = change_password (context, + client, + ctx->password, + buf2, + sizeof(buf2), + prompter, + data, + options); + if (ret) + goto out; + password = buf2; + chpw = 1; + krb5_init_creds_free(context, ctx); + goto again; + } + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + + memset_s(buf, sizeof(buf), 0, sizeof(buf)); + memset_s(buf2, sizeof(buf), 0, sizeof(buf2)); + return ret; +} + +/** + * Get new credentials using keyblock. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_keyblock(krb5_context context, + krb5_creds *creds, + krb5_principal client, + krb5_keyblock *keyblock, + krb5_deltat start_time, + const char *in_tkt_service, + krb5_get_init_creds_opt *options) +{ + krb5_init_creds_context ctx; + krb5_error_code ret; + + memset(creds, 0, sizeof(*creds)); + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keyblock(context, ctx, keyblock); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + krb5_process_last_request(context, options, ctx); + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + + return ret; +} + +/** + * Get new credentials using keytab. + * + * @ingroup krb5_credential + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_keytab(krb5_context context, + krb5_creds *creds, + krb5_principal client, + krb5_keytab keytab, + krb5_deltat start_time, + const char *in_tkt_service, + krb5_get_init_creds_opt *options) +{ + krb5_init_creds_context ctx; + krb5_keytab_entry ktent; + krb5_error_code ret; + + memset(&ktent, 0, sizeof(ktent)); + memset(creds, 0, sizeof(*creds)); + + if (strcmp(client->realm, "") == 0) { + /* + * Referral realm. We have a keytab, so pick a realm by + * matching in the keytab. + */ + ret = krb5_kt_get_entry(context, keytab, client, 0, 0, &ktent); + if (ret == 0) + client = ktent.principal; + } + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keytab(context, ctx, keytab); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + if (ret == 0) + krb5_process_last_request(context, options, ctx); + + out: + krb5_kt_free_entry(context, &ktent); + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + + return ret; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_init_creds_set_gss_mechanism(krb5_context context, + krb5_gss_init_ctx gssic, + const struct gss_OID_desc_struct *gss_mech) +{ + gssic->mech = gss_mech; /* OIDs are interned, so no copy required */ +} + +KRB5_LIB_FUNCTION const struct gss_OID_desc_struct * KRB5_LIB_CALL +_krb5_init_creds_get_gss_mechanism(krb5_context context, + krb5_gss_init_ctx gssic) +{ + return gssic->mech; +} + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +_krb5_init_creds_set_gss_cred(krb5_context context, + krb5_gss_init_ctx gssic, + struct gss_cred_id_t_desc_struct *gss_cred) +{ + if (gssic->cred != gss_cred && gssic->flags.release_cred) + gssic->release_cred(context, gssic, gssic->cred); + + gssic->cred = gss_cred; + gssic->flags.release_cred = 1; +} + +KRB5_LIB_FUNCTION const struct gss_cred_id_t_desc_struct * KRB5_LIB_CALL +_krb5_init_creds_get_gss_cred(krb5_context context, + krb5_gss_init_ctx gssic) +{ + return gssic->cred; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_init_creds_init_gss(krb5_context context, + krb5_init_creds_context ctx, + krb5_gssic_step step, + krb5_gssic_finish finish, + krb5_gssic_release_cred release_cred, + krb5_gssic_delete_sec_context delete_sec_context, + const struct gss_cred_id_t_desc_struct *gss_cred, + const struct gss_OID_desc_struct *gss_mech, + unsigned int flags) +{ + krb5_gss_init_ctx gssic; + + gssic = calloc(1, sizeof(*gssic)); + if (gssic == NULL) + return krb5_enomem(context); + + if (ctx->gss_init_ctx) + free_gss_init_ctx(context, ctx->gss_init_ctx); + ctx->gss_init_ctx = gssic; + + gssic->cred = (struct gss_cred_id_t_desc_struct *)gss_cred; + gssic->mech = gss_mech; + if (flags & KRB5_GSS_IC_FLAG_RELEASE_CRED) + gssic->flags.release_cred = 1; + + gssic->step = step; + gssic->finish = finish; + gssic->release_cred = release_cred; + gssic->delete_sec_context = delete_sec_context; + + return 0; +} diff --git a/third_party/heimdal/lib/krb5/k524_err.et b/third_party/heimdal/lib/krb5/k524_err.et new file mode 100644 index 0000000..4827b39 --- /dev/null +++ b/third_party/heimdal/lib/krb5/k524_err.et @@ -0,0 +1,20 @@ +# +# Error messages for the k524 functions +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table k524 + +prefix KRB524 +error_code BADKEY, "wrong keytype in ticket" +error_code BADADDR, "incorrect network address" +error_code BADPRINC, "cannot convert V5 principal" #unused +error_code BADREALM, "V5 realm name longer than V4 maximum" #unused +error_code V4ERR, "kerberos V4 error server" +error_code ENCFULL, "encoding too large at server" +error_code DECEMPTY, "decoding out of data" #unused +error_code NOTRESP, "service not responding" #unused +end + diff --git a/third_party/heimdal/lib/krb5/k5e1_err.et b/third_party/heimdal/lib/krb5/k5e1_err.et new file mode 100644 index 0000000..19414f1 --- /dev/null +++ b/third_party/heimdal/lib/krb5/k5e1_err.et @@ -0,0 +1,13 @@ +id "$Id$" + +error_table k5e1 + +index 4 + +prefix KRB5_DCC +error_code CANNOT_CREATE, "Can't create new subsidiary cache" + +prefix KRB5_KCC +error_code INVALID_ANCHOR, "Invalid keyring anchor name" +error_code UNKNOWN_VERSION, "Unknown keyring collection version" +error_code INVALID_UID, "Invalid UID in persistent keyring name" diff --git a/third_party/heimdal/lib/krb5/kcm.c b/third_party/heimdal/lib/krb5/kcm.c new file mode 100644 index 0000000..17a26e3 --- /dev/null +++ b/third_party/heimdal/lib/krb5/kcm.c @@ -0,0 +1,1505 @@ +/* + * Copyright (c) 2005, PADL Software Pty Ltd. + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifdef HAVE_KCM +/* + * Client library for Kerberos Credentials Manager (KCM) daemon + */ + +#include "kcm.h" +#include + +static krb5_error_code +kcm_set_kdc_offset(krb5_context, krb5_ccache, krb5_deltat); + +static const char *kcm_ipc_name = "ANY:org.h5l.kcm"; + +typedef struct krb5_kcmcache { + char *name; +} krb5_kcmcache; + +typedef struct krb5_kcm_cursor { + unsigned long offset; + unsigned long length; + kcmuuid_t *uuids; +} *krb5_kcm_cursor; + + +#define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) +#define CACHENAME(X) (KCMCACHE(X)->name) +#define KCMCURSOR(C) ((krb5_kcm_cursor)(C)) + +static HEIMDAL_MUTEX kcm_mutex = HEIMDAL_MUTEX_INITIALIZER; +static heim_ipc kcm_ipc = NULL; + +static krb5_error_code +kcm_send_request(krb5_context context, + krb5_storage *request, + krb5_data *response_data) +{ + krb5_error_code ret = 0; + krb5_data request_data; + + krb5_data_zero(response_data); + + HEIMDAL_MUTEX_lock(&kcm_mutex); + if (kcm_ipc == NULL) + ret = heim_ipc_init_context(kcm_ipc_name, &kcm_ipc); + HEIMDAL_MUTEX_unlock(&kcm_mutex); + if (ret) + return KRB5_CC_NOSUPP; + + ret = krb5_storage_to_data(request, &request_data); + if (ret) { + return krb5_enomem(context); + } + + ret = heim_ipc_call(kcm_ipc, &request_data, response_data, NULL); + krb5_data_free(&request_data); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kcm_storage_request(krb5_context context, + uint16_t opcode, + krb5_storage **storage_p) +{ + krb5_storage *sp; + krb5_error_code ret; + + *storage_p = NULL; + + sp = krb5_storage_emem(); + if (sp == NULL) + return krb5_enomem(context); + + /* Send MAJOR | VERSION | OPCODE */ + ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR); + if (ret) + goto fail; + ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR); + if (ret) + goto fail; + ret = krb5_store_int16(sp, opcode); + if (ret) + goto fail; + + *storage_p = sp; + fail: + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to encode KCM request", "")); + krb5_storage_free(sp); + } + + return ret; +} + +/* + * A sort of a state() for caches -- we use this to see if the local default + * cache name for KCM happens to exist. See kcm_alloc() below. + */ +static krb5_error_code +kcm_stat(krb5_context context, const char *name) +{ + krb5_error_code ret; + krb5_storage *request = NULL; + krb5_data response_data; + + krb5_data_zero(&response_data); + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); + if (ret == 0) + ret = krb5_store_stringz(request, name); + if (ret == 0) + ret = krb5_kcm_call(context, request, NULL, &response_data); + krb5_storage_free(request); + krb5_data_free(&response_data); + return ret; +} + +static krb5_error_code kcm_get_default_name(krb5_context, + const krb5_cc_ops *, + const char *, char **); + +static krb5_error_code +kcm_alloc(krb5_context context, + const krb5_cc_ops *ops, + const char *residual, + const char *sub, + krb5_ccache *id) +{ + krb5_error_code ret; + krb5_kcmcache *k; + size_t ops_prefix_len = strlen(ops->prefix); + size_t plen = 0; + size_t local_def_name_len; + char *local_def_name = NULL; /* Our idea of default KCM cache name */ + char *kcm_def_name = NULL; /* KCM's knowledge of default cache name */ + int aret; + + /* Get the KCM:%{UID} default */ + if (ops == &krb5_kcm_ops) + ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_KCM, &local_def_name); + else + ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_API, &local_def_name); + if (ret) + return ret; + local_def_name_len = strlen(local_def_name); + + /* Get the default ccache name from KCM if possible */ + (void) kcm_get_default_name(context, ops, NULL, &kcm_def_name); + + /* + * We have a sticky situation in that applications that call + * krb5_cc_default() will be getting the locally configured or compiled-in + * default KCM cache name, which may not exist in the user's KCM session, + * and which the KCM daemon may not be able to alias to the actual default + * for the user's session. + * + * To deal with this we heuristically detect when an application uses the + * default KCM ccache name. + * + * If the residual happens to be the local default KCM name we may end up + * using whatever the default KCM cache name is instead of the local + * default. + * + * Note that here `residual' may be any of: + * + * - %{UID} + * - %{UID}: + * - %{UID}: + * - + * - + * - + * + * Only the first two count as "maybe I mean the default KCM cache". + */ + if (residual && !sub && + strncmp(residual, local_def_name + ops_prefix_len + 1, + local_def_name_len - (ops_prefix_len + 1)) == 0) { + if (residual[local_def_name_len - (ops_prefix_len + 1)] == '\0' || + (residual[local_def_name_len - (ops_prefix_len + 1)] == ':' && + residual[local_def_name_len - ops_prefix_len] == '\0')) { + /* + * If we got a default cache name from KCM and the requested default + * cache does not exist, use the former. + */ + if (kcm_def_name && kcm_stat(context, residual)) + residual = kcm_def_name + ops_prefix_len + 1; + } + } + + if (residual && residual[0] == '\0') + residual = NULL; + if (sub && sub[0] == '\0') + sub = NULL; + + if (residual == NULL && sub == NULL) { + /* Use the default cache name, either from KCM or local default */ + if (kcm_def_name) + residual = kcm_def_name + ops_prefix_len + 1; + else + residual = local_def_name + ops_prefix_len + 1; + } + + if (residual) { + /* KCM cache names must start with {UID} or {UID}: */ + plen = strspn(residual, "0123456789"); + if (plen && residual[plen] != ':' && residual[plen] != '\0') + plen = 0; + /* + * If `plen', then residual is such a residual, else we'll want to + * prefix the {UID}:. + */ + } + + k = calloc(1, sizeof(*k)); + if (k == NULL) { + free(local_def_name); + free(kcm_def_name); + return krb5_enomem(context); + } + k->name = NULL; + + if (residual == NULL && sub == NULL) { + /* One more way to get a default */ + aret = asprintf(&k->name, "%llu", (unsigned long long)getuid()); + } else if (residual == NULL) { + /* + * Treat the subsidiary as the residual (maybe this will turn out to be + * wrong). + */ + aret = asprintf(&k->name, "%llu:%s", (unsigned long long)getuid(), + sub); + } else if (plen) { + /* The residual is a UID */ + aret = asprintf(&k->name, "%s%s%s", residual, + sub ? ":" : "", sub ? sub : ""); + } else if (sub == NULL) { + /* The residual is NOT a UID */ + aret = asprintf(&k->name, "%llu:%s", (unsigned long long)getuid(), + residual); + } else { + /* Ditto, plus we have a subsidiary. `residual && sub && !plen' */ + aret = asprintf(&k->name, "%llu:%s:%s", (unsigned long long)getuid(), + residual, sub); + } + if (aret == -1 || k->name == NULL) { + free(local_def_name); + free(kcm_def_name); + free(k); + return krb5_enomem(context); + } + + free(local_def_name); + free(kcm_def_name); + (*id)->data.data = k; + (*id)->data.length = sizeof(*k); + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kcm_call(krb5_context context, + krb5_storage *request, + krb5_storage **response_p, + krb5_data *response_data_p) +{ + krb5_data response_data; + krb5_error_code ret; + int32_t status; + krb5_storage *response; + + if (response_p != NULL) + *response_p = NULL; + + krb5_data_zero(&response_data); + ret = kcm_send_request(context, request, &response_data); + if (ret) { + krb5_data_free(&response_data); + return ret; + } + + response = krb5_storage_from_data(&response_data); + if (response == NULL) { + krb5_data_free(&response_data); + return KRB5_CC_IO; + } + + ret = krb5_ret_int32(response, &status); + if (ret) { + krb5_storage_free(response); + krb5_data_free(&response_data); + return KRB5_CC_FORMAT; + } + + if (status) { + krb5_storage_free(response); + krb5_data_free(&response_data); + return status; + } + + if (response_p != NULL) { + *response_data_p = response_data; + *response_p = response; + + return 0; + } + + krb5_storage_free(response); + krb5_data_free(&response_data); + + return 0; +} + +static void +kcm_free(krb5_context context, krb5_ccache *id) +{ + krb5_kcmcache *k = KCMCACHE(*id); + + if (k != NULL) { + free(k->name); + memset_s(k, sizeof(*k), 0, sizeof(*k)); + krb5_data_free(&(*id)->data); + } +} + +static krb5_error_code KRB5_CALLCONV +kcm_get_name_2(krb5_context context, + krb5_ccache id, + const char **name, + const char **col, + const char **sub) +{ + /* + * TODO: + * + * - name should be : + * - col should be + * - sub should be + */ + if (name) + *name = CACHENAME(id); + if (col) + *col = NULL; + if (sub) + *sub = CACHENAME(id); + return 0; +} + +static krb5_error_code +kcm_resolve_2_kcm(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) +{ + /* + * For now, for KCM the `res' is the `sub'. + * + * TODO: We should use `res' as the IPC name instead of the one currently + * hard-coded in `kcm_ipc_name'. + */ + return kcm_alloc(context, &krb5_kcm_ops, res, sub, id); +} + +static krb5_error_code +kcm_resolve_2_api(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) +{ + /* + * For now, for KCM the `res' is the `sub'. + * + * TODO: We should use `res' as the IPC name instead of the one currently + * hard-coded in `kcm_ipc_name'. + */ + return kcm_alloc(context, &krb5_akcm_ops, res, sub, id); +} + +/* + * Request: + * + * Response: + * NameZ + */ +static krb5_error_code +kcm_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) +{ + krb5_kcmcache *k; + krb5_error_code ret; + krb5_storage *request, *response; + krb5_data response_data; + + ret = kcm_alloc(context, ops, NULL, NULL, id); + if (ret) + return ret; + + k = KCMCACHE(*id); + + ret = krb5_kcm_storage_request(context, KCM_OP_GEN_NEW, &request); + if (ret) { + kcm_free(context, id); + return ret; + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + kcm_free(context, id); + return ret; + } + + free(k->name); + k->name = NULL; + ret = krb5_ret_stringz(response, &k->name); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + if (ret) + kcm_free(context, id); + + return ret; +} + +static krb5_error_code +kcm_gen_new_kcm(krb5_context context, krb5_ccache *id) +{ + return kcm_gen_new(context, &krb5_kcm_ops, id); +} + +static krb5_error_code +kcm_gen_new_api(krb5_context context, krb5_ccache *id) +{ + return kcm_gen_new(context, &krb5_akcm_ops, id); +} + +/* + * Request: + * NameZ + * Principal + * + * Response: + * + */ +static krb5_error_code +kcm_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_INITIALIZE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_principal(request, primary_principal); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + + if (context->kdc_sec_offset) + kcm_set_kdc_offset(context, id, context->kdc_sec_offset); + + return ret; +} + +static krb5_error_code +kcm_close(krb5_context context, + krb5_ccache id) +{ + kcm_free(context, &id); + return 0; +} + +/* + * Request: + * NameZ + * + * Response: + * + */ +static krb5_error_code +kcm_destroy(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_DESTROY, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +/* + * Request: + * NameZ + * Creds + * + * Response: + * + */ +static krb5_error_code +kcm_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_STORE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds(request, creds); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +#if 0 +/* + * Request: + * NameZ + * WhichFields + * MatchCreds + * + * Response: + * Creds + * + */ +static krb5_error_code +kcm_retrieve(krb5_context context, + krb5_ccache id, + krb5_flags which, + const krb5_creds *mcred, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = krb5_kcm_storage_request(context, KCM_OP_RETRIEVE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, which); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds_tag(request, rk_UNCONST(mcred)); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_creds(response, creds); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} +#endif + +/* + * Request: + * NameZ + * + * Response: + * Principal + */ +static krb5_error_code +kcm_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_principal(response, principal); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} + +/* + * Request: + * NameZ + * + * Response: + * Cursor + * + */ +static krb5_error_code +kcm_get_first (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_error_code ret; + krb5_kcm_cursor c; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_UUID_LIST, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret) + return ret; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = krb5_enomem(context); + return ret; + } + + while (1) { + ssize_t sret; + kcmuuid_t uuid; + void *ptr; + + sret = krb5_storage_read(response, &uuid, sizeof(uuid)); + if (sret == 0) { + ret = 0; + break; + } else if (sret != sizeof(uuid)) { + ret = EINVAL; + break; + } + + ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1)); + if (ptr == NULL) { + free(c->uuids); + free(c); + return krb5_enomem(context); + } + c->uuids = ptr; + + memcpy(&c->uuids[c->length], &uuid, sizeof(uuid)); + c->length += 1; + } + + krb5_storage_free(response); + krb5_data_free(&response_data); + + if (ret) { + free(c->uuids); + free(c); + return ret; + } + + *cursor = c; + + return 0; +} + +/* + * Request: + * NameZ + * Cursor + * + * Response: + * Creds + */ +static krb5_error_code +kcm_get_next (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_kcm_cursor c = KCMCURSOR(*cursor); + krb5_storage *request, *response; + krb5_data response_data; + ssize_t sret; + + again: + + if (c->offset >= c->length) + return KRB5_CC_END; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_CRED_BY_UUID, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + sret = krb5_storage_write(request, + &c->uuids[c->offset], + sizeof(c->uuids[c->offset])); + c->offset++; + if (sret != sizeof(c->uuids[c->offset])) { + krb5_storage_free(request); + return krb5_enomem(context); + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret == KRB5_CC_END) { + goto again; + } else if (ret) + return ret; + + ret = krb5_ret_creds(response, creds); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} + +/* + * Request: + * NameZ + * Cursor + * + * Response: + * + */ +static krb5_error_code +kcm_end_get (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_kcm_cursor c = KCMCURSOR(*cursor); + + free(c->uuids); + free(c); + + *cursor = NULL; + + return 0; +} + +/* + * Request: + * NameZ + * WhichFields + * MatchCreds + * + * Response: + * + */ +static krb5_error_code +kcm_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *cred) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, which); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds_tag(request, cred); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +static krb5_error_code +kcm_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_SET_FLAGS, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, flags); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +static int +kcm_get_version(krb5_context context, + krb5_ccache id) +{ + return 0; +} + +/* + * Send nothing + * get back list of uuids + */ + +static krb5_error_code +kcm_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + krb5_error_code ret; + krb5_kcm_cursor c; + krb5_storage *request, *response; + krb5_data response_data; + + *cursor = NULL; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = krb5_enomem(context); + goto out; + } + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_UUID_LIST, &request); + if (ret) + goto out; + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret) + goto out; + + while (1) { + ssize_t sret; + kcmuuid_t uuid; + void *ptr; + + sret = krb5_storage_read(response, &uuid, sizeof(uuid)); + if (sret == 0) { + ret = 0; + break; + } else if (sret != sizeof(uuid)) { + ret = EINVAL; + goto out; + } + + ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1)); + if (ptr == NULL) { + ret = krb5_enomem(context); + goto out; + } + c->uuids = ptr; + + memcpy(&c->uuids[c->length], &uuid, sizeof(uuid)); + c->length += 1; + } + + krb5_storage_free(response); + krb5_data_free(&response_data); + + out: + if (ret && c) { + free(c->uuids); + free(c); + } else + *cursor = c; + + return ret; +} + +/* + * Send uuid + * Recv cache name + */ + +static krb5_error_code +kcm_get_cache_next(krb5_context context, krb5_cc_cursor cursor, const krb5_cc_ops *ops, krb5_ccache *id) +{ + krb5_error_code ret; + krb5_kcm_cursor c = KCMCURSOR(cursor); + krb5_storage *request, *response; + krb5_data response_data; + ssize_t sret; + char *name; + + *id = NULL; + + again: + + if (c->offset >= c->length) + return KRB5_CC_END; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_CACHE_BY_UUID, &request); + if (ret) + return ret; + + sret = krb5_storage_write(request, + &c->uuids[c->offset], + sizeof(c->uuids[c->offset])); + c->offset++; + if (sret != sizeof(c->uuids[c->offset])) { + krb5_storage_free(request); + return krb5_enomem(context); + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret == KRB5_CC_END) + goto again; + else if (ret) + return ret; + + ret = krb5_ret_stringz(response, &name); + krb5_storage_free(response); + krb5_data_free(&response_data); + + if (ret == 0) { + ret = _krb5_cc_allocate(context, ops, id); + if (ret == 0) + ret = kcm_alloc(context, ops, name, NULL, id); + krb5_xfree(name); + } + + return ret; +} + +static krb5_error_code +kcm_get_cache_next_kcm(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ +#ifndef KCM_IS_API_CACHE + return kcm_get_cache_next(context, cursor, &krb5_kcm_ops, id); +#else + return KRB5_CC_END; +#endif +} + +static krb5_error_code +kcm_get_cache_next_api(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + return kcm_get_cache_next(context, cursor, &krb5_akcm_ops, id); +} + + +static krb5_error_code +kcm_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + krb5_kcm_cursor c = KCMCURSOR(cursor); + + free(c->uuids); + free(c); + return 0; +} + + +static krb5_error_code +kcm_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code ret; + krb5_kcmcache *oldk = KCMCACHE(from); + krb5_kcmcache *newk = KCMCACHE(to); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_MOVE_CACHE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, oldk->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_stringz(request, newk->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + + if (ret == 0) + krb5_cc_destroy(context, from); + return ret; +} + +static krb5_error_code +kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops, + const char *defstr, char **str) +{ + krb5_error_code ret; + krb5_storage *request, *response; + krb5_data response_data; + char *name; + int aret; + + *str = NULL; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_DEFAULT_CACHE, &request); + if (ret) + return ret; + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret) { + if (defstr) + return _krb5_expand_default_cc_name(context, defstr, str); + return ret; + } + + ret = krb5_ret_stringz(response, &name); + krb5_storage_free(response); + krb5_data_free(&response_data); + if (ret) + return ret; + + aret = asprintf(str, "%s:%s", ops->prefix, name); + free(name); + if (aret == -1 || *str == NULL) + return krb5_enomem(context); + + return 0; +} + +static krb5_error_code +kcm_get_default_name_api(krb5_context context, char **str) +{ + return kcm_get_default_name(context, &krb5_akcm_ops, + KRB5_DEFAULT_CCNAME_KCM_API, str); +} + +static krb5_error_code +kcm_get_default_name_kcm(krb5_context context, char **str) +{ + return kcm_get_default_name(context, &krb5_kcm_ops, + KRB5_DEFAULT_CCNAME_KCM_KCM, str); +} + +static krb5_error_code +kcm_set_default(krb5_context context, krb5_ccache id) +{ + krb5_error_code ret; + krb5_storage *request; + krb5_kcmcache *k = KCMCACHE(id); + + ret = krb5_kcm_storage_request(context, KCM_OP_SET_DEFAULT_CACHE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + krb5_storage_free(request); + + return ret; +} + +static krb5_error_code +kcm_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime) +{ + *mtime = time(NULL); + return 0; +} + +static krb5_error_code +kcm_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset) +{ + krb5_kcmcache *k = KCMCACHE(id); + krb5_error_code ret; + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_SET_KDC_OFFSET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + ret = krb5_store_int32(request, kdc_offset); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + krb5_storage_free(request); + + return ret; +} + +static krb5_error_code +kcm_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset) +{ + krb5_kcmcache *k = KCMCACHE(id); + krb5_error_code ret; + krb5_storage *request, *response; + krb5_data response_data; + int32_t offset; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_KDC_OFFSET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, &response, &response_data); + krb5_storage_free(request); + if (ret) + return ret; + + ret = krb5_ret_int32(response, &offset); + krb5_storage_free(response); + krb5_data_free(&response_data); + if (ret) + return ret; + + *kdc_offset = offset; + + return 0; +} + +/** + * Variable containing the KCM based credential cache implemention. + * + * @ingroup krb5_ccache + */ + +KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { + KRB5_CC_OPS_VERSION_5, + "KCM", + NULL, + NULL, + kcm_gen_new_kcm, + kcm_initialize, + kcm_destroy, + kcm_close, + kcm_store_cred, + NULL /* kcm_retrieve */, + kcm_get_principal, + kcm_get_first, + kcm_get_next, + kcm_end_get, + kcm_remove_cred, + kcm_set_flags, + kcm_get_version, + kcm_get_cache_first, + kcm_get_cache_next_kcm, + kcm_end_cache_get, + kcm_move, + kcm_get_default_name_kcm, + kcm_set_default, + kcm_lastchange, + kcm_set_kdc_offset, + kcm_get_kdc_offset, + kcm_get_name_2, + kcm_resolve_2_kcm +}; + +KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { + KRB5_CC_OPS_VERSION_5, + "API", + NULL, + NULL, + kcm_gen_new_api, + kcm_initialize, + kcm_destroy, + kcm_close, + kcm_store_cred, + NULL /* kcm_retrieve */, + kcm_get_principal, + kcm_get_first, + kcm_get_next, + kcm_end_get, + kcm_remove_cred, + kcm_set_flags, + kcm_get_version, + kcm_get_cache_first, + kcm_get_cache_next_api, + kcm_end_cache_get, + kcm_move, + kcm_get_default_name_api, + kcm_set_default, + kcm_lastchange, + NULL, + NULL, + kcm_get_name_2, + kcm_resolve_2_api +}; + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_kcm_is_running(krb5_context context) +{ + krb5_error_code ret; + krb5_ccache_data ccdata; + krb5_ccache id = &ccdata; + krb5_boolean running; + + ret = kcm_alloc(context, &krb5_kcm_ops, NULL, NULL, &id); + if (ret) + return 0; + + running = (_krb5_kcm_noop(context, id) == 0); + + kcm_free(context, &id); + + return running; +} + +/* + * Request: + * + * Response: + * + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kcm_noop(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret; + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_NOOP, &request); + if (ret) + return ret; + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * ServerPrincipalPresent + * ServerPrincipal OPTIONAL + * Key + * + * Repsonse: + * + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kcm_get_initial_ticket(krb5_context context, + krb5_ccache id, + krb5_principal server, + krb5_keyblock *key) +{ + krb5_kcmcache *k = KCMCACHE(id); + krb5_error_code ret; + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int8(request, (server == NULL) ? 0 : 1); + if (ret) { + krb5_storage_free(request); + return ret; + } + + if (server != NULL) { + ret = krb5_store_principal(request, server); + if (ret) { + krb5_storage_free(request); + return ret; + } + } + + ret = krb5_store_keyblock(request, *key); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * KDCFlags + * EncryptionType + * ServerPrincipal + * + * Repsonse: + * + */ +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kcm_get_ticket(krb5_context context, + krb5_ccache id, + krb5_kdc_flags flags, + krb5_enctype enctype, + krb5_principal server) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = krb5_kcm_storage_request(context, KCM_OP_GET_TICKET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, flags.i); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, enctype); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_principal(request, server); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_kcm_call(context, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +#endif /* HAVE_KCM */ diff --git a/third_party/heimdal/lib/krb5/kcm.h b/third_party/heimdal/lib/krb5/kcm.h new file mode 100644 index 0000000..ba484b9 --- /dev/null +++ b/third_party/heimdal/lib/krb5/kcm.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2005, PADL Software Pty Ltd. + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __KCM_H__ +#define __KCM_H__ + +/* + * KCM protocol definitions + */ + +#define KCM_PROTOCOL_VERSION_MAJOR 2 +#define KCM_PROTOCOL_VERSION_MINOR 0 + +typedef unsigned char kcmuuid_t[16]; + +typedef enum kcm_operation { + KCM_OP_NOOP, + KCM_OP_GET_NAME, + KCM_OP_RESOLVE, + KCM_OP_GEN_NEW, + KCM_OP_INITIALIZE, + KCM_OP_DESTROY, + KCM_OP_STORE, + KCM_OP_RETRIEVE, + KCM_OP_GET_PRINCIPAL, + KCM_OP_GET_CRED_UUID_LIST, + KCM_OP_GET_CRED_BY_UUID, + KCM_OP_REMOVE_CRED, + KCM_OP_SET_FLAGS, + KCM_OP_CHOWN, + KCM_OP_CHMOD, + KCM_OP_GET_INITIAL_TICKET, + KCM_OP_GET_TICKET, + KCM_OP_MOVE_CACHE, + KCM_OP_GET_CACHE_UUID_LIST, + KCM_OP_GET_CACHE_BY_UUID, + KCM_OP_GET_DEFAULT_CACHE, + KCM_OP_SET_DEFAULT_CACHE, + KCM_OP_GET_KDC_OFFSET, + KCM_OP_SET_KDC_OFFSET, + /* NTLM operations */ + KCM_OP_ADD_NTLM_CRED, + KCM_OP_HAVE_NTLM_CRED, + KCM_OP_DEL_NTLM_CRED, + KCM_OP_DO_NTLM_AUTH, + KCM_OP_GET_NTLM_USER_LIST, + KCM_OP_MAX +} kcm_operation; + +#define KCM_NTLM_FLAG_SESSIONKEY 1 +#define KCM_NTLM_FLAG_NTLM2_SESSION 2 +#define KCM_NTLM_FLAG_KEYEX 4 +#define KCM_NTLM_FLAG_AV_GUEST 8 + +#endif /* __KCM_H__ */ + diff --git a/third_party/heimdal/lib/krb5/kerberos.8 b/third_party/heimdal/lib/krb5/kerberos.8 new file mode 100644 index 0000000..fdcea04 --- /dev/null +++ b/third_party/heimdal/lib/krb5/kerberos.8 @@ -0,0 +1,115 @@ +.\" Copyright (c) 2000 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd Jun 27, 2013 +.Dt KERBEROS 8 +.Os HEIMDAL +.Sh NAME +.Nm kerberos +.Nd introduction to the Kerberos system +.Sh DESCRIPTION +Kerberos is a network authentication system. Its purpose is to +securely authenticate users and services in an insecure network +environment. +.Pp +This is done with a Kerberos server acting as a trusted third party, +keeping a database with secret keys for all users and services +(collectively called +.Em principals ) . +.Pp +Each principal belongs to exactly one +.Em realm , +which is the administrative domain in Kerberos. A realm usually +corresponds to an organisation, and the realm should normally be +derived from that organisation's domain name. A realm is served by one +or more Kerberos servers. +.Pp +The authentication process involves exchange of +.Sq tickets +and +.Sq authenticators +which together prove the principal's identity. +.Pp +When you login to the Kerberos system, either through the normal +system login or with the +.Xr kinit 1 +program, you acquire a +.Em ticket granting ticket +which allows you to get new tickets for other services, such as +.Ic telnet +or +.Ic ftp , +without giving your password. +.Pp +For more information on how Kerberos works, see the tutorial at +.Lk https://kerberos.org/software/tutorial.html +or the informal +.Dq dialogue +at +.Lk https://web.mit.edu/kerberos/dialogue.html . +.Pp +For setup instructions see the Heimdal Texinfo manual. +.Sh SEE ALSO +.Xr ftp 1 , +.Xr kdestroy 1 , +.Xr kinit 1 , +.Xr klist 1 , +.Xr kpasswd 1 , +.Xr telnet 1 , +.Xr krb5 3 , +.Xr krb5.conf 5 , +.Xr kadmin 1 , +.Xr kdc 8 , +.Xr ktutil 1 +.Sh HISTORY +The Kerberos authentication system was developed in the late 1980's as +part of the Athena Project at the Massachusetts Institute of +Technology. Versions one through three never reached outside MIT, but +version 4 was (and still is) quite popular, especially in the academic +community, but is also used in commercial products like the AFS +filesystem. +.Pp +The problems with version 4 are that it has many limitations, the code +was not too well written (since it had been developed over a long +time), and it has a number of known security problems. To resolve many +of these issues work on version five started, and resulted in IETF RFC +1510 in 1993. IETF RFC 1510 was obsoleted in 2005 with IETF RFC 4120, +also known as Kerberos clarifications. With the arrival of IETF RFC +4120, the work on adding extensibility and internationalization have +started (Kerberos extensions), and a new RFC will hopefully appear +soon. +.Pp +This manual page is part of the +.Nm Heimdal +Kerberos 5 distribution, which has been in development at the Royal +Institute of Technology in Stockholm, Sweden, since about 1997. diff --git a/third_party/heimdal/lib/krb5/keyblock.c b/third_party/heimdal/lib/krb5/keyblock.c new file mode 100644 index 0000000..317bed3 --- /dev/null +++ b/third_party/heimdal/lib/krb5/keyblock.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * Zero out a keyblock + * + * @param keyblock keyblock to zero out + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_keyblock_zero(krb5_keyblock *keyblock) +{ + keyblock->keytype = 0; + krb5_data_zero(&keyblock->keyvalue); +} + +/** + * Free a keyblock's content, also zero out the content of the keyblock. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock content to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_keyblock_contents(krb5_context context, + krb5_keyblock *keyblock) +{ + if(keyblock) { + if (keyblock->keyvalue.data != NULL) + memset_s(keyblock->keyvalue.data, keyblock->keyvalue.length, + 0, keyblock->keyvalue.length); + krb5_data_free (&keyblock->keyvalue); + keyblock->keytype = KRB5_ENCTYPE_NULL; + } +} + +/** + * Free a keyblock, also zero out the content of the keyblock, uses + * krb5_free_keyblock_contents() to free the content. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION void KRB5_LIB_CALL +krb5_free_keyblock(krb5_context context, + krb5_keyblock *keyblock) +{ + if(keyblock){ + krb5_free_keyblock_contents(context, keyblock); + free(keyblock); + } +} + +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock_contents(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @return 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_keyblock_contents (krb5_context context, + const krb5_keyblock *inblock, + krb5_keyblock *to) +{ + return copy_EncryptionKey(inblock, to); +} + +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @return 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_copy_keyblock (krb5_context context, + const krb5_keyblock *inblock, + krb5_keyblock **to) +{ + krb5_error_code ret; + krb5_keyblock *k; + + *to = NULL; + + k = calloc (1, sizeof(*k)); + if (k == NULL) + return krb5_enomem(context); + + ret = krb5_copy_keyblock_contents (context, inblock, k); + if (ret) { + free(k); + return ret; + } + *to = k; + return 0; +} + +/** + * Get encryption type of a keyblock. + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_enctype KRB5_LIB_CALL +krb5_keyblock_get_enctype(const krb5_keyblock *block) +{ + return block->keytype; +} + +/** + * Fill in `key' with key data of type `enctype' from `data' of length + * `size'. Key should be freed using krb5_free_keyblock_contents(). + * + * @return 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_keyblock_init(krb5_context context, + krb5_enctype type, + const void *data, + size_t size, + krb5_keyblock *key) +{ + krb5_error_code ret; + size_t len; + + memset(key, 0, sizeof(*key)); + + ret = krb5_enctype_keysize(context, type, &len); + if (ret) + return ret; + + if (len != size) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "Encryption key %d is %lu bytes " + "long, %lu was passed in", + type, (unsigned long)len, (unsigned long)size); + return KRB5_PROG_ETYPE_NOSUPP; + } + ret = krb5_data_copy(&key->keyvalue, data, len); + if(ret) { + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + return ret; + } + key->keytype = type; + + return 0; +} diff --git a/third_party/heimdal/lib/krb5/keytab.c b/third_party/heimdal/lib/krb5/keytab.c new file mode 100644 index 0000000..bcb3ed8 --- /dev/null +++ b/third_party/heimdal/lib/krb5/keytab.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/** + * @page krb5_keytab_intro The keytab handing functions + * @section section_krb5_keytab Kerberos Keytabs + * + * See the library functions here: @ref krb5_keytab + * + * Keytabs are long term key storage for servers, their equvalment of + * password files. + * + * Normally the only function that useful for server are to specify + * what keytab to use to other core functions like krb5_rd_req() + * krb5_kt_resolve(), and krb5_kt_close(). + * + * @subsection krb5_keytab_names Keytab names + * + * A keytab name is on the form type:residual. The residual part is + * specific to each keytab-type. + * + * When a keytab-name is resolved, the type is matched with an internal + * list of keytab types. If there is no matching keytab type, + * the default keytab is used. The current default type is FILE. + * + * The default value can be changed in the configuration file + * /etc/krb5.conf by setting the variable + * [defaults]default_keytab_name. + * + * The keytab types that are implemented in Heimdal are: + * - file + * store the keytab in a file, the type's name is FILE . The + * residual part is a filename. For compatibility with other + * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE + * has the same format as FILE. JAVA14 have a format that is + * compatible with older versions of MIT kerberos and SUN's Java + * based installation. They store a truncted kvno, so when the knvo + * excess 255, they are truncted in this format. + * + * - keytab + * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ), + * the type's name is AFSKEYFILE. The residual part is a filename. + * + * - memory + * The keytab is stored in a memory segment. This allows sensitive + * and/or temporary data not to be stored on disk. The type's name + * is MEMORY. Each MEMORY keytab is referenced counted by and + * opened by the residual name, so two handles can point to the + * same memory area. When the last user closes using krb5_kt_close() + * the keytab, the keys in they keytab is memset() to zero and freed + * and can no longer be looked up by name. + * + * + * @subsection krb5_keytab_example Keytab example + * + * This is a minimalistic version of ktutil. + * + * @code +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_keytab keytab; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + krb5_error_code ret; + char *principal; + + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_kt_default (context, &keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_default"); + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); + while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ + krb5_unparse_name(context, entry.principal, &principal); + printf("principal: %s\n", principal); + free(principal); + krb5_kt_free_entry(context, &entry); + } + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_end_seq_get"); + ret = krb5_kt_close(context, keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_close"); + krb5_free_context(context); + return 0; +} + * @endcode + * + */ + + +/** + * Register a new keytab backend. + * + * @param context a Keberos context. + * @param ops a backend to register. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_register(krb5_context context, + const krb5_kt_ops *ops) +{ + struct krb5_keytab_data *tmp; + + if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) { + krb5_set_error_message(context, KRB5_KT_BADNAME, + N_("can't register cache type, prefix too long", "")); + return KRB5_KT_BADNAME; + } + + tmp = realloc(context->kt_types, + (context->num_kt_types + 1) * sizeof(*context->kt_types)); + if(tmp == NULL) + return krb5_enomem(context); + memcpy(&tmp[context->num_kt_types], ops, + sizeof(tmp[context->num_kt_types])); + context->kt_types = tmp; + context->num_kt_types++; + return 0; +} + +static const char * +keytab_name(const char *name, const char **type, size_t *type_len) +{ + const char *residual; + + residual = strchr(name, ':'); + + if (residual == NULL || + ISPATHSEP(name[0]) +#ifdef _WIN32 + /* Avoid treating : as a keytab type + * specification */ + || name + 1 == residual +#endif + ) { + + *type = "FILE"; + *type_len = strlen(*type); + residual = name; + } else { + *type = name; + *type_len = residual - name; + residual++; + } + + return residual; +} + +/** + * Resolve the keytab name (of the form `type:residual') in `name' + * into a keytab in `id'. + * + * @param context a Keberos context. + * @param name name to resolve + * @param id resulting keytab, free with krb5_kt_close(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_resolve(krb5_context context, + const char *name, + krb5_keytab *id) +{ + krb5_keytab k; + int i; + const char *type, *residual; + size_t type_len; + krb5_error_code ret; + + residual = keytab_name(name, &type, &type_len); + + for(i = 0; i < context->num_kt_types; i++) { + if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0) + break; + } + if(i == context->num_kt_types) { + krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE, + N_("unknown keytab type %.*s", "type"), + (int)type_len, type); + return KRB5_KT_UNKNOWN_TYPE; + } + + k = malloc (sizeof(*k)); + if (k == NULL) + return krb5_enomem(context); + memcpy(k, &context->kt_types[i], sizeof(*k)); + k->data = NULL; + ret = (*k->resolve)(context, residual, k); + if(ret) { + free(k); + k = NULL; + } + *id = k; + return ret; +} + +/* + * Default ktname from context with possible environment + * override + */ +static const char *default_ktname(krb5_context context) +{ + const char *tmp = NULL; + + tmp = secure_getenv("KRB5_KTNAME"); + if(tmp != NULL) + return tmp; + return context->default_keytab; +} + +/** + * copy the name of the default keytab into `name'. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_default_name(krb5_context context, char *name, size_t namesize) +{ + if (strlcpy (name, default_ktname(context), namesize) >= namesize) { + krb5_clear_error_message (context); + return KRB5_CONFIG_NOTENUFSPACE; + } + return 0; +} + +/** + * Copy the name of the default modify keytab into `name'. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize) +{ + const char *kt; + + if(context->default_keytab_modify == NULL) { + kt = default_ktname(context); + + if (strncasecmp(kt, "ANY:", 4) == 0) { + size_t len = strcspn(kt + 4, ","); + if (len >= namesize) { + krb5_clear_error_message(context); + return KRB5_CONFIG_NOTENUFSPACE; + } + strlcpy(name, kt + 4, namesize); + name[len] = '\0'; + return 0; + } + } else + kt = context->default_keytab_modify; + if (strlcpy (name, kt, namesize) >= namesize) { + krb5_clear_error_message (context); + return KRB5_CONFIG_NOTENUFSPACE; + } + return 0; +} + +/** + * Set `id' to the default keytab. + * + * @param context a Keberos context. + * @param id the new default keytab. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_default(krb5_context context, krb5_keytab *id) +{ + return krb5_kt_resolve (context, default_ktname(context), id); +} + +/** + * Read the key identified by `(principal, vno, enctype)' from the + * keytab in `keyprocarg' (the default if == NULL) into `*key'. + * + * @param context a Keberos context. + * @param keyprocarg + * @param principal + * @param vno + * @param enctype + * @param key + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_read_service_key(krb5_context context, + krb5_pointer keyprocarg, + krb5_principal principal, + krb5_kvno vno, + krb5_enctype enctype, + krb5_keyblock **key) +{ + krb5_keytab keytab = NULL; /* Quiet lint */ + krb5_keytab_entry entry; + krb5_error_code ret; + + memset(&entry, 0, sizeof(entry)); + if (keyprocarg) + ret = krb5_kt_resolve (context, keyprocarg, &keytab); + else + ret = krb5_kt_default (context, &keytab); + + if (ret) + return ret; + + ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); + if (ret == 0) { + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + } + krb5_kt_close (context, keytab); + return ret; +} + +/** + * Return the type of the `keytab' in the string `prefix of length + * `prefixsize'. + * + * @param context a Keberos context. + * @param keytab the keytab to get the prefix for + * @param prefix prefix buffer + * @param prefixsize length of prefix buffer + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_get_type(krb5_context context, + krb5_keytab keytab, + char *prefix, + size_t prefixsize) +{ + strlcpy(prefix, keytab->prefix, prefixsize); + return 0; +} + +/** + * Retrieve the name of the keytab `keytab' into `name', `namesize' + * + * @param context a Keberos context. + * @param keytab the keytab to get the name for. + * @param name name buffer. + * @param namesize size of name buffer. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_get_name(krb5_context context, + krb5_keytab keytab, + char *name, + size_t namesize) +{ + return (*keytab->get_name)(context, keytab, name, namesize); +} + +/** + * Retrieve the full name of the keytab `keytab' and store the name in + * `str'. + * + * @param context a Keberos context. + * @param keytab keytab to get name for. + * @param str the name of the keytab name, usee krb5_xfree() to free + * the string. On error, *str is set to NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_get_full_name(krb5_context context, + krb5_keytab keytab, + char **str) +{ + char type[KRB5_KT_PREFIX_MAX_LEN]; + char name[MAXPATHLEN]; + krb5_error_code ret; + + *str = NULL; + + ret = krb5_kt_get_type(context, keytab, type, sizeof(type)); + if (ret) + return ret; + + ret = krb5_kt_get_name(context, keytab, name, sizeof(name)); + if (ret) + return ret; + + if (asprintf(str, "%s:%s", type, name) == -1) { + *str = NULL; + return krb5_enomem(context); + } + + return 0; +} + +/** + * Finish using the keytab in `id'. All resources will be released, + * even on errors. + * + * @param context a Keberos context. + * @param id keytab to close. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_close(krb5_context context, + krb5_keytab id) +{ + krb5_error_code ret = 0; + + if (id) { + ret = (id->close)(context, id); + memset(id, 0, sizeof(*id)); + free(id); + } + return ret; +} + +/** + * Destroy (remove) the keytab in `id'. All resources will be released, + * even on errors, does the equvalment of krb5_kt_close() on the resources. + * + * @param context a Keberos context. + * @param id keytab to destroy. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_destroy(krb5_context context, + krb5_keytab id) +{ + krb5_error_code ret; + + ret = (*id->destroy)(context, id); + krb5_kt_close(context, id); + return ret; +} + +/* + * Match any aliases in keytab `entry' with `principal'. + */ + +static krb5_boolean +compare_aliases(krb5_context context, + krb5_keytab_entry *entry, + krb5_const_principal principal) +{ + unsigned int i; + if (entry->aliases == NULL) + return FALSE; + for (i = 0; i < entry->aliases->len; i++) + if (krb5_principal_compare(context, &entry->aliases->val[i], principal)) + return TRUE; + return FALSE; +} + +/** + * Compare `entry' against `principal, vno, enctype'. + * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. + * Return TRUE if they compare the same, FALSE otherwise. + * + * @param context a Keberos context. + * @param entry an entry to match with. + * @param principal principal to match, NULL matches all principals. + * @param vno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * + * @return Return TRUE or match, FALSE if not matched. + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +krb5_kt_compare(krb5_context context, + krb5_keytab_entry *entry, + krb5_const_principal principal, + krb5_kvno vno, + krb5_enctype enctype) +{ + /* krb5_principal_compare() does not special-case the referral realm */ + if (principal != NULL && strcmp(principal->realm, "") == 0 && + !(krb5_principal_compare_any_realm(context, entry->principal, principal) || + compare_aliases(context, entry, principal))) { + return FALSE; + } else if (principal != NULL && strcmp(principal->realm, "") != 0 && + !(krb5_principal_compare(context, entry->principal, principal) || + compare_aliases(context, entry, principal))) { + return FALSE; + } + if (vno && vno != entry->vno) + return FALSE; + if (enctype && enctype != entry->keyblock.keytype) + return FALSE; + return TRUE; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kt_principal_not_found(krb5_context context, + krb5_error_code ret, + krb5_keytab id, + krb5_const_principal principal, + krb5_enctype enctype, + int kvno) +{ + char kvno_str[25]; + char *enctype_str = NULL; + char *kt_name = NULL; + char *princ = NULL; + + (void) krb5_unparse_name(context, principal, &princ); + (void) krb5_kt_get_full_name(context, id, &kt_name); + if (enctype) + (void) krb5_enctype_to_string(context, enctype, &enctype_str); + + if (kvno) + snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); + else + kvno_str[0] = '\0'; + + krb5_set_error_message(context, ret, + N_("Failed to find %s%s in keytab %s (%s)", + "principal, kvno, keytab file, enctype"), + princ ? princ : "", + kvno_str, + kt_name ? kt_name : "unknown keytab", + enctype_str ? enctype_str : "unknown enctype"); + free(princ); + free(kt_name); + free(enctype_str); + return ret; +} + +static krb5_error_code +krb5_kt_get_entry_wrapped(krb5_context context, + krb5_keytab id, + krb5_const_principal principal, + krb5_kvno kvno, + krb5_enctype enctype, + krb5_keytab_entry *entry) +{ + krb5_keytab_entry tmp; + krb5_error_code ret; + krb5_kt_cursor cursor; + + if(id->get) + return (*id->get)(context, id, principal, kvno, enctype, entry); + + memset(&tmp, 0, sizeof(tmp)); + ret = krb5_kt_start_seq_get (context, id, &cursor); + if (ret) { + /* This is needed for krb5_verify_init_creds, but keep error + * string from previous error for the human. */ + context->error_code = KRB5_KT_NOTFOUND; + return KRB5_KT_NOTFOUND; + } + + entry->vno = 0; + while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { + if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { + /* the file keytab might only store the lower 8 bits of + the kvno, so only compare those bits */ + if (kvno == tmp.vno + || (tmp.vno < 256 && kvno % 256 == tmp.vno)) { + krb5_kt_copy_entry_contents (context, &tmp, entry); + krb5_kt_free_entry (context, &tmp); + krb5_kt_end_seq_get(context, id, &cursor); + return 0; + } else if (kvno == 0 && tmp.vno > entry->vno) { + if (entry->vno) + krb5_kt_free_entry (context, entry); + krb5_kt_copy_entry_contents (context, &tmp, entry); + } + } + krb5_kt_free_entry(context, &tmp); + } + krb5_kt_end_seq_get (context, id, &cursor); + if (entry->vno == 0) + return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND, + id, principal, enctype, kvno); + return 0; +} + +/** + * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' + * from the keytab `id'. Matching is done like krb5_kt_compare(). + * + * @param context a Keberos context. + * @param id a keytab. + * @param principal principal to match, NULL matches all principals. + * @param kvno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_get_entry(krb5_context context, + krb5_keytab id, + krb5_const_principal principal, + krb5_kvno kvno, + krb5_enctype enctype, + krb5_keytab_entry *entry) +{ + krb5_error_code ret; + krb5_const_principal try_princ; + krb5_name_canon_iterator name_canon_iter; + + if (!principal) + /* Use `NULL' instead of `principal' to quiet static analizers */ + return krb5_kt_get_entry_wrapped(context, id, NULL, kvno, enctype, + entry); + + ret = krb5_name_canon_iterator_start(context, principal, &name_canon_iter); + if (ret) + return ret; + + do { + ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, + NULL); + if (ret) + break; + if (try_princ == NULL) { + ret = KRB5_KT_NOTFOUND; + continue; + } + ret = krb5_kt_get_entry_wrapped(context, id, try_princ, kvno, + enctype, entry); + } while (ret == KRB5_KT_NOTFOUND && name_canon_iter); + + if (ret && ret != KRB5_KT_NOTFOUND) + krb5_set_error_message(context, ret, + N_("Name canon failed while searching keytab", + "")); + krb5_free_name_canon_iterator(context, name_canon_iter); + return ret; +} + +/** + * Copy the contents of `in' into `out'. + * + * @param context a Keberos context. + * @param in the keytab entry to copy. + * @param out the copy of the keytab entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_copy_entry_contents(krb5_context context, + const krb5_keytab_entry *in, + krb5_keytab_entry *out) +{ + krb5_error_code ret; + + memset(out, 0, sizeof(*out)); + + ret = krb5_copy_principal (context, in->principal, &out->principal); + if (ret) + return ret; + ret = krb5_copy_keyblock_contents (context, + &in->keyblock, + &out->keyblock); + if (ret) { + krb5_free_principal(context, out->principal); + memset(out, 0, sizeof(*out)); + return ret; + } + out->vno = in->vno; + out->timestamp = in->timestamp; + return 0; +} + +/** + * Free the contents of `entry'. + * + * @param context a Keberos context. + * @param entry the entry to free + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_free_entry(krb5_context context, + krb5_keytab_entry *entry) +{ + krb5_free_principal (context, entry->principal); + krb5_free_keyblock_contents (context, &entry->keyblock); + memset(entry, 0, sizeof(*entry)); + return 0; +} + +/** + * Set `cursor' to point at the beginning of `id'. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + if(id->start_seq_get == NULL) { + krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, + N_("start_seq_get is not supported " + "in the %s keytab type", ""), + id->prefix); + return HEIM_ERR_OPNOTSUPP; + } + return (*id->start_seq_get)(context, id, cursor); +} + +/** + * Get the next entry from keytab, advance the cursor. On last entry + * the function will return KRB5_KT_END. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * @param cursor the cursor of the iteration. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_next_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor) +{ + if(id->next_entry == NULL) { + krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, + N_("next_entry is not supported in the %s " + " keytab", ""), + id->prefix); + return HEIM_ERR_OPNOTSUPP; + } + memset(entry, 0x0, sizeof(*entry)); + return (*id->next_entry)(context, id, entry, cursor); +} + +/** + * Release all resources associated with `cursor'. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor the cursor to free. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + if(id->end_seq_get == NULL) { + krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, + "end_seq_get is not supported in the %s " + " keytab", id->prefix); + return HEIM_ERR_OPNOTSUPP; + } + return (*id->end_seq_get)(context, id, cursor); +} + +/** + * Add the entry in `entry' to the keytab `id'. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to add + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_add_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + if(id->add == NULL) { + krb5_set_error_message(context, KRB5_KT_NOWRITE, + N_("Add is not supported in the %s keytab", ""), + id->prefix); + return KRB5_KT_NOWRITE; + } + if (entry->timestamp == 0) + entry->timestamp = time(NULL); + return (*id->add)(context, id,entry); +} + +/** + * Remove an entry from the keytab, matching is done using + * krb5_kt_compare(). + + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to remove + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_remove_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + if(id->remove == NULL) { + krb5_set_error_message(context, KRB5_KT_NOWRITE, + N_("Remove is not supported in the %s keytab", ""), + id->prefix); + return KRB5_KT_NOWRITE; + } + return (*id->remove)(context, id, entry); +} + +/** + * Return true if the keytab exists and have entries + * + * @param context a Keberos context. + * @param id a keytab. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_kt_have_content(krb5_context context, + krb5_keytab id) +{ + krb5_keytab_entry entry; + krb5_kt_cursor cursor; + krb5_error_code ret; + char *name; + + memset(&entry, 0, sizeof(entry)); + ret = krb5_kt_start_seq_get(context, id, &cursor); + if (ret) + goto notfound; + + ret = krb5_kt_next_entry(context, id, &entry, &cursor); + krb5_kt_end_seq_get(context, id, &cursor); + if (ret) + goto notfound; + + krb5_kt_free_entry(context, &entry); + + return 0; + + notfound: + ret = krb5_kt_get_full_name(context, id, &name); + if (ret == 0) { + krb5_set_error_message(context, KRB5_KT_NOTFOUND, + N_("No entry in keytab: %s", ""), name); + free(name); + } + return KRB5_KT_NOTFOUND; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_kt_client_default_name(krb5_context context, char **name) +{ + const char *tmp; + + tmp = secure_getenv("KRB5_CLIENT_KTNAME"); + if (tmp == NULL) + tmp = krb5_config_get_string(context, NULL, + "libdefaults", + "default_client_keytab_name", NULL); + if (tmp == NULL) + tmp = CLIENT_KEYTAB_DEFAULT; + + return _krb5_expand_path_tokens(context, tmp, 1, name); +} diff --git a/third_party/heimdal/lib/krb5/keytab_any.c b/third_party/heimdal/lib/krb5/keytab_any.c new file mode 100644 index 0000000..6663d17 --- /dev/null +++ b/third_party/heimdal/lib/krb5/keytab_any.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2001-2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +struct any_data { + krb5_keytab kt; + char *name; + struct any_data *next; +}; + +static void +free_list (krb5_context context, struct any_data *a) +{ + struct any_data *next; + + for (; a != NULL; a = next) { + next = a->next; + free (a->name); + if(a->kt) + krb5_kt_close(context, a->kt); + free (a); + } +} + +static krb5_error_code KRB5_CALLCONV +any_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct any_data *a, *a0 = NULL, *prev = NULL; + krb5_error_code ret; + char buf[256]; + + while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) { + a = calloc(1, sizeof(*a)); + if (a == NULL) { + ret = krb5_enomem(context); + goto fail; + } + if (a0 == NULL) { + a0 = a; + a->name = strdup(buf); + if (a->name == NULL) { + ret = krb5_enomem(context); + goto fail; + } + } else + a->name = NULL; + if (prev != NULL) + prev->next = a; + a->next = NULL; + ret = krb5_kt_resolve (context, buf, &a->kt); + if (ret) + goto fail; + prev = a; + } + if (a0 == NULL) { + krb5_set_error_message(context, ENOENT, N_("empty ANY: keytab", "")); + return ENOENT; + } + id->data = a0; + return 0; + fail: + free_list (context, a0); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +any_get_name (krb5_context context, + krb5_keytab id, + char *name, + size_t namesize) +{ + struct any_data *a = id->data; + strlcpy(name, a->name, namesize); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +any_close (krb5_context context, + krb5_keytab id) +{ + struct any_data *a = id->data; + + free_list (context, a); + return 0; +} + +struct any_cursor_extra_data { + struct any_data *a; + krb5_kt_cursor cursor; +}; + +static krb5_error_code KRB5_CALLCONV +any_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *c) +{ + struct any_data *a = id->data; + struct any_cursor_extra_data *ed; + krb5_error_code ret; + + c->data = malloc (sizeof(struct any_cursor_extra_data)); + if(c->data == NULL) + return krb5_enomem(context); + ed = (struct any_cursor_extra_data *)c->data; + for (ed->a = a; ed->a != NULL; ed->a = ed->a->next) { + ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); + if (ret == 0) + break; + } + if (ed->a == NULL) { + free (c->data); + c->data = NULL; + krb5_clear_error_message (context); + return KRB5_KT_END; + } + return 0; +} + +static krb5_error_code KRB5_CALLCONV +any_next_entry (krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor) +{ + krb5_error_code ret, ret2; + struct any_cursor_extra_data *ed; + + ed = (struct any_cursor_extra_data *)cursor->data; + do { + ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor); + if (ret == 0) + return 0; + else if (ret != KRB5_KT_END) + return ret; + + ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); + if (ret2) + return ret2; + while ((ed->a = ed->a->next) != NULL) { + ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); + if (ret2 == 0) + break; + } + if (ed->a == NULL) { + krb5_clear_error_message (context); + return KRB5_KT_END; + } + } while (1); +} + +static krb5_error_code KRB5_CALLCONV +any_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + krb5_error_code ret = 0; + struct any_cursor_extra_data *ed; + + ed = (struct any_cursor_extra_data *)cursor->data; + if (ed->a != NULL) + ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); + free (ed); + cursor->data = NULL; + return ret; +} + +static krb5_error_code KRB5_CALLCONV +any_add_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct any_data *a = id->data; + krb5_error_code ret; + while(a != NULL) { + ret = krb5_kt_add_entry(context, a->kt, entry); + if(ret != 0 && ret != KRB5_KT_NOWRITE) { + krb5_set_error_message(context, ret, + N_("failed to add entry to %s", ""), + a->name); + return ret; + } + a = a->next; + } + return 0; +} + +static krb5_error_code KRB5_CALLCONV +any_remove_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct any_data *a = id->data; + krb5_error_code ret; + krb5_boolean found = FALSE; + while(a != NULL) { + ret = krb5_kt_remove_entry(context, a->kt, entry); + if(ret == 0) + found = TRUE; + else { + if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { + krb5_set_error_message(context, ret, + N_("Failed to remove keytab " + "entry from %s", "keytab name"), + a->name); + return ret; + } + } + a = a->next; + } + if(!found) + return KRB5_KT_NOTFOUND; + return 0; +} + +const krb5_kt_ops krb5_any_ops = { + "ANY", + any_resolve, + any_get_name, + any_close, + NULL, /* destroy */ + NULL, /* get */ + any_start_seq_get, + any_next_entry, + any_end_seq_get, + any_add_entry, + any_remove_entry, + NULL, + 0 +}; diff --git a/third_party/heimdal/lib/krb5/keytab_file.c b/third_party/heimdal/lib/krb5/keytab_file.c new file mode 100644 index 0000000..61b5d6d --- /dev/null +++ b/third_party/heimdal/lib/krb5/keytab_file.c @@ -0,0 +1,856 @@ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#define KRB5_KT_VNO_1 1 +#define KRB5_KT_VNO_2 2 +#define KRB5_KT_VNO KRB5_KT_VNO_2 + +#define KRB5_KT_FL_JAVA 1 + + +/* file operations -------------------------------------------- */ + +struct fkt_data { + char *filename; + int flags; +}; + +static krb5_error_code +krb5_kt_ret_data(krb5_context context, + krb5_storage *sp, + krb5_data *data) +{ + krb5_error_code ret; + krb5_ssize_t bytes; + int16_t size; + + ret = krb5_ret_int16(sp, &size); + if(ret) + return ret; + data->length = size; + data->data = malloc(size); + if (data->data == NULL) + return krb5_enomem(context); + bytes = krb5_storage_read(sp, data->data, size); + if (bytes != size) + return (bytes == -1) ? errno : KRB5_KT_END; + return 0; +} + +static krb5_error_code +krb5_kt_ret_string(krb5_context context, + krb5_storage *sp, + heim_general_string *data) +{ + krb5_error_code ret; + krb5_ssize_t bytes; + int16_t size; + + ret = krb5_ret_int16(sp, &size); + if(ret) + return ret; + *data = malloc(size + 1); + if (*data == NULL) + return krb5_enomem(context); + bytes = krb5_storage_read(sp, *data, size); + (*data)[size] = '\0'; + if (bytes != size) + return (bytes == -1) ? errno : KRB5_KT_END; + return 0; +} + +static krb5_error_code +krb5_kt_store_data(krb5_context context, + krb5_storage *sp, + krb5_data data) +{ + krb5_error_code ret; + krb5_ssize_t bytes; + + ret = krb5_store_int16(sp, data.length); + if (ret != 0) + return ret; + bytes = krb5_storage_write(sp, data.data, data.length); + if (bytes != (int)data.length) + return bytes == -1 ? errno : KRB5_KT_END; + return 0; +} + +static krb5_error_code +krb5_kt_store_string(krb5_storage *sp, + heim_general_string data) +{ + krb5_error_code ret; + krb5_ssize_t bytes; + size_t len = strlen(data); + + ret = krb5_store_int16(sp, len); + if (ret != 0) + return ret; + bytes = krb5_storage_write(sp, data, len); + if (bytes != (int)len) + return bytes == -1 ? errno : KRB5_KT_END; + return 0; +} + +static krb5_error_code +krb5_kt_ret_keyblock(krb5_context context, + struct fkt_data *fkt, + krb5_storage *sp, + krb5_keyblock *p) +{ + int ret; + int16_t tmp; + + ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */ + if(ret) { + krb5_set_error_message(context, ret, + N_("Cant read keyblock from file %s", ""), + fkt->filename); + return ret; + } + p->keytype = tmp; + ret = krb5_kt_ret_data(context, sp, &p->keyvalue); + if (ret) + krb5_set_error_message(context, ret, + N_("Cant read keyblock from file %s", ""), + fkt->filename); + return ret; +} + +static krb5_error_code +krb5_kt_store_keyblock(krb5_context context, + struct fkt_data *fkt, + krb5_storage *sp, + krb5_keyblock *p) +{ + int ret; + + ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */ + if(ret) { + krb5_set_error_message(context, ret, + N_("Cant store keyblock to file %s", ""), + fkt->filename); + return ret; + } + ret = krb5_kt_store_data(context, sp, p->keyvalue); + if (ret) + krb5_set_error_message(context, ret, + N_("Cant store keyblock to file %s", ""), + fkt->filename); + return ret; +} + + +static krb5_error_code +krb5_kt_ret_principal(krb5_context context, + struct fkt_data *fkt, + krb5_storage *sp, + krb5_principal *princ) +{ + size_t i; + int ret; + krb5_principal p; + int16_t len; + + ALLOC(p, 1); + if(p == NULL) + return krb5_enomem(context); + + ret = krb5_ret_int16(sp, &len); + if(ret) { + krb5_set_error_message(context, ret, + N_("Failed decoding length of " + "keytab principal in keytab file %s", ""), + fkt->filename); + goto out; + } + if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) + len--; + if (len < 0) { + ret = KRB5_KT_END; + krb5_set_error_message(context, ret, + N_("Keytab principal contains " + "invalid length in keytab %s", ""), + fkt->filename); + goto out; + } + ret = krb5_kt_ret_string(context, sp, &p->realm); + if(ret) { + krb5_set_error_message(context, ret, + N_("Can't read realm from keytab: %s", ""), + fkt->filename); + goto out; + } + p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val)); + if(p->name.name_string.val == NULL) { + ret = krb5_enomem(context); + goto out; + } + p->name.name_string.len = len; + for(i = 0; i < p->name.name_string.len; i++){ + ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i); + if(ret) { + krb5_set_error_message(context, ret, + N_("Can't read principal from " + "keytab: %s", ""), + fkt->filename); + goto out; + } + } + if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) + p->name.name_type = KRB5_NT_UNKNOWN; + else { + int32_t tmp32; + ret = krb5_ret_int32(sp, &tmp32); + p->name.name_type = tmp32; + if (ret) { + krb5_set_error_message(context, ret, + N_("Can't read name-type from " + "keytab: %s", ""), + fkt->filename); + goto out; + } + } + *princ = p; + return 0; +out: + krb5_free_principal(context, p); + return ret; +} + +static krb5_error_code +krb5_kt_store_principal(krb5_context context, + krb5_storage *sp, + krb5_principal p) +{ + size_t i; + int ret; + + if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS)) + ret = krb5_store_int16(sp, p->name.name_string.len + 1); + else + ret = krb5_store_int16(sp, p->name.name_string.len); + if(ret) return ret; + ret = krb5_kt_store_string(sp, p->realm); + if(ret) return ret; + for(i = 0; i < p->name.name_string.len; i++){ + ret = krb5_kt_store_string(sp, p->name.name_string.val[i]); + if(ret) + return ret; + } + if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) { + ret = krb5_store_int32(sp, p->name.name_type); + if(ret) + return ret; + } + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct fkt_data *d; + + d = malloc(sizeof(*d)); + if(d == NULL) + return krb5_enomem(context); + d->filename = strdup(name); + if(d->filename == NULL) { + free(d); + return krb5_enomem(context); + } + d->flags = 0; + id->data = d; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id) +{ + krb5_error_code ret; + + ret = fkt_resolve(context, name, id); + if (ret == 0) { + struct fkt_data *d = id->data; + d->flags |= KRB5_KT_FL_JAVA; + } + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fkt_close(krb5_context context, krb5_keytab id) +{ + struct fkt_data *d = id->data; + free(d->filename); + free(d); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_destroy(krb5_context context, krb5_keytab id) +{ + struct fkt_data *d = id->data; + _krb5_erase_file(context, d->filename); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_get_name(krb5_context context, + krb5_keytab id, + char *name, + size_t namesize) +{ + /* This function is XXX */ + struct fkt_data *d = id->data; + strlcpy(name, d->filename, namesize); + return 0; +} + +static void +storage_set_flags(krb5_context context, krb5_storage *sp, int vno) +{ + int flags = 0; + switch(vno) { + case KRB5_KT_VNO_1: + flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS; + flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE; + flags |= KRB5_STORAGE_HOST_BYTEORDER; + break; + case KRB5_KT_VNO_2: + break; + default: + krb5_warnx(context, + "storage_set_flags called with bad vno (%d)", vno); + } + krb5_storage_set_flags(sp, flags); +} + +static krb5_error_code +fkt_start_seq_get_int(krb5_context context, + krb5_keytab id, + int flags, + int exclusive, + krb5_kt_cursor *c) +{ + int8_t pvno, tag; + krb5_error_code ret; + struct fkt_data *d = id->data; + const char *stdio_mode = "rb"; + + memset(c, 0, sizeof(*c)); + c->fd = open (d->filename, flags); + if (c->fd < 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("keytab %s open failed: %s", ""), + d->filename, strerror(ret)); + return ret; + } + rk_cloexec(c->fd); + ret = _krb5_xlock(context, c->fd, exclusive, d->filename); + if (ret) { + close(c->fd); + return ret; + } + if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND)) + stdio_mode = "ab+"; + else if ((flags & O_ACCMODE) == O_RDWR) + stdio_mode = "rb+"; + else if ((flags & O_ACCMODE) == O_WRONLY) + stdio_mode = "wb"; + c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode); + if (c->sp == NULL) { + close(c->fd); + return krb5_enomem(context); + } + krb5_storage_set_eof_code(c->sp, KRB5_KT_END); + ret = krb5_ret_int8(c->sp, &pvno); + if(ret) { + krb5_storage_free(c->sp); + close(c->fd); + krb5_clear_error_message(context); + return ret; + } + if(pvno != 5) { + krb5_storage_free(c->sp); + close(c->fd); + krb5_clear_error_message (context); + return KRB5_KEYTAB_BADVNO; + } + ret = krb5_ret_int8(c->sp, &tag); + if (ret) { + krb5_storage_free(c->sp); + close(c->fd); + krb5_clear_error_message(context); + return ret; + } + id->version = tag; + storage_set_flags(context, c->sp, id->version); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *c) +{ + return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c); +} + +static krb5_error_code +fkt_next_entry_int(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor, + off_t *start, + off_t *end) +{ + struct fkt_data *d = id->data; + int32_t len; + int ret; + int8_t tmp8; + int32_t tmp32; + uint32_t utmp32; + off_t pos, curpos; + + pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); +loop: + ret = krb5_ret_int32(cursor->sp, &len); + if (ret) + return ret; + if(len < 0) { + pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR); + goto loop; + } + ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); + if (ret) + goto out; + ret = krb5_ret_uint32(cursor->sp, &utmp32); + entry->timestamp = utmp32; + if (ret) + goto out; + ret = krb5_ret_int8(cursor->sp, &tmp8); + if (ret) + goto out; + entry->vno = tmp8; + ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock); + if (ret) + goto out; + /* there might be a 32 bit kvno here + * if it's zero, assume that the 8bit one was right, + * otherwise trust the new value */ + curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); + if(len + 4 + pos - curpos >= 4) { + ret = krb5_ret_int32(cursor->sp, &tmp32); + if (ret == 0 && tmp32 != 0) + entry->vno = tmp32; + } + /* there might be a flags field here */ + if(len + 4 + pos - curpos >= 8) { + ret = krb5_ret_uint32(cursor->sp, &utmp32); + if (ret == 0) + entry->flags = utmp32; + } else + entry->flags = 0; + + entry->aliases = NULL; + + if(start) *start = pos; + if(end) *end = pos + 4 + len; + out: + if (ret) + krb5_kt_free_entry(context, entry); + krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fkt_next_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor) +{ + return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL); +} + +static krb5_error_code KRB5_CALLCONV +fkt_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + krb5_storage_free(cursor->sp); + close(cursor->fd); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +fkt_setup_keytab(krb5_context context, + krb5_keytab id, + krb5_storage *sp) +{ + krb5_error_code ret; + ret = krb5_store_int8(sp, 5); + if(ret) + return ret; + if(id->version == 0) + id->version = KRB5_KT_VNO; + return krb5_store_int8 (sp, id->version); +} + +static krb5_error_code KRB5_CALLCONV +fkt_add_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + int ret; + int fd; + krb5_storage *sp; + krb5_ssize_t bytes; + struct fkt_data *d = id->data; + krb5_data keytab; + int32_t len; + + fd = open(d->filename, O_RDWR | O_BINARY | O_CLOEXEC); + if (fd < 0) { + fd = open(d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600); + if (fd < 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("open(%s): %s", ""), d->filename, + strerror(ret)); + return ret; + } + rk_cloexec(fd); + + ret = _krb5_xlock(context, fd, 1, d->filename); + if (ret) { + close(fd); + return ret; + } + sp = krb5_storage_stdio_from_fd(fd, "wb+"); + if (sp == NULL) { + close(fd); + return krb5_enomem(context); + } + krb5_storage_set_eof_code(sp, KRB5_KT_END); + ret = fkt_setup_keytab(context, id, sp); + if (ret) { + goto out; + } + storage_set_flags(context, sp, id->version); + } else { + int8_t pvno, tag; + + rk_cloexec(fd); + + ret = _krb5_xlock(context, fd, 1, d->filename); + if (ret) { + close(fd); + return ret; + } + sp = krb5_storage_stdio_from_fd(fd, "wb+"); + if (sp == NULL) { + (void) close(fd); + return ret; + } + krb5_storage_set_eof_code(sp, KRB5_KT_END); + ret = krb5_ret_int8(sp, &pvno); + if(ret) { + /* we probably have a zero byte file, so try to set it up + properly */ + ret = fkt_setup_keytab(context, id, sp); + if(ret) { + krb5_set_error_message(context, ret, + N_("%s: keytab is corrupted: %s", ""), + d->filename, strerror(ret)); + goto out; + } + storage_set_flags(context, sp, id->version); + } else { + if(pvno != 5) { + ret = KRB5_KEYTAB_BADVNO; + krb5_set_error_message(context, ret, + N_("Bad version in keytab %s", ""), + d->filename); + goto out; + } + ret = krb5_ret_int8 (sp, &tag); + if (ret) { + krb5_set_error_message(context, ret, + N_("failed reading tag from " + "keytab %s", ""), + d->filename); + goto out; + } + id->version = tag; + storage_set_flags(context, sp, id->version); + } + } + + { + krb5_storage *emem; + emem = krb5_storage_emem(); + if(emem == NULL) { + ret = krb5_enomem(context); + goto out; + } + ret = krb5_kt_store_principal(context, emem, entry->principal); + if(ret) { + krb5_set_error_message(context, ret, + N_("Failed storing principal " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } + ret = krb5_store_int32 (emem, entry->timestamp); + if(ret) { + krb5_set_error_message(context, ret, + N_("Failed storing timpstamp " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } + ret = krb5_store_int8 (emem, entry->vno % 256); + if(ret) { + krb5_set_error_message(context, ret, + N_("Failed storing kvno " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } + ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock); + if(ret) { + krb5_storage_free(emem); + goto out; + } + if ((d->flags & KRB5_KT_FL_JAVA) == 0) { + ret = krb5_store_int32 (emem, entry->vno); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed storing extended kvno " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } + ret = krb5_store_uint32 (emem, entry->flags); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed storing extended kvno " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } + } + + ret = krb5_storage_to_data(emem, &keytab); + krb5_storage_free(emem); + if(ret) { + krb5_set_error_message(context, ret, + N_("Failed converting keytab entry " + "to memory block for keytab %s", ""), + d->filename); + goto out; + } + } + + while(1) { + off_t here; + + here = krb5_storage_seek(sp, 0, SEEK_CUR); + if (here == -1) { + ret = errno; + krb5_set_error_message(context, ret, + N_("Failed writing keytab block " + "in keytab %s: %s", ""), + d->filename, strerror(ret)); + goto out; + } + ret = krb5_ret_int32(sp, &len); + if (ret) { + /* There could have been a partial length. Recover! */ + (void) krb5_storage_truncate(sp, here); + len = keytab.length; + break; + } + if(len < 0) { + len = -len; + if(len >= (int)keytab.length) { + krb5_storage_seek(sp, -4, SEEK_CUR); + break; + } + } + krb5_storage_seek(sp, len, SEEK_CUR); + } + ret = krb5_store_int32(sp, len); + if (ret != 0) + goto out; + bytes = krb5_storage_write(sp, keytab.data, keytab.length); + if (bytes != keytab.length) { + ret = bytes == -1 ? errno : KRB5_KT_END; + krb5_set_error_message(context, ret, + N_("Failed writing keytab block " + "in keytab %s: %s", ""), + d->filename, strerror(ret)); + } + memset(keytab.data, 0, keytab.length); + krb5_data_free(&keytab); + out: + if (ret == 0) + ret = krb5_storage_fsync(sp); + krb5_storage_free(sp); + close(fd); + return ret; +} + +static krb5_error_code KRB5_CALLCONV +fkt_remove_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct fkt_data *fkt = id->data; + krb5_ssize_t bytes; + krb5_keytab_entry e; + krb5_kt_cursor cursor; + off_t pos_start, pos_end; + int found = 0; + krb5_error_code ret; + + ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor); + if (ret != 0) { + const char *emsg = krb5_get_error_message(context, ret); + + krb5_set_error_message(context, ret, + N_("Could not open keytab file for write: %s: %s", ""), + fkt->filename, + emsg); + krb5_free_error_message(context, emsg); + return ret; + } + while (ret == 0 && + (ret = fkt_next_entry_int(context, id, &e, &cursor, + &pos_start, &pos_end)) == 0) { + if (krb5_kt_compare(context, &e, entry->principal, + entry->vno, entry->keyblock.keytype)) { + int32_t len; + unsigned char buf[128]; + found = 1; + krb5_storage_seek(cursor.sp, pos_start, SEEK_SET); + len = pos_end - pos_start - 4; + ret = krb5_store_int32(cursor.sp, -len); + memset(buf, 0, sizeof(buf)); + while (ret == 0 && len > 0) { + bytes = krb5_storage_write(cursor.sp, buf, + min((size_t)len, sizeof(buf))); + if (bytes != min((size_t)len, sizeof(buf))) { + ret = bytes == -1 ? errno : KRB5_KT_END; + break; + } + len -= min((size_t)len, sizeof(buf)); + } + } + krb5_kt_free_entry(context, &e); + } + (void) krb5_kt_end_seq_get(context, id, &cursor); + if (ret == KRB5_KT_END) + ret = 0; + if (ret) { + const char *emsg = krb5_get_error_message(context, ret); + + krb5_set_error_message(context, ret, + N_("Could not remove keytab entry from %s: %s", ""), + fkt->filename, + emsg); + krb5_free_error_message(context, emsg); + } else if (!found) { + krb5_clear_error_message(context); + return KRB5_KT_NOTFOUND; + } + return ret; +} + +const krb5_kt_ops krb5_fkt_ops = { + "FILE", + fkt_resolve, + fkt_get_name, + fkt_close, + fkt_destroy, + NULL, /* get */ + fkt_start_seq_get, + fkt_next_entry, + fkt_end_seq_get, + fkt_add_entry, + fkt_remove_entry, + NULL, + 0 +}; + +const krb5_kt_ops krb5_wrfkt_ops = { + "WRFILE", + fkt_resolve, + fkt_get_name, + fkt_close, + fkt_destroy, + NULL, /* get */ + fkt_start_seq_get, + fkt_next_entry, + fkt_end_seq_get, + fkt_add_entry, + fkt_remove_entry, + NULL, + 0 +}; + +const krb5_kt_ops krb5_javakt_ops = { + "JAVA14", + fkt_resolve_java14, + fkt_get_name, + fkt_close, + fkt_destroy, + NULL, /* get */ + fkt_start_seq_get, + fkt_next_entry, + fkt_end_seq_get, + fkt_add_entry, + fkt_remove_entry, + NULL, + 0 +}; diff --git a/third_party/heimdal/lib/krb5/keytab_keyfile.c b/third_party/heimdal/lib/krb5/keytab_keyfile.c new file mode 100644 index 0000000..af3ac86 --- /dev/null +++ b/third_party/heimdal/lib/krb5/keytab_keyfile.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifndef HEIMDAL_SMALLER + +/* afs keyfile operations --------------------------------------- */ + +/* + * Minimum tools to handle the AFS KeyFile. + * + * Format of the KeyFile is: + * {[ ] * numkeys} + * + * It just adds to the end of the keyfile, deleting isn't implemented. + * Use your favorite text/hex editor to delete keys. + * + */ + +#define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell" +#define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf" + +struct akf_data { + uint32_t num_entries; + char *filename; + char *cell; + char *realm; +}; + +/* + * set `d->cell' and `d->realm' + */ + +static int +get_cell_and_realm (krb5_context context, struct akf_data *d) +{ + FILE *f; + char buf[BUFSIZ], *cp; + int ret; + + f = fopen (AFS_SERVERTHISCELL, "r"); + if (f == NULL) { + ret = errno; + krb5_set_error_message (context, ret, + N_("Open ThisCell %s: %s", ""), + AFS_SERVERTHISCELL, + strerror(ret)); + return ret; + } + if (fgets (buf, sizeof(buf), f) == NULL) { + fclose (f); + krb5_set_error_message (context, EINVAL, + N_("No cell in ThisCell file %s", ""), + AFS_SERVERTHISCELL); + return EINVAL; + } + buf[strcspn(buf, "\n")] = '\0'; + fclose(f); + + d->cell = strdup (buf); + if (d->cell == NULL) + return krb5_enomem(context); + + f = fopen (AFS_SERVERMAGICKRBCONF, "r"); + if (f != NULL) { + if (fgets (buf, sizeof(buf), f) == NULL) { + free (d->cell); + d->cell = NULL; + fclose (f); + krb5_set_error_message (context, EINVAL, + N_("No realm in ThisCell file %s", ""), + AFS_SERVERMAGICKRBCONF); + return EINVAL; + } + buf[strcspn(buf, "\n")] = '\0'; + fclose(f); + } + /* uppercase */ + for (cp = buf; *cp != '\0'; cp++) + *cp = toupper((unsigned char)*cp); + + d->realm = strdup (buf); + if (d->realm == NULL) { + free (d->cell); + d->cell = NULL; + return krb5_enomem(context); + } + return 0; +} + +/* + * init and get filename + */ + +static krb5_error_code KRB5_CALLCONV +akf_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + int ret; + struct akf_data *d = calloc(1, sizeof (struct akf_data)); + + if (d == NULL) + return krb5_enomem(context); + + d->num_entries = 0; + ret = get_cell_and_realm (context, d); + if (ret) { + free (d); + return ret; + } + d->filename = strdup (name); + if (d->filename == NULL) { + free (d->cell); + free (d->realm); + free (d); + return krb5_enomem(context); + } + id->data = d; + + return 0; +} + +/* + * cleanup + */ + +static krb5_error_code KRB5_CALLCONV +akf_close(krb5_context context, krb5_keytab id) +{ + struct akf_data *d = id->data; + + free (d->filename); + free (d->cell); + free (d); + return 0; +} + +/* + * Return filename + */ + +static krb5_error_code KRB5_CALLCONV +akf_get_name(krb5_context context, + krb5_keytab id, + char *name, + size_t name_sz) +{ + struct akf_data *d = id->data; + + strlcpy (name, d->filename, name_sz); + return 0; +} + +/* + * Init + */ + +static krb5_error_code KRB5_CALLCONV +akf_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *c) +{ + int32_t ret; + struct akf_data *d = id->data; + + c->fd = open (d->filename, O_RDONLY | O_BINARY | O_CLOEXEC, 0600); + if (c->fd < 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("keytab afs keyfile open %s failed: %s", ""), + d->filename, strerror(ret)); + return ret; + } + + c->data = NULL; + c->sp = krb5_storage_from_fd(c->fd); + if (c->sp == NULL) { + close(c->fd); + krb5_clear_error_message (context); + return KRB5_KT_NOTFOUND; + } + krb5_storage_set_eof_code(c->sp, KRB5_KT_END); + + ret = krb5_ret_uint32(c->sp, &d->num_entries); + if(ret || d->num_entries > INT_MAX / 8) { + krb5_storage_free(c->sp); + close(c->fd); + krb5_clear_error_message (context); + if(ret == KRB5_KT_END) + return KRB5_KT_NOTFOUND; + return ret; + } + + return 0; +} + +static krb5_error_code KRB5_CALLCONV +akf_next_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *cursor) +{ + struct akf_data *d = id->data; + int32_t kvno; + off_t pos; + int ret; + + pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); + + if ((pos - 4) / (4 + 8) >= d->num_entries) + return KRB5_KT_END; + + ret = krb5_make_principal (context, &entry->principal, + d->realm, "afs", d->cell, NULL); + if (ret) + goto out; + + ret = krb5_ret_int32(cursor->sp, &kvno); + if (ret) { + krb5_free_principal (context, entry->principal); + goto out; + } + + entry->vno = kvno; + + if (cursor->data) + entry->keyblock.keytype = ETYPE_DES_CBC_MD5; + else + entry->keyblock.keytype = ETYPE_DES_CBC_CRC; + entry->keyblock.keyvalue.length = 8; + entry->keyblock.keyvalue.data = malloc (8); + if (entry->keyblock.keyvalue.data == NULL) { + krb5_free_principal (context, entry->principal); + ret = krb5_enomem(context); + goto out; + } + + ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8); + if(ret != 8) + ret = (ret < 0) ? errno : KRB5_KT_END; + else + ret = 0; + + entry->timestamp = time(NULL); + entry->flags = 0; + entry->aliases = NULL; + + out: + if (cursor->data) { + krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET); + cursor->data = NULL; + } else + cursor->data = cursor; + return ret; +} + +static krb5_error_code KRB5_CALLCONV +akf_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + krb5_storage_free(cursor->sp); + close(cursor->fd); + cursor->data = NULL; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +akf_add_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct akf_data *d = id->data; + int fd, created = 0; + krb5_error_code ret; + int32_t len; + krb5_storage *sp; + + + if (entry->keyblock.keyvalue.length != 8) + return 0; + switch(entry->keyblock.keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + break; + default: + return 0; + } + + fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC); + if (fd < 0) { + fd = open (d->filename, + O_RDWR | O_BINARY | O_CREAT | O_EXCL | O_CLOEXEC, 0600); + if (fd < 0) { + ret = errno; + krb5_set_error_message(context, ret, + N_("open keyfile(%s): %s", ""), + d->filename, + strerror(ret)); + return ret; + } + created = 1; + } + + sp = krb5_storage_from_fd(fd); + if(sp == NULL) { + close(fd); + return krb5_enomem(context); + } + if (created) + len = 0; + else { + if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) { + ret = errno; + krb5_storage_free(sp); + close(fd); + krb5_set_error_message(context, ret, + N_("seeking in keyfile: %s", ""), + strerror(ret)); + return ret; + } + + ret = krb5_ret_int32(sp, &len); + if(ret) { + krb5_storage_free(sp); + close(fd); + return ret; + } + } + + /* + * Make sure we don't add the entry twice, assumes the DES + * encryption types are all the same key. + */ + if (len > 0) { + int32_t kvno; + int i; + + for (i = 0; i < len; i++) { + ret = krb5_ret_int32(sp, &kvno); + if (ret) { + krb5_set_error_message (context, ret, + N_("Failed getting kvno from keyfile", "")); + goto out; + } + if(krb5_storage_seek(sp, 8, SEEK_CUR) < 0) { + ret = errno; + krb5_set_error_message (context, ret, + N_("Failed seeing in keyfile: %s", ""), + strerror(ret)); + goto out; + } + if (kvno == entry->vno) { + ret = 0; + goto out; + } + } + } + + len++; + + if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) { + ret = errno; + krb5_set_error_message (context, ret, + N_("Failed seeing in keyfile: %s", ""), + strerror(ret)); + goto out; + } + + ret = krb5_store_int32(sp, len); + if(ret) { + ret = errno; + krb5_set_error_message (context, ret, + N_("keytab keyfile failed new length", "")); + goto out; + } + + if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) { + ret = errno; + krb5_set_error_message (context, ret, + N_("seek to end: %s", ""), strerror(ret)); + goto out; + } + + ret = krb5_store_int32(sp, entry->vno); + if(ret) { + krb5_set_error_message(context, ret, + N_("keytab keyfile failed store kvno", "")); + goto out; + } + ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data, + entry->keyblock.keyvalue.length); + if(ret != entry->keyblock.keyvalue.length) { + if (ret < 0) + ret = errno; + else + ret = ENOTTY; + krb5_set_error_message(context, ret, + N_("keytab keyfile failed to add key", "")); + goto out; + } + ret = 0; +out: + krb5_storage_free(sp); + close (fd); + return ret; +} + +const krb5_kt_ops krb5_akf_ops = { + "AFSKEYFILE", + akf_resolve, + akf_get_name, + akf_close, + NULL, /* destroy */ + NULL, /* get */ + akf_start_seq_get, + akf_next_entry, + akf_end_seq_get, + akf_add_entry, + NULL, /* remove */ + NULL, + 0 +}; + +#endif /* HEIMDAL_SMALLER */ diff --git a/third_party/heimdal/lib/krb5/keytab_memory.c b/third_party/heimdal/lib/krb5/keytab_memory.c new file mode 100644 index 0000000..87953a6 --- /dev/null +++ b/third_party/heimdal/lib/krb5/keytab_memory.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* memory operations -------------------------------------------- */ + +struct mkt_data { + krb5_keytab_entry *entries; + int num_entries; + char *name; + int refcount; + struct mkt_data *next; +}; + +/* this mutex protects mkt_head, ->refcount, and ->next + * content is not protected (name is static and need no protection) + */ +static HEIMDAL_MUTEX mkt_mutex = HEIMDAL_MUTEX_INITIALIZER; +static struct mkt_data *mkt_head; + + +static krb5_error_code KRB5_CALLCONV +mkt_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct mkt_data *d; + + HEIMDAL_MUTEX_lock(&mkt_mutex); + + for (d = mkt_head; d != NULL; d = d->next) + if (strcmp(d->name, name) == 0) + break; + if (d) { + if (d->refcount < 1) + krb5_abortx(context, "Double close on memory keytab, " + "refcount < 1 %d", d->refcount); + d->refcount++; + id->data = d; + HEIMDAL_MUTEX_unlock(&mkt_mutex); + return 0; + } + + d = calloc(1, sizeof(*d)); + if(d == NULL) { + HEIMDAL_MUTEX_unlock(&mkt_mutex); + return krb5_enomem(context); + } + d->name = strdup(name); + if (d->name == NULL) { + HEIMDAL_MUTEX_unlock(&mkt_mutex); + free(d); + return krb5_enomem(context); + } + d->entries = NULL; + d->num_entries = 0; + d->refcount = 1; + d->next = mkt_head; + mkt_head = d; + HEIMDAL_MUTEX_unlock(&mkt_mutex); + id->data = d; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +mkt_close(krb5_context context, krb5_keytab id) +{ + struct mkt_data *d = id->data, **dp; + int i; + + HEIMDAL_MUTEX_lock(&mkt_mutex); + if (d->refcount < 1) + krb5_abortx(context, + "krb5 internal error, memory keytab refcount < 1 on close"); + + if (--d->refcount > 0) { + HEIMDAL_MUTEX_unlock(&mkt_mutex); + return 0; + } + for (dp = &mkt_head; *dp != NULL; dp = &(*dp)->next) { + if (*dp == d) { + *dp = d->next; + break; + } + } + HEIMDAL_MUTEX_unlock(&mkt_mutex); + + free(d->name); + for(i = 0; i < d->num_entries; i++) + krb5_kt_free_entry(context, &d->entries[i]); + free(d->entries); + free(d); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +mkt_get_name(krb5_context context, + krb5_keytab id, + char *name, + size_t namesize) +{ + struct mkt_data *d = id->data; + strlcpy(name, d->name, namesize); + return 0; +} + +static krb5_error_code KRB5_CALLCONV +mkt_start_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *c) +{ + /* XXX */ + c->fd = 0; + return 0; +} + +static krb5_error_code KRB5_CALLCONV +mkt_next_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry, + krb5_kt_cursor *c) +{ + struct mkt_data *d = id->data; + if(c->fd >= d->num_entries) + return KRB5_KT_END; + return krb5_kt_copy_entry_contents(context, &d->entries[c->fd++], entry); +} + +static krb5_error_code KRB5_CALLCONV +mkt_end_seq_get(krb5_context context, + krb5_keytab id, + krb5_kt_cursor *cursor) +{ + return 0; +} + +static krb5_error_code KRB5_CALLCONV +mkt_add_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct mkt_data *d = id->data; + krb5_keytab_entry *tmp; + tmp = realloc(d->entries, (d->num_entries + 1) * sizeof(*d->entries)); + if (tmp == NULL) + return krb5_enomem(context); + d->entries = tmp; + return krb5_kt_copy_entry_contents(context, entry, + &d->entries[d->num_entries++]); +} + +static krb5_error_code KRB5_CALLCONV +mkt_remove_entry(krb5_context context, + krb5_keytab id, + krb5_keytab_entry *entry) +{ + struct mkt_data *d = id->data; + krb5_keytab_entry *e, *end; + int found = 0; + + if (d->num_entries == 0) { + krb5_clear_error_message(context); + return KRB5_KT_NOTFOUND; + } + + /* do this backwards to minimize copying */ + for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) { + if(krb5_kt_compare(context, e, entry->principal, + entry->vno, entry->keyblock.keytype)) { + krb5_kt_free_entry(context, e); + memmove(e, e + 1, (end - e - 1) * sizeof(*e)); + memset(end - 1, 0, sizeof(*end)); + d->num_entries--; + end--; + found = 1; + } + } + if (!found) { + krb5_clear_error_message (context); + return KRB5_KT_NOTFOUND; + } + e = realloc(d->entries, d->num_entries * sizeof(*d->entries)); + if(e != NULL || d->num_entries == 0) + d->entries = e; + return 0; +} + +const krb5_kt_ops krb5_mkt_ops = { + "MEMORY", + mkt_resolve, + mkt_get_name, + mkt_close, + NULL, /* destroy */ + NULL, /* get */ + mkt_start_seq_get, + mkt_next_entry, + mkt_end_seq_get, + mkt_add_entry, + mkt_remove_entry, + NULL, + 0 +}; diff --git a/third_party/heimdal/lib/krb5/krb5-plugin.7 b/third_party/heimdal/lib/krb5/krb5-plugin.7 new file mode 100644 index 0000000..0b1e729 --- /dev/null +++ b/third_party/heimdal/lib/krb5/krb5-plugin.7 @@ -0,0 +1,359 @@ +.\" Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd December 21, 2011 +.Dt KRB5-PLUGIN 7 +.Os HEIMDAL +.Sh NAME +.Nm krb5-plugin +.Nd plugin interface for Heimdal +.Sh SYNOPSIS +.In krb5.h +.In krb5/an2ln_plugin.h +.In krb5/ccache_plugin.h +.In krb5/db_plugin.h +.In krb5/kuserok_plugin.h +.In krb5/locate_plugin.h +.In krb5/send_to_kdc_plugin.h +.Sh DESCRIPTION +Heimdal has a plugin interface. Plugins may be statically linked into +Heimdal and registered via the +.Xr krb5_plugin_register 3 +function, or they may be dynamically loaded from shared objects present +in the Heimdal plugins directories. +.Pp +Plugins consist of a C struct whose struct name is given in the +associated header file, such as, for example, +.Va krb5plugin_kuserok_ftable +and a pointer to which is either registered via +.Xr krb5_plugin_register 3 +or via a plugin load function exported by a shared object. +Plugin load functions should be named by concatenating the name defined in the +associated header file with the string "plugin_load" (e.g. +"krb5_plugin_kuserok_plugin_load" for the plugin for +.Xr krb5_kuserok 3 +). +The plugin load function must be of type +.Va heim_plugin_load_ft +which is: +.Bd -literal -offset indent +krb5_error_code HEIM_CALLCONV +my_plugin_load(heim_pcontext context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + heim_plugin_common_ftable_cp **plugins); + +.Ed +where +.Va HEIM_CALLCONV +is +.Va __stdcall +on Windows. +.Pp +The plugin should set the get_instance output parameter to the a +function that will return the instances of its library +dependencies. For example: +.Bd -literal -offset indent +static uintptr_t HEIM_LIB_CALL +my_plugin_get_instance(const char *name) +{ + if (strcmp(name, "krb5") == 0) + return krb5_get_instance(name); + return 0; +} +.Ed +.Pp +The +.Va get_instance +function is used to check that dynamically-linked plugins are +linked with the same Heimdal shared objects as the one loading +and running the plugin. +.Pp +The output parameters +.Va plugins +and +.Va n_plugins +output an array of pointers to function tabls, and the number of +those, respectively. +.Pp +The plugin structs for all plugin types always begin with the same three +common fields: +.Bl -enum -compact +.It +.Va minor_version +, an int. Plugin minor versions are defined in each plugin type's +associated header file. +.It +.Va init +, a pointer to a function with two arguments, a +.Va heim_pcontext +(which for krb5 plugins is actually a krb5_context), +and a +.Va void ** +, returning a heim_error_code. This function will be called to +initialize a plugin-specific context in the form of a +.Va void * +that will be output through the init function's second argument. +.It +.Va fini +, a pointer to a function of one argument, a +.Va void * +, consisting of the plugin's context to be destroyed, and +returning +.Va void. +.El +.Pp +Each plugin type may add fields to this struct following the above +three. Plugins are typically invoked in no particular order until one +succeeds or fails, or all return a special return value that indicates +that the plugin was not applicable. For krb5 plugins, +.Va KRB5_PLUGIN_NO_HANDLE +indicates that the plugin was not applicable. +.Pp +Heimdal plugin callers either invoke all plugins until one returns an +error or all return +.Va KRB5_PLUGIN_NO_HANDLE +, or invoke all plugins until one returns a value other than +.Va KRB5_PLUGIN_NO_HANDLE +with the expectation that only one plugin would return success and all +oters would return +.Va KRB5_PLUGIN_NO_HANDLE. +Thus Heimdal plugin invokation can be deterministic in spite of +non-deterministic invocation order. +.Pp +There is a database plugin system intended for many of the uses of +databases in Heimdal. The plugin is expected to call +.Xr heim_db_register 3 +from its +.Va init +entry point to register a DB type. The DB plugin's +.Va fini +function must do nothing, and the plugin must not provide any other +entry points. +.Pp +The krb5_kuserok plugin adds a single field to its struct: a pointer to +a function that implements kuserok functionality with the following +form: +.Bd -literal -offset indent +static krb5_error_code +kuserok(void *plug_ctx, krb5_context context, const char *rule, + unsigned int flags, const char *k5login_dir, + const char *luser, krb5_const_principal principal, + krb5_boolean *result) +.Ed +.Pp +The +.Va luser +, +.Va principal +and +.Va result +arguments are self-explanatory (see +.Xr krb5_kuserok 3 +). The +.Va plug_ctx +argument is the context output by the plugin's init function. The +.Va rule +argument is a kuserok rule from the krb5.conf file; each plugin is invoked once +for each rule until all plugins fail or one succeeds. The +.Va k5login_dir +argument provides an alternative k5login file location, if not NULL. +The +.Va flags +argument indicates whether the plugin may call +.Xr krb5_aname_to_localname 3 +(KUSEROK_ANAME_TO_LNAME_OK), and whether k5login databases are expected to be +authoritative (KUSEROK_K5LOGIN_IS_AUTHORITATIVE). +.Pp +The plugin for +.Xr krb5_aname_to_localname 3 +is named "an2ln" and has a single extra field for the plugin struct: +.Bd -literal -offset indent +typedef krb5_error_code (*set_result_f)(void *, const char *); + +static krb5_error_code +an2ln(void *plug_ctx, krb5_context context, const char *rule, + krb5_const_principal aname, set_result_f set_res_f, void *set_res_ctx) +.Ed +.Pp +The arguments for the +.Va an2ln +plugin are similar to those of the kuserok plugin, but the result, being +a string, is set by calling the +.Va set_res_f +function argument with the +.Va set_res_ctx +and result string as arguments. The +.Va set_res_f +function will make a copy of the string. +.Sh FILES +.Bl -tag -compact +.It Pa libdir/plugin/krb5/* +Shared objects containing plugins for Heimdal. +.El +.Sh EXAMPLES +.Pp +An example an2ln plugin that maps principals to a constant "nouser" +follows: +.Pp +.Bd -literal -offset indent +#include + +/* Note that `context' here is actually a krb5_context value */ +static krb5_error_code KRB5_CALLCONV +nouser_plug_init(heim_pcontext context, void **ctx) +{ + *ctx = NULL; + return 0; +} + +static void KRB5_CALLCONV nouser_plug_fini(void *ctx) { } + +static krb5_error_code KRB5_CALLCONV +nouser_plug_an2ln(void *plug_ctx, krb5_context context, + const char *rule, + krb5_const_principal aname, + set_result_f set_res_f, void *set_res_ctx) +{ + krb5_error_code ret; + + if (strcmp(rule, "NOUSER") != 0) + return KRB5_PLUGIN_NO_HANDLE; + + ret = set_res_f(set_res_ctx, "nouser"); + + return ret; +} + +krb5plugin_an2ln_ftable an2ln = { + KRB5_PLUGIN_AN2LN_VERSION_0, + nouser_plug_init, + nouser_plug_fini, + nouser_plug_an2ln, +}; + +static const krb5plugin_an2ln_ftable *const plugins[] = { + &an2ln +}; + +static uintptr_t +an2ln_get_instance(const char *libname) +{ + if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} + +/* Note that `context' here is actually a krb5_context value */ +krb5_error_code +an2ln_plugin_load(heim_pcontext context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + const krb5plugin_an2ln_ftable * const **pplugins) +{ + *get_instance = an2ln_get_instance; + *num_plugins = sizeof(plugins) / sizeof(plugins[0]); + *pplugins = plugins; + return 0; +} +.Ed +.Pp +An example kuserok plugin that rejects all requests follows. (Note that +there exists a built-in plugin with this functionality; see +.Xr krb5_kuserok 3 +). +.Pp +.Bd -literal -offset indent +#include + +static krb5_error_code KRB5_CALLCONV +reject_plug_init(heim_context context, void **ctx) +{ + *ctx = NULL; + return 0; +} + +static void KRB5_CALLCONV reject_plug_fini(void *ctx) { } + +static krb5_error_code KRB5_CALLCONV +reject_plug_kuserok(void *plug_ctx, krb5_context context, const char *rule, + unsigned int flags, const char *k5login_dir, + const char *luser, krb5_const_principal principal, + krb5_boolean *result) +{ + if (strcmp(rule, "REJECT") != 0) + return KRB5_PLUGIN_NO_HANDLE; + + *result = FALSE; + return 0; +} + +static krb5plugin_kuserok_ftable kuserok = { + KRB5_PLUGIN_KUSEROK_VERSION_0, + reject_plug_init, + reject_plug_fini, + reject_plug_kuserok, +}; + +static const krb5plugin_kuserok_ftable *const plugins[] = { + &kuserok +}; + +static uintptr_t +kuserok_get_instance(const char *libname) +{ + if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + + return 0; +} + +krb5_error_code +krb5_plugin_kuserok_plugin_load( + heim_context context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + const krb5plugin_kuserok_ftable * const **pplugins) +{ + *krb5_instance = kuserok_get_instance; + *num_plugins = sizeof(plugins) / sizeof(plugins[0]); + *pplugins = plugins; + return 0; +} + +.Ed +.Sh SEE ALSO +.Xr krb5_plugin_register 3 +.Xr krb5_kuserok 3 +.Xr krb5_aname_to_localname 3 diff --git a/third_party/heimdal/lib/krb5/krb5.conf.5 b/third_party/heimdal/lib/krb5/krb5.conf.5 new file mode 100644 index 0000000..a10b572 --- /dev/null +++ b/third_party/heimdal/lib/krb5/krb5.conf.5 @@ -0,0 +1,1475 @@ +.\" Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd May 4, 2005 +.Dt KRB5.CONF 5 +.Os HEIMDAL +.Sh NAME +.Nm krb5.conf +.Nd configuration file for Kerberos 5 +.Sh SYNOPSIS +.In krb5.h +.Sh DESCRIPTION +The +.Nm +file specifies several configuration parameters for the Kerberos 5 +library, as well as for some programs. +.Pp +The file consists of one or more sections, containing a number of +bindings. +The value of each binding can be either a string or a list of other +bindings. +The grammar looks like: +.Bd -literal -offset indent +file: + /* empty */ + sections + includes + +sections: + section sections + section + +section: + '[' section_name ']' bindings + +section_name: + STRING + +bindings: + binding bindings + binding + +binding: + name '=' STRING + name '=' '{' bindings '}' + +name: + STRING + +includes: + 'include' path + 'includedir' path + +path: STRING + +.Ed +.Li STRINGs +consists of one or more non-whitespace characters. +.Pp +Files and directories may be included by absolute path, with percent +token expansion (see the TOKEN EXPANSION section). Including a +directory causes all files in the directory to be included as if each +file had been included separately, but only files whose names consist of +alphanumeric, hyphen, and underscore are included, though they may also +end in '.conf'. +.Pp +STRINGs that are specified later in this man-page uses the following +notation. +.Bl -tag -width "xxx" -offset indent +.It boolean +values can be either yes/true or no/false. +.It time +values can be a list of year, month, day, hour, min, second. +Example: 1 month 2 days 30 min. +If no unit is given, seconds is assumed. +.It etypes +valid encryption types are: des-cbc-crc, des-cbc-md4, des-cbc-md5, +des3-cbc-sha1, arcfour-hmac-md5, aes128-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96, +aes128-cts-hmac-sha256-128, and aes256-cts-hmac-sha384-192. +.It address +an address can be either a IPv4 or a IPv6 address. +.El +.Pp +Currently recognised sections and bindings are: +.Bl -tag -width "xxx" -offset indent +.It Li [appdefaults] +Specifies the default values to be used for Kerberos applications. +You can specify defaults per application, realm, or a combination of +these. +The preference order is: +.Bl -enum -compact +.It +.Va application Va realm Va option +.It +.Va application Va option +.It +.Va realm Va option +.It +.Va option +.El +.Pp +The supported options are: +.Bl -tag -width "xxx" -offset indent +.It Li forwardable = Va boolean +When obtaining initial credentials, make the credentials forwardable. +.It Li proxiable = Va boolean +When obtaining initial credentials, make the credentials proxiable. +.It Li no-addresses = Va boolean +When obtaining initial credentials, request them for an empty set of +addresses, making the tickets valid from any address. +.It Li ticket_lifetime = Va time +Default ticket lifetime. +.It Li renew_lifetime = Va time +Default renewable ticket lifetime. +.It Li encrypt = Va boolean +Use encryption, when available. +.It Li forward = Va boolean +Forward credentials to remote host (for +.Xr rsh 1 , +.Xr telnet 1 , +etc). +.It Li historical_anon_pkinit = Va boolean +Enable legacy anonymous pkinit command-line syntax. +With this option set to +.Li true, +the +.Xr kinit 1 +.Fl Fl anonymous +command with no principal argument specified will request an anonymous pkinit +ticket from the default realm. +If a principal argument is specified, it is used as an explicit realm name for +anonymous pkinit even without an +.Li @ +prefix. +.It Li delegate-destination-tgt = Va boolean +When forwarding credentials to a remote host, forward a TGT for the +realm of the destination host rather than a TGT for the user's realm. +This is useful when hosts in the remote realm should not or cannot +(e.g. firewalled from user realm's KDC) obtain tickets for services +in the user's realm. When the user's realm and the host's realm are +the same, this parameter has no effect. The setting can be applied +to a single realm as follows: +.Bd -literal -offset indent +EXAMPLE.COM = { + delegate-destination-tgt = true +} +.Ed +.It Li pkinit_pool = Va HX509-STORE +This is a multi-valued parameter naming one or more stores of +intermediate certification authority (CA) certificates for the +client's end entity certificate. +.It Li pkinit_anchors = Va HX509-STORE ... +This is a multi-valued parameter naming one or more stores of +anchors for PKINIT KDC certificates. +.It Li pkinit_revoke = Va HX509-STORE ... +This is a multi-valued parameter naming one or more stores of +CRLs for the issuers of PKINIT KDC certificates. +Only the first valid CRL for a particular issuer will be checked. +If no CRLs are configured, then CRLs will not be checked. +This is because hx509 currently lacks support. +.El +.It Li [libdefaults] +.Bl -tag -width "xxx" -offset indent +.It Li default_realm = Va REALM +Default realm to use, this is also known as your +.Dq local realm . +The default is the result of +.Fn krb5_get_host_realm "local hostname" . +.It Li allow_weak_crypto = Va boolean +are weak crypto algorithms allowed to be used, among others, DES is +considered weak. +.It Li clockskew = Va time +Maximum time differential (in seconds) allowed when comparing +times. +Default is 300 seconds (five minutes). +.It Li kdc_timeout = Va time +Maximum time to wait for a reply from the kdc, default is 3 seconds. +.It Li capath = { +.Bl -tag -width "xxx" -offset indent +.It Va destination-realm Li = Va next-hop-realm +.It ... +.It Li } +.El +This is deprecated, see the +.Li capaths +section below. +.It Li default_cc_type = Va cctype +sets the default credentials type. +.It Li default_cc_name = Va ccname +the default credentials cache name. +If you want to change the type only use +.Li default_cc_type . +The string can contain variables that are expanded at runtime. See the TOKEN +EXPANSION section. +.It Li default_file_cache_collections = Va FILE:/path/with/tokens ... +This multi-valued parameter allows more than one path to be +configured for the FILE credentials cache type to look in. The FILE +credentials cache type will also consider file names whose prefixes +match these and end in +.Va +name +as subsidiary caches in the collection. The values of this +parameter are subject to token expansion. See the TOKEN EXPANSION +section. +.It Li enable_file_cache_iteration = Va boolean +If enabled, the +.Va FILE +credential cache type will support iteration of all subsidiary +caches in the default collection, meaning that +.Xr kinit 1 +.Va -l +option will list them. This does require scanning the directory +containing a given +.Va FILE +ccache, which, if it is +.Va /tmp +may be a slow operation. Defaults to false. +.It Li default_etypes = Va etypes ... +A list of default encryption types to use. (Default: all enctypes if +allow_weak_crypto = TRUE, else all enctypes except single DES enctypes.) +.It Li default_as_etypes = Va etypes ... +A list of default encryption types to use in AS requests. (Default: the +value of default_etypes.) +.It Li default_tgs_etypes = Va etypes ... +A list of default encryption types to use in TGS requests. (Default: +the value of default_etypes.) +.It Li default_etypes_des = Va etypes ... +A list of default encryption types to use when requesting a DES credential. +.It Li default_keytab_name = Va keytab +The keytab to use if no other is specified, default is +.Dq FILE:/etc/krb5.keytab . +.It Li default_client_keytab_name = Va keytab +The keytab to use for client credential acquisition if no other is +specified, default is +.Dq FILE:%{LOCALSTATEDIR}/user/%{euid}/client.keytab . +See the TOKEN EXPANSION section. +.It Li dns_lookup_kdc = Va boolean +Use DNS SRV records to lookup KDC services location. +.It Li dns_lookup_realm = Va boolean +Use DNS TXT records to lookup domain to realm mappings. +.It Li enforce_ok_as_delegate = Va boolean +If this flag to true, GSSAPI credential delegation will be +disabled when the +.Ar ok-as-delegate +flag is not set in the service ticket. +If this flag is false, the +.Ar ok-as-delegate +ticket flag is only enforced when an application specifically +requests enforcement. +The default value is false. +.It Li kdc_timesync = Va boolean +Try to keep track of the time differential between the local machine +and the KDC, and then compensate for that when issuing requests. +.It Li max_retries = Va number +The max number of times to try to contact each KDC. +.It Li large_msg_size = Va number +The threshold where protocols with tiny maximum message sizes are not +considered usable to send messages to the KDC. +.It Li ticket_lifetime = Va time +Default ticket lifetime. +.It Li renew_lifetime = Va time +Default renewable ticket lifetime. +.It Li forwardable = Va boolean +When obtaining initial credentials, make the credentials forwardable. +This option is also valid in the [realms] section. +.It Li proxiable = Va boolean +When obtaining initial credentials, make the credentials proxiable. +This option is also valid in the [realms] section. +.It Li verify_ap_req_nofail = Va boolean +If enabled, failure to verify credentials against a local key is a +fatal error. +The application has to be able to read the corresponding service key +for this to work. +Some applications, like +.Xr su 1 , +enable this option unconditionally. +.It Li warn_pwexpire = Va time +How soon to warn for expiring password. +Default is seven days. +.It Li http_proxy = Va proxy-spec +A HTTP-proxy to use when talking to the KDC via HTTP. +.It Li dns_proxy = Va proxy-spec +Enable using DNS via HTTP. +.It Li extra_addresses = Va address ... +A list of addresses to get tickets for along with all local addresses. +.It Li time_format = Va string +How to print time strings in logs, this string is passed to +.Xr strftime 3 . +.It Li date_format = Va string +How to print date strings in logs, this string is passed to +.Xr strftime 3 . +.It Li log_utc = Va boolean +Write log-entries using UTC instead of your local time zone. +.It Li scan_interfaces = Va boolean +Scan all network interfaces for addresses, as opposed to simply using +the address associated with the system's host name. +.It Li fcache_version = Va int +Use file credential cache format version specified. +.It Li fcc-mit-ticketflags = Va boolean +Use MIT compatible format for file credential cache. +It's the field ticketflags that is stored in reverse bit order for +older than Heimdal 0.7. +Setting this flag to +.Dv TRUE +makes it store the MIT way, this is default for Heimdal 0.7. +.It Li check-rd-req-server +If set to "ignore", the framework will ignore any of the server input to +.Xr krb5_rd_req 3 , +this is very useful when the GSS-API server input the +wrong server name into the gss_accept_sec_context call. +.It Li k5login_directory = Va directory +Alternative location for user .k5login files. This option is provided +for compatibility with MIT krb5 configuration files. This path is +subject to percent token expansion (see TOKEN EXPANSION). +.It Li k5login_authoritative = Va boolean +If true then if a principal is not found in k5login files then +.Xr krb5_userok 3 +will not fallback on principal to username mapping. This option is +provided for compatibility with MIT krb5 configuration files. +.It Li kuserok = Va rule ... +Specifies +.Xr krb5_userok 3 +behavior. If multiple values are given, then +.Xr krb5_userok 3 +will evaluate them in order until one succeeds or all fail. Rules are +implemented by plugins, with three built-in plugins +described below. Default: USER-K5LOGIN SIMPLE DENY. +.It Li kuserok = Va DENY +If set and evaluated then +.Xr krb5_userok 3 +will deny access to the given username no matter what the principal name +might be. +.It Li kuserok = Va SIMPLE +If set and evaluated then +.Xr krb5_userok 3 +will use principal to username mapping (see auth_to_local below). If +the principal maps to the requested username then access is allowed. +.It Li kuserok = Va SYSTEM-K5LOGIN[:directory] +If set and evaluated then +.Xr krb5_userok 3 +will use k5login files named after the +.Va luser +argument to +.Xr krb5_userok 3 +in the given directory or in +.Pa /etc/k5login.d/ . +K5login files are text files, with each line containing just a principal +name; principals apearing in a user's k5login file are permitted access +to the user's account. Note: this rule performs no ownership nor +permissions checks on k5login files; proper ownership and +permissions/ACLs are expected due to the k5login location being a +system location. +.It Li kuserok = Va USER-K5LOGIN +If set and evaluated then +.Xr krb5_userok 3 +will use +.Pa ~luser/.k5login +and +.Pa ~luser/.k5login.d/* . +User k5login files and directories must be owned by the user and must +not have world nor group write permissions. +.It Li aname2lname-text-db = Va filename +The named file must be a sorted (in increasing order) text file where +every line consists of an unparsed principal name optionally followed by +whitespace and a username. The aname2lname function will do a binary +search on this file, if configured, looking for lines that match the +given principal name, and if found the given username will be used, or, +if the username is missing, an error will be returned. If the file +doesn't exist, or if no matching line is found then other plugins will +be allowed to run. +.It Li fcache_strict_checking +strict checking in FILE credential caches that owner, no symlink and +permissions is correct. +.It Li moduli = Va FILE +Names a file that contains acceptable modular Diffie-Hellman +groups for PKINIT. +The given file should contain lines with whitespace-separated +fields in this order: +.Va name, nbits, p, g, q . +Lines starting with a +.Va # +are comments. +.It Li pkinit_dh_min_bits = Va NUMBER +PKINIT client's minimum acceptable modular Diffie-Hellman public +key size in bits. +.It Li enable-kx509 = Va boolean +Enable use of kx509 so that every TGT that can has a corresponding +PKIX certificate. Default: false. +.It Li kx509_gen_key_type = Va public-key-type +Type of public key for kx509 private key generation. Defaults to +.Va rsa +and currently only +.Va rsa +is supported. +.It Li kx509_gen_rsa_key_size = Va number-of-bits +RSA key size for kx509. Defaults to 2048. +.It Li kx509_store = path +A file path into which to write a certificate obtained with +kx509, and its private key, when attempting kx509 optimistically +using credentials from a default ccache. Tokens will be +expanded. +.It Li kx509_hostname = Va hostname +If set, then the kx509 client will use this hostname for the +kx509 service. This can also be set in the +.Li [realm] +section on a per-realm basis. If not set then a TGS name will be +used. +.It Li name_canon_rules = Va rules +One or more service principal name canonicalization rules. Each rule +consists of one or more tokens separated by colon (':'). Currently +these rules are used only for hostname canonicalization (usually when +getting a service ticket, from a ccache or a TGS, but also when +acquiring GSS initiator credentials from a keytab). These rules can be +used to implement DNS resolver-like search lists without having to use +DNS. +.Pp +NOTE: Name canonicalization rules are an experimental feature. +.Pp +The first token is a rule type, one of: +.Va as-is, +.Va qualify, or +.Va nss. +.Pp +Any remaining tokens must be options tokens: +.Va use_fast +(use FAST to protect TGS exchanges; currently not supported), +.Va use_dnssec +(use DNSSEC to protect hostname lookups; currently not supported), +.Va ccache_only +, +.Va use_referrals, +.Va no_referrals, +.Va lookup_realm, +.Va mindots=N, +.Va maxdots=N, +.Va order=N, +domain= +.Va domain, +realm= +.Va realm, +match_domain= +.Va domain, +and match_realm= +.Va realm. +.Pp +When trying to obtain a service ticket for a host-based service +principal name, name canonicalization rules are applied to that name in +the order given, one by one, until one succeds (a service ticket is +obtained), or all fail. Similarly when acquiring GSS initiator +credentials from a keytab, and when comparing a non-canonical GSS name +to a canonical one. +.Pp +For each rule the system checks that the hostname has at least +.Va mindots +periods (if given) in it, at most +.Va maxdots +periods (if given), that the hostname ends in the given +.Va match_domain +(if given), +and that the realm of the principal matches the +.Va match_realm +(if given). +.Pp +.Va As-is +rules leave the hostname unmodified but may set a realm. +.Va Qualify +rules qualify the hostname with the given +.Va domain +and also may set the realm. +The +.Va nss +rule uses the system resolver to lookup the host's canonical name and is +usually not secure. Note that using the +.Va nss +rule type implies having to have principal aliases in the HDB (though +not necessarily in keytabs). +.Pp +The empty realm denotes "ask the client's realm's TGS". The empty realm +may be set as well as matched. +.Pp +The order in which rules are applied is as follows: first all the rules +with explicit +.Va order +then all other rules in the order in which they appear. If any two +rules have the same explicit +.Va order , +their order of appearance in krb5.conf breaks the tie. Explicitly +specifying order can be useful where tools read and write the +configuration file without preserving parameter order. +.Pp +Malformed rules are ignored. +.It Li allow_hierarchical_capaths = Va boolean +When validating cross-realm transit paths, absent any explicit capath from the +client realm to the server realm, allow a hierarchical transit path via the +common ancestor domain of the two realms. +Defaults to true. +Note, absent an explicit setting, hierarchical capaths are always used by +the KDC when generating a referral to a destination with which is no direct +trust. +.It Li client_aware_channel_bindings = Va boolean +If this flag is true, then all application protocol authentication +requests will be flagged to indicate that the application supports +channel bindings when operating over a secure channel. +The default value is false. +.It Li check_pac = Va boolean +If this flag is true and a Windows Privilege Attribute Certificate (PAC) +is present in the ticket authorization data, then +.Xr krb5_rd_req 3 +will validate the PAC before returning success. The default value is true. +.It Li report_canonical_client_name = Va boolean +If this flag is true, then the canonical client name from the PAC will +be used instead of the client name in the ticket. The default value is false. +Note that setting it to true implicitly sets +.Va check_pac +to true. +.El +.It Li [domain_realm] +This is a list of mappings from DNS domain to Kerberos realm. +.Pp +It is used by the client and the TGS both to determine the realm +of host-based service principal names based on the principal's +hostname component. +.Pp +The client may try DNS to determine a host's realm; see the +`dns_lookup_realm' parameter, and see below. +.Pp +The TGS will issue a referral when a host-based service does not +exist in the requested realm but can be mapped with these rules +to a different realm. +The TGS will also issue a referral when a host-based service +exists in the requested realm as an alias of a service in another +realm. +.Pp +Each binding in this section looks like: +.Pp +.Dl domain = realm +.Pp +The domain can be either a full name of a host or a trailing +component, in the latter case the domain-string should start with a +period. +The trailing component only matches hosts that are in the same domain, ie +.Dq .example.com +matches +.Dq foo.example.com , +but not +.Dq foo.test.example.com . +.Pp +The realm may be the token `dns_locate', in which case the actual +realm will be determined using DNS (independently of the setting +of the `dns_lookup_realm' option). +.It Li [realms] +.Bl -tag -width "xxx" -offset indent +.It Va REALM Li = { +.Bl -tag -width "xxx" -offset indent +.It Li kdc = Va [service/]host[:port] +Specifies a list of kdcs for this realm. +If the optional +.Va port +is absent, the +default value for the +.Dq kerberos/udp +.Dq kerberos/tcp , +and +.Dq http/tcp +port (depending on service) will be used. +The kdcs will be used in the order that they are specified. +.Pp +The optional +.Va service +specifies over what medium the kdc should be +contacted. +Possible services are +.Dq udp , +.Dq tcp , +and +.Dq http . +Http can also be written as +.Dq http:// . +Default service is +.Dq udp +and +.Dq tcp . +.It Li admin_server = Va host[:port] +Specifies the admin server for this realm, where all the modifications +to the database are performed. +.It Li kpasswd_server = Va host[:port] +Points to the server where all the password changes are performed. +If there is no such entry, the kpasswd port on the admin_server host +will be tried. +.It Li tgs_require_subkey +a boolan variable that defaults to false. +Old DCE secd (pre 1.1) might need this to be true. +.It Li auth_to_local_names = { +.Bl -tag -width "xxx" -offset indent +.It Va principal_name = Va username +The given +.Va principal_name +will be mapped to the given +.Va username +if the +.Va REALM +is a default realm. +.El +.It Li } +.It Li auth_to_local = HEIMDAL_DEFAULT +Use the Heimdal default principal to username mapping. +Applies to principals from the +.Va REALM +if and only if +.Va REALM +is a default realm. +.It Li auth_to_local = DEFAULT +Use the MIT default principal to username mapping. +Applies to principals from the +.Va REALM +if and only if +.Va REALM +is a default realm. +.It Li auth_to_local = DB:/path/to/db.txt +Use a binary search of the given DB. The DB must be a flat-text +file sortedf in the "C" locale, with each record being a line +(separated by either LF or CRLF) consisting of a principal name +followed by whitespace followed by a username. +Applies to principals from the +.Va REALM +if and only if +.Va REALM +is a default realm. +.It Li auth_to_local = DB:/path/to/db +Use the given DB, if there's a plugin for it. +Applies to principals from the +.Va REALM +if and only if +.Va REALM +is a default realm. +.It Li auth_to_local = RULE:... +Use the given rule, if there's a plugin for it. +Applies to principals from the +.Va REALM +if and only if +.Va REALM +is a default realm. +.It Li auth_to_local = NONE +No additional principal to username mapping is done. Note that +.Va auth_to_local_names +and any preceding +.Va auth_to_local +rules have precedence. +.It Li pkinit_require_eku = BOOL +If +.Va true +then the KDC PKINIT Extended Key Usage (EKU) OID (1.3.6.5.2.3.5) +must be present in KDCs' PKINIT certificates. +Defaults to +.Va true . +.It Li pkinit_require_krbtgt_otherName = BOOL +If +.Va true +then the PKINIT Subject Alternative Name (SAN) for the TGS must +be present in KDCs' PKINIT certificates, and must match their +realm. +Defaults to +.Va true . +.It Li pkinit_require_hostname_match = BOOL +If +.Va true +then KDCs' PKINIT certificates must match their hostnames. +Defaults to +.Va false . +.It Li pkinit_trustedCertifiers = BOOL +If +.Va true +then PKINIT client will tell KDCs which trust anchors it trusts. +Defaults to +.Va true . +.It Li disable_pac = BOOL +If +.Va true +then the KDC will not sign tickets with PAC, which disables S4U2Proxy support. +Defaults to +.Va false . +.El +.It Li } +.El +.It Li [capaths] +.Bl -tag -width "xxx" -offset indent +.It Va client-realm Li = { +.Bl -tag -width "xxx" -offset indent +.It Va server-realm Li = Va hop-realm ... +This serves two purposes. First the first listed +.Va hop-realm +tells a client which realm it should contact in order to ultimately +obtain credentials for a service in the +.Va server-realm . +Secondly, it tells the KDC (and other servers) which realms are +allowed in a multi-hop traversal from +.Va client-realm +to +.Va server-realm . +Except for the client case, the order of the realms are not important. +.El +.It Va } +.El +.It Li [logging] +.Bl -tag -width "xxx" -offset indent +.It Va entity Li = Va destination +Specifies that +.Va entity +should use the specified +.Li destination +for logging. +See the +.Xr krb5_openlog 3 +manual page for a list of defined destinations. +.El +.It Li [kdc] +.Bl -tag -width "xxx" -offset indent +.It Li database Li = { +.Bl -tag -width "xxx" -offset indent +.It Li dbname Li = Va [DATBASETYPE:]DATABASENAME +Use this database for this realm. The +.Va DATABASETYPE +should be one of 'lmdb', 'db3', 'db1', 'db', 'sqlite', or 'ldap'. +See the info documetation how to configure different database backends. +.It Li realm Li = Va REALM +Specifies the realm that will be stored in this database. +It realm isn't set, it will used as the default database, there can +only be one entry that doesn't have a +.Li realm +stanza. +.It Li mkey_file Li = Pa FILENAME +Use this keytab file for the master key of this database. +If not specified +.Va DATABASENAME Ns .mkey +will be used. +.It Li acl_file Li = PA FILENAME +Use this file for the ACL list of this database. +.It Li log_file Li = Pa FILENAME +Use this file as the log of changes performed to the database. +This file is used by +.Nm ipropd-master +for propagating changes to slaves. It is also used by +.Nm kadmind +and +.Nm kadmin +(when used with the +.Li -l +option), and by all applications using +.Nm libkadm5 +with the local backend, for two-phase commit functionality. Slaves also +use this. Setting this to +.Nm /dev/null +disables two-phase commit and incremental propagation. Use +.Nm iprop-log +to show the contents of this log file. +.It Li log-max-size = Pa number +When the log reaches this size (in bytes), the log will be truncated, +saving some entries, and keeping the latest version number so as to not +disrupt incremental propagation. If set to a negative value then +automatic log truncation will be disabled. Defaults to 52428800 (50MB). +.El +.It Li } +.It Li max-request = Va SIZE +Maximum size of a kdc request. +.It Li require-preauth = Va BOOL +If set pre-authentication is required. +.It Li ports = Va "list of ports" +List of ports the kdc should listen to. +.It Li addresses = Va "list of interfaces" +List of addresses the kdc should bind to. +.It Li enable-http = Va BOOL +Should the kdc answer kdc-requests over http. +.It Li tgt-use-strongest-session-key = Va BOOL +If this is TRUE then the KDC will prefer the strongest key from the +client's AS-REQ or TGS-REQ enctype list for the ticket session key that +is supported by the KDC and the target principal when the target +principal is a krbtgt principal. Else it will prefer the first key from +the client's AS-REQ enctype list that is also supported by the KDC and +the target principal. Defaults to FALSE. +.It Li svc-use-strongest-session-key = Va BOOL +Like tgt-use-strongest-session-key, but applies to the session key +enctype of tickets for services other than krbtgt principals. Defaults +to FALSE. +.It Li preauth-use-strongest-session-key = Va BOOL +If TRUE then select the strongest possible enctype from the client's +AS-REQ for PA-ETYPE-INFO2 (i.e., for password-based pre-authentication). +Else pick the first supported enctype from the client's AS-REQ. Defaults +to FALSE. +.It Li use-strongest-server-key = Va BOOL +If TRUE then the KDC picks, for the ticket encrypted part's key, the +first supported enctype from the target service principal's hdb entry's +current keyset. Else the KDC picks the first supported enctype from the +target service principal's hdb entry's current keyset. Defaults to TRUE. +.It Li check-ticket-addresses = Va BOOL +Verify the addresses in the tickets used in tgs requests. +.\" XXX +.It Li warn_ticket_addresses = Va BOOL +Warn about, but allow, usage of tickets from hosts that don't match the +addresses in the tickets. +.It Li allow-null-ticket-addresses = Va BOOL +Allow address-less tickets. +.\" XXX +.It Li disable_pac = Va BOOL +Do not include a PAC in service tickets. +However, if a service has the +.Li auth-data-reqd +attribute then the KDC will include a PAC anyways. +.It Li enable_fast = Va BOOL +Enable RFC 6113 FAST support, this is enabled by default. +.It Li enable_fast_cookie = Va BOOL +If FAST is enabled, enable support for the FAST cookie +and mechanisms that require it. +.It Li enable_armored_pa_enc_timestamp = Va BOOL +Enable armored encrypted timestamp pre-authentication with key +strengthening. +RFC 6113 says not to use PA-ENC-TIMESTAMP in FAST armored tunnels +as there is a newer replacement, PA-ENC-CHALLENGE, but for +interoperability with earlier versions of Heimdal, this is +enabled by default for now. +.It Li enable_unarmored_pa_enc_timestamp = Va BOOL +Enable unarmored encrypted timestamp pre-authentication. +Enabled by default for now, but in a future release will be +disabled. +.It Li enable-pkinit = Va BOOL +Enable PKINIT (disabled by default). +.It Li require-pkinit-freshness = Va BOOL +If PKINIT is enabled, require that PKINIT requests contain a +freshness token proving recent possession of the private key. +Disabled by default. +.It Li allow-anonymous = Va BOOL +If the kdc is allowed to hand out anonymous tickets. +.It Li synthetic_clients = Va BOOL +If enabled then the KDC will issue tickets for clients that don't +exist in the HDB provided that they use PKINIT, that PKINIT is +enabled, and that the client's have certificates with PKINIT +subject alternative names (SANs). +.It Li synthetic_clients_max_life = Va TIME +Maximum ticket lifetime for synthetic clients. +Default: 5 minutes. +.It Li synthetic_clients_max_renew = Va TIME +Maximum ticket renewable lifetime for synthetic clients. +Default: 5 minutes. +.It Li pkinit_identity = Va HX509-STORE +This is an HX509 store containing the KDC's PKINIT credential +(private key and end-entity certificate). +This is single valued, though multiple stores can be specified by +separating them with commas. +An +.Va HX509-STORE +is of the form +.Va TYPE:name +where +.Va TYPE +is one of +.Va FILE, Va PEM-FILE, Va DER-FILE, Va PKCS12, Va PKCS11, +or on OX X, +.Va KEYCHAIN . +The form of the +.Va name +depends on the +.Va TYPE . +For +.Va FILE, Va PEM-FILE, Va DER-FILE, +and +.Va PKCS12 +the +.Va name +is a file path. +See the Heimdal hx509 documentation for more information. +.It Li pkinit_pool = Va HX509-STORE +This is a multi-valued parameter naming one or more stores of +intermediate certification authority (CA) certificates for the +KDC's end entity certificate. +.It Li pkinit_anchors = Va HX509-STORE ... +This is a multi-valued parameter naming one or more stores of +anchors for PKINIT client certificates. +Note that the +.Va DIR +type of +.Va HX509-STORE +is also supported here. +.Va DIR +type stores are OpenSSL-style CA certificate hash directories. +.It Li pkinit_revoke = Va HX509-STORE ... +This is a multi-valued parameter naming one or more stores of +CRLs for the issuers of PKINIT client certificates. +Only the first valid CRL for a particular issuer will be checked. +If no CRLs are configured, then CRLs will not be checked. +This is because the KDC will not dereference CRL distribution +points nor request OCSP responses. +.It Li pkinit_kdc_ocsp = Va PATH +This names a file whose contents is the DER encoding of an +OCSPResponse for the KDC's end entity certificate. +.It Li pkinit_kdc_friendly_name = Va NAME +This is an optional friendly name of the KDC's end entity +certificate. +This is only helpful when the +.Li pkinit_identity +store contains many credentials. +.It Li pkinit_principal_in_certificate = Va BOOL +If set to +.Va true +then the KDC will match AS-REQ client principal names to the +PKINIT +.Va subjectAlternativeName +values from the clients' certificates. +Defaults to +.Va true . +.It Li pkinit_dh_min_bits = Va NUMBER +Minimum acceptable modular Diffie-Hellman public key size in +bits. +.It Li pkinit_max_life_from_cert_extension = Va BOOL +If set to +.Va true +then the KDC will override the +.Va max_life +attribute of the client principal's HDB record with a maximum +ticket life taken from a certificate extension with OID +.Va { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 4 } +and the DER encoding of an +.Va INTEGER +number of seconds. +Alternatively, if the extended key usage OID +.Va { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 3 } +is included in the client's certificate, then the +.Va notAfter +minus the current time will be used. +.It Li pkinit_max_life_bound = Va TIME +If set, this will be a hard bound on the maximum ticket lifetime +taken from the client's certificate. +As usual, +.Va TIME +can be given as a number followed by a unit, such as +.Dq 2d +for +.Dq two days . +.It Li pkinit_max_life_from_cert = Va TIME +If set, this will override the +.Va max_life +attribute of the client principal's HDB record with the +.Va notAfter +of the client's certificate minus the current time, bounded to +the given relative +.Va TIME +unless the +.Li pkinit_max_life_from_cert_extension +parameter is set and the client's certificate has that extension. +As usual, +.Va TIME +can be given as a number followed by a unit, such as +.Dq 2d +for +.Dq two days . +.It Li enable_gss_preauth = Va boolean +Enables pre-authentication using a GSS-API mechanism supported by the client and KDC. +The GSS-API initiator and AS request client names must match, unless the +.Li WELLKNOWN/FEDERATED +name was used in the AS request, in which case the AS reply will contain the +GSS-API initiator name. Authorization and mapping behavior may be customized +by plugins. If synthetic clients are enabled, then the GSS-API initiator need +not exist in the local database. GSS-API pre-authentication is disabled by +default. +.It Li enable_gss_auth_data = Va boolean +When using GSS-API pre-authentication, includes a Kerberos authorization data +element containing naming attributes associated with the GSS-API initiator. This +is disabled by default as it may significantly increase the size of returned +tickets. +.It Li gss_mechanisms_allowed = Va mechs ... +A list of GSS-API mechanisms that may be used for GSS-API pre-authentication. +.It Li gss_cross_realm_mechanisms_allowed = Va mechs ... +A list of GSS-API mechanisms that, when using the default authorization +mechanism, will be permitted to map Kerberos principals in foreign realms. The +list is empty by default. Initiator names from mechanisms not on this list will +be mapped to an enterprise principal in the AS-REQ realm. This option is +intended to avoid conflating GSS-API pre-authentication and Kerberos +cross-realm authentication. The behavior is provided by the default +authorization mechanism and will be overridden by an authorization plugin. +Mechanisms may be identified by dot-separated OID or a short name. +.It Li historical_anon_realm = Va boolean +Enables pre-7.0 non-RFC-comformant KDC behavior. +With this option set to +.Li true +the client realm in anonymous pkinit AS replies will be the requested realm, +rather than the RFC-conformant +.Li WELLKNOWN:ANONYMOUS +realm. +This can have a security impact on servers that expect to grant access to +anonymous-but-authenticated to the KDC users of the realm in question: +they would also grant access to unauthenticated anonymous users. +As such, it is not recommend to set this option to +.Li true. +.It Li encode_as_rep_as_tgs_rep = Va BOOL +Encode as-rep as tgs-rep to be compatible with mistakes older DCE secd did. +.\" XXX +.It Li kdc_warn_pwexpire = Va TIME +The time before expiration that the user should be warned that her +password is about to expire. +.It Li logging = Va Logging +What type of logging the kdc should use, see also [logging]/kdc. +.It Li hdb-ldap-structural-object Va structural object +If the LDAP backend is used for storing principals, this is the +structural object that will be used when creating and when reading +objects. +The default value is account . +.It Li hdb-ldap-create-base Va creation dn +is the dn that will be appended to the principal when creating entries. +Default value is the search dn. +.It Li enable-digest = Va BOOL +Should the kdc answer digest requests. The default is FALSE. +.It Li digests_allowed = Va list of digests +Specifies the digests the kdc will reply to. The default is +.Li ntlm-v2 . +.It Li enable-kx509 = Va boolean +Enables kx509 service. +.Pp +The kx509 service is configurable for a number of cases: +.Bl -tag -width "" -offset indent +.It Li default certificates for user or service principals, +.It Li non-default certificate requests including subject alternative names (SAN) and extended key usage (EKU) certificate extensions, for either client, server, or mixed usage. +.El +.Pp +Distinct configurations are supported for all of these cases as +shown below: +.Bd -literal -offset indent +[kdc] + enable-kx509 = yes | no + require_csr = yes | no + require_initial_kca_tickets = yes | no + realm = { + = { + kx509 = { +